feat(apk): bouton de copie du code 2FA sur chaque ligne de la liste
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -131,6 +131,8 @@ begin
|
|||||||
LObj.AddPair('initial', Initial(E.Display));
|
LObj.AddPair('initial', Initial(E.Display));
|
||||||
LObj.AddPair('hasUser', TJSONBool.Create(E.Username <> ''));
|
LObj.AddPair('hasUser', TJSONBool.Create(E.Username <> ''));
|
||||||
LObj.AddPair('isNote', TJSONBool.Create(E.IsNote));
|
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);
|
LEntries.AddElement(LObj);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
@@ -919,6 +919,10 @@ function renderRows() {
|
|||||||
+ (e.sub ? '<span>' + esc(e.sub) + '</span>' : '') + '</div>'
|
+ (e.sub ? '<span>' + esc(e.sub) + '</span>' : '') + '</div>'
|
||||||
+ (e.hasUser ? '<button class="btn ico-btn" data-copy="user">'
|
+ (e.hasUser ? '<button class="btn ico-btn" data-copy="user">'
|
||||||
+ ico('user', 'Copy username') + '</button>' : '')
|
+ ico('user', 'Copy username') + '</button>' : '')
|
||||||
|
// 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 ? '<button class="btn ico-btn" data-copy="rtotp">'
|
||||||
|
+ ico('clock', 'Copy 2FA code') + '</button>' : '')
|
||||||
+ '<button class="btn ico-btn" data-copy="pwd">'
|
+ '<button class="btn ico-btn" data-copy="pwd">'
|
||||||
+ (e.isNote ? ico('note', 'Copy text') : ico('key', 'Copy password'))
|
+ (e.isNote ? ico('note', 'Copy text') : ico('key', 'Copy password'))
|
||||||
+ '</button></div>';
|
+ '</button></div>';
|
||||||
@@ -1001,6 +1005,7 @@ var ICONS = {
|
|||||||
dots: '<circle cx="12" cy="5" r="1.4"/><circle cx="12" cy="12" r="1.4"/>'
|
dots: '<circle cx="12" cy="5" r="1.4"/><circle cx="12" cy="12" r="1.4"/>'
|
||||||
+ '<circle cx="12" cy="19" r="1.4"/>',
|
+ '<circle cx="12" cy="19" r="1.4"/>',
|
||||||
check: '<path d="M4 12.5l5.5 5.5L20 7"/>',
|
check: '<path d="M4 12.5l5.5 5.5L20 7"/>',
|
||||||
|
clock: '<circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/>',
|
||||||
dice: '<rect x="4" y="4" width="16" height="16" rx="3"/>'
|
dice: '<rect x="4" y="4" width="16" height="16" rx="3"/>'
|
||||||
+ '<circle cx="9" cy="9" r="1.2"/><circle cx="15" cy="15" r="1.2"/>'
|
+ '<circle cx="9" cy="9" r="1.2"/><circle cx="15" cy="15" r="1.2"/>'
|
||||||
+ '<circle cx="15" cy="9" r="1.2"/><circle cx="9" cy="15" r="1.2"/>',
|
+ '<circle cx="15" cy="9" r="1.2"/><circle cx="9" cy="15" r="1.2"/>',
|
||||||
|
|||||||
+10
@@ -2032,6 +2032,16 @@ begin
|
|||||||
begin
|
begin
|
||||||
E := FVault.Entry(LIdx);
|
E := FVault.Entry(LIdx);
|
||||||
if Param('f') = 'user' then CopyToClipboard(E.Username, 'Username')
|
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 if E.IsNote then CopyToClipboard(E.Password, 'Content')
|
||||||
else CopyToClipboard(E.Password, 'Password');
|
else CopyToClipboard(E.Password, 'Password');
|
||||||
end;
|
end;
|
||||||
|
|||||||
Reference in New Issue
Block a user