MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / verify_token

Function verify_token

nodedb-cluster/src/auth/join_token.rs:100–125  ·  view source on GitHub ↗

Verify a hex-encoded token against `secret`. Returns the bound `(for_node, expiry_unix_secs)` on success. The HMAC comparison is constant-time (via `hmac::Mac::verify_slice` which uses the `subtle` crate internally).

(token_hex: &str, secret: &[u8; 32])

Source from the content-addressed store, hash-verified

98/// The HMAC comparison is constant-time (via `hmac::Mac::verify_slice`
99/// which uses the `subtle` crate internally).
100pub fn verify_token(token_hex: &str, secret: &[u8; 32]) -> Result<(u64, u64), TokenError> {
101 if token_hex.len() != TOKEN_HEX_LEN {
102 return Err(TokenError::WrongLength);
103 }
104 let bytes = hex_decode(token_hex)?;
105 let (body, tag) = bytes.split_at(TOKEN_HEADER_LEN);
106 let mut mac = <Hmac<Sha256>>::new_from_slice(secret).map_err(|_| TokenError::HmacKeyLength)?;
107 mac.update(body);
108 mac.verify_slice(tag).map_err(|_| TokenError::InvalidMac)?;
109 let for_node = u64::from_le_bytes(body[..8].try_into().expect("slice is 8 bytes"));
110 let expiry = u64::from_le_bytes(body[8..].try_into().expect("slice is 8 bytes"));
111 let now = SystemTime::now()
112 .duration_since(UNIX_EPOCH)
113 .map(|d| d.as_secs())
114 .unwrap_or_else(|_| {
115 tracing::error!(
116 "system clock is before UNIX_EPOCH during token verification; \
117 using 0 (epoch) — check NTP/RTC configuration"
118 );
119 0
120 });
121 if now > expiry {
122 return Err(TokenError::Expired);
123 }
124 Ok((for_node, expiry))
125}
126
127fn hex_decode(s: &str) -> Result<Vec<u8>, TokenError> {
128 let mut out = Vec::with_capacity(s.len() / 2);

Callers 6

handleMethod · 0.85
handleMethod · 0.85
verify_rejects_expiredFunction · 0.85

Calls 6

nowFunction · 0.85
duration_sinceMethod · 0.80
hex_decodeFunction · 0.70
lenMethod · 0.45
updateMethod · 0.45
expectMethod · 0.45

Tested by 5

handleMethod · 0.68
verify_rejects_expiredFunction · 0.68