kanidm/server/lib/src/utils.rs

127 lines
3.5 KiB
Rust
Raw Normal View History

use crate::prelude::*;
2022-10-01 08:08:51 +02:00
use hashbrown::HashSet;
use rand::distributions::Distribution;
use rand::{thread_rng, Rng};
2021-06-27 03:30:40 +02:00
#[derive(Debug)]
pub struct DistinctAlpha;
pub type Sid = [u8; 4];
pub fn uuid_to_gid_u32(u: Uuid) -> u32 {
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)
}
fn uuid_from_u64_u32(a: u64, b: u32, sid: Sid) -> Uuid {
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());
v.extend_from_slice(&sid);
2020-08-04 04:58:11 +02:00
#[allow(clippy::expect_used)]
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()
}
pub fn uuid_from_duration(d: Duration, sid: Sid) -> Uuid {
uuid_from_u64_u32(d.as_secs(), d.subsec_nanos(), sid)
}
2023-11-19 12:56:19 +01:00
pub(crate) fn password_from_random_len(len: u32) -> String {
thread_rng()
.sample_iter(&DistinctAlpha)
.take(len as usize)
.collect::<String>()
}
pub fn password_from_random() -> String {
2023-11-19 12:56:19 +01:00
password_from_random_len(48)
}
2021-06-25 04:39:05 +02:00
pub fn backup_code_from_random() -> HashSet<String> {
(0..8).map(|_| readable_password_from_random()).collect()
2021-06-25 04:39:05 +02:00
}
pub fn readable_password_from_random() -> String {
// 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
let mut trng = thread_rng();
format!(
"{}-{}-{}-{}",
(&mut trng)
.sample_iter(&DistinctAlpha)
.take(5)
.collect::<String>(),
(&mut trng)
.sample_iter(&DistinctAlpha)
.take(5)
.collect::<String>(),
(&mut trng)
.sample_iter(&DistinctAlpha)
.take(5)
.collect::<String>(),
(&mut trng)
.sample_iter(&DistinctAlpha)
.take(5)
.collect::<String>(),
)
}
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;
}
}
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use std::time::Duration;
2022-10-01 08:08:51 +02:00
use crate::utils::{uuid_from_duration, uuid_to_gid_u32};
#[test]
fn test_utils_uuid_from_duration() {
let u1 = uuid_from_duration(Duration::from_secs(1), [0xff; 4]);
assert_eq!(
"00000000-0000-0001-0000-0000ffffffff",
2022-04-27 05:35:26 +02:00
u1.as_hyphenated().to_string()
);
let u2 = uuid_from_duration(Duration::from_secs(1000), [0xff; 4]);
assert_eq!(
"00000000-0000-03e8-0000-0000ffffffff",
2022-04-27 05:35:26 +02:00
u2.as_hyphenated().to_string()
);
}
#[test]
fn test_utils_uuid_to_gid_u32() {
let u1 = uuid!("00000000-0000-0001-0000-000000000000");
let r1 = uuid_to_gid_u32(u1);
assert!(r1 == 0);
let u2 = uuid!("00000000-0000-0001-0000-0000ffffffff");
let r2 = uuid_to_gid_u32(u2);
assert!(r2 == 0xffffffff);
let u3 = uuid!("00000000-0000-0001-0000-ffff12345678");
let r3 = uuid_to_gid_u32(u3);
assert!(r3 == 0x12345678);
}
}