fix(channels): use platform message IDs to prevent duplicate memories
Fixes #430 - Prevents duplicate memories after restart by using platform message IDs instead of random UUIDs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c3cc835346
commit
e8553a800a
9 changed files with 217 additions and 82 deletions
|
|
@ -8,8 +8,8 @@
|
|||
// Already-paired tokens are persisted in config so restarts don't require
|
||||
// re-pairing.
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
use parking_lot::Mutex;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::collections::HashSet;
|
||||
use std::time::Instant;
|
||||
|
||||
|
|
@ -70,9 +70,7 @@ impl PairingGuard {
|
|||
|
||||
/// The one-time pairing code (only set when no tokens exist yet).
|
||||
pub fn pairing_code(&self) -> Option<String> {
|
||||
self.pairing_code
|
||||
.lock()
|
||||
.clone()
|
||||
self.pairing_code.lock().clone()
|
||||
}
|
||||
|
||||
/// Whether pairing is required at all.
|
||||
|
|
@ -85,10 +83,7 @@ impl PairingGuard {
|
|||
pub fn try_pair(&self, code: &str) -> Result<Option<String>, u64> {
|
||||
// Check brute force lockout
|
||||
{
|
||||
let attempts = self
|
||||
.failed_attempts
|
||||
.lock()
|
||||
;
|
||||
let attempts = self.failed_attempts.lock();
|
||||
if let (count, Some(locked_at)) = &*attempts {
|
||||
if *count >= MAX_PAIR_ATTEMPTS {
|
||||
let elapsed = locked_at.elapsed().as_secs();
|
||||
|
|
@ -100,25 +95,16 @@ impl PairingGuard {
|
|||
}
|
||||
|
||||
{
|
||||
let mut pairing_code = self
|
||||
.pairing_code
|
||||
.lock()
|
||||
;
|
||||
let mut pairing_code = self.pairing_code.lock();
|
||||
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()
|
||||
;
|
||||
let mut attempts = self.failed_attempts.lock();
|
||||
*attempts = (0, None);
|
||||
}
|
||||
let token = generate_token();
|
||||
let mut tokens = self
|
||||
.paired_tokens
|
||||
.lock()
|
||||
;
|
||||
let mut tokens = self.paired_tokens.lock();
|
||||
tokens.insert(hash_token(&token));
|
||||
|
||||
// Consume the pairing code so it cannot be reused
|
||||
|
|
@ -131,10 +117,7 @@ impl PairingGuard {
|
|||
|
||||
// Increment failed attempts
|
||||
{
|
||||
let mut attempts = self
|
||||
.failed_attempts
|
||||
.lock()
|
||||
;
|
||||
let mut attempts = self.failed_attempts.lock();
|
||||
attempts.0 += 1;
|
||||
if attempts.0 >= MAX_PAIR_ATTEMPTS {
|
||||
attempts.1 = Some(Instant::now());
|
||||
|
|
@ -150,28 +133,19 @@ impl PairingGuard {
|
|||
return true;
|
||||
}
|
||||
let hashed = hash_token(token);
|
||||
let tokens = self
|
||||
.paired_tokens
|
||||
.lock()
|
||||
;
|
||||
let tokens = self.paired_tokens.lock();
|
||||
tokens.contains(&hashed)
|
||||
}
|
||||
|
||||
/// Returns true if the gateway is already paired (has at least one token).
|
||||
pub fn is_paired(&self) -> bool {
|
||||
let tokens = self
|
||||
.paired_tokens
|
||||
.lock()
|
||||
;
|
||||
let tokens = self.paired_tokens.lock();
|
||||
!tokens.is_empty()
|
||||
}
|
||||
|
||||
/// Get all paired token hashes (for persisting to config).
|
||||
pub fn tokens(&self) -> Vec<String> {
|
||||
let tokens = self
|
||||
.paired_tokens
|
||||
.lock()
|
||||
;
|
||||
let tokens = self.paired_tokens.lock();
|
||||
tokens.iter().cloned().collect()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue