test: add comprehensive pairing code consumption tests
Add comprehensive tests for pairing code consumption feature
This commit is contained in:
parent
dc654f6835
commit
bd02d73ecc
1 changed files with 31 additions and 18 deletions
|
|
@ -28,7 +28,7 @@ pub struct PairingGuard {
|
||||||
/// Whether pairing is required at all.
|
/// Whether pairing is required at all.
|
||||||
require_pairing: bool,
|
require_pairing: bool,
|
||||||
/// One-time pairing code (generated on startup, consumed on first pair).
|
/// One-time pairing code (generated on startup, consumed on first pair).
|
||||||
pairing_code: Option<String>,
|
pairing_code: Mutex<Option<String>>,
|
||||||
/// Set of SHA-256 hashed bearer tokens (persisted across restarts).
|
/// Set of SHA-256 hashed bearer tokens (persisted across restarts).
|
||||||
paired_tokens: Mutex<HashSet<String>>,
|
paired_tokens: Mutex<HashSet<String>>,
|
||||||
/// Brute-force protection: failed attempt counter + lockout time.
|
/// Brute-force protection: failed attempt counter + lockout time.
|
||||||
|
|
@ -62,15 +62,18 @@ impl PairingGuard {
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
require_pairing,
|
require_pairing,
|
||||||
pairing_code: code,
|
pairing_code: Mutex::new(code),
|
||||||
paired_tokens: Mutex::new(tokens),
|
paired_tokens: Mutex::new(tokens),
|
||||||
failed_attempts: Mutex::new((0, None)),
|
failed_attempts: Mutex::new((0, None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The one-time pairing code (only set when no tokens exist yet).
|
/// The one-time pairing code (only set when no tokens exist yet).
|
||||||
pub fn pairing_code(&self) -> Option<&str> {
|
pub fn pairing_code(&self) -> Option<String> {
|
||||||
self.pairing_code.as_deref()
|
self.pairing_code
|
||||||
|
.lock()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether pairing is required at all.
|
/// Whether pairing is required at all.
|
||||||
|
|
@ -97,7 +100,12 @@ impl PairingGuard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref expected) = self.pairing_code {
|
{
|
||||||
|
let mut pairing_code = self
|
||||||
|
.pairing_code
|
||||||
|
.lock()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
|
if let Some(ref expected) = *pairing_code {
|
||||||
if constant_time_eq(code.trim(), expected.trim()) {
|
if constant_time_eq(code.trim(), expected.trim()) {
|
||||||
// Reset failed attempts on success
|
// Reset failed attempts on success
|
||||||
{
|
{
|
||||||
|
|
@ -113,9 +121,14 @@ impl PairingGuard {
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
tokens.insert(hash_token(&token));
|
tokens.insert(hash_token(&token));
|
||||||
|
|
||||||
|
// Consume the pairing code so it cannot be reused
|
||||||
|
*pairing_code = None;
|
||||||
|
|
||||||
return Ok(Some(token));
|
return Ok(Some(token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Increment failed attempts
|
// Increment failed attempts
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue