ferrox_security/
fingerprint.rs1use std::collections::hash_map::DefaultHasher;
2use std::hash::{Hash, Hasher};
3
4pub struct ClientFingerprint;
6
7impl ClientFingerprint {
8 pub fn compute_fingerprint(user_agent: &str, accept_language: &str, subnet_ip: &str) -> u64 {
10 let mut hasher = DefaultHasher::new();
11 user_agent.hash(&mut hasher);
12 accept_language.hash(&mut hasher);
13
14 let subnet = if let Some(idx) = subnet_ip.rfind('.') {
16 &subnet_ip[..idx]
17 } else {
18 subnet_ip
19 };
20 subnet.hash(&mut hasher);
21
22 hasher.finish()
23 }
24
25 pub fn verify_binding(bound_fingerprint: u64, current_user_agent: &str, current_lang: &str, current_ip: &str) -> bool {
27 let current_fp = Self::compute_fingerprint(current_user_agent, current_lang, current_ip);
28 bound_fingerprint == current_fp
29 }
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35
36 #[test]
37 fn test_client_fingerprint_binding() {
38 let fp = ClientFingerprint::compute_fingerprint("Mozilla/5.0", "it-IT", "192.168.1.50");
39 assert!(ClientFingerprint::verify_binding(fp, "Mozilla/5.0", "it-IT", "192.168.1.99")); assert!(!ClientFingerprint::verify_binding(fp, "MaliciousBot/1.0", "it-IT", "192.168.1.50"));
41 }
42}