diff --git a/android-client/PMA.WebUI.pas b/android-client/PMA.WebUI.pas index b0b3726..2bee99a 100644 --- a/android-client/PMA.WebUI.pas +++ b/android-client/PMA.WebUI.pas @@ -131,6 +131,8 @@ begin LObj.AddPair('initial', Initial(E.Display)); LObj.AddPair('hasUser', TJSONBool.Create(E.Username <> '')); LObj.AddPair('isNote', TJSONBool.Create(E.IsNote)); + // Un booleen, jamais le secret : le code se calcule chez Delphi a la copie. + LObj.AddPair('hasTotp', TJSONBool.Create(E.Totp <> '')); LEntries.AddElement(LObj); end; diff --git a/android-client/web/app.html b/android-client/web/app.html index a28d7ab..671188b 100644 --- a/android-client/web/app.html +++ b/android-client/web/app.html @@ -919,6 +919,10 @@ function renderRows() { + (e.sub ? '' + esc(e.sub) + '' : '') + '' + (e.hasUser ? '' : '') + // LE CODE 2FA A PORTEE DE POUCE, comme l'identifiant et le mot de + // passe : il fallait ouvrir l'entree pour le copier. + + (e.hasTotp ? '' : '') + ''; @@ -1001,6 +1005,7 @@ var ICONS = { dots: '' + '', check: '', + clock: '', dice: '' + '' + '', diff --git a/mainApk.pas b/mainApk.pas index 158ecc8..d0a1ab2 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -2032,6 +2032,16 @@ begin begin E := FVault.Entry(LIdx); if Param('f') = 'user' then CopyToClipboard(E.Username, 'Username') + else if Param('f') = 'rtotp' then + begin + // Calcule a l'instant de la copie : un code se perime en 30 s. + var LLeft, LPeriod: Integer; + var LCode := TotpNow(E.Totp, LLeft, LPeriod); + if LCode <> '' then + CopyToClipboard(LCode, Format('2FA code (%d s left)', [LLeft])) + else + WebCall('PM.toast("Unreadable 2FA secret")'); + end else if E.IsNote then CopyToClipboard(E.Password, 'Content') else CopyToClipboard(E.Password, 'Password'); end;