1use crate::value::to_value;
2use crate::{is_str_any, is_str_wildcard, EResult, Error, ItemKind, Value, OID};
3use crate::{OID_MASK_PREFIX_FORMULA, OID_MASK_PREFIX_REGEX};
4use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
5use std::cmp::Ordering;
6use std::collections::{hash_set, HashSet};
7use std::convert::TryFrom;
8use std::fmt;
9use std::hash::{Hash, Hasher};
10use std::str::FromStr;
11use submap::AclMap;
12
13static ERR_INVALID_OID_MASK: &str = "Invalid OID mask format";
14static ERR_PATH_MASK_EMPTY: &str = "Empty path mask";
15static ERR_INVALID_OID_MASK_OP: &str = "Invalid OID mask for this op";
16
17#[inline]
18pub fn create_acl_map() -> AclMap {
19 AclMap::new()
20 .separator('/')
21 .wildcard_multiple(crate::WILDCARD)
22 .match_any_multiple(crate::MATCH_ANY)
23 .formula_prefix(OID_MASK_PREFIX_FORMULA)
24 .regex_prefix(OID_MASK_PREFIX_REGEX)
25}
26
27#[derive(Debug, Clone, Eq)]
28pub struct PathMask {
29 chunks: Option<Vec<String>>,
30}
31
32impl PathMask {
33 #[inline]
34 fn new_any() -> Self {
35 Self { chunks: None }
36 }
37 #[inline]
38 fn is_any(&self) -> bool {
39 self.chunks.is_none()
40 }
41 fn matches_split(&self, path_split: &mut std::str::Split<'_, char>) -> bool {
42 if let Some(ref chunks) = self.chunks {
43 let mut s_m = chunks.iter();
44 loop {
45 if let Some(i_chunk) = path_split.next() {
46 if let Some(m_chunk) = s_m.next() {
47 if is_str_wildcard(m_chunk) {
48 return true;
49 }
50 if !is_str_any(m_chunk) && i_chunk != m_chunk {
51 return false;
52 }
53 } else {
54 return false;
55 }
56 } else {
57 return s_m.next().is_none();
58 }
59 }
60 } else {
61 true
62 }
63 }
64}
65
66impl AsRef<PathMask> for PathMask {
67 fn as_ref(&self) -> &PathMask {
68 self
69 }
70}
71
72impl<'de> Deserialize<'de> for PathMask {
73 fn deserialize<D>(deserializer: D) -> Result<PathMask, D::Error>
74 where
75 D: Deserializer<'de>,
76 {
77 deserializer.deserialize_unit(PathMaskVisitor)
78 }
79}
80
81struct PathMaskVisitor;
82impl serde::de::Visitor<'_> for PathMaskVisitor {
83 type Value = PathMask;
84 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
85 formatter.write_str("a string-packed path mask")
86 }
87 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
88 where
89 E: serde::de::Error,
90 {
91 value
92 .parse()
93 .map_err(|e| E::custom(format!("{}: {}", e, value)))
94 }
95 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
96 where
97 E: serde::de::Error,
98 {
99 value
100 .parse()
101 .map_err(|e| E::custom(format!("{}: {}", e, value)))
102 }
103}
104
105#[derive(Debug, Clone, Default)]
106pub struct PathMaskList {
107 acl_map: AclMap,
108}
109
110impl Serialize for PathMaskList {
111 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
112 where
113 S: Serializer,
114 {
115 let path_masks = self.acl_map.list();
116 let mut seq = serializer.serialize_seq(Some(path_masks.len()))?;
117 for el in path_masks {
118 seq.serialize_element(el)?;
119 }
120 seq.end()
121 }
122}
123
124impl<'de> Deserialize<'de> for PathMaskList {
125 fn deserialize<D>(deserializer: D) -> Result<PathMaskList, D::Error>
126 where
127 D: Deserializer<'de>,
128 {
129 let masks: Vec<String> = Deserialize::deserialize(deserializer)?;
130 Ok(PathMaskList::from_string_list(&masks))
131 }
132}
133
134impl From<PathMaskList> for Value {
135 fn from(v: PathMaskList) -> Value {
136 to_value(v).unwrap()
137 }
138}
139
140impl TryFrom<Value> for PathMaskList {
141 type Error = Error;
142 fn try_from(value: Value) -> EResult<PathMaskList> {
143 match value {
144 Value::Seq(_) => {
145 let masks: Vec<String> = value.deserialize_into()?;
146 Ok(PathMaskList::from_string_list(&masks))
147 }
148 Value::String(s) => {
149 if s.is_empty() {
150 Ok(<_>::default())
151 } else {
152 Ok(PathMaskList::from_str_list(
153 &s.split(',').collect::<Vec<_>>(),
154 ))
155 }
156 }
157 _ => Err(Error::invalid_data("Expected vec or string")),
158 }
159 }
160}
161
162impl PathMaskList {
163 pub fn from_str_list(s_masks: &[&str]) -> Self {
164 let mut acl_map = create_acl_map();
165 for s in s_masks {
166 if !s.is_empty() {
167 acl_map.insert(s);
168 }
169 }
170 Self { acl_map }
171 }
172 pub fn from_string_list(s_masks: &[String]) -> Self {
173 let mut acl_map = create_acl_map();
174 for s in s_masks {
175 if !s.is_empty() {
176 acl_map.insert(s);
177 }
178 }
179 Self { acl_map }
180 }
181 #[inline]
182 pub fn matches(&self, path: &str) -> bool {
183 self.acl_map.matches(path)
184 }
185 pub fn is_empty(&self) -> bool {
186 self.acl_map.is_empty()
187 }
188}
189
190impl AsRef<PathMaskList> for PathMaskList {
191 fn as_ref(&self) -> &PathMaskList {
192 self
193 }
194}
195
196impl PartialEq for PathMask {
197 fn eq(&self, other: &Self) -> bool {
198 self.chunks == other.chunks
199 }
200}
201
202impl Ord for PathMask {
203 fn cmp(&self, other: &Self) -> Ordering {
204 self.chunks.cmp(&other.chunks)
205 }
206}
207
208impl Hash for PathMask {
209 fn hash<H: Hasher>(&self, hasher: &mut H) {
210 self.chunks.hash(hasher);
211 }
212}
213
214impl PartialOrd for PathMask {
215 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
216 Some(self.cmp(other))
217 }
218}
219
220impl fmt::Display for PathMask {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 if let Some(ref chunks) = self.chunks {
223 write!(f, "{}", chunks.join("/"))
224 } else {
225 write!(f, "#")
226 }
227 }
228}
229
230impl FromStr for PathMask {
231 type Err = Error;
232 fn from_str(s: &str) -> Result<Self, Self::Err> {
233 if s.is_empty() {
234 Err(Error::invalid_data(ERR_PATH_MASK_EMPTY))
235 } else if is_str_wildcard(s) {
236 Ok(Self::new_any())
237 } else {
238 let mut chunks = Vec::new();
239 for chunk in s.split('/') {
240 if is_str_wildcard(chunk) {
241 chunks.push("#".to_owned());
242 break;
243 }
244 chunks.push(chunk.to_owned());
245 }
246 Ok(Self {
247 chunks: Some(chunks),
248 })
249 }
250 }
251}
252
253#[derive(Debug, Clone, Default)]
254pub struct OIDMaskList {
255 oid_masks: HashSet<OIDMask>,
256 acl_map: AclMap,
257}
258
259impl PartialEq for OIDMaskList {
260 fn eq(&self, other: &Self) -> bool {
261 self.oid_masks == other.oid_masks
262 }
263}
264
265impl Eq for OIDMaskList {}
266
267impl Serialize for OIDMaskList {
268 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
269 where
270 S: Serializer,
271 {
272 let mut seq = serializer.serialize_seq(Some(self.oid_masks.len()))?;
273 for element in &self.oid_masks {
274 seq.serialize_element(&element.to_string())?;
275 }
276 seq.end()
277 }
278}
279
280impl<'de> Deserialize<'de> for OIDMaskList {
281 fn deserialize<D>(deserializer: D) -> Result<OIDMaskList, D::Error>
282 where
283 D: Deserializer<'de>,
284 {
285 let masks: HashSet<OIDMask> = Deserialize::deserialize(deserializer)?;
286 Ok(OIDMaskList::new(masks))
287 }
288}
289
290impl FromIterator<OIDMask> for OIDMaskList {
291 fn from_iter<I>(masks: I) -> Self
292 where
293 I: IntoIterator<Item = OIDMask>,
294 {
295 let mut s: HashSet<OIDMask> = HashSet::new();
296 for mask in masks {
297 s.insert(mask);
298 }
299 Self::new(s)
300 }
301}
302
303impl OIDMaskList {
304 #[inline]
305 pub fn new(oid_masks: HashSet<OIDMask>) -> Self {
306 let mut acl_map = create_acl_map();
307 for mask in &oid_masks {
308 acl_map.insert(&mask.as_path());
309 }
310 Self { oid_masks, acl_map }
311 }
312 #[inline]
313 pub fn new0(oid_mask: OIDMask) -> Self {
314 let mut acl_map = create_acl_map();
315 acl_map.insert(&oid_mask.as_path());
316 let mut oid_masks = HashSet::new();
317 oid_masks.insert(oid_mask);
318 Self { oid_masks, acl_map }
319 }
320 #[inline]
321 pub fn new_any() -> Self {
322 let mut acl_map = create_acl_map();
323 acl_map.insert(crate::WILDCARD[0]);
324 let mut oid_masks = HashSet::new();
325 oid_masks.insert(OIDMask::new_any());
326 Self { oid_masks, acl_map }
327 }
328 pub fn from_str_list(s_masks: &[&str]) -> EResult<Self> {
329 let mut oid_masks = HashSet::new();
330 for s in s_masks {
331 oid_masks.insert(s.parse()?);
332 }
333 Ok(Self::new(oid_masks))
334 }
335 pub fn from_string_list(s_masks: &[String]) -> EResult<Self> {
336 let mut oid_masks = HashSet::new();
337 for s in s_masks {
338 oid_masks.insert(s.parse()?);
339 }
340 Ok(Self::new(oid_masks))
341 }
342 #[inline]
343 pub fn matches(&self, oid: &OID) -> bool {
344 self.acl_map.matches(oid.as_path())
345 }
346 #[inline]
347 pub fn matches_mask(&self, mask: &OIDMask) -> bool {
348 self.acl_map.matches(&mask.as_path())
349 }
350 #[inline]
351 pub fn is_empty(&self) -> bool {
352 self.oid_masks.is_empty()
353 }
354 #[inline]
355 pub fn oid_masks(&self) -> &HashSet<OIDMask> {
356 &self.oid_masks
357 }
358 #[inline]
359 pub fn oid_masks_mut(&mut self) -> &mut HashSet<OIDMask> {
360 &mut self.oid_masks
361 }
362 #[inline]
363 pub fn as_string_vec(&self) -> Vec<String> {
364 self.oid_masks.iter().map(ToString::to_string).collect()
365 }
366 pub fn try_from_iter<I, T>(values: I) -> EResult<Self>
367 where
368 I: IntoIterator<Item = T>,
369 T: TryInto<OIDMask, Error = Error>,
370 {
371 let mut res = HashSet::new();
372 for v in values {
373 let mask: OIDMask = v.try_into()?;
374 res.insert(mask);
375 }
376 Ok(Self::new(res))
377 }
378 pub fn iter(&self) -> hash_set::Iter<'_, OIDMask> {
379 <&Self as IntoIterator>::into_iter(self)
380 }
381}
382
383impl<'a> IntoIterator for &'a OIDMaskList {
384 type Item = &'a OIDMask;
385 type IntoIter = hash_set::Iter<'a, OIDMask>;
386
387 fn into_iter(self) -> Self::IntoIter {
388 self.oid_masks.iter()
389 }
390}
391
392impl IntoIterator for OIDMaskList {
393 type Item = OIDMask;
394 type IntoIter = hash_set::IntoIter<Self::Item>;
395
396 fn into_iter(self) -> Self::IntoIter {
397 self.oid_masks.into_iter()
398 }
399}
400
401impl AsRef<OIDMaskList> for OIDMaskList {
402 fn as_ref(&self) -> &OIDMaskList {
403 self
404 }
405}
406
407#[derive(Debug, Clone, Eq)]
408pub struct OIDMask {
409 kind: Option<ItemKind>,
410 path: PathMask,
411}
412
413impl OIDMask {
414 #[inline]
415 fn check(s: &str) -> EResult<()> {
416 if s.len() > 65000 {
417 return Err(Error::invalid_data("OID mask too long"));
418 }
419 for c in s.chars() {
420 if !(c.is_alphanumeric() || crate::OID_MASK_ALLOWED_SYMBOLS.contains(c) || c == '/') {
421 return Err(Error::invalid_data(format!(
422 "Invalid symbol in OID mask: {}",
423 c
424 )));
425 }
426 }
427 Ok(())
428 }
429 #[inline]
430 pub fn kind(&self) -> Option<ItemKind> {
431 self.kind
432 }
433 #[inline]
438 pub fn to_wildcard_oid(&self) -> EResult<OID> {
439 if let Some(kind) = self.kind {
440 if let Some(ref ch) = self.path.chunks {
441 for (i, p) in ch.iter().enumerate() {
442 if is_str_any(p) || (is_str_wildcard(p) && i < p.len()) {
443 return Err(Error::invalid_data(ERR_INVALID_OID_MASK_OP));
444 }
445 }
446 }
447 Ok(OID::new0_unchecked(kind, &self.path.to_string())?)
448 } else {
449 Err(Error::invalid_data(ERR_INVALID_OID_MASK_OP))
450 }
451 }
452 fn parse_oid_mask(s: &str, c: char) -> EResult<Self> {
453 if is_str_wildcard(s) {
454 Ok(Self::new_any())
455 } else {
456 s.find(c).map_or_else(
457 || {
458 let kind: ItemKind = s.parse()?;
459 Ok(OIDMask {
460 kind: Some(kind),
461 path: PathMask::new_any(),
462 })
463 },
464 |tpos| {
465 if tpos == s.len() {
466 Err(Error::invalid_data(format!(
467 "{}: {}",
468 ERR_INVALID_OID_MASK, s
469 )))
470 } else {
471 let tp_str = &s[..tpos];
472 let kind: Option<ItemKind> = if is_str_any(tp_str) {
473 None
474 } else {
475 Some(s[..tpos].parse()?)
476 };
477 let p = &s[tpos + 1..];
478 OIDMask::check(p)?;
479 Ok(OIDMask {
480 kind,
481 path: p.parse()?,
482 })
483 }
484 },
485 )
486 }
487 }
488 #[inline]
489 pub fn from_path(s: &str) -> EResult<Self> {
490 Self::parse_oid_mask(s, '/')
491 }
492 #[inline]
493 pub fn as_path(&self) -> String {
494 if self.path.chunks.is_some() {
495 format!(
496 "{}/{}",
497 if let Some(ref kind) = self.kind {
498 kind.as_str()
499 } else {
500 "+"
501 },
502 self.path
503 )
504 } else if let Some(ref kind) = self.kind {
505 format!("{}/#", kind.as_str())
506 } else {
507 "#".to_owned()
508 }
509 }
510 #[inline]
511 pub fn chunks(&self) -> Option<Vec<&str>> {
512 self.path
513 .chunks
514 .as_ref()
515 .map(|v| v.iter().map(String::as_str).collect())
516 }
517 #[inline]
518 pub fn new_any() -> Self {
519 OIDMask {
520 kind: None,
521 path: PathMask::new_any(),
522 }
523 }
524 pub fn matches(&self, oid: &OID) -> bool {
525 let oid_tp = oid.kind();
526 let sp = oid.full_id().split('/');
527 if let Some(mask_tp) = self.kind {
528 if mask_tp != oid_tp {
529 return false;
530 }
531 }
532 if self.path.matches_split(&mut sp.clone()) {
533 return true;
534 }
535 false
536 }
537}
538
539impl PartialEq for OIDMask {
540 fn eq(&self, other: &Self) -> bool {
541 self.kind == other.kind && self.path == other.path
542 }
543}
544
545impl Ord for OIDMask {
546 fn cmp(&self, other: &Self) -> Ordering {
547 if self.kind == other.kind {
548 self.path.cmp(&other.path)
549 } else {
550 self.kind.cmp(&other.kind)
551 }
552 }
553}
554
555impl fmt::Display for OIDMask {
556 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
557 if let Some(kind) = self.kind {
558 write!(f, "{}:{}", kind, self.path)
559 } else if self.path.is_any() {
560 write!(f, "#")
561 } else {
562 write!(f, "+:{}", self.path)
563 }
564 }
565}
566
567impl From<Vec<OIDMask>> for OIDMaskList {
568 fn from(v: Vec<OIDMask>) -> Self {
569 Self::from_iter(v)
570 }
571}
572
573impl From<OID> for OIDMask {
574 fn from(oid: OID) -> Self {
575 OIDMask {
576 kind: Some(oid.kind()),
577 path: oid.full_id().parse().unwrap(),
578 }
579 }
580}
581
582impl From<OID> for OIDMaskList {
583 fn from(oid: OID) -> Self {
584 let mask = OIDMask {
585 kind: Some(oid.kind()),
586 path: oid.full_id().parse().unwrap(),
587 };
588 mask.into()
589 }
590}
591
592impl AsRef<OIDMask> for OIDMask {
593 fn as_ref(&self) -> &OIDMask {
594 self
595 }
596}
597
598impl AsRef<PathMask> for OIDMask {
599 fn as_ref(&self) -> &PathMask {
600 &self.path
601 }
602}
603
604impl FromStr for OIDMask {
605 type Err = Error;
606 fn from_str(s: &str) -> Result<Self, Self::Err> {
607 Self::parse_oid_mask(s, ':')
608 }
609}
610
611macro_rules! impl_oidmask_from_str {
612 ($t: ty) => {
613 impl TryFrom<$t> for OIDMask {
614 type Error = Error;
615 fn try_from(s: $t) -> EResult<Self> {
616 s.parse()
617 }
618 }
619 };
620}
621
622impl_oidmask_from_str!(String);
623impl_oidmask_from_str!(&str);
624impl_oidmask_from_str!(&&str);
625
626impl Hash for OIDMask {
627 fn hash<H: Hasher>(&self, hasher: &mut H) {
628 self.kind.map_or(0, |v| v as u16).hash(hasher);
629 self.path.hash(hasher);
630 }
631}
632
633impl PartialOrd for OIDMask {
634 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
635 Some(self.cmp(other))
636 }
637}
638
639impl<'de> Deserialize<'de> for OIDMask {
640 fn deserialize<D>(deserializer: D) -> Result<OIDMask, D::Error>
641 where
642 D: Deserializer<'de>,
643 {
644 let s: String = Deserialize::deserialize(deserializer)?;
645 s.parse().map_err(serde::de::Error::custom)
646 }
647}
648
649impl Serialize for OIDMask {
650 #[inline]
651 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
652 where
653 S: Serializer,
654 {
655 serializer.serialize_str(&self.to_string())
656 }
657}
658
659impl From<OIDMaskList> for Value {
660 fn from(v: OIDMaskList) -> Value {
661 to_value(v).unwrap()
662 }
663}
664
665impl From<OIDMask> for OIDMaskList {
666 fn from(mask: OIDMask) -> Self {
667 OIDMaskList::new0(mask)
668 }
669}
670
671impl TryFrom<Value> for OIDMaskList {
672 type Error = Error;
673 fn try_from(value: Value) -> EResult<OIDMaskList> {
674 match value {
675 Value::Seq(_) => {
676 let masks: Vec<String> = value.deserialize_into()?;
677 Ok(OIDMaskList::from_string_list(&masks)?)
678 }
679 Value::String(s) => {
680 if s.is_empty() {
681 Ok(<_>::default())
682 } else {
683 Ok(OIDMaskList::from_str_list(
684 &s.split(',').collect::<Vec<_>>(),
685 )?)
686 }
687 }
688 _ => Err(Error::invalid_data("Expected vec or string")),
689 }
690 }
691}
692
693#[derive(Serialize, Deserialize, Eq, PartialEq, Hash, Copy, Clone, Debug)]
694#[serde(rename_all = "lowercase")]
695pub enum Op {
696 Log,
697 Developer,
698 Moderator,
699 Supervisor,
700}
701
702impl fmt::Display for Op {
703 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
704 write!(
705 f,
706 "{}",
707 match self {
708 Op::Log => "log",
709 Op::Developer => "developer",
710 Op::Moderator => "moderator",
711 Op::Supervisor => "supervisor",
712 }
713 )
714 }
715}
716
717#[derive(Serialize, Deserialize, Default, Clone, Debug)]
718struct AclItemsPvt {
719 #[serde(default)]
720 items: OIDMaskList,
721 #[serde(default)]
722 pvt: PathMaskList,
723 #[serde(default)]
724 rpvt: PathMaskList,
725}
726
727#[allow(clippy::trivially_copy_pass_by_ref)]
734fn is_false(val: &bool) -> bool {
735 !val
736}
737
738#[derive(Serialize, Deserialize, Clone, Debug)]
740pub struct Acl {
741 id: String,
742 #[serde(default, skip_serializing_if = "is_false")]
743 admin: bool,
744 #[serde(default)]
745 read: AclItemsPvt,
746 #[serde(default)]
747 write: AclItemsPvt,
748 #[serde(default)]
749 deny_read: AclItemsPvt,
750 #[serde(default, alias = "deny")]
751 deny_write: AclItemsPvt,
752 #[serde(default)]
753 ops: HashSet<Op>,
754 #[serde(skip_serializing_if = "Option::is_none")]
755 meta: Option<Value>,
756 from: Vec<String>,
757}
758
759impl Acl {
760 #[inline]
761 pub fn id(&self) -> &str {
762 &self.id
763 }
764 pub fn get_items_allow_deny_reading(&self) -> (Vec<String>, Vec<String>) {
765 if self.admin {
766 (vec!["#".to_owned()], vec![])
767 } else {
768 let mut allow: HashSet<String> = self.read.items.as_string_vec().into_iter().collect();
769 let allow_write: HashSet<String> =
770 self.write.items.as_string_vec().into_iter().collect();
771 allow.extend(allow_write);
772 let deny: HashSet<String> = self.deny_read.items.as_string_vec().into_iter().collect();
773 (allow.into_iter().collect(), deny.into_iter().collect())
774 }
775 }
776 #[inline]
777 pub fn check_admin(&self) -> bool {
778 self.admin
779 }
780 #[inline]
781 pub fn check_op(&self, op: Op) -> bool {
782 self.admin || self.ops.contains(&op)
783 }
784 #[inline]
785 pub fn check_item_read(&self, oid: &OID) -> bool {
786 self.admin
787 || ((self.read.items.matches(oid) || self.write.items.matches(oid))
788 && !self.deny_read.items.matches(oid))
789 }
790 #[inline]
791 pub fn check_item_mask_read(&self, mask: &OIDMask) -> bool {
792 self.admin
793 || ((self.read.items.matches_mask(mask) || self.write.items.matches_mask(mask))
794 && !self.deny_read.items.matches_mask(mask))
795 }
796 #[inline]
797 pub fn check_item_write(&self, oid: &OID) -> bool {
798 self.admin
799 || (self.write.items.matches(oid)
800 && !self.deny_write.items.matches(oid)
801 && !self.deny_read.items.matches(oid))
802 }
803 #[inline]
804 pub fn check_item_mask_write(&self, mask: &OIDMask) -> bool {
805 self.admin
806 || (self.write.items.matches_mask(mask)
807 && !self.deny_write.items.matches_mask(mask)
808 && !self.deny_read.items.matches_mask(mask))
809 }
810 #[inline]
811 pub fn check_pvt_read(&self, path: &str) -> bool {
812 self.admin || (self.read.pvt.matches(path) && !self.deny_read.pvt.matches(path))
813 }
814 #[inline]
815 pub fn check_pvt_write(&self, path: &str) -> bool {
816 self.admin
817 || (self.write.pvt.matches(path)
818 && !self.deny_write.pvt.matches(path)
819 && !self.deny_read.pvt.matches(path))
820 }
821 #[inline]
822 pub fn check_rpvt_read(&self, path: &str) -> bool {
823 if self.admin {
824 true
825 } else {
826 let mut sp = path.splitn(2, '/');
827 if let Some(node) = sp.next() {
828 if let Some(uri) = sp.next() {
829 let stripped_uri = if let Some(u) = uri.strip_prefix("https://") {
830 u
831 } else if let Some(u) = uri.strip_prefix("http://") {
832 u
833 } else {
834 uri
835 };
836 let stripped_path = format!("{node}/{stripped_uri}");
837 self.read.rpvt.matches(&stripped_path)
838 && !self.deny_read.rpvt.matches(&stripped_path)
839 } else {
840 false
841 }
842 } else {
843 false
844 }
845 }
846 }
847 #[inline]
848 pub fn require_admin(&self) -> EResult<()> {
849 if self.check_admin() {
850 Ok(())
851 } else {
852 Err(Error::access("admin access required"))
853 }
854 }
855 pub fn require_op(&self, op: Op) -> EResult<()> {
856 if self.check_op(op) {
857 Ok(())
858 } else {
859 Err(Error::access(format!("operation access required: {}", op)))
860 }
861 }
862 pub fn require_item_read(&self, oid: &OID) -> EResult<()> {
863 if self.check_item_read(oid) {
864 Ok(())
865 } else {
866 Err(Error::access(format!("read access required for: {}", oid)))
867 }
868 }
869 pub fn require_item_mask_read(&self, mask: &OIDMask) -> EResult<()> {
870 if self.check_item_mask_read(mask) {
871 Ok(())
872 } else {
873 Err(Error::access(format!("read access required for: {}", mask)))
874 }
875 }
876 pub fn require_item_write(&self, oid: &OID) -> EResult<()> {
877 if self.check_item_write(oid) {
878 Ok(())
879 } else {
880 Err(Error::access(format!("write access required for: {}", oid)))
881 }
882 }
883 pub fn require_item_mask_write(&self, mask: &OIDMask) -> EResult<()> {
884 if self.check_item_mask_write(mask) {
885 Ok(())
886 } else {
887 Err(Error::access(format!(
888 "write access required for: {}",
889 mask
890 )))
891 }
892 }
893 pub fn require_pvt_read(&self, path: &str) -> EResult<()> {
894 if self.check_pvt_read(path) {
895 Ok(())
896 } else {
897 Err(Error::access(format!("read access required for: {}", path)))
898 }
899 }
900 pub fn require_pvt_write(&self, path: &str) -> EResult<()> {
901 if self.check_pvt_write(path) {
902 Ok(())
903 } else {
904 Err(Error::access(format!(
905 "write access required for: {}",
906 path
907 )))
908 }
909 }
910 pub fn require_rpvt_read(&self, path: &str) -> EResult<()> {
911 if self.check_rpvt_read(path) {
912 Ok(())
913 } else {
914 Err(Error::access(format!("read access required for: {}", path)))
915 }
916 }
917 #[inline]
918 pub fn contains_acl(&self, acl_id: &str) -> bool {
919 self.from.iter().any(|v| v == acl_id)
920 }
921 #[inline]
922 pub fn meta(&self) -> Option<&Value> {
923 self.meta.as_ref()
924 }
925 #[inline]
926 pub fn from(&self) -> &[String] {
927 &self.from
928 }
929}
930
931#[cfg(test)]
932mod tests {
933 use super::{Acl, OIDMask, OIDMaskList, PathMask, PathMaskList};
934 use crate::{ItemKind, OID};
935
936 #[test]
937 fn test_path_mask() {
938 let s = "#";
939 let mask: PathMask = s.parse().unwrap();
940 assert_eq!(s, mask.to_string());
941 assert_eq!(mask.chunks, None);
942 let s = "";
943 assert!(s.parse::<PathMask>().is_err());
944 let s = "data/#";
945 let mask: PathMask = s.parse().unwrap();
946 assert_eq!(s, mask.to_string());
947 assert_eq!(mask.chunks.unwrap(), ["data", "#"]);
948 let s = "data/tests/t1";
949 let mask: PathMask = s.parse().unwrap();
950 assert_eq!(s, mask.to_string());
951 assert_eq!(mask.chunks.unwrap(), ["data", "tests", "t1"]);
952 let s = "data/tests/*";
953 let mask: PathMask = s.parse().unwrap();
954 assert_eq!(mask.to_string(), "data/tests/#");
955 assert_eq!(mask.chunks.unwrap(), ["data", "tests", "#"]);
956 let s = "data/*/t1";
957 let mask: PathMask = s.parse().unwrap();
958 assert_ne!(s, mask.to_string());
959 assert_eq!(mask.chunks.unwrap(), ["data", "#"]);
960 }
961
962 #[test]
963 fn test_oid_mask() {
964 let s = "#";
965 let mask: OIDMask = s.parse().unwrap();
966 assert_eq!(s, mask.to_string());
967 assert_eq!(mask.path.chunks, None);
968 assert_eq!(mask.as_path(), "#");
969 let s = "";
970 assert!(s.parse::<OIDMask>().is_err());
971 let s = "sensor:";
972 assert!(s.parse::<OIDMask>().is_err());
973 let s = "sensor:data/#";
974 let mask: OIDMask = s.parse().unwrap();
975 assert_eq!(mask.as_path(), "sensor/data/#");
976 assert_eq!(s, mask.to_string());
977 assert_eq!(mask.kind.unwrap(), ItemKind::Sensor);
978 assert_eq!(mask.path.chunks.unwrap(), ["data", "#"]);
979 let s = "#:data/#";
980 assert!(s.parse::<OIDMask>().is_err());
981 let s = "+:data/tests/t1";
982 let mask: OIDMask = s.parse().unwrap();
983 assert_eq!(mask.as_path(), "+/data/tests/t1");
984 assert_eq!(s, mask.to_string());
985 assert_eq!(mask.path.chunks.unwrap(), ["data", "tests", "t1"]);
986 assert_eq!(mask.kind, None);
987 let s = "unit:data/tests/*";
988 let mask: OIDMask = s.parse().unwrap();
989 assert_eq!(mask.to_string(), "unit:data/tests/#");
990 assert_eq!(mask.path.chunks.unwrap(), ["data", "tests", "#"]);
991 assert_eq!(mask.kind.unwrap(), ItemKind::Unit);
992 let s = "data/*/t1";
993 let mask: PathMask = s.parse().unwrap();
994 assert_ne!(s, mask.to_string());
995 assert_eq!(mask.chunks.unwrap(), ["data", "#"]);
996 }
997
998 #[test]
999 fn test_path_mask_list() {
1000 let p =
1001 PathMaskList::from_str_list(&["test/tests", "+/xxx", "zzz/?/222", "abc", "a/b/#/c"]);
1002 assert!(!p.matches("test"));
1003 assert!(p.matches("test/tests"));
1004 assert!(!p.matches("test/tests2"));
1005 assert!(p.matches("aaa/xxx"));
1006 assert!(!p.matches("aaa/xxx/123"));
1007 assert!(p.matches("zzz/xxx/222"));
1008 assert!(!p.matches("zzz/xxx/222/555"));
1009 assert!(!p.matches("zzz/xxx/223"));
1010 assert!(p.matches("abc"));
1011 assert!(!p.matches("abd"));
1012 assert!(p.matches("abc/xxx"));
1013 assert!(!p.matches("abc/zzz"));
1014 assert!(p.matches("a/b/zzz"));
1015 assert!(p.matches("a/b/zzz/xxx"));
1016 let p = PathMaskList::from_str_list(&["*"]);
1017 assert!(p.matches("test"));
1018 assert!(p.matches("test/tests"));
1019 assert!(p.matches("test/tests2"));
1020 assert!(p.matches("aaa/xxx"));
1021 assert!(p.matches("aaa/xxx/123"));
1022 assert!(p.matches("zzz/xxx/222"));
1023 assert!(p.matches("zzz/xxx/222/555"));
1024 assert!(p.matches("zzz/xxx/223"));
1025 assert!(p.matches("abc"));
1026 assert!(p.matches("abd"));
1027 assert!(p.matches("abc/xxx"));
1028 assert!(p.matches("abc/zzz"));
1029 assert!(p.matches("a/b/zzz"));
1030 assert!(p.matches("a/b/zzz/xxx"));
1031 }
1032
1033 #[test]
1034 fn test_oid_mask_list() {
1035 let p = OIDMaskList::from_str_list(&[
1036 "unit:test/tests",
1037 "sensor:+/xxx",
1038 "+:zzz/?/222",
1039 "lvar:abc",
1040 "+:a/b/#/c",
1041 ])
1042 .unwrap();
1043 assert!(!p.matches(&"unit:test".parse().unwrap()));
1044 assert!(p.matches(&"unit:test/tests".parse().unwrap()));
1045 assert!(!p.matches(&"sensor:test/tests".parse().unwrap()));
1046 assert!(!p.matches(&"unit:test/tests2".parse().unwrap()));
1047 assert!(p.matches(&"sensor:aaa/xxx".parse().unwrap()));
1048 assert!(!p.matches(&"lvar:aaa/xxx".parse().unwrap()));
1049 assert!(p.matches(&"unit:zzz/xxx/222".parse().unwrap()));
1050 assert!(p.matches(&"sensor:zzz/xxx/222".parse().unwrap()));
1051 assert!(!p.matches(&"sensor:zzz/xxx/222/555".parse().unwrap()));
1052 assert!(!p.matches(&"unit:zzz/xxx/223".parse().unwrap()));
1053 assert!(p.matches(&"lvar:abc".parse().unwrap()));
1054 assert!(!p.matches(&"unit:abc".parse().unwrap()));
1055 assert!(!p.matches(&"lvar:abd".parse().unwrap()));
1056 assert!(!p.matches(&"lvar:abc/xxx".parse().unwrap()));
1057 assert!(p.matches(&"sensor:abc/xxx".parse().unwrap()));
1058 assert!(!p.matches(&"sensor:abc/zzz".parse().unwrap()));
1059 assert!(p.matches(&"unit:a/b/zzz".parse().unwrap()));
1060 assert!(p.matches(&"unit:a/b/zzz/xxx".parse().unwrap()));
1061 assert!(!p.matches(&"unit:a/c/zzz/xxx".parse().unwrap()));
1062 let p = OIDMaskList::from_str_list(&["*"]).unwrap();
1063 assert!(p.matches(&"unit:test".parse().unwrap()));
1064 assert!(p.matches(&"unit:test/tests".parse().unwrap()));
1065 assert!(p.matches(&"sensor:test/tests".parse().unwrap()));
1066 assert!(p.matches(&"unit:test/tests2".parse().unwrap()));
1067 assert!(p.matches(&"sensor:aaa/xxx".parse().unwrap()));
1068 assert!(p.matches(&"lvar:aaa/xxx".parse().unwrap()));
1069 assert!(p.matches(&"unit:zzz/xxx/222".parse().unwrap()));
1070 assert!(p.matches(&"sensor:zzz/xxx/222".parse().unwrap()));
1071 assert!(p.matches(&"sensor:zzz/xxx/222/555".parse().unwrap()));
1072 assert!(p.matches(&"unit:zzz/xxx/223".parse().unwrap()));
1073 assert!(p.matches(&"lvar:abc".parse().unwrap()));
1074 assert!(p.matches(&"unit:abc".parse().unwrap()));
1075 assert!(p.matches(&"lvar:abd".parse().unwrap()));
1076 assert!(p.matches(&"lvar:abc/xxx".parse().unwrap()));
1077 assert!(p.matches(&"sensor:abc/xxx".parse().unwrap()));
1078 assert!(p.matches(&"sensor:abc/zzz".parse().unwrap()));
1079 assert!(p.matches(&"unit:a/b/zzz".parse().unwrap()));
1080 assert!(p.matches(&"unit:a/b/zzz/xxx".parse().unwrap()));
1081 assert!(p.matches(&"unit:a/c/zzz/xxx".parse().unwrap()));
1082
1083 let p = OIDMaskList::from_str_list(&["sensor:content/#"]).unwrap();
1084 assert!(p.matches(&"sensor:content/data".parse().unwrap()));
1085 let p = OIDMaskList::from_str_list(&["sensor:+"]).unwrap();
1086 assert!(!p.matches(&"sensor:content/data".parse().unwrap()));
1087 }
1088
1089 #[test]
1090 fn test_oid_wildcard_mask() {
1091 let mask: OIDMask = "sensor:tests/#".parse().unwrap();
1092 let oid_mask: OID = mask.to_wildcard_oid().unwrap();
1093 assert!(oid_mask.is_wildcard());
1094 assert_eq!(oid_mask.to_wildcard_str("%"), "sensor:tests/%");
1095 let mask: OIDMask = "sensor:#".parse().unwrap();
1096 let oid_mask: OID = mask.to_wildcard_oid().unwrap();
1097 assert!(oid_mask.is_wildcard());
1098 assert_eq!(oid_mask.to_wildcard_str("%"), "sensor:%");
1099 let mask: OIDMask = "sensor:+/#".parse().unwrap();
1100 assert!(mask.to_wildcard_oid().is_err());
1101 }
1102
1103 #[test]
1104 fn test_rpvt_acl() {
1105 let p_allow = PathMaskList::from_str_list(&["node1/res", "node2/res/#"]);
1106 let p_deny = PathMaskList::from_str_list(&["node2/res/secret"]);
1107 let mut acl: Acl = serde_json::from_str(
1108 r#"{
1109 "id": "test",
1110 "from": ["test"]
1111 }"#,
1112 )
1113 .unwrap();
1114 acl.read.rpvt = p_allow;
1115 acl.deny_read.rpvt = p_deny;
1116 for pfx in &["", "http://", "https://"] {
1117 assert!(acl.check_rpvt_read(&format!("node1/{pfx}res")));
1118 assert!(!acl.check_rpvt_read(&format!("node2/{pfx}res")));
1119 assert!(acl.check_rpvt_read(&format!("node2/{pfx}res/res1")));
1120 assert!(!acl.check_rpvt_read(&format!("node2/{pfx}res/secret")));
1121 assert!(!acl.check_rpvt_read(&format!("node3/{pfx}res")));
1122 }
1123 }
1124}