Files
Password-Manager/android-client/PMA.Biometric.pas
T
r-zakarya 60b806536a fix(android): the prompt field is CancelButtonText, not NegativeButtonText
NegativeButtonText is the Android API name; FMX's record exposes CancelButtonText.
2026-08-15 00:51:24 +01:00

104 lines
3.1 KiB
ObjectPascal

unit PMA.Biometric;
{
Fine couche au-dessus de FMX.BiometricAuth.
On passe par le service FMX plutot que par BiometricPrompt en JNI direct :
le rappel de BiometricPrompt exige une classe Java implementant une
interface, donc un .jar a compiler et embarquer. FMX fournit deja ce pont.
MODELE RETENU : la cle du Keystore est creee avec une validite APRES
authentification (quelques dizaines de secondes). L'utilisateur s'authentifie,
puis la cle devient utilisable pendant ce delai. C'est plus simple qu'un
CryptoObject lie a chaque operation, et suffisant ici : la fenetre est courte
et l'application est au premier plan pendant ce temps.
L'APPEL DOIT SE FAIRE SUR LE THREAD PRINCIPAL - il affiche un dialogue
systeme. Le travail lourd (dechiffrement) part ensuite dans un thread.
}
interface
uses
System.SysUtils;
type
TBioOutcome = (boOK, boUnavailable, boFailed, boCancelled);
/// L'appareil peut-il authentifier (empreinte, visage, ou code de
/// verrouillage) ? False signifie qu'aucune protection n'est configuree.
function BiometricAvailable: Boolean;
/// Demande l'authentification puis appelle AThen. Non bloquant : le resultat
/// arrive par le rappel, sur le thread principal.
/// Si l'appareil ne sait pas authentifier, AThen est appele avec boUnavailable
/// SANS refuser l'acces - a l'appelant de decider. Un telephone sans
/// verrouillage ne peut de toute facon pas proteger la cle.
procedure AuthenticateThen(const APrompt: string; const AThen: TProc<TBioOutcome>);
implementation
{$IF DEFINED(ANDROID)}
uses
FMX.BiometricAuth, FMX.Platform;
{$ENDIF}
function BiometricAvailable: Boolean;
{$IF DEFINED(ANDROID)}
var
LSvc: IFMXBiometricAuthService;
begin
Result := TPlatformServices.Current.SupportsPlatformService(
IFMXBiometricAuthService, LSvc) and LSvc.CanAuthenticate;
end;
{$ELSE}
begin
Result := False;
end;
{$ENDIF}
procedure AuthenticateThen(const APrompt: string; const AThen: TProc<TBioOutcome>);
{$IF DEFINED(ANDROID)}
var
LSvc: IFMXBiometricAuthService;
LProps: TBiometricPromptProperties;
begin
if not Assigned(AThen) then Exit;
if not (TPlatformServices.Current.SupportsPlatformService(
IFMXBiometricAuthService, LSvc) and LSvc.CanAuthenticate) then
begin
AThen(boUnavailable);
Exit;
end;
LProps := Default(TBiometricPromptProperties);
LProps.Title := 'Deverrouiller le coffre';
LProps.Description := APrompt;
LProps.CancelButtonText := 'Annuler';
LSvc.SetPromptProperties(LProps);
// DeviceCredential inclus : un telephone sans empreinte enrolee mais avec
// un code de verrouillage reste utilisable, au lieu d'etre bloque.
LSvc.SetBiometricStrengths([TBiometricStrength.Strong,
TBiometricStrength.DeviceCredential]);
LSvc.Authenticate(
procedure
begin
AThen(boOK);
end,
procedure(const AFailReason: TBiometricFailReason; const AMessage: string)
begin
if AFailReason = TBiometricFailReason.Cancelled then
AThen(boCancelled)
else
AThen(boFailed);
end);
end;
{$ELSE}
begin
if Assigned(AThen) then AThen(boUnavailable);
end;
{$ENDIF}
end.