surrealdb_core/iam/entities/resources/
actor.rs1use revision::revisioned;
2use std::collections::{HashMap, HashSet};
3use std::ops::Deref;
4use std::str::FromStr;
5
6use cedar_policy::{Entity, EntityId, EntityTypeName, EntityUid, RestrictedExpression};
7use serde::{Deserialize, Serialize};
8
9use super::{Level, Resource, ResourceKind};
10use crate::iam::{Error, Role};
11use crate::sql::statements::{DefineAccessStatement, DefineUserStatement};
12
13#[revisioned(revision = 1)]
17#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
18#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
19#[non_exhaustive]
20pub struct Actor {
21 res: Resource,
22 roles: Vec<Role>,
23}
24
25impl Default for Actor {
26 fn default() -> Self {
27 Self {
28 res: ResourceKind::Actor.on_level(Level::No),
29 roles: Vec::new(),
30 }
31 }
32}
33
34impl std::fmt::Display for Actor {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 if self.res.level() == &Level::No {
37 return write!(f, "Actor::Anonymous");
38 }
39
40 write!(
41 f,
42 "{}{}::{}({})",
43 self.res.level(),
44 self.res.kind(),
45 self.res.id(),
46 self.roles.iter().map(|r| format!("{}", r)).collect::<Vec<String>>().join(", ")
47 )
48 }
49}
50
51impl Actor {
52 pub fn new(id: String, roles: Vec<Role>, level: Level) -> Self {
53 Self {
54 res: Resource::new(id, super::ResourceKind::Actor, level),
55 roles,
56 }
57 }
58
59 pub fn has_role(&self, role: Role) -> bool {
61 self.roles.contains(&role)
62 }
63
64 pub fn has_owner_role(&self) -> bool {
66 self.roles.iter().any(|r| r.eq(&Role::Owner))
67 }
68
69 pub fn has_editor_role(&self) -> bool {
71 self.roles.iter().any(|r| r.eq(&Role::Owner) || r.eq(&Role::Editor))
72 }
73
74 pub fn has_viewer_role(&self) -> bool {
76 self.roles.iter().any(|r| r.eq(&Role::Owner) || r.eq(&Role::Editor) || r.eq(&Role::Viewer))
77 }
78
79 pub fn cedar_attrs(&self) -> HashMap<String, RestrictedExpression> {
81 [
82 ("type", self.kind().into()),
83 ("level", self.level().into()),
84 ("roles", RestrictedExpression::new_set(self.roles.iter().map(|r| r.into()))),
85 ]
86 .into_iter()
87 .map(|(x, v)| (x.into(), v))
88 .collect()
89 }
90
91 pub fn cedar_parents(&self) -> HashSet<EntityUid> {
92 let mut parents = HashSet::with_capacity(1);
93 parents.insert(self.res.level().into());
94 parents
95 }
96
97 pub fn cedar_entities(&self) -> Vec<Entity> {
98 let mut entities = Vec::new();
99
100 entities.push(self.into());
101
102 for role in self.roles.iter() {
103 entities.push(role.into());
104 }
105
106 for level in self.res.level().cedar_entities() {
107 entities.push(level);
108 }
109
110 entities
111 }
112}
113
114impl Deref for Actor {
115 type Target = Resource;
116 fn deref(&self) -> &Self::Target {
117 &self.res
118 }
119}
120
121impl std::convert::From<&Actor> for EntityUid {
122 fn from(actor: &Actor) -> Self {
123 EntityUid::from_type_name_and_id(
124 EntityTypeName::from_str("Actor").unwrap(),
125 EntityId::from_str(actor.id()).unwrap(),
126 )
127 }
128}
129
130impl std::convert::From<&Actor> for Entity {
131 fn from(actor: &Actor) -> Self {
132 Entity::new(actor.into(), actor.cedar_attrs(), actor.cedar_parents())
133 }
134}
135
136impl std::convert::TryFrom<(&DefineUserStatement, Level)> for Actor {
137 type Error = Error;
138 fn try_from(val: (&DefineUserStatement, Level)) -> Result<Self, Self::Error> {
139 let roles = val.0.roles.iter().map(Role::try_from).collect::<Result<_, _>>()?;
140 Ok(Self::new(val.0.name.to_string(), roles, val.1))
141 }
142}
143
144impl std::convert::From<(&DefineAccessStatement, Level)> for Actor {
145 fn from(val: (&DefineAccessStatement, Level)) -> Self {
146 Self::new(val.0.name.to_string(), Vec::default(), val.1)
147 }
148}