fapolicy_rules/parser/
parse.rs

1/*
2 * Copyright Concurrent Technologies Corporation 2021
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7 */
8
9use nom::bytes::complete::{is_not, tag, take_until};
10
11use nom::character::complete::digit1;
12use nom::character::complete::space0;
13use nom::character::is_alphanumeric;
14use nom::combinator::rest;
15use nom::error::ErrorKind;
16
17use nom::sequence::tuple;
18
19use crate::parser::error::RuleParseError;
20use crate::parser::error::RuleParseError::*;
21use crate::parser::object;
22use crate::parser::subject;
23use crate::parser::trace::Trace;
24
25use crate::{Object, Rvalue, Subject};
26use nom::IResult;
27
28// general parser defs and functions
29
30pub type StrTrace<'a> = Trace<&'a str>;
31pub(crate) type TraceError<'a> = RuleParseError<StrTrace<'a>>;
32pub(crate) type NomTraceError<'a> = nom::error::Error<StrTrace<'a>>;
33pub(crate) type TraceResult<'a, O> = IResult<StrTrace<'a>, O, TraceError<'a>>;
34
35#[derive(Debug)]
36pub(crate) struct SubObj {
37    pub subject: Subject,
38    pub object: Object,
39}
40
41// todo;; this should be absolute path
42pub(crate) fn filepath(i: StrTrace) -> TraceResult<StrTrace> {
43    nom::bytes::complete::is_not(" \t\n")(i)
44}
45
46// todo;; this should be mimetype
47pub(crate) fn filetype(i: StrTrace) -> TraceResult<Rvalue> {
48    nom::bytes::complete::is_not(" \t\n")(i)
49        .map(|(r, v)| (r, Rvalue::Literal(v.current.to_string())))
50}
51
52pub(crate) fn pattern(i: StrTrace) -> IResult<StrTrace, StrTrace, TraceError> {
53    nom::bytes::complete::take_while1(|x| is_alphanumeric(x as u8) || x == '_')(i)
54}
55
56pub(crate) fn trust_flag(i: StrTrace) -> TraceResult<bool> {
57    match digit1(i) {
58        Ok((r, v)) if v.current == "1" => Ok((r, true)),
59        Ok((r, v)) if v.current == "0" => Ok((r, false)),
60        Ok((_, _)) => Err(nom::Err::Failure(Nom(i, ErrorKind::Digit))),
61        Err(e) => Err(e),
62    }
63}
64
65pub(crate) fn subject_object_parts(i: StrTrace) -> TraceResult<SubObj> {
66    if !i.current.contains(':') {
67        return Err(nom::Err::Error(MissingSeparator(i)));
68    }
69
70    let (_, ss) = take_until(" :")(i)?;
71    let (_, s) = subject::parse(ss)?;
72
73    let (_, (_, _, _, oo)) = tuple((is_not(":"), tag(":"), space0, rest))(i)?;
74    let (ii, o) = object::parse(oo)?;
75
76    Ok((
77        ii,
78        SubObj {
79            subject: s,
80            object: o,
81        },
82    ))
83}
84
85pub(crate) fn end_of_rule(i: StrTrace) -> nom::IResult<StrTrace, (), RuleParseError<StrTrace>> {
86    match rest(i) {
87        Ok((rem, v)) if v.current.is_empty() => Ok((rem, ())),
88        Ok((_, v)) => Err(nom::Err::Error(ExpectedEndOfInput(v))),
89        res => res.map(|(rem, _)| (rem, ())),
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn parse_trust_flag() {
99        assert!(trust_flag("1".into()).ok().unwrap().1);
100        assert!(!trust_flag("0".into()).ok().unwrap().1);
101        assert_eq!(None, trust_flag("2".into()).ok());
102        assert_eq!(None, trust_flag("foo".into()).ok());
103    }
104}