OperServ: add SET READONLY lockdown
All checks were successful
CI / check (push) Successful in 3m31s
All checks were successful
CI / check (push) Successful in 3m31s
This commit is contained in:
parent
b2442f85e6
commit
0027decdb7
8 changed files with 112 additions and 2 deletions
|
|
@ -680,11 +680,15 @@ pub struct EventLog {
|
|||
versions: HashMap<String, u64>, // per-origin highest seq applied (version vector)
|
||||
entries: Vec<LogEntry>, // full log, kept so peers can pull what they lack
|
||||
outbound: Option<broadcast::Sender<LogEntry>>, // push newly committed entries to peers
|
||||
// Operator lockdown (OperServ SET READONLY): while set, locally-authored
|
||||
// writes are refused. Ephemeral — it resets on restart and never persists,
|
||||
// and gossip ingestion is unaffected so a read-only node stays in sync.
|
||||
readonly: bool,
|
||||
}
|
||||
|
||||
impl EventLog {
|
||||
fn open(path: PathBuf, origin: String) -> (Self, Vec<Event>) {
|
||||
let mut log = Self { path, origin, lamport: 0, versions: HashMap::new(), entries: Vec::new(), outbound: None };
|
||||
let mut log = Self { path, origin, lamport: 0, versions: HashMap::new(), entries: Vec::new(), outbound: None, readonly: false };
|
||||
if let Ok(data) = std::fs::read_to_string(&log.path) {
|
||||
for line in data.lines().filter(|l| !l.trim().is_empty()) {
|
||||
match serde_json::from_str::<LogEntry>(line) {
|
||||
|
|
@ -719,6 +723,10 @@ impl EventLog {
|
|||
// Lamport clock and are pushed to peers; local (channel) events are written
|
||||
// for restart but never gossiped and carry no version-vector identity.
|
||||
fn append(&mut self, event: Event) -> std::io::Result<()> {
|
||||
// Operator lockdown refuses every locally-authored write at this one seam.
|
||||
if self.readonly {
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "services are read-only"));
|
||||
}
|
||||
let global = event.scope() == Scope::Global;
|
||||
let entry = if global {
|
||||
self.lamport += 1;
|
||||
|
|
|
|||
|
|
@ -197,6 +197,17 @@ impl Db {
|
|||
self.defcon = level.clamp(1, 5);
|
||||
}
|
||||
|
||||
/// Whether the services are in operator read-only lockdown.
|
||||
pub fn readonly(&self) -> bool {
|
||||
self.log.readonly
|
||||
}
|
||||
|
||||
/// Enter or leave read-only lockdown: while on, locally-authored writes are
|
||||
/// refused. Ephemeral (never persisted); gossip ingestion is unaffected.
|
||||
pub fn set_readonly(&mut self, on: bool) {
|
||||
self.log.readonly = on;
|
||||
}
|
||||
|
||||
/// Whether new nick/account registrations are frozen (defcon 3 or lower).
|
||||
pub fn registrations_frozen(&self) -> bool {
|
||||
self.defcon <= 3
|
||||
|
|
|
|||
|
|
@ -228,6 +228,12 @@ impl Store for Db {
|
|||
fn set_defcon(&mut self, level: u8) {
|
||||
Db::set_defcon(self, level)
|
||||
}
|
||||
fn readonly(&self) -> bool {
|
||||
Db::readonly(self)
|
||||
}
|
||||
fn set_readonly(&mut self, on: bool) {
|
||||
Db::set_readonly(self, on)
|
||||
}
|
||||
fn registrations_frozen(&self) -> bool {
|
||||
Db::registrations_frozen(self)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue