first version of create_user
This commit is contained in:
parent
ed06c58913
commit
de17ff12be
40
src/api/createuser_args.rs
Normal file
40
src/api/createuser_args.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,20 +16,20 @@ pub enum DeletePrimaryGroup {
|
|||||||
#[derive(Debug, Builder, Eq, PartialEq)]
|
#[derive(Debug, Builder, Eq, PartialEq)]
|
||||||
#[builder(public)]
|
#[builder(public)]
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
pub struct NewUserArgs<'a> {
|
pub struct DeleteUserArgs<'a> {
|
||||||
pub username: &'a str,
|
pub username: &'a str,
|
||||||
pub delete_home: DeleteHome,
|
pub delete_home: DeleteHome,
|
||||||
pub delete_primary_group: DeletePrimaryGroup,
|
pub delete_primary_group: DeletePrimaryGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> NewUserArgs<'a> {
|
impl<'a> DeleteUserArgs<'a> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn builder() -> NewUserArgsBuilder<'a> {
|
pub fn builder() -> DeleteUserArgsBuilder<'a> {
|
||||||
NewUserArgsBuilder::default()
|
DeleteUserArgsBuilder::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NewUserArgs<'_> {
|
impl Default for DeleteUserArgs<'_> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
username: "defaultuser",
|
username: "defaultuser",
|
@ -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 {
|
pub trait UserDBRead {
|
||||||
fn get_all_users(&self) -> Vec<&crate::User>;
|
fn get_all_users(&self) -> Vec<&crate::User>;
|
||||||
fn get_user_by_name(&self, name: &str) -> Option<&crate::User>;
|
fn get_user_by_name(&self, name: &str) -> Option<&crate::User>;
|
||||||
@ -18,24 +20,8 @@ pub trait UserDBValidation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait UserDBWrite {
|
pub trait UserDBWrite {
|
||||||
fn delete_user(
|
fn delete_user(&mut self, params: DeleteUserArgs) -> Result<crate::User, crate::UserLibError>;
|
||||||
&mut self,
|
fn new_user(&mut self, params: CreateUserArgs) -> Result<&crate::User, crate::UserLibError>;
|
||||||
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_group(&mut self, group: &crate::Group) -> Result<(), crate::UserLibError>;
|
fn delete_group(&mut self, group: &crate::Group) -> Result<(), crate::UserLibError>;
|
||||||
fn new_group(&mut self) -> Result<&crate::Group, crate::UserLibError>;
|
fn new_group(&mut self) -> Result<&crate::Group, crate::UserLibError>;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,26 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
extern crate adduser;
|
extern crate adduser;
|
||||||
|
use adduser::api::UserDBWrite;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
simplelog::CombinedLogger::init(vec![simplelog::TermLogger::new(
|
env_logger::init();
|
||||||
simplelog::LevelFilter::Warn,
|
|
||||||
simplelog::Config::default(),
|
|
||||||
simplelog::TerminalMode::Mixed,
|
|
||||||
)])
|
|
||||||
.unwrap();
|
|
||||||
//use adduser::api::UserDBWrite;
|
|
||||||
|
|
||||||
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()
|
let user = adduser::User::default()
|
||||||
.username("fest".into())
|
.username("fest".into())
|
||||||
|
@ -21,7 +21,7 @@ fn main() {
|
|||||||
let mut db = adduser::UserDBLocal::load_files(mf).unwrap();
|
let mut db = adduser::UserDBLocal::load_files(mf).unwrap();
|
||||||
|
|
||||||
let user_res: Result<adduser::User, adduser::UserLibError> = db.delete_user(
|
let user_res: Result<adduser::User, adduser::UserLibError> = db.delete_user(
|
||||||
adduser::api::NewUserArgs::builder()
|
adduser::api::DeleteUserArgs::builder()
|
||||||
.username("teste")
|
.username("teste")
|
||||||
// .delete_home(adduser::api::DeleteHome::Delete)
|
// .delete_home(adduser::api::DeleteHome::Delete)
|
||||||
.build()
|
.build()
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#![feature(option_expect_none)]
|
||||||
#![warn(
|
#![warn(
|
||||||
clippy::all,
|
clippy::all,
|
||||||
//clippy::restriction,
|
//clippy::restriction,
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use std::path::PathBuf;
|
use std::{io::Seek, io::SeekFrom, path::PathBuf};
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use std::fs::File;
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Files {
|
pub struct Files {
|
||||||
pub passwd: Option<PathBuf>,
|
pub passwd: Option<PathBuf>,
|
||||||
pub shadow: Option<PathBuf>,
|
pub shadow: Option<PathBuf>,
|
||||||
@ -62,14 +63,18 @@ impl Files {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct LockedFileGuard {
|
pub struct LockedFileGuard {
|
||||||
lockfile: PathBuf,
|
lockfile: PathBuf,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
pub(crate) file: File,
|
pub(crate) file: File,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct TempLockFile {
|
struct TempLockFile {
|
||||||
tlf: PathBuf,
|
tlf: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TempLockFile {
|
impl Drop for TempLockFile {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
info!("removing temporary lockfile {}", self.tlf.to_str().unwrap());
|
info!("removing temporary lockfile {}", self.tlf.to_str().unwrap());
|
||||||
@ -82,7 +87,6 @@ impl Deref for TempLockFile {
|
|||||||
&self.tlf
|
&self.tlf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LockedFileGuard {
|
impl LockedFileGuard {
|
||||||
pub fn new(path: &PathBuf) -> Result<Self, crate::UserLibError> {
|
pub fn new(path: &PathBuf) -> Result<Self, crate::UserLibError> {
|
||||||
let locked = Self::try_to_lock_file(path);
|
let locked = Self::try_to_lock_file(path);
|
||||||
@ -109,6 +113,27 @@ impl LockedFileGuard {
|
|||||||
Ok(())
|
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.
|
/// This function tries to lock a file in the way other passwd locking mechanisms work.
|
||||||
///
|
///
|
||||||
/// * get the pid
|
/// * get the pid
|
||||||
@ -177,7 +202,7 @@ impl LockedFileGuard {
|
|||||||
debug!("successfully locked");
|
debug!("successfully locked");
|
||||||
|
|
||||||
// open the file
|
// open the file
|
||||||
let resfile = File::open(&path);
|
let resfile = OpenOptions::new().read(true).write(true).open(&path);
|
||||||
return match resfile {
|
return match resfile {
|
||||||
Ok(file) => Ok((lockfilepath, file)),
|
Ok(file) => Ok((lockfilepath, file)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -3,8 +3,12 @@
|
|||||||
pub mod files;
|
pub mod files;
|
||||||
pub mod hashes;
|
pub mod hashes;
|
||||||
|
|
||||||
use crate::api::UserRead;
|
use crate::{
|
||||||
use crate::{api::GroupRead, UserLibError};
|
api::{
|
||||||
|
CreateUserArgs, DeleteHome, DeleteUserArgs, GroupRead, UserDBRead, UserDBWrite, UserRead,
|
||||||
|
},
|
||||||
|
UserLibError,
|
||||||
|
};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -146,9 +150,8 @@ impl UserDBLocal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::api::{DeleteHome, NewUserArgs, UserDBRead, UserDBWrite};
|
|
||||||
impl UserDBWrite for UserDBLocal {
|
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
|
// try to get the user from the database
|
||||||
let user_opt = self.get_user_by_name(args.username);
|
let user_opt = self.get_user_by_name(args.username);
|
||||||
let user = match user_opt {
|
let user = match user_opt {
|
||||||
@ -218,47 +221,28 @@ impl UserDBWrite for UserDBLocal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_user(
|
fn new_user(&mut self, args: CreateUserArgs) -> Result<&crate::User, crate::UserLibError> {
|
||||||
&mut self, /*
|
if self.users.contains_key(args.username) {
|
||||||
username: String,
|
Err(format!("The username {} already exists! Aborting!", args.username).into())
|
||||||
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())
|
|
||||||
} else {
|
} else {
|
||||||
let pwd = if self.source_files.shadow.is_none(){
|
let mut new_user = crate::User::default();
|
||||||
crate::Password::Encrypted(crate::EncryptedPassword{});
|
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> {
|
fn delete_group(&mut self, _group: &crate::Group) -> Result<(), crate::UserLibError> {
|
||||||
@ -472,16 +456,16 @@ fn test_user_db_read_implementation() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_user_db_write_implementation() {
|
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 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";
|
let user = "test";
|
||||||
|
|
||||||
assert_eq!(data.get_all_users().len(), 1);
|
assert_eq!(data.get_all_users().len(), 1);
|
||||||
assert!(data
|
assert!(data
|
||||||
.delete_user(NewUserArgs::builder().username(user).build().unwrap())
|
.delete_user(DeleteUserArgs::builder().username(user).build().unwrap())
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert!(data
|
assert!(data
|
||||||
.delete_user(NewUserArgs::builder().username(user).build().unwrap())
|
.delete_user(DeleteUserArgs::builder().username(user).build().unwrap())
|
||||||
.is_err());
|
.is_err());
|
||||||
assert_eq!(data.get_all_users().len(), 0);
|
assert_eq!(data.get_all_users().len(), 0);
|
||||||
}
|
}
|
||||||
|
42
tests/create_user_test.rs
Normal file
42
tests/create_user_test.rs
Normal 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"));
|
||||||
|
}
|
@ -24,7 +24,7 @@ fn test_delete_user_function() {
|
|||||||
let mut db = adduser::UserDBLocal::load_files(mf).unwrap();
|
let mut db = adduser::UserDBLocal::load_files(mf).unwrap();
|
||||||
|
|
||||||
let user_res: Result<adduser::User, adduser::UserLibError> = db.delete_user(
|
let user_res: Result<adduser::User, adduser::UserLibError> = db.delete_user(
|
||||||
adduser::api::NewUserArgs::builder()
|
adduser::api::DeleteUserArgs::builder()
|
||||||
.username("teste")
|
.username("teste")
|
||||||
// .delete_home(adduser::api::DeleteHome::Delete)
|
// .delete_home(adduser::api::DeleteHome::Delete)
|
||||||
.build()
|
.build()
|
||||||
|
Loading…
Reference in New Issue
Block a user