test2
This commit is contained in:
parent
310575a8e9
commit
bceb479c78
22
src/api.rs
Normal file
22
src/api.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
trait UserDBRead {
|
||||||
|
fn get_all_users(&self) -> Vec<crate::Passwd>;
|
||||||
|
fn get_user_by_name(&self, name: &str) -> Option<crate::Passwd>;
|
||||||
|
fn get_user_by_id(&self, uid: u64) -> Option<crate::Passwd>;
|
||||||
|
fn get_all_groups(&self) -> Vec<crate::Group>;
|
||||||
|
fn get_group_by_name(&self) -> Option<crate::Group>;
|
||||||
|
fn get_group_by_id(&self) -> Option<crate::Group>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait UserDBValidation {
|
||||||
|
fn is_uid_valid_and_free(&self) -> bool;
|
||||||
|
fn is_username_valid_and_free(&self) -> bool;
|
||||||
|
fn is_gid_valid_and_free(&self) -> bool;
|
||||||
|
fn is_groupname_valid_and_free(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait UserDBWrite {
|
||||||
|
fn set_user(&self) -> Option<crate::Passwd>;
|
||||||
|
fn new_user(&self) -> Option<crate::Passwd>;
|
||||||
|
fn set_group(&self) -> Option<crate::Group>;
|
||||||
|
fn new_group(&self) -> Option<crate::Group>;
|
||||||
|
}
|
143
src/group.rs
Normal file
143
src/group.rs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#![warn(
|
||||||
|
clippy::all,
|
||||||
|
/* clippy::restriction,*/
|
||||||
|
clippy::pedantic,
|
||||||
|
clippy::nursery,
|
||||||
|
clippy::cargo
|
||||||
|
)]
|
||||||
|
#![allow(clippy::non_ascii_literal)]
|
||||||
|
|
||||||
|
use log::warn;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use crate::passwd;
|
||||||
|
use crate::userlib_error::UserLibError;
|
||||||
|
use std::cmp::Eq;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::fmt::{self, Debug, Display};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Groupname<'a> {
|
||||||
|
groupname: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Groupname<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.groupname,)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for Groupname<'a> {
|
||||||
|
type Error = UserLibError;
|
||||||
|
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
|
||||||
|
lazy_static! {
|
||||||
|
static ref USERVALIDATION: Regex =
|
||||||
|
Regex::new("^[a-z_]([a-z0-9_\\-]{0,31}|[a-z0-9_\\-]{0,30}\\$)$").unwrap();
|
||||||
|
}
|
||||||
|
if USERVALIDATION.is_match(source) {
|
||||||
|
Ok(Self { groupname: source })
|
||||||
|
} else if source == "Debian-exim" {
|
||||||
|
warn!("username {} is not a valid username. This might cause problems. (It is default in Debian and Ubuntu)", source);
|
||||||
|
Ok(Self { groupname: source })
|
||||||
|
} else {
|
||||||
|
Err(UserLibError::Message(format!(
|
||||||
|
"Invalid username {}",
|
||||||
|
source
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A record(line) in the user database `/etc/shadow` found in most linux systems.
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Group<'a> {
|
||||||
|
groupname: Groupname<'a>, /* Username. */
|
||||||
|
pub(crate) password: passwd::Password<'a>, /* Usually not used (disabled with x) */
|
||||||
|
gid: passwd::Gid, /* Group ID. */
|
||||||
|
members: Vec<passwd::Username<'a>>, /* Real name. */
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Group<'a> {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn get_groupname(&self) -> &'a str {
|
||||||
|
self.groupname.groupname
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub const fn get_members(&self) -> &Vec<passwd::Username<'a>> {
|
||||||
|
&self.members
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Display for Group<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}:{}:{}:{}",
|
||||||
|
self.groupname,
|
||||||
|
self.password,
|
||||||
|
self.gid,
|
||||||
|
self.members
|
||||||
|
.iter()
|
||||||
|
.map(|mem| format!("{}", mem))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(",")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Group<'a> {
|
||||||
|
/// Parse a line formatted like one in `/etc/shadow` and construct a matching `Shadow` instance
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// /*let shad = adduser::shadow::Shadow::new_from_string(
|
||||||
|
/// "test:!!$6$/RotIe4VZzzAun4W$7YUONvru1rDnllN5TvrnOMsWUD5wSDUPAD6t6/Xwsr/0QOuWF3HcfAhypRkGa8G1B9qqWV5kZSnCb8GKMN9N61:18260:0:99999:7:::"
|
||||||
|
/// ).unwrap();
|
||||||
|
/// assert_eq!(shad.get_username(), "test");*/
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// When parsing fails this function returns a `UserLibError::Message` containing some information as to why the function failed.
|
||||||
|
pub fn new_from_string(line: &'a str) -> Result<Self, UserLibError> {
|
||||||
|
println!("{}", &line);
|
||||||
|
let elements: Vec<&str> = line.split(':').collect();
|
||||||
|
if elements.len() == 4 {
|
||||||
|
Ok(Group {
|
||||||
|
groupname: Groupname::try_from(*elements.get(0).unwrap())?,
|
||||||
|
password: passwd::Password::Disabled,
|
||||||
|
gid: passwd::Gid::try_from(*elements.get(2).unwrap())?,
|
||||||
|
members: parse_members_list(*elements.get(3).unwrap()),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(UserLibError::Message(format!(
|
||||||
|
"Failed to parse: not enough elements ({}): {:?}",
|
||||||
|
elements.len(),
|
||||||
|
elements
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_members_list<'a>(source: &'a str) -> Vec<passwd::Username<'a>> {
|
||||||
|
let mut res = vec![];
|
||||||
|
for mem in source.split(',') {
|
||||||
|
res.push(passwd::Username::try_from(mem).expect("failed to parse username"));
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_and_back_identity() {
|
||||||
|
println!("Test");
|
||||||
|
let line = "teste:x:1002:test,teste";
|
||||||
|
let line2 = Group::new_from_string(line).unwrap();
|
||||||
|
assert_eq!(format!("{}", line2), line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_groupname() {
|
||||||
|
println!("Test");
|
||||||
|
let line = "teste:x:1002:test,teste";
|
||||||
|
let line2 = Group::new_from_string(line).unwrap();
|
||||||
|
assert_eq!(line2.get_groupname(), "teste");
|
||||||
|
}
|
57
src/userlib.rs
Normal file
57
src/userlib.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#![warn(
|
||||||
|
clippy::all,
|
||||||
|
/* clippy::restriction,*/
|
||||||
|
clippy::pedantic,
|
||||||
|
clippy::nursery,
|
||||||
|
clippy::cargo
|
||||||
|
)]
|
||||||
|
#![allow(clippy::non_ascii_literal)]
|
||||||
|
|
||||||
|
use log::warn;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use crate::userlib_error::UserLibError;
|
||||||
|
use std::cmp::Eq;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::fmt::{self, Display};
|
||||||
|
use std::io::{BufRead, Read};
|
||||||
|
|
||||||
|
pub struct UserDBLocal<'a> {
|
||||||
|
pub(crate) passwd_entries: Vec<crate::Passwd<'a>>,
|
||||||
|
pub(crate) shadow_entries: Vec<crate::Shadow<'a>>,
|
||||||
|
pub(crate) group_entries: Vec<crate::Group<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> UserDBLocal<'a> {
|
||||||
|
#[must_use]
|
||||||
|
pub fn import_from_strings(
|
||||||
|
passwd_content: &'a str,
|
||||||
|
shadow_content: &'a str,
|
||||||
|
group_content: &'a str,
|
||||||
|
) -> Self {
|
||||||
|
let res = UserDBLocal {
|
||||||
|
passwd_entries: passwd_content
|
||||||
|
.lines()
|
||||||
|
.map(|line| crate::Passwd::new_from_string(line).expect("failed to read lines"))
|
||||||
|
.collect(),
|
||||||
|
group_entries: group_content
|
||||||
|
.lines()
|
||||||
|
.map(|line| crate::Group::new_from_string(line).expect("Parsing failed"))
|
||||||
|
.collect(),
|
||||||
|
shadow_entries: shadow_content
|
||||||
|
.lines()
|
||||||
|
.map(|line| crate::Shadow::new_from_string(line).expect("Parsing failed"))
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_creator_user_db_local() {
|
||||||
|
let data = UserDBLocal::import_from_strings("testuser: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,teste");
|
||||||
|
assert_eq!(
|
||||||
|
data.passwd_entries.get(0).unwrap().get_username(),
|
||||||
|
"testuser"
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user