feat(android): TOTP codes and custom fields in the detail screen
The detail screen showed site, username and password and silently dropped everything else - custom fields, notes, 2FA. It is now built per entry rather than from a fixed template: every row is a caption, a value, and whether it is secret, so reveal and copy exist once instead of once per kind of field. Two rows stay special on purpose. A note's body is stored in the password column, so it gets its own caption and no mask. The 2FA code is the only live row - refreshed every second, placed first, since it is what you pull a phone out for. PMA.Totp takes bare base32 or an otpauth:// URI; both travel in snapshots depending on how the entry was created. Checked against all six RFC 6238 vectors, including T=20000000000, which overflows 32 bits. The rows hold plaintext, so clearing them is part of locking, not of navigating away. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,8 @@ program selftest;
|
||||
uses
|
||||
System.SysUtils, System.Hash, System.NetEncoding, System.Diagnostics,
|
||||
PMA.Crypto in 'PMA.Crypto.pas',
|
||||
PMA.TestVector in 'PMA.TestVector.pas';
|
||||
PMA.TestVector in 'PMA.TestVector.pas',
|
||||
PMA.Totp in 'PMA.Totp.pas';
|
||||
|
||||
var
|
||||
GFailures: Integer = 0;
|
||||
@@ -40,6 +41,19 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// URI plutot que base32 nu : elle porte les 8 chiffres de la RFC, et fait
|
||||
// passer l'analyseur d'otpauth:// dans le meme mouvement.
|
||||
const
|
||||
RFC6238_URI = 'otpauth://totp/rfc?secret=' +
|
||||
'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&digits=8';
|
||||
|
||||
procedure CheckTotp(AUnix: Int64; const AWant: string);
|
||||
var
|
||||
LLeft, LPeriod: Integer;
|
||||
begin
|
||||
Check('T=' + AUnix.ToString, TotpAt(RFC6238_URI, AUnix, LLeft, LPeriod), AWant);
|
||||
end;
|
||||
|
||||
var
|
||||
LSalt, LKey: TBytes;
|
||||
LPlain: string;
|
||||
@@ -107,6 +121,26 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// ---- TOTP, vecteurs de la RFC 6238 --------------------------------------
|
||||
// Secret "12345678901234567890" en base32, 8 chiffres, aux instants publies
|
||||
// par la RFC. C'est le seul moyen de verifier a la fois la base32, le HMAC
|
||||
// et la troncature - un code plausible peut etre faux.
|
||||
Writeln('TOTP (RFC 6238)...');
|
||||
try
|
||||
CheckTotp(59, '94287082');
|
||||
CheckTotp(1111111109, '07081804');
|
||||
CheckTotp(1111111111, '14050471');
|
||||
CheckTotp(1234567890, '89005924');
|
||||
CheckTotp(2000000000, '69279037');
|
||||
CheckTotp(20000000000, '65353130');
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
Writeln(' ERREUR ', E.ClassName, ' : ', E.Message);
|
||||
Inc(GFailures);
|
||||
end;
|
||||
end;
|
||||
|
||||
Writeln;
|
||||
if GFailures = 0 then
|
||||
Writeln('Tout est bon.')
|
||||
|
||||
Reference in New Issue
Block a user