fix(server): forget the IP addresses of sign-up attempts

Serverpod's rate limit for new anonymous accounts (30 per IP address and
hour) notes every attempt with the address it came from, and deletes
those notes only for email sign-in, which this instance doesn't offer. So
the IP address of everyone who ever started the app stayed in the
database, and in every backup, for good.

The server now deletes them hourly once the limit's hour is past, so an
address is kept for at most two hours. The rows already there go at the
first run after the deploy; backups keep them until they expire (about
three months).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-10 05:37:00 +02:00
commit 0d03ef7973
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -34,6 +34,15 @@ Future<void> run(List<String> args) async {
.pruning
.pruneAnonymousPeople();
// The IP addresses of sign-up attempts, hourly, once the rate limit is
// done with them (decided 2026-10-10).
await pod.futureCalls.cancel(_attemptPruning);
await pod.futureCalls
.callRecurring(identifier: _attemptPruning)
.cron('27 * * * *')
.pruning
.forgetSignUpAttempts();
// So are the files nobody can reach any more (ADR 0004, rule 5).
await pod.futureCalls.cancel(_filePruning);
await pod.futureCalls
@ -79,6 +88,9 @@ Future<void> _loadDictionaries(Serverpod pod) async {
/// The identifier of the daily pruning.
const _pruning = 'prune-abandoned-anonymous-people';
/// The identifier of the hourly forgetting of sign-up attempts.
const _attemptPruning = 'forget-sign-up-attempts';
/// The identifier of the daily pruning of files.
const _filePruning = 'prune-unreferenced-files';