ADR 0017, step 3. `password.beginChange` and `password.change` take the old password's SRP proof and a TOTP or recovery code, and the same keys wrapped under the new password; a session alone changes nothing, and an account without a confirmed authenticator is told to set one up first. `password.setRecoveryKeys` replaces the keys' wrapping under the recovery phrase for a TOTP code, so a device holding the keys can make a new phrase. A change of password ends every other session of the account in every service of the instance; resets of the password and of the account end them all. The register ends its own and keeps a notice per member (`sessions_ended_notice`, a migration that only creates it), told at once and hourly until it confirms, as deletions are told: it names a moment, so sessions made since stay, and the session that asked for a change. A member answering one ends its sessions made before that moment; a member signing someone in after a reset ends its own first and makes the new session only once its clock is past the moment. A reset not due says when it takes effect (`takesEffectAt` on `PasswordRefusedException`), across members too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
100 lines
No EOL
2.9 KiB
JSON
100 lines
No EOL
2.9 KiB
JSON
{
|
|
"__className__": "serverpod.DatabaseMigration",
|
|
"actions": [
|
|
{
|
|
"__className__": "serverpod.DatabaseMigrationAction",
|
|
"type": "createTable",
|
|
"createTable": {
|
|
"__className__": "serverpod.TableDefinition",
|
|
"name": "sessions_ended_notice",
|
|
"dartName": "SessionsEndedNotice",
|
|
"module": "halkyon_base",
|
|
"schema": "public",
|
|
"columns": [
|
|
{
|
|
"__className__": "serverpod.ColumnDefinition",
|
|
"name": "id",
|
|
"fieldName": "id",
|
|
"columnType": 6,
|
|
"isNullable": false,
|
|
"columnDefault": "serial",
|
|
"dartType": "int?"
|
|
},
|
|
{
|
|
"__className__": "serverpod.ColumnDefinition",
|
|
"name": "account",
|
|
"fieldName": "account",
|
|
"columnType": 7,
|
|
"isNullable": false,
|
|
"dartType": "UuidValue"
|
|
},
|
|
{
|
|
"__className__": "serverpod.ColumnDefinition",
|
|
"name": "member",
|
|
"fieldName": "member",
|
|
"columnType": 0,
|
|
"isNullable": false,
|
|
"dartType": "String"
|
|
},
|
|
{
|
|
"__className__": "serverpod.ColumnDefinition",
|
|
"name": "endedBefore",
|
|
"fieldName": "endedBefore",
|
|
"columnType": 4,
|
|
"isNullable": false,
|
|
"dartType": "DateTime"
|
|
},
|
|
{
|
|
"__className__": "serverpod.ColumnDefinition",
|
|
"name": "keepSession",
|
|
"fieldName": "keepSession",
|
|
"columnType": 7,
|
|
"isNullable": true,
|
|
"dartType": "UuidValue?"
|
|
},
|
|
{
|
|
"__className__": "serverpod.ColumnDefinition",
|
|
"name": "attempts",
|
|
"fieldName": "attempts",
|
|
"columnType": 6,
|
|
"isNullable": false,
|
|
"dartType": "int"
|
|
},
|
|
{
|
|
"__className__": "serverpod.ColumnDefinition",
|
|
"name": "lastAttemptAt",
|
|
"fieldName": "lastAttemptAt",
|
|
"columnType": 4,
|
|
"isNullable": true,
|
|
"dartType": "DateTime?"
|
|
}
|
|
],
|
|
"foreignKeys": [],
|
|
"indexes": [
|
|
{
|
|
"__className__": "serverpod.IndexDefinition",
|
|
"indexName": "sessions_ended_notice_idx",
|
|
"elements": [
|
|
{
|
|
"__className__": "serverpod.IndexElementDefinition",
|
|
"type": 0,
|
|
"definition": "account"
|
|
},
|
|
{
|
|
"__className__": "serverpod.IndexElementDefinition",
|
|
"type": 0,
|
|
"definition": "member"
|
|
}
|
|
],
|
|
"type": "btree",
|
|
"isUnique": true,
|
|
"isPrimary": false
|
|
}
|
|
],
|
|
"managed": true
|
|
}
|
|
}
|
|
],
|
|
"warnings": [],
|
|
"migrationApiVersion": 1
|
|
} |