stynx_code_auth/infrastructure/oauth/
pkce.rs1use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
2use sha2::{Digest, Sha256};
3
4pub struct PkceChallenge {
5 pub code_verifier: String,
6 pub code_challenge: String,
7}
8
9pub fn generate_pkce() -> PkceChallenge {
10 let verifier_bytes = generate_random_bytes();
11 let code_verifier = URL_SAFE_NO_PAD.encode(&verifier_bytes);
12
13 let mut hasher = Sha256::new();
14 hasher.update(code_verifier.as_bytes());
15 let hash = hasher.finalize();
16 let code_challenge = URL_SAFE_NO_PAD.encode(hash);
17
18 PkceChallenge {
19 code_verifier,
20 code_challenge,
21 }
22}
23
24fn generate_random_bytes() -> [u8; 32] {
25 use std::collections::hash_map::DefaultHasher;
26 use std::hash::{Hash, Hasher};
27 use std::time::{SystemTime, UNIX_EPOCH};
28
29 let mut bytes = [0u8; 32];
30 let now = SystemTime::now()
31 .duration_since(UNIX_EPOCH)
32 .unwrap_or_default()
33 .as_nanos();
34 let pid = std::process::id();
35
36 for (i, byte) in bytes.iter_mut().enumerate() {
37 let mut hasher = DefaultHasher::new();
38 now.hash(&mut hasher);
39 pid.hash(&mut hasher);
40 i.hash(&mut hasher);
41 (now ^ (pid as u128) ^ (i as u128)).hash(&mut hasher);
42 *byte = (hasher.finish() & 0xff) as u8;
43 }
44 bytes
45}