Compare commits
	
		
			No commits in common. "a25092c7a015e984e9a458b6cf6ad29436c3866e" and "3232f2b1dad3983729c670ccbbcf82fd3b74babf" have entirely different histories.
		
	
	
		
			a25092c7a0
			...
			3232f2b1da
		
	
		
@ -1,3 +1,3 @@
 | 
				
			|||||||
pub mod passwd;
 | 
					pub mod passwd;
 | 
				
			||||||
pub mod userlib_error;
 | 
					
 | 
				
			||||||
pub use passwd::{Password, Username};
 | 
					pub use passwd::{Password, Username};
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										151
									
								
								src/passwd.rs
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								src/passwd.rs
									
									
									
									
									
								
							@ -1,11 +1,10 @@
 | 
				
			|||||||
#![warn(
 | 
					/*#![warn(
 | 
				
			||||||
    clippy::all,
 | 
					    clippy::all,
 | 
				
			||||||
/*    clippy::restriction,*/
 | 
					    clippy::restriction,
 | 
				
			||||||
    clippy::pedantic,
 | 
					    clippy::pedantic,
 | 
				
			||||||
    clippy::nursery,
 | 
					    clippy::nursery,
 | 
				
			||||||
    clippy::cargo
 | 
					    clippy::cargo
 | 
				
			||||||
)]
 | 
					)]*/
 | 
				
			||||||
use crate::userlib_error::UserLibError;
 | 
					 | 
				
			||||||
use std::cmp::Eq;
 | 
					use std::cmp::Eq;
 | 
				
			||||||
use std::convert::TryFrom;
 | 
					use std::convert::TryFrom;
 | 
				
			||||||
use std::fmt::{self, Display};
 | 
					use std::fmt::{self, Display};
 | 
				
			||||||
@ -73,105 +72,25 @@ pub struct Passwd<'a> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Passwd<'a> {
 | 
					impl<'a> Passwd<'a> {
 | 
				
			||||||
    /// Parse a line formatted like one in `/etc/passwd` and construct a matching `Passwd` instance
 | 
					    pub fn new_from_string(line: &'a str) -> Result<Self, &str> {
 | 
				
			||||||
    ///
 | 
					        let elements: Vec<&str> = line.split(":").collect();
 | 
				
			||||||
    /// # Example
 | 
					 | 
				
			||||||
    /// ```
 | 
					 | 
				
			||||||
    /// let pwd = adduser::passwd::Passwd::new_from_string(
 | 
					 | 
				
			||||||
    ///     "testuser:testpassword:1001:1001:full Name,,,,:/home/test:/bin/test"
 | 
					 | 
				
			||||||
    /// ).unwrap();
 | 
					 | 
				
			||||||
    /// assert_eq!(pwd.get_username(), "testuser");
 | 
					 | 
				
			||||||
    /// ```
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// # 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> {
 | 
					 | 
				
			||||||
        let elements: Vec<&str> = line.split(':').collect();
 | 
					 | 
				
			||||||
        if elements.len() == 7 {
 | 
					        if elements.len() == 7 {
 | 
				
			||||||
            Ok(Passwd {
 | 
					            Ok(Passwd {
 | 
				
			||||||
                username: Username::try_from(*elements.get(0).unwrap())?,
 | 
					                username: Username::try_from(*elements.get(0).unwrap())
 | 
				
			||||||
                password: Password::try_from(*elements.get(1).unwrap())?,
 | 
					                    .expect("failed to parse username."),
 | 
				
			||||||
                uid: Uid::try_from(*elements.get(2).unwrap())?,
 | 
					                password: Password::try_from(*elements.get(1).unwrap())
 | 
				
			||||||
                gid: Gid::try_from(*elements.get(3).unwrap())?,
 | 
					                    .expect("Failed to parse Password"),
 | 
				
			||||||
                gecos: Gecos::try_from(*elements.get(4).unwrap())?,
 | 
					                uid: Uid::try_from(*elements.get(2).unwrap()).expect("Failed to parse uid"),
 | 
				
			||||||
                home_dir: HomeDir::try_from(*elements.get(5).unwrap())?,
 | 
					                gid: Gid::try_from(*elements.get(3).unwrap()).expect("Failed to parse gid"),
 | 
				
			||||||
                shell_dir: ShellDir::try_from(*elements.get(6).unwrap())?,
 | 
					                gecos: Gecos::try_from(*elements.get(4).unwrap())
 | 
				
			||||||
 | 
					                    .expect("Failed to parse Gecos field"),
 | 
				
			||||||
 | 
					                home_dir: HomeDir::try_from(*elements.get(5).unwrap())
 | 
				
			||||||
 | 
					                    .expect("Failed to parse home directory"),
 | 
				
			||||||
 | 
					                shell_dir: ShellDir::try_from(*elements.get(6).unwrap())
 | 
				
			||||||
 | 
					                    .expect("Failed to parse shell directory"),
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            Err("Failed to parse: not enough elements".into())
 | 
					            Err("Failed to parse: not enough elements")
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_username(&self) -> &'a str {
 | 
					 | 
				
			||||||
        self.username.username
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_password(&self) -> &'a str {
 | 
					 | 
				
			||||||
        self.password.password
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_uid(&self) -> u32 {
 | 
					 | 
				
			||||||
        self.uid.uid
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_gid(&self) -> u32 {
 | 
					 | 
				
			||||||
        self.gid.gid
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_comment(&self) -> &Gecos {
 | 
					 | 
				
			||||||
        &self.gecos
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_home_dir(&self) -> &'a str {
 | 
					 | 
				
			||||||
        self.home_dir.dir
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_shell_dir(&self) -> &'a str {
 | 
					 | 
				
			||||||
        self.shell_dir.shell
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a> Gecos<'a> {
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_comment(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { comment, .. } => Some(comment),
 | 
					 | 
				
			||||||
            Gecos::Detail { .. } => None,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_full_name(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { full_name, .. } => Some(full_name),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_room(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { room, .. } => Some(room),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_phone_work(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { phone_work, .. } => Some(phone_work),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_phone_home(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { phone_home, .. } => Some(phone_home),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_other(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { other, .. } => Some(other),
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -221,7 +140,7 @@ impl Display for Username<'_> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> TryFrom<&'a str> for Username<'a> {
 | 
					impl<'a> TryFrom<&'a str> for Username<'a> {
 | 
				
			||||||
    type Error = UserLibError;
 | 
					    type Error = &'static str;
 | 
				
			||||||
    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
					    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
        Ok(Self { username: source })
 | 
					        Ok(Self { username: source })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -234,7 +153,7 @@ impl Display for Password<'_> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> TryFrom<&'a str> for Password<'a> {
 | 
					impl<'a> TryFrom<&'a str> for Password<'a> {
 | 
				
			||||||
    type Error = UserLibError;
 | 
					    type Error = &'static str;
 | 
				
			||||||
    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
					    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
        Ok(Self { password: source })
 | 
					        Ok(Self { password: source })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -247,7 +166,7 @@ impl Display for Uid {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl TryFrom<&str> for Uid {
 | 
					impl TryFrom<&str> for Uid {
 | 
				
			||||||
    type Error = UserLibError;
 | 
					    type Error = &'static str;
 | 
				
			||||||
    fn try_from(source: &str) -> std::result::Result<Self, Self::Error> {
 | 
					    fn try_from(source: &str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
        Ok(Self {
 | 
					        Ok(Self {
 | 
				
			||||||
            uid: source.parse::<u32>().unwrap(),
 | 
					            uid: source.parse::<u32>().unwrap(),
 | 
				
			||||||
@ -262,7 +181,7 @@ impl Display for Gid {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl TryFrom<&str> for Gid {
 | 
					impl TryFrom<&str> for Gid {
 | 
				
			||||||
    type Error = UserLibError;
 | 
					    type Error = &'static str;
 | 
				
			||||||
    fn try_from(source: &str) -> std::result::Result<Self, Self::Error> {
 | 
					    fn try_from(source: &str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
        Ok(Self {
 | 
					        Ok(Self {
 | 
				
			||||||
            gid: source.parse::<u32>().unwrap(),
 | 
					            gid: source.parse::<u32>().unwrap(),
 | 
				
			||||||
@ -290,7 +209,7 @@ impl Display for Gecos<'_> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> TryFrom<&'a str> for Gecos<'a> {
 | 
					impl<'a> TryFrom<&'a str> for Gecos<'a> {
 | 
				
			||||||
    type Error = UserLibError;
 | 
					    type Error = &'static str;
 | 
				
			||||||
    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
					    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
        let vals: Vec<&str> = source.split(',').collect();
 | 
					        let vals: Vec<&str> = source.split(',').collect();
 | 
				
			||||||
        if vals.len() == 5 {
 | 
					        if vals.len() == 5 {
 | 
				
			||||||
@ -309,7 +228,8 @@ impl<'a> TryFrom<&'a str> for Gecos<'a> {
 | 
				
			|||||||
                phone_home: vals.get(3).unwrap(),
 | 
					                phone_home: vals.get(3).unwrap(),
 | 
				
			||||||
                other: "",
 | 
					                other: "",
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        } else if vals.len() == 1 {
 | 
					        }
 | 
				
			||||||
 | 
					        else if vals.len() == 1 {
 | 
				
			||||||
            Ok(Gecos::Simple {
 | 
					            Ok(Gecos::Simple {
 | 
				
			||||||
                comment: vals.get(0).unwrap(),
 | 
					                comment: vals.get(0).unwrap(),
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
@ -326,7 +246,7 @@ impl Display for HomeDir<'_> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> TryFrom<&'a str> for HomeDir<'a> {
 | 
					impl<'a> TryFrom<&'a str> for HomeDir<'a> {
 | 
				
			||||||
    type Error = UserLibError;
 | 
					    type Error = &'static str;
 | 
				
			||||||
    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
					    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
        Ok(Self { dir: source })
 | 
					        Ok(Self { dir: source })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -339,7 +259,7 @@ impl Display for ShellDir<'_> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> TryFrom<&'a str> for ShellDir<'a> {
 | 
					impl<'a> TryFrom<&'a str> for ShellDir<'a> {
 | 
				
			||||||
    type Error = UserLibError;
 | 
					    type Error = &'static str;
 | 
				
			||||||
    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
					    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
        Ok(Self { shell: source })
 | 
					        Ok(Self { shell: source })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -359,11 +279,11 @@ fn test_default_user() {
 | 
				
			|||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn test_parse_gecos() {
 | 
					fn test_parse_gecos() {
 | 
				
			||||||
    // test if the Gecos field can be parsed and the resulting struct is populated correctly.
 | 
					    // test if the Gecos field can be parsed and the resulting struct is populated correctly.
 | 
				
			||||||
    let gcdetail = "Full Name,504,11345342,ä1-2312,myemail@test.com";
 | 
					    let gcd = "Full Name,504,11345342,ä1-2312,myemail@test.com";
 | 
				
			||||||
    let gcsimple = "A böring comment →";
 | 
					    let gcs = "A böring comment →";
 | 
				
			||||||
    let gc_no_other: &str = "systemd Network Management,,,";
 | 
					    let gc_no_other: &str = "systemd Network Management,,,";
 | 
				
			||||||
    let res_detail = Gecos::try_from(gcdetail).unwrap();
 | 
					    let res_detail = Gecos::try_from(gcd).unwrap();
 | 
				
			||||||
    let res_simple = Gecos::try_from(gcsimple).unwrap();
 | 
					    let res_simple = Gecos::try_from(gcs).unwrap();
 | 
				
			||||||
    let res_no_other = Gecos::try_from(gc_no_other).unwrap();
 | 
					    let res_no_other = Gecos::try_from(gc_no_other).unwrap();
 | 
				
			||||||
    match res_simple {
 | 
					    match res_simple {
 | 
				
			||||||
        Gecos::Simple { comment } => assert_eq!(comment, "A böring comment →"),
 | 
					        Gecos::Simple { comment } => assert_eq!(comment, "A böring comment →"),
 | 
				
			||||||
@ -406,11 +326,6 @@ fn test_parse_gecos() {
 | 
				
			|||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn test_new_from_string() {
 | 
					fn test_new_from_string() {
 | 
				
			||||||
    // Test if a single line can be parsed and if the resulting struct is populated correctly.
 | 
					    // Test if a single line can be parsed and if the resulting struct is populated correctly.
 | 
				
			||||||
    let fail = Passwd::new_from_string("").err().unwrap();
 | 
					 | 
				
			||||||
    assert_eq!(
 | 
					 | 
				
			||||||
        fail,
 | 
					 | 
				
			||||||
        UserLibError::Message("Failed to parse: not enough elements".into())
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    let pwd =
 | 
					    let pwd =
 | 
				
			||||||
        Passwd::new_from_string("testuser:testpassword:1001:1001:testcomment:/home/test:/bin/test")
 | 
					        Passwd::new_from_string("testuser:testpassword:1001:1001:testcomment:/home/test:/bin/test")
 | 
				
			||||||
            .unwrap();
 | 
					            .unwrap();
 | 
				
			||||||
@ -454,8 +369,8 @@ fn test_parse_passwd() {
 | 
				
			|||||||
        let lineorig: String = line.unwrap();
 | 
					        let lineorig: String = line.unwrap();
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            // ignoring the numbers of `,` since the implementation does not (yet) reproduce a missing comment field.
 | 
					            // ignoring the numbers of `,` since the implementation does not (yet) reproduce a missing comment field.
 | 
				
			||||||
            format!("{}", Passwd::new_from_string(&lineorig.clone()).unwrap()).replace(",", ""),
 | 
					            format!("{}", Passwd::new_from_string(&lineorig.clone()).unwrap()).replace(",",""),
 | 
				
			||||||
            lineorig.replace(",", "")
 | 
					            lineorig.replace(",","")
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,46 +0,0 @@
 | 
				
			|||||||
use std::error::Error;
 | 
					 | 
				
			||||||
use std::fmt::{self, Display};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					 | 
				
			||||||
pub enum ParseError {
 | 
					 | 
				
			||||||
    Username,
 | 
					 | 
				
			||||||
    Password,
 | 
					 | 
				
			||||||
    Uid,
 | 
					 | 
				
			||||||
    Gid,
 | 
					 | 
				
			||||||
    Gecos,
 | 
					 | 
				
			||||||
    HomeDir,
 | 
					 | 
				
			||||||
    ShellDir,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					 | 
				
			||||||
pub enum UserLibError {
 | 
					 | 
				
			||||||
    NotFound,
 | 
					 | 
				
			||||||
    ParseError,
 | 
					 | 
				
			||||||
    Message(String),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Display for UserLibError {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            Self::NotFound => write!(f, ""),
 | 
					 | 
				
			||||||
            Self::ParseError => write!(f, "Failed to parse"), // TODO details
 | 
					 | 
				
			||||||
            Self::Message(message) => write!(f, "{}", message),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Error for UserLibError {
 | 
					 | 
				
			||||||
    fn description(&self) -> &str {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            Self::NotFound => "not found",
 | 
					 | 
				
			||||||
            Self::ParseError => "failed to parse",
 | 
					 | 
				
			||||||
            Self::Message(message) => message,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl From<&str> for UserLibError {
 | 
					 | 
				
			||||||
    fn from(err: &str) -> Self {
 | 
					 | 
				
			||||||
        Self::Message(err.to_owned())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user