db: one timestamp for a ban/account's logged event and in-memory record, so a peer replaying it converges (two now() calls could straddle a second)
All checks were successful
CI / check (push) Successful in 3m55s
All checks were successful
CI / check (push) Successful in 3m55s
This commit is contained in:
parent
47dfa76fd5
commit
9a197fca3d
2 changed files with 17 additions and 9 deletions
|
|
@ -9,10 +9,11 @@ impl Db {
|
||||||
// Unverified only when email confirmation actually applies (email is
|
// Unverified only when email confirmation actually applies (email is
|
||||||
// configured and an address was given); otherwise verified immediately.
|
// configured and an address was given); otherwise verified immediately.
|
||||||
let verified = !(self.email_enabled && email.is_some());
|
let verified = !(self.email_enabled && email.is_some());
|
||||||
|
let ts = now(); // one timestamp: registered-at == last-seen at creation
|
||||||
let account = Account {
|
let account = Account {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
email,
|
email,
|
||||||
ts: now(),
|
ts,
|
||||||
home: self.log.origin.clone(),
|
home: self.log.origin.clone(),
|
||||||
scram256: Some(creds.scram256),
|
scram256: Some(creds.scram256),
|
||||||
scram512: Some(creds.scram512),
|
scram512: Some(creds.scram512),
|
||||||
|
|
@ -24,7 +25,7 @@ impl Db {
|
||||||
greet: String::new(), no_autoop: false, no_protect: false, hide_status: false,
|
greet: String::new(), no_autoop: false, no_protect: false, hide_status: false,
|
||||||
vhost: None,
|
vhost: None,
|
||||||
vhost_request: None,
|
vhost_request: None,
|
||||||
last_seen: now(),
|
last_seen: ts,
|
||||||
noexpire: false,
|
noexpire: false,
|
||||||
expiry_warned: false,
|
expiry_warned: false,
|
||||||
oper_note: None,
|
oper_note: None,
|
||||||
|
|
@ -64,10 +65,11 @@ impl Db {
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let ts = now(); // one timestamp: registered-at == last-seen at creation
|
||||||
let account = Account {
|
let account = Account {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
email,
|
email,
|
||||||
ts: now(),
|
ts,
|
||||||
home: self.log.origin.clone(),
|
home: self.log.origin.clone(),
|
||||||
scram256: Some(scram256.to_string()),
|
scram256: Some(scram256.to_string()),
|
||||||
scram512: (!scram512.is_empty()).then(|| scram512.to_string()),
|
scram512: (!scram512.is_empty()).then(|| scram512.to_string()),
|
||||||
|
|
@ -79,7 +81,7 @@ impl Db {
|
||||||
greet: String::new(), no_autoop: false, no_protect: false, hide_status: false,
|
greet: String::new(), no_autoop: false, no_protect: false, hide_status: false,
|
||||||
vhost: None,
|
vhost: None,
|
||||||
vhost_request: None,
|
vhost_request: None,
|
||||||
last_seen: now(),
|
last_seen: ts,
|
||||||
noexpire: false,
|
noexpire: false,
|
||||||
expiry_warned: false,
|
expiry_warned: false,
|
||||||
oper_note: None,
|
oper_note: None,
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,17 @@ impl Db {
|
||||||
pub fn akill_add(&mut self, kind: XlineKind, mask: &str, setter: &str, reason: &str, expires: Option<u64>) -> Result<bool, RegError> {
|
pub fn akill_add(&mut self, kind: XlineKind, mask: &str, setter: &str, reason: &str, expires: Option<u64>) -> Result<bool, RegError> {
|
||||||
// Storage/gossip keep the ircd's line token; the API is typed.
|
// Storage/gossip keep the ircd's line token; the API is typed.
|
||||||
let wire = kind.wire();
|
let wire = kind.wire();
|
||||||
|
// One timestamp for the logged event AND the in-memory record: two `now()`
|
||||||
|
// calls could straddle a second, so a peer replaying the event would store a
|
||||||
|
// different ts than us and gossip state would never converge.
|
||||||
|
let ts = now();
|
||||||
let same = |a: &Akill| a.kind == wire && a.mask.eq_ignore_ascii_case(mask);
|
let same = |a: &Akill| a.kind == wire && a.mask.eq_ignore_ascii_case(mask);
|
||||||
let fresh = !self.net.akills.iter().any(|a| same(a) && a.expires.is_none_or(|e| e > now()));
|
let fresh = !self.net.akills.iter().any(|a| same(a) && a.expires.is_none_or(|e| e > ts));
|
||||||
self.log
|
self.log
|
||||||
.append(Event::AkillAdded { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts: now(), expires })
|
.append(Event::AkillAdded { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts, expires })
|
||||||
.map_err(|_| RegError::Internal)?;
|
.map_err(|_| RegError::Internal)?;
|
||||||
self.net.akills.retain(|a| !same(a));
|
self.net.akills.retain(|a| !same(a));
|
||||||
self.net.akills.push(Akill { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts: now(), expires });
|
self.net.akills.push(Akill { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts, expires });
|
||||||
Ok(fresh)
|
Ok(fresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,13 +50,15 @@ impl Db {
|
||||||
pub fn forbid_add(&mut self, kind: ForbidKind, mask: &str, setter: &str, reason: &str) -> Result<bool, RegError> {
|
pub fn forbid_add(&mut self, kind: ForbidKind, mask: &str, setter: &str, reason: &str) -> Result<bool, RegError> {
|
||||||
// The store persists/gossips the wire token; the API is typed.
|
// The store persists/gossips the wire token; the API is typed.
|
||||||
let wire = kind.wire();
|
let wire = kind.wire();
|
||||||
|
// One timestamp for the event AND the in-memory record (see akill_add).
|
||||||
|
let ts = now();
|
||||||
let same = |f: &Forbid| f.kind == wire && f.mask.eq_ignore_ascii_case(mask);
|
let same = |f: &Forbid| f.kind == wire && f.mask.eq_ignore_ascii_case(mask);
|
||||||
let fresh = !self.net.forbids.iter().any(same);
|
let fresh = !self.net.forbids.iter().any(same);
|
||||||
self.log
|
self.log
|
||||||
.append(Event::ForbidAdded { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts: now() })
|
.append(Event::ForbidAdded { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts })
|
||||||
.map_err(|_| RegError::Internal)?;
|
.map_err(|_| RegError::Internal)?;
|
||||||
self.net.forbids.retain(|f| !same(f));
|
self.net.forbids.retain(|f| !same(f));
|
||||||
self.net.forbids.push(Forbid { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts: now() });
|
self.net.forbids.push(Forbid { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts });
|
||||||
Ok(fresh)
|
Ok(fresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue