first version of create_user

This commit is contained in:
Dietrich 2020-11-10 13:45:21 +01:00
parent ed06c58913
commit de17ff12be
10 changed files with 174 additions and 85 deletions

View File

@ -0,0 +1,40 @@
#![allow(clippy::default_trait_access)]
use std::path::PathBuf;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CreateHome {
Create,
Skip,
HomeFromDir { path: PathBuf },
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CreatePrimaryGroup {
Create,
Skip,
CreateIfEmptyOrAdd,
}
#[derive(Debug, Builder, Eq, PartialEq)]
#[builder(public)]
#[builder(default)]
pub struct CreateUserArgs<'a> {
pub username: &'a str,
pub delete_home: CreateHome,
pub delete_primary_group: CreatePrimaryGroup,
}
impl<'a> CreateUserArgs<'a> {
#[must_use]
pub fn builder() -> CreateUserArgsBuilder<'a> {
CreateUserArgsBuilder::default()
}
}
impl Default for CreateUserArgs<'_> {
fn default() -> Self {
Self {
username: "defaultuser",
delete_home: CreateHome::Create,
delete_primary_group: CreatePrimaryGroup::CreateIfEmptyOrAdd,
}
}
}

View File

@ -16,20 +16,20 @@ pub enum DeletePrimaryGroup {
#[derive(Debug, Builder, Eq, PartialEq)]
#[builder(public)]
#[builder(default)]
pub struct NewUserArgs<'a> {
pub struct DeleteUserArgs<'a> {
pub username: &'a str,
pub delete_home: DeleteHome,
pub delete_primary_group: DeletePrimaryGroup,
}
impl<'a> NewUserArgs<'a> {
impl<'a> DeleteUserArgs<'a> {
#[must_use]
pub fn builder() -> NewUserArgsBuilder<'a> {
NewUserArgsBuilder::default()
pub fn builder() -> DeleteUserArgsBuilder<'a> {
DeleteUserArgsBuilder::default()
}
}
impl Default for NewUserArgs<'_> {
impl Default for DeleteUserArgs<'_> {
fn default() -> Self {
Self {
username: "defaultuser",

View File

@ -1,6 +1,8 @@
pub mod newuser_args;
pub mod createuser_args;
pub mod deleteuser_args;
pub use newuser_args::{DeleteHome, DeletePrimaryGroup, NewUserArgs};
pub use createuser_args::{CreateHome, CreatePrimaryGroup, CreateUserArgs};
pub use deleteuser_args::{DeleteHome, DeletePrimaryGroup, DeleteUserArgs};
pub trait UserDBRead {
fn get_all_users(&self) -> Vec<&crate::User>;
fn get_user_by_name(&self, name: &str) -> Option<&crate::User>;
@ -18,24 +20,8 @@ pub trait UserDBValidation {
}
pub trait UserDBWrite {
fn delete_user(
&mut self,
params: newuser_args::NewUserArgs,
) -> Result<crate::User, crate::UserLibError>;
fn new_user(
&mut self, /*
username: String,
enc_password: String,
uid: u32,
gid: u32,
full_name: String,
room: String,
phone_work: String,
phone_home: String,
other: Option<Vec<String>>,
home_dir: String,
shell_path: String,*/
) -> Result<&crate::User, crate::UserLibError>;
fn delete_user(&mut self, params: DeleteUserArgs) -> Result<crate::User, crate::UserLibError>;
fn new_user(&mut self, params: CreateUserArgs) -> Result<&crate::User, crate::UserLibError>;
fn delete_group(&mut self, group: &crate::Group) -> Result<(), crate::UserLibError>;
fn new_group(&mut self) -> Result<&crate::Group, crate::UserLibError>;
}

View File

@ -1,15 +1,26 @@
use std::path::PathBuf;
extern crate adduser;
use adduser::api::UserDBWrite;
fn main() {
simplelog::CombinedLogger::init(vec![simplelog::TermLogger::new(
simplelog::LevelFilter::Warn,
simplelog::Config::default(),
simplelog::TerminalMode::Mixed,
)])
.unwrap();
//use adduser::api::UserDBWrite;
env_logger::init();
let _db = adduser::UserDBLocal::load_files(adduser::Files::default());
let mf = adduser::Files {
passwd: Some(PathBuf::from("./passwd")),
shadow: Some(PathBuf::from("./shadow")),
group: Some(PathBuf::from("./group")),
};
let mut db = adduser::UserDBLocal::load_files(mf).unwrap();
let _user_res: Result<&adduser::User, adduser::UserLibError> = db.new_user(
adduser::api::CreateUserArgs::builder()
.username("teste")
// .delete_home(adduser::api::DeleteHome::Delete)
.build()
.unwrap(),
);
let user = adduser::User::default()
.username("fest".into())

View File

@ -21,7 +21,7 @@ fn main() {
let mut db = adduser::UserDBLocal::load_files(mf).unwrap();
let user_res: Result<adduser::User, adduser::UserLibError> = db.delete_user(
adduser::api::NewUserArgs::builder()
adduser::api::DeleteUserArgs::builder()
.username("teste")
// .delete_home(adduser::api::DeleteHome::Delete)
.build()

View File

@ -1,3 +1,4 @@
#![feature(option_expect_none)]
#![warn(
clippy::all,
//clippy::restriction,

View File

@ -1,12 +1,13 @@
use std::path::PathBuf;
use std::{io::Seek, io::SeekFrom, path::PathBuf};
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::fs::File;
use std::fs::{File, OpenOptions};
use std::io::Read;
use std::io::Write;
use std::ops::Deref;
#[derive(Debug)]
pub struct Files {
pub passwd: Option<PathBuf>,
pub shadow: Option<PathBuf>,
@ -62,14 +63,18 @@ impl Files {
}
}
#[derive(Debug)]
pub struct LockedFileGuard {
lockfile: PathBuf,
path: PathBuf,
pub(crate) file: File,
}
#[derive(Debug)]
struct TempLockFile {
tlf: PathBuf,
}
impl Drop for TempLockFile {
fn drop(&mut self) {
info!("removing temporary lockfile {}", self.tlf.to_str().unwrap());
@ -82,7 +87,6 @@ impl Deref for TempLockFile {
&self.tlf
}
}
impl LockedFileGuard {
pub fn new(path: &PathBuf) -> Result<Self, crate::UserLibError> {
let locked = Self::try_to_lock_file(path);
@ -109,6 +113,27 @@ impl LockedFileGuard {
Ok(())
}
pub fn append(&mut self, appendee: String) -> Result<(), crate::UserLibError> {
// Seek to the last character.
self.file.seek(SeekFrom::End(-1)).map_or_else(
|e| Err(format!("Failed to append to file {}", e)),
|_| Ok(()),
)?;
// Read the last character
let mut b = [0 as u8; 1];
self.file.read_exact(&mut b)?;
// Verify it is '\n' else append '\n' so in any case the file ends with with a newline now
if &b != b"\n" {
//self.file.write_all(&b)?;
self.file.write_all(b"\n")?;
}
// write the new line.
self.file.write_all(&appendee.into_bytes()).map_or_else(
|e| Err(("Failed to append to file".to_owned(), e).into()),
Ok,
)
}
/// This function tries to lock a file in the way other passwd locking mechanisms work.
///
/// * get the pid
@ -177,7 +202,7 @@ impl LockedFileGuard {
debug!("successfully locked");
// open the file
let resfile = File::open(&path);
let resfile = OpenOptions::new().read(true).write(true).open(&path);
return match resfile {
Ok(file) => Ok((lockfilepath, file)),
Err(e) => {

View File

@ -3,8 +3,12 @@
pub mod files;
pub mod hashes;
use crate::api::UserRead;
use crate::{api::GroupRead, UserLibError};
use crate::{
api::{
CreateUserArgs, DeleteHome, DeleteUserArgs, GroupRead, UserDBRead, UserDBWrite, UserRead,
},
UserLibError,
};
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::collections::HashMap;
@ -146,9 +150,8 @@ impl UserDBLocal {
}
}
use crate::api::{DeleteHome, NewUserArgs, UserDBRead, UserDBWrite};
impl UserDBWrite for UserDBLocal {
fn delete_user(&mut self, args: NewUserArgs) -> Result<crate::User, UserLibError> {
fn delete_user(&mut self, args: DeleteUserArgs) -> Result<crate::User, UserLibError> {
// try to get the user from the database
let user_opt = self.get_user_by_name(args.username);
let user = match user_opt {
@ -218,47 +221,28 @@ impl UserDBWrite for UserDBLocal {
}
}
fn new_user(
&mut self, /*
username: String,
enc_password: String,
uid: u32,
gid: u32,
full_name: String,
room: String,
phone_work: String,
phone_home: String,
other: Option<Vec<String>>,
home_dir: String,
shell_path: String,*/
) -> Result<&crate::User, crate::UserLibError> {
/*if self.users.contains_key(&username) {
Err(format!(
"The username {} already exists! Aborting!",
username
)
.into())
fn new_user(&mut self, args: CreateUserArgs) -> Result<&crate::User, crate::UserLibError> {
if self.users.contains_key(args.username) {
Err(format!("The username {} already exists! Aborting!", args.username).into())
} else {
let pwd = if self.source_files.shadow.is_none(){
crate::Password::Encrypted(crate::EncryptedPassword{});
let mut new_user = crate::User::default();
new_user.username(args.username.to_owned());
if self.users.contains_key(args.username) {
Err("Failed to create the user. A user with the same Name already exists".into())
} else {
let opened = self.source_files.lock_all_get();
let (mut locked_p, mut _locked_s, mut _locked_g) =
opened.expect("failed to lock files!");
dbg!(&locked_p);
locked_p.append(format!("{}", new_user))?;
self.users
.insert(args.username.to_owned(), new_user)
.expect_none("Is always none");
self.users
.get(args.username)
.map_or_else(|| Err("User was not successfully added!".into()), Ok)
}
else{
crate::Password::Shadow(crate::Shadow{})
}
self.users.insert(
username,
crate::User {
username: crate::Username { username },
password:,
uid: crate::Uid{uid},
gid:crate::Gid{gid},
gecos: crate::Gecos{},
home_dir:crate::HomeDir{dir: home_dir},
shell_path: crate::ShellPath{shell: shell_path},
},
)
}*/
todo!()
}
}
fn delete_group(&mut self, _group: &crate::Group) -> Result<(), crate::UserLibError> {
@ -472,16 +456,16 @@ fn test_user_db_read_implementation() {
#[test]
fn test_user_db_write_implementation() {
use crate::api::NewUserArgs;
use crate::api::DeleteUserArgs;
let mut 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 user = "test";
assert_eq!(data.get_all_users().len(), 1);
assert!(data
.delete_user(NewUserArgs::builder().username(user).build().unwrap())
.delete_user(DeleteUserArgs::builder().username(user).build().unwrap())
.is_ok());
assert!(data
.delete_user(NewUserArgs::builder().username(user).build().unwrap())
.delete_user(DeleteUserArgs::builder().username(user).build().unwrap())
.is_err());
assert_eq!(data.get_all_users().len(), 0);
}

42
tests/create_user_test.rs Normal file
View File

@ -0,0 +1,42 @@
extern crate adduser;
mod testfiles;
#[test]
fn test_create_user_function() {
use testfiles::Fixture;
use adduser::api::UserDBWrite;
use adduser::api::UserRead;
use std::fs;
let p = Fixture::copy("passwd");
let s = Fixture::copy("shadow");
let g = Fixture::copy("group");
let pf = fs::read_to_string(&p.path).unwrap();
let mf = adduser::Files {
passwd: Some(p.path.clone()),
shadow: Some(s.path),
group: Some(g.path),
};
let mut db = adduser::UserDBLocal::load_files(mf).unwrap();
let user_res: Result<&adduser::User, adduser::UserLibError> = db.new_user(
adduser::api::CreateUserArgs::builder()
.username("test2")
// .delete_home(adduser::api::DeleteHome::Delete)
.build()
.unwrap(),
);
let pf2 = fs::read_to_string(&p.path).unwrap();
assert_eq!(user_res.unwrap().get_username().unwrap(), "test2");
let pflines = pf.lines();
let pflines2 = pf2.lines();
for (l1, l2) in pflines.zip(pflines2) {
dbg!(l1, l2);
assert!(l1 == l2);
}
assert!(pf2.lines().last().unwrap().starts_with("test2"));
}

View File

@ -24,7 +24,7 @@ fn test_delete_user_function() {
let mut db = adduser::UserDBLocal::load_files(mf).unwrap();
let user_res: Result<adduser::User, adduser::UserLibError> = db.delete_user(
adduser::api::NewUserArgs::builder()
adduser::api::DeleteUserArgs::builder()
.username("teste")
// .delete_home(adduser::api::DeleteHome::Delete)
.build()