1use crate::cnf::MAX_COMPUTATION_DEPTH;
2use crate::dbs::Notification;
3use crate::err::Error;
4use crate::iam::{Action, Auth, ResourceKind};
5use crate::sql::statements::define::{DefineIndexStatement, DefineTableStatement};
6use crate::sql::Base;
7use async_channel::Sender;
8use std::sync::Arc;
9use uuid::Uuid;
10
11#[derive(Clone, Debug)]
20pub struct Options {
21 id: Option<Uuid>,
23 ns: Option<Arc<str>>,
25 db: Option<Arc<str>>,
27 dive: u32,
29 pub(crate) auth: Arc<Auth>,
31 pub(crate) auth_enabled: bool,
33 pub(crate) live: bool,
35 pub(crate) force: Force,
37 pub(crate) perms: bool,
39 pub(crate) strict: bool,
41 pub(crate) import: bool,
43 pub(crate) futures: Futures,
45 pub(crate) version: Option<u64>,
47 pub(crate) sender: Option<Sender<Notification>>,
49}
50
51#[derive(Clone, Debug)]
52#[non_exhaustive]
53pub enum Force {
54 All,
55 None,
56 Table(Arc<[DefineTableStatement]>),
57 Index(Arc<[DefineIndexStatement]>),
58}
59
60#[derive(Copy, Clone, Debug)]
61pub enum Futures {
62 Disabled,
63 Enabled,
64 Never,
65}
66
67impl Default for Options {
68 fn default() -> Self {
69 Options::new()
70 }
71}
72
73impl Options {
74 pub fn new() -> Options {
76 Options {
77 id: None,
78 ns: None,
79 db: None,
80 dive: *MAX_COMPUTATION_DEPTH,
81 live: false,
82 perms: true,
83 force: Force::None,
84 strict: false,
85 import: false,
86 futures: Futures::Disabled,
87 auth_enabled: true,
88 sender: None,
89 auth: Arc::new(Auth::default()),
90 version: None,
91 }
92 }
93
94 pub fn set_ns(&mut self, ns: Option<Arc<str>>) {
99 self.ns = ns
100 }
101
102 pub fn set_db(&mut self, db: Option<Arc<str>>) {
105 self.db = db
106 }
107
108 pub fn with_max_computation_depth(mut self, depth: u32) -> Self {
112 self.dive = depth;
113 self
114 }
115
116 pub fn with_id(mut self, id: Uuid) -> Self {
119 self.id = Some(id);
120 self
121 }
122
123 pub fn with_ns(mut self, ns: Option<Arc<str>>) -> Self {
126 self.ns = ns;
127 self
128 }
129
130 pub fn with_db(mut self, db: Option<Arc<str>>) -> Self {
133 self.db = db;
134 self
135 }
136
137 pub fn with_auth(mut self, auth: Arc<Auth>) -> Self {
140 self.auth = auth;
141 self
142 }
143
144 pub fn with_live(mut self, live: bool) -> Self {
147 self.live = live;
148 self
149 }
150
151 pub fn with_perms(mut self, perms: bool) -> Self {
154 self.perms = perms;
155 self
156 }
157
158 pub fn with_force(mut self, force: Force) -> Self {
160 self.force = force;
161 self
162 }
163
164 pub fn with_strict(mut self, strict: bool) -> Self {
166 self.strict = strict;
167 self
168 }
169
170 pub fn with_import(mut self, import: bool) -> Self {
172 self.set_import(import);
173 self
174 }
175
176 pub fn set_import(&mut self, import: bool) {
178 self.import = import;
179 }
180
181 pub fn with_futures(mut self, futures: bool) -> Self {
183 self.set_futures(futures);
184 self
185 }
186
187 pub fn set_futures(&mut self, futures: bool) {
188 self.futures = match self.futures {
189 Futures::Never => Futures::Never,
190 _ => match futures {
191 true => Futures::Enabled,
192 false => Futures::Disabled,
193 },
194 };
195 }
196
197 pub fn with_futures_never(mut self) -> Self {
199 self.set_futures_never();
200 self
201 }
202
203 pub fn set_futures_never(&mut self) {
205 self.futures = Futures::Never;
206 }
207
208 pub fn with_auth_enabled(mut self, auth_enabled: bool) -> Self {
210 self.auth_enabled = auth_enabled;
211 self
212 }
213
214 pub fn with_version(mut self, version: Option<u64>) -> Self {
216 self.version = version;
217 self
218 }
219
220 pub fn new_with_auth(&self, auth: Arc<Auth>) -> Self {
224 Self {
225 sender: self.sender.clone(),
226 auth,
227 ns: self.ns.clone(),
228 db: self.db.clone(),
229 force: self.force.clone(),
230 perms: self.perms,
231 ..*self
232 }
233 }
234
235 pub fn new_with_perms(&self, perms: bool) -> Self {
237 Self {
238 sender: self.sender.clone(),
239 auth: self.auth.clone(),
240 ns: self.ns.clone(),
241 db: self.db.clone(),
242 force: self.force.clone(),
243 perms,
244 ..*self
245 }
246 }
247
248 pub fn new_with_force(&self, force: Force) -> Self {
250 Self {
251 sender: self.sender.clone(),
252 auth: self.auth.clone(),
253 ns: self.ns.clone(),
254 db: self.db.clone(),
255 force,
256 ..*self
257 }
258 }
259
260 pub fn new_with_strict(&self, strict: bool) -> Self {
262 Self {
263 sender: self.sender.clone(),
264 auth: self.auth.clone(),
265 ns: self.ns.clone(),
266 db: self.db.clone(),
267 force: self.force.clone(),
268 strict,
269 ..*self
270 }
271 }
272
273 pub fn new_with_import(&self, import: bool) -> Self {
275 Self {
276 sender: self.sender.clone(),
277 auth: self.auth.clone(),
278 ns: self.ns.clone(),
279 db: self.db.clone(),
280 force: self.force.clone(),
281 import,
282 ..*self
283 }
284 }
285
286 pub fn new_with_futures(&self, futures: bool) -> Self {
288 Self {
289 sender: self.sender.clone(),
290 auth: self.auth.clone(),
291 ns: self.ns.clone(),
292 db: self.db.clone(),
293 force: self.force.clone(),
294 futures: match self.futures {
295 Futures::Never => Futures::Never,
296 _ => match futures {
297 true => Futures::Enabled,
298 false => Futures::Disabled,
299 },
300 },
301 ..*self
302 }
303 }
304
305 pub fn new_with_sender(&self, sender: Sender<Notification>) -> Self {
307 Self {
308 auth: self.auth.clone(),
309 ns: self.ns.clone(),
310 db: self.db.clone(),
311 force: self.force.clone(),
312 sender: Some(sender),
313 ..*self
314 }
315 }
316
317 pub fn selected_base(&self) -> Result<Base, Error> {
319 match (self.ns.as_ref(), self.db.as_ref()) {
320 (None, None) => Ok(Base::Root),
321 (Some(_), None) => Ok(Base::Ns),
322 (Some(_), Some(_)) => Ok(Base::Db),
323 (None, Some(_)) => Err(Error::NsEmpty),
324 }
325 }
326
327 pub fn dive(&self, cost: u8) -> Result<Self, Error> {
332 if self.dive < cost as u32 {
333 return Err(Error::ComputationDepthExceeded);
334 }
335 Ok(Self {
336 sender: self.sender.clone(),
337 auth: self.auth.clone(),
338 ns: self.ns.clone(),
339 db: self.db.clone(),
340 force: self.force.clone(),
341 dive: self.dive - cost as u32,
342 ..*self
343 })
344 }
345
346 #[inline(always)]
350 pub fn id(&self) -> Result<Uuid, Error> {
351 self.id.ok_or_else(|| fail!("No Node ID is specified"))
352 }
353
354 #[inline(always)]
356 pub fn ns(&self) -> Result<&str, Error> {
357 self.ns.as_deref().ok_or(Error::NsEmpty)
358 }
359
360 #[inline(always)]
362 pub fn db(&self) -> Result<&str, Error> {
363 self.db.as_deref().ok_or(Error::DbEmpty)
364 }
365
366 #[inline(always)]
368 pub fn ns_db(&self) -> Result<(&str, &str), Error> {
369 Ok((self.ns()?, self.db()?))
370 }
371
372 #[inline(always)]
374 pub fn realtime(&self) -> Result<(), Error> {
375 if !self.live {
376 return Err(Error::RealtimeDisabled);
377 }
378 Ok(())
379 }
380
381 #[inline(always)]
383 pub fn valid_for_ns(&self) -> Result<(), Error> {
384 if self.ns.is_none() {
385 return Err(Error::NsEmpty);
386 }
387 Ok(())
388 }
389
390 #[inline(always)]
392 pub fn valid_for_db(&self) -> Result<(), Error> {
393 if self.ns.is_none() {
394 return Err(Error::NsEmpty);
395 }
396 if self.db.is_none() {
397 return Err(Error::DbEmpty);
398 }
399 Ok(())
400 }
401
402 pub fn is_allowed(&self, action: Action, res: ResourceKind, base: &Base) -> Result<(), Error> {
404 let res = match base {
406 Base::Root => res.on_root(),
407 Base::Ns => res.on_ns(self.ns()?),
408 Base::Db => {
409 let (ns, db) = self.ns_db()?;
410 res.on_db(ns, db)
411 }
412 Base::Sc(_) => {
414 return Err(Error::InvalidAuth);
416 }
417 };
418
419 if !self.auth_enabled && self.auth.is_anon() {
421 return Ok(());
422 }
423
424 self.auth.is_allowed(action, &res).map_err(Error::IamError)
425 }
426
427 pub fn check_perms(&self, action: Action) -> Result<bool, Error> {
439 if !self.perms {
441 return Ok(false);
442 }
443 if !self.auth_enabled && self.auth.is_anon() {
445 return Ok(false);
446 }
447 match action {
449 Action::Edit => {
451 let allowed = self.auth.has_editor_role();
453 let (ns, db) = self.ns_db()?;
458 let db_in_actor_level = self.auth.is_root()
459 || self.auth.is_ns_check(ns)
460 || self.auth.is_db_check(ns, db);
461 Ok(!allowed || !db_in_actor_level)
464 }
465 Action::View => {
467 let allowed = self.auth.has_viewer_role();
469 let (ns, db) = self.ns_db()?;
474 let db_in_actor_level = self.auth.is_root()
475 || self.auth.is_ns_check(ns)
476 || self.auth.is_db_check(ns, db);
477 Ok(!allowed || !db_in_actor_level)
480 }
481 }
482 }
483}
484
485#[cfg(test)]
486mod tests {
487
488 use super::*;
489 use crate::iam::Role;
490
491 #[test]
492 fn is_allowed() {
493 {
495 let opts = Options::default().with_auth_enabled(false);
496
497 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Ns).unwrap_err();
499 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Db).unwrap_err();
501 opts.clone()
502 .with_db(Some("db".into()))
503 .is_allowed(Action::View, ResourceKind::Any, &Base::Db)
504 .unwrap_err();
505
506 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Root).unwrap();
508 opts.clone()
510 .with_ns(Some("ns".into()))
511 .is_allowed(Action::View, ResourceKind::Any, &Base::Ns)
512 .unwrap();
513 opts.clone()
515 .with_ns(Some("ns".into()))
516 .with_db(Some("db".into()))
517 .is_allowed(Action::View, ResourceKind::Any, &Base::Db)
518 .unwrap();
519 }
520
521 {
523 let opts = Options::default()
524 .with_auth_enabled(true)
525 .with_auth(Auth::for_root(Role::Owner).into());
526
527 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Ns).unwrap_err();
529 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Db).unwrap_err();
531 opts.clone()
532 .with_db(Some("db".into()))
533 .is_allowed(Action::View, ResourceKind::Any, &Base::Db)
534 .unwrap_err();
535
536 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Root).unwrap();
538 opts.clone()
540 .with_ns(Some("ns".into()))
541 .is_allowed(Action::View, ResourceKind::Any, &Base::Ns)
542 .unwrap();
543 opts.clone()
545 .with_ns(Some("ns".into()))
546 .with_db(Some("db".into()))
547 .is_allowed(Action::View, ResourceKind::Any, &Base::Db)
548 .unwrap();
549 }
550 }
551
552 #[test]
553 pub fn execute_futures() {
554 let mut opts = Options::default().with_futures(false);
555
556 assert!(matches!(opts.futures, Futures::Disabled));
558
559 opts = opts.with_futures(true);
561 assert!(matches!(opts.futures, Futures::Enabled));
562
563 opts = opts.with_futures_never();
565 opts = opts.with_futures(true);
566 assert!(matches!(opts.futures, Futures::Never));
567 }
568}