diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt b/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt index 13b54249..d31d05b1 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt @@ -63,7 +63,7 @@ class OathManager( startTimeMs = currentTimeMs // cancel any pending actions, except for addToAny - if(!addToAny) { + if (!addToAny) { pendingAction?.let { Log.d(TAG, "Cancelling pending action/closing nfc dialog.") it.invoke(Result.failure(CancellationException())) @@ -213,7 +213,7 @@ class OathManager( // Awaiting an action for a different or no device? pendingAction?.let { action -> pendingAction = null - if(addToAny) { + if (addToAny) { // Special "add to any YubiKey" action, process addToAny = false action.invoke(Result.success(oath)) @@ -281,8 +281,12 @@ class OathManager( CredentialData.parseUri(URI.create(uri)) addToAny = true return useOathSessionNfc("Add account") { session -> - val credential = session.putCredential(credentialData, requireTouch) + // We need to check for duplicates here since we haven't yet read the credentials + if (session.credentials.any { it.id.contentEquals(credentialData.id) }) { + throw Exception("A credential with this ID already exists!") + } + val credential = session.putCredential(credentialData, requireTouch) val code = if (credentialData.oathType == OathType.TOTP && !requireTouch) { // recalculate the code diff --git a/lib/oath/views/add_account_page.dart b/lib/oath/views/add_account_page.dart index bc740bcb..f503f08c 100755 --- a/lib/oath/views/add_account_page.dart +++ b/lib/oath/views/add_account_page.dart @@ -69,6 +69,7 @@ class _OathAddAccountPageState extends ConsumerState { bool _isObscure = true; List _periodValues = [20, 30, 45, 60]; List _digitsValues = [6, 8]; + List? _credentials; @override void dispose() { @@ -205,8 +206,13 @@ class _OathAddAccountPageState extends ConsumerState { oathState = ref .watch(oathStateProvider(deviceNode.path)) .maybeWhen(data: (data) => data, orElse: () => null); + _credentials = ref + .watch(credentialListProvider(deviceNode.path)) + ?.map((e) => e.credential) + .toList(); } else { oathState = widget.state; + _credentials = widget.credentials; } final otpauthUri = _otpauthUri; @@ -254,7 +260,7 @@ class _OathAddAccountPageState extends ConsumerState { final secretLengthValid = secret.length * 5 % 8 < 5; // is this credentials name/issuer pair different from all other? - final isUnique = widget.credentials + final isUnique = _credentials ?.where((element) => element.name == _accountController.text.trim() && (element.issuer ?? '') == _issuerController.text.trim())