From 5ede65f454b08303f588754a208dca0c37d3ce34 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Thu, 16 Jul 2026 15:49:49 +0700 Subject: [PATCH] feat(iam): tambahkan CSPRNG (OsRng) untuk token state/PKCE --- Cargo.lock | 2 ++ crates/zesdex-iam/Cargo.toml | 2 ++ crates/zesdex-iam/src/infrastructure/mod.rs | 1 + crates/zesdex-iam/src/infrastructure/rng.rs | 38 +++++++++++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 crates/zesdex-iam/src/infrastructure/rng.rs diff --git a/Cargo.lock b/Cargo.lock index 3cd27ef..b8758d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4772,7 +4772,9 @@ dependencies = [ "anyhow", "base64", "chrono", + "hex", "libc", + "rand_core 0.6.4", "reqwest", "serde", "serde_json", diff --git a/crates/zesdex-iam/Cargo.toml b/crates/zesdex-iam/Cargo.toml index eceb749..1c24e77 100644 --- a/crates/zesdex-iam/Cargo.toml +++ b/crates/zesdex-iam/Cargo.toml @@ -18,3 +18,5 @@ tracing.workspace = true url.workspace = true base64.workspace = true sha2.workspace = true +hex.workspace = true +rand_core = { version = "0.6", features = ["getrandom"] } diff --git a/crates/zesdex-iam/src/infrastructure/mod.rs b/crates/zesdex-iam/src/infrastructure/mod.rs index 4c61c09..236a93f 100644 --- a/crates/zesdex-iam/src/infrastructure/mod.rs +++ b/crates/zesdex-iam/src/infrastructure/mod.rs @@ -1,2 +1,3 @@ pub mod http; pub mod persistence; +pub mod rng; diff --git a/crates/zesdex-iam/src/infrastructure/rng.rs b/crates/zesdex-iam/src/infrastructure/rng.rs new file mode 100644 index 0000000..a0559cf --- /dev/null +++ b/crates/zesdex-iam/src/infrastructure/rng.rs @@ -0,0 +1,38 @@ +//! Cryptographically secure random-token generation for OAuth CSRF state +//! tokens and PKCE verifiers. +use rand_core::{OsRng, RngCore}; + +/// Generate `n_bytes` of CSPRNG output, hex-encoded. +/// +/// Why: the previous implementation derived "randomness" from +/// `SystemTime::now()` XORed with a monotonic counter — predictable given +/// a bounded guess at request time, which undermines both CSRF `state` +/// and PKCE verifier unpredictability. `OsRng` draws from the OS entropy +/// source (`getrandom`/`/dev/urandom` equivalent) and is the same +/// primitive already used correctly for password-salt generation in +/// `zesdex-libs::password::hash_password`. +/// +/// Return: a lowercase hex string of length `2 * n_bytes`. +pub fn secure_token_hex(n_bytes: usize) -> String { + let mut buf = vec![0u8; n_bytes]; + OsRng.fill_bytes(&mut buf); + hex::encode(buf) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn secure_token_hex_produces_correct_length() { + assert_eq!(secure_token_hex(16).len(), 32); + assert_eq!(secure_token_hex(32).len(), 64); + } + + #[test] + fn secure_token_hex_is_not_constant() { + let a = secure_token_hex(16); + let b = secure_token_hex(16); + assert_ne!(a, b, "two consecutive calls must not produce the same token"); + } +}