From 2a79877d898bd0a46d837605e20bdc1e4fb11b17 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 18 Dec 2024 13:51:59 +0545 Subject: [PATCH 01/36] feat: Wording of error message update for invalid_grant #3205 --- .../response_string/response_string.dart | 1 + .../response_string_extension.dart | 3 +++ .../helper_functions/helper_functions.dart | 1 + .../message_handler/global_message.dart | 2 ++ .../message_handler/response_message.dart | 5 ++++ lib/l10n/arb/app_en.arb | 3 ++- lib/l10n/arb/app_fr.arb | 3 ++- lib/l10n/untranslated.json | 6 +++-- lib/oidc4vc/get_credential.dart | 24 +++++++++---------- 9 files changed, 32 insertions(+), 16 deletions(-) diff --git a/lib/app/shared/enum/message/response_string/response_string.dart b/lib/app/shared/enum/message/response_string/response_string.dart index acae3068b..b04b88ac6 100644 --- a/lib/app/shared/enum/message/response_string/response_string.dart +++ b/lib/app/shared/enum/message/response_string/response_string.dart @@ -163,4 +163,5 @@ enum ResponseString { RESPONSE_STRING_vpFormatsNotSupportedErrorDescription, RESPONSE_STRING_invalidPresentationDefinitionUriErrorDescription, RESPONSE_STRING_recoveryPhraseIncorrectErrorMessage, + RESPONSE_STRING_invalidCode, } diff --git a/lib/app/shared/enum/message/response_string/response_string_extension.dart b/lib/app/shared/enum/message/response_string/response_string_extension.dart index b4c43abe2..77051c7a9 100644 --- a/lib/app/shared/enum/message/response_string/response_string_extension.dart +++ b/lib/app/shared/enum/message/response_string/response_string_extension.dart @@ -522,6 +522,9 @@ extension ResponseStringX on ResponseString { case ResponseString.RESPONSE_STRING_recoveryPhraseIncorrectErrorMessage: return globalMessage .RESPONSE_STRING_recoveryPhraseIncorrectErrorMessage; + + case ResponseString.RESPONSE_STRING_invalidCode: + return globalMessage.RESPONSE_STRING_invalidCode; } } } diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index 7f02fdb75..a2b79e61d 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -1349,6 +1349,7 @@ ResponseString getErrorResponseString(String errorString) { return ResponseString.RESPONSE_STRING_theWalletIsNotRegistered; case 'invalid_grant': + return ResponseString.RESPONSE_STRING_invalidCode; case 'invalid_token': return ResponseString.RESPONSE_STRING_credentialIssuanceDenied; diff --git a/lib/app/shared/message_handler/global_message.dart b/lib/app/shared/message_handler/global_message.dart index b9d6d1df2..c3ca61ded 100644 --- a/lib/app/shared/message_handler/global_message.dart +++ b/lib/app/shared/message_handler/global_message.dart @@ -401,4 +401,6 @@ class GlobalMessage { String get RESPONSE_STRING_recoveryPhraseIncorrectErrorMessage => l10n.recoveryPhraseIncorrectErrorMessage; + + String get RESPONSE_STRING_invalidCode => l10n.invalidCode; } diff --git a/lib/app/shared/message_handler/response_message.dart b/lib/app/shared/message_handler/response_message.dart index 73e911557..23422bf7b 100644 --- a/lib/app/shared/message_handler/response_message.dart +++ b/lib/app/shared/message_handler/response_message.dart @@ -803,6 +803,11 @@ class ResponseMessage with MessageHandler { .RESPONSE_STRING_recoveryPhraseIncorrectErrorMessage.localise( context, ); + + case ResponseString.RESPONSE_STRING_invalidCode: + return ResponseString.RESPONSE_STRING_invalidCode.localise( + context, + ); } } return ''; diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 97b4c7fe8..308c084fc 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1173,5 +1173,6 @@ "reject": "Reject", "operation": "Operation", "chooseYourSSIProfileOrCustomizeYourOwn": "Choose your wallet profile or customize your own", - "recoveryPhraseIncorrectErrorMessage": " Please try again with correct order." + "recoveryPhraseIncorrectErrorMessage": " Please try again with correct order.", + "invalidCode": "Invalid code" } diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index 7bc138383..b4a9040d0 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -1139,5 +1139,6 @@ }, "reject": "Rejet", "operation": "Opération", - "chooseYourSSIProfileOrCustomizeYourOwn": "Choisissez un écosystème pour votre wallet" + "chooseYourSSIProfileOrCustomizeYourOwn": "Choisissez un écosystème pour votre wallet", + "invalidCode": "Code invalide" } \ No newline at end of file diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index bfc550ae5..793327351 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -7,7 +7,8 @@ "reject", "operation", "chooseYourSSIProfileOrCustomizeYourOwn", - "recoveryPhraseIncorrectErrorMessage" + "recoveryPhraseIncorrectErrorMessage", + "invalidCode" ], "es": [ @@ -18,7 +19,8 @@ "reject", "operation", "chooseYourSSIProfileOrCustomizeYourOwn", - "recoveryPhraseIncorrectErrorMessage" + "recoveryPhraseIncorrectErrorMessage", + "invalidCode" ], "fr": [ diff --git a/lib/oidc4vc/get_credential.dart b/lib/oidc4vc/get_credential.dart index beef14d6e..508192016 100644 --- a/lib/oidc4vc/get_credential.dart +++ b/lib/oidc4vc/get_credential.dart @@ -125,19 +125,19 @@ Future< return null; } } -dynamic credentialResponseDataValue; - try { - credentialResponseDataValue = await getSingleCredentialData( - profileCubit: profileCubit, - openIdConfiguration: openIdConfiguration, - accessToken: accessToken, - dio: Dio(), - credentialData: credentialData, - publicKeyForDPop: publicKeyForDPop, + dynamic credentialResponseDataValue; + try { + credentialResponseDataValue = await getSingleCredentialData( + profileCubit: profileCubit, + openIdConfiguration: openIdConfiguration, + accessToken: accessToken, + dio: Dio(), + credentialData: credentialData, + publicKeyForDPop: publicKeyForDPop, ); -} catch (e) { - rethrow; -} + } catch (e) { + rethrow; + } /// update nonce value if (credentialResponseDataValue is Map) { From 9f9ec2a5569cabf84fcaf05322507a9255af6166 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 18 Dec 2024 14:05:45 +0545 Subject: [PATCH 02/36] feat: Update wording #3198 --- .../drawer/ssi/oidc4vc_settngs/widget/client_type_widget.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_type_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_type_widget.dart index 97a96b3a5..613b2acf2 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_type_widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_type_widget.dart @@ -13,7 +13,7 @@ class ClientTypeWidget extends StatelessWidget { return BlocBuilder( builder: (context, state) { return OptionContainer( - title: 'Wallet Client_id Scheme', + title: 'OIDC4VCI client_id value', body: ListView.builder( itemCount: ClientType.values.length, shrinkWrap: true, From 3a0aac60bff6636d4bf43cb3fd47c26cba96bf2d Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 18 Dec 2024 14:09:22 +0545 Subject: [PATCH 03/36] feat: Update wording #3199 --- .../ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart | 2 +- .../ssi/oidc4vc_settngs/widget/did_key_type_widget.dart | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart index 9fafad65c..bdb9295b9 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart @@ -36,7 +36,7 @@ class Oidc4vcSettingMenuView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SecurityLevelWidget(), - const DidKeyTypeWidget(), + const KeyIdentifierAndKeyTypeWidget(), const DraftTypeWidget(), const CryptographicHolderBindingWidget(), const ScopeParameterWidget(), diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/did_key_type_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/did_key_type_widget.dart index 4125d8863..34b9d9644 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/did_key_type_widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/did_key_type_widget.dart @@ -5,16 +5,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:oidc4vc/oidc4vc.dart'; -class DidKeyTypeWidget extends StatelessWidget { - const DidKeyTypeWidget({super.key}); +class KeyIdentifierAndKeyTypeWidget extends StatelessWidget { + const KeyIdentifierAndKeyTypeWidget({super.key}); @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { return OptionContainer( - title: 'Default DID', - subtitle: 'Select one of the DIDs', + title: 'Key identifier and key type', + subtitle: 'Select jwk thumbprint or a DID method', body: ListView.builder( itemCount: DidKeyType.values.length, shrinkWrap: true, From 33344cc2c0975f48357034f97c16e8f30b71c54c Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 18 Dec 2024 14:16:16 +0545 Subject: [PATCH 04/36] feat: Setup draft 13 for custom #3203 --- lib/dashboard/profile/models/profile_setting.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index 56fbbd9fe..6b8c7021e 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -717,7 +717,7 @@ class CustomOidc4VcProfile extends Equatable { credentialManifestSupport: false, cryptoHolderBinding: true, defaultDid: DidKeyType.edDSA, - oidc4vciDraft: OIDC4VCIDraftType.draft11, + oidc4vciDraft: OIDC4VCIDraftType.draft13, oidc4vpDraft: OIDC4VPDraftType.draft18, scope: false, securityLevel: false, From ab78971cae027e245e80984b09f0e8fe92730a47 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 18 Dec 2024 17:25:36 +0545 Subject: [PATCH 05/36] feat: Remove alg and use from headers of jwt #3202 --- packages/oidc4vc/lib/src/oidc4vc.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index c18061dc5..ddf7cc03a 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -1649,7 +1649,9 @@ class OIDC4VC { case ProofHeaderType.jwk: vpBuilder.setProtectedHeader( 'jwk', - tokenParameters.publicJWK, + tokenParameters.publicJWK + ..removeWhere((key, value) => key == 'use') + ..removeWhere((key, value) => key == 'alg'), ); } } From 92d8d82123207285f7923666be51daed7d19c18b Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 18 Dec 2024 17:35:40 +0545 Subject: [PATCH 06/36] version update: 2.18.14+5587 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index f6d295aab..adc615465 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: altme description: AltMe Flutter App -version: 2.18.13+5586 +version: 2.18.14+5587 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: From 40a61b2d1c1ce46f57aa22b36360f22b64a1803e Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 19 Dec 2024 16:23:56 +0545 Subject: [PATCH 07/36] feat: Update french translation #3206 --- lib/l10n/arb/app_en.arb | 2 +- lib/l10n/arb/app_fr.arb | 6 ++++-- lib/l10n/untranslated.json | 4 ---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 308c084fc..def351618 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1173,6 +1173,6 @@ "reject": "Reject", "operation": "Operation", "chooseYourSSIProfileOrCustomizeYourOwn": "Choose your wallet profile or customize your own", - "recoveryPhraseIncorrectErrorMessage": " Please try again with correct order.", + "recoveryPhraseIncorrectErrorMessage": "Please try again with correct order.", "invalidCode": "Invalid code" } diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index b4a9040d0..07687839f 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -1109,8 +1109,8 @@ "restoreACryptoWallet": "Restaurer un wallet crypto", "restoreAnAppBackup": "Restaurer une sauvegarde de {appName}", "credentialPickShare": "Partagez", - "credentialPickTitle": "Choisissez la ou les attestation(s) que vous souhaitez obtenir", - "credentialShareTitle": "Choisissez la ou les attestation(s) à partager", + "credentialPickTitle": "Choisissez une ou plusieurs attestation(s)", + "credentialShareTitle": "Choisissez une ou plusieurs attestation(s)", "enterYourSecretCode": "Entrez votre code secret.", "jwk": "JWK", "typeYourPINCodeToOpenTheWallet": "Entrez votre code PIN pour ouvrir le wallet", @@ -1140,5 +1140,7 @@ "reject": "Rejet", "operation": "Opération", "chooseYourSSIProfileOrCustomizeYourOwn": "Choisissez un écosystème pour votre wallet", + "recoveryPhraseIncorrectErrorMessage": "Veuillez recommencer dans le bon ordre.", "invalidCode": "Code invalide" + } \ No newline at end of file diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index 793327351..7fe7715e2 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -21,9 +21,5 @@ "chooseYourSSIProfileOrCustomizeYourOwn", "recoveryPhraseIncorrectErrorMessage", "invalidCode" - ], - - "fr": [ - "recoveryPhraseIncorrectErrorMessage" ] } From dcf01f4cd6edd9b5ea7a4eb08f7ae40d82d477bd Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 19 Dec 2024 16:26:06 +0545 Subject: [PATCH 08/36] feat: Add switch for OIDC4VP #3159 --- .../view/oidc4vc_settings_menu.dart | 3 +- ...et.dart => oidc4vc_draft_type_widget.dart} | 4 +- .../widget/oidc4vp_draft_type_widget.dart | 65 +++++++++++++++++++ .../ssi/oidc4vc_settngs/widget/widget.dart | 3 +- .../profile/cubit/profile_cubit.dart | 2 + .../profile/models/profile_setting.dart | 2 +- .../profile/models/profile_setting.g.dart | 3 + .../oidc4vc/lib/src/oidc4vp_draft_type.dart | 12 ++++ 8 files changed, 89 insertions(+), 5 deletions(-) rename lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/{draft_type_widget.dart => oidc4vc_draft_type_widget.dart} (95%) create mode 100644 lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vp_draft_type_widget.dart diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart index bdb9295b9..056d5edd7 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart @@ -37,7 +37,8 @@ class Oidc4vcSettingMenuView extends StatelessWidget { children: [ const SecurityLevelWidget(), const KeyIdentifierAndKeyTypeWidget(), - const DraftTypeWidget(), + const OIDC4VCDraftTypeWidget(), + const OIDC4VPDraftTypeWidget(), const CryptographicHolderBindingWidget(), const ScopeParameterWidget(), const ClientAuthenticationWidget(), diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/draft_type_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vc_draft_type_widget.dart similarity index 95% rename from lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/draft_type_widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vc_draft_type_widget.dart index 349ed25ae..3e512e9d8 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/draft_type_widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vc_draft_type_widget.dart @@ -5,8 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:oidc4vc/oidc4vc.dart'; -class DraftTypeWidget extends StatelessWidget { - const DraftTypeWidget({super.key}); +class OIDC4VCDraftTypeWidget extends StatelessWidget { + const OIDC4VCDraftTypeWidget({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vp_draft_type_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vp_draft_type_widget.dart new file mode 100644 index 000000000..692988f2c --- /dev/null +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vp_draft_type_widget.dart @@ -0,0 +1,65 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/app/shared/widget/divider_for_radio_list.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +class OIDC4VPDraftTypeWidget extends StatelessWidget { + const OIDC4VPDraftTypeWidget({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return OptionContainer( + title: 'OIDC4VP', + subtitle: 'Protocole standard release', + body: ListView.builder( + itemCount: OIDC4VPDraftType.values.length, + shrinkWrap: true, + physics: const ScrollPhysics(), + padding: EdgeInsets.zero, + itemBuilder: (context, index) { + final draftType = OIDC4VPDraftType.values[index]; + + if (draftType == OIDC4VPDraftType.draft23) return Container(); + + return Column( + children: [ + ListTile( + onTap: () { + context.read().updateProfileSetting( + oidc4vpDraftType: draftType, + ); + }, + shape: RoundedRectangleBorder( + side: BorderSide( + color: Theme.of(context).colorScheme.onSurface, + width: 0.5, + ), + ), + title: Text( + draftType.formattedString, + style: Theme.of(context).textTheme.bodyLarge, + ), + trailing: Icon( + state.model.profileSetting.selfSovereignIdentityOptions + .customOidc4vcProfile.oidc4vpDraft == + draftType + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + size: Sizes.icon2x, + color: Theme.of(context).colorScheme.primary, + ), + ), + const DividerForRadioList(), + ], + ); + }, + ), + ); + }, + ); + } +} diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart index 3e9eee7ef..fd4c7aab4 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart @@ -3,7 +3,8 @@ export 'client_type_widget.dart'; export 'cryptograhic_holder_binding.dart'; export 'did_key_type_widget.dart'; export 'dpop_support_widget.dart'; -export 'draft_type_widget.dart'; +export 'oidc4vc_draft_type_widget.dart'; +export 'oidc4vp_draft_type_widget.dart'; export 'option_container.dart'; export 'pre_registered_widget.dart'; export 'proof_header_widget.dart'; diff --git a/lib/dashboard/profile/cubit/profile_cubit.dart b/lib/dashboard/profile/cubit/profile_cubit.dart index 81ee1d0bf..15c0fe97f 100644 --- a/lib/dashboard/profile/cubit/profile_cubit.dart +++ b/lib/dashboard/profile/cubit/profile_cubit.dart @@ -433,6 +433,7 @@ class ProfileCubit extends Cubit { bool? secureSecurityAuthenticationWithPinCode, bool? verifySecurityIssuerWebsiteIdentity, OIDC4VCIDraftType? oidc4vciDraftType, + OIDC4VPDraftType? oidc4vpDraftType, ClientType? clientType, VCFormatType? vcFormatType, List? formatsSupported, @@ -472,6 +473,7 @@ class ProfileCubit extends Cubit { clientId: clientId, clientSecret: clientSecret, oidc4vciDraft: oidc4vciDraftType, + oidc4vpDraft: oidc4vpDraftType, clientType: clientType, vcFormatType: vcFormatType, proofType: proofType, diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index 6b8c7021e..03836334f 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -718,7 +718,7 @@ class CustomOidc4VcProfile extends Equatable { cryptoHolderBinding: true, defaultDid: DidKeyType.edDSA, oidc4vciDraft: OIDC4VCIDraftType.draft13, - oidc4vpDraft: OIDC4VPDraftType.draft18, + oidc4vpDraft: OIDC4VPDraftType.draft21, scope: false, securityLevel: false, siopv2Draft: SIOPV2DraftType.draft12, diff --git a/lib/dashboard/profile/models/profile_setting.g.dart b/lib/dashboard/profile/models/profile_setting.g.dart index cc2d8dff3..185f46866 100644 --- a/lib/dashboard/profile/models/profile_setting.g.dart +++ b/lib/dashboard/profile/models/profile_setting.g.dart @@ -326,6 +326,9 @@ const _$OIDC4VPDraftTypeEnumMap = { OIDC4VPDraftType.draft13: '13', OIDC4VPDraftType.draft18: '18', OIDC4VPDraftType.draft20: '20', + OIDC4VPDraftType.draft21: '21', + OIDC4VPDraftType.draft22: '22', + OIDC4VPDraftType.draft23: '23', }; const _$SIOPV2DraftTypeEnumMap = { diff --git a/packages/oidc4vc/lib/src/oidc4vp_draft_type.dart b/packages/oidc4vc/lib/src/oidc4vp_draft_type.dart index a5e6aab65..3c3e9eba3 100644 --- a/packages/oidc4vc/lib/src/oidc4vp_draft_type.dart +++ b/packages/oidc4vc/lib/src/oidc4vp_draft_type.dart @@ -9,6 +9,12 @@ enum OIDC4VPDraftType { draft18, @JsonValue('20') draft20, + @JsonValue('21') + draft21, + @JsonValue('22') + draft22, + @JsonValue('23') + draft23, } extension OIDC4VPDraftTypeX on OIDC4VPDraftType { @@ -22,6 +28,12 @@ extension OIDC4VPDraftTypeX on OIDC4VPDraftType { return 'Draft 18'; case OIDC4VPDraftType.draft20: return 'Draft 20'; + case OIDC4VPDraftType.draft21: + return 'Draft 21'; + case OIDC4VPDraftType.draft22: + return 'Draft 22 (Partial)'; + case OIDC4VPDraftType.draft23: + return 'Draft 23'; } } } From 03de78c4fb31f60ac0ed67bcbdbd7be369be09af Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 19 Dec 2024 18:14:31 +0545 Subject: [PATCH 09/36] feat: Remove client id scheme for draft 22 and above #3160 --- .../helper_functions/helper_functions.dart | 22 ++++- .../cubit/qr_code_scan_cubit.dart | 89 +++++++++++++++---- lib/scan/cubit/scan_cubit.dart | 36 ++++++-- lib/splash/bloclisteners/blocklisteners.dart | 9 ++ .../oidc4vc/lib/src/oidc4vp_draft_type.dart | 4 + .../helper_functions_test.dart | 7 +- 6 files changed, 137 insertions(+), 30 deletions(-) diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index a2b79e61d..6b035872d 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -1504,6 +1504,7 @@ Future fetchRequestUriPayload({ String getUpdatedUrlForSIOPV2OIC4VP({ required Uri uri, required Map response, + required String clientId, }) { final responseType = response['response_type']; final redirectUri = response['redirect_uri']; @@ -1511,7 +1512,6 @@ String getUpdatedUrlForSIOPV2OIC4VP({ final responseUri = response['response_uri']; final responseMode = response['response_mode']; final nonce = response['nonce']; - final clientId = response['client_id']; final claims = response['claims']; final stateValue = response['state']; final presentationDefinition = response['presentation_definition']; @@ -1526,7 +1526,7 @@ String getUpdatedUrlForSIOPV2OIC4VP({ queryJson['scope'] = scope; } - if (!uri.queryParameters.containsKey('client_id') && clientId != null) { + if (!uri.queryParameters.containsKey('client_id')) { queryJson['client_id'] = clientId; } @@ -2426,3 +2426,21 @@ bool isContract(String reciever) { if (reciever.startsWith('KT1')) return true; return false; } + +String getClientIdForPresentation({ + required bool draft22AndAbove, + required String? clientId, +}) { + if (clientId == null) return ''; + if (draft22AndAbove) { + final parts = clientId.split(':'); + if (parts.length == 2) { + return parts[1]; + } else { + // this is mistake though + return clientId; + } + } else { + return clientId; + } +} diff --git a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart index 2e038fa75..84bb4ba05 100644 --- a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart +++ b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart @@ -200,7 +200,7 @@ class QRCodeScanCubit extends Cubit { if (requestUri != null || request != null) { /// verifier side (oidc4vp) or (siopv2 oidc4vc) with request_uri /// verify the encoded data first - await verifyJWTBeforeLaunchingOIDC4VCANDSIOPV2Flow(); + await verifyJWTBeforeLaunchingOIDC4VPANDSIOPV2Flow(); return; } else { emit(state.acceptHost()); @@ -611,6 +611,20 @@ class QRCodeScanCubit extends Cubit { final String? requestUri = uri.queryParameters['request_uri']; final String? request = uri.queryParameters['request']; + final bool draft22AndAbove = profileCubit + .state + .model + .profileSetting + .selfSovereignIdentityOptions + .customOidc4vcProfile + .oidc4vpDraft + .draft22AndAbove; + + final clientId = getClientIdForPresentation( + draft22AndAbove: draft22AndAbove, + clientId: state.uri!.queryParameters['client_id'], + ); + /// check if request uri is provided or not if (requestUri != null || request != null) { late dynamic encodedData; @@ -634,6 +648,7 @@ class QRCodeScanCubit extends Cubit { final String newUrl = getUpdatedUrlForSIOPV2OIC4VP( uri: uri, response: response, + clientId: clientId, ); emit( @@ -713,8 +728,8 @@ class QRCodeScanCubit extends Cubit { final redirectUri = state.uri!.queryParameters['redirect_uri']; final responseUri = state.uri!.queryParameters['response_uri']; - final clientId = state.uri!.queryParameters['client_id']; - final isClientIdUrl = isURL(clientId.toString()); + + final isClientIdUrl = isURL(clientId); /// id_token only if (isIDTokenOnly(responseType)) { @@ -791,7 +806,7 @@ class QRCodeScanCubit extends Cubit { if (isSecurityHigh && responseUri != null && isClientIdUrl && - !responseUri.contains(clientId.toString())) { + !responseUri.contains(clientId)) { throw ResponseMessage( data: { 'error': 'invalid_request', @@ -806,7 +821,7 @@ class QRCodeScanCubit extends Cubit { if (isSecurityHigh && redirectUri != null && isClientIdUrl && - !redirectUri.contains(clientId.toString())) { + !redirectUri.contains(clientId)) { throw ResponseMessage( data: { 'error': 'invalid_request', @@ -1070,7 +1085,7 @@ class QRCodeScanCubit extends Cubit { } /// verify jwt - Future verifyJWTBeforeLaunchingOIDC4VCANDSIOPV2Flow() async { + Future verifyJWTBeforeLaunchingOIDC4VPANDSIOPV2Flow() async { final String? requestUri = state.uri?.queryParameters['request_uri']; final String? request = state.uri?.queryParameters['request']; @@ -1079,10 +1094,8 @@ class QRCodeScanCubit extends Cubit { if (request != null) { encodedData = request; } else if (requestUri != null) { - encodedData = await fetchRequestUriPayload( - url: requestUri, - client: client, - ); + encodedData = + await fetchRequestUriPayload(url: requestUri, client: client); } final customOidc4vcProfile = profileCubit.state.model.profileSetting @@ -1094,7 +1107,7 @@ class QRCodeScanCubit extends Cubit { final Map payload = jwtDecode.parseJwt(encodedData as String); - final String clientId = payload['client_id'].toString(); + var clientId = payload['client_id'].toString(); //check Signature try { @@ -1117,7 +1130,42 @@ class QRCodeScanCubit extends Cubit { Map? publicKeyJwk; - final clientIdScheme = payload['client_id_scheme']; + var clientIdScheme = payload['client_id_scheme']; + + /// With OIDC4VP Draft 22 and above the client_id_scheme is removed + /// from the authorization request but the value is added to the + /// client_id to be the new client_id value + /// + /// in the client_id Authorization Request parameter and other places + /// where the Client Identifier is used, the Client Identifier Schemes + /// are prefixed to the usual Client Identifier, separated by a : + /// (colon) character: : + + if (clientIdScheme == null) { + final draft22AndAbove = profileCubit + .state + .model + .profileSetting + .selfSovereignIdentityOptions + .customOidc4vcProfile + .oidc4vpDraft + .draft22AndAbove; + + if (draft22AndAbove) { + final parts = clientId.split(':'); + if (parts.length == 2) { + clientIdScheme = parts[0]; + clientId = parts[1]; + } else { + throw ResponseMessage( + data: { + 'error': 'invalid_request', + 'error_description': 'Invalid client_id', + }, + ); + } + } + } if (clientIdScheme != null) { final Map header = @@ -1174,7 +1222,16 @@ class QRCodeScanCubit extends Cubit { final redirectUri = state.uri!.queryParameters['redirect_uri']; final responseUri = state.uri!.queryParameters['response_uri']; - final clientId = state.uri!.queryParameters['client_id'] ?? ''; + final customOidc4vcProfile = profileCubit.state.model.profileSetting + .selfSovereignIdentityOptions.customOidc4vcProfile; + + final bool draft22AndAbove = + customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; + + final clientId = getClientIdForPresentation( + draft22AndAbove: draft22AndAbove, + clientId: state.uri!.queryParameters['client_id'], + ); final nonce = state.uri?.queryParameters['nonce']; final stateValue = state.uri?.queryParameters['state']; @@ -1182,8 +1239,7 @@ class QRCodeScanCubit extends Cubit { // final bool? isEBSI = // await isEBSIForVerifier(client: client, uri: state.uri!); - final didKeyType = profileCubit.state.model.profileSetting - .selfSovereignIdentityOptions.customOidc4vcProfile.defaultDid; + final didKeyType = customOidc4vcProfile.defaultDid; final privateKey = await fetchPrivateKey( profileCubit: profileCubit, @@ -1196,9 +1252,6 @@ class QRCodeScanCubit extends Cubit { didKeyType: didKeyType, ); - final customOidc4vcProfile = profileCubit.state.model.profileSetting - .selfSovereignIdentityOptions.customOidc4vcProfile; - final Map responseData = await oidc4vc.getDataForSiopV2Flow( clientId: clientId, diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index 60cdff339..12a2ef357 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -558,11 +558,17 @@ class ScanCubit extends Cubit { if (responseMode == 'direct_post.jwt') { final iat = (DateTime.now().millisecondsSinceEpoch / 1000).round(); - final clientId = uri.queryParameters['client_id'] ?? ''; - final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; + final bool draft22AndAbove = + customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; + + final clientId = getClientIdForPresentation( + draft22AndAbove: draft22AndAbove, + clientId: uri.queryParameters['client_id'], + ); + final didKeyType = customOidc4vcProfile.defaultDid; final (did, _) = await getDidAndKid( @@ -836,10 +842,17 @@ class ScanCubit extends Cubit { VCFormatType? formatFromPresentationSubmission, }) async { final nonce = uri.queryParameters['nonce'] ?? ''; - final clientId = uri.queryParameters['client_id'] ?? ''; - final customOidc4vcProfile = - profileSetting.selfSovereignIdentityOptions.customOidc4vcProfile; + final customOidc4vcProfile = profileCubit.state.model.profileSetting + .selfSovereignIdentityOptions.customOidc4vcProfile; + + final bool draft22AndAbove = + customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; + + final clientId = getClientIdForPresentation( + draft22AndAbove: draft22AndAbove, + clientId: uri.queryParameters['client_id'], + ); if (formatFromPresentationSubmission == VCFormatType.vcSdJWT) { final credentialListJwt = getStringCredentialsForToken( @@ -935,12 +948,19 @@ class ScanCubit extends Cubit { profileCubit: profileCubit, ); - final nonce = uri.queryParameters['nonce'] ?? ''; - final clientId = uri.queryParameters['client_id'] ?? ''; - final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; + final bool draft22AndAbove = + customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; + + final clientId = getClientIdForPresentation( + draft22AndAbove: draft22AndAbove, + clientId: uri.queryParameters['client_id'], + ); + + final nonce = uri.queryParameters['nonce'] ?? ''; + final idToken = await oidc4vc.extractIdToken( clientId: clientId, credentialsToBePresented: credentialList, diff --git a/lib/splash/bloclisteners/blocklisteners.dart b/lib/splash/bloclisteners/blocklisteners.dart index cfcb2c4bd..6b7a3283d 100644 --- a/lib/splash/bloclisteners/blocklisteners.dart +++ b/lib/splash/bloclisteners/blocklisteners.dart @@ -331,9 +331,18 @@ final qrCodeBlocListener = BlocListener( token: encodedData as String, ); + final bool draft22AndAbove = + customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; + + final clientId = getClientIdForPresentation( + draft22AndAbove: draft22AndAbove, + clientId: state.uri!.queryParameters['client_id'], + ); + url = getUpdatedUrlForSIOPV2OIC4VP( uri: state.uri!, response: response, + clientId: clientId, ); } diff --git a/packages/oidc4vc/lib/src/oidc4vp_draft_type.dart b/packages/oidc4vc/lib/src/oidc4vp_draft_type.dart index 3c3e9eba3..f4b4eb0d3 100644 --- a/packages/oidc4vc/lib/src/oidc4vp_draft_type.dart +++ b/packages/oidc4vc/lib/src/oidc4vp_draft_type.dart @@ -36,4 +36,8 @@ extension OIDC4VPDraftTypeX on OIDC4VPDraftType { return 'Draft 23'; } } + + bool get draft22AndAbove { + return this == OIDC4VPDraftType.draft22 || this == OIDC4VPDraftType.draft23; + } } diff --git a/test/app/shared/helper_functions/helper_functions_test.dart b/test/app/shared/helper_functions/helper_functions_test.dart index 03c884f34..a24f8e799 100644 --- a/test/app/shared/helper_functions/helper_functions_test.dart +++ b/test/app/shared/helper_functions/helper_functions_test.dart @@ -1058,8 +1058,11 @@ void main() { 'client_metadata_uri': 'https://example.com/client_metadata', }; - final updatedUrl = - getUpdatedUrlForSIOPV2OIC4VP(uri: uri, response: response); + final updatedUrl = getUpdatedUrlForSIOPV2OIC4VP( + uri: uri, + response: response, + clientId: 'client123', + ); expect( updatedUrl.split('&'), From c1a67b6d63cdaaa54b63f71833ebdf123ce4450a Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 19 Dec 2024 18:20:20 +0545 Subject: [PATCH 10/36] version update: 2.18.15+5588 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index adc615465..df6cfea7e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: altme description: AltMe Flutter App -version: 2.18.14+5587 +version: 2.18.15+5588 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: From 5ecc57345f860a2b0e58a3a473b21adb6a4f6906 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 14:51:38 +0545 Subject: [PATCH 11/36] feat: Update french language #3213 --- lib/l10n/arb/app_fr.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index 07687839f..4834d12de 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -1108,7 +1108,7 @@ "documentation": "Documentation", "restoreACryptoWallet": "Restaurer un wallet crypto", "restoreAnAppBackup": "Restaurer une sauvegarde de {appName}", - "credentialPickShare": "Partagez", + "credentialPickShare": "Partager", "credentialPickTitle": "Choisissez une ou plusieurs attestation(s)", "credentialShareTitle": "Choisissez une ou plusieurs attestation(s)", "enterYourSecretCode": "Entrez votre code secret.", From 2cb1495cb21ca45b1859e0392384b48fc89e6b10 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 15:43:54 +0545 Subject: [PATCH 12/36] feat: Update client id fetching ways #3215 --- .../helper_functions/helper_functions.dart | 13 ++++----- .../cubit/qr_code_scan_cubit.dart | 28 +++++-------------- lib/scan/cubit/scan_cubit.dart | 22 ++++----------- lib/splash/bloclisteners/blocklisteners.dart | 8 ++---- 4 files changed, 20 insertions(+), 51 deletions(-) diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index 6b035872d..987a41900 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -1128,7 +1128,10 @@ Future getHost({ ).host; } else { /// verification case - final clientId = uri.queryParameters['client_id']; + + final clientId = getClientIdForPresentation( + uri.queryParameters['client_id'], + ); if (clientId != null) { return clientId; @@ -2427,17 +2430,13 @@ bool isContract(String reciever) { return false; } -String getClientIdForPresentation({ - required bool draft22AndAbove, - required String? clientId, -}) { +String? getClientIdForPresentation(String? clientId) { if (clientId == null) return ''; - if (draft22AndAbove) { + if (clientId.contains(':')) { final parts = clientId.split(':'); if (parts.length == 2) { return parts[1]; } else { - // this is mistake though return clientId; } } else { diff --git a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart index 84bb4ba05..696cc7d15 100644 --- a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart +++ b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart @@ -611,18 +611,8 @@ class QRCodeScanCubit extends Cubit { final String? requestUri = uri.queryParameters['request_uri']; final String? request = uri.queryParameters['request']; - final bool draft22AndAbove = profileCubit - .state - .model - .profileSetting - .selfSovereignIdentityOptions - .customOidc4vcProfile - .oidc4vpDraft - .draft22AndAbove; - final clientId = getClientIdForPresentation( - draft22AndAbove: draft22AndAbove, - clientId: state.uri!.queryParameters['client_id'], + state.uri!.queryParameters['client_id'], ); /// check if request uri is provided or not @@ -648,7 +638,7 @@ class QRCodeScanCubit extends Cubit { final String newUrl = getUpdatedUrlForSIOPV2OIC4VP( uri: uri, response: response, - clientId: clientId, + clientId: clientId.toString(), ); emit( @@ -729,7 +719,7 @@ class QRCodeScanCubit extends Cubit { final redirectUri = state.uri!.queryParameters['redirect_uri']; final responseUri = state.uri!.queryParameters['response_uri']; - final isClientIdUrl = isURL(clientId); + final isClientIdUrl = isURL(clientId.toString()); /// id_token only if (isIDTokenOnly(responseType)) { @@ -806,7 +796,7 @@ class QRCodeScanCubit extends Cubit { if (isSecurityHigh && responseUri != null && isClientIdUrl && - !responseUri.contains(clientId)) { + !responseUri.contains(clientId.toString())) { throw ResponseMessage( data: { 'error': 'invalid_request', @@ -821,7 +811,7 @@ class QRCodeScanCubit extends Cubit { if (isSecurityHigh && redirectUri != null && isClientIdUrl && - !redirectUri.contains(clientId)) { + !redirectUri.contains(clientId.toString())) { throw ResponseMessage( data: { 'error': 'invalid_request', @@ -1225,12 +1215,8 @@ class QRCodeScanCubit extends Cubit { final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; - final bool draft22AndAbove = - customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; - final clientId = getClientIdForPresentation( - draft22AndAbove: draft22AndAbove, - clientId: state.uri!.queryParameters['client_id'], + state.uri!.queryParameters['client_id'], ); final nonce = state.uri?.queryParameters['nonce']; @@ -1254,7 +1240,7 @@ class QRCodeScanCubit extends Cubit { final Map responseData = await oidc4vc.getDataForSiopV2Flow( - clientId: clientId, + clientId: clientId.toString(), privateKey: privateKey, did: did, kid: kid, diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index 12a2ef357..3deb08b82 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -561,12 +561,8 @@ class ScanCubit extends Cubit { final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; - final bool draft22AndAbove = - customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; - final clientId = getClientIdForPresentation( - draft22AndAbove: draft22AndAbove, - clientId: uri.queryParameters['client_id'], + uri.queryParameters['client_id'], ); final didKeyType = customOidc4vcProfile.defaultDid; @@ -846,12 +842,8 @@ class ScanCubit extends Cubit { final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; - final bool draft22AndAbove = - customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; - final clientId = getClientIdForPresentation( - draft22AndAbove: draft22AndAbove, - clientId: uri.queryParameters['client_id'], + uri.queryParameters['client_id'], ); if (formatFromPresentationSubmission == VCFormatType.vcSdJWT) { @@ -874,7 +866,7 @@ class ScanCubit extends Cubit { ); final vpToken = await oidc4vc.extractVpToken( - clientId: clientId, + clientId: clientId.toString(), credentialsToBePresented: credentialList, did: did, kid: kid, @@ -951,18 +943,14 @@ class ScanCubit extends Cubit { final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; - final bool draft22AndAbove = - customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; - final clientId = getClientIdForPresentation( - draft22AndAbove: draft22AndAbove, - clientId: uri.queryParameters['client_id'], + uri.queryParameters['client_id'], ); final nonce = uri.queryParameters['nonce'] ?? ''; final idToken = await oidc4vc.extractIdToken( - clientId: clientId, + clientId: clientId.toString(), credentialsToBePresented: credentialList, did: did, kid: kid, diff --git a/lib/splash/bloclisteners/blocklisteners.dart b/lib/splash/bloclisteners/blocklisteners.dart index 6b7a3283d..81edd1139 100644 --- a/lib/splash/bloclisteners/blocklisteners.dart +++ b/lib/splash/bloclisteners/blocklisteners.dart @@ -331,18 +331,14 @@ final qrCodeBlocListener = BlocListener( token: encodedData as String, ); - final bool draft22AndAbove = - customOidc4vcProfile.oidc4vpDraft.draft22AndAbove; - final clientId = getClientIdForPresentation( - draft22AndAbove: draft22AndAbove, - clientId: state.uri!.queryParameters['client_id'], + state.uri!.queryParameters['client_id'], ); url = getUpdatedUrlForSIOPV2OIC4VP( uri: state.uri!, response: response, - clientId: clientId, + clientId: clientId.toString(), ); } From 955b994ec56df76ee5aacc848a3bd126ba7ef7e0 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 16:35:14 +0545 Subject: [PATCH 13/36] feat: Update VC not available screen update #3212 --- .../required_credential_not_found.dart | 33 ++----------------- lib/l10n/arb/app_en.arb | 3 +- lib/l10n/untranslated.json | 10 ++++-- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart index 5d12fe2f7..7e209bbeb 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart @@ -9,9 +9,7 @@ class RequiredCredentialNotFound extends StatelessWidget { Widget build(BuildContext context) { final l10n = context.l10n; return BasePage( - title: l10n.credentialPickTitle, titleAlignment: Alignment.topCenter, - titleLeading: const BackLeadingButton(), scrollView: false, padding: const EdgeInsets.only( right: Sizes.spaceNormal, @@ -21,50 +19,25 @@ class RequiredCredentialNotFound extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - l10n.requiredCredentialNotFoundTitle, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleMedium, - ), - const Spacer( - flex: 3, - ), Image.asset( ImageStrings.cardMissing, width: 127, fit: BoxFit.fitWidth, ), - const Spacer( - flex: 1, - ), + const SizedBox(height: 30), Text( l10n.requiredCredentialNotFoundSubTitle, textAlign: TextAlign.center, style: Theme.of(context).textTheme.headlineSmall, ), - const Spacer( - flex: 1, - ), - Text( - l10n.requiredCredentialNotFoundDescription, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleMedium, - ), - Text( - AltMeStrings.appSupportMail, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.headlineSmall, - ), - const Spacer( - flex: 3, - ), ], ), navigation: Padding( padding: const EdgeInsets.all(Sizes.spaceXSmall), child: MyElevatedButton( - text: l10n.backToHome, + text: l10n.back, onPressed: () { Navigator.popUntil( context, diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index def351618..94edcb5dc 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1174,5 +1174,6 @@ "operation": "Operation", "chooseYourSSIProfileOrCustomizeYourOwn": "Choose your wallet profile or customize your own", "recoveryPhraseIncorrectErrorMessage": "Please try again with correct order.", - "invalidCode": "Invalid code" + "invalidCode": "Invalid code", + "back": "Back" } diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index 7fe7715e2..ef971b7fc 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -8,7 +8,8 @@ "operation", "chooseYourSSIProfileOrCustomizeYourOwn", "recoveryPhraseIncorrectErrorMessage", - "invalidCode" + "invalidCode", + "back" ], "es": [ @@ -20,6 +21,11 @@ "operation", "chooseYourSSIProfileOrCustomizeYourOwn", "recoveryPhraseIncorrectErrorMessage", - "invalidCode" + "invalidCode", + "back" + ], + + "fr": [ + "back" ] } From 2e543ba417e26989ffc94a95602f995c56939ee7 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 17:27:21 +0545 Subject: [PATCH 14/36] feat: Return error when user cancels the presentation #3207 --- ...al_manifest_credential_offer_pick_page.dart | 14 +++++++++++++- lib/scan/cubit/scan_cubit.dart | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart index 43c4cc1cb..201ebebe0 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:altme/app/app.dart'; import 'package:altme/credentials/credentials.dart'; import 'package:altme/dashboard/dashboard.dart'; @@ -327,7 +329,17 @@ class _CredentialManifestOfferPickViewState const SizedBox(height: 8), MyOutlinedButton( text: l10n.cancel, - onPressed: () => Navigator.of(context).pop(), + onPressed: () { + unawaited( + context + .read() + .sendErrorToServer( + uri: widget.uri, + data: {'error': 'access_denied'}, + ), + ); + Navigator.of(context).pop(); + }, ), ], ), diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index 3deb08b82..0b7b28eea 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -725,6 +725,24 @@ class ScanCubit extends Cubit { } } + Future sendErrorToServer({ + required Uri uri, + required Map data, + }) async { + final String responseOrRedirectUri = uri.queryParameters['redirect_uri'] ?? + uri.queryParameters['response_uri']!; + + await client.dio.post( + responseOrRedirectUri, + data: data, + options: Options( + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + ), + ); + } + Future<(Map, VCFormatType)> getPresentationSubmission({ required List credentialsToBePresented, required PresentationDefinition presentationDefinition, From 0703556f8e30fd20f58e8859784563cc8918203d Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 17:38:20 +0545 Subject: [PATCH 15/36] feat: Return error when User dont have VC requested #3208 --- ...l_manifest_credential_offer_pick_page.dart | 2 +- .../required_credential_not_found.dart | 94 ++++++++++++------- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart index 201ebebe0..71d677e02 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart @@ -187,7 +187,7 @@ class _CredentialManifestOfferPickViewState } }, child: credentialManifestState.filteredCredentialList.isEmpty - ? const RequiredCredentialNotFound() + ? RequiredCredentialNotFound(uri: widget.uri) : BasePage( title: l10n.credentialShareTitle, titleAlignment: Alignment.topCenter, diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart index 7e209bbeb..0fd79dc3a 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart @@ -1,49 +1,71 @@ +import 'dart:async'; + import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/home/home.dart'; import 'package:altme/l10n/l10n.dart'; +import 'package:altme/scan/scan.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; class RequiredCredentialNotFound extends StatelessWidget { - const RequiredCredentialNotFound({super.key}); + const RequiredCredentialNotFound({super.key, required this.uri}); + + final Uri uri; @override Widget build(BuildContext context) { final l10n = context.l10n; - return BasePage( - titleAlignment: Alignment.topCenter, - scrollView: false, - padding: const EdgeInsets.only( - right: Sizes.spaceNormal, - left: Sizes.spaceNormal, - bottom: Sizes.spaceNormal, - ), - body: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - ImageStrings.cardMissing, - width: 127, - fit: BoxFit.fitWidth, - ), - const SizedBox(height: 30), - Text( - l10n.requiredCredentialNotFoundSubTitle, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.headlineSmall, + return PopScope( + canPop: false, + child: BasePage( + titleAlignment: Alignment.topCenter, + scrollView: false, + padding: const EdgeInsets.only( + right: Sizes.spaceNormal, + left: Sizes.spaceNormal, + bottom: Sizes.spaceNormal, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + ImageStrings.cardMissing, + width: 127, + fit: BoxFit.fitWidth, + ), + const SizedBox(height: 30), + Text( + l10n.requiredCredentialNotFoundSubTitle, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.headlineSmall, + ), + ], + ), + navigation: Padding( + padding: const EdgeInsets.all(Sizes.spaceXSmall), + child: MyElevatedButton( + text: l10n.back, + onPressed: () { + if (context + .read() + .state + .filteredCredentialList + .isEmpty) { + unawaited( + context.read().sendErrorToServer( + uri: uri, + data: {'error': 'access_denied'}, + ), + ); + } + Navigator.popUntil( + context, + (route) => route.settings.name == AltMeStrings.dashBoardPage, + ); + }, ), - ], - ), - navigation: Padding( - padding: const EdgeInsets.all(Sizes.spaceXSmall), - child: MyElevatedButton( - text: l10n.back, - onPressed: () { - Navigator.popUntil( - context, - (route) => route.settings.name == AltMeStrings.dashBoardPage, - ); - }, ), ), ); From 62e417e4ef98e959674ae9aa088c313e3a8a1621 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 17:39:02 +0545 Subject: [PATCH 16/36] feat: Return error when User dont have VC requested #3208 --- .../required_credential_not_found.dart | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart index 0fd79dc3a..199f0316f 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/widgets/required_credential_not_found.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:altme/app/app.dart'; -import 'package:altme/dashboard/home/home.dart'; import 'package:altme/l10n/l10n.dart'; import 'package:altme/scan/scan.dart'; import 'package:flutter/material.dart'; @@ -48,18 +47,12 @@ class RequiredCredentialNotFound extends StatelessWidget { child: MyElevatedButton( text: l10n.back, onPressed: () { - if (context - .read() - .state - .filteredCredentialList - .isEmpty) { - unawaited( - context.read().sendErrorToServer( - uri: uri, - data: {'error': 'access_denied'}, - ), - ); - } + unawaited( + context.read().sendErrorToServer( + uri: uri, + data: {'error': 'access_denied'}, + ), + ); Navigator.popUntil( context, (route) => route.settings.name == AltMeStrings.dashBoardPage, From 58bac82bb2a9c1697a9af1c90e565f7ac014b523 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 17:42:49 +0545 Subject: [PATCH 17/36] feat: Return error when User cannot authenticate #3209 --- .../credential_manifest_credential_offer_pick_page.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart index 71d677e02..3485582af 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart @@ -432,6 +432,12 @@ class _CredentialManifestOfferPickViewState ); if (!authenticated) { + unawaited( + context.read().sendErrorToServer( + uri: widget.uri, + data: {'error': 'access_denied'}, + ), + ); return; } } From 407bd1e75b4d9b98cfcea28541d6f106981d9d80 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 17:58:16 +0545 Subject: [PATCH 18/36] feat: Send errrors back to verifier #3210 --- .../cubit/qr_code_scan_cubit.dart | 262 +++++++++--------- 1 file changed, 131 insertions(+), 131 deletions(-) diff --git a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart index 696cc7d15..d5e3bd78c 100644 --- a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart +++ b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart @@ -664,19 +664,19 @@ class QRCodeScanCubit extends Cubit { // } if (!keys.contains('response_type')) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'The response_type is missing.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'The response_type is missing.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } else if (!keys.contains('client_id')) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'The client_id is missing.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'The client_id is missing.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } final String? responseMode = state.uri!.queryParameters['response_mode']; @@ -687,12 +687,12 @@ class QRCodeScanCubit extends Cubit { /// check response mode value if (!correctResponeMode) { - throw ResponseMessage( - data: { - 'error': 'unsupported_response_type', - 'error_description': 'The response mode is not supported.', - }, - ); + final error = { + 'error': 'unsupported_response_type', + 'error_description': 'The response mode is not supported.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } final bool isSecurityHigh = profileCubit.state.model.profileSetting @@ -706,12 +706,12 @@ class QRCodeScanCubit extends Cubit { registrationMap['subject_syntax_types_supported'] as List; if (!data.contains('did:key')) { if (isSecurityHigh) { - throw ResponseMessage( - data: { - 'error': 'unsupported_response_type', - 'error_description': 'The subject syntax type is not supported.', - }, - ); + final error = { + 'error': 'unsupported_response_type', + 'error_description': 'The subject syntax type is not supported.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } } } @@ -724,22 +724,21 @@ class QRCodeScanCubit extends Cubit { /// id_token only if (isIDTokenOnly(responseType)) { if (redirectUri == null && responseUri == null) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': - 'Only response_uri or redirect_uri is required.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'Only response_uri or redirect_uri is required.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } if (isSecurityHigh && !keys.contains('nonce')) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'The nonce is missing.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'The nonce is missing.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } } @@ -747,25 +746,25 @@ class QRCodeScanCubit extends Cubit { if (hasIDToken(responseType)) { final scope = state.uri!.queryParameters['scope']; if (scope == null || !scope.contains('openid')) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': - 'The openid scope is required in the scope list.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': + 'The openid scope is required in the scope list.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } } /// contain vp_token but may or may not contain id_token if (hasVPToken(responseType)) { if (!keys.contains('nonce')) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'The nonce is missing.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'The nonce is missing.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } if (responseMode == 'direct_post') { @@ -773,23 +772,23 @@ class QRCodeScanCubit extends Cubit { final bothAbsent = redirectUri == null && responseUri == null; if (bothAbsent) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': - 'The response_uri and redirect_uri are missing.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': + 'The response_uri and redirect_uri are missing.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } if (bothPresent) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': - 'Only response_uri or redirect_uri is required.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': + 'Only response_uri or redirect_uri is required.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } } @@ -797,12 +796,12 @@ class QRCodeScanCubit extends Cubit { responseUri != null && isClientIdUrl && !responseUri.contains(clientId.toString())) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'The client_id must be equal to response_uri.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'The client_id must be equal to response_uri.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } } @@ -812,12 +811,12 @@ class QRCodeScanCubit extends Cubit { redirectUri != null && isClientIdUrl && !redirectUri.contains(clientId.toString())) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'The client_id must be equal to redirect_uri.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'The client_id must be equal to redirect_uri.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } } @@ -837,13 +836,13 @@ class QRCodeScanCubit extends Cubit { uri: state.uri!, ); } else { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': - 'The response type supported is id_token, or vp_token or both.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': + 'The response type supported is id_token, or vp_token or both.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } } @@ -965,51 +964,51 @@ class QRCodeScanCubit extends Cubit { }) async { if (!keys.contains('presentation_definition') && !keys.contains('presentation_definition_uri')) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': - 'The presentation_definition or presentation_definition_uri is ' - 'required, only one but one is required.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': + 'The presentation_definition or presentation_definition_uri is ' + 'required, only one but one is required.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } final Map? presentationDefinitionData = await getPresentationDefinition(client: client, uri: uri); if (presentationDefinitionData == null) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'Presentation definition is invalid', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'Presentation definition is invalid', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } final PresentationDefinition presentationDefinition = PresentationDefinition.fromJson(presentationDefinitionData); if (presentationDefinition.inputDescriptors.isEmpty) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': - 'The input_descriptors is required in the presentation_definition' - ' object', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': + 'The input_descriptors is required in the presentation_definition' + ' object', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } if (presentationDefinition.inputDescriptors.isEmpty) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': - 'The input_descriptors is required in the presentation_definition' - ' object', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': + 'The input_descriptors is required in the presentation_definition' + ' object', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } Map? clientMetaData; @@ -1019,24 +1018,24 @@ class QRCodeScanCubit extends Cubit { if (clientMetaData != null) { if (!clientMetaData.containsKey('vp_formats')) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'Format is missing.', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'Format is missing.', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } } } for (final descriptor in presentationDefinition.inputDescriptors) { if (descriptor.constraints == null) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'Presentation definition is invalid', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'Presentation definition is invalid', + }; + unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + throw ResponseMessage(data: error); } } @@ -1147,12 +1146,13 @@ class QRCodeScanCubit extends Cubit { clientIdScheme = parts[0]; clientId = parts[1]; } else { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'Invalid client_id', - }, - ); + final error = { + 'error': 'invalid_request', + 'error_description': 'Invalid client_id', + }; + unawaited( + scanCubit.sendErrorToServer(uri: state.uri!, data: error)); + throw ResponseMessage(data: error); } } } From 7232a542bae3a1c9747b2add00208b4a8f5dbb85 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 18:02:58 +0545 Subject: [PATCH 19/36] version update: 2.18.16+5589 --- .vscode/launch.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 0ae10e8fa..b4e33cecb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -28,13 +28,7 @@ "request": "launch", "type": "dart", "program": "lib/main_production.dart", - "args": [ - "--flavor", - "production", - "--target", - "lib/main_production.dart", - "--release" - ] + "args": ["--flavor", "production", "--target", "lib/main_production.dart"] } ] } From 3f71b3badd54ceb8ca8f917e978ca2c4adff3e3e Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 20 Dec 2024 18:07:25 +0545 Subject: [PATCH 20/36] version update: 2.18.16+5589 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index df6cfea7e..9e7f86a73 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: altme description: AltMe Flutter App -version: 2.18.15+5588 +version: 2.18.16+5589 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: From ce0a48b15154a9e08b05d39949017ab2709ac9a6 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 20 Dec 2024 15:12:01 +0000 Subject: [PATCH 21/36] Regression issue : the authorization_server endpoint in the offer is not taken into account anymore #3172 --- packages/oidc4vc/lib/src/oidc4vc.dart | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index c18061dc5..d6a635752 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -864,6 +864,23 @@ class OIDC4VC { /// authorization_servers in opentIdConfiguration.authorizationServers final listOpenIDConfiguration = openIdConfiguration.authorizationServers ?? []; + + // check if authorization server is present in the credential offer + final authorizationServerFromCredentialOffer = + getAuthorizationServerFromCredentialOffer(credentialOfferJson); + // if authorization server is present in the credential offer + // we check if it is present in the authorization servers + // from credential issuer metadata + // https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-issuer-metadata-p + if (authorizationServerFromCredentialOffer != null) { + if (listOpenIDConfiguration + .contains(authorizationServerFromCredentialOffer)) { + return '$authorizationServerFromCredentialOffer/authorize'; + } else { + // that's forbidden and we can't continue the process + throw Exception('AUTHORIZATION_SERVER_NOT_FOUND'); + } + } if (listOpenIDConfiguration.isNotEmpty) { if (listOpenIDConfiguration.length == 1) { authorizationEndpoint = @@ -1978,4 +1995,23 @@ class OIDC4VC { }; return jwk; } + + String? getAuthorizationServerFromCredentialOffer( + dynamic credentialOfferJson, + ) { + try { + /// Extract the authorization endpoint from from + /// authorization_server in credentialOfferJson + final jsonPathAuthorizationServer = JsonPath( + r'$..authorization_server', + ); + final data = jsonPathAuthorizationServer + .read(credentialOfferJson) + .first + .value! as String; + return data; + } catch (e) { + return null; + } + } } From 31f6f587b3d3b80454a1308f6665bc784c3121fd Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 23 Dec 2024 13:35:04 +0545 Subject: [PATCH 22/36] feat: Return error when user cancels the presentation #3207 --- .../view/selective_disclosure_pick_page.dart | 17 ++++++++++++++++- .../view/query_by_example_present_page.dart | 8 ++++++++ .../qr_code_scan/cubit/qr_code_scan_cubit.dart | 3 ++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/view/selective_disclosure_pick_page.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/view/selective_disclosure_pick_page.dart index abafaf7d1..9f9bb0e41 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/view/selective_disclosure_pick_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/view/selective_disclosure_pick_page.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'package:altme/app/app.dart'; @@ -199,7 +200,15 @@ class _SelectiveDisclosurePickViewState const SizedBox(height: 8), MyOutlinedButton( text: l10n.cancel, - onPressed: () => Navigator.of(context).pop(), + onPressed: () { + unawaited( + context.read().sendErrorToServer( + uri: widget.uri, + data: {'error': 'access_denied'}, + ), + ); + Navigator.of(context).pop(); + }, ), ], ), @@ -320,6 +329,12 @@ class _SelectiveDisclosurePickViewState ); if (!authenticated) { + unawaited( + context.read().sendErrorToServer( + uri: widget.uri, + data: {'error': 'access_denied'}, + ), + ); return; } } diff --git a/lib/dashboard/home/tab_bar/credentials/present/query_by_example_present/view/query_by_example_present_page.dart b/lib/dashboard/home/tab_bar/credentials/present/query_by_example_present/view/query_by_example_present_page.dart index 1bbadeae5..97cf0d775 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/query_by_example_present/view/query_by_example_present_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/query_by_example_present/view/query_by_example_present_page.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:altme/app/app.dart'; import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/l10n/l10n.dart'; @@ -84,6 +86,12 @@ class _QueryByExamplePresentPageState extends State { const SizedBox(height: 8), MyOutlinedButton( onPressed: () { + unawaited( + context.read().sendErrorToServer( + uri: widget.uri, + data: {'error': 'access_denied'}, + ), + ); Navigator.of(context).pop(); }, text: l10n.credentialPresentCancel, diff --git a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart index d5e3bd78c..2c8ff279d 100644 --- a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart +++ b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart @@ -1151,7 +1151,8 @@ class QRCodeScanCubit extends Cubit { 'error_description': 'Invalid client_id', }; unawaited( - scanCubit.sendErrorToServer(uri: state.uri!, data: error)); + scanCubit.sendErrorToServer(uri: state.uri!, data: error), + ); throw ResponseMessage(data: error); } } From b27cc697af1657a0a3fa96aa78e72d325e646daf Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 23 Dec 2024 13:36:13 +0545 Subject: [PATCH 23/36] feat: Add release in launch.json --- .vscode/launch.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index b4e33cecb..0ae10e8fa 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -28,7 +28,13 @@ "request": "launch", "type": "dart", "program": "lib/main_production.dart", - "args": ["--flavor", "production", "--target", "lib/main_production.dart"] + "args": [ + "--flavor", + "production", + "--target", + "lib/main_production.dart", + "--release" + ] } ] } From dea7bdfbf73ef73b05cc7c8842616003909ff571 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 23 Dec 2024 15:40:34 +0545 Subject: [PATCH 24/36] feat: Handle all errors of OIDC4VP #3210 --- .../cubit/qr_code_scan_cubit.dart | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart index 2c8ff279d..078bb21c6 100644 --- a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart +++ b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart @@ -607,13 +607,10 @@ class QRCodeScanCubit extends Cubit { ); } - Future startSIOPV2OIDC4VPProcess(Uri uri) async { - final String? requestUri = uri.queryParameters['request_uri']; - final String? request = uri.queryParameters['request']; - - final clientId = getClientIdForPresentation( - state.uri!.queryParameters['client_id'], - ); + Future startSIOPV2OIDC4VPProcess(Uri oldUri) async { + final String? requestUri = oldUri.queryParameters['request_uri']; + final String? request = oldUri.queryParameters['request']; + final String? clientId = oldUri.queryParameters['client_id']; /// check if request uri is provided or not if (requestUri != null || request != null) { @@ -636,7 +633,7 @@ class QRCodeScanCubit extends Cubit { ); final String newUrl = getUpdatedUrlForSIOPV2OIC4VP( - uri: uri, + uri: oldUri, response: response, clientId: clientId.toString(), ); @@ -668,14 +665,14 @@ class QRCodeScanCubit extends Cubit { 'error': 'invalid_request', 'error_description': 'The response_type is missing.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } else if (!keys.contains('client_id')) { final error = { 'error': 'invalid_request', 'error_description': 'The client_id is missing.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } @@ -691,7 +688,7 @@ class QRCodeScanCubit extends Cubit { 'error': 'unsupported_response_type', 'error_description': 'The response mode is not supported.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } @@ -710,7 +707,7 @@ class QRCodeScanCubit extends Cubit { 'error': 'unsupported_response_type', 'error_description': 'The subject syntax type is not supported.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } } @@ -728,7 +725,7 @@ class QRCodeScanCubit extends Cubit { 'error': 'invalid_request', 'error_description': 'Only response_uri or redirect_uri is required.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } @@ -737,7 +734,7 @@ class QRCodeScanCubit extends Cubit { 'error': 'invalid_request', 'error_description': 'The nonce is missing.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } } @@ -751,7 +748,7 @@ class QRCodeScanCubit extends Cubit { 'error_description': 'The openid scope is required in the scope list.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } } @@ -763,7 +760,7 @@ class QRCodeScanCubit extends Cubit { 'error': 'invalid_request', 'error_description': 'The nonce is missing.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } @@ -777,7 +774,7 @@ class QRCodeScanCubit extends Cubit { 'error_description': 'The response_uri and redirect_uri are missing.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } @@ -787,7 +784,7 @@ class QRCodeScanCubit extends Cubit { 'error_description': 'Only response_uri or redirect_uri is required.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } } @@ -800,7 +797,7 @@ class QRCodeScanCubit extends Cubit { 'error': 'invalid_request', 'error_description': 'The client_id must be equal to response_uri.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } } @@ -815,7 +812,7 @@ class QRCodeScanCubit extends Cubit { 'error': 'invalid_request', 'error_description': 'The client_id must be equal to redirect_uri.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } } @@ -841,7 +838,7 @@ class QRCodeScanCubit extends Cubit { 'error_description': 'The response type supported is id_token, or vp_token or both.', }; - unawaited(scanCubit.sendErrorToServer(uri: uri, data: error)); + unawaited(scanCubit.sendErrorToServer(uri: state.uri!, data: error)); throw ResponseMessage(data: error); } } From 2f59ae408d2ff437e71312c9fb8d2913f9486e9a Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 23 Dec 2024 15:42:52 +0545 Subject: [PATCH 25/36] feat: Hide OIDC4VP switch for 10,18 #3214 --- .../oidc4vc_settngs/widget/oidc4vp_draft_type_widget.dart | 5 ++++- lib/dashboard/profile/models/profile.dart | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vp_draft_type_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vp_draft_type_widget.dart index 692988f2c..1147bb5fa 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vp_draft_type_widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/oidc4vp_draft_type_widget.dart @@ -23,7 +23,10 @@ class OIDC4VPDraftTypeWidget extends StatelessWidget { itemBuilder: (context, index) { final draftType = OIDC4VPDraftType.values[index]; - if (draftType == OIDC4VPDraftType.draft23) return Container(); + if (draftType == OIDC4VPDraftType.draft10 || + draftType == OIDC4VPDraftType.draft13 || + draftType == OIDC4VPDraftType.draft18 || + draftType == OIDC4VPDraftType.draft23) return Container(); return Column( children: [ diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index 98de700f5..f3c0a9654 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -232,7 +232,7 @@ class ProfileModel extends Equatable { cryptoHolderBinding: true, defaultDid: Parameters.didKeyTypeForDefault, oidc4vciDraft: OIDC4VCIDraftType.draft13, - oidc4vpDraft: OIDC4VPDraftType.draft18, + oidc4vpDraft: OIDC4VPDraftType.draft20, scope: false, securityLevel: false, proofHeader: ProofHeaderType.kid, // N/A @@ -316,7 +316,7 @@ class ProfileModel extends Equatable { cryptoHolderBinding: true, defaultDid: Parameters.didKeyTypeForOwfBaselineProfile, oidc4vciDraft: OIDC4VCIDraftType.draft13, - oidc4vpDraft: OIDC4VPDraftType.draft18, + oidc4vpDraft: OIDC4VPDraftType.draft20, scope: true, securityLevel: true, proofHeader: ProofHeaderType.kid, From eb8ead2ca12b5aa5bdf0020180f2da70a4e4c4d4 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 23 Dec 2024 15:45:38 +0545 Subject: [PATCH 26/36] version update: 2.18.17+5590 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 9e7f86a73..c0066ea84 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: altme description: AltMe Flutter App -version: 2.18.16+5589 +version: 2.18.17+5590 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: From 2cc190bc2b6964bee6b1a279c49d0c76f7438352 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 23 Dec 2024 11:03:09 +0000 Subject: [PATCH 27/36] Manage nested display attribute in issuer metadata for openbadge #3073 part 1 --- .../widgets/credential_subject_data.dart | 78 ++++++++++++++++--- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart index bbb1ed1a7..4d07f4442 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart @@ -71,6 +71,18 @@ class CredentialSubjectData extends StatelessWidget { final languageCode = context.read().state.locale.languageCode; + return displayWidget( + credentialSubjectReference, + languageCode, + credentialSubjectData, + ); + } + + Widget displayWidget( + Map credentialSubjectReference, + String languageCode, + Map credentialSubjectData, + ) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: credentialSubjectReference.entries @@ -81,11 +93,11 @@ class CredentialSubjectData extends StatelessWidget { final key = map.key; final value = map.value; - if (value is! Map) return Container(); + if (value is! Map) return const SizedBox.shrink(); if (value.containsKey('display')) { final display = getDisplay(value, languageCode); - if (display == null) return Container(); + if (display == null) return const SizedBox.shrink(); if (credentialSubjectData.containsKey(key)) { title = display['name'].toString(); @@ -100,18 +112,62 @@ class CredentialSubjectData extends StatelessWidget { ? jsonEncode(credentialSubjectData[key]) : credentialSubjectData[key].toString(); } else { - return Container(); + return const SizedBox.shrink(); } } - if (data == null) return Container(); - - final widget = DisplayCredentialField( - title: title, - data: data, - type: value['value_type'].toString(), - showVertically: showVertically, - ); + if (data == null) return const SizedBox.shrink(); + late Widget widget; + final nestedFields = Map.from(value); + nestedFields.remove('display').remove('value_type'); + if (nestedFields.isNotEmpty) { + try { + final json = jsonDecode(data); + if (json is! Map) { + return const SizedBox.shrink(); + } + final List column = []; + + /// for each element in Map toto, call displayWidget + + for (final element in nestedFields.entries) { + final elementValue = element.value; + if (elementValue is Map) { + if (elementValue.isEmpty) { + column.add( + DisplayCredentialField( + title: element.key, + data: json[element.key], + showVertically: showVertically, + ), + ); + } else { + column.add( + displayWidget( + {element.key: elementValue}, + languageCode, + json, + ), + ); + } + } + } + + widget = IndentedCredentialFields( + title: title, + children: column, + ); + } catch (e) { + return const SizedBox.shrink(); + } + } else { + widget = DisplayCredentialField( + title: title, + data: data, + type: value['value_type'].toString(), + showVertically: showVertically, + ); + } return widget; }).toList(), From f264c7fd8998eb32600a4d7667496057c5999e3b Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 24 Dec 2024 17:06:57 +0545 Subject: [PATCH 28/36] feat: Add error for client id scheme #3210 --- .../qr_code_scan/cubit/qr_code_scan_cubit.dart | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart index 078bb21c6..df74e2bf8 100644 --- a/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart +++ b/lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart @@ -1174,6 +1174,19 @@ class QRCodeScanCubit extends Cubit { } else if (clientIdScheme == 'redirect_uri') { /// no need to verify return emit(state.acceptHost()); + } else if (clientIdScheme == 'did') { + /// bypass + } else { + /// if client_id_scheme is not in the list -> did, redirect_uri, + /// verifier_attestation, x509_san_dns + final error = { + 'error': 'invalid_request', + 'error_description': 'Invalid client_id_scheme', + }; + unawaited( + scanCubit.sendErrorToServer(uri: state.uri!, data: error), + ); + throw ResponseMessage(data: error); } final VerificationType isVerified = await verifyEncodedData( From 5353601c2e85eaa0050725e390912e7f664ae47c Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 26 Dec 2024 17:28:09 +0545 Subject: [PATCH 29/36] feat: Solve display issue #3219 --- .../credential_subject_type_extension.dart | 30 +++++++++++-------- .../shared/helper_functions/get_display.dart | 2 +- .../helper_functions/helper_functions.dart | 10 ++++--- .../models/credential/credential.dart | 2 +- .../view/oid4c4vc_credential_pick_page.dart | 2 +- pubspec.yaml | 2 +- 6 files changed, 27 insertions(+), 21 deletions(-) diff --git a/lib/app/shared/enum/type/credential_subject_type/credential_subject_type_extension.dart b/lib/app/shared/enum/type/credential_subject_type/credential_subject_type_extension.dart index 4c92095fb..a4e8aa46a 100644 --- a/lib/app/shared/enum/type/credential_subject_type/credential_subject_type_extension.dart +++ b/lib/app/shared/enum/type/credential_subject_type/credential_subject_type_extension.dart @@ -2,18 +2,22 @@ part of 'credential_subject_type.dart'; extension CredentialSubjectTypeExtension on CredentialSubjectType { Color backgroundColor(CredentialModel credentialModel) { - final Color backgroundColor; - if (credentialModel.display?.backgroundColor != null) { - backgroundColor = Color( - int.parse( - 'FF${credentialModel.display?.backgroundColor!.replaceAll('#', '')}', - radix: 16, - ), - ); - } else { - backgroundColor = defaultBackgroundColor; + try { + final Color backgroundColor; + if (credentialModel.display?.backgroundColor != null) { + backgroundColor = Color( + int.parse( + 'FF${credentialModel.display?.backgroundColor!.replaceAll('#', '')}', + radix: 16, + ), + ); + } else { + backgroundColor = defaultBackgroundColor; + } + return backgroundColor; + } catch (e) { + return defaultBackgroundColor; } - return backgroundColor; } Color get defaultBackgroundColor { @@ -31,7 +35,7 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { case CredentialSubjectType.selfIssued: return const Color(0xffEFF0F6); case CredentialSubjectType.defaultCredential: - return Colors.white; + return const Color(0xff6600FF); case CredentialSubjectType.professionalStudentCard: return const Color(0xffCAFFBF); case CredentialSubjectType.kycAgeCredential: @@ -88,7 +92,7 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { case CredentialSubjectType.identityCredential: case CredentialSubjectType.eudiPid: case CredentialSubjectType.pid: - return Colors.white; + return const Color(0xff6600FF); } } diff --git a/lib/app/shared/helper_functions/get_display.dart b/lib/app/shared/helper_functions/get_display.dart index 360e1dc6b..2b0fccc0d 100644 --- a/lib/app/shared/helper_functions/get_display.dart +++ b/lib/app/shared/helper_functions/get_display.dart @@ -20,7 +20,7 @@ dynamic getDisplay(dynamic value, String languageCode) { element['locale'].toString().contains('en'), orElse: () => displays.firstWhere( (element) => - element is Map && element.containsKey('locale'), + element is Map && !element.containsKey('locale'), orElse: () => displays.firstWhere( (element) => element is Map, // if local is not provided diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index 987a41900..0f7b9a0db 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -1756,7 +1756,7 @@ Future<(String?, String?, String?, String?, String?)> getClientDetails({ (Display display) => display.locale.toString().contains('en'), ) ?? credSupportedDisplay.firstWhereOrNull( - (Display display) => display.locale != null, + (Display display) => display.locale == null, ) ?? credSupportedDisplay.first; // if local is not provided } @@ -1791,7 +1791,8 @@ Future<(String?, String?, String?, String?, String?)> getClientDetails({ ) ?? displays.firstWhereOrNull( (Display display) => display.locale != null, - ); + ) ?? + displays.first; // if local is not provided } } } @@ -1808,8 +1809,9 @@ Future<(String?, String?, String?, String?, String?)> getClientDetails({ (Display display) => display.locale.toString().contains('en'), ) ?? displays.firstWhereOrNull( - (Display display) => display.locale != null, - ); + (Display display) => display.locale == null, + ) ?? + displays.first; // if local is not provided; } return (display, credentialSupported); } diff --git a/lib/dashboard/home/tab_bar/credentials/models/credential/credential.dart b/lib/dashboard/home/tab_bar/credentials/models/credential/credential.dart index 5230a8615..6931a2d57 100644 --- a/lib/dashboard/home/tab_bar/credentials/models/credential/credential.dart +++ b/lib/dashboard/home/tab_bar/credentials/models/credential/credential.dart @@ -33,7 +33,7 @@ class Credential { return Credential( 'dummy1', ['dummy2'], - ['dummy3'], + [''], 'dummy4', 'dummy5', '', //date diff --git a/lib/dashboard/home/tab_bar/credentials/oid4c4vc_pick/oid4c4vc_credential_pick/view/oid4c4vc_credential_pick_page.dart b/lib/dashboard/home/tab_bar/credentials/oid4c4vc_pick/oid4c4vc_credential_pick/view/oid4c4vc_credential_pick_page.dart index 4151ed6d3..0c3c07e4f 100644 --- a/lib/dashboard/home/tab_bar/credentials/oid4c4vc_pick/oid4c4vc_credential_pick/view/oid4c4vc_credential_pick_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/oid4c4vc_pick/oid4c4vc_credential_pick/view/oid4c4vc_credential_pick_page.dart @@ -167,7 +167,7 @@ class Oidc4vcCredentialPickView extends StatelessWidget { ), credDisplayType: CredDisplayType.List, profileSetting: profileSetting, - displyalDescription: false, + displyalDescription: true, isDiscover: false, ) else diff --git a/pubspec.yaml b/pubspec.yaml index c0066ea84..504870163 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: altme description: AltMe Flutter App -version: 2.18.17+5590 +version: 2.18.18+5591 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: From c036ff9bb655f5e7b6a1016861f8c1ba3247c6b9 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 27 Dec 2024 15:39:32 +0545 Subject: [PATCH 30/36] feat: Solve display issue #3219 --- .../widgets/display_description_card.dart | 13 +++++++------ .../widgets/display_name_card.dart | 19 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/dashboard/home/tab_bar/credentials/widgets/display_description_card.dart b/lib/dashboard/home/tab_bar/credentials/widgets/display_description_card.dart index 32f367a66..774ed852e 100644 --- a/lib/dashboard/home/tab_bar/credentials/widgets/display_description_card.dart +++ b/lib/dashboard/home/tab_bar/credentials/widgets/display_description_card.dart @@ -26,12 +26,13 @@ class DisplayDescriptionCard extends StatelessWidget { } String getDescription(BuildContext context) { - var nameValue = GetTranslation.getTranslation( - credentialModel.credentialPreview.description, - context.l10n, - ); - if (nameValue == '') { - nameValue = credentialModel.display?.description ?? ''; + var nameValue = credentialModel.display?.description ?? ''; + + if (credentialModel.display == null) { + nameValue = GetTranslation.getTranslation( + credentialModel.credentialPreview.description, + context.l10n, + ); } return nameValue; diff --git a/lib/dashboard/home/tab_bar/credentials/widgets/display_name_card.dart b/lib/dashboard/home/tab_bar/credentials/widgets/display_name_card.dart index b5c675402..4d5ec0c2c 100644 --- a/lib/dashboard/home/tab_bar/credentials/widgets/display_name_card.dart +++ b/lib/dashboard/home/tab_bar/credentials/widgets/display_name_card.dart @@ -24,14 +24,17 @@ class DisplayNameCard extends StatelessWidget { String getName(BuildContext context) { var nameValue = credentialModel.display?.name ?? ''; - if (nameValue == '') { - nameValue = credentialModel.credentialPreview.type.last; - } - if (nameValue == '') { - nameValue = GetTranslation.getTranslation( - credentialModel.credentialPreview.name, - context.l10n, - ); + + if (credentialModel.display == null) { + if (nameValue == '') { + nameValue = credentialModel.credentialPreview.type.last; + } + if (nameValue == '') { + nameValue = GetTranslation.getTranslation( + credentialModel.credentialPreview.name, + context.l10n, + ); + } } return nameValue; From b8f425ffd02144603d23de1e8eb5986a93724744 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 27 Dec 2024 18:21:15 +0545 Subject: [PATCH 31/36] version update: 2.18.19+5592 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 504870163..449e9bc54 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: altme description: AltMe Flutter App -version: 2.18.18+5591 +version: 2.18.19+5592 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: From 666963e246151aeef6a5c4aa16bb8fa2e126f109 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 30 Dec 2024 08:03:32 +0000 Subject: [PATCH 32/36] remove /authorize, it should come from openId configuration --- lib/oidc4vc/get_authorization_uri_for_issuer.dart | 2 ++ packages/oidc4vc/lib/src/oidc4vc.dart | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/oidc4vc/get_authorization_uri_for_issuer.dart b/lib/oidc4vc/get_authorization_uri_for_issuer.dart index 98fedc4fe..47c376506 100644 --- a/lib/oidc4vc/get_authorization_uri_for_issuer.dart +++ b/lib/oidc4vc/get_authorization_uri_for_issuer.dart @@ -149,6 +149,8 @@ Future getAuthorizationUriForIssuer({ final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; + /// TODO: return an error message if + /// openIdConfiguration.pushedAuthorizationRequestEndpoint is null final parUrl = openIdConfiguration.pushedAuthorizationRequestEndpoint ?? '$authorizationEndpoint/par'; diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index d6a635752..a87fbde48 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -875,7 +875,7 @@ class OIDC4VC { if (authorizationServerFromCredentialOffer != null) { if (listOpenIDConfiguration .contains(authorizationServerFromCredentialOffer)) { - return '$authorizationServerFromCredentialOffer/authorize'; + return authorizationServerFromCredentialOffer; } else { // that's forbidden and we can't continue the process throw Exception('AUTHORIZATION_SERVER_NOT_FOUND'); @@ -884,7 +884,7 @@ class OIDC4VC { if (listOpenIDConfiguration.isNotEmpty) { if (listOpenIDConfiguration.length == 1) { authorizationEndpoint = - '${listOpenIDConfiguration.first}/authorize'; + listOpenIDConfiguration.first; } else { try { /// Extract the authorization endpoint from from @@ -898,7 +898,7 @@ class OIDC4VC { .first .value! as String; if (listOpenIDConfiguration.contains(data)) { - authorizationEndpoint = '$data/authorize'; + authorizationEndpoint = data; } } catch (e) { final jsonPathCredentialOffer = JsonPath( @@ -909,7 +909,7 @@ class OIDC4VC { .first .value! as String; if (data.isNotEmpty && listOpenIDConfiguration.contains(data)) { - authorizationEndpoint = '$data/authorize'; + authorizationEndpoint = data; } } } From 39316dcfdc3d4fd1e76150e9c30e9bc45c783547 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 30 Dec 2024 15:24:34 +0000 Subject: [PATCH 33/36] Manage nested display attribute in issuer metadata for openbadge #3073 --- .../widgets/credential_subject_data.dart | 122 +++++++++++------- pubspec.lock | 84 ++++++------ 2 files changed, 120 insertions(+), 86 deletions(-) diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart index 4d07f4442..c9f36d502 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart @@ -70,7 +70,6 @@ class CredentialSubjectData extends StatelessWidget { if (credentialSubjectData is! Map) return Container(); final languageCode = context.read().state.locale.languageCode; - return displayWidget( credentialSubjectReference, languageCode, @@ -79,38 +78,42 @@ class CredentialSubjectData extends StatelessWidget { } Widget displayWidget( - Map credentialSubjectReference, + Map displayInstructions, String languageCode, Map credentialSubjectData, ) { - return Column( + final Widget column = Column( crossAxisAlignment: CrossAxisAlignment.start, - children: credentialSubjectReference.entries - .map((MapEntry map) { + children: + displayInstructions.entries.map((MapEntry map) { String? title; String? data; - final key = map.key; - final value = map.value; + final displayInstructionKey = map.key; + final displayInstructionValue = map.value; - if (value is! Map) return const SizedBox.shrink(); + if (displayInstructionValue is! Map) { + return const SizedBox.shrink(); + } - if (value.containsKey('display')) { - final display = getDisplay(value, languageCode); + if (displayInstructionValue.containsKey('display')) { + final display = getDisplay(displayInstructionValue, languageCode); if (display == null) return const SizedBox.shrink(); - if (credentialSubjectData.containsKey(key)) { + if (credentialSubjectData.containsKey(displayInstructionKey)) { title = display['name'].toString(); - data = credentialSubjectData[key] is Map - ? jsonEncode(credentialSubjectData[key]) - : credentialSubjectData[key].toString(); + data = credentialSubjectData[displayInstructionKey] is Map || + credentialSubjectData[displayInstructionKey] is List + ? jsonEncode(credentialSubjectData[displayInstructionKey]) + : credentialSubjectData[displayInstructionKey].toString(); } } else { - if (credentialSubjectData[key] != null) { + if (credentialSubjectData[displayInstructionKey] != null) { title = null; - data = credentialSubjectData[key] is Map - ? jsonEncode(credentialSubjectData[key]) - : credentialSubjectData[key].toString(); + data = credentialSubjectData[displayInstructionKey] is Map || + credentialSubjectData[displayInstructionKey] is List + ? jsonEncode(credentialSubjectData[displayInstructionKey]) + : credentialSubjectData[displayInstructionKey].toString(); } else { return const SizedBox.shrink(); } @@ -118,41 +121,41 @@ class CredentialSubjectData extends StatelessWidget { if (data == null) return const SizedBox.shrink(); late Widget widget; - final nestedFields = Map.from(value); - nestedFields.remove('display').remove('value_type'); - if (nestedFields.isNotEmpty) { + final nestedFieldsFromDisplayInstruction = + Map.from(displayInstructionValue); + nestedFieldsFromDisplayInstruction.remove('display'); + nestedFieldsFromDisplayInstruction.remove('value_type'); + if (nestedFieldsFromDisplayInstruction.isNotEmpty) { try { final json = jsonDecode(data); - if (json is! Map) { - return const SizedBox.shrink(); - } final List column = []; - - /// for each element in Map toto, call displayWidget - - for (final element in nestedFields.entries) { - final elementValue = element.value; - if (elementValue is Map) { - if (elementValue.isEmpty) { - column.add( - DisplayCredentialField( - title: element.key, - data: json[element.key], - showVertically: showVertically, - ), - ); - } else { + if (json is Map) { + column.addAll( + toto(json, nestedFieldsFromDisplayInstruction, languageCode), + ); + } + if (json is List) { + for (final listElement in json) { + if (listElement is Map) { column.add( - displayWidget( - {element.key: elementValue}, - languageCode, - json, + Padding( + padding: const EdgeInsets.only(top: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: toto( + listElement, + nestedFieldsFromDisplayInstruction, + languageCode, + ), + ), ), ); } } } + /// for each element in Map toto, call displayWidget + widget = IndentedCredentialFields( title: title, children: column, @@ -164,7 +167,7 @@ class CredentialSubjectData extends StatelessWidget { widget = DisplayCredentialField( title: title, data: data, - type: value['value_type'].toString(), + type: displayInstructionValue['value_type'].toString(), showVertically: showVertically, ); } @@ -172,6 +175,37 @@ class CredentialSubjectData extends StatelessWidget { return widget; }).toList(), ); + return column; + } + + List toto( + Map json, + Map nestedFieldsFromDisplayInstruction, + String languageCode) { + final List column = []; + for (final element in nestedFieldsFromDisplayInstruction.entries) { + final elementValue = element.value; + if (elementValue is Map) { + if (elementValue.isEmpty) { + column.add( + DisplayCredentialField( + title: element.key, + data: json[element.key], + showVertically: showVertically, + ), + ); + } else { + column.add( + displayWidget( + {element.key: elementValue}, + languageCode, + json, + ), + ); + } + } + } + return column; } } diff --git a/pubspec.lock b/pubspec.lock index 42657032d..06806f877 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: android_intent_plus - sha256: "38921ec22ebb3b9a7eb678792cf6fab0b6f458b61b9d327688573449c9b47db3" + sha256: "53136214d506d3128c9f4e5bfce3d026abe7e8038958629811a8d3223b1757c1" url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.2.1" ansicolor: dependency: transitive description: @@ -45,10 +45,10 @@ packages: dependency: "direct main" description: name: app_links - sha256: ad1a6d598e7e39b46a34f746f9a8b011ee147e4c275d407fa457e7a62f84dd99 + sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950" url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.3" app_links_linux: dependency: transitive description: @@ -294,10 +294,10 @@ packages: dependency: transitive description: name: built_value - sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2" url: "https://pub.dev" source: hosted - version: "8.9.2" + version: "8.9.3" cached_network_image: dependency: "direct main" description: @@ -430,10 +430,10 @@ packages: dependency: "direct main" description: name: connectivity_plus - sha256: "876849631b0c7dc20f8b471a2a03142841b482438e3b707955464f5ffca3e4c3" + sha256: e0817759ec6d2d8e57eb234e6e57d2173931367a865850c7acea40d4b4f9c27d url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.1.1" connectivity_plus_platform_interface: dependency: transitive description: @@ -605,10 +605,10 @@ packages: dependency: transitive description: name: device_info_plus_platform_interface - sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" + sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.0.2" devicelocale: dependency: "direct main" description: @@ -1093,10 +1093,10 @@ packages: dependency: "direct main" description: name: flutter_slidable - sha256: "2c5611c0b44e20d180e4342318e1bbc28b0a44ad2c442f5df16962606fd3e8e3" + sha256: a857de7ea701f276fd6a6c4c67ae885b60729a3449e42766bb0e655171042801 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" flutter_sodium: dependency: transitive description: @@ -1255,10 +1255,10 @@ packages: dependency: transitive description: name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" http_parser: dependency: transitive description: @@ -1493,10 +1493,10 @@ packages: dependency: transitive description: name: local_auth_darwin - sha256: "6d2950da311d26d492a89aeb247c72b4653ddc93601ea36a84924a396806d49c" + sha256: "5c5127061107278ab4cafa1ac51b3b6760282bf1a2abf011270908a429d1634b" url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" local_auth_platform_interface: dependency: transitive description: @@ -1708,18 +1708,18 @@ packages: dependency: "direct main" description: name: open_filex - sha256: ba425ea49affd0a98a234aa9344b9ea5d4c4f7625a1377961eae9fe194c3d523 + sha256: dcb7bd3d32db8db5260253a62f1564c02c2c8df64bc0187cd213f65f827519bd url: "https://pub.dev" source: hosted - version: "4.5.0" + version: "4.6.0" package_config: dependency: transitive description: name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" package_info_plus: dependency: "direct overridden" description: @@ -1732,10 +1732,10 @@ packages: dependency: transitive description: name: package_info_plus_platform_interface - sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 + sha256: a5ef9986efc7bf772f2696183a3992615baa76c1ffb1189318dd8803778fb05b url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" path: dependency: "direct main" description: @@ -2004,18 +2004,18 @@ packages: dependency: transitive description: name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" qr: dependency: transitive description: @@ -2195,10 +2195,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d" + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.5.4" shared_preferences_linux: dependency: transitive description: @@ -2296,10 +2296,10 @@ packages: dependency: transitive description: name: source_helper - sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" url: "https://pub.dev" source: hosted - version: "1.3.4" + version: "1.3.5" source_map_stack_trace: dependency: transitive description: @@ -2312,10 +2312,10 @@ packages: dependency: transitive description: name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" url: "https://pub.dev" source: hosted - version: "0.10.12" + version: "0.10.13" source_span: dependency: transitive description: @@ -2368,10 +2368,10 @@ packages: dependency: transitive description: name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -2449,10 +2449,10 @@ packages: dependency: transitive description: name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" typed_data: dependency: transitive description: @@ -2609,10 +2609,10 @@ packages: dependency: transitive description: name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" web: dependency: transitive description: @@ -2745,18 +2745,18 @@ packages: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" yaml_edit: dependency: transitive description: name: yaml_edit - sha256: e9c1a3543d2da0db3e90270dbb1e4eebc985ee5e3ffe468d83224472b2194a5f + sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" sdks: dart: ">=3.4.0 <4.0.0" flutter: ">=3.22.0" From 1e32ac1ca7e83c219cf59b2afdcce13bc93dbed2 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 30 Dec 2024 15:46:13 +0000 Subject: [PATCH 34/36] version: 2.18.20+5593 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 449e9bc54..4cce7d043 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: altme description: AltMe Flutter App -version: 2.18.19+5592 +version: 2.18.20+5593 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: From 2e13344920f5f27351d7d9866f5c3a6a43500a00 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 30 Dec 2024 18:20:58 +0000 Subject: [PATCH 35/36] title of jwt_json-ld depends on display from metadata --- .../widgets/credential_subject_data.dart | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart index c9f36d502..57fb68afe 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart @@ -131,7 +131,11 @@ class CredentialSubjectData extends StatelessWidget { final List column = []; if (json is Map) { column.addAll( - toto(json, nestedFieldsFromDisplayInstruction, languageCode), + displayBlock( + json, + nestedFieldsFromDisplayInstruction, + languageCode, + ), ); } if (json is List) { @@ -142,7 +146,7 @@ class CredentialSubjectData extends StatelessWidget { padding: const EdgeInsets.only(top: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: toto( + children: displayBlock( listElement, nestedFieldsFromDisplayInstruction, languageCode, @@ -178,18 +182,28 @@ class CredentialSubjectData extends StatelessWidget { return column; } - List toto( - Map json, - Map nestedFieldsFromDisplayInstruction, - String languageCode) { + List displayBlock( + Map json, + Map nestedFieldsFromDisplayInstruction, + String languageCode, + ) { final List column = []; + late String? title; for (final element in nestedFieldsFromDisplayInstruction.entries) { final elementValue = element.value; if (elementValue is Map) { + if (elementValue.containsKey('display')) { + final display = getDisplay(elementValue, languageCode); + + title = display['name'].toString(); + } else { + title = null; + } + if (elementValue.isEmpty) { column.add( DisplayCredentialField( - title: element.key, + title: title, data: json[element.key], showVertically: showVertically, ), From 5a306faa7112b4dd5191e43257dc5fa099fee1cd Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 30 Dec 2024 18:35:39 +0000 Subject: [PATCH 36/36] version: 2.19.0+5594 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 4cce7d043..a528b6dd6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: altme description: AltMe Flutter App -version: 2.18.20+5593 +version: 2.19.0+5594 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: