From 3d5eec1f88401be0203b25e6a3c0806ed7e69cb5 Mon Sep 17 00:00:00 2001 From: Oppiie Date: Sun, 13 Oct 2024 15:23:48 -0400 Subject: [PATCH 1/4] Update register response with transports field --- .../lib/types/register_response.dart | 2 ++ .../passkeys_web/lib/models/passkeySignUpResponse.dart | 7 ++++++- .../passkeys_web/lib/models/passkeySignUpResponse.g.dart | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/passkeys/passkeys_platform_interface/lib/types/register_response.dart b/packages/passkeys/passkeys_platform_interface/lib/types/register_response.dart index 7b819ca0..e4902896 100644 --- a/packages/passkeys/passkeys_platform_interface/lib/types/register_response.dart +++ b/packages/passkeys/passkeys_platform_interface/lib/types/register_response.dart @@ -4,10 +4,12 @@ class RegisterResponseType { required this.rawId, required this.clientDataJSON, required this.attestationObject, + required this.transports, }); final String id; final String rawId; final String clientDataJSON; final String attestationObject; + final List transports; } diff --git a/packages/passkeys/passkeys_web/lib/models/passkeySignUpResponse.dart b/packages/passkeys/passkeys_web/lib/models/passkeySignUpResponse.dart index baef6fc5..43f44f16 100644 --- a/packages/passkeys/passkeys_web/lib/models/passkeySignUpResponse.dart +++ b/packages/passkeys/passkeys_web/lib/models/passkeySignUpResponse.dart @@ -21,10 +21,15 @@ class AttestationResponse { factory AttestationResponse.fromJson(Map json) => _$AttestationResponseFromJson(json); - AttestationResponse(this.clientDataJSON, this.attestationObject); + AttestationResponse( + this.clientDataJSON, + this.attestationObject, + this.transports, + ); final String clientDataJSON; final String attestationObject; + final List transports; Map toJson() => _$AttestationResponseToJson(this); } diff --git a/packages/passkeys/passkeys_web/lib/models/passkeySignUpResponse.g.dart b/packages/passkeys/passkeys_web/lib/models/passkeySignUpResponse.g.dart index 9e54d558..28c6b082 100644 --- a/packages/passkeys/passkeys_web/lib/models/passkeySignUpResponse.g.dart +++ b/packages/passkeys/passkeys_web/lib/models/passkeySignUpResponse.g.dart @@ -26,6 +26,7 @@ AttestationResponse _$AttestationResponseFromJson(Map json) => AttestationResponse( json['clientDataJSON'] as String, json['attestationObject'] as String, + json['transports'] as List, ); Map _$AttestationResponseToJson( @@ -33,4 +34,5 @@ Map _$AttestationResponseToJson( { 'clientDataJSON': instance.clientDataJSON, 'attestationObject': instance.attestationObject, + 'transports': instance.transports, }; From 140ea883a040adccc675a182866e5ee7b5b61864 Mon Sep 17 00:00:00 2001 From: Oppiie Date: Sun, 13 Oct 2024 17:31:59 -0400 Subject: [PATCH 2/4] Update passkeys_web.dart --- packages/passkeys/passkeys_web/lib/passkeys_web.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/passkeys/passkeys_web/lib/passkeys_web.dart b/packages/passkeys/passkeys_web/lib/passkeys_web.dart index 270629e1..c5a54173 100644 --- a/packages/passkeys/passkeys_web/lib/passkeys_web.dart +++ b/packages/passkeys/passkeys_web/lib/passkeys_web.dart @@ -44,6 +44,7 @@ class PasskeysWeb extends PasskeysPlatform { rawId: typedResponse.rawId, clientDataJSON: typedResponse.response.clientDataJSON, attestationObject: typedResponse.response.attestationObject, + transports: typedResponse.response.transports, ); } catch (e) { final exception = _parseException(e as String); From 48d82a99ade6529e4b7384c3670685c52ab1a0b0 Mon Sep 17 00:00:00 2001 From: Oppiie Date: Sun, 13 Oct 2024 17:53:52 -0400 Subject: [PATCH 3/4] Added support in iOS and Android --- .../passkeys_android/MessageHandler.java | 241 ++++++++++-------- .../passkeys_android/lib/messages.g.dart | 72 ++++-- .../lib/passkeys_android.dart | 1 + .../passkeys_android/pigeons/messages.dart | 4 + .../passkeys_ios/ios/Classes/messages.swift | 7 +- .../passkeys/passkeys_ios/lib/messages.g.dart | 53 ++-- .../passkeys_ios/lib/passkeys_ios.dart | 1 + .../passkeys_ios/pigeons/messages.dart | 4 + 8 files changed, 244 insertions(+), 139 deletions(-) diff --git a/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/MessageHandler.java b/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/MessageHandler.java index b124da54..afb1ec76 100644 --- a/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/MessageHandler.java +++ b/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/MessageHandler.java @@ -85,17 +85,20 @@ public void register( @Nullable Long timeout, @Nullable String attestation, @NonNull List excludeCredentials, - @NonNull Messages.Result result - ) { + @NonNull Messages.Result result) { UserType userType = new UserType(user.getName(), user.getDisplayName(), user.getId(), user.getIcon()); RelyingPartyType relyingPartyType = new RelyingPartyType(relyingParty.getId(), relyingParty.getName()); - AuthenticatorSelectionType authSelectionType = new AuthenticatorSelectionType(authenticatorSelection.getAuthenticatorAttachment(), authenticatorSelection.getRequireResidentKey(), authenticatorSelection.getResidentKey(), authenticatorSelection.getUserVerification()); + AuthenticatorSelectionType authSelectionType = new AuthenticatorSelectionType( + authenticatorSelection.getAuthenticatorAttachment(), authenticatorSelection.getRequireResidentKey(), + authenticatorSelection.getResidentKey(), authenticatorSelection.getUserVerification()); List pubKeyCredParamsType = new ArrayList<>(); if (pubKeyCredParams != null) { - pubKeyCredParamsType = pubKeyCredParams.stream().map(p -> new PubKeyCredParamType(p.getType(), p.getAlg())).collect(Collectors.toList()); + pubKeyCredParamsType = pubKeyCredParams.stream().map(p -> new PubKeyCredParamType(p.getType(), p.getAlg())) + .collect(Collectors.toList()); } - final List excludeCredentialsType = excludeCredentials.stream().map(c -> new ExcludeCredentialType(c.getType(), c.getId())).collect(Collectors.toList()); + final List excludeCredentialsType = excludeCredentials.stream() + .map(c -> new ExcludeCredentialType(c.getType(), c.getId())).collect(Collectors.toList()); CreateCredentialOptions createCredentialOptions = new CreateCredentialOptions( challenge, @@ -105,56 +108,70 @@ public void register( timeout, authSelectionType, attestation, - excludeCredentialsType - ); + excludeCredentialsType); try { String options = createCredentialOptions.toJSON().toString(); Activity activity = plugin.requireActivity(); CredentialManager credentialManager = CredentialManager.create(activity); - CreatePublicKeyCredentialRequest createPublicKeyCredentialRequest = new CreatePublicKeyCredentialRequest(options); + CreatePublicKeyCredentialRequest createPublicKeyCredentialRequest = new CreatePublicKeyCredentialRequest( + options); currentCancellationSignal = new CancellationSignal(); - credentialManager.createCredentialAsync(activity, createPublicKeyCredentialRequest, currentCancellationSignal, Runnable::run, new CredentialManagerCallback() { - - @Override - public void onResult(CreateCredentialResponse res) { - String resp = res.getData().getString("androidx.credentials.BUNDLE_KEY_REGISTRATION_RESPONSE_JSON"); - try { - JSONObject json = new JSONObject(resp); - JSONObject response = json.getJSONObject("response"); - result.success(new Messages.RegisterResponse.Builder().setId(json.getString("id")).setRawId(json.getString("rawId")).setClientDataJSON(response.getString("clientDataJSON")).setAttestationObject(response.getString("attestationObject")).build()); - } catch (JSONException e) { - Log.e(TAG, "Error parsing response: " + resp, e); - result.error(e); - } - } - - @Override - public void onError(CreateCredentialException e) { - Exception platformException = e; - if (Objects.equals(e.getMessage(), "Unable to create key during registration")) { - // currently, Android throws this error when users skip the fingerPrint animation => we interpret this as a cancellation for now - platformException = new Messages.FlutterError("cancelled", e.getMessage(), ""); - } else if (e instanceof CreateCredentialCancellationException) { - platformException = new Messages.FlutterError("cancelled", e.getMessage(), ""); - } else if (e instanceof CreatePublicKeyCredentialDomException) { - if (Objects.equals(e.getMessage(), "User is unable to create passkeys.")) { - platformException = new Messages.FlutterError("android-missing-google-sign-in", e.getMessage(), MISSING_GOOGLE_SIGN_IN_ERROR); - } else if (Objects.equals(e.getMessage(), "Unable to get sync account.")) { - platformException = new Messages.FlutterError("android-sync-account-not-available", e.getMessage(), SYNC_ACCOUNT_NOT_AVAILABLE_ERROR); - } else if (Objects.equals(e.getMessage(), "One of the excluded credentials exists on the local device")) { - platformException = new Messages.FlutterError("exclude-credentials-match", e.getMessage(), EXCLUDE_CREDENTIALS_MATCH_ERROR); - } else { - platformException = new Messages.FlutterError("android-unhandled: " + e.getType(), e.getMessage(), e.getErrorMessage()); + credentialManager.createCredentialAsync(activity, createPublicKeyCredentialRequest, + currentCancellationSignal, Runnable::run, + new CredentialManagerCallback() { + + @Override + public void onResult(CreateCredentialResponse res) { + String resp = res.getData() + .getString("androidx.credentials.BUNDLE_KEY_REGISTRATION_RESPONSE_JSON"); + try { + JSONObject json = new JSONObject(resp); + JSONObject response = json.getJSONObject("response"); + result.success(new Messages.RegisterResponse.Builder().setId(json.getString("id")) + .setRawId(json.getString("rawId")) + .setClientDataJSON(response.getString("clientDataJSON")) + .setAttestationObject(response.getString("attestationObject")) + .setTransports(json.getJSONArray("transports").toList()).build()); + } catch (JSONException e) { + Log.e(TAG, "Error parsing response: " + resp, e); + result.error(e); + } } - } else { - platformException = new Messages.FlutterError("android-unhandled" + e.getType(), e.getMessage(), e.getErrorMessage()); - } - result.error(platformException); - } - }); + @Override + public void onError(CreateCredentialException e) { + Exception platformException = e; + if (Objects.equals(e.getMessage(), "Unable to create key during registration")) { + // currently, Android throws this error when users skip the fingerPrint + // animation => we interpret this as a cancellation for now + platformException = new Messages.FlutterError("cancelled", e.getMessage(), ""); + } else if (e instanceof CreateCredentialCancellationException) { + platformException = new Messages.FlutterError("cancelled", e.getMessage(), ""); + } else if (e instanceof CreatePublicKeyCredentialDomException) { + if (Objects.equals(e.getMessage(), "User is unable to create passkeys.")) { + platformException = new Messages.FlutterError("android-missing-google-sign-in", + e.getMessage(), MISSING_GOOGLE_SIGN_IN_ERROR); + } else if (Objects.equals(e.getMessage(), "Unable to get sync account.")) { + platformException = new Messages.FlutterError("android-sync-account-not-available", + e.getMessage(), SYNC_ACCOUNT_NOT_AVAILABLE_ERROR); + } else if (Objects.equals(e.getMessage(), + "One of the excluded credentials exists on the local device")) { + platformException = new Messages.FlutterError("exclude-credentials-match", + e.getMessage(), EXCLUDE_CREDENTIALS_MATCH_ERROR); + } else { + platformException = new Messages.FlutterError("android-unhandled: " + e.getType(), + e.getMessage(), e.getErrorMessage()); + } + } else { + platformException = new Messages.FlutterError("android-unhandled" + e.getType(), + e.getMessage(), e.getErrorMessage()); + } + + result.error(platformException); + } + }); } catch (JSONException e) { Log.e(TAG, "Error creating JSON", e); result.error(e); @@ -162,13 +179,18 @@ public void onError(CreateCredentialException e) { } @Override - public void authenticate(@NonNull String relyingPartyId, @NonNull String challenge, @Nullable Long timeout, @Nullable String userVerification, @Nullable List allowCredentials, @NonNull Messages.Result result) { + public void authenticate(@NonNull String relyingPartyId, @NonNull String challenge, @Nullable Long timeout, + @Nullable String userVerification, @Nullable List allowCredentials, + @NonNull Messages.Result result) { List allowCredentialsType = new ArrayList<>(); if (allowCredentials != null) { - allowCredentialsType = allowCredentials.stream().map(c -> new AllowCredentialType(c.getType(), c.getId(), c.getTransports())).collect(Collectors.toList()); + allowCredentialsType = allowCredentials.stream() + .map(c -> new AllowCredentialType(c.getType(), c.getId(), c.getTransports())) + .collect(Collectors.toList()); } - GetCredentialOptions getCredentialOptions = new GetCredentialOptions(challenge, timeout, relyingPartyId, allowCredentialsType, userVerification); + GetCredentialOptions getCredentialOptions = new GetCredentialOptions(challenge, timeout, relyingPartyId, + allowCredentialsType, userVerification); try { String options = getCredentialOptions.toJSON().toString(); @@ -177,64 +199,77 @@ public void authenticate(@NonNull String relyingPartyId, @NonNull String challen CredentialManager credentialManager = CredentialManager.create(activity); GetPublicKeyCredentialOption getPublicKeyCredentialOption = new GetPublicKeyCredentialOption(options); - GetCredentialRequest getCredRequest = new GetCredentialRequest.Builder().addCredentialOption(getPublicKeyCredentialOption).build(); + GetCredentialRequest getCredRequest = new GetCredentialRequest.Builder() + .addCredentialOption(getPublicKeyCredentialOption).build(); currentCancellationSignal = new CancellationSignal(); - credentialManager.getCredentialAsync(activity, getCredRequest, currentCancellationSignal, Runnable::run, new CredentialManagerCallback() { - @Override - public void onResult(GetCredentialResponse res) { - Credential credential = res.getCredential(); - if (credential instanceof PublicKeyCredential) { - String responseJson = ((PublicKeyCredential) credential).getAuthenticationResponseJson(); - try { - final JSONObject json = new JSONObject(responseJson); - final JSONObject response = json.getJSONObject("response"); - - final String id = json.getString("id"); - final String rawId = json.getString("rawId"); - - final String clientDataJSON = response.getString("clientDataJSON"); - final String userHandle = response.getString("userHandle"); - final String signature = response.getString("signature"); - final String authenticatorData = response.getString("authenticatorData"); - - final Messages.AuthenticateResponse msg = new Messages.AuthenticateResponse.Builder().setId(id).setRawId(rawId).setClientDataJSON(clientDataJSON).setAuthenticatorData(authenticatorData).setSignature(signature).setUserHandle(userHandle).build(); - - result.success(msg); - } catch (JSONException e) { - Log.e(TAG, "Error parsing response: " + responseJson, e); - result.error(e); - } - } else { - result.error(new Exception("Credential is of type " + credential.getClass().getName() + ", but should be of type PublicKeyCredential")); - } - } - - @Override - public void onError(GetCredentialException e) { - Exception platformException = e; - Log.e(TAG, "onError called", e); - - // currently, Android throws this error when users skip the fingerPrint animation => we interpret this as a cancellation for now - if (Objects.equals(e.getMessage(), "None of the allowed credentials can be authenticated")) { - platformException = new Messages.FlutterError("cancelled", e.getMessage(), ""); - } else if (e instanceof GetCredentialCancellationException) { - platformException = new Messages.FlutterError("cancelled", e.getMessage(), ""); - } else if (e instanceof NoCredentialException) { - platformException = new Messages.FlutterError("android-no-credential", e.getMessage(), ""); - } else if (e instanceof GetPublicKeyCredentialDomException) { - if (Objects.equals(e.getMessage(), "Failed to decrypt credential.")) { - platformException = new Messages.FlutterError("android-sync-account-not-available", e.getMessage(), SYNC_ACCOUNT_NOT_AVAILABLE_ERROR); - } else { - platformException = new Messages.FlutterError("android-unhandled: " + e.getType(), e.getMessage(), e.getErrorMessage()); + credentialManager.getCredentialAsync(activity, getCredRequest, currentCancellationSignal, Runnable::run, + new CredentialManagerCallback() { + @Override + public void onResult(GetCredentialResponse res) { + Credential credential = res.getCredential(); + if (credential instanceof PublicKeyCredential) { + String responseJson = ((PublicKeyCredential) credential) + .getAuthenticationResponseJson(); + try { + final JSONObject json = new JSONObject(responseJson); + final JSONObject response = json.getJSONObject("response"); + + final String id = json.getString("id"); + final String rawId = json.getString("rawId"); + + final String clientDataJSON = response.getString("clientDataJSON"); + final String userHandle = response.getString("userHandle"); + final String signature = response.getString("signature"); + final String authenticatorData = response.getString("authenticatorData"); + + final Messages.AuthenticateResponse msg = new Messages.AuthenticateResponse.Builder() + .setId(id).setRawId(rawId).setClientDataJSON(clientDataJSON) + .setAuthenticatorData(authenticatorData).setSignature(signature) + .setUserHandle(userHandle).build(); + + result.success(msg); + } catch (JSONException e) { + Log.e(TAG, "Error parsing response: " + responseJson, e); + result.error(e); + } + } else { + result.error(new Exception("Credential is of type " + credential.getClass().getName() + + ", but should be of type PublicKeyCredential")); + } } - } else { - platformException = new Messages.FlutterError("android-unhandled: " + e.getType(), e.getMessage(), e.getErrorMessage()); - } - result.error(platformException); - } - }); + @Override + public void onError(GetCredentialException e) { + Exception platformException = e; + Log.e(TAG, "onError called", e); + + // currently, Android throws this error when users skip the fingerPrint + // animation => we interpret this as a cancellation for now + if (Objects.equals(e.getMessage(), + "None of the allowed credentials can be authenticated")) { + platformException = new Messages.FlutterError("cancelled", e.getMessage(), ""); + } else if (e instanceof GetCredentialCancellationException) { + platformException = new Messages.FlutterError("cancelled", e.getMessage(), ""); + } else if (e instanceof NoCredentialException) { + platformException = new Messages.FlutterError("android-no-credential", e.getMessage(), + ""); + } else if (e instanceof GetPublicKeyCredentialDomException) { + if (Objects.equals(e.getMessage(), "Failed to decrypt credential.")) { + platformException = new Messages.FlutterError("android-sync-account-not-available", + e.getMessage(), SYNC_ACCOUNT_NOT_AVAILABLE_ERROR); + } else { + platformException = new Messages.FlutterError("android-unhandled: " + e.getType(), + e.getMessage(), e.getErrorMessage()); + } + } else { + platformException = new Messages.FlutterError("android-unhandled: " + e.getType(), + e.getMessage(), e.getErrorMessage()); + } + + result.error(platformException); + } + }); } catch (JSONException e) { throw new RuntimeException(e); } diff --git a/packages/passkeys/passkeys_android/lib/messages.g.dart b/packages/passkeys/passkeys_android/lib/messages.g.dart index 9a0a6910..2d7bbec6 100644 --- a/packages/passkeys/passkeys_android/lib/messages.g.dart +++ b/packages/passkeys/passkeys_android/lib/messages.g.dart @@ -218,6 +218,7 @@ class RegisterResponse { required this.rawId, required this.clientDataJSON, required this.attestationObject, + required this.transports, }); /// The ID @@ -232,12 +233,16 @@ class RegisterResponse { /// The attestation object String attestationObject; + /// The supported transports for the authenticator + List transports; + Object encode() { return [ id, rawId, clientDataJSON, attestationObject, + transports, ]; } @@ -248,6 +253,7 @@ class RegisterResponse { rawId: result[1]! as String, clientDataJSON: result[2]! as String, attestationObject: result[3]! as String, + transports: result[4]! as List, ); } } @@ -340,21 +346,21 @@ class _PasskeysApiCodec extends StandardMessageCodec { @override Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { - case 128: + case 128: return AllowCredential.decode(readValue(buffer)!); - case 129: + case 129: return AuthenticateResponse.decode(readValue(buffer)!); - case 130: + case 130: return AuthenticatorSelection.decode(readValue(buffer)!); - case 131: + case 131: return ExcludeCredential.decode(readValue(buffer)!); - case 132: + case 132: return PubKeyCredParam.decode(readValue(buffer)!); - case 133: + case 133: return RegisterResponse.decode(readValue(buffer)!); - case 134: + case 134: return RelyingParty.decode(readValue(buffer)!); - case 135: + case 135: return User.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -374,10 +380,10 @@ class PasskeysApi { Future canAuthenticate() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.passkeys_android.PasskeysApi.canAuthenticate', codec, + 'dev.flutter.pigeon.passkeys_android.PasskeysApi.canAuthenticate', + codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; + final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -399,12 +405,28 @@ class PasskeysApi { } } - Future register(String arg_challenge, RelyingParty arg_relyingParty, User arg_user, AuthenticatorSelection arg_authenticatorSelection, List? arg_pubKeyCredParams, int? arg_timeout, String? arg_attestation, List arg_excludeCredentials) async { + Future register( + String arg_challenge, + RelyingParty arg_relyingParty, + User arg_user, + AuthenticatorSelection arg_authenticatorSelection, + List? arg_pubKeyCredParams, + int? arg_timeout, + String? arg_attestation, + List arg_excludeCredentials) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_android.PasskeysApi.register', codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_challenge, arg_relyingParty, arg_user, arg_authenticatorSelection, arg_pubKeyCredParams, arg_timeout, arg_attestation, arg_excludeCredentials]) as List?; + final List? replyList = await channel.send([ + arg_challenge, + arg_relyingParty, + arg_user, + arg_authenticatorSelection, + arg_pubKeyCredParams, + arg_timeout, + arg_attestation, + arg_excludeCredentials + ]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -426,12 +448,22 @@ class PasskeysApi { } } - Future authenticate(String arg_relyingPartyId, String arg_challenge, int? arg_timeout, String? arg_userVerification, List? arg_allowCredentials) async { + Future authenticate( + String arg_relyingPartyId, + String arg_challenge, + int? arg_timeout, + String? arg_userVerification, + List? arg_allowCredentials) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_android.PasskeysApi.authenticate', codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_relyingPartyId, arg_challenge, arg_timeout, arg_userVerification, arg_allowCredentials]) as List?; + final List? replyList = await channel.send([ + arg_relyingPartyId, + arg_challenge, + arg_timeout, + arg_userVerification, + arg_allowCredentials + ]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -455,10 +487,10 @@ class PasskeysApi { Future cancelCurrentAuthenticatorOperation() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.passkeys_android.PasskeysApi.cancelCurrentAuthenticatorOperation', codec, + 'dev.flutter.pigeon.passkeys_android.PasskeysApi.cancelCurrentAuthenticatorOperation', + codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; + final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/packages/passkeys/passkeys_android/lib/passkeys_android.dart b/packages/passkeys/passkeys_android/lib/passkeys_android.dart index f17545d1..ed214d38 100644 --- a/packages/passkeys/passkeys_android/lib/passkeys_android.dart +++ b/packages/passkeys/passkeys_android/lib/passkeys_android.dart @@ -87,6 +87,7 @@ class PasskeysAndroid extends PasskeysPlatform { rawId: r.rawId, clientDataJSON: r.clientDataJSON, attestationObject: r.attestationObject, + transports: r.transports, ); } diff --git a/packages/passkeys/passkeys_android/pigeons/messages.dart b/packages/passkeys/passkeys_android/pigeons/messages.dart index 70e68f09..5f598a31 100644 --- a/packages/passkeys/passkeys_android/pigeons/messages.dart +++ b/packages/passkeys/passkeys_android/pigeons/messages.dart @@ -104,6 +104,7 @@ class RegisterResponse { required this.rawId, required this.clientDataJSON, required this.attestationObject, + required this.transports, }); /// The ID @@ -117,6 +118,9 @@ class RegisterResponse { /// The attestation object final String attestationObject; + + /// The supported transports for the authenticator + final List transports; } /// Represents an authenticate response diff --git a/packages/passkeys/passkeys_ios/ios/Classes/messages.swift b/packages/passkeys/passkeys_ios/ios/Classes/messages.swift index 6c2c9da8..40a2a75f 100644 --- a/packages/passkeys/passkeys_ios/ios/Classes/messages.swift +++ b/packages/passkeys/passkeys_ios/ios/Classes/messages.swift @@ -102,18 +102,22 @@ struct RegisterResponse { var clientDataJSON: String /// The attestation object var attestationObject: String + /// The supported transports for the authenticator + var transports: [String] static func fromList(_ list: [Any?]) -> RegisterResponse? { let id = list[0] as! String let rawId = list[1] as! String let clientDataJSON = list[2] as! String let attestationObject = list[3] as! String + let transports = list[3] as! [String] return RegisterResponse( id: id, rawId: rawId, clientDataJSON: clientDataJSON, - attestationObject: attestationObject + attestationObject: attestationObject, + transports: transports ) } func toList() -> [Any?] { @@ -122,6 +126,7 @@ struct RegisterResponse { rawId, clientDataJSON, attestationObject, + transports, ] } } diff --git a/packages/passkeys/passkeys_ios/lib/messages.g.dart b/packages/passkeys/passkeys_ios/lib/messages.g.dart index 8cea8da0..a633be17 100644 --- a/packages/passkeys/passkeys_ios/lib/messages.g.dart +++ b/packages/passkeys/passkeys_ios/lib/messages.g.dart @@ -73,6 +73,7 @@ class RegisterResponse { required this.rawId, required this.clientDataJSON, required this.attestationObject, + required this.transports, }); /// The ID @@ -87,12 +88,16 @@ class RegisterResponse { /// The attestation object String attestationObject; + /// The supported transports for the authenticator + List transports; + Object encode() { return [ id, rawId, clientDataJSON, attestationObject, + transports, ]; } @@ -103,6 +108,7 @@ class RegisterResponse { rawId: result[1]! as String, clientDataJSON: result[2]! as String, attestationObject: result[3]! as String, + transports: result[4]! as List, ); } } @@ -183,13 +189,13 @@ class _PasskeysApiCodec extends StandardMessageCodec { @override Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { - case 128: + case 128: return AuthenticateResponse.decode(readValue(buffer)!); - case 129: + case 129: return RegisterResponse.decode(readValue(buffer)!); - case 130: + case 130: return RelyingParty.decode(readValue(buffer)!); - case 131: + case 131: return User.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -211,8 +217,7 @@ class PasskeysApi { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.canAuthenticate', codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; + final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -234,12 +239,20 @@ class PasskeysApi { } } - Future register(String arg_challenge, RelyingParty arg_relyingParty, User arg_user, List arg_excludeCredentialIDs) async { + Future register( + String arg_challenge, + RelyingParty arg_relyingParty, + User arg_user, + List arg_excludeCredentialIDs) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.register', codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_challenge, arg_relyingParty, arg_user, arg_excludeCredentialIDs]) as List?; + final List? replyList = await channel.send([ + arg_challenge, + arg_relyingParty, + arg_user, + arg_excludeCredentialIDs + ]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -261,12 +274,22 @@ class PasskeysApi { } } - Future authenticate(String arg_relyingPartyId, String arg_challenge, bool arg_conditionalUI, List arg_allowedCredentialIDs, bool arg_preferImmediatelyAvailableCredentials) async { + Future authenticate( + String arg_relyingPartyId, + String arg_challenge, + bool arg_conditionalUI, + List arg_allowedCredentialIDs, + bool arg_preferImmediatelyAvailableCredentials) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.authenticate', codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_relyingPartyId, arg_challenge, arg_conditionalUI, arg_allowedCredentialIDs, arg_preferImmediatelyAvailableCredentials]) as List?; + final List? replyList = await channel.send([ + arg_relyingPartyId, + arg_challenge, + arg_conditionalUI, + arg_allowedCredentialIDs, + arg_preferImmediatelyAvailableCredentials + ]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -290,10 +313,10 @@ class PasskeysApi { Future cancelCurrentAuthenticatorOperation() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.cancelCurrentAuthenticatorOperation', codec, + 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.cancelCurrentAuthenticatorOperation', + codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; + final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/packages/passkeys/passkeys_ios/lib/passkeys_ios.dart b/packages/passkeys/passkeys_ios/lib/passkeys_ios.dart index 852c5f81..0fddd0a9 100644 --- a/packages/passkeys/passkeys_ios/lib/passkeys_ios.dart +++ b/packages/passkeys/passkeys_ios/lib/passkeys_ios.dart @@ -40,6 +40,7 @@ class PasskeysIOS extends PasskeysPlatform { rawId: r.rawId, clientDataJSON: r.clientDataJSON, attestationObject: r.attestationObject, + transports: r.transports, ); } diff --git a/packages/passkeys/passkeys_ios/pigeons/messages.dart b/packages/passkeys/passkeys_ios/pigeons/messages.dart index ac5b21ef..bf41c015 100644 --- a/packages/passkeys/passkeys_ios/pigeons/messages.dart +++ b/packages/passkeys/passkeys_ios/pigeons/messages.dart @@ -38,6 +38,7 @@ class RegisterResponse { required this.rawId, required this.clientDataJSON, required this.attestationObject, + required this.transports, }); /// The ID @@ -51,6 +52,9 @@ class RegisterResponse { /// The attestation object final String attestationObject; + + /// The supported transports for the authenticator + final List transports; } /// Represents an authenticate response From 76fae05e3cb8f929be0c64dcc758fe4d608b52f0 Mon Sep 17 00:00:00 2001 From: Oppiie Date: Mon, 14 Oct 2024 13:13:31 -0400 Subject: [PATCH 4/4] PR feedback fixes --- .../passkeys_android/MessageHandler.java | 13 +++- .../corbado/passkeys_android/Messages.java | 27 ++++++- .../passkeys_android/lib/messages.g.dart | 70 ++++++------------- .../lib/passkeys_android.dart | 2 +- .../passkeys_android/pigeons/messages.dart | 2 +- .../ios/Classes/RegisterController.swift | 3 +- .../passkeys_ios/ios/Classes/messages.swift | 4 +- .../passkeys/passkeys_ios/lib/messages.g.dart | 51 +++++--------- .../passkeys_ios/lib/passkeys_ios.dart | 2 +- .../passkeys_ios/pigeons/messages.dart | 2 +- .../lib/types/register_response.dart | 2 +- 11 files changed, 85 insertions(+), 93 deletions(-) diff --git a/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/MessageHandler.java b/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/MessageHandler.java index afb1ec76..01a9790f 100644 --- a/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/MessageHandler.java +++ b/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/MessageHandler.java @@ -129,11 +129,20 @@ public void onResult(CreateCredentialResponse res) { try { JSONObject json = new JSONObject(resp); JSONObject response = json.getJSONObject("response"); - result.success(new Messages.RegisterResponse.Builder().setId(json.getString("id")) + + List typedTransports = new ArrayList<>(); + JSONArray transports = response.getJSONArray("transports"); + for (int i = 0; i < transports.length(); i++) { + typedTransports.add(transports.getString(i)); + } + + result.success(new Messages.RegisterResponse.Builder() + .setId(json.getString("id")) .setRawId(json.getString("rawId")) .setClientDataJSON(response.getString("clientDataJSON")) .setAttestationObject(response.getString("attestationObject")) - .setTransports(json.getJSONArray("transports").toList()).build()); + .setTransports(typedTransports) + .build()); } catch (JSONException e) { Log.e(TAG, "Error parsing response: " + resp, e); result.error(e); diff --git a/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/Messages.java b/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/Messages.java index f77bc644..adb44904 100644 --- a/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/Messages.java +++ b/packages/passkeys/passkeys_android/android/src/main/java/com/corbado/passkeys_android/Messages.java @@ -708,6 +708,20 @@ public void setAttestationObject(@NonNull String setterArg) { this.attestationObject = setterArg; } + /** The supported transports for the authenticator */ + private @NonNull List transports; + + public @NonNull List getTransports() { + return transports; + } + + public void setTransports(@NonNull List setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"transports\" is null."); + } + this.transports = setterArg; + } + /** Constructor is non-public to enforce null safety; use Builder. */ RegisterResponse() {} @@ -741,23 +755,32 @@ public static final class Builder { return this; } + private @Nullable List transports; + + public @NonNull Builder setTransports(@NonNull List setterArg) { + this.transports = setterArg; + return this; + } + public @NonNull RegisterResponse build() { RegisterResponse pigeonReturn = new RegisterResponse(); pigeonReturn.setId(id); pigeonReturn.setRawId(rawId); pigeonReturn.setClientDataJSON(clientDataJSON); pigeonReturn.setAttestationObject(attestationObject); + pigeonReturn.setTransports(transports); return pigeonReturn; } } @NonNull ArrayList toList() { - ArrayList toListResult = new ArrayList(4); + ArrayList toListResult = new ArrayList(5); toListResult.add(id); toListResult.add(rawId); toListResult.add(clientDataJSON); toListResult.add(attestationObject); + toListResult.add(transports); return toListResult; } @@ -771,6 +794,8 @@ ArrayList toList() { pigeonResult.setClientDataJSON((String) clientDataJSON); Object attestationObject = list.get(3); pigeonResult.setAttestationObject((String) attestationObject); + Object transports = list.get(4); + pigeonResult.setTransports((List) transports); return pigeonResult; } } diff --git a/packages/passkeys/passkeys_android/lib/messages.g.dart b/packages/passkeys/passkeys_android/lib/messages.g.dart index 2d7bbec6..5128fb61 100644 --- a/packages/passkeys/passkeys_android/lib/messages.g.dart +++ b/packages/passkeys/passkeys_android/lib/messages.g.dart @@ -234,7 +234,7 @@ class RegisterResponse { String attestationObject; /// The supported transports for the authenticator - List transports; + List transports; Object encode() { return [ @@ -253,7 +253,7 @@ class RegisterResponse { rawId: result[1]! as String, clientDataJSON: result[2]! as String, attestationObject: result[3]! as String, - transports: result[4]! as List, + transports: (result[4] as List?)!.cast(), ); } } @@ -346,21 +346,21 @@ class _PasskeysApiCodec extends StandardMessageCodec { @override Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { - case 128: + case 128: return AllowCredential.decode(readValue(buffer)!); - case 129: + case 129: return AuthenticateResponse.decode(readValue(buffer)!); - case 130: + case 130: return AuthenticatorSelection.decode(readValue(buffer)!); - case 131: + case 131: return ExcludeCredential.decode(readValue(buffer)!); - case 132: + case 132: return PubKeyCredParam.decode(readValue(buffer)!); - case 133: + case 133: return RegisterResponse.decode(readValue(buffer)!); - case 134: + case 134: return RelyingParty.decode(readValue(buffer)!); - case 135: + case 135: return User.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -380,10 +380,10 @@ class PasskeysApi { Future canAuthenticate() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.passkeys_android.PasskeysApi.canAuthenticate', - codec, + 'dev.flutter.pigeon.passkeys_android.PasskeysApi.canAuthenticate', codec, binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send(null) as List?; + final List? replyList = + await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -405,28 +405,12 @@ class PasskeysApi { } } - Future register( - String arg_challenge, - RelyingParty arg_relyingParty, - User arg_user, - AuthenticatorSelection arg_authenticatorSelection, - List? arg_pubKeyCredParams, - int? arg_timeout, - String? arg_attestation, - List arg_excludeCredentials) async { + Future register(String arg_challenge, RelyingParty arg_relyingParty, User arg_user, AuthenticatorSelection arg_authenticatorSelection, List? arg_pubKeyCredParams, int? arg_timeout, String? arg_attestation, List arg_excludeCredentials) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_android.PasskeysApi.register', codec, binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send([ - arg_challenge, - arg_relyingParty, - arg_user, - arg_authenticatorSelection, - arg_pubKeyCredParams, - arg_timeout, - arg_attestation, - arg_excludeCredentials - ]) as List?; + final List? replyList = + await channel.send([arg_challenge, arg_relyingParty, arg_user, arg_authenticatorSelection, arg_pubKeyCredParams, arg_timeout, arg_attestation, arg_excludeCredentials]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -448,22 +432,12 @@ class PasskeysApi { } } - Future authenticate( - String arg_relyingPartyId, - String arg_challenge, - int? arg_timeout, - String? arg_userVerification, - List? arg_allowCredentials) async { + Future authenticate(String arg_relyingPartyId, String arg_challenge, int? arg_timeout, String? arg_userVerification, List? arg_allowCredentials) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_android.PasskeysApi.authenticate', codec, binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send([ - arg_relyingPartyId, - arg_challenge, - arg_timeout, - arg_userVerification, - arg_allowCredentials - ]) as List?; + final List? replyList = + await channel.send([arg_relyingPartyId, arg_challenge, arg_timeout, arg_userVerification, arg_allowCredentials]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -487,10 +461,10 @@ class PasskeysApi { Future cancelCurrentAuthenticatorOperation() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.passkeys_android.PasskeysApi.cancelCurrentAuthenticatorOperation', - codec, + 'dev.flutter.pigeon.passkeys_android.PasskeysApi.cancelCurrentAuthenticatorOperation', codec, binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send(null) as List?; + final List? replyList = + await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/packages/passkeys/passkeys_android/lib/passkeys_android.dart b/packages/passkeys/passkeys_android/lib/passkeys_android.dart index ed214d38..a55ae405 100644 --- a/packages/passkeys/passkeys_android/lib/passkeys_android.dart +++ b/packages/passkeys/passkeys_android/lib/passkeys_android.dart @@ -87,7 +87,7 @@ class PasskeysAndroid extends PasskeysPlatform { rawId: r.rawId, clientDataJSON: r.clientDataJSON, attestationObject: r.attestationObject, - transports: r.transports, + transports: r.transports.whereType().toList(), ); } diff --git a/packages/passkeys/passkeys_android/pigeons/messages.dart b/packages/passkeys/passkeys_android/pigeons/messages.dart index 5f598a31..18bf0b0a 100644 --- a/packages/passkeys/passkeys_android/pigeons/messages.dart +++ b/packages/passkeys/passkeys_android/pigeons/messages.dart @@ -120,7 +120,7 @@ class RegisterResponse { final String attestationObject; /// The supported transports for the authenticator - final List transports; + final List transports; } /// Represents an authenticate response diff --git a/packages/passkeys/passkeys_ios/ios/Classes/RegisterController.swift b/packages/passkeys/passkeys_ios/ios/Classes/RegisterController.swift index 9400d45c..ed41ff20 100644 --- a/packages/passkeys/passkeys_ios/ios/Classes/RegisterController.swift +++ b/packages/passkeys/passkeys_ios/ios/Classes/RegisterController.swift @@ -34,7 +34,8 @@ class RegisterController: NSObject, ASAuthorizationControllerDelegate, ASAuthori id: credentialRegistration.credentialID.toBase64URL(), rawId: credentialRegistration.credentialID.toBase64URL(), clientDataJSON: credentialRegistration.rawClientDataJSON.toBase64URL(), - attestationObject: credentialRegistration.rawAttestationObject!.toBase64URL() + attestationObject: credentialRegistration.rawAttestationObject!.toBase64URL(), + transports: credentialRegistration.transports ) completion?(.success(response)) break diff --git a/packages/passkeys/passkeys_ios/ios/Classes/messages.swift b/packages/passkeys/passkeys_ios/ios/Classes/messages.swift index 40a2a75f..3ccba475 100644 --- a/packages/passkeys/passkeys_ios/ios/Classes/messages.swift +++ b/packages/passkeys/passkeys_ios/ios/Classes/messages.swift @@ -103,14 +103,14 @@ struct RegisterResponse { /// The attestation object var attestationObject: String /// The supported transports for the authenticator - var transports: [String] + var transports: [String?] static func fromList(_ list: [Any?]) -> RegisterResponse? { let id = list[0] as! String let rawId = list[1] as! String let clientDataJSON = list[2] as! String let attestationObject = list[3] as! String - let transports = list[3] as! [String] + let transports = list[4] as! [String?] return RegisterResponse( id: id, diff --git a/packages/passkeys/passkeys_ios/lib/messages.g.dart b/packages/passkeys/passkeys_ios/lib/messages.g.dart index a633be17..7ae5af2b 100644 --- a/packages/passkeys/passkeys_ios/lib/messages.g.dart +++ b/packages/passkeys/passkeys_ios/lib/messages.g.dart @@ -89,7 +89,7 @@ class RegisterResponse { String attestationObject; /// The supported transports for the authenticator - List transports; + List transports; Object encode() { return [ @@ -108,7 +108,7 @@ class RegisterResponse { rawId: result[1]! as String, clientDataJSON: result[2]! as String, attestationObject: result[3]! as String, - transports: result[4]! as List, + transports: (result[4] as List?)!.cast(), ); } } @@ -189,13 +189,13 @@ class _PasskeysApiCodec extends StandardMessageCodec { @override Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { - case 128: + case 128: return AuthenticateResponse.decode(readValue(buffer)!); - case 129: + case 129: return RegisterResponse.decode(readValue(buffer)!); - case 130: + case 130: return RelyingParty.decode(readValue(buffer)!); - case 131: + case 131: return User.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -217,7 +217,8 @@ class PasskeysApi { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.canAuthenticate', codec, binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send(null) as List?; + final List? replyList = + await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -239,20 +240,12 @@ class PasskeysApi { } } - Future register( - String arg_challenge, - RelyingParty arg_relyingParty, - User arg_user, - List arg_excludeCredentialIDs) async { + Future register(String arg_challenge, RelyingParty arg_relyingParty, User arg_user, List arg_excludeCredentialIDs) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.register', codec, binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send([ - arg_challenge, - arg_relyingParty, - arg_user, - arg_excludeCredentialIDs - ]) as List?; + final List? replyList = + await channel.send([arg_challenge, arg_relyingParty, arg_user, arg_excludeCredentialIDs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -274,22 +267,12 @@ class PasskeysApi { } } - Future authenticate( - String arg_relyingPartyId, - String arg_challenge, - bool arg_conditionalUI, - List arg_allowedCredentialIDs, - bool arg_preferImmediatelyAvailableCredentials) async { + Future authenticate(String arg_relyingPartyId, String arg_challenge, bool arg_conditionalUI, List arg_allowedCredentialIDs, bool arg_preferImmediatelyAvailableCredentials) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.authenticate', codec, binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send([ - arg_relyingPartyId, - arg_challenge, - arg_conditionalUI, - arg_allowedCredentialIDs, - arg_preferImmediatelyAvailableCredentials - ]) as List?; + final List? replyList = + await channel.send([arg_relyingPartyId, arg_challenge, arg_conditionalUI, arg_allowedCredentialIDs, arg_preferImmediatelyAvailableCredentials]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -313,10 +296,10 @@ class PasskeysApi { Future cancelCurrentAuthenticatorOperation() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.cancelCurrentAuthenticatorOperation', - codec, + 'dev.flutter.pigeon.passkeys_ios.PasskeysApi.cancelCurrentAuthenticatorOperation', codec, binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send(null) as List?; + final List? replyList = + await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/packages/passkeys/passkeys_ios/lib/passkeys_ios.dart b/packages/passkeys/passkeys_ios/lib/passkeys_ios.dart index 0fddd0a9..e847720b 100644 --- a/packages/passkeys/passkeys_ios/lib/passkeys_ios.dart +++ b/packages/passkeys/passkeys_ios/lib/passkeys_ios.dart @@ -40,7 +40,7 @@ class PasskeysIOS extends PasskeysPlatform { rawId: r.rawId, clientDataJSON: r.clientDataJSON, attestationObject: r.attestationObject, - transports: r.transports, + transports: r.transports.whereType().toList(), ); } diff --git a/packages/passkeys/passkeys_ios/pigeons/messages.dart b/packages/passkeys/passkeys_ios/pigeons/messages.dart index bf41c015..7d229d3f 100644 --- a/packages/passkeys/passkeys_ios/pigeons/messages.dart +++ b/packages/passkeys/passkeys_ios/pigeons/messages.dart @@ -54,7 +54,7 @@ class RegisterResponse { final String attestationObject; /// The supported transports for the authenticator - final List transports; + final List transports; } /// Represents an authenticate response diff --git a/packages/passkeys/passkeys_platform_interface/lib/types/register_response.dart b/packages/passkeys/passkeys_platform_interface/lib/types/register_response.dart index e4902896..e15cbce2 100644 --- a/packages/passkeys/passkeys_platform_interface/lib/types/register_response.dart +++ b/packages/passkeys/passkeys_platform_interface/lib/types/register_response.dart @@ -11,5 +11,5 @@ class RegisterResponseType { final String rawId; final String clientDataJSON; final String attestationObject; - final List transports; + final List transports; }