adjust and implement more of the api
This commit is contained in:
parent
f2000c7650
commit
70fcd823da
56
src/api.rs
56
src/api.rs
@ -22,40 +22,40 @@ pub trait UserDBWrite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait UserRead {
|
pub trait UserRead {
|
||||||
fn get_username(&self) -> Option<crate::User>;
|
fn get_username(&self) -> Option<&str>;
|
||||||
fn get_uid(&self) -> Option<crate::User>;
|
fn get_uid(&self) -> u32;
|
||||||
fn get_gid(&self) -> Option<crate::User>;
|
fn get_gid(&self) -> u32;
|
||||||
fn get_password(&self) -> Option<crate::User>;
|
fn get_password(&self) -> Option<&str>;
|
||||||
fn get_gecos(&self) -> Option<crate::User>;
|
fn get_gecos(&self) -> Option<&crate::Gecos>;
|
||||||
fn get_home_dir(&self) -> Option<crate::User>;
|
fn get_home_dir(&self) -> Option<&str>;
|
||||||
fn get_shell_path(&self) -> Option<crate::User>;
|
fn get_shell_path(&self) -> Option<&str>;
|
||||||
fn get_full_name(&self) -> Option<String>;
|
fn get_full_name(&self) -> Option<&str>;
|
||||||
fn get_room(&self) -> Option<String>;
|
fn get_room(&self) -> Option<&str>;
|
||||||
fn get_phone_work(&self) -> Option<String>;
|
fn get_phone_work(&self) -> Option<&str>;
|
||||||
fn get_phone_home(&self) -> Option<String>;
|
fn get_phone_home(&self) -> Option<&str>;
|
||||||
fn get_other(&self) -> Option<Vec<String>>;
|
fn get_other(&self) -> Option<&Vec<String>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UserWrite {
|
pub trait UserWrite {
|
||||||
fn set_username(&self) -> Option<crate::User>;
|
fn set_username(&self, username: String);
|
||||||
fn set_uid(&self) -> Option<crate::User>;
|
fn set_uid(&self, uid: u32);
|
||||||
fn set_gid(&self) -> Option<crate::User>;
|
fn set_gid(&self, gid: u32);
|
||||||
fn set_password(&self) -> Option<crate::User>;
|
fn set_password(&self, password: String);
|
||||||
fn set_gecos(&self) -> Option<crate::User>;
|
fn set_gecos(&self, gecos: crate::Gecos);
|
||||||
fn set_home_dir(&self) -> Option<crate::User>;
|
fn set_home_dir(&self, home_dir: String);
|
||||||
fn set_shell_path(&self) -> Option<crate::User>;
|
fn set_shell_path(&self, shell_path: String);
|
||||||
fn set_full_name(&self) -> Option<String>;
|
fn set_full_name(&self, full_name: String);
|
||||||
fn set_room(&self) -> Option<String>;
|
fn set_room(&self, room: String);
|
||||||
fn set_phone_work(&self) -> Option<String>;
|
fn set_phone_work(&self, phone_work: String);
|
||||||
fn set_phone_home(&self) -> Option<String>;
|
fn set_phone_home(&self, phone_home: String);
|
||||||
fn set_other(&self) -> Option<Vec<String>>;
|
fn set_other(&self, other: Option<Vec<String>>);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GroupRead {
|
pub trait GroupRead {
|
||||||
fn get_groupname(&self) -> Option<crate::Group>;
|
fn get_groupname(&self) -> Option<&str>;
|
||||||
fn get_encrypted_password(&self) -> Option<crate::Group>;
|
fn get_encrypted_password(&self) -> Option<&str>;
|
||||||
fn get_gid(&self) -> Option<crate::Group>;
|
fn get_gid(&self) -> Option<u32>;
|
||||||
fn get_members(&self) -> Option<crate::Group>;
|
fn get_member_names(&self) -> Option<Vec<&str>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GroupWrite<T> {
|
pub trait GroupWrite<T> {
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
use crate::userlib::NewFromString;
|
use crate::userlib::NewFromString;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
use crate::userlib_error::UserLibError;
|
use crate::userlib_error::UserLibError;
|
||||||
use std::cmp::Eq;
|
use std::cmp::Eq;
|
||||||
@ -58,18 +57,27 @@ pub struct Group {
|
|||||||
members: Vec<crate::Username>, /* Real name. */
|
members: Vec<crate::Username>, /* Real name. */
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Group {
|
use crate::api::GroupRead;
|
||||||
|
impl GroupRead for Group {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_groupname(&self) -> &str {
|
fn get_groupname(&self) -> Option<&str> {
|
||||||
&self.groupname.groupname
|
Some(&self.groupname.groupname)
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn get_members(&self) -> &Vec<crate::Username> {
|
fn get_member_names(&self) -> Option<Vec<&str>> {
|
||||||
&self.members
|
let mut r: Vec<&str> = Vec::new();
|
||||||
|
for u in self.members.iter() {
|
||||||
|
r.push(&u.username);
|
||||||
|
}
|
||||||
|
Some(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gid(&self) -> u32 {
|
fn get_gid(&self) -> Option<u32> {
|
||||||
self.gid.get_gid()
|
Some(self.gid.get_gid())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_encrypted_password(&self) -> Option<&str> {
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,14 +99,16 @@ impl Display for Group {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NewFromString for Group {
|
impl NewFromString for Group {
|
||||||
/// Parse a line formatted like one in `/etc/shadow` and construct a matching `Shadow` instance
|
/// Parse a line formatted like one in `/etc/group` and construct a matching [`Group`] instance
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// /*let shad = adduser::shadow::Shadow::new_from_string(
|
/// use crate::adduser::api::GroupRead;
|
||||||
/// "test:!!$6$/RotIe4VZzzAun4W$7YUONvru1rDnllN5TvrnOMsWUD5wSDUPAD6t6/Xwsr/0QOuWF3HcfAhypRkGa8G1B9qqWV5kZSnCb8GKMN9N61:18260:0:99999:7:::"
|
/// use adduser::NewFromString;
|
||||||
|
/// let grp = adduser::Group::new_from_string(
|
||||||
|
/// "teste:x:1002:test,teste".to_owned()
|
||||||
/// ).unwrap();
|
/// ).unwrap();
|
||||||
/// assert_eq!(shad.get_username(), "test");*/
|
/// assert_eq!(grp.get_groupname().unwrap(), "teste");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
@ -148,11 +158,11 @@ fn test_parse_and_back_identity() {
|
|||||||
fn test_groupname() {
|
fn test_groupname() {
|
||||||
let line = "teste:x:1002:test,teste";
|
let line = "teste:x:1002:test,teste";
|
||||||
let line2 = Group::new_from_string(line.to_owned()).unwrap();
|
let line2 = Group::new_from_string(line.to_owned()).unwrap();
|
||||||
assert_eq!(line2.get_groupname(), "teste");
|
assert_eq!(line2.get_groupname().unwrap(), "teste");
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_root_group() {
|
fn test_root_group() {
|
||||||
let line = "root:x:0:";
|
let line = "root:x:0:";
|
||||||
let line2 = Group::new_from_string(line.to_owned()).unwrap();
|
let line2 = Group::new_from_string(line.to_owned()).unwrap();
|
||||||
assert_eq!(line2.get_groupname(), "root");
|
assert_eq!(line2.get_groupname().unwrap(), "root");
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ pub enum Gecos {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Gecos {
|
impl Gecos {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_comment(&'a self) -> Option<&'a str> {
|
pub fn get_comment(&self) -> Option<&str> {
|
||||||
match &self {
|
match &self {
|
||||||
Gecos::Simple { comment, .. } => Some(&comment),
|
Gecos::Simple { comment, .. } => Some(&comment),
|
||||||
Gecos::Detail { .. } => None,
|
Gecos::Detail { .. } => None,
|
||||||
@ -70,7 +70,7 @@ impl<'a> Gecos {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_phone_home(&'_ self) -> Option<&'_ str> {
|
pub fn get_phone_home(&self) -> Option<&str> {
|
||||||
match &self {
|
match &self {
|
||||||
Gecos::Simple { .. } => None,
|
Gecos::Simple { .. } => None,
|
||||||
Gecos::Detail { phone_home, .. } => {
|
Gecos::Detail { phone_home, .. } => {
|
||||||
|
@ -20,18 +20,19 @@ pub struct User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NewFromString for User {
|
impl NewFromString for User {
|
||||||
/// Parse a line formatted like one in `/etc/passwd` and construct a matching [`adduser::User`] instance
|
/// Parse a line formatted like one in `/etc/passwd` and construct a matching [`User`] instance
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
/// use crate::adduser::api::UserRead;
|
||||||
/// use adduser::NewFromString;
|
/// use adduser::NewFromString;
|
||||||
/// let pwd = adduser::User::new_from_string(
|
/// let pwd = adduser::User::new_from_string(
|
||||||
/// "testuser:testpassword:1001:1001:full Name,,,,:/home/test:/bin/test".to_string()).unwrap();
|
/// "testuser:testpassword:1001:1001:full Name,,,,:/home/test:/bin/test".to_string()).unwrap();
|
||||||
/// assert_eq!(pwd.get_username(), "testuser");
|
/// assert_eq!(pwd.get_username().unwrap(), "testuser");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// When parsing fails this function returns a `UserLibError::Message` containing some information as to why the function failed.
|
/// When parsing fails this function returns a [`UserLibError::Message`](crate::userlib_error::UserLibError::Message) containing some information as to why the function failed.
|
||||||
fn new_from_string(line: String) -> Result<Self, crate::UserLibError>
|
fn new_from_string(line: String) -> Result<Self, crate::UserLibError>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@ -56,38 +57,58 @@ impl NewFromString for User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl crate::api::UserRead for User {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_username(&self) -> &str {
|
fn get_username(&self) -> Option<&str> {
|
||||||
&self.username.username
|
Some(&self.username.username)
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_password(&self) -> &str {
|
fn get_password(&self) -> Option<&str> {
|
||||||
match &self.password {
|
match &self.password {
|
||||||
crate::Password::Encrypted(crate::EncryptedPassword { password }) => &password,
|
crate::Password::Encrypted(crate::EncryptedPassword { password }) => Some(&password),
|
||||||
crate::Password::Shadow(crate::Shadow { ref password, .. }) => &password.password,
|
crate::Password::Shadow(crate::Shadow { ref password, .. }) => Some(&password.password),
|
||||||
crate::Password::Disabled => &"x",
|
crate::Password::Disabled => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn get_uid(&self) -> u32 {
|
fn get_uid(&self) -> u32 {
|
||||||
self.uid.uid
|
self.uid.uid
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn get_gid(&self) -> u32 {
|
fn get_gid(&self) -> u32 {
|
||||||
self.gid.gid
|
self.gid.gid
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn get_comment(&self) -> &crate::Gecos {
|
fn get_gecos(&self) -> Option<&crate::Gecos> {
|
||||||
&self.gecos
|
Some(&self.gecos)
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_home_dir(&self) -> &str {
|
fn get_home_dir(&self) -> Option<&str> {
|
||||||
&self.home_dir.dir
|
Some(&self.home_dir.dir)
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_shell_path(&self) -> &str {
|
fn get_shell_path(&self) -> Option<&str> {
|
||||||
&self.shell_path.shell
|
Some(&self.shell_path.shell)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_full_name(&self) -> Option<&str> {
|
||||||
|
self.gecos.get_full_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_room(&self) -> Option<&str> {
|
||||||
|
self.gecos.get_room()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_phone_work(&self) -> Option<&str> {
|
||||||
|
self.gecos.get_phone_work()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_phone_home(&self) -> Option<&str> {
|
||||||
|
self.gecos.get_phone_home()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_other(&self) -> Option<&Vec<String>> {
|
||||||
|
self.gecos.get_other()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ use std::fmt::{self, Display};
|
|||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Username {
|
pub struct Username {
|
||||||
/// The username value
|
/// The username value
|
||||||
pub(in crate::user) username: String,
|
pub(crate) username: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Username {
|
impl Display for Username {
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
)]
|
)]
|
||||||
#![allow(clippy::non_ascii_literal)]
|
#![allow(clippy::non_ascii_literal)]
|
||||||
|
|
||||||
|
use crate::api::GroupRead;
|
||||||
|
use crate::api::UserRead;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -103,7 +105,7 @@ impl UserDBRead for UserDBLocal {
|
|||||||
|
|
||||||
fn get_group_by_name(&self, name: &str) -> Option<&crate::Group> {
|
fn get_group_by_name(&self, name: &str) -> Option<&crate::Group> {
|
||||||
for group in self.groups.iter() {
|
for group in self.groups.iter() {
|
||||||
if group.get_groupname() == name {
|
if group.get_groupname().unwrap() == name {
|
||||||
return Some(group);
|
return Some(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +114,7 @@ impl UserDBRead for UserDBLocal {
|
|||||||
|
|
||||||
fn get_group_by_id(&self, id: u32) -> Option<&crate::Group> {
|
fn get_group_by_id(&self, id: u32) -> Option<&crate::Group> {
|
||||||
for group in self.groups.iter() {
|
for group in self.groups.iter() {
|
||||||
if group.get_gid() == id {
|
if group.get_gid().unwrap() == id {
|
||||||
return Some(group);
|
return Some(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,12 +138,15 @@ impl UserDBValidation for UserDBLocal {
|
|||||||
|
|
||||||
fn is_gid_valid_and_free(&self, gid: u32) -> bool {
|
fn is_gid_valid_and_free(&self, gid: u32) -> bool {
|
||||||
warn!("No valid check, only free check");
|
warn!("No valid check, only free check");
|
||||||
self.groups.iter().all(|x| x.get_gid() != gid)
|
self.groups.iter().all(|x| x.get_gid().unwrap() != gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_groupname_valid_and_free(&self, name: &str) -> bool {
|
fn is_groupname_valid_and_free(&self, name: &str) -> bool {
|
||||||
let valid = crate::group::is_groupname_valid(name);
|
let valid = crate::group::is_groupname_valid(name);
|
||||||
let free = self.groups.iter().all(|x| x.get_groupname() != name);
|
let free = self
|
||||||
|
.groups
|
||||||
|
.iter()
|
||||||
|
.all(|x| x.get_groupname().unwrap() != name);
|
||||||
valid && free
|
valid && free
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,14 +179,21 @@ fn shadow_to_users(
|
|||||||
fn user_vec_to_hashmap(users: Vec<crate::User>) -> HashMap<String, crate::User> {
|
fn user_vec_to_hashmap(users: Vec<crate::User>) -> HashMap<String, crate::User> {
|
||||||
users
|
users
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| (x.get_username().to_owned(), x))
|
.map(|x| {
|
||||||
|
(
|
||||||
|
x.get_username()
|
||||||
|
.expect("An empty username is not supported")
|
||||||
|
.to_owned(),
|
||||||
|
x,
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to parse a String into some Object
|
/// Try to parse a String into some Object
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// if the parsing failed a [`UserLibError::Message`] is returned containing a more detailed error message.
|
/// if the parsing failed a [`UserLibError::Message`](crate::userlib_error::UserLibError::Message) is returned containing a more detailed error message.
|
||||||
pub trait NewFromString {
|
pub trait NewFromString {
|
||||||
fn new_from_string(line: String) -> Result<Self, crate::UserLibError>
|
fn new_from_string(line: String) -> Result<Self, crate::UserLibError>
|
||||||
where
|
where
|
||||||
@ -209,7 +221,10 @@ where
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_creator_user_db_local() {
|
fn test_creator_user_db_local() {
|
||||||
let data = UserDBLocal::import_from_strings("test:x:1001:1001:full Name,004,000342,001-2312,myemail@test.com:/home/test:/bin/test", "test:!!$6$/RotIe4VZzzAun4W$7YUONvru1rDnllN5TvrnOMsWUD5wSDUPAD6t6/Xwsr/0QOuWF3HcfAhypRkGa8G1B9qqWV5kZSnCb8GKMN9N61:18260:0:99999:7:::", "teste:x:1002:test,test");
|
let data = UserDBLocal::import_from_strings("test:x:1001:1001:full Name,004,000342,001-2312,myemail@test.com:/home/test:/bin/test", "test:!!$6$/RotIe4VZzzAun4W$7YUONvru1rDnllN5TvrnOMsWUD5wSDUPAD6t6/Xwsr/0QOuWF3HcfAhypRkGa8G1B9qqWV5kZSnCb8GKMN9N61:18260:0:99999:7:::", "teste:x:1002:test,test");
|
||||||
assert_eq!(data.users.get("test").unwrap().get_username(), "test")
|
assert_eq!(
|
||||||
|
data.users.get("test").unwrap().get_username().unwrap(),
|
||||||
|
"test"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -218,7 +233,7 @@ fn test_parsing_local_database() {
|
|||||||
let my_passwd_lines = file_to_string(Some(&PathBuf::from("/etc/passwd")));
|
let my_passwd_lines = file_to_string(Some(&PathBuf::from("/etc/passwd")));
|
||||||
let my_group_lines = file_to_string(Some(&PathBuf::from("/etc/group")));
|
let my_group_lines = file_to_string(Some(&PathBuf::from("/etc/group")));
|
||||||
let data = UserDBLocal::import_from_strings(&my_passwd_lines, "", &my_group_lines);
|
let data = UserDBLocal::import_from_strings(&my_passwd_lines, "", &my_group_lines);
|
||||||
assert_eq!(data.groups.get(0).unwrap().get_groupname(), "root");
|
assert_eq!(data.groups.get(0).unwrap().get_groupname().unwrap(), "root");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -230,11 +245,20 @@ fn test_user_db_read_implementation() {
|
|||||||
assert!(data.get_all_users().len() > 10);
|
assert!(data.get_all_users().len() > 10);
|
||||||
assert!(data.get_user_by_name("root").is_some());
|
assert!(data.get_user_by_name("root").is_some());
|
||||||
assert_eq!(data.get_user_by_name("root").unwrap().get_uid(), 0);
|
assert_eq!(data.get_user_by_name("root").unwrap().get_uid(), 0);
|
||||||
assert_eq!(data.get_user_by_id(0).unwrap().get_username(), "root");
|
assert_eq!(
|
||||||
|
data.get_user_by_id(0).unwrap().get_username().unwrap(),
|
||||||
|
"root"
|
||||||
|
);
|
||||||
assert!(data.get_all_groups().len() > 10);
|
assert!(data.get_all_groups().len() > 10);
|
||||||
assert!(data.get_group_by_name("root").is_some());
|
assert!(data.get_group_by_name("root").is_some());
|
||||||
assert_eq!(data.get_group_by_name("root").unwrap().get_gid(), 0);
|
assert_eq!(
|
||||||
assert_eq!(data.get_group_by_id(0).unwrap().get_groupname(), "root");
|
data.get_group_by_name("root").unwrap().get_gid().unwrap(),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
data.get_group_by_id(0).unwrap().get_groupname().unwrap(),
|
||||||
|
"root"
|
||||||
|
);
|
||||||
assert!(data.get_user_by_name("norealnameforsure").is_none());
|
assert!(data.get_user_by_name("norealnameforsure").is_none());
|
||||||
assert!(data.get_group_by_name("norealgroupforsure").is_none());
|
assert!(data.get_group_by_name("norealgroupforsure").is_none());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user