2022-10-01 08:08:51 +02:00
|
|
|
use std::fs::Metadata;
|
2021-07-08 02:09:15 +02:00
|
|
|
use std::io::ErrorKind;
|
2022-10-01 08:08:51 +02:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
use std::os::linux::fs::MetadataExt;
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
use std::os::macos::fs::MetadataExt;
|
2021-07-08 02:09:15 +02:00
|
|
|
use std::path::PathBuf;
|
2020-03-22 02:31:02 +01:00
|
|
|
use std::time::{Duration, SystemTime};
|
2021-07-08 02:09:15 +02:00
|
|
|
|
|
|
|
use filetime::FileTime;
|
2022-10-01 08:08:51 +02:00
|
|
|
use hashbrown::HashSet;
|
133 limit to human readable characters. (#174)
Implements #133, limit password generators to distict human readable characters. This removes the common confusions such as I,l, 1, 0, O, o, m,rn, etc . This in mind, they may not all have been found, but it should be easier now to improve upon.
2020-01-27 03:56:15 +01:00
|
|
|
use rand::distributions::Distribution;
|
2019-10-07 00:41:30 +02:00
|
|
|
use rand::{thread_rng, Rng};
|
2022-10-01 08:08:51 +02:00
|
|
|
use touch::file as touch_file;
|
2022-07-06 02:53:43 +02:00
|
|
|
// #[cfg(target_os = "windows")]
|
|
|
|
// use std::os::windows::fs::MetadataExt;
|
2022-12-18 04:26:20 +01:00
|
|
|
use crate::prelude::*;
|
2022-07-06 02:53:43 +02:00
|
|
|
#[cfg(target_family = "unix")]
|
2021-06-27 03:30:40 +02:00
|
|
|
use users::{get_current_gid, get_current_uid};
|
|
|
|
|
133 limit to human readable characters. (#174)
Implements #133, limit password generators to distict human readable characters. This removes the common confusions such as I,l, 1, 0, O, o, m,rn, etc . This in mind, they may not all have been found, but it should be easier now to improve upon.
2020-01-27 03:56:15 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct DistinctAlpha;
|
|
|
|
|
2021-05-21 08:35:09 +02:00
|
|
|
pub type Sid = [u8; 4];
|
2019-09-06 05:04:58 +02:00
|
|
|
|
2022-05-24 02:49:34 +02:00
|
|
|
pub fn uuid_to_gid_u32(u: Uuid) -> u32 {
|
2019-11-30 00:39:31 +01:00
|
|
|
let b_ref = u.as_bytes();
|
|
|
|
let mut x: [u8; 4] = [0; 4];
|
|
|
|
x.clone_from_slice(&b_ref[12..16]);
|
|
|
|
u32::from_be_bytes(x)
|
|
|
|
}
|
|
|
|
|
2021-05-21 08:35:09 +02:00
|
|
|
fn uuid_from_u64_u32(a: u64, b: u32, sid: Sid) -> Uuid {
|
2019-09-06 05:04:58 +02:00
|
|
|
let mut v: Vec<u8> = Vec::with_capacity(16);
|
|
|
|
v.extend_from_slice(&a.to_be_bytes());
|
|
|
|
v.extend_from_slice(&b.to_be_bytes());
|
2020-01-09 11:07:14 +01:00
|
|
|
v.extend_from_slice(&sid);
|
2019-09-06 05:04:58 +02:00
|
|
|
|
2020-08-04 04:58:11 +02:00
|
|
|
#[allow(clippy::expect_used)]
|
2022-12-18 04:26:20 +01:00
|
|
|
uuid::Builder::from_slice(v.as_slice())
|
2020-08-04 04:58:11 +02:00
|
|
|
.expect("invalid slice for uuid builder")
|
2022-04-27 05:35:26 +02:00
|
|
|
.into_uuid()
|
2019-09-06 05:04:58 +02:00
|
|
|
}
|
|
|
|
|
2021-05-21 08:35:09 +02:00
|
|
|
pub fn uuid_from_duration(d: Duration, sid: Sid) -> Uuid {
|
2019-09-06 05:04:58 +02:00
|
|
|
uuid_from_u64_u32(d.as_secs(), d.subsec_nanos(), sid)
|
|
|
|
}
|
|
|
|
|
2019-10-07 00:41:30 +02:00
|
|
|
pub fn password_from_random() -> String {
|
133 limit to human readable characters. (#174)
Implements #133, limit password generators to distict human readable characters. This removes the common confusions such as I,l, 1, 0, O, o, m,rn, etc . This in mind, they may not all have been found, but it should be easier now to improve upon.
2020-01-27 03:56:15 +01:00
|
|
|
let rand_string: String = thread_rng().sample_iter(&DistinctAlpha).take(48).collect();
|
2019-10-07 00:41:30 +02:00
|
|
|
rand_string
|
|
|
|
}
|
|
|
|
|
2021-06-25 04:39:05 +02:00
|
|
|
pub fn backup_code_from_random() -> HashSet<String> {
|
2023-04-26 13:55:42 +02:00
|
|
|
(0..8).map(|_| readable_password_from_random()).collect()
|
2021-06-25 04:39:05 +02:00
|
|
|
}
|
|
|
|
|
2019-10-31 01:48:15 +01:00
|
|
|
pub fn readable_password_from_random() -> String {
|
2022-05-24 02:49:34 +02:00
|
|
|
// 2^112 bits, means we need at least 55^20 to have as many bits of entropy.
|
|
|
|
// this leads us to 4 groups of 5 to create 55^20
|
2021-01-10 04:41:56 +01:00
|
|
|
let mut trng = thread_rng();
|
2019-10-31 01:48:15 +01:00
|
|
|
format!(
|
|
|
|
"{}-{}-{}-{}",
|
2021-01-10 04:41:56 +01:00
|
|
|
(&mut trng)
|
|
|
|
.sample_iter(&DistinctAlpha)
|
2022-05-24 02:49:34 +02:00
|
|
|
.take(5)
|
2021-01-10 04:41:56 +01:00
|
|
|
.collect::<String>(),
|
|
|
|
(&mut trng)
|
|
|
|
.sample_iter(&DistinctAlpha)
|
2022-05-24 02:49:34 +02:00
|
|
|
.take(5)
|
2021-01-10 04:41:56 +01:00
|
|
|
.collect::<String>(),
|
|
|
|
(&mut trng)
|
|
|
|
.sample_iter(&DistinctAlpha)
|
2022-05-24 02:49:34 +02:00
|
|
|
.take(5)
|
2021-01-10 04:41:56 +01:00
|
|
|
.collect::<String>(),
|
|
|
|
(&mut trng)
|
|
|
|
.sample_iter(&DistinctAlpha)
|
2022-05-24 02:49:34 +02:00
|
|
|
.take(5)
|
2021-01-10 04:41:56 +01:00
|
|
|
.collect::<String>(),
|
2019-10-31 01:48:15 +01:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-03-22 02:31:02 +01:00
|
|
|
pub fn duration_from_epoch_now() -> Duration {
|
2020-08-04 04:58:11 +02:00
|
|
|
#[allow(clippy::expect_used)]
|
2020-03-22 02:31:02 +01:00
|
|
|
SystemTime::now()
|
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)
|
2020-08-04 04:58:11 +02:00
|
|
|
.expect("invalid duration from epoch now")
|
2020-03-22 02:31:02 +01:00
|
|
|
}
|
|
|
|
|
2021-07-08 02:09:15 +02:00
|
|
|
pub fn touch_file_or_quit(file_path: &str) {
|
|
|
|
/*
|
|
|
|
Attempt to touch the file file_path, will quit the application if it fails for any reason.
|
|
|
|
|
|
|
|
Will also create a new file if it doesn't already exist.
|
|
|
|
*/
|
|
|
|
if PathBuf::from(file_path).exists() {
|
|
|
|
let t = FileTime::from_system_time(SystemTime::now());
|
|
|
|
match filetime::set_file_times(file_path, t, t) {
|
|
|
|
Ok(_) => debug!(
|
|
|
|
"Successfully touched existing file {}, can continue",
|
|
|
|
file_path
|
|
|
|
),
|
|
|
|
Err(e) => {
|
|
|
|
match e.kind() {
|
|
|
|
ErrorKind::PermissionDenied => {
|
|
|
|
// we bail here because you won't be able to write them back...
|
|
|
|
error!("Permission denied writing to {}, quitting.", file_path)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
error!(
|
|
|
|
"Failed to write to {} due to error: {:?} ... quitting.",
|
|
|
|
file_path, e
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::process::exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
match touch_file::write(file_path, "", false) {
|
|
|
|
Ok(_) => debug!("Successfully touched new file {}", file_path),
|
|
|
|
Err(e) => {
|
|
|
|
error!(
|
|
|
|
"Failed to write to {} due to error: {:?} ... quitting.",
|
|
|
|
file_path, e
|
|
|
|
);
|
|
|
|
std::process::exit(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-22 02:31:02 +01:00
|
|
|
/*
|
2019-10-10 11:42:33 +02:00
|
|
|
#[allow(dead_code)]
|
2021-05-21 08:35:09 +02:00
|
|
|
pub fn uuid_from_now(sid: Sid) -> Uuid {
|
2019-10-15 04:34:07 +02:00
|
|
|
let d = SystemTime::now()
|
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)
|
|
|
|
.unwrap();
|
2019-10-10 11:42:33 +02:00
|
|
|
uuid_from_duration(d, sid)
|
|
|
|
}
|
2020-03-22 02:31:02 +01:00
|
|
|
*/
|
2019-10-10 11:42:33 +02:00
|
|
|
|
133 limit to human readable characters. (#174)
Implements #133, limit password generators to distict human readable characters. This removes the common confusions such as I,l, 1, 0, O, o, m,rn, etc . This in mind, they may not all have been found, but it should be easier now to improve upon.
2020-01-27 03:56:15 +01:00
|
|
|
impl Distribution<char> for DistinctAlpha {
|
|
|
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
|
|
|
|
const RANGE: u32 = 55;
|
|
|
|
const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHJKLMNPQRSTUVWXYZ\
|
|
|
|
abcdefghjkpqrstuvwxyz\
|
|
|
|
0123456789";
|
|
|
|
// This probably needs to be checked for entropy/quality
|
|
|
|
loop {
|
|
|
|
let var = rng.next_u32() >> (32 - 6);
|
|
|
|
if var < RANGE {
|
|
|
|
return GEN_ASCII_STR_CHARSET[var as usize] as char;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-27 03:30:40 +02:00
|
|
|
#[cfg(target_family = "unix")]
|
2023-02-28 02:39:39 +01:00
|
|
|
/// Check a given file's metadata is read-only for the current user (true = read-only)
|
2021-06-27 03:30:40 +02:00
|
|
|
pub fn file_permissions_readonly(meta: &Metadata) -> bool {
|
|
|
|
// Who are we running as?
|
|
|
|
let cuid = get_current_uid();
|
|
|
|
let cgid = get_current_gid();
|
|
|
|
|
|
|
|
// Who owns the file?
|
|
|
|
// Who is the group owner of the file?
|
|
|
|
let f_gid = meta.st_gid();
|
|
|
|
let f_uid = meta.st_uid();
|
|
|
|
|
|
|
|
let f_mode = meta.st_mode();
|
|
|
|
|
|
|
|
!(
|
|
|
|
// If we are the owner, we have write perms as we can alter the DAC rights
|
|
|
|
cuid == f_uid ||
|
|
|
|
// If we are the group owner, check the mode bits do not have write.
|
|
|
|
(cgid == f_gid && (f_mode & 0o0020) != 0) ||
|
|
|
|
// Finally, check that everyone bits don't have write.
|
|
|
|
((f_mode & 0o0002) != 0)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-02-28 02:39:39 +01:00
|
|
|
#[cfg(not(target_family = "unix"))]
|
|
|
|
/// Check a given file's metadata is read-only for the current user (true = read-only) Stub function if you're building for windows!
|
|
|
|
pub fn file_permissions_readonly(meta: &Metadata) -> bool {
|
|
|
|
debug!(
|
|
|
|
"Windows target asked to check metadata on {:?} returning false",
|
|
|
|
meta
|
|
|
|
);
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2019-09-06 05:04:58 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-12-18 04:26:20 +01:00
|
|
|
use crate::prelude::*;
|
2019-09-06 05:04:58 +02:00
|
|
|
use std::time::Duration;
|
2022-10-01 08:08:51 +02:00
|
|
|
|
|
|
|
use crate::utils::{uuid_from_duration, uuid_to_gid_u32};
|
|
|
|
|
2019-09-06 05:04:58 +02:00
|
|
|
#[test]
|
|
|
|
fn test_utils_uuid_from_duration() {
|
2020-01-09 11:07:14 +01:00
|
|
|
let u1 = uuid_from_duration(Duration::from_secs(1), [0xff; 4]);
|
2019-09-06 05:04:58 +02:00
|
|
|
assert_eq!(
|
|
|
|
"00000000-0000-0001-0000-0000ffffffff",
|
2022-04-27 05:35:26 +02:00
|
|
|
u1.as_hyphenated().to_string()
|
2019-09-06 05:04:58 +02:00
|
|
|
);
|
|
|
|
|
2020-01-09 11:07:14 +01:00
|
|
|
let u2 = uuid_from_duration(Duration::from_secs(1000), [0xff; 4]);
|
2019-09-06 05:04:58 +02:00
|
|
|
assert_eq!(
|
|
|
|
"00000000-0000-03e8-0000-0000ffffffff",
|
2022-04-27 05:35:26 +02:00
|
|
|
u2.as_hyphenated().to_string()
|
2019-09-06 05:04:58 +02:00
|
|
|
);
|
|
|
|
}
|
2019-11-30 00:39:31 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_utils_uuid_to_gid_u32() {
|
2022-12-18 04:26:20 +01:00
|
|
|
let u1 = uuid!("00000000-0000-0001-0000-000000000000");
|
2022-05-24 02:49:34 +02:00
|
|
|
let r1 = uuid_to_gid_u32(u1);
|
2019-11-30 00:39:31 +01:00
|
|
|
assert!(r1 == 0);
|
|
|
|
|
2022-12-18 04:26:20 +01:00
|
|
|
let u2 = uuid!("00000000-0000-0001-0000-0000ffffffff");
|
2022-05-24 02:49:34 +02:00
|
|
|
let r2 = uuid_to_gid_u32(u2);
|
2019-11-30 00:39:31 +01:00
|
|
|
assert!(r2 == 0xffffffff);
|
|
|
|
|
2022-12-18 04:26:20 +01:00
|
|
|
let u3 = uuid!("00000000-0000-0001-0000-ffff12345678");
|
2022-05-24 02:49:34 +02:00
|
|
|
let r3 = uuid_to_gid_u32(u3);
|
2019-11-30 00:39:31 +01:00
|
|
|
assert!(r3 == 0x12345678);
|
|
|
|
}
|
2019-09-06 05:04:58 +02:00
|
|
|
}
|