restructure
This commit is contained in:
parent
1ab0adbc06
commit
063fb41708
129
Cargo.lock
generated
129
Cargo.lock
generated
@ -5,7 +5,9 @@ name = "adduser"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"log",
|
||||||
"regex",
|
"regex",
|
||||||
|
"simplelog",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -17,18 +19,77 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"time",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.78"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.3.3"
|
version = "2.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.3.9"
|
version = "1.3.9"
|
||||||
@ -47,6 +108,26 @@ version = "0.6.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simplelog"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b2736f58087298a448859961d3f4a0850b832e72619d75adc69da7993c2cd3c"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"log",
|
||||||
|
"termcolor",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -55,3 +136,51 @@ checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
@ -9,3 +9,5 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1"
|
regex = "1"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
|
log = "0.4"
|
||||||
|
simplelog = "0.8"
|
||||||
|
@ -5,11 +5,19 @@ use std::fs::File;
|
|||||||
use std::io::{prelude::*, BufReader};
|
use std::io::{prelude::*, BufReader};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
simplelog::CombinedLogger::init(vec![simplelog::TermLogger::new(
|
||||||
|
simplelog::LevelFilter::Warn,
|
||||||
|
simplelog::Config::default(),
|
||||||
|
simplelog::TerminalMode::Mixed,
|
||||||
|
)])
|
||||||
|
.unwrap();
|
||||||
let file = File::open("/etc/passwd").unwrap();
|
let file = File::open("/etc/passwd").unwrap();
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
|
|
||||||
for line in reader.lines() {
|
for line in reader.lines() {
|
||||||
println!("{}", Passwd::new_from_string(&line.unwrap()).unwrap());
|
let line = line.unwrap();
|
||||||
|
println!("{}", line);
|
||||||
|
println!("{}", Passwd::new_from_string(&line).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
// let pwd = Passwd::default();
|
// let pwd = Passwd::default();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
pub mod passwd;
|
pub mod passwd;
|
||||||
pub mod userlib_error;
|
pub mod userlib_error;
|
||||||
|
322
src/passwd.rs
322
src/passwd.rs
@ -7,6 +7,7 @@
|
|||||||
)]
|
)]
|
||||||
#![allow(clippy::non_ascii_literal)]
|
#![allow(clippy::non_ascii_literal)]
|
||||||
|
|
||||||
|
use log::warn;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::userlib_error::UserLibError;
|
use crate::userlib_error::UserLibError;
|
||||||
@ -25,11 +26,50 @@ pub struct Username<'a> {
|
|||||||
username: &'a str,
|
username: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Username<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.username,)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for Username<'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 { username: source })
|
||||||
|
} else {
|
||||||
|
Err(UserLibError::Message("Invalid username".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Password<'a> {
|
pub struct Password<'a> {
|
||||||
password: &'a str,
|
password: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Password<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.password,)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for Password<'a> {
|
||||||
|
type Error = UserLibError;
|
||||||
|
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
|
||||||
|
if source == "x" {
|
||||||
|
warn!("password from shadow not loaded!")
|
||||||
|
} else {
|
||||||
|
warn!("Password field has an unexpected value")
|
||||||
|
};
|
||||||
|
Ok(Self { password: source })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Uid {
|
pub struct Uid {
|
||||||
uid: u32,
|
uid: u32,
|
||||||
@ -39,6 +79,7 @@ pub struct Uid {
|
|||||||
pub struct Gid {
|
pub struct Gid {
|
||||||
gid: u32,
|
gid: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The gecos field of a user.
|
/// The gecos field of a user.
|
||||||
///
|
///
|
||||||
/// In the `/etc/passwd` file this field is a `,` sepparated list of items.
|
/// In the `/etc/passwd` file this field is a `,` sepparated list of items.
|
||||||
@ -59,6 +100,129 @@ pub enum Gecos<'a> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, .. } => {
|
||||||
|
if full_name.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(full_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub const fn get_room(&'a self) -> Option<&'a str> {
|
||||||
|
match *self {
|
||||||
|
Gecos::Simple { .. } => None,
|
||||||
|
Gecos::Detail { room, .. } => {
|
||||||
|
if room.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(room)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub const fn get_phone_work(&'a self) -> Option<&'a str> {
|
||||||
|
match *self {
|
||||||
|
Gecos::Simple { .. } => None,
|
||||||
|
Gecos::Detail { phone_work, .. } => {
|
||||||
|
if phone_work.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
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, .. } => {
|
||||||
|
if phone_home.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(phone_home)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub const fn get_other(&'a self) -> Option<&Vec<&'a str>> {
|
||||||
|
match self {
|
||||||
|
Gecos::Simple { .. } => None,
|
||||||
|
Gecos::Detail { other, .. } => match other {
|
||||||
|
None => None,
|
||||||
|
Some(comments) => Some(comments),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Gecos<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match &self {
|
||||||
|
Gecos::Simple { comment } => write!(f, "{}", comment),
|
||||||
|
Gecos::Detail {
|
||||||
|
full_name,
|
||||||
|
room,
|
||||||
|
phone_work,
|
||||||
|
phone_home,
|
||||||
|
other,
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"{},{},{},{}{}",
|
||||||
|
full_name,
|
||||||
|
room,
|
||||||
|
phone_work,
|
||||||
|
phone_home,
|
||||||
|
match other {
|
||||||
|
None => "".to_string(),
|
||||||
|
Some(cont) => format!(",{}", cont.join(",")),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for Gecos<'a> {
|
||||||
|
type Error = UserLibError;
|
||||||
|
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
|
||||||
|
let vals: Vec<&str> = source.split(',').collect();
|
||||||
|
if vals.len() > 3 {
|
||||||
|
Ok(Gecos::Detail {
|
||||||
|
full_name: vals[0],
|
||||||
|
room: vals[1],
|
||||||
|
phone_work: vals[2],
|
||||||
|
phone_home: vals[3],
|
||||||
|
other: if vals.len() == 4 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(vals[4..].to_vec())
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else if vals.len() == 1 {
|
||||||
|
Ok(Gecos::Simple {
|
||||||
|
comment: vals.get(0).unwrap(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
panic!(format!("Could not parse this string: {}", source))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/// The home directory of a user
|
/// The home directory of a user
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct HomeDir<'a> {
|
pub struct HomeDir<'a> {
|
||||||
@ -142,78 +306,6 @@ impl<'a> Passwd<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, .. } => {
|
|
||||||
if full_name.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(full_name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[must_use]
|
|
||||||
pub const fn get_room(&'a self) -> Option<&'a str> {
|
|
||||||
match *self {
|
|
||||||
Gecos::Simple { .. } => None,
|
|
||||||
Gecos::Detail { room, .. } => {
|
|
||||||
if room.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(room)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[must_use]
|
|
||||||
pub const fn get_phone_work(&'a self) -> Option<&'a str> {
|
|
||||||
match *self {
|
|
||||||
Gecos::Simple { .. } => None,
|
|
||||||
Gecos::Detail { phone_work, .. } => {
|
|
||||||
if phone_work.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
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, .. } => {
|
|
||||||
if phone_home.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(phone_home)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[must_use]
|
|
||||||
pub const fn get_other(&'a self) -> Option<&Vec<&'a str>> {
|
|
||||||
match self {
|
|
||||||
Gecos::Simple { .. } => None,
|
|
||||||
Gecos::Detail { other, .. } => match other {
|
|
||||||
None => None,
|
|
||||||
Some(comments) => Some(comments),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Passwd<'_> {
|
impl Default for Passwd<'_> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Passwd {
|
Passwd {
|
||||||
@ -252,40 +344,6 @@ impl Display for Passwd<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Username<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.username,)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a str> for Username<'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 { username: source })
|
|
||||||
} else {
|
|
||||||
Err(UserLibError::Message("Invalid username".into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Password<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.password,)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a str> for Password<'a> {
|
|
||||||
type Error = UserLibError;
|
|
||||||
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
|
|
||||||
Ok(Self { password: source })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Uid {
|
impl Display for Uid {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.uid,)
|
write!(f, "{}", self.uid,)
|
||||||
@ -316,58 +374,6 @@ impl TryFrom<&str> for Gid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Gecos<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match &self {
|
|
||||||
Gecos::Simple { comment } => write!(f, "{}", comment),
|
|
||||||
Gecos::Detail {
|
|
||||||
full_name,
|
|
||||||
room,
|
|
||||||
phone_work,
|
|
||||||
phone_home,
|
|
||||||
other,
|
|
||||||
} => write!(
|
|
||||||
f,
|
|
||||||
"{},{},{},{}{}",
|
|
||||||
full_name,
|
|
||||||
room,
|
|
||||||
phone_work,
|
|
||||||
phone_home,
|
|
||||||
match other {
|
|
||||||
None => "".to_string(),
|
|
||||||
Some(cont) => format!(",{}", cont.join(",")),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a str> for Gecos<'a> {
|
|
||||||
type Error = UserLibError;
|
|
||||||
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
|
|
||||||
let vals: Vec<&str> = source.split(',').collect();
|
|
||||||
if vals.len() > 3 {
|
|
||||||
Ok(Gecos::Detail {
|
|
||||||
full_name: vals[0],
|
|
||||||
room: vals[1],
|
|
||||||
phone_work: vals[2],
|
|
||||||
phone_home: vals[3],
|
|
||||||
other: if vals.len() == 4 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(vals[4..].to_vec())
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else if vals.len() == 1 {
|
|
||||||
Ok(Gecos::Simple {
|
|
||||||
comment: vals.get(0).unwrap(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
panic!(format!("Could not parse this string: {}", source))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for HomeDir<'_> {
|
impl Display for HomeDir<'_> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.dir,)
|
write!(f, "{}", self.dir,)
|
||||||
|
Loading…
Reference in New Issue
Block a user