lrau 0.6.0

LrAU is an authentication and permission management system.
Documentation
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg(feature = "diesel-support")]
mod diesel_support {
    pub use super::*;
    pub use diesel::{
        pg::Pg,
        serialize::Output,
        sql_types::Jsonb,
        types::{FromSql, ToSql},
    };
    pub use std::io::Write;

    // This allows you to use it in postgresql.
    impl FromSql<Jsonb, Pg> for Permissions {
        fn from_sql(bytes: Option<&[u8]>) -> diesel::deserialize::Result<Self> {
            let value =
                <serde_json::Value as FromSql<Jsonb, Pg>>::from_sql(bytes)?;
            Ok(serde_json::from_value(value)?)
        }
    }

    impl ToSql<Jsonb, Pg> for Permissions {
        fn to_sql<W: Write>(
            &self,
            out: &mut Output<W, Pg>,
        ) -> diesel::serialize::Result {
            let value = serde_json::to_value(self)?;
            <serde_json::Value as ToSql<Jsonb, Pg>>::to_sql(&value, out)
        }
    }
}
#[cfg(feature = "diesel-support")]
use diesel_support::*;

/// The permissions struct stores a vector of
/// `Permissions`
#[derive(Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Default)]
#[cfg_attr(
    feature = "diesel-support",
    derive(FromSqlRow, AsExpression),
    sql_type = "Jsonb"
)]
#[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
    #[must_use]
    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<T>(&self, path: &[T], r#mut: bool) -> bool where String: PartialEq<T>{
        // 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;

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

        // Begins a loop through the vec
        '_permission: for permission in &self.vec {
            // Check we don't run into a problem like this:
            //
            // | Path    | Permission |
            // |---------|------------|
            // | server  | server     |
            // | control | control    | 
            // |         | reboot     | X Too sepcific
            //
            // Where we would end up getting permissions from paths
            // which are more specific. Without this check you can easily
            // get improper privaliged access.
            if permission.path.len() > path.len() { continue; }
            let mut matches = 0_usize;
            '_segments: for (n, permission_seg) in permission.path.iter().enumerate() {

                // Make sure we quit when we should.
                match path.get(n) {
                    Some(path_seg) => {
                        // Check if the paths have diverged, ie:
                        //
                        // | Path     | Permission |
                        // |----------|------------|
                        // | server   | server     |
                        // | control  | control    |
                        // | shutdown | reboot     | X diverged
                        if permission_seg != path_seg {
                            continue '_permission;
                        } else {
                            matches += 1
                        }
                    },
                    None => break '_segments,
                }
            }
            if matches > bestn {
                best = Some(permission);
                bestn = matches;
            }
        }

        // 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 }
    }
}

/// The permission struct stores an individual
/// permission.
/// This contains information about a user accessing
/// certain areas of a program.
/// You probably will never need to access this because it is included
/// int [`Permissions`](Permissions)
///
/// 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 (as an array) `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: Vec<String>,
    pub auth: bool,
    #[cfg_attr(feature = "serde", serde(default))]
    pub r#mut: bool,
}

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