1use std::hash::Hash;
4
5use crate::{
6 domain::{
7 DomainError, ObjectRef, ObjectType, RelationName, Relationship, SubjectRef, SubjectType,
8 },
9 revision::Consistency,
10};
11
12#[cfg_attr(
15 feature = "serde",
16 derive(serde::Serialize),
17 serde(rename_all = "camelCase", deny_unknown_fields)
18)]
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub struct Object {
21 pub namespace: String,
23 pub id: String,
25}
26
27impl Object {
28 #[must_use]
30 pub fn new(namespace: impl Into<String>, id: impl Into<String>) -> Self {
31 Self {
32 namespace: namespace.into(),
33 id: id.into(),
34 }
35 }
36
37 pub fn validate(&self) -> Result<(), DomainError> {
44 ObjectRef::try_from(self).map(drop)
45 }
46}
47
48#[cfg(feature = "serde")]
49impl<'de> serde::Deserialize<'de> for Object {
50 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
51 where
52 D: serde::Deserializer<'de>,
53 {
54 #[derive(serde::Deserialize)]
55 #[serde(rename_all = "camelCase", deny_unknown_fields)]
56 struct ObjectSerde {
57 namespace: String,
58 id: String,
59 }
60
61 let value = ObjectSerde::deserialize(deserializer)?;
62 let object = Self {
63 namespace: value.namespace,
64 id: value.id,
65 };
66 object.validate().map_err(serde::de::Error::custom)?;
67 Ok(object)
68 }
69}
70
71#[cfg_attr(feature = "serde", derive(serde::Serialize))]
74#[derive(Debug, Clone, PartialEq, Eq, Hash)]
75pub struct Relation(pub String);
76
77impl Relation {
78 #[must_use]
80 pub fn new(name: impl Into<String>) -> Self {
81 Self(name.into())
82 }
83
84 pub fn validate(&self) -> Result<(), DomainError> {
91 RelationName::try_from(self).map(drop)
92 }
93}
94
95#[cfg(feature = "serde")]
96impl<'de> serde::Deserialize<'de> for Relation {
97 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
98 where
99 D: serde::Deserializer<'de>,
100 {
101 let relation = Self(<String as serde::Deserialize>::deserialize(deserializer)?);
102 relation.validate().map_err(serde::de::Error::custom)?;
103 Ok(relation)
104 }
105}
106
107#[cfg_attr(
109 feature = "serde",
110 derive(serde::Serialize),
111 serde(rename_all = "camelCase", tag = "type", content = "value")
112)]
113#[derive(Debug, Clone, PartialEq, Eq, Hash)]
114pub enum User {
115 UserId(String),
118 Userset(Object, Relation),
121}
122
123impl User {
124 #[must_use]
126 pub fn user_id(id: impl Into<String>) -> Self {
127 Self::UserId(id.into())
128 }
129
130 #[must_use]
132 pub fn userset(object: Object, relation: Relation) -> Self {
133 Self::Userset(object, relation)
134 }
135
136 pub fn validate(&self) -> Result<(), DomainError> {
143 SubjectRef::try_from(self).map(drop)
144 }
145}
146
147#[cfg(feature = "serde")]
148impl<'de> serde::Deserialize<'de> for User {
149 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
150 where
151 D: serde::Deserializer<'de>,
152 {
153 #[derive(serde::Deserialize)]
154 #[serde(rename_all = "camelCase", tag = "type", content = "value")]
155 enum UserSerde {
156 UserId(String),
157 Userset(Object, Relation),
158 }
159
160 let user = match UserSerde::deserialize(deserializer)? {
161 UserSerde::UserId(id) => Self::UserId(id),
162 UserSerde::Userset(object, relation) => Self::Userset(object, relation),
163 };
164 user.validate().map_err(serde::de::Error::custom)?;
165 Ok(user)
166 }
167}
168
169#[cfg_attr(
173 feature = "serde",
174 derive(serde::Serialize),
175 serde(rename_all = "camelCase", deny_unknown_fields)
176)]
177#[derive(Debug, Clone, PartialEq, Eq, Hash)]
178pub struct RelationTuple {
179 pub object: Object,
181 pub relation: Relation,
183 pub user: User,
185}
186
187impl RelationTuple {
188 #[must_use]
190 pub fn new(object: Object, relation: Relation, user: User) -> Self {
191 Self {
192 object,
193 relation,
194 user,
195 }
196 }
197
198 pub fn validate(&self) -> Result<(), DomainError> {
205 Relationship::try_from(self).map(drop)
206 }
207}
208
209#[cfg(feature = "serde")]
210impl<'de> serde::Deserialize<'de> for RelationTuple {
211 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
212 where
213 D: serde::Deserializer<'de>,
214 {
215 #[derive(serde::Deserialize)]
216 #[serde(rename_all = "camelCase", deny_unknown_fields)]
217 struct RelationTupleSerde {
218 object: Object,
219 relation: Relation,
220 user: User,
221 }
222
223 let value = RelationTupleSerde::deserialize(deserializer)?;
224 let tuple = Self {
225 object: value.object,
226 relation: value.relation,
227 user: value.user,
228 };
229 tuple.validate().map_err(serde::de::Error::custom)?;
230 Ok(tuple)
231 }
232}
233
234#[cfg_attr(
236 feature = "serde",
237 derive(serde::Serialize, serde::Deserialize),
238 serde(rename_all = "camelCase", deny_unknown_fields)
239)]
240#[derive(Debug, Clone, PartialEq, Eq)]
241pub struct CheckRequest {
242 pub object: Object,
244 pub relation: Relation,
246 pub user: User,
248 pub consistency: Consistency,
250}
251
252impl CheckRequest {
253 #[must_use]
255 pub fn new(object: Object, relation: Relation, user: User, consistency: Consistency) -> Self {
256 Self {
257 object,
258 relation,
259 user,
260 consistency,
261 }
262 }
263
264 pub fn validate(&self) -> Result<(), DomainError> {
270 self.object.validate()?;
271 self.relation.validate()?;
272 self.user.validate()
273 }
274}
275
276#[cfg_attr(
278 feature = "serde",
279 derive(serde::Serialize, serde::Deserialize),
280 serde(rename_all = "camelCase", deny_unknown_fields)
281)]
282#[derive(Debug, Clone, Copy, PartialEq, Eq)]
283pub struct CheckResponse {
284 pub allowed: bool,
286}
287
288#[cfg_attr(
290 feature = "serde",
291 derive(serde::Serialize, serde::Deserialize),
292 serde(rename_all = "camelCase", deny_unknown_fields)
293)]
294#[derive(Debug, Clone, PartialEq, Eq)]
295pub struct ExpandRequest {
296 pub object: Object,
298 pub relation: Relation,
300 pub consistency: Consistency,
302}
303
304impl ExpandRequest {
305 #[must_use]
307 pub fn new(object: Object, relation: Relation, consistency: Consistency) -> Self {
308 Self {
309 object,
310 relation,
311 consistency,
312 }
313 }
314
315 pub fn validate(&self) -> Result<(), DomainError> {
321 self.object.validate()?;
322 self.relation.validate()
323 }
324}
325
326#[cfg_attr(
328 feature = "serde",
329 derive(serde::Serialize, serde::Deserialize),
330 serde(rename_all = "camelCase", deny_unknown_fields)
331)]
332#[derive(Debug, Clone, PartialEq, Eq)]
333pub struct ExpandResponse {
334 pub expanded: ExpandedUserset,
336}
337
338#[cfg_attr(
340 feature = "serde",
341 derive(serde::Serialize),
342 serde(rename_all = "camelCase", deny_unknown_fields)
343)]
344#[derive(Debug, Clone, PartialEq, Eq)]
345pub struct LookupResourcesRequest {
346 pub subject: User,
348 pub permission: Relation,
350 pub resource_type: String,
352}
353
354impl LookupResourcesRequest {
355 #[must_use]
357 pub fn new(subject: User, permission: Relation, resource_type: impl Into<String>) -> Self {
358 Self {
359 subject,
360 permission,
361 resource_type: resource_type.into(),
362 }
363 }
364
365 pub fn validate(&self) -> Result<(), DomainError> {
371 self.subject.validate()?;
372 self.permission.validate()?;
373 ObjectType::try_from(self.resource_type.as_str()).map(drop)
374 }
375}
376
377#[cfg(feature = "serde")]
378impl<'de> serde::Deserialize<'de> for LookupResourcesRequest {
379 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
380 where
381 D: serde::Deserializer<'de>,
382 {
383 #[derive(serde::Deserialize)]
384 #[serde(rename_all = "camelCase", deny_unknown_fields)]
385 struct LookupResourcesRequestSerde {
386 subject: User,
387 permission: Relation,
388 resource_type: String,
389 }
390
391 let value = LookupResourcesRequestSerde::deserialize(deserializer)?;
392 let request = Self {
393 subject: value.subject,
394 permission: value.permission,
395 resource_type: value.resource_type,
396 };
397 request.validate().map_err(serde::de::Error::custom)?;
398 Ok(request)
399 }
400}
401
402#[cfg_attr(
404 feature = "serde",
405 derive(serde::Serialize, serde::Deserialize),
406 serde(rename_all = "camelCase", deny_unknown_fields)
407)]
408#[derive(Debug, Clone, PartialEq, Eq)]
409pub struct LookupResources {
410 pub resources: Vec<Object>,
412}
413
414#[cfg_attr(
416 feature = "serde",
417 derive(serde::Serialize),
418 serde(rename_all = "camelCase", deny_unknown_fields)
419)]
420#[derive(Debug, Clone, PartialEq, Eq)]
421pub struct LookupSubjectsRequest {
422 pub resource: Object,
424 pub permission: Relation,
426 pub subject_type: String,
428}
429
430impl LookupSubjectsRequest {
431 #[must_use]
433 pub fn new(resource: Object, permission: Relation, subject_type: impl Into<String>) -> Self {
434 Self {
435 resource,
436 permission,
437 subject_type: subject_type.into(),
438 }
439 }
440
441 pub fn validate(&self) -> Result<(), DomainError> {
447 self.resource.validate()?;
448 self.permission.validate()?;
449 SubjectType::try_from(self.subject_type.as_str()).map(drop)
450 }
451}
452
453#[cfg(feature = "serde")]
454impl<'de> serde::Deserialize<'de> for LookupSubjectsRequest {
455 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
456 where
457 D: serde::Deserializer<'de>,
458 {
459 #[derive(serde::Deserialize)]
460 #[serde(rename_all = "camelCase", deny_unknown_fields)]
461 struct LookupSubjectsRequestSerde {
462 resource: Object,
463 permission: Relation,
464 subject_type: String,
465 }
466
467 let value = LookupSubjectsRequestSerde::deserialize(deserializer)?;
468 let request = Self {
469 resource: value.resource,
470 permission: value.permission,
471 subject_type: value.subject_type,
472 };
473 request.validate().map_err(serde::de::Error::custom)?;
474 Ok(request)
475 }
476}
477
478#[cfg_attr(
480 feature = "serde",
481 derive(serde::Serialize, serde::Deserialize),
482 serde(rename_all = "camelCase", deny_unknown_fields)
483)]
484#[derive(Debug, Clone, PartialEq, Eq)]
485pub struct LookupSubjects {
486 pub subjects: Vec<User>,
488}
489
490#[cfg_attr(
492 feature = "serde",
493 derive(serde::Serialize, serde::Deserialize),
494 serde(rename_all = "camelCase", deny_unknown_fields)
495)]
496#[derive(Debug, Clone, PartialEq, Eq)]
497pub struct LookupPermissionsRequest {
498 pub subject: User,
500 pub resource: Object,
502 pub consistency: Consistency,
504}
505
506impl LookupPermissionsRequest {
507 #[must_use]
509 pub fn new(subject: User, resource: Object, consistency: Consistency) -> Self {
510 Self {
511 subject,
512 resource,
513 consistency,
514 }
515 }
516
517 pub fn validate(&self) -> Result<(), DomainError> {
523 self.subject.validate()?;
524 self.resource.validate()
525 }
526}
527
528#[cfg_attr(
530 feature = "serde",
531 derive(serde::Serialize, serde::Deserialize),
532 serde(rename_all = "camelCase", deny_unknown_fields)
533)]
534#[derive(Debug, Clone, PartialEq, Eq)]
535pub struct LookupPermissions {
536 pub permissions: Vec<Relation>,
538}
539
540#[cfg_attr(
542 feature = "serde",
543 derive(serde::Serialize),
544 serde(rename_all = "camelCase", deny_unknown_fields)
545)]
546#[derive(Debug, Clone, PartialEq, Eq)]
547pub struct LookupObjectPermissionsRequest {
548 pub resource: Object,
550 pub subject_type: String,
552 pub consistency: Consistency,
554}
555
556impl LookupObjectPermissionsRequest {
557 #[must_use]
559 pub fn new(
560 resource: Object,
561 subject_type: impl Into<String>,
562 consistency: Consistency,
563 ) -> Self {
564 Self {
565 resource,
566 subject_type: subject_type.into(),
567 consistency,
568 }
569 }
570
571 pub fn validate(&self) -> Result<(), DomainError> {
577 self.resource.validate()?;
578 SubjectType::try_from(self.subject_type.as_str()).map(drop)
579 }
580}
581
582#[cfg(feature = "serde")]
583impl<'de> serde::Deserialize<'de> for LookupObjectPermissionsRequest {
584 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
585 where
586 D: serde::Deserializer<'de>,
587 {
588 #[derive(serde::Deserialize)]
589 #[serde(rename_all = "camelCase", deny_unknown_fields)]
590 struct LookupObjectPermissionsRequestSerde {
591 resource: Object,
592 subject_type: String,
593 consistency: Consistency,
594 }
595
596 let value = LookupObjectPermissionsRequestSerde::deserialize(deserializer)?;
597 let request = Self {
598 resource: value.resource,
599 subject_type: value.subject_type,
600 consistency: value.consistency,
601 };
602 request.validate().map_err(serde::de::Error::custom)?;
603 Ok(request)
604 }
605}
606
607#[cfg_attr(
609 feature = "serde",
610 derive(serde::Serialize, serde::Deserialize),
611 serde(rename_all = "camelCase", deny_unknown_fields)
612)]
613#[derive(Debug, Clone, PartialEq, Eq)]
614pub struct LookupObjectPermissions {
615 pub permissions: Vec<PermissionSubjects>,
617}
618
619#[cfg_attr(
621 feature = "serde",
622 derive(serde::Serialize, serde::Deserialize),
623 serde(rename_all = "camelCase", deny_unknown_fields)
624)]
625#[derive(Debug, Clone, PartialEq, Eq)]
626pub struct PermissionSubjects {
627 pub permission: Relation,
629 pub subjects: Vec<User>,
631}
632
633#[cfg_attr(
635 feature = "serde",
636 derive(serde::Serialize, serde::Deserialize),
637 serde(rename_all = "camelCase", deny_unknown_fields)
638)]
639#[derive(Debug, Clone, Default)]
640pub struct NamespaceConfig {
641 pub name: String,
643 pub relations: std::collections::HashMap<Relation, RelationConfig>,
645}
646
647#[cfg_attr(
649 feature = "serde",
650 derive(serde::Serialize, serde::Deserialize),
651 serde(rename_all = "camelCase", deny_unknown_fields)
652)]
653#[derive(Debug, Clone)]
654pub struct RelationConfig {
655 pub name: Relation,
657 pub userset_rewrite: Option<UsersetExpression>,
659}
660
661#[cfg_attr(
663 feature = "serde",
664 derive(serde::Serialize, serde::Deserialize),
665 serde(rename_all = "camelCase")
666)]
667#[derive(Debug, Clone)]
668pub enum UsersetExpression {
669 This,
671 ComputedUserset {
674 relation: Relation,
676 },
677 TupleToUserset {
681 tupleset_relation: Relation,
683 computed_userset_relation: Relation,
685 },
686 Union(Vec<UsersetExpression>),
688 Intersection(Vec<UsersetExpression>),
690 Exclusion {
692 base: Box<UsersetExpression>,
694 exclude: Box<UsersetExpression>,
696 },
697}
698
699#[cfg_attr(
701 feature = "serde",
702 derive(serde::Serialize, serde::Deserialize),
703 serde(rename_all = "camelCase")
704)]
705#[derive(Debug, Clone, PartialEq, Eq)]
706pub enum ExpandedUserset {
707 User(String),
709 Userset(Object, Relation),
711 Union(Vec<ExpandedUserset>),
713 Intersection(Vec<ExpandedUserset>),
715 Exclusion {
717 base: Box<ExpandedUserset>,
719 exclude: Box<ExpandedUserset>,
721 },
722}