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::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}
58
59#[derive(Copy, Clone, Debug)]
60pub enum Futures {
61 Disabled,
62 Enabled,
63 Never,
64}
65
66impl Default for Options {
67 fn default() -> Self {
68 Options::new()
69 }
70}
71
72impl Options {
73 pub fn new() -> Options {
75 Options {
76 id: None,
77 ns: None,
78 db: None,
79 dive: *MAX_COMPUTATION_DEPTH,
80 live: false,
81 perms: true,
82 force: Force::None,
83 strict: false,
84 import: false,
85 futures: Futures::Disabled,
86 auth_enabled: true,
87 sender: None,
88 auth: Arc::new(Auth::default()),
89 version: None,
90 }
91 }
92
93 pub fn set_ns(&mut self, ns: Option<Arc<str>>) {
98 self.ns = ns
99 }
100
101 pub fn set_db(&mut self, db: Option<Arc<str>>) {
104 self.db = db
105 }
106
107 pub fn with_max_computation_depth(mut self, depth: u32) -> Self {
111 self.dive = depth;
112 self
113 }
114
115 pub fn with_id(mut self, id: Uuid) -> Self {
118 self.id = Some(id);
119 self
120 }
121
122 pub fn with_ns(mut self, ns: Option<Arc<str>>) -> Self {
125 self.ns = ns;
126 self
127 }
128
129 pub fn with_db(mut self, db: Option<Arc<str>>) -> Self {
132 self.db = db;
133 self
134 }
135
136 pub fn with_auth(mut self, auth: Arc<Auth>) -> Self {
139 self.auth = auth;
140 self
141 }
142
143 pub fn with_live(mut self, live: bool) -> Self {
146 self.live = live;
147 self
148 }
149
150 pub fn with_perms(mut self, perms: bool) -> Self {
153 self.perms = perms;
154 self
155 }
156
157 pub fn with_force(mut self, force: Force) -> Self {
159 self.force = force;
160 self
161 }
162
163 pub fn with_strict(mut self, strict: bool) -> Self {
165 self.strict = strict;
166 self
167 }
168
169 pub fn with_import(mut self, import: bool) -> Self {
171 self.set_import(import);
172 self
173 }
174
175 pub fn set_import(&mut self, import: bool) {
177 self.import = import;
178 }
179
180 pub fn with_futures(mut self, futures: bool) -> Self {
182 self.set_futures(futures);
183 self
184 }
185
186 pub fn set_futures(&mut self, futures: bool) {
187 self.futures = match self.futures {
188 Futures::Never => Futures::Never,
189 _ => match futures {
190 true => Futures::Enabled,
191 false => Futures::Disabled,
192 },
193 };
194 }
195
196 pub fn with_futures_never(mut self) -> Self {
198 self.set_futures_never();
199 self
200 }
201
202 pub fn set_futures_never(&mut self) {
204 self.futures = Futures::Never;
205 }
206
207 pub fn with_auth_enabled(mut self, auth_enabled: bool) -> Self {
209 self.auth_enabled = auth_enabled;
210 self
211 }
212
213 pub fn with_version(mut self, version: Option<u64>) -> Self {
215 self.version = version;
216 self
217 }
218
219 pub fn new_with_auth(&self, auth: Arc<Auth>) -> Self {
223 Self {
224 sender: self.sender.clone(),
225 auth,
226 ns: self.ns.clone(),
227 db: self.db.clone(),
228 force: self.force.clone(),
229 perms: self.perms,
230 ..*self
231 }
232 }
233
234 pub fn new_with_perms(&self, perms: bool) -> Self {
236 Self {
237 sender: self.sender.clone(),
238 auth: self.auth.clone(),
239 ns: self.ns.clone(),
240 db: self.db.clone(),
241 force: self.force.clone(),
242 perms,
243 ..*self
244 }
245 }
246
247 pub fn new_with_force(&self, force: Force) -> Self {
249 Self {
250 sender: self.sender.clone(),
251 auth: self.auth.clone(),
252 ns: self.ns.clone(),
253 db: self.db.clone(),
254 force,
255 ..*self
256 }
257 }
258
259 pub fn new_with_strict(&self, strict: bool) -> Self {
261 Self {
262 sender: self.sender.clone(),
263 auth: self.auth.clone(),
264 ns: self.ns.clone(),
265 db: self.db.clone(),
266 force: self.force.clone(),
267 strict,
268 ..*self
269 }
270 }
271
272 pub fn new_with_import(&self, import: bool) -> Self {
274 Self {
275 sender: self.sender.clone(),
276 auth: self.auth.clone(),
277 ns: self.ns.clone(),
278 db: self.db.clone(),
279 force: self.force.clone(),
280 import,
281 ..*self
282 }
283 }
284
285 pub fn new_with_futures(&self, futures: bool) -> Self {
287 Self {
288 sender: self.sender.clone(),
289 auth: self.auth.clone(),
290 ns: self.ns.clone(),
291 db: self.db.clone(),
292 force: self.force.clone(),
293 futures: match self.futures {
294 Futures::Never => Futures::Never,
295 _ => match futures {
296 true => Futures::Enabled,
297 false => Futures::Disabled,
298 },
299 },
300 ..*self
301 }
302 }
303
304 pub fn new_with_sender(&self, sender: Sender<Notification>) -> Self {
306 Self {
307 auth: self.auth.clone(),
308 ns: self.ns.clone(),
309 db: self.db.clone(),
310 force: self.force.clone(),
311 sender: Some(sender),
312 ..*self
313 }
314 }
315
316 pub fn selected_base(&self) -> Result<Base, Error> {
318 match (self.ns.as_ref(), self.db.as_ref()) {
319 (None, None) => Ok(Base::Root),
320 (Some(_), None) => Ok(Base::Ns),
321 (Some(_), Some(_)) => Ok(Base::Db),
322 (None, Some(_)) => Err(Error::NsEmpty),
323 }
324 }
325
326 pub fn dive(&self, cost: u8) -> Result<Self, Error> {
331 if self.dive < cost as u32 {
332 return Err(Error::ComputationDepthExceeded);
333 }
334 Ok(Self {
335 sender: self.sender.clone(),
336 auth: self.auth.clone(),
337 ns: self.ns.clone(),
338 db: self.db.clone(),
339 force: self.force.clone(),
340 dive: self.dive - cost as u32,
341 ..*self
342 })
343 }
344
345 #[inline(always)]
349 pub fn id(&self) -> Result<Uuid, Error> {
350 self.id.ok_or_else(|| fail!("No Node ID is specified"))
351 }
352
353 #[inline(always)]
355 pub fn ns(&self) -> Result<&str, Error> {
356 self.ns.as_deref().ok_or(Error::NsEmpty)
357 }
358
359 #[inline(always)]
361 pub fn db(&self) -> Result<&str, Error> {
362 self.db.as_deref().ok_or(Error::DbEmpty)
363 }
364
365 #[inline(always)]
367 pub fn ns_db(&self) -> Result<(&str, &str), Error> {
368 Ok((self.ns()?, self.db()?))
369 }
370
371 #[inline(always)]
373 pub fn realtime(&self) -> Result<(), Error> {
374 if !self.live {
375 return Err(Error::RealtimeDisabled);
376 }
377 Ok(())
378 }
379
380 #[inline(always)]
382 pub fn valid_for_ns(&self) -> Result<(), Error> {
383 if self.ns.is_none() {
384 return Err(Error::NsEmpty);
385 }
386 Ok(())
387 }
388
389 #[inline(always)]
391 pub fn valid_for_db(&self) -> Result<(), Error> {
392 if self.ns.is_none() {
393 return Err(Error::NsEmpty);
394 }
395 if self.db.is_none() {
396 return Err(Error::DbEmpty);
397 }
398 Ok(())
399 }
400
401 pub fn is_allowed(&self, action: Action, res: ResourceKind, base: &Base) -> Result<(), Error> {
403 let res = match base {
405 Base::Root => res.on_root(),
406 Base::Ns => res.on_ns(self.ns()?),
407 Base::Db => {
408 let (ns, db) = self.ns_db()?;
409 res.on_db(ns, db)
410 }
411 Base::Sc(_) => {
413 return Err(Error::InvalidAuth);
415 }
416 };
417
418 if !self.auth_enabled && self.auth.is_anon() {
420 return Ok(());
421 }
422
423 self.auth.is_allowed(action, &res).map_err(Error::IamError)
424 }
425
426 pub fn check_perms(&self, action: Action) -> Result<bool, Error> {
438 if !self.perms {
440 return Ok(false);
441 }
442 if !self.auth_enabled && self.auth.is_anon() {
444 return Ok(false);
445 }
446 match action {
448 Action::Edit => {
450 let allowed = self.auth.has_editor_role();
452 let (ns, db) = self.ns_db()?;
457 let db_in_actor_level = self.auth.is_root()
458 || self.auth.is_ns_check(ns)
459 || self.auth.is_db_check(ns, db);
460 Ok(!allowed || !db_in_actor_level)
463 }
464 Action::View => {
466 let allowed = self.auth.has_viewer_role();
468 let (ns, db) = self.ns_db()?;
473 let db_in_actor_level = self.auth.is_root()
474 || self.auth.is_ns_check(ns)
475 || self.auth.is_db_check(ns, db);
476 Ok(!allowed || !db_in_actor_level)
479 }
480 }
481 }
482}
483
484#[cfg(test)]
485mod tests {
486
487 use super::*;
488 use crate::iam::Role;
489
490 #[test]
491 fn is_allowed() {
492 {
494 let opts = Options::default().with_auth_enabled(false);
495
496 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Ns).unwrap_err();
498 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Db).unwrap_err();
500 opts.clone()
501 .with_db(Some("db".into()))
502 .is_allowed(Action::View, ResourceKind::Any, &Base::Db)
503 .unwrap_err();
504
505 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Root).unwrap();
507 opts.clone()
509 .with_ns(Some("ns".into()))
510 .is_allowed(Action::View, ResourceKind::Any, &Base::Ns)
511 .unwrap();
512 opts.clone()
514 .with_ns(Some("ns".into()))
515 .with_db(Some("db".into()))
516 .is_allowed(Action::View, ResourceKind::Any, &Base::Db)
517 .unwrap();
518 }
519
520 {
522 let opts = Options::default()
523 .with_auth_enabled(true)
524 .with_auth(Auth::for_root(Role::Owner).into());
525
526 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Ns).unwrap_err();
528 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Db).unwrap_err();
530 opts.clone()
531 .with_db(Some("db".into()))
532 .is_allowed(Action::View, ResourceKind::Any, &Base::Db)
533 .unwrap_err();
534
535 opts.is_allowed(Action::View, ResourceKind::Any, &Base::Root).unwrap();
537 opts.clone()
539 .with_ns(Some("ns".into()))
540 .is_allowed(Action::View, ResourceKind::Any, &Base::Ns)
541 .unwrap();
542 opts.clone()
544 .with_ns(Some("ns".into()))
545 .with_db(Some("db".into()))
546 .is_allowed(Action::View, ResourceKind::Any, &Base::Db)
547 .unwrap();
548 }
549 }
550
551 #[test]
552 pub fn execute_futures() {
553 let mut opts = Options::default().with_futures(false);
554
555 assert!(matches!(opts.futures, Futures::Disabled));
557
558 opts = opts.with_futures(true);
560 assert!(matches!(opts.futures, Futures::Enabled));
561
562 opts = opts.with_futures_never();
564 opts = opts.with_futures(true);
565 assert!(matches!(opts.futures, Futures::Never));
566 }
567}