1#![allow(unused_variables)]
2#![allow(unused_imports)]
3use std::fmt::{Display, Formatter};
4use std::str::FromStr;
5
6use crate::auth::{CallError, CheckResult};
7use crate::error::ReadError;
8use crate::pb::tuple_set::ObjectSpec;
9use crate::pb::TupleSet;
10use chrono::{DateTime, Utc};
11pub use error::ConnectError;
12use error::{AddError, ParseError};
13use http::Uri;
14use tonic::transport::Channel;
15
16pub mod auth;
17#[cfg(feature = "axum")]
18pub mod axum;
19mod error;
20
21#[derive(Clone, Debug)]
22pub struct Namespace(pub String);
23const PERSONAL: &str = "personal";
24const ROOT: &str = "root";
25const TOKEN: &str = "token";
26const SERVICEACCOUNT_NS: &str = "serviceaccount";
27impl Namespace {
28 pub fn personal() -> Namespace {
29 Namespace(PERSONAL.into())
30 }
31 pub fn token() -> Namespace {
32 Namespace(TOKEN.into())
33 }
34 pub fn root() -> Namespace {
35 Namespace(ROOT.into())
36 }
37 pub fn serviceaccount() -> Namespace {
38 Namespace(SERVICEACCOUNT_NS.into())
39 }
40}
41
42#[derive(Clone, Debug)]
43pub struct Permission(pub &'static str);
44
45#[derive(Clone, Debug)]
46pub struct Rel(pub String);
47impl Rel {
48 pub const TRIPLE_DOT: &'static str = "...";
49 pub const IS: &'static str = "is";
50 pub const PARENT: &'static str = "parent";
51 pub const IAM_GET: &'static str = "iam.get";
52 pub const IAM_UPDATE: &'static str = "iam.update";
53 pub const IAM_DELETE: &'static str = "iam.delete";
54 pub const SERVICEACCOUNT_GET: &'static str = "serviceaccount.get";
55 pub const SERVICEACCOUNT_CREATE: &'static str = "serviceaccount.create";
56 pub const SERVICEACCOUNT_KEY_GET: &'static str = "serviceaccount.key.get";
57 pub const SERVICEACCOUNT_KEY_CREATE: &'static str = "serviceaccount.key.create";
58 pub const SERVICEACCOUNT_CREATE_TOKEN: &'static str = "serviceaccount.createToken";
59 pub const USER_CREATE: &'static str = "user.create";
60
61 pub fn triple_dot() -> Rel {
62 Rel(Self::TRIPLE_DOT.into())
63 }
64 pub fn is() -> Rel {
65 Rel(Self::IS.into())
66 }
67 pub fn parent() -> Rel {
68 Rel(Self::PARENT.into())
69 }
70 pub fn iam_get() -> Rel {
71 Rel(Self::IAM_GET.into())
72 }
73 pub fn iam_update() -> Rel {
74 Rel(Self::IAM_UPDATE.into())
75 }
76 pub fn iam_delete() -> Rel {
77 Rel(Self::IAM_DELETE.into())
78 }
79 pub fn serviceaccount_get() -> Rel {
80 Rel(Self::SERVICEACCOUNT_GET.into())
81 }
82 pub fn serviceaccount_create() -> Rel {
83 Rel(Self::SERVICEACCOUNT_CREATE.into())
84 }
85 pub fn serviceaccount_key_get() -> Rel {
86 Rel(Self::SERVICEACCOUNT_KEY_GET.into())
87 }
88 pub fn serviceaccount_key_create() -> Rel {
89 Rel(Self::SERVICEACCOUNT_KEY_CREATE.into())
90 }
91 pub fn serviceaccount_create_token() -> Rel {
92 Rel(Self::SERVICEACCOUNT_CREATE_TOKEN.into())
93 }
94 pub fn user_upsert() -> Rel {
95 Rel(Self::USER_CREATE.into())
96 }
97}
98
99impl From<Permission> for Rel {
100 fn from(value: Permission) -> Self {
101 Rel(value.0.to_string())
102 }
103}
104
105#[derive(Clone, Debug)]
106pub struct UserId(pub String);
107
108#[derive(Clone, Debug)]
109pub struct Timestamp(pub String);
110
111impl Timestamp {
112 pub fn empty() -> Self {
113 Timestamp("1:0000000000000".into())
114 }
115}
116
117impl FromStr for UserId {
118 type Err = ParseError;
119
120 fn from_str(s: &str) -> Result<Self, Self::Err> {
121 Ok(UserId(s.into()))
122 }
123}
124
125impl TryFrom<String> for UserId {
126 type Error = ParseError;
127 fn try_from(value: String) -> Result<Self, Self::Error> {
128 UserId::from_str(&value)
129 }
130}
131
132#[derive(Clone, Debug)]
133pub struct Obj(pub String);
134const ROOT_OBJ: &str = "root";
135const UNSPECIFIED_OBJ: &str = "...";
136impl Obj {
137 pub fn unspecified() -> Obj {
138 Obj(UNSPECIFIED_OBJ.into())
139 }
140 pub fn root() -> Obj {
141 Obj(ROOT_OBJ.into())
142 }
143}
144
145impl FromStr for Obj {
146 type Err = ParseError;
147
148 fn from_str(s: &str) -> Result<Self, Self::Err> {
149 Ok(Obj(s.into()))
150 }
151}
152
153impl TryFrom<String> for Obj {
154 type Error = ParseError;
155 fn try_from(value: String) -> Result<Self, Self::Error> {
156 Obj::from_str(&value)
157 }
158}
159
160#[derive(Clone, Debug)]
161pub struct Tuple {
162 pub ns: Namespace,
163 pub obj: Obj,
164 pub rel: Rel,
165 pub sbj: User,
166}
167
168impl Display for Tuple {
169 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
170 match self {
171 Tuple {
172 ref ns,
173 ref obj,
174 ref rel,
175 sbj: User::UserId(ref s),
176 } => write!(f, "Tuple({}:{}#{}@{})", ns.0, obj.0, rel.0, s),
177 Tuple {
178 ref ns,
179 ref obj,
180 ref rel,
181 sbj:
182 User::UserSet {
183 ns: ref ns2,
184 obj: ref obj2,
185 rel: ref rel2,
186 },
187 } => write!(
188 f,
189 "Tuple({}:{}#{}@{}:{}#{})",
190 ns.0, obj.0, rel.0, ns2.0, obj2.0, rel2.0
191 ),
192 }
193 }
194}
195
196#[derive(Clone, Debug)]
197pub enum Condition {
198 Expires(DateTime<Utc>),
199}
200
201#[derive(Clone, Debug)]
202pub enum User {
203 UserId(String),
204 UserSet { ns: Namespace, obj: Obj, rel: Rel },
205}
206
207mod pb {
208 tonic::include_proto!("am");
209}
210
211#[derive(Clone, Debug)]
212pub struct CheckClient {
213 pub(crate) client: pb::check_service_client::CheckServiceClient<Channel>,
214}
215
216impl CheckClient {
217 pub async fn get_all(&mut self, ns: &Namespace, obj: &Obj) -> Result<Vec<Tuple>, ReadError> {
234 let response = self
235 .client
236 .read(pb::ReadRequest {
237 tuple_sets: vec![TupleSet {
238 ns: ns.0.clone(),
239 spec: Some(pb::tuple_set::Spec::ObjectSpec(ObjectSpec {
240 obj: obj.0.clone(),
241 rel: None,
242 })),
243 }],
244 ts: None,
245 })
246 .await?;
247 let response = response.into_inner();
248 Ok(response
249 .tuples
250 .into_iter()
251 .map(|tup| Tuple {
252 ns: Namespace(tup.ns),
253 obj: Obj(tup.obj),
254 rel: Rel(tup.rel),
255 sbj: match tup.user {
256 None => todo!(),
257 Some(user) => match user {
258 pb::tuple::User::UserId(userid) => User::UserId(userid),
259 pb::tuple::User::UserSet(pb::UserSet { ns, obj, rel }) => User::UserSet {
260 ns: Namespace(ns),
261 obj: Obj(obj),
262 rel: Rel(rel),
263 },
264 },
265 },
266 })
267 .collect())
268 }
269 }
271impl CheckClient {
272 pub async fn create(uri: Uri) -> Result<Self, ConnectError> {
273 match Channel::builder(uri).connect().await {
274 Ok(channel) => Ok(CheckClient {
275 client: pb::check_service_client::CheckServiceClient::new(channel),
276 }),
277 Err(err) => Err(ConnectError(err)),
278 }
279 }
280 pub async fn add_one(&mut self, tuple: Tuple) -> Result<String, AddError> {
287 let add_tuples = vec![pb::Tuple {
288 ns: tuple.ns.0.to_string(),
289 obj: tuple.obj.0,
290 rel: tuple.rel.0.to_string(),
291 user: match tuple.sbj {
292 User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
293 User::UserSet {
294 ns: Namespace(ns),
295 obj: Obj(obj),
296 rel: Rel(rel),
297 } => Some(pb::tuple::User::UserSet(pb::UserSet {
298 ns: ns.to_string(),
299 obj,
300 rel: rel.to_string(),
301 })),
302 },
303 condition: None,
304 }];
305 dbg!(&add_tuples);
306 self.client
307 .write(pb::WriteRequest {
308 add_tuples,
309 ..Default::default()
310 })
311 .await
312 .map(|r| r.into_inner().ts)
313 .map_err(Into::into)
314 }
315
316 pub async fn add_one_with_condition(
317 &mut self,
318 tuple: Tuple,
319 condition: Condition,
320 ) -> Result<String, AddError> {
321 let add_tuples = vec![pb::Tuple {
322 ns: tuple.ns.0.to_string(),
323 obj: tuple.obj.0,
324 rel: tuple.rel.0.to_string(),
325 user: match tuple.sbj {
326 User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
327 User::UserSet {
328 ns: Namespace(ns),
329 obj: Obj(obj),
330 rel: Rel(rel),
331 } => Some(pb::tuple::User::UserSet(pb::UserSet {
332 ns: ns.to_string(),
333 obj,
334 rel: rel.to_string(),
335 })),
336 },
337 condition: match condition {
338 Condition::Expires(exp) => Some(pb::tuple::Condition::Expires(exp.timestamp())),
339 },
340 }];
341 self.client
342 .write(pb::WriteRequest {
343 add_tuples,
344 ..Default::default()
345 })
346 .await
347 .map(|r| r.into_inner().ts)
348 .map_err(Into::into)
349 }
350
351 pub async fn add_many(&mut self, tuples: Vec<Tuple>) -> Result<String, AddError> {
352 let add_tuples = tuples
353 .into_iter()
354 .map(|tuple| pb::Tuple {
355 ns: tuple.ns.0,
356 obj: tuple.obj.0,
357 rel: tuple.rel.0,
358 user: match tuple.sbj {
359 User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
360 User::UserSet {
361 ns: Namespace(ns),
362 obj: Obj(obj),
363 rel: Rel(rel),
364 } => Some(pb::tuple::User::UserSet(pb::UserSet { ns, obj, rel })),
365 },
366 condition: None,
367 })
368 .collect();
369 self.client
370 .write(pb::WriteRequest {
371 add_tuples,
372 ..Default::default()
373 })
374 .await
375 .map(|r| r.into_inner().ts)
376 .map_err(Into::into)
377 }
378
379 pub async fn delete_one(&mut self, tuple: Tuple) -> Result<String, AddError> {
380 let del_tuples = vec![pb::Tuple {
381 ns: tuple.ns.0,
382 obj: tuple.obj.0,
383 rel: tuple.rel.0.to_string(),
384 user: match tuple.sbj {
385 User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
386 User::UserSet {
387 ns: Namespace(ns),
388 obj: Obj(obj),
389 rel: Rel(rel),
390 } => Some(pb::tuple::User::UserSet(pb::UserSet {
391 ns: ns.to_string(),
392 obj,
393 rel: rel.to_string(),
394 })),
395 },
396 condition: None,
397 }];
398 self.client
399 .write(pb::WriteRequest {
400 del_tuples,
401 ..Default::default()
402 })
403 .await
404 .map(|r| r.into_inner().ts)
405 .map_err(Into::into)
406 }
407}
408
409impl CheckClient {
423 pub async fn check(
424 &mut self,
425 Namespace(ns): Namespace,
426 Obj(obj): Obj,
427 Permission(permission): Permission,
428 UserId(user_id): UserId,
429 timestamp: Option<Timestamp>,
430 ) -> Result<CheckResult, CallError> {
431 let r = pb::CheckRequest {
432 ns: ns.to_string(),
433 obj,
434 rel: permission.to_string(),
435 user_id,
436 ts: timestamp.unwrap_or(Timestamp::empty()).0,
437 };
438 match self.client.check(r).await.map(|r| r.into_inner()) {
439 Ok(pb::CheckResponse {
440 principal: Some(pb::Principal { id }),
441 ok,
442 }) if ok => Ok(CheckResult::Ok(id.into())),
443 Ok(pb::CheckResponse {
444 principal: Some(pb::Principal { id }),
445 ok,
446 }) if !ok => Ok(CheckResult::Forbidden(id.into())),
447 Ok(pb::CheckResponse {
448 principal: None, ..
449 }) => Ok(CheckResult::UnknownPutativeUser),
450 Ok(pb::CheckResponse { .. }) => Err(CallError::UnexpectedResponseFormat),
451 Err(status) => Err(status.into()),
452 }
453 }
454
455 pub async fn list(
456 &mut self,
457 Namespace(ns): Namespace,
458 Rel(rel): Rel,
459 UserId(user_id): UserId,
460 timestamp: Option<Timestamp>,
461 ) -> Result<Vec<String>, CallError> {
462 let r = pb::ListRequest {
463 ns,
464 rel: rel.to_string(),
465 user_id,
466 ts: timestamp.unwrap_or(Timestamp::empty()).0,
467 };
468 match self.client.list(r).await.map(|r| r.into_inner()) {
469 Ok(response) => Ok(response.objs),
470 Err(e) => Err(e.into()),
471 }
472 }
473}