Skip to main content

surrealdb_core/sql/statements/
access.rs

1use std::fmt;
2use std::fmt::{Display, Formatter};
3
4use crate::sql::{Base, Cond, Ident, RecordIdLit};
5use crate::val::{Datetime, Duration, Strand, Uuid};
6
7#[derive(Clone, Debug, PartialEq, Eq)]
8#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
9pub enum AccessStatement {
10	Grant(AccessStatementGrant),   // Create access grant.
11	Show(AccessStatementShow),     // Show access grants.
12	Revoke(AccessStatementRevoke), // Revoke access grant.
13	Purge(AccessStatementPurge),   // Purge access grants.
14}
15
16impl From<AccessStatement> for crate::expr::statements::access::AccessStatement {
17	fn from(v: AccessStatement) -> Self {
18		match v {
19			AccessStatement::Grant(v) => Self::Grant(v.into()),
20			AccessStatement::Show(v) => Self::Show(v.into()),
21			AccessStatement::Revoke(v) => Self::Revoke(v.into()),
22			AccessStatement::Purge(v) => Self::Purge(v.into()),
23		}
24	}
25}
26
27impl From<crate::expr::statements::access::AccessStatement> for AccessStatement {
28	fn from(v: crate::expr::statements::access::AccessStatement) -> Self {
29		match v {
30			crate::expr::statements::access::AccessStatement::Grant(v) => Self::Grant(v.into()),
31			crate::expr::statements::access::AccessStatement::Show(v) => Self::Show(v.into()),
32			crate::expr::statements::access::AccessStatement::Revoke(v) => Self::Revoke(v.into()),
33			crate::expr::statements::access::AccessStatement::Purge(v) => Self::Purge(v.into()),
34		}
35	}
36}
37
38#[derive(Clone, Debug, PartialEq, Eq)]
39#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
40pub struct AccessStatementGrant {
41	pub ac: Ident,
42	pub base: Option<Base>,
43	pub subject: Subject,
44}
45
46impl From<AccessStatementGrant> for crate::expr::statements::access::AccessStatementGrant {
47	fn from(v: AccessStatementGrant) -> Self {
48		Self {
49			ac: v.ac.into(),
50			base: v.base.map(Into::into),
51			subject: v.subject.into(),
52		}
53	}
54}
55
56impl From<crate::expr::statements::access::AccessStatementGrant> for AccessStatementGrant {
57	fn from(v: crate::expr::statements::access::AccessStatementGrant) -> Self {
58		Self {
59			ac: v.ac.into(),
60			base: v.base.map(Into::into),
61			subject: v.subject.into(),
62		}
63	}
64}
65
66#[derive(Clone, Debug, Default, PartialEq, Eq)]
67#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
68pub struct AccessStatementShow {
69	pub ac: Ident,
70	pub base: Option<Base>,
71	pub gr: Option<Ident>,
72	pub cond: Option<Cond>,
73}
74
75impl From<AccessStatementShow> for crate::expr::statements::access::AccessStatementShow {
76	fn from(v: AccessStatementShow) -> Self {
77		Self {
78			ac: v.ac.into(),
79			base: v.base.map(Into::into),
80			gr: v.gr.map(Into::into),
81			cond: v.cond.map(Into::into),
82		}
83	}
84}
85
86impl From<crate::expr::statements::access::AccessStatementShow> for AccessStatementShow {
87	fn from(v: crate::expr::statements::access::AccessStatementShow) -> Self {
88		Self {
89			ac: v.ac.into(),
90			base: v.base.map(Into::into),
91			gr: v.gr.map(Into::into),
92			cond: v.cond.map(Into::into),
93		}
94	}
95}
96
97#[derive(Clone, Debug, Default, PartialEq, Eq)]
98#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
99pub struct AccessStatementRevoke {
100	pub ac: Ident,
101	pub base: Option<Base>,
102	pub gr: Option<Ident>,
103	pub cond: Option<Cond>,
104}
105
106impl From<AccessStatementRevoke> for crate::expr::statements::access::AccessStatementRevoke {
107	fn from(v: AccessStatementRevoke) -> Self {
108		Self {
109			ac: v.ac.into(),
110			base: v.base.map(Into::into),
111			gr: v.gr.map(Into::into),
112			cond: v.cond.map(Into::into),
113		}
114	}
115}
116
117impl From<crate::expr::statements::access::AccessStatementRevoke> for AccessStatementRevoke {
118	fn from(v: crate::expr::statements::access::AccessStatementRevoke) -> Self {
119		Self {
120			ac: v.ac.into(),
121			base: v.base.map(Into::into),
122			gr: v.gr.map(Into::into),
123			cond: v.cond.map(Into::into),
124		}
125	}
126}
127
128#[derive(Clone, Debug, Default, PartialEq, Eq)]
129#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
130pub struct AccessStatementPurge {
131	pub ac: Ident,
132	pub base: Option<Base>,
133	// TODO: Merge these booleans into a enum as having them both be false is invalid state.
134	pub expired: bool,
135	pub revoked: bool,
136	pub grace: Duration,
137}
138
139impl From<AccessStatementPurge> for crate::expr::statements::access::AccessStatementPurge {
140	fn from(v: AccessStatementPurge) -> Self {
141		Self {
142			ac: v.ac.into(),
143			base: v.base.map(Into::into),
144			expired: v.expired,
145			revoked: v.revoked,
146			grace: v.grace,
147		}
148	}
149}
150
151impl From<crate::expr::statements::access::AccessStatementPurge> for AccessStatementPurge {
152	fn from(v: crate::expr::statements::access::AccessStatementPurge) -> Self {
153		Self {
154			ac: v.ac.into(),
155			base: v.base.map(Into::into),
156			expired: v.expired,
157			revoked: v.revoked,
158			grace: v.grace,
159		}
160	}
161}
162
163#[derive(Clone, Debug, PartialEq, Eq)]
164#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
165pub struct AccessGrant {
166	pub id: Ident,                    // Unique grant identifier.
167	pub ac: Ident,                    // Access method used to create the grant.
168	pub creation: Datetime,           // Grant creation time.
169	pub expiration: Option<Datetime>, // Grant expiration time, if any.
170	pub revocation: Option<Datetime>, // Grant revocation time, if any.
171	pub subject: Subject,             // Subject of the grant.
172	pub grant: Grant,                 // Grant data.
173}
174
175#[derive(Clone, Debug, PartialEq, Eq)]
176#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
177pub enum Subject {
178	Record(RecordIdLit),
179	User(Ident),
180}
181
182impl From<Subject> for crate::expr::statements::access::Subject {
183	fn from(v: Subject) -> Self {
184		match v {
185			Subject::Record(id) => Self::Record(id.into()),
186			Subject::User(name) => Self::User(name.into()),
187		}
188	}
189}
190
191impl From<crate::expr::statements::access::Subject> for Subject {
192	fn from(v: crate::expr::statements::access::Subject) -> Self {
193		match v {
194			crate::expr::statements::access::Subject::Record(id) => Self::Record(id.into()),
195			crate::expr::statements::access::Subject::User(name) => Self::User(name.into()),
196		}
197	}
198}
199
200#[derive(Clone, Debug, PartialEq, Eq)]
201#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
202pub enum Grant {
203	Jwt(GrantJwt),
204	Record(GrantRecord),
205	Bearer(GrantBearer),
206}
207
208impl Grant {
209	// Returns the type of the grant as a string.
210	pub fn variant(&self) -> &str {
211		match self {
212			Grant::Jwt(_) => "jwt",
213			Grant::Record(_) => "record",
214			Grant::Bearer(_) => "bearer",
215		}
216	}
217}
218
219#[derive(Clone, Debug, PartialEq, Eq)]
220#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
221pub struct GrantJwt {
222	pub jti: Uuid,             // JWT ID
223	pub token: Option<Strand>, // JWT. Will not be stored after being returned.
224}
225
226#[derive(Clone, Debug, PartialEq, Eq)]
227#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
228pub struct GrantRecord {
229	pub rid: Uuid,             // Record ID
230	pub jti: Uuid,             // JWT ID
231	pub token: Option<Strand>, // JWT. Will not be stored after being returned.
232}
233
234#[derive(Clone, Debug, PartialEq, Eq)]
235#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
236pub struct GrantBearer {
237	pub id: Ident, // Key ID
238	// Key. Will not be stored and be returned as redacted.
239	// Immediately after generation, it will contain the plaintext key.
240	// Will be hashed before storage so that the plaintext key is not stored.
241	pub key: Strand,
242}
243
244impl Display for AccessStatement {
245	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
246		match self {
247			Self::Grant(stmt) => {
248				write!(f, "ACCESS {}", stmt.ac)?;
249				if let Some(ref v) = stmt.base {
250					write!(f, " ON {v}")?;
251				}
252				write!(f, " GRANT")?;
253				match &stmt.subject {
254					Subject::User(x) => write!(f, " FOR USER {}", x)?,
255					Subject::Record(x) => write!(f, " FOR RECORD {}", x)?,
256				}
257				Ok(())
258			}
259			Self::Show(stmt) => {
260				write!(f, "ACCESS {}", stmt.ac)?;
261				if let Some(ref v) = stmt.base {
262					write!(f, " ON {v}")?;
263				}
264				write!(f, " SHOW")?;
265				match &stmt.gr {
266					Some(v) => write!(f, " GRANT {v}")?,
267					None => match &stmt.cond {
268						Some(v) => write!(f, " {v}")?,
269						None => write!(f, " ALL")?,
270					},
271				};
272				Ok(())
273			}
274			Self::Revoke(stmt) => {
275				write!(f, "ACCESS {}", stmt.ac)?;
276				if let Some(ref v) = stmt.base {
277					write!(f, " ON {v}")?;
278				}
279				write!(f, " REVOKE")?;
280				match &stmt.gr {
281					Some(v) => write!(f, " GRANT {v}")?,
282					None => match &stmt.cond {
283						Some(v) => write!(f, " {v}")?,
284						None => write!(f, " ALL")?,
285					},
286				};
287				Ok(())
288			}
289			Self::Purge(stmt) => {
290				write!(f, "ACCESS {}", stmt.ac)?;
291				if let Some(ref v) = stmt.base {
292					write!(f, " ON {v}")?;
293				}
294				write!(f, " PURGE")?;
295				match (stmt.expired, stmt.revoked) {
296					(true, false) => write!(f, " EXPIRED")?,
297					(false, true) => write!(f, " REVOKED")?,
298					(true, true) => write!(f, " EXPIRED, REVOKED")?,
299					// This case should not parse.
300					(false, false) => write!(f, " NONE")?,
301				};
302				if !stmt.grace.is_zero() {
303					write!(f, " FOR {}", stmt.grace)?;
304				}
305				Ok(())
306			}
307		}
308	}
309}