feat: add the registration config keys and their module options
Six keys, and the parser's first list, bool and word-valued ones: registration, registrations_per_hour, info_replies_per_hour, admins, admin_notify, register_hosts. Lists drop empty items, because `admins =` is exactly what the Nix module renders for an unset option, and addresses are validated at load rather than at first use — a typo would otherwise pass the start and then silently never match an admin command. Validated values are normalised through Address::short(), so a spelling carrying the default port collapses to the one the daemon will compare against. registration defaults to silent, so adding these keys changes nothing for anyone who writes in. Verified the generator and the parser agree by feeding the module's rendered output to the binary, in both the fully-set and all-defaults shapes — which matters because config.rs hard-errors on an unknown key. The bucur half waits for the lock: that host pins this flake at the rev before these options existed, so setting them there now would break its eval. It lands with the deploy.
This commit is contained in:
parent
e606b3a1e0
commit
ff289671a5
2 changed files with 228 additions and 0 deletions
81
flake.nix
81
flake.nix
|
|
@ -151,6 +151,12 @@
|
|||
cap_bytes = ${toString cfg.capBytes}
|
||||
poll_secs = ${toString cfg.pollSecs}
|
||||
timeout = ${toString cfg.timeout}
|
||||
registration = ${cfg.registration}
|
||||
registrations_per_hour = ${toString cfg.registrationsPerHour}
|
||||
info_replies_per_hour = ${toString cfg.infoRepliesPerHour}
|
||||
admins = ${lib.concatStringsSep ", " cfg.admins}
|
||||
admin_notify = ${if cfg.adminNotify then "on" else "off"}
|
||||
register_hosts = ${lib.concatStringsSep ", " cfg.registerHosts}
|
||||
'';
|
||||
in
|
||||
{
|
||||
|
|
@ -266,6 +272,81 @@
|
|||
description = "Network timeout for smolmail operations, in seconds.";
|
||||
};
|
||||
|
||||
registration = mkOption {
|
||||
type = types.enum [ "silent" "open" "closed" ];
|
||||
default = "silent";
|
||||
description = ''
|
||||
Whether strangers may register themselves by mail. `silent`
|
||||
drops an unknown sender without a reply, which is how every
|
||||
version before self-service behaved — so upgrading never
|
||||
starts mailing strangers on its own. `open` lets them
|
||||
register; `closed` tells them registration is shut.
|
||||
|
||||
Only the initial value: an admin's `Twt-Registration` is
|
||||
persisted in the daemon's state and outranks it, so the mode
|
||||
can change by mail without a redeploy.
|
||||
'';
|
||||
};
|
||||
|
||||
registrationsPerHour = mkOption {
|
||||
type = types.ints.positive;
|
||||
default = 10;
|
||||
description = ''
|
||||
Daemon-wide cap on registration attempts that reach the
|
||||
network, per hour. Attempts rather than successes: one that
|
||||
fails its key check costs the same outbound dial.
|
||||
|
||||
This is the cap that matters — identity keys are free to
|
||||
mint, so a per-sender budget does not bind an attacker.
|
||||
'';
|
||||
};
|
||||
|
||||
infoRepliesPerHour = mkOption {
|
||||
type = types.ints.positive;
|
||||
default = 30;
|
||||
description = "Daemon-wide cap on info replies to unknown senders, per hour.";
|
||||
};
|
||||
|
||||
admins = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = [ "tobias@smol.place" ];
|
||||
description = ''
|
||||
Addresses allowed to send `Twt-Admit`, `Twt-Block` and
|
||||
`Twt-Registration`, in `user@host` short form. Each is
|
||||
validated when the daemon loads its config, so a typo fails
|
||||
the start rather than silently never matching.
|
||||
|
||||
Admit your own admin identity once with the CLI so the daemon
|
||||
pins your key and hands you a token; until it holds one, its
|
||||
acks land in your requests tier.
|
||||
'';
|
||||
};
|
||||
|
||||
adminNotify = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Mail every admin when a feed is created, with the author's
|
||||
address and key fingerprint — and for a remote author the
|
||||
unpinned server key their host presented.
|
||||
'';
|
||||
};
|
||||
|
||||
registerHosts = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = [ "smol.place" ];
|
||||
description = ''
|
||||
Hosts whose users may register. Empty means any host.
|
||||
|
||||
Note what empty allows: the daemon will dial a `host:port` an
|
||||
unknown sender chose, a mild port-scan primitive with timing
|
||||
feedback from inside this machine's network. Bounded by
|
||||
`registrationsPerHour`, closed entirely by listing hosts here.
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue