fix(auth): a hold-out moves a reset on only by its own time, and a reset lives 30 days at most

The reading of the full reading's fixes found that every refusal at the
address's ceiling moved a reset to 72 hours after it (A1): someone who
knows only the address kept the owner's own reset from ever taking effect
with one burst every three days, and kept a forgotten one alive (A2).

Now a hold-out that begins before a reset takes effect moves it on only by
the time it holds the owner out and no hold-out counted before did
(account_reset.heldOutUntil, under a row lock), so the owner gets 72 hours
outside hold-outs in total; and every reset not carried out lapses 30 days
after it was asked (resetLivesAtMost), whatever moved it, besides a week
after it took effect.

Migration (module, Learn's and Todo's servers, Learn's device schema):
ALTER TABLE "account_reset" ADD COLUMN "heldOutUntil" timestamp without
time zone; nullable, existing rows counted from now on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-21 15:50:29 +02:00
commit 274b796faa
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
5 changed files with 41748 additions and 65 deletions

View file

@ -0,0 +1,33 @@
{
"__className__": "serverpod.DatabaseMigration",
"actions": [
{
"__className__": "serverpod.DatabaseMigrationAction",
"type": "alterTable",
"alterTable": {
"__className__": "serverpod.TableMigration",
"name": "account_reset",
"schema": "public",
"addColumns": [
{
"__className__": "serverpod.ColumnDefinition",
"name": "heldOutUntil",
"fieldName": "heldOutUntil",
"columnType": 4,
"isNullable": true,
"dartType": "DateTime?"
}
],
"deleteColumns": [],
"modifyColumns": [],
"addIndexes": [],
"deleteIndexes": [],
"addForeignKeys": [],
"deleteForeignKeys": [],
"warnings": []
}
}
],
"warnings": [],
"migrationApiVersion": 1
}

View file

@ -26,6 +26,7 @@ part '20261020204619104-session-code-tries/migration.dart';
part '20261020211224692-email-code-purpose/migration.dart';
part '20261021100422048-session-ended-warning/migration.dart';
part '20261021110159867-second-factor-paths/migration.dart';
part '20261021134803749-reset-hold-outs/migration.dart';
/// Migration registry for the client-side database.
class MigrationRegistry {
@ -54,6 +55,7 @@ class MigrationRegistry {
_Migration20261020211224692_email_code_purpose(),
_Migration20261021100422048_session_ended_warning(),
_Migration20261021110159867_second_factor_paths(),
_Migration20261021134803749_reset_hold_outs(),
];
/// List of all client-side database migration versions.