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.
|
||||
require_pairing: bool,
|
||||
/// 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).
|
||||
paired_tokens: Mutex<HashSet<String>>,
|
||||
/// Brute-force protection: failed attempt counter + lockout time.
|
||||
|
|
@ -62,15 +62,18 @@ impl PairingGuard {
|
|||
};
|
||||
Self {
|
||||
require_pairing,
|
||||
pairing_code: code,
|
||||
pairing_code: Mutex::new(code),
|
||||
paired_tokens: Mutex::new(tokens),
|
||||
failed_attempts: Mutex::new((0, None)),
|
||||
}
|
||||
}
|
||||
|
||||
/// The one-time pairing code (only set when no tokens exist yet).
|
||||
pub fn pairing_code(&self) -> Option<&str> {
|
||||
self.pairing_code.as_deref()
|
||||
pub fn pairing_code(&self) -> Option<String> {
|
||||
self.pairing_code
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
.clone()
|
||||
}
|
||||
|
||||
/// Whether pairing is required at all.
|
||||
|
|
@ -97,23 +100,33 @@ impl PairingGuard {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(ref expected) = self.pairing_code {
|
||||
if constant_time_eq(code.trim(), expected.trim()) {
|
||||
// Reset failed attempts on success
|
||||
{
|
||||
let mut attempts = self
|
||||
.failed_attempts
|
||||
{
|
||||
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()) {
|
||||
// Reset failed attempts on success
|
||||
{
|
||||
let mut attempts = self
|
||||
.failed_attempts
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
*attempts = (0, None);
|
||||
}
|
||||
let token = generate_token();
|
||||
let mut tokens = self
|
||||
.paired_tokens
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
*attempts = (0, None);
|
||||
tokens.insert(hash_token(&token));
|
||||
|
||||
// Consume the pairing code so it cannot be reused
|
||||
*pairing_code = None;
|
||||
|
||||
return Ok(Some(token));
|
||||
}
|
||||
let token = generate_token();
|
||||
let mut tokens = self
|
||||
.paired_tokens
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
tokens.insert(hash_token(&token));
|
||||
return Ok(Some(token));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue