fix(auth): an account whose second factor doesn't work deletes itself

An account whose setup never finished, or whose authenticators' reset took
effect, could not delete itself (the re-review's eighth finding): deletion
asked for a TOTP or recovery code it had no way to give. Such an account
now deletes itself with the password's proof and a code by mail to its
address asked for deleting (EmailCodePurpose.deletion, which nothing else
takes), the address checked against the account's as everywhere after the
password; an account whose second factor works still takes a code from it.
The app's deletion sheet asks for the password and mails the code there,
then takes it.

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-20 23:30:22 +02:00
commit 293ec6b103
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -26,6 +26,8 @@ abstract class DeletionProof
required this.clientProof,
this.totpCode,
this.recoveryCode,
this.request,
this.code,
required this.host,
required this.address,
required this.language,
@ -37,6 +39,8 @@ abstract class DeletionProof
required _idt.ByteData clientProof,
String? totpCode,
String? recoveryCode,
_isc.UuidValue? request,
String? code,
required String host,
required String address,
required String language,
@ -55,6 +59,10 @@ abstract class DeletionProof
),
totpCode: jsonSerialization['totpCode'] as String?,
recoveryCode: jsonSerialization['recoveryCode'] as String?,
request: jsonSerialization['request'] == null
? null
: _isc.UuidValueJsonExtension.fromJson(jsonSerialization['request']),
code: jsonSerialization['code'] as String?,
host: jsonSerialization['host'] as String,
address: jsonSerialization['address'] as String,
language: jsonSerialization['language'] as String,
@ -71,6 +79,14 @@ abstract class DeletionProof
String? recoveryCode;
/// A code by mail asked for deleting (`EmailCodePurpose.deletion`), in
/// place of the codes above where no second factor works: a setup never
/// finished, or the authenticators' reset taken effect (the re-review's
/// eighth finding).
_isc.UuidValue? request;
String? code;
/// The host the device addressed the instance by: the server it reached
/// checks it is its own before the register binds the proof to it.
String host;
@ -91,6 +107,8 @@ abstract class DeletionProof
_idt.ByteData? clientProof,
String? totpCode,
String? recoveryCode,
_isc.UuidValue? request,
String? code,
String? host,
String? address,
String? language,
@ -104,6 +122,8 @@ abstract class DeletionProof
'clientProof': clientProof.toJson(),
if (totpCode != null) 'totpCode': totpCode,
if (recoveryCode != null) 'recoveryCode': recoveryCode,
if (request != null) 'request': request?.toJson(),
if (code != null) 'code': code,
'host': host,
'address': address,
'language': language,
@ -119,6 +139,8 @@ abstract class DeletionProof
'clientProof': clientProof.toJson(),
if (totpCode != null) 'totpCode': totpCode,
if (recoveryCode != null) 'recoveryCode': recoveryCode,
if (request != null) 'request': request?.toJson(),
if (code != null) 'code': code,
'host': host,
'address': address,
'language': language,
@ -140,6 +162,8 @@ class _DeletionProofImpl extends DeletionProof {
required _idt.ByteData clientProof,
String? totpCode,
String? recoveryCode,
_isc.UuidValue? request,
String? code,
required String host,
required String address,
required String language,
@ -149,6 +173,8 @@ class _DeletionProofImpl extends DeletionProof {
clientProof: clientProof,
totpCode: totpCode,
recoveryCode: recoveryCode,
request: request,
code: code,
host: host,
address: address,
language: language,
@ -164,6 +190,8 @@ class _DeletionProofImpl extends DeletionProof {
_idt.ByteData? clientProof,
Object? totpCode = _Undefined,
Object? recoveryCode = _Undefined,
Object? request = _Undefined,
Object? code = _Undefined,
String? host,
String? address,
String? language,
@ -174,6 +202,8 @@ class _DeletionProofImpl extends DeletionProof {
clientProof: clientProof ?? this.clientProof.clone(),
totpCode: totpCode is String? ? totpCode : this.totpCode,
recoveryCode: recoveryCode is String? ? recoveryCode : this.recoveryCode,
request: request is _isc.UuidValue? ? request : this.request,
code: code is String? ? code : this.code,
host: host ?? this.host,
address: address ?? this.address,
language: language ?? this.language,