1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// The permissions struct stores a vector of
/// `Permissions`
#[derive(Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Permissions {
    #[cfg_attr(feature = "serde", serde(rename = "permissions"))]
    pub vec: Vec<Permission>,
}

impl Permissions {
    /// To create a new permissions you need to specify a vec to use.
    /// If you don't want this you can use the `default` function
    pub fn new(vec: Vec<Permission>) -> Self {
        Self { vec }
    }

    /// This function gets wether the permissions at
    /// `path` have the desired permissions.
    pub fn get_permission(&self, path: &str, r#mut: bool) -> bool {
        // Variable to store the closest path that we have
        // found.
        let mut best = None;
        // Variable to store how many path segments match
        let mut bestn = 0;
        // Splits the required path by path separators
        let path: Vec<&str> = path.split('/').collect();

        // Check the len isn't 0
        if path.is_empty() {
            return false;
        }

        // Begins a loop through the vec
        for i in &self.vec {
            // Gets the path, split by path separators
            let ipath: Vec<&str> = i.path.split('/').collect();
            let mut matches = 0;
            // Loops through the path separators.
            for path_segment in ipath {
                // Checks for a match
                if path_segment
                    == match path.get(matches) {
                        Some(m) => *m,
                        None => break,
                    }
                {
                    matches += 1;
                    // Checks if we have suppassed the required
                    // ammount of matches.
                    if bestn < matches {
                        // And if so makes this the new best.
                        bestn = matches;
                        best = Some(i);
                        // Checks if we already have a full
                        // match.
                        if matches == path.len() {
                            break;
                        }
                    }
                } else if matches == 0 {
                    break;
                }
            }
        }

        // Now check if there even was a match
        if let Some(best) = best {
            // And if so check if its permissions are valid
            return best.auth && (best.r#mut || !r#mut);
        }

        // Return false if in doubt.
        false
    }
}

// Its just easier to do it this way.
impl From<Vec<Permission>> for Permissions {
    fn from(vec: Vec<Permission>) -> Self {
        Self { vec }
    }
}

// Simple default
impl Default for Permissions {
    fn default() -> Self {
        Self { vec: Vec::new() }
    }
}

/// The permission struct stores an individual
/// permission.
/// This contains information about a user accessing
/// certain areas of a program.
///
/// It can be configured in toml like below:
/// First specify an individual element in a
/// `permissions` array.
/// In this you need to specify a path `path`,
/// and wether the user has permission `auth`.
/// Then you can specify mutability `mut`.
///
/// ```toml
/// # Create an array element
/// [[permissions]]
/// # Specify the path
/// path = "/contacts"
/// # Specify the authentication
/// auth = true
/// # Specify if they can mutate the contacts
/// mut = true
/// ```
///
/// This creates a permission in the `/contacts`
/// path, where the user can both read and mutate it.
#[derive(Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Permission {
    pub path: String,
    pub auth: bool,
    #[cfg_attr(feature = "serde", serde(default))]
    pub r#mut: bool,
}

impl Permission {
    /// Creates a new permission.
    pub fn new(path: String, auth: bool, r#mut: bool) -> Self {
        Self { path, auth, r#mut }
    }
}