Compare commits

..

2 Commits

Author SHA1 Message Date
1ab0adbc06 user validation and tests 2020-09-30 20:58:24 +02:00
5000fba6e7 doc update for enum Gecos 2020-09-30 18:23:44 +02:00
4 changed files with 105 additions and 2 deletions

52
Cargo.lock generated
View File

@ -3,3 +3,55 @@
[[package]]
name = "adduser"
version = "0.1.0"
dependencies = [
"lazy_static",
"regex",
]
[[package]]
name = "aho-corasick"
version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
dependencies = [
"memchr",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
[[package]]
name = "regex"
version = "1.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"lazy_static",
]

View File

@ -7,3 +7,5 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
regex = "1"
lazy_static = "1.4"

View File

@ -1,3 +1,6 @@
#[macro_use]
extern crate lazy_static;
pub mod passwd;
pub mod userlib_error;
pub use passwd::{Password, Username};

View File

@ -7,6 +7,8 @@
)]
#![allow(clippy::non_ascii_literal)]
use regex::Regex;
use crate::userlib_error::UserLibError;
use std::cmp::Eq;
use std::convert::TryFrom;
@ -37,7 +39,12 @@ pub struct Uid {
pub struct Gid {
gid: u32,
}
/// The gecos field of a user.
///
/// In the `/etc/passwd` file this field is a `,` sepparated list of items.
/// The first 4 values are more or less standardised to be full name, room, phone at work and phone at home. After that there can be some extra fields often containing the emailadress and even additional information.
///
/// This enum represents the first 4 values by name and adds the other values to a list of strings [`Gecos::Detail`]. If only one field is found and no `,` at all this value is used as a human readable comment [`Gecos::Simple`].
#[derive(Debug, PartialEq, Eq)]
pub enum Gecos<'a> {
Detail {
@ -254,7 +261,15 @@ impl Display for 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()))
}
}
}
@ -381,6 +396,37 @@ impl<'a> TryFrom<&'a str> for ShellPath<'a> {
// Tests ----------------------------------------------------------------------
#[test]
fn test_username_validation() {
// Failing tests
let umlauts = Username::try_from("täst"); // umlauts
assert_eq!(
Err(UserLibError::Message("Invalid username".into())),
umlauts
);
let number_first = Username::try_from("11elf"); // numbers first
assert_eq!(
Err(UserLibError::Message("Invalid username".into())),
number_first
);
let slashes = Username::try_from("test/name"); // slashes in the name
assert_eq!(
Err(UserLibError::Message("Invalid username".into())),
slashes
);
let long = Username::try_from("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // maximum size 32 letters
assert_eq!(Err(UserLibError::Message("Invalid username".into())), long);
// Working tests
let single = Username::try_from("t"); // single characters are ok
assert_eq!(single.unwrap().username, "t");
let normal = Username::try_from("superman"); // regular username
assert_eq!(normal.unwrap().username, "superman");
let normal = Username::try_from("anna3pete"); // regular username containing a number
assert_eq!(normal.unwrap().username, "anna3pete");
let normal = Username::try_from("enya$"); // regular username ending in a $
assert_eq!(normal.unwrap().username, "enya$");
}
#[test]
fn test_default_user() {
// Check if a user can be created.