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> {
218 let response = self
219 .client
220 .read(pb::ReadRequest {
221 tuple_sets: vec![TupleSet {
222 ns: ns.0.clone(),
223 spec: Some(pb::tuple_set::Spec::ObjectSpec(ObjectSpec {
224 obj: obj.0.clone(),
225 rel: None,
226 })),
227 }],
228 ts: None,
229 })
230 .await?;
231 let response = response.into_inner();
232 Ok(response
233 .tuples
234 .into_iter()
235 .map(|tup| Tuple {
236 ns: Namespace(tup.ns),
237 obj: Obj(tup.obj),
238 rel: Rel(tup.rel),
239 sbj: match tup.user {
240 None => todo!(),
241 Some(user) => match user {
242 pb::tuple::User::UserId(userid) => User::UserId(userid),
243 pb::tuple::User::UserSet(pb::UserSet { ns, obj, rel }) => User::UserSet {
244 ns: Namespace(ns),
245 obj: Obj(obj),
246 rel: Rel(rel),
247 },
248 },
249 },
250 })
251 .collect())
252 }
253}
254impl CheckClient {
255 pub async fn create(uri: Uri) -> Result<Self, ConnectError> {
256 match Channel::builder(uri).connect().await {
257 Ok(channel) => Ok(CheckClient {
258 client: pb::check_service_client::CheckServiceClient::new(channel),
259 }),
260 Err(err) => Err(ConnectError(err)),
261 }
262 }
263 pub async fn add_one(&mut self, tuple: Tuple) -> Result<String, AddError> {
264 let add_tuples = vec![pb::Tuple {
265 ns: tuple.ns.0.to_string(),
266 obj: tuple.obj.0,
267 rel: tuple.rel.0.to_string(),
268 user: match tuple.sbj {
269 User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
270 User::UserSet {
271 ns: Namespace(ns),
272 obj: Obj(obj),
273 rel: Rel(rel),
274 } => Some(pb::tuple::User::UserSet(pb::UserSet {
275 ns: ns.to_string(),
276 obj,
277 rel: rel.to_string(),
278 })),
279 },
280 condition: None,
281 }];
282 dbg!(&add_tuples);
283 self.client
284 .write(pb::WriteRequest {
285 add_tuples,
286 ..Default::default()
287 })
288 .await
289 .map(|r| r.into_inner().ts)
290 .map_err(Into::into)
291 }
292
293 pub async fn add_one_with_condition(
294 &mut self,
295 tuple: Tuple,
296 condition: Condition,
297 ) -> Result<String, AddError> {
298 let add_tuples = vec![pb::Tuple {
299 ns: tuple.ns.0.to_string(),
300 obj: tuple.obj.0,
301 rel: tuple.rel.0.to_string(),
302 user: match tuple.sbj {
303 User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
304 User::UserSet {
305 ns: Namespace(ns),
306 obj: Obj(obj),
307 rel: Rel(rel),
308 } => Some(pb::tuple::User::UserSet(pb::UserSet {
309 ns: ns.to_string(),
310 obj,
311 rel: rel.to_string(),
312 })),
313 },
314 condition: match condition {
315 Condition::Expires(exp) => Some(pb::tuple::Condition::Expires(exp.timestamp())),
316 },
317 }];
318 self.client
319 .write(pb::WriteRequest {
320 add_tuples,
321 ..Default::default()
322 })
323 .await
324 .map(|r| r.into_inner().ts)
325 .map_err(Into::into)
326 }
327
328 pub async fn add_many(&mut self, tuples: Vec<Tuple>) -> Result<String, AddError> {
329 let add_tuples = tuples
330 .into_iter()
331 .map(|tuple| pb::Tuple {
332 ns: tuple.ns.0,
333 obj: tuple.obj.0,
334 rel: tuple.rel.0,
335 user: match tuple.sbj {
336 User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
337 User::UserSet {
338 ns: Namespace(ns),
339 obj: Obj(obj),
340 rel: Rel(rel),
341 } => Some(pb::tuple::User::UserSet(pb::UserSet { ns, obj, rel })),
342 },
343 condition: None,
344 })
345 .collect();
346 self.client
347 .write(pb::WriteRequest {
348 add_tuples,
349 ..Default::default()
350 })
351 .await
352 .map(|r| r.into_inner().ts)
353 .map_err(Into::into)
354 }
355
356 pub async fn delete_one(&mut self, tuple: Tuple) -> Result<String, AddError> {
357 let del_tuples = vec![pb::Tuple {
358 ns: tuple.ns.0,
359 obj: tuple.obj.0,
360 rel: tuple.rel.0.to_string(),
361 user: match tuple.sbj {
362 User::UserId(user_id) => Some(pb::tuple::User::UserId(user_id)),
363 User::UserSet {
364 ns: Namespace(ns),
365 obj: Obj(obj),
366 rel: Rel(rel),
367 } => Some(pb::tuple::User::UserSet(pb::UserSet {
368 ns: ns.to_string(),
369 obj,
370 rel: rel.to_string(),
371 })),
372 },
373 condition: None,
374 }];
375 self.client
376 .write(pb::WriteRequest {
377 del_tuples,
378 ..Default::default()
379 })
380 .await
381 .map(|r| r.into_inner().ts)
382 .map_err(Into::into)
383 }
384}
385
386impl CheckClient {
387 pub async fn check(
388 &mut self,
389 Namespace(ns): Namespace,
390 Obj(obj): Obj,
391 Permission(permission): Permission,
392 UserId(user_id): UserId,
393 timestamp: Option<Timestamp>,
394 ) -> Result<CheckResult, CallError> {
395 let r = pb::CheckRequest {
396 ns: ns.to_string(),
397 obj,
398 rel: permission.to_string(),
399 user_id,
400 ts: timestamp.unwrap_or(Timestamp::empty()).0,
401 };
402 match self.client.check(r).await.map(|r| r.into_inner()) {
403 Ok(pb::CheckResponse {
404 principal: Some(pb::Principal { id }),
405 ok,
406 }) if ok => Ok(CheckResult::Ok(id.into())),
407 Ok(pb::CheckResponse {
408 principal: Some(pb::Principal { id }),
409 ok,
410 }) if !ok => Ok(CheckResult::Forbidden(id.into())),
411 Ok(pb::CheckResponse {
412 principal: None, ..
413 }) => Ok(CheckResult::UnknownPutativeUser),
414 Ok(pb::CheckResponse { .. }) => Err(CallError::UnexpectedResponseFormat),
415 Err(status) => Err(status.into()),
416 }
417 }
418
419 pub async fn list(
420 &mut self,
421 Namespace(ns): Namespace,
422 Rel(rel): Rel,
423 UserId(user_id): UserId,
424 timestamp: Option<Timestamp>,
425 ) -> Result<Vec<String>, CallError> {
426 let r = pb::ListRequest {
427 ns,
428 rel: rel.to_string(),
429 user_id,
430 ts: timestamp.unwrap_or(Timestamp::empty()).0,
431 };
432 match self.client.list(r).await.map(|r| r.into_inner()) {
433 Ok(response) => Ok(response.objs),
434 Err(e) => Err(e.into()),
435 }
436 }
437}