diff --git a/src/models/authelia.rs b/src/models/authelia.rs index 089ea24..a10e002 100644 --- a/src/models/authelia.rs +++ b/src/models/authelia.rs @@ -2,10 +2,7 @@ use non_empty_string::NonEmptyString; use serde::{Deserialize, Serialize}; use serde_json::Value; -use std::{ - collections::HashMap, - ops::{Deref, DerefMut}, -}; +use std::collections::HashMap; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UsersFile { @@ -27,68 +24,8 @@ pub struct UserFile { pub extra: Option>, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct User { - pub displayname: NonEmptyString, - pub email: Option, - pub password: NonEmptyString, - pub disabled: bool, - pub groups: Vec, - - #[serde(flatten)] - pub extra: Option>, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Users { - pub users: HashMap, - - #[serde(flatten)] - pub extra: Option>, -} - -impl Deref for Users { - type Target = HashMap; - - fn deref(&self) -> &Self::Target { - &self.users - } -} - -impl DerefMut for Users { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.users - } -} - -impl From for User { - fn from(user_file: UserFile) -> Self { - Self { - displayname: user_file.displayname, - email: user_file.email, - password: user_file.password, - disabled: user_file.disabled.unwrap_or(false), - groups: user_file.groups.unwrap_or_default(), - extra: user_file.extra, - } - } -} - -impl From for Users { - fn from(users_file: UsersFile) -> Self { - Self { - users: users_file - .users - .into_iter() - .map(|(key, user)| (key, User::from(user))) - .collect(), - extra: users_file.extra, - } - } -} - -impl From for UserFile { - fn from(user: User) -> Self { +impl From for UserFile { + fn from(user: super::users::User) -> Self { Self { displayname: user.displayname, email: user.email, @@ -104,8 +41,8 @@ impl From for UserFile { } } -impl From for UsersFile { - fn from(users: Users) -> Self { +impl From for UsersFile { + fn from(users: super::users::Users) -> Self { Self { users: users .users @@ -116,45 +53,3 @@ impl From for UsersFile { } } } - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Group { - pub users: Vec, -} - -pub struct Groups { - pub groups: HashMap, -} - -impl Deref for Groups { - type Target = HashMap; - - fn deref(&self) -> &Self::Target { - &self.groups - } -} - -impl DerefMut for Groups { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.groups - } -} - -impl From for Groups { - fn from(users_file: UsersFile) -> Self { - users_file.users.into_iter().fold( - Self { - groups: HashMap::new(), - }, - |mut acc, (key, user)| { - for group in user.groups.unwrap_or_default() { - acc.entry(group) - .or_insert_with(|| Group { users: Vec::new() }) - .users - .push(key.clone()); - } - acc - }, - ) - } -} diff --git a/src/models/groups.rs b/src/models/groups.rs new file mode 100644 index 0000000..d7fea95 --- /dev/null +++ b/src/models/groups.rs @@ -0,0 +1,49 @@ +use non_empty_string::NonEmptyString; +use serde::{Deserialize, Serialize}; + +use std::{ + collections::HashMap, + ops::{Deref, DerefMut}, +}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Group { + pub users: Vec, +} + +pub struct Groups { + pub groups: HashMap, +} + +impl Deref for Groups { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.groups + } +} + +impl DerefMut for Groups { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.groups + } +} + +impl From for Groups { + fn from(users_file: super::authelia::UsersFile) -> Self { + users_file.users.into_iter().fold( + Self { + groups: HashMap::new(), + }, + |mut acc, (key, user)| { + for group in user.groups.unwrap_or_default() { + acc.entry(group) + .or_insert_with(|| Group { users: Vec::new() }) + .users + .push(key.clone()); + } + acc + }, + ) + } +} diff --git a/src/models/mod.rs b/src/models/mod.rs index f520466..9766fd7 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1 +1,3 @@ pub mod authelia; +pub mod groups; +pub mod users; diff --git a/src/models/users.rs b/src/models/users.rs new file mode 100644 index 0000000..8fac784 --- /dev/null +++ b/src/models/users.rs @@ -0,0 +1,68 @@ +use non_empty_string::NonEmptyString; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use std::{ + collections::HashMap, + ops::{Deref, DerefMut}, +}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct User { + pub displayname: NonEmptyString, + pub email: Option, + pub password: NonEmptyString, + pub disabled: bool, + pub groups: Vec, + + #[serde(flatten)] + pub extra: Option>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Users { + pub users: HashMap, + + #[serde(flatten)] + pub extra: Option>, +} + +impl Deref for Users { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.users + } +} + +impl DerefMut for Users { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.users + } +} + +impl From for User { + fn from(user_file: super::authelia::UserFile) -> Self { + Self { + displayname: user_file.displayname, + email: user_file.email, + password: user_file.password, + disabled: user_file.disabled.unwrap_or(false), + groups: user_file.groups.unwrap_or_default(), + extra: user_file.extra, + } + } +} + +impl From for Users { + fn from(users_file: super::authelia::UsersFile) -> Self { + Self { + users: users_file + .users + .into_iter() + .map(|(key, user)| (key, User::from(user))) + .collect(), + extra: users_file.extra, + } + } +} diff --git a/src/routes/groups.rs b/src/routes/groups.rs index ffdd722..6fa0a5e 100644 --- a/src/routes/groups.rs +++ b/src/routes/groups.rs @@ -11,7 +11,7 @@ use log::error; use non_empty_string::NonEmptyString; use serde::{Deserialize, Serialize}; -use crate::{models::authelia, routes::auth, state::State}; +use crate::{models::groups, routes::auth, state::State}; #[derive(Debug, Serialize)] struct GroupResponse { @@ -19,8 +19,8 @@ struct GroupResponse { users: Vec, } -impl From<(NonEmptyString, authelia::Group)> for GroupResponse { - fn from((groupname, group): (NonEmptyString, authelia::Group)) -> Self { +impl From<(NonEmptyString, groups::Group)> for GroupResponse { + fn from((groupname, group): (NonEmptyString, groups::Group)) -> Self { Self { groupname, users: group.users, @@ -30,8 +30,8 @@ impl From<(NonEmptyString, authelia::Group)> for GroupResponse { type GroupsResponse = HashMap; -impl From for GroupsResponse { - fn from(groups: authelia::Groups) -> Self { +impl From for GroupsResponse { + fn from(groups: groups::Groups) -> Self { groups .groups .into_iter() @@ -74,7 +74,7 @@ pub struct GroupCreate { users: Vec, } -impl From for authelia::Group { +impl From for groups::Group { fn from(update: GroupCreate) -> Self { Self { users: update.users, @@ -97,7 +97,7 @@ pub async fn create( return Err(StatusCode::CONFLICT); } - let group_created = authelia::Group::from(group_create); + let group_created = groups::Group::from(group_create); for username in &group_created.users { if !users.contains_key(username) { @@ -125,7 +125,7 @@ pub struct GroupUpdate { users: Vec, } -impl From for authelia::Group { +impl From for groups::Group { fn from(update: GroupUpdate) -> Self { Self { users: update.users, @@ -150,7 +150,7 @@ pub async fn update( .unwrap_or_else(|| groupname.clone()); let group_existing = groups.get(&groupname).ok_or(StatusCode::NOT_FOUND)?; - let group_updated = authelia::Group::from(group_update); + let group_updated = groups::Group::from(group_update); if groupname != new_groupname && (groupname == state.config.oauth.admin_group diff --git a/src/routes/users.rs b/src/routes/users.rs index 686b558..67ebdbb 100644 --- a/src/routes/users.rs +++ b/src/routes/users.rs @@ -12,7 +12,7 @@ use non_empty_string::NonEmptyString; use serde::{Deserialize, Serialize}; use crate::{ - models::authelia, routes::auth, state::State, utils::crypto::generate_random_password_hash, + models::users, routes::auth, state::State, utils::crypto::generate_random_password_hash, }; #[derive(Debug, Serialize)] @@ -23,8 +23,8 @@ struct UserResponse { groups: Option>, } -impl From<(NonEmptyString, authelia::User)> for UserResponse { - fn from((username, user): (NonEmptyString, authelia::User)) -> Self { +impl From<(NonEmptyString, users::User)> for UserResponse { + fn from((username, user): (NonEmptyString, users::User)) -> Self { Self { username, displayname: user.displayname, @@ -36,8 +36,8 @@ impl From<(NonEmptyString, authelia::User)> for UserResponse { type UsersResponse = HashMap; -impl From for UsersResponse { - fn from(users: authelia::Users) -> Self { +impl From for UsersResponse { + fn from(users: users::Users) -> Self { users .users .into_iter() @@ -84,7 +84,7 @@ pub struct UserCreate { } #[allow(clippy::fallible_impl_from)] -impl From for authelia::User { +impl From for users::User { fn from(user_create: UserCreate) -> Self { Self { displayname: user_create.displayname, @@ -112,7 +112,7 @@ pub async fn create( return Err(StatusCode::CONFLICT); } - let user_created = authelia::User::from(user_create); + let user_created = users::User::from(user_create); users.users.insert(username.clone(), user_created.clone()); state.save_users(users).map_err(|e| { @@ -132,7 +132,7 @@ pub struct UserUpdate { groups: Option>, } -impl From<(Self, UserUpdate)> for authelia::User { +impl From<(Self, UserUpdate)> for users::User { fn from((user_existing, user_update): (Self, UserUpdate)) -> Self { Self { displayname: user_update.displayname, @@ -162,7 +162,7 @@ pub async fn update( .unwrap_or_else(|| username.clone()); let user_existing = users.remove(&username).ok_or(StatusCode::NOT_FOUND)?; - let user_updated = authelia::User::from((user_existing, user_update)); + let user_updated = users::User::from((user_existing, user_update)); users .users diff --git a/src/utils/authelia.rs b/src/utils/authelia.rs index 0022bd7..ade7bac 100644 --- a/src/utils/authelia.rs +++ b/src/utils/authelia.rs @@ -3,34 +3,33 @@ use std::error::Error; use crate::{models, state::State}; impl State { - pub fn load_users(&self) -> Result> { + pub fn load_users(&self) -> Result> { let file_contents = std::fs::read_to_string(&self.config.authelia.user_database)?; let users_file: models::authelia::UsersFile = serde_yaml::from_str(&file_contents)?; - let users = models::authelia::Users::from(users_file); + let users = models::users::Users::from(users_file); Ok(users) } - pub fn load_groups(&self) -> Result> { + pub fn load_groups(&self) -> Result> { let file_contents = std::fs::read_to_string(&self.config.authelia.user_database)?; let users_file = serde_yaml::from_str::(&file_contents)?; - let groups = models::authelia::Groups::from(users_file); + let groups = models::groups::Groups::from(users_file); Ok(groups) } pub fn load_users_and_groups( &self, - ) -> Result<(models::authelia::Users, models::authelia::Groups), Box> - { + ) -> Result<(models::users::Users, models::groups::Groups), Box> { let file_contents = std::fs::read_to_string(&self.config.authelia.user_database)?; let users_file = serde_yaml::from_str::(&file_contents)?; - let users = models::authelia::Users::from(users_file.clone()); - let groups = models::authelia::Groups::from(users_file); + let users = models::users::Users::from(users_file.clone()); + let groups = models::groups::Groups::from(users_file); Ok((users, groups)) } pub fn save_users( &self, - users: models::authelia::Users, + users: models::users::Users, ) -> Result<(), Box> { let users_file = models::authelia::UsersFile::from(users); let file_contents = serde_yaml::to_string(&users_file)?;