cosmic_space/
security.rs

1use std::cmp::Ordering;
2use std::collections::{HashMap, HashSet};
3use std::ops;
4use std::ops::{Deref, DerefMut};
5use std::str::FromStr;
6
7use nom::combinator::all_consuming;
8use nom_supreme::parser_ext::MapRes;
9use serde::{Deserialize, Serialize};
10
11use cosmic_nom::new_span;
12
13use crate::err::SpaceErr;
14use crate::point::Point;
15use crate::parse::error::result;
16use crate::parse::{particle_perms, permissions, permissions_mask, privilege, MapResolver};
17use crate::selector::{PointHierarchy, Selector};
18use crate::wave::ScopeGrant;
19use crate::Agent;
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub enum Access {
23    Super,
24    Owner,
25    // in the cases where describing access for an agent that
26    // has both super and is owner
27    SuperOwner,
28    Enumerated(EnumeratedAccess),
29}
30
31impl Access {
32    pub fn has_super(&self) -> bool {
33        match self {
34            Access::Super => true,
35            Access::SuperOwner => true,
36            _ => false,
37        }
38    }
39
40    pub fn has_owner(&self) -> bool {
41        match self {
42            Access::Owner => true,
43            Access::SuperOwner => true,
44            _ => false,
45        }
46    }
47
48    pub fn has_full(&self) -> bool {
49        match self {
50            Access::Super => true,
51            Access::Owner => true,
52            Access::SuperOwner => true,
53            Access::Enumerated(_) => false,
54        }
55    }
56
57    pub fn none() -> Self {
58        Self::Enumerated(EnumeratedAccess::none())
59    }
60
61    pub fn permissions(&self) -> Permissions {
62        match self {
63            Access::Super => Permissions::full(),
64            Access::Owner => Permissions::full(),
65            Access::SuperOwner => Permissions::full(),
66            Access::Enumerated(enumerated) => enumerated.permissions.clone(),
67        }
68    }
69
70    pub fn check_privilege(&self, privilege: &str) -> Result<(), SpaceErr> {
71        match self {
72            Access::Super => Ok(()),
73            Access::Owner => Ok(()),
74            Access::SuperOwner => Ok(()),
75            Access::Enumerated(enumerated) => match enumerated.privileges.has(privilege).is_ok() {
76                true => Ok(()),
77                false => Err(format!("'{}'", privilege).into()),
78            },
79        }
80    }
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub enum Privileges {
85    Full,
86    Enumerated(EnumeratedPrivileges),
87}
88
89impl Privileges {
90    pub fn has(&self, privilege: &str) -> Result<(), ()> {
91        match self {
92            Privileges::Full => Ok(()),
93            Privileges::Enumerated(privileges) => privileges.has(privilege),
94        }
95    }
96
97    pub fn none() -> Self {
98        Self::Enumerated(EnumeratedPrivileges::none())
99    }
100
101    pub fn or(mut self, other: &Self) -> Self {
102        match self {
103            Privileges::Full => self,
104            Privileges::Enumerated(privileges) => match other {
105                Privileges::Full => Privileges::Full,
106                Privileges::Enumerated(other) => Privileges::Enumerated(privileges.or(other)),
107            },
108        }
109    }
110
111    pub fn and(self, other: &Self) -> Privileges {
112        match other {
113            Privileges::Full => self,
114            Privileges::Enumerated(enumerated_other) => match self {
115                Privileges::Full => other.clone(),
116                Privileges::Enumerated(enumerated_self) => {
117                    Privileges::Enumerated(enumerated_self.and(enumerated_other))
118                }
119            },
120        }
121    }
122}
123
124impl ops::BitOr<&Privilege> for &Privileges {
125    type Output = Privileges;
126
127    fn bitor(self, rhs: &Privilege) -> Self::Output {
128        match rhs {
129            Privilege::Full => Privileges::Full,
130            Privilege::Single(p) => match self {
131                Privileges::Full => Privileges::Full,
132                Privileges::Enumerated(enumerated) => {
133                    let mut enumerated = enumerated.clone();
134                    enumerated.set.insert(p.to_string());
135                    Privileges::Enumerated(enumerated)
136                }
137            },
138        }
139    }
140}
141
142impl ops::BitOr<&Privilege> for Privileges {
143    type Output = Privileges;
144
145    fn bitor(self, rhs: &Privilege) -> Self::Output {
146        match rhs {
147            Privilege::Full => Privileges::Full,
148            Privilege::Single(p) => match self {
149                Privileges::Full => Privileges::Full,
150                Privileges::Enumerated(enumerated) => {
151                    let mut enumerated = enumerated.clone();
152                    enumerated.set.insert(p.to_string());
153                    Privileges::Enumerated(enumerated)
154                }
155            },
156        }
157    }
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct EnumeratedPrivileges {
162    set: HashSet<String>,
163}
164
165impl EnumeratedPrivileges {
166    pub fn new() -> Self {
167        Self {
168            set: HashSet::new(),
169        }
170    }
171
172    pub fn none() -> Self {
173        Self {
174            set: HashSet::new(),
175        }
176    }
177
178    pub fn or(mut self, other: &Self) -> Self {
179        for p in other.set.iter() {
180            if self.has(p).is_err() {
181                self.add(p.as_str());
182            }
183        }
184        self
185    }
186
187    pub fn and(mut self, other: &Self) -> Self {
188        self.set.retain(|p| other.has(p).is_ok());
189        self
190    }
191
192    pub fn add(&mut self, privilege: &str) {
193        self.set.insert(privilege.to_string());
194    }
195
196    pub fn has(&self, privilege: &str) -> Result<(), ()> {
197        let privilege = privilege.to_string();
198        if self.set.contains(&privilege) {
199            Ok(())
200        } else {
201            Err(())
202        }
203    }
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
207pub enum Privilege {
208    Full,
209    Single(String),
210}
211
212impl ToString for Privilege {
213    fn to_string(&self) -> String {
214        match self {
215            Privilege::Full => "*".to_string(),
216            Privilege::Single(name) => name.clone(),
217        }
218    }
219}
220
221impl FromStr for Privilege {
222    type Err = SpaceErr;
223
224    fn from_str(s: &str) -> Result<Self, Self::Err> {
225        let span = new_span(s);
226        Ok(result(all_consuming(privilege)(span))?)
227    }
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct EnumeratedAccess {
232    pub permissions: Permissions,
233    pub privileges: Privileges,
234}
235
236impl EnumeratedAccess {
237    pub fn mask(&mut self, scope_grant: &ScopeGrant) {}
238
239    pub fn full() -> Self {
240        Self {
241            permissions: Permissions::full(),
242            privileges: Privileges::Full,
243        }
244    }
245
246    pub fn none() -> Self {
247        Self {
248            permissions: Permissions::none(),
249            privileges: Privileges::none(),
250        }
251    }
252
253    pub fn and(&mut self, access: &Self) {
254        self.permissions.and(&access.permissions);
255        self.privileges = self.privileges.clone().and(&access.privileges);
256    }
257
258    pub fn clear_privs(&mut self) {
259        self.privileges = Privileges::none()
260    }
261
262    pub fn add(&mut self, grant: &AccessGrant) {
263        match &grant.kind {
264            AccessGrantKindDef::Super => {
265                // we can't mask Super with Enumerated... it does nothing
266            }
267            AccessGrantKindDef::Privilege(prv) => {
268                self.privileges = self.privileges.clone() | prv;
269            }
270            AccessGrantKindDef::PermissionsMask(mask) => match mask.kind {
271                PermissionsMaskKind::Or => self.permissions.or(&mask.permissions),
272                PermissionsMaskKind::And => self.permissions.and(&mask.permissions),
273            },
274        }
275    }
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
279pub struct PermissionsMask {
280    pub kind: PermissionsMaskKind,
281    pub permissions: Permissions,
282}
283
284impl FromStr for PermissionsMask {
285    type Err = SpaceErr;
286
287    fn from_str(s: &str) -> Result<Self, Self::Err> {
288        let s = new_span(s);
289        Ok(result(all_consuming(permissions_mask)(s))?)
290    }
291}
292
293impl ToString for PermissionsMask {
294    fn to_string(&self) -> String {
295        match self.kind {
296            PermissionsMaskKind::Or => format!("+{}", self.permissions.to_string()),
297            PermissionsMaskKind::And => format!("&{}", self.permissions.to_string()),
298        }
299    }
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
303pub struct Permissions {
304    pub child: ChildPerms,
305    pub particle: ParticlePerms,
306}
307
308impl FromStr for Permissions {
309    type Err = SpaceErr;
310
311    fn from_str(s: &str) -> Result<Self, Self::Err> {
312        result(permissions(new_span(s)))
313    }
314}
315
316impl Permissions {
317    pub fn full() -> Self {
318        Self {
319            child: ChildPerms::full(),
320            particle: ParticlePerms::full(),
321        }
322    }
323
324    pub fn none() -> Self {
325        Self {
326            child: ChildPerms::none(),
327            particle: ParticlePerms::none(),
328        }
329    }
330
331    pub fn or(&mut self, permissions: &Permissions) {
332        self.child.or(&permissions.child);
333        self.particle.or(&permissions.particle);
334    }
335
336    pub fn and(&mut self, permissions: &Permissions) {
337        self.child.and(&permissions.child);
338        self.particle.and(&permissions.particle);
339    }
340}
341
342impl ToString for Permissions {
343    fn to_string(&self) -> String {
344        format!("{}-{}", self.child.to_string(), self.particle.to_string())
345    }
346}
347
348#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
349pub struct ChildPerms {
350    pub create: bool,
351    pub select: bool,
352    pub delete: bool,
353}
354
355impl ChildPerms {
356    pub fn full() -> Self {
357        Self {
358            create: true,
359            select: true,
360            delete: true,
361        }
362    }
363
364    pub fn none() -> Self {
365        Self {
366            create: false,
367            select: false,
368            delete: false,
369        }
370    }
371
372    pub fn or(&mut self, block: &ChildPerms) {
373        self.create |= block.create;
374        self.select |= block.select;
375        self.delete |= block.delete;
376    }
377
378    pub fn and(&mut self, block: &ChildPerms) {
379        self.create &= block.create;
380        self.select &= block.select;
381        self.delete &= block.delete;
382    }
383}
384
385impl ToString for ChildPerms {
386    fn to_string(&self) -> String {
387        let mut rtn = String::new();
388
389        if self.create {
390            rtn.push_str("C");
391        } else {
392            rtn.push_str("c");
393        }
394
395        if self.select {
396            rtn.push_str("S");
397        } else {
398            rtn.push_str("s");
399        }
400
401        if self.delete {
402            rtn.push_str("D");
403        } else {
404            rtn.push_str("d");
405        }
406
407        rtn
408    }
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
412pub struct ParticlePerms {
413    pub read: bool,
414    pub write: bool,
415    pub execute: bool,
416}
417
418impl ParticlePerms {
419    pub fn full() -> Self {
420        Self {
421            read: true,
422            write: true,
423            execute: true,
424        }
425    }
426
427    pub fn none() -> Self {
428        Self {
429            read: false,
430            write: false,
431            execute: false,
432        }
433    }
434
435    pub fn or(&mut self, block: &ParticlePerms) {
436        self.read |= block.read;
437        self.write |= block.write;
438        self.execute |= block.execute;
439    }
440
441    pub fn and(&mut self, block: &ParticlePerms) {
442        self.read &= block.read;
443        self.write &= block.write;
444        self.execute &= block.execute;
445    }
446}
447
448impl FromStr for ParticlePerms {
449    type Err = SpaceErr;
450
451    fn from_str(s: &str) -> Result<Self, Self::Err> {
452        let s = new_span(s);
453        Ok(result(all_consuming(particle_perms)(s))?)
454    }
455}
456
457impl ToString for ParticlePerms {
458    fn to_string(&self) -> String {
459        let mut rtn = String::new();
460
461        if self.read {
462            rtn.push_str("R");
463        } else {
464            rtn.push_str("r");
465        }
466
467        if self.write {
468            rtn.push_str("W");
469        } else {
470            rtn.push_str("w");
471        }
472
473        if self.execute {
474            rtn.push_str("X");
475        } else {
476            rtn.push_str("x");
477        }
478
479        rtn
480    }
481}
482
483#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
484pub enum PermissionsMaskKind {
485    Or,
486    And,
487}
488
489#[derive(Debug, Clone, Serialize, Deserialize)]
490pub struct AccessGrantDef<Priv, PermMask, PointSelector, Point> {
491    pub kind: AccessGrantKindDef<Priv, PermMask>,
492    pub on_point: PointSelector,
493    pub to_point: PointSelector,
494    pub by_particle: Point,
495}
496
497pub type GrantTo = GrantToDef<Selector>;
498pub enum GrantToDef<PointSelector> {
499    World,
500    PointSelector(PointSelector),
501}
502
503impl GrantTo {
504    pub fn is_match(&self, hierarchy: &PointHierarchy) -> Result<(), ()> {
505        match self {
506            GrantTo::World => Ok(()),
507            GrantTo::PointSelector(selector) => match selector.matches(hierarchy) {
508                true => Ok(()),
509                false => Err(()),
510            },
511        }
512    }
513}
514
515pub type AccessGrant = AccessGrantDef<Privilege, PermissionsMask, Selector, Point>;
516pub type AccessGrantKind = AccessGrantKindDef<Privilege, PermissionsMask>;
517
518#[derive(Debug, Clone, Serialize, Deserialize)]
519pub enum AccessGrantKindDef<Priv, PermMask> {
520    Super,
521    Privilege(Priv),
522    PermissionsMask(PermMask),
523}
524
525impl<Priv, PermMask> ToString for AccessGrantKindDef<Priv, PermMask> {
526    fn to_string(&self) -> String {
527        match self {
528            AccessGrantKindDef::Super => "super".to_string(),
529            AccessGrantKindDef::Privilege(_) => "priv".to_string(),
530            AccessGrantKindDef::PermissionsMask(_) => "perm".to_string(),
531        }
532    }
533}
534
535impl Ord for IndexedAccessGrant {
536    fn cmp(&self, other: &Self) -> Ordering {
537        if self.id < other.id {
538            Ordering::Greater
539        } else if self.id < other.id {
540            Ordering::Less
541        } else {
542            Ordering::Equal
543        }
544    }
545}
546
547#[derive(Debug, Clone)]
548pub struct IndexedAccessGrant {
549    pub id: i32,
550    pub access_grant: AccessGrant,
551}
552
553impl Eq for IndexedAccessGrant {}
554
555impl PartialEq<Self> for IndexedAccessGrant {
556    fn eq(&self, other: &Self) -> bool {
557        self.id == other.id
558    }
559}
560
561impl PartialOrd<Self> for IndexedAccessGrant {
562    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
563        if self.id < other.id {
564            Some(Ordering::Greater)
565        } else if self.id < other.id {
566            Some(Ordering::Less)
567        } else {
568            Some(Ordering::Equal)
569        }
570    }
571}
572
573impl Deref for IndexedAccessGrant {
574    type Target = AccessGrant;
575
576    fn deref(&self) -> &Self::Target {
577        &self.access_grant
578    }
579}
580
581impl Into<AccessGrant> for IndexedAccessGrant {
582    fn into(self) -> AccessGrant {
583        self.access_grant
584    }
585}
586
587pub trait AccessProvider: Send + Sync {
588    fn access(&self, to: &Agent, on: &Point) -> Result<Access, SpaceErr>;
589}
590
591pub struct AllAccessProvider();
592
593impl AccessProvider for AllAccessProvider {
594    fn access(&self, _: &Agent, _: &Point) -> Result<Access, SpaceErr> {
595        Ok(Access::SuperOwner)
596    }
597}