From c96284297e0e48e9f6285533fec22c5736ba4882 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 5 Feb 2024 11:35:48 +0530 Subject: [PATCH 01/70] feat: Simply menu of setting #2348 --- .../advanced_settings2.dart | 4 - .../ssi/advanced_settings2/src/src.dart | 1 - .../src/view/advance_settings2_menu.dart | 79 ------------------- .../ssi/advanced_settings2/src/view/src.dart | 1 - .../oidc4vc_profile/oidc4vc_profile.dart | 0 .../view/oidc4vc_profile_page.dart | 0 .../oidc4vc_settngs/oidc4vc_settings.dart | 0 .../view/oidc4vc_settings_menu.dart | 0 .../widget/client_authentication_widget.dart | 0 .../widget/client_credentials_widget.dart | 0 .../widget/credential_manifest_support.dart | 0 .../widget/cryptograhic_holder_binding.dart | 0 .../widget/did_key_type_widget.dart | 0 .../widget/draft_type_widget.dart | 0 .../widget/option_container.dart | 0 .../widget/scope_parameter.dart | 0 .../widget/security_level_widget.dart | 0 .../widget/six_or_four_pin_widget.dart | 0 .../widget/subject_syntax_type_widget.dart | 0 .../widget/vc_format_widget.dart | 0 .../oidc4vc_settngs/widget/widget.dart | 0 .../drawer/ssi/src/view/ssi_menu.dart | 21 ++++- lib/dashboard/drawer/ssi/ssi.dart | 4 +- .../trust_framework/trust_framework.dart | 0 .../view/trust_framework_page.dart | 0 .../widgets/issuer_verifier_selector.dart | 0 .../trust_framework/widgets/widgets.dart | 0 27 files changed, 21 insertions(+), 89 deletions(-) delete mode 100644 lib/dashboard/drawer/ssi/advanced_settings2/advanced_settings2.dart delete mode 100644 lib/dashboard/drawer/ssi/advanced_settings2/src/src.dart delete mode 100644 lib/dashboard/drawer/ssi/advanced_settings2/src/view/advance_settings2_menu.dart delete mode 100644 lib/dashboard/drawer/ssi/advanced_settings2/src/view/src.dart rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_profile/oidc4vc_profile.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_profile/view/oidc4vc_profile_page.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/oidc4vc_settings.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/view/oidc4vc_settings_menu.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/client_authentication_widget.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/client_credentials_widget.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/credential_manifest_support.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/cryptograhic_holder_binding.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/did_key_type_widget.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/draft_type_widget.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/option_container.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/scope_parameter.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/security_level_widget.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/six_or_four_pin_widget.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/subject_syntax_type_widget.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/vc_format_widget.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/oidc4vc_settngs/widget/widget.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/trust_framework/trust_framework.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/trust_framework/view/trust_framework_page.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/trust_framework/widgets/issuer_verifier_selector.dart (100%) rename lib/dashboard/drawer/ssi/{advanced_settings2 => }/trust_framework/widgets/widgets.dart (100%) diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/advanced_settings2.dart b/lib/dashboard/drawer/ssi/advanced_settings2/advanced_settings2.dart deleted file mode 100644 index 49343d087..000000000 --- a/lib/dashboard/drawer/ssi/advanced_settings2/advanced_settings2.dart +++ /dev/null @@ -1,4 +0,0 @@ -export 'oidc4vc_profile/oidc4vc_profile.dart'; -export 'oidc4vc_settngs/oidc4vc_settings.dart'; -export 'src/src.dart'; -export 'trust_framework/trust_framework.dart'; diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/src/src.dart b/lib/dashboard/drawer/ssi/advanced_settings2/src/src.dart deleted file mode 100644 index a9970189d..000000000 --- a/lib/dashboard/drawer/ssi/advanced_settings2/src/src.dart +++ /dev/null @@ -1 +0,0 @@ -export 'view/advance_settings2_menu.dart'; diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/src/view/advance_settings2_menu.dart b/lib/dashboard/drawer/ssi/advanced_settings2/src/view/advance_settings2_menu.dart deleted file mode 100644 index 99da9efdf..000000000 --- a/lib/dashboard/drawer/ssi/advanced_settings2/src/view/advance_settings2_menu.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:altme/app/app.dart'; -import 'package:altme/dashboard/dashboard.dart'; - -import 'package:altme/l10n/l10n.dart'; -import 'package:altme/theme/theme.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -class AdvancedSettings2Menu extends StatelessWidget { - const AdvancedSettings2Menu({super.key}); - - static Route route() { - return MaterialPageRoute( - settings: const RouteSettings(name: '/AdvancedSettings2Menu'), - builder: (_) => const AdvancedSettings2Menu(), - ); - } - - @override - Widget build(BuildContext context) { - return const AdvancedSettings2View(); - } -} - -class AdvancedSettings2View extends StatelessWidget { - const AdvancedSettings2View({super.key}); - - @override - Widget build(BuildContext context) { - final l10n = context.l10n; - return Drawer( - backgroundColor: Theme.of(context).colorScheme.drawerBackground, - child: SafeArea( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - BackLeadingButton( - padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, - ), - WalletLogo( - profileModel: context.read().state.model, - height: 90, - width: MediaQuery.of(context).size.shortestSide * 0.5, - showPoweredBy: true, - ), - const SizedBox(height: Sizes.spaceSmall), - // DrawerItem( - // title: l10n.oidc4vcProfile, - // onTap: () async { - // await Navigator.of(context) - // .push(OIDC4VCProfilePage.route()); - // }, - // ), - DrawerItem( - title: l10n.oidc4vc_settings, - onTap: () { - Navigator.of(context) - .push(Oidc4vcSettingMenu.route()); - }, - ), - DrawerItem( - title: l10n.trustFramework, - onTap: () async { - await Navigator.of(context) - .push(TrustFrameworkPage.route()); - }, - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/src/view/src.dart b/lib/dashboard/drawer/ssi/advanced_settings2/src/view/src.dart deleted file mode 100644 index a4c11e78e..000000000 --- a/lib/dashboard/drawer/ssi/advanced_settings2/src/view/src.dart +++ /dev/null @@ -1 +0,0 @@ -export 'advance_settings2_menu.dart'; diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_profile/oidc4vc_profile.dart b/lib/dashboard/drawer/ssi/oidc4vc_profile/oidc4vc_profile.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_profile/oidc4vc_profile.dart rename to lib/dashboard/drawer/ssi/oidc4vc_profile/oidc4vc_profile.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_profile/view/oidc4vc_profile_page.dart b/lib/dashboard/drawer/ssi/oidc4vc_profile/view/oidc4vc_profile_page.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_profile/view/oidc4vc_profile_page.dart rename to lib/dashboard/drawer/ssi/oidc4vc_profile/view/oidc4vc_profile_page.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/oidc4vc_settings.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/oidc4vc_settings.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/oidc4vc_settings.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/oidc4vc_settings.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/view/oidc4vc_settings_menu.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/view/oidc4vc_settings_menu.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/client_authentication_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_authentication_widget.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/client_authentication_widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_authentication_widget.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/client_credentials_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_credentials_widget.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/client_credentials_widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_credentials_widget.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/credential_manifest_support.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/credential_manifest_support.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/credential_manifest_support.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/credential_manifest_support.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/cryptograhic_holder_binding.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/cryptograhic_holder_binding.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/cryptograhic_holder_binding.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/cryptograhic_holder_binding.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/did_key_type_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/did_key_type_widget.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/did_key_type_widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/did_key_type_widget.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/draft_type_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/draft_type_widget.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/draft_type_widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/draft_type_widget.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/option_container.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/option_container.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/option_container.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/option_container.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/scope_parameter.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/scope_parameter.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/scope_parameter.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/scope_parameter.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/security_level_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/security_level_widget.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/security_level_widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/security_level_widget.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/six_or_four_pin_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/six_or_four_pin_widget.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/six_or_four_pin_widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/six_or_four_pin_widget.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/subject_syntax_type_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/subject_syntax_type_widget.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/subject_syntax_type_widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/subject_syntax_type_widget.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/vc_format_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/vc_format_widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/oidc4vc_settngs/widget/widget.dart rename to lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart diff --git a/lib/dashboard/drawer/ssi/src/view/ssi_menu.dart b/lib/dashboard/drawer/ssi/src/view/ssi_menu.dart index b3298b5aa..46411ac57 100644 --- a/lib/dashboard/drawer/ssi/src/view/ssi_menu.dart +++ b/lib/dashboard/drawer/ssi/src/view/ssi_menu.dart @@ -84,14 +84,29 @@ class SSIView extends StatelessWidget { }, ), if (context.read().state.model.profileType == - ProfileType.custom) + ProfileType.custom) ...[ + // DrawerItem( + // title: l10n.oidc4vcProfile, + // onTap: () async { + // await Navigator.of(context) + // .push(OIDC4VCProfilePage.route()); + // }, + // ), DrawerItem( - title: l10n.advanceSettings, + title: l10n.oidc4vc_settings, + onTap: () { + Navigator.of(context) + .push(Oidc4vcSettingMenu.route()); + }, + ), + DrawerItem( + title: l10n.trustFramework, onTap: () async { await Navigator.of(context) - .push(AdvancedSettings2Menu.route()); + .push(TrustFrameworkPage.route()); }, ), + ], ], ), ), diff --git a/lib/dashboard/drawer/ssi/ssi.dart b/lib/dashboard/drawer/ssi/ssi.dart index 7ad0c6f18..36dc5f244 100644 --- a/lib/dashboard/drawer/ssi/ssi.dart +++ b/lib/dashboard/drawer/ssi/ssi.dart @@ -1,5 +1,7 @@ -export 'advanced_settings2/advanced_settings2.dart'; export 'backup/backup.dart'; export 'manage_did/manage_did.dart'; +export 'oidc4vc_profile/oidc4vc_profile.dart'; +export 'oidc4vc_settngs/oidc4vc_settings.dart'; export 'restore/restore.dart'; export 'src/src.dart'; +export 'trust_framework/trust_framework.dart'; diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/trust_framework/trust_framework.dart b/lib/dashboard/drawer/ssi/trust_framework/trust_framework.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/trust_framework/trust_framework.dart rename to lib/dashboard/drawer/ssi/trust_framework/trust_framework.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/trust_framework/view/trust_framework_page.dart b/lib/dashboard/drawer/ssi/trust_framework/view/trust_framework_page.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/trust_framework/view/trust_framework_page.dart rename to lib/dashboard/drawer/ssi/trust_framework/view/trust_framework_page.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/trust_framework/widgets/issuer_verifier_selector.dart b/lib/dashboard/drawer/ssi/trust_framework/widgets/issuer_verifier_selector.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/trust_framework/widgets/issuer_verifier_selector.dart rename to lib/dashboard/drawer/ssi/trust_framework/widgets/issuer_verifier_selector.dart diff --git a/lib/dashboard/drawer/ssi/advanced_settings2/trust_framework/widgets/widgets.dart b/lib/dashboard/drawer/ssi/trust_framework/widgets/widgets.dart similarity index 100% rename from lib/dashboard/drawer/ssi/advanced_settings2/trust_framework/widgets/widgets.dart rename to lib/dashboard/drawer/ssi/trust_framework/widgets/widgets.dart From 582b7f243fa5175b474e5a5cde3dfb0328f29fb0 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 5 Feb 2024 12:48:06 +0530 Subject: [PATCH 02/70] feat: Add new issuer for EmailPass with jwt_vc_json format #2342 --- lib/app/shared/constants/urls.dart | 2 ++ lib/app/shared/enum/credential_category.dart | 1 - .../credential_subject_type_extension.dart | 14 ++++++++++++-- lib/credentials/cubit/credentials_cubit.dart | 17 +++++++++++------ 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/lib/app/shared/constants/urls.dart b/lib/app/shared/constants/urls.dart index 3dae06e8d..099997679 100644 --- a/lib/app/shared/constants/urls.dart +++ b/lib/app/shared/constants/urls.dart @@ -17,6 +17,8 @@ class Urls { static const String issuerBaseUrl = 'https://issuer.talao.co'; static const String phonePassUrl = 'https://issuer.talao.co/phonepass'; static const String emailPassUrl = 'https://issuer.talao.co/emailpass'; + static const String emailPassUrlJWTVCJSON = + 'https://issuer.talao.co/emailpass?format=jwt_vc_json'; static const String tezotopiaVoucherUrl = 'https://issuer.tezotopia.altme.io/issuer/voucher_mobile'; diff --git a/lib/app/shared/enum/credential_category.dart b/lib/app/shared/enum/credential_category.dart index b8bdc3041..54eca369e 100644 --- a/lib/app/shared/enum/credential_category.dart +++ b/lib/app/shared/enum/credential_category.dart @@ -1,4 +1,3 @@ -import 'package:altme/app/app.dart'; import 'package:altme/l10n/l10n.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; 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 59f207bf1..8efed783d 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 @@ -639,7 +639,6 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { case CredentialSubjectType.binanceAssociatedWallet: case CredentialSubjectType.tezosAssociatedWallet: case CredentialSubjectType.defiCompliance: - case CredentialSubjectType.emailPass: case CredentialSubjectType.tezotopiaMembership: case CredentialSubjectType.phonePass: case CredentialSubjectType.chainbornMembership: @@ -648,6 +647,7 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { case CredentialSubjectType.verifiableIdCard: case CredentialSubjectType.over18: case CredentialSubjectType.livenessCard: + case CredentialSubjectType.emailPass: return [VCFormatType.ldpVc, VCFormatType.jwtVcJson]; case CredentialSubjectType.nationality: @@ -736,7 +736,17 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { case CredentialSubjectType.emailPass: image = ImageStrings.dummyEmailPassCard; - link = Urls.emailPassUrl; + + switch (vcFormatType) { + case VCFormatType.ldpVc: + link = Urls.emailPassUrl; + case VCFormatType.jwtVcJson: + link = Urls.emailPassUrlJWTVCJSON; + case VCFormatType.jwtVc: + case VCFormatType.jwtVcJsonLd: + link = ''; + } + whyGetThisCard = ResponseString.RESPONSE_STRING_emailPassWhyGetThisCard; expirationDateDetails = ResponseString.RESPONSE_STRING_emailPassExpirationDate; diff --git a/lib/credentials/cubit/credentials_cubit.dart b/lib/credentials/cubit/credentials_cubit.dart index 2318a3718..8056b9911 100644 --- a/lib/credentials/cubit/credentials_cubit.dart +++ b/lib/credentials/cubit/credentials_cubit.dart @@ -695,12 +695,17 @@ class CredentialsCubit extends Cubit { break; case CredentialCategory.contactInfoCredentials: - if (discoverCardsOptions.displayEmailPass && - !allSubjectTypeForCategory - .contains(CredentialSubjectType.emailPass)) { - allSubjectTypeForCategory.add( - CredentialSubjectType.emailPass, - ); + if (!allSubjectTypeForCategory + .contains(CredentialSubjectType.emailPass)) { + final displayEmailPass = vcFormatType == VCFormatType.ldpVc && + discoverCardsOptions.displayEmailPass; + final displayEmailPassJwt = + vcFormatType == VCFormatType.jwtVcJson && + discoverCardsOptions.displayEmailPassJwt; + + if (displayEmailPass || displayEmailPassJwt) { + allSubjectTypeForCategory.add(CredentialSubjectType.emailPass); + } } if (discoverCardsOptions.displayPhonePass && From 33adbb3b0d17059e56149b9c0693c3b95210a7ba Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 5 Feb 2024 14:09:33 +0530 Subject: [PATCH 03/70] Add new VC format in OIDC4VC settings / switch for VC format #2345 --- .../credential_subject_type_extension.dart | 4 ++++ packages/oidc4vc/lib/src/vc_format_type.dart | 4 ++++ 2 files changed, 8 insertions(+) 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 8efed783d..f67a19693 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 @@ -744,6 +744,7 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { link = Urls.emailPassUrlJWTVCJSON; case VCFormatType.jwtVc: case VCFormatType.jwtVcJsonLd: + case VCFormatType.vcSdJWT: link = ''; } @@ -777,6 +778,7 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { link = Urls.over18JWTVCJSON; case VCFormatType.jwtVc: case VCFormatType.jwtVcJsonLd: + case VCFormatType.vcSdJWT: link = ''; } whyGetThisCard = ResponseString.RESPONSE_STRING_over18WhyGetThisCard; @@ -837,6 +839,7 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { link = Urls.identityCardUrlJWTVCJSON; case VCFormatType.jwtVc: case VCFormatType.jwtVcJsonLd: + case VCFormatType.vcSdJWT: link = ''; } @@ -907,6 +910,7 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { link = Urls.livenessCardJWTVCJSON; case VCFormatType.jwtVc: case VCFormatType.jwtVcJsonLd: + case VCFormatType.vcSdJWT: link = ''; } diff --git a/packages/oidc4vc/lib/src/vc_format_type.dart b/packages/oidc4vc/lib/src/vc_format_type.dart index 690385c0a..53e249cba 100644 --- a/packages/oidc4vc/lib/src/vc_format_type.dart +++ b/packages/oidc4vc/lib/src/vc_format_type.dart @@ -9,6 +9,8 @@ enum VCFormatType { jwtVcJson, @JsonValue('jwt_vc_json-ld') jwtVcJsonLd, + @JsonValue('vc+sd-jwt') + vcSdJWT, } extension VCFormatTypeX on VCFormatType { @@ -22,6 +24,8 @@ extension VCFormatTypeX on VCFormatType { return 'jwt_vc_json'; case VCFormatType.jwtVcJsonLd: return 'jwt_vc_json-ld'; + case VCFormatType.vcSdJWT: + return 'vc+sd-jwt (Experimental)'; } } } From 3463826ba6e2135eacd141afaa7e984629a9002f Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 6 Feb 2024 11:38:51 +0530 Subject: [PATCH 04/70] Adpoted new credential_configurations_supported #2256 #2259 --- .../helper_functions/helper_functions.dart | 47 ++++++++---- .../initiate_oidv4vc_credential_issuance.dart | 30 +++++++- .../lib/src/models/openid_configuration.dart | 4 + packages/oidc4vc/lib/src/oidc4vc.dart | 73 +++++++++++++++++-- 4 files changed, 130 insertions(+), 24 deletions(-) diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index 187ec5cc1..b8d6da0a8 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -637,8 +637,11 @@ Future<(OIDC4VCType?, OpenIdConfiguration?, OpenIdConfiguration?, dynamic)> } final credentialsSupported = openIdConfiguration.credentialsSupported; + final credentialConfigurationsSupported = + openIdConfiguration.credentialConfigurationsSupported; - if (credentialsSupported == null) { + if (credentialsSupported == null && + credentialConfigurationsSupported == null) { throw ResponseMessage( data: { 'error': 'invalid_request', @@ -647,13 +650,18 @@ Future<(OIDC4VCType?, OpenIdConfiguration?, OpenIdConfiguration?, dynamic)> ); } - final credSupported = credentialsSupported[0]; + CredentialsSupported? credSupported; + + if (credentialsSupported != null) { + credSupported = credentialsSupported[0]; + } + for (final oidc4vcType in OIDC4VCType.values) { if (oidc4vcType.isEnabled && url.startsWith(oidc4vcType.offerPrefix)) { if (oidc4vcType == OIDC4VCType.DEFAULT || oidc4vcType == OIDC4VCType.EBSIV3) { - if (credSupported.trustFramework != null && - credSupported == credSupported.trustFramework) { + if (credSupported?.trustFramework != null && + credSupported == credSupported?.trustFramework) { return ( OIDC4VCType.DEFAULT, openIdConfiguration, @@ -662,8 +670,8 @@ Future<(OIDC4VCType?, OpenIdConfiguration?, OpenIdConfiguration?, dynamic)> ); } - if (credSupported.trustFramework?.name != null && - credSupported.trustFramework?.name == 'ebsi') { + if (credSupported?.trustFramework?.name != null && + credSupported?.trustFramework?.name == 'ebsi') { return ( OIDC4VCType.EBSIV3, openIdConfiguration, @@ -758,7 +766,8 @@ Future handleErrorForOID4VCI({ ); } - if (openIdConfiguration.credentialsSupported == null) { + if (openIdConfiguration.credentialsSupported == null && + openIdConfiguration.credentialConfigurationsSupported == null) { throw ResponseMessage( data: { 'error': 'invalid_issuer_metadata', @@ -1011,7 +1020,9 @@ bool isURL(String input) { } MessageHandler getMessageHandler(dynamic e) { - if (e is DioException) { + if (e is MessageHandler) { + return e; + } else if (e is DioException) { final error = NetworkException.getDioException(error: e); return NetworkException(data: error.data); @@ -1022,8 +1033,6 @@ MessageHandler getMessageHandler(dynamic e) { 'error_description': '${e.message}\n\n${e.source}', }, ); - } else if (e is MessageHandler) { - return e; } else if (e is TypeError) { return ResponseMessage( data: { @@ -1032,10 +1041,20 @@ MessageHandler getMessageHandler(dynamic e) { }, ); } else { - return ResponseMessage( - message: - ResponseString.RESPONSE_STRING_SOMETHING_WENT_WRONG_TRY_AGAIN_LATER, - ); + final stringException = e.toString().replaceAll('Exception: ', ''); + if (stringException == 'CREDENTIAL_SUPPORT_DATA_ERROR') { + return ResponseMessage( + data: { + 'error': 'unsupported_credential_format', + 'error_description': 'The credential support format has some issues.', + }, + ); + } else { + return ResponseMessage( + message: + ResponseString.RESPONSE_STRING_SOMETHING_WENT_WRONG_TRY_AGAIN_LATER, + ); + } } } diff --git a/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart b/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart index bcdfe11ef..0dfb29cab 100644 --- a/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart +++ b/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart @@ -33,9 +33,33 @@ Future initiateOIDC4VCCredentialIssuance({ if (keys.contains('credential_type')) { credentials = uriFromScannedResponse.queryParameters['credential_type']; } else { - if (credentialOfferJson == null) throw Exception(); + final validCredentialOffer = credentialOfferJson != null && + credentialOfferJson is Map; - credentials = credentialOfferJson['credentials']; + if (!validCredentialOffer) { + throw ResponseMessage( + data: { + 'error': 'invalid_issuer_metadata', + 'error_description': 'The issuer configuration is invalid. ' + 'The credential offer is missing.', + }, + ); + } + + if (credentialOfferJson.containsKey('credentials')) { + credentials = credentialOfferJson['credentials']; + } else if (credentialOfferJson + .containsKey('credential_configuration_ids')) { + credentials = credentialOfferJson['credential_configuration_ids']; + } else { + throw ResponseMessage( + data: { + 'error': 'invalid_issuer_metadata', + 'error_description': 'The issuer configuration is invalid. ' + 'The credential offer is missing.', + }, + ); + } } final (preAuthorizedCode, issuer) = await getIssuerAndPreAuthorizedCode( @@ -43,6 +67,8 @@ Future initiateOIDC4VCCredentialIssuance({ dioClient: dioClient, ); + //cleared up to here + if (credentials is List) { final codeForAuthorisedFlow = Uri.parse(scannedResponse).queryParameters['code']; diff --git a/packages/oidc4vc/lib/src/models/openid_configuration.dart b/packages/oidc4vc/lib/src/models/openid_configuration.dart index 7392c1e25..fc1aa587c 100644 --- a/packages/oidc4vc/lib/src/models/openid_configuration.dart +++ b/packages/oidc4vc/lib/src/models/openid_configuration.dart @@ -9,6 +9,7 @@ class OpenIdConfiguration extends Equatable { const OpenIdConfiguration({ this.authorizationServer, this.credentialsSupported, + this.credentialConfigurationsSupported, this.credentialEndpoint, this.credentialIssuer, this.subjectSyntaxTypesSupported, @@ -45,6 +46,8 @@ class OpenIdConfiguration extends Equatable { final List? subjectTrustFrameworksSupported; @JsonKey(name: 'credentials_supported') final List? credentialsSupported; + @JsonKey(name: 'credential_configurations_supported') + final dynamic credentialConfigurationsSupported; @JsonKey(name: 'deferred_credential_endpoint') final String? deferredCredentialEndpoint; @JsonKey(name: 'service_documentation') @@ -70,6 +73,7 @@ class OpenIdConfiguration extends Equatable { authorizationEndpoint, subjectTrustFrameworksSupported, credentialsSupported, + credentialConfigurationsSupported, deferredCredentialEndpoint, serviceDocumentation, credentialManifest, diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 2461cf23f..092fb84ed 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -785,13 +785,17 @@ class OIDC4VC { if (credentialType.startsWith('https://api.preprod.ebsi.eu')) { format = 'jwt_vc'; types = []; - } else { - final jsonPath = JsonPath(r'$..credentials_supported'); + } else if (openIdConfiguration.credentialsSupported != null) { + final credentialsSupported = JsonPath(r'$..credentials_supported') + .read(jsonDecode(jsonEncode(openIdConfiguration))) + .first + .value; + + if (credentialsSupported is! List) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } - final credentialSupported = (jsonPath - .read(jsonDecode(jsonEncode(openIdConfiguration))) - .first - .value as List) + final credentialSupported = credentialsSupported .where( (dynamic e) => e is Map && @@ -800,11 +804,64 @@ class OIDC4VC { (e.containsKey('id') && e['id'].toString() == credential)), ) - .first as Map; + .firstOrNull; + + if (credentialSupported == null || + credentialSupported is! Map) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } + types = (credentialSupported['types'] as List) .map((e) => e.toString()) .toList(); format = credentialSupported['format'].toString(); + } else if (openIdConfiguration.credentialConfigurationsSupported != + null) { + // draft 13 case + + final credentialsSupported = + JsonPath(r'$..credential_configurations_supported') + .read(jsonDecode(jsonEncode(openIdConfiguration))) + .first + .value; + + if (credentialsSupported is! Map) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } + + final credentialSupportedMapEntry = credentialsSupported.entries.where( + (dynamic entry) { + final dynamic ele = entry.value; + if (ele is! Map) return false; + + final credentialDefinition = ele['credential_definition']; + + if (credentialDefinition is! Map) return false; + + if (!credentialDefinition.containsKey('type')) return false; + + final type = credentialDefinition['type']; + + if (type is! List) return false; + + if (type.contains(credential)) return true; + + return false; + }, + ).firstOrNull; + + if (credentialSupportedMapEntry == null) throw Exception(); + + final credentialSupported = credentialSupportedMapEntry.value; + + types = (credentialSupported['credential_definition']['type'] + as List) + .map((e) => e.toString()) + .toList(); + + format = credentialSupported['format'].toString(); + } else { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); } } else if (credential is Map) { types = (credential['types'] as List) @@ -813,7 +870,7 @@ class OIDC4VC { credentialType = types.last; format = credential['format'].toString(); } else { - throw Exception(); + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); } return (credentialType, types, format); From a22a59f3885bc269d813de2105654347b0ce8aa6 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 6 Feb 2024 15:57:05 +0530 Subject: [PATCH 05/70] feat: Implemented Draft 13 #2256 #2259 --- packages/oidc4vc/lib/src/oidc4vc.dart | 70 ++++++++++++------- .../oidc4vc/lib/src/oidc4vci_draft_type.dart | 4 ++ 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 092fb84ed..3862437f9 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -409,7 +409,8 @@ class OIDC4VC { openIdConfiguration.deferredCredentialEndpoint; } - final (credentialType, types, format) = await getCredentialData( + final (credentialType, types, credentialDefinition, format) = + await getCredentialData( openIdConfiguration: openIdConfiguration, credential: credential, ); @@ -446,6 +447,7 @@ class OIDC4VC { credentialIdentifier: credentialIdentifier, cryptoHolderBinding: cryptoHolderBinding, oidc4vciDraftType: oidc4vciDraftType, + credentialDefinition: credentialDefinition, ); credentialResponseData.add(credentialResponseDataValue); @@ -460,6 +462,7 @@ class OIDC4VC { format: format, cryptoHolderBinding: cryptoHolderBinding, oidc4vciDraftType: oidc4vciDraftType, + credentialDefinition: credentialDefinition, ); credentialResponseData.add(credentialResponseDataValue); @@ -477,11 +480,12 @@ class OIDC4VC { required IssuerTokenParameters issuerTokenParameters, required OpenIdConfiguration openIdConfiguration, required String credentialType, - required List types, + required List? types, required String format, required bool cryptoHolderBinding, required OIDC4VCIDraftType oidc4vciDraftType, String? credentialIdentifier, + Map? credentialDefinition, }) async { final credentialData = await buildCredentialData( cnonce: cnonce, @@ -493,6 +497,7 @@ class OIDC4VC { credentialIdentifier: credentialIdentifier, cryptoHolderBinding: cryptoHolderBinding, oidc4vciDraftType: oidc4vciDraftType, + credentialDefinition: credentialDefinition, ); /// sign proof @@ -736,12 +741,13 @@ class OIDC4VC { required IssuerTokenParameters issuerTokenParameters, required OpenIdConfiguration openIdConfiguration, required String credentialType, - required List types, + required List? types, required String format, required bool cryptoHolderBinding, required OIDC4VCIDraftType oidc4vciDraftType, String? credentialIdentifier, String? cnonce, + Map? credentialDefinition, }) async { final vcJwt = await getIssuerJwt(issuerTokenParameters, cnonce); @@ -758,25 +764,47 @@ class OIDC4VC { case OIDC4VCIDraftType.draft8: credentialData['type'] = credentialType; credentialData['format'] = format; + case OIDC4VCIDraftType.draft11: + if (types == null) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } + credentialData['types'] = types; credentialData['format'] = format; + case OIDC4VCIDraftType.draft12: + if (types == null) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } + credentialData['types'] = types; if (credentialIdentifier != null) { credentialData['credential_identifier'] = credentialIdentifier; } + + case OIDC4VCIDraftType.draft13: + credentialData['format'] = format; + + if (credentialDefinition == null) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } + + credentialData['credential_definition'] = credentialDefinition; } return credentialData; } - Future<(String, List, String)> getCredentialData({ + /// (credentialType, types, credential_definition, format) + Future<(String, List?, Map?, String)> + getCredentialData({ required OpenIdConfiguration openIdConfiguration, required dynamic credential, }) async { String? credentialType; List? types; + Map? credentialDefinition; String? format; if (credential is String) { @@ -830,36 +858,28 @@ class OIDC4VC { } final credentialSupportedMapEntry = credentialsSupported.entries.where( - (dynamic entry) { - final dynamic ele = entry.value; - if (ele is! Map) return false; - - final credentialDefinition = ele['credential_definition']; - - if (credentialDefinition is! Map) return false; - - if (!credentialDefinition.containsKey('type')) return false; + (entry) { + final dynamic ele = entry.key; - final type = credentialDefinition['type']; - - if (type is! List) return false; - - if (type.contains(credential)) return true; + if (ele == credential) return true; return false; }, ).firstOrNull; - if (credentialSupportedMapEntry == null) throw Exception(); + if (credentialSupportedMapEntry == null) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } final credentialSupported = credentialSupportedMapEntry.value; - types = (credentialSupported['credential_definition']['type'] - as List) - .map((e) => e.toString()) - .toList(); - format = credentialSupported['format'].toString(); + + if ((credentialSupported is Map) && + (credentialSupported.containsKey('credential_definition'))) { + credentialDefinition = credentialSupported['credential_definition'] + as Map; + } } else { throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); } @@ -873,7 +893,7 @@ class OIDC4VC { throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); } - return (credentialType, types, format); + return (credentialType, types, credentialDefinition, format); } Future verifyEncodedData({ diff --git a/packages/oidc4vc/lib/src/oidc4vci_draft_type.dart b/packages/oidc4vc/lib/src/oidc4vci_draft_type.dart index 18f897a79..9ce1132d3 100644 --- a/packages/oidc4vc/lib/src/oidc4vci_draft_type.dart +++ b/packages/oidc4vc/lib/src/oidc4vci_draft_type.dart @@ -7,6 +7,8 @@ enum OIDC4VCIDraftType { draft11, @JsonValue('12') draft12, + @JsonValue('13') + draft13, } extension OIDC4VCIDraftTypeX on OIDC4VCIDraftType { @@ -18,6 +20,8 @@ extension OIDC4VCIDraftTypeX on OIDC4VCIDraftType { return 'Draft 11'; case OIDC4VCIDraftType.draft12: return 'Draft 12 (Partial)'; + case OIDC4VCIDraftType.draft13: + return 'Draft 13'; } } } From 8426903e4bd902460522b0f558cd6298cc379d8a Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 6 Feb 2024 18:07:42 +0530 Subject: [PATCH 06/70] Implement tx_code #2258 #2352 --- .../cubit/qr_code_scan_cubit.dart | 21 ++++++++++---- lib/dashboard/user_pin/model/model.dart | 1 + lib/dashboard/user_pin/model/tx_code.dart | 29 +++++++++++++++++++ lib/dashboard/user_pin/user_pin.dart | 1 + .../user_pin/view/user_pin_page.dart | 20 ++++++++----- packages/oidc4vc/lib/src/oidc4vc.dart | 7 ++++- 6 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 lib/dashboard/user_pin/model/model.dart create mode 100644 lib/dashboard/user_pin/model/tx_code.dart 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 dfe343c91..9688d8bc7 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 @@ -406,11 +406,21 @@ class QRCodeScanCubit extends Cubit { ['urn:ietf:params:oauth:grant-type:pre-authorized_code']; bool? userPinRequired; - - if (preAuthorizedCodeGrant != null && - preAuthorizedCodeGrant is Map && - preAuthorizedCodeGrant.containsKey('user_pin_required')) { - userPinRequired = preAuthorizedCodeGrant['user_pin_required'] as bool; + TxCode? txCode; + + if (preAuthorizedCodeGrant != null && preAuthorizedCodeGrant is Map) { + if (preAuthorizedCodeGrant.containsKey('user_pin_required')) { + userPinRequired = + preAuthorizedCodeGrant['user_pin_required'] as bool; + } else if (preAuthorizedCodeGrant.containsKey('tx_code')) { + /// draft 13 + final txCodeMap = preAuthorizedCodeGrant['tx_code']; + + if (txCodeMap is Map) { + txCode = TxCode.fromJson(txCodeMap); + userPinRequired = true; + } + } } if (userPinRequired != null && userPinRequired) { @@ -418,6 +428,7 @@ class QRCodeScanCubit extends Cubit { state.copyWith( qrScanStatus: QrScanStatus.success, route: UserPinPage.route( + txCode: txCode, onCancel: () { goBack(); }, diff --git a/lib/dashboard/user_pin/model/model.dart b/lib/dashboard/user_pin/model/model.dart new file mode 100644 index 000000000..6bd819ff5 --- /dev/null +++ b/lib/dashboard/user_pin/model/model.dart @@ -0,0 +1 @@ +export 'tx_code.dart'; diff --git a/lib/dashboard/user_pin/model/tx_code.dart b/lib/dashboard/user_pin/model/tx_code.dart new file mode 100644 index 000000000..4858c3b0b --- /dev/null +++ b/lib/dashboard/user_pin/model/tx_code.dart @@ -0,0 +1,29 @@ +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'tx_code.g.dart'; + +@JsonSerializable() +class TxCode extends Equatable { + const TxCode({ + required this.length, + required this.inputMode, + required this.description, + }); + + factory TxCode.fromJson(Map json) => _$TxCodeFromJson(json); + + final int length; + @JsonKey(name: 'input_mode') + final String inputMode; + final String description; + + Map toJson() => _$TxCodeToJson(this); + + @override + List get props => [ + length, + inputMode, + description, + ]; +} diff --git a/lib/dashboard/user_pin/user_pin.dart b/lib/dashboard/user_pin/user_pin.dart index c0cf45bf2..5d2b28857 100644 --- a/lib/dashboard/user_pin/user_pin.dart +++ b/lib/dashboard/user_pin/user_pin.dart @@ -1 +1,2 @@ +export 'model/model.dart'; export 'view/user_pin_page.dart'; diff --git a/lib/dashboard/user_pin/view/user_pin_page.dart b/lib/dashboard/user_pin/view/user_pin_page.dart index c9246274c..edf904ce9 100644 --- a/lib/dashboard/user_pin/view/user_pin_page.dart +++ b/lib/dashboard/user_pin/view/user_pin_page.dart @@ -12,19 +12,23 @@ class UserPinPage extends StatelessWidget { super.key, required this.onProceed, required this.onCancel, + required this.txCode, }); final void Function(String pincode) onProceed; final Function onCancel; + final TxCode? txCode; static Route route({ required void Function(String pincode) onProceed, required Function onCancel, + required TxCode? txCode, }) { return MaterialPageRoute( builder: (_) => UserPinPage( onProceed: onProceed, onCancel: onCancel, + txCode: txCode, ), settings: const RouteSettings(name: '/UserPinPage'), ); @@ -38,6 +42,7 @@ class UserPinPage extends StatelessWidget { child: UserPinView( onCancel: onCancel, onProceed: onProceed, + txCode: txCode, ), ); } @@ -48,10 +53,12 @@ class UserPinView extends StatefulWidget { super.key, required this.onProceed, required this.onCancel, + required this.txCode, }); final void Function(String pincode) onProceed; final Function onCancel; + final TxCode? txCode; @override State createState() => _UserPinViewState(); @@ -80,15 +87,12 @@ class _UserPinViewState extends State { backgroundColor: Theme.of(context).colorScheme.background, scrollView: false, body: PinCodeWidget( - title: l10n.pleaseInsertTheSecredCodeReceived, + title: widget.txCode?.description ?? + l10n.pleaseInsertTheSecredCodeReceived, passwordEnteredCallback: _onPasscodeEntered, - passwordDigits: state - .model - .profileSetting - .selfSovereignIdentityOptions - .customOidc4vcProfile - .userPinDigits - .value, + passwordDigits: widget.txCode?.length ?? + state.model.profileSetting.selfSovereignIdentityOptions + .customOidc4vcProfile.userPinDigits.value, deleteButton: Text( l10n.delete, style: Theme.of(context).textTheme.labelLarge, diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 3862437f9..cf1f991cb 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -582,7 +582,12 @@ class OIDC4VC { if (clientSecret != null) tokenData['client_secret'] = clientSecret; } - if (userPin != null) tokenData['user_pin'] = userPin; + if (userPin != null) { + tokenData['user_pin'] = userPin; + + /// draft 13 + tokenData['tx_code'] = userPin; + } return tokenData; } From 9888a07bf5303d2ddac8bb874921a9b28703482b Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 6 Feb 2024 18:33:47 +0530 Subject: [PATCH 07/70] version update 2.2.16+378 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 50999492c..c74167a66 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.15+377 +version: 2.2.16+378 environment: sdk: ">=3.1.0 <4.0.0" From c59b9f142f0293fe45158846b6bf9a526c71c436 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 7 Feb 2024 09:03:52 +0530 Subject: [PATCH 08/70] Add new Profile in Wallet Profile menu GAIN POC (Experimental) at the end of the list #2346 --- assets/image/gainPOCExperimental.png | Bin 0 -> 17026 bytes lib/app/shared/constants/image_strings.dart | 3 ++ .../enum/type/profile/profile_type.dart | 10 ++-- .../helper_functions/helper_functions.dart | 2 +- lib/app/shared/widget/powered_by_text.dart | 21 ++++---- lib/app/shared/widget/wallet_logo.dart | 16 +++--- lib/app/view/app.dart | 1 + .../profile/cubit/profile_cubit.dart | 42 ++++++++++++++++ lib/dashboard/profile/models/profile.dart | 46 ++++++++++++++++++ lib/splash/view/splash_page.dart | 7 +-- 10 files changed, 119 insertions(+), 29 deletions(-) create mode 100644 assets/image/gainPOCExperimental.png diff --git a/assets/image/gainPOCExperimental.png b/assets/image/gainPOCExperimental.png new file mode 100644 index 0000000000000000000000000000000000000000..76c98fb3d753092c6b5c74f5579315030b3d0462 GIT binary patch literal 17026 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ӯ` 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 Z3-TWtSR+r;q;%XdLPbltMDbDh{{cSx!5jbp literal 0 HcmV?d00001 diff --git a/lib/app/shared/constants/image_strings.dart b/lib/app/shared/constants/image_strings.dart index 2506e33cd..44adc9fb5 100644 --- a/lib/app/shared/constants/image_strings.dart +++ b/lib/app/shared/constants/image_strings.dart @@ -7,6 +7,9 @@ class ImageStrings { static const String imagePath = 'assets/image'; static const String ebsiLogo = '$imagePath/ebsi_logo.png'; + static const String gainPOCExperimentalLogo = + '$imagePath/gainPOCExperimental.png'; + static const String cardMissing = '$imagePath/card_missing.png'; static const String employmentCertificateFront = '$imagePath/carte-attestation-employeur-recto.png'; diff --git a/lib/app/shared/enum/type/profile/profile_type.dart b/lib/app/shared/enum/type/profile/profile_type.dart index 46c087915..9a7e09c95 100644 --- a/lib/app/shared/enum/type/profile/profile_type.dart +++ b/lib/app/shared/enum/type/profile/profile_type.dart @@ -1,11 +1,6 @@ import 'package:altme/l10n/l10n.dart'; -enum ProfileType { - custom, - ebsiV3, - dutch, - enterprise, -} +enum ProfileType { custom, ebsiV3, dutch, enterprise, gainPOCExperimental } extension ProfileTypeX on ProfileType { String getTitle({ @@ -21,6 +16,8 @@ extension ProfileTypeX on ProfileType { return l10n.decentralizedIdentityInteropProfile; case ProfileType.enterprise: return name.isEmpty ? 'Enterprise' : name; + case ProfileType.gainPOCExperimental: + return 'GAIN POC (Experimental)'; } } @@ -31,6 +28,7 @@ extension ProfileTypeX on ProfileType { return false; case ProfileType.ebsiV3: case ProfileType.enterprise: + case ProfileType.gainPOCExperimental: return true; } } diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index b8d6da0a8..7df4a6b40 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -468,7 +468,7 @@ Future<(String, String)> getDidAndKid({ required String privateKey, required SecureStorageProvider secureStorage, required DidKeyType didKeyType, - DIDKitProvider? didKitProvider, + required DIDKitProvider? didKitProvider, }) async { late String did; late String kid; diff --git a/lib/app/shared/widget/powered_by_text.dart b/lib/app/shared/widget/powered_by_text.dart index 82ce7f7f1..ad973590c 100644 --- a/lib/app/shared/widget/powered_by_text.dart +++ b/lib/app/shared/widget/powered_by_text.dart @@ -1,3 +1,5 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/l10n/l10n.dart'; import 'package:flutter/material.dart'; class PoweredByText extends StatelessWidget { @@ -5,15 +7,14 @@ class PoweredByText extends StatelessWidget { @override Widget build(BuildContext context) { - // final l10n = context.l10n; - // return SizedBox( - // child: Text( - // '${l10n.poweredBy} ${Parameters.appName}', - // maxLines: 1, - // textAlign: TextAlign.center, - // style: Theme.of(context).textTheme.bodyLarge, - // ), - // ); - return const SizedBox.shrink(); + final l10n = context.l10n; + return SizedBox( + child: Text( + '${l10n.poweredBy} ${Parameters.appName}', + maxLines: 1, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyLarge, + ), + ); } } diff --git a/lib/app/shared/widget/wallet_logo.dart b/lib/app/shared/widget/wallet_logo.dart index da55039a2..55382d13a 100644 --- a/lib/app/shared/widget/wallet_logo.dart +++ b/lib/app/shared/widget/wallet_logo.dart @@ -35,6 +35,8 @@ class WalletLogo extends StatelessWidget { image = ImageStrings.ebsiLogo; case ProfileType.enterprise: image = profileModel.profileSetting.generalOptions.companyLogo; + case ProfileType.gainPOCExperimental: + image = ImageStrings.gainPOCExperimentalLogo; } return Column( @@ -61,13 +63,13 @@ class WalletLogo extends StatelessWidget { ), ), ), - if (showPoweredBy && - profileModel.profileType == ProfileType.enterprise) ...[ - if (profileModel.profileType.showSponseredBy) ...[ - const SizedBox(height: 5), - const Center(child: PoweredByText()), - ], - ], + // if (showPoweredBy && + // profileModel.profileType == ProfileType.enterprise) ...[ + // if (profileModel.profileType.showSponseredBy) ...[ + // const SizedBox(height: 5), + // const Center(child: PoweredByText()), + // ], + // ], ], ); } diff --git a/lib/app/view/app.dart b/lib/app/view/app.dart index 919221048..f54f771f5 100644 --- a/lib/app/view/app.dart +++ b/lib/app/view/app.dart @@ -69,6 +69,7 @@ class App extends StatelessWidget { create: (context) => ProfileCubit( secureStorageProvider: secureStorageProvider, oidc4vc: OIDC4VC(), + didKitProvider: DIDKitProvider(), ), ), BlocProvider( diff --git a/lib/dashboard/profile/cubit/profile_cubit.dart b/lib/dashboard/profile/cubit/profile_cubit.dart index 5b0f7d355..31a45facc 100644 --- a/lib/dashboard/profile/cubit/profile_cubit.dart +++ b/lib/dashboard/profile/cubit/profile_cubit.dart @@ -6,6 +6,7 @@ import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/dashboard/profile/models/models.dart'; import 'package:altme/polygon_id/cubit/polygon_id_cubit.dart'; import 'package:bloc/bloc.dart'; +import 'package:did_kit/did_kit.dart'; import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:oidc4vc/oidc4vc.dart'; @@ -21,12 +22,14 @@ class ProfileCubit extends Cubit { ProfileCubit({ required this.secureStorageProvider, required this.oidc4vc, + required this.didKitProvider, }) : super(ProfileState(model: ProfileModel.empty())) { load(); } final SecureStorageProvider secureStorageProvider; final OIDC4VC oidc4vc; + final DIDKitProvider didKitProvider; Timer? _timer; @@ -267,6 +270,7 @@ class ProfileCubit extends Cubit { didKeyType: DidKeyType.ebsiv3, privateKey: privateKey, secureStorage: secureStorageProvider, + didKitProvider: didKitProvider, ); profileModel = ProfileModel.ebsiV3( @@ -289,6 +293,7 @@ class ProfileCubit extends Cubit { didKeyType: DidKeyType.jwkP256, privateKey: privateKey, secureStorage: secureStorageProvider, + didKitProvider: didKitProvider, ); profileModel = ProfileModel.dutch( @@ -300,6 +305,29 @@ class ProfileCubit extends Cubit { clientSecret: randomString(12), ); + case ProfileType.gainPOCExperimental: + final privateKey = await getPrivateKey( + secureStorage: secureStorageProvider, + didKeyType: DidKeyType.p256, + oidc4vc: oidc4vc, + ); + + final (did, _) = await getDidAndKid( + didKeyType: DidKeyType.p256, + privateKey: privateKey, + secureStorage: secureStorageProvider, + didKitProvider: didKitProvider, + ); + + profileModel = ProfileModel.gainPOCExperimental( + polygonIdNetwork: polygonIdNetwork, + walletType: walletType, + walletProtectionType: walletProtectionType, + isDeveloperMode: isDeveloperMode, + clientId: did, + clientSecret: randomString(12), + ); + case ProfileType.enterprise: final enterpriseProfileSettingJsonString = await secureStorageProvider.get( @@ -544,6 +572,20 @@ class ProfileCubit extends Cubit { .selfSovereignIdentityOptions.customOidc4vcProfile.clientSecret, ), ); + case ProfileType.gainPOCExperimental: + await update( + ProfileModel.gainPOCExperimental( + polygonIdNetwork: state.model.polygonIdNetwork, + walletProtectionType: state.model.walletProtectionType, + isDeveloperMode: state.model.isDeveloperMode, + walletType: state.model.walletType, + enterpriseWalletName: state.model.enterpriseWalletName, + clientId: state.model.profileSetting.selfSovereignIdentityOptions + .customOidc4vcProfile.clientId, + clientSecret: state.model.profileSetting + .selfSovereignIdentityOptions.customOidc4vcProfile.clientSecret, + ), + ); case ProfileType.custom: final String customProfileSettingBackup = await secureStorageProvider.get( diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index a8bc61827..5d10824a0 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -122,6 +122,52 @@ class ProfileModel extends Equatable { ), ); + factory ProfileModel.gainPOCExperimental({ + required PolygonIdNetwork polygonIdNetwork, + required WalletType walletType, + required WalletProtectionType walletProtectionType, + required bool isDeveloperMode, + required String? clientId, + required String? clientSecret, + String? enterpriseWalletName, + }) => + ProfileModel( + enterpriseWalletName: enterpriseWalletName, + polygonIdNetwork: polygonIdNetwork, + walletType: walletType, + walletProtectionType: walletProtectionType, + isDeveloperMode: isDeveloperMode, + profileType: ProfileType.gainPOCExperimental, + profileSetting: ProfileSetting( + blockchainOptions: BlockchainOptions.initial(), + generalOptions: GeneralOptions.empty(), + helpCenterOptions: HelpCenterOptions.initial(), + discoverCardsOptions: DiscoverCardsOptions.initial(), + selfSovereignIdentityOptions: SelfSovereignIdentityOptions( + displayManageDecentralizedId: true, + customOidc4vcProfile: CustomOidc4VcProfile( + clientAuthentication: ClientAuthentication.clientId, + credentialManifestSupport: true, + cryptoHolderBinding: true, + defaultDid: DidKeyType.p256, + oidc4vciDraft: OIDC4VCIDraftType.draft13, + oidc4vpDraft: OIDC4VPDraftType.draft18, + scope: false, + securityLevel: false, + siopv2Draft: SIOPV2DraftType.draft12, + subjectSyntaxeType: SubjectSyntax.did, + userPinDigits: UserPinDigits.four, + clientId: clientId, + clientSecret: clientSecret, + vcFormatType: VCFormatType.vcSdJWT, + ), + ), + settingsMenu: SettingsMenu.initial(), + version: '', + walletSecurityOptions: WalletSecurityOptions.initial(), + ), + ); + final PolygonIdNetwork polygonIdNetwork; final WalletType walletType; final WalletProtectionType walletProtectionType; diff --git a/lib/splash/view/splash_page.dart b/lib/splash/view/splash_page.dart index f982e1c5b..1f013fcd9 100644 --- a/lib/splash/view/splash_page.dart +++ b/lib/splash/view/splash_page.dart @@ -249,11 +249,8 @@ class _SplashViewState extends State { const Spacer(flex: 1), SubTitle(profileModel: state.model), const Spacer(flex: 5), - if (state.model.profileType.showSponseredBy) - const PoweredByText() - else - const LoadingText(), - const SizedBox(height: 10), + // const LoadingText(), + // const SizedBox(height: 10), BlocBuilder( builder: (context, state) { return TweenAnimationBuilder( From ccf08965735c47398dddea6a0d68694a828b7066 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 7 Feb 2024 18:00:10 +0530 Subject: [PATCH 09/70] Support vcSDJWT credential partially --- .vscode/launch.json | 8 +---- .../home_credential_category_list.dart | 2 +- .../cubit/qr_code_scan_cubit.dart | 2 ++ lib/oidc4vc/add_oidc4vc_credential.dart | 36 +++++++++++++------ lib/oidc4vc/get_and_add_credential.dart | 3 ++ .../get_and_add_deffered_credential.dart | 3 ++ packages/oidc4vc/lib/src/vc_format_type.dart | 15 ++++++++ pubspec.lock | 28 +++++++-------- 8 files changed, 64 insertions(+), 33 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"] } ] } diff --git a/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_list.dart b/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_list.dart index 970942486..441baf113 100644 --- a/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_list.dart +++ b/lib/dashboard/home/tab_bar/credentials/list/widgets/home_credential_category_list.dart @@ -55,7 +55,7 @@ class HomeCredentialCategoryList extends StatelessWidget { } /// do not load the credential if vc format is different - if (vcFormatType.formattedString != element.getFormat) { + if (vcFormatType.value != element.getFormat) { return false; } 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 9688d8bc7..220f282ff 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 @@ -777,6 +777,7 @@ class QRCodeScanCubit extends Cubit { credentialsCubit: credentialsCubit, dioClient: client, oidc4vc: oidc4vc, + jwtDecode: jwtDecode, ); } catch (e) { emitError(e); @@ -1250,6 +1251,7 @@ class QRCodeScanCubit extends Cubit { clientId: clientId, clientSecret: clientSecret, profileCubit: profileCubit, + jwtDecode: jwtDecode, ); } diff --git a/lib/oidc4vc/add_oidc4vc_credential.dart b/lib/oidc4vc/add_oidc4vc_credential.dart index bfa0d8cee..c2095bc0c 100644 --- a/lib/oidc4vc/add_oidc4vc_credential.dart +++ b/lib/oidc4vc/add_oidc4vc_credential.dart @@ -5,32 +5,46 @@ import 'package:altme/credentials/credentials.dart'; import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/dashboard/home/tab_bar/credentials/models/activity/activity.dart'; import 'package:credential_manifest/credential_manifest.dart'; -import 'package:jose/jose.dart'; +import 'package:jwt_decode/jwt_decode.dart'; import 'package:oidc4vc/oidc4vc.dart'; import 'package:uuid/uuid.dart'; Future addOIDC4VCCredential({ required dynamic encodedCredentialFromOIDC4VC, required CredentialsCubit credentialsCubit, - String? issuer, required String credentialType, required bool isLastCall, required String format, - String? credentialIdToBeDeleted, required OpenIdConfiguration? openIdConfiguration, + required JWTDecode jwtDecode, + String? credentialIdToBeDeleted, + String? issuer, }) async { late Map credentialFromOIDC4VC; - if (format == 'jwt_vc' || format == 'jwt_vc_json') { + if (format == 'jwt_vc' || format == 'jwt_vc_json' || format == 'vc+sd-jwt') { //jwt_vc - final jws = JsonWebSignature.fromCompactSerialization( - encodedCredentialFromOIDC4VC['credential'] as String, - ); + final data = encodedCredentialFromOIDC4VC['credential'] as String; - final jsonContent = - jws.unverifiedPayload.jsonContent as Map; + final jsonContent = jwtDecode.parseJwt(data); - credentialFromOIDC4VC = jsonContent['vc'] as Map; + if (format == 'vc+sd-jwt') { + credentialFromOIDC4VC = jsonContent; + } else { + credentialFromOIDC4VC = jsonContent['vc'] as Map; + } + + if (format == 'vc+sd-jwt') { + /// type + if (!credentialFromOIDC4VC.containsKey('type')) { + credentialFromOIDC4VC['type'] = [credentialType]; + } + + ///credentialSubject + if (!credentialFromOIDC4VC.containsKey('credentialSubject')) { + credentialFromOIDC4VC['credentialSubject'] = {'type': credentialType}; + } + } /// id -> jti if (!credentialFromOIDC4VC.containsKey('id')) { @@ -86,7 +100,7 @@ Future addOIDC4VCCredential({ // 'urn:uuid:${const Uuid().v4()}'; // } - credentialFromOIDC4VC['jwt'] = encodedCredentialFromOIDC4VC['credential']; + credentialFromOIDC4VC['jwt'] = data; } else if (format == 'ldp_vc') { //ldp_vc diff --git a/lib/oidc4vc/get_and_add_credential.dart b/lib/oidc4vc/get_and_add_credential.dart index 492594845..d7103b488 100644 --- a/lib/oidc4vc/get_and_add_credential.dart +++ b/lib/oidc4vc/get_and_add_credential.dart @@ -4,6 +4,7 @@ import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/oidc4vc/oidc4vc.dart'; import 'package:did_kit/did_kit.dart'; +import 'package:jwt_decode/jwt_decode.dart'; import 'package:oidc4vc/oidc4vc.dart'; import 'package:secure_storage/secure_storage.dart'; import 'package:uuid/uuid.dart'; @@ -30,6 +31,7 @@ Future getAndAddCredential({ required DidKeyType didKeyType, required String? clientId, required String? clientSecret, + required JWTDecode jwtDecode, }) async { final privateKey = await fetchPrivateKey( isEBSIV3: isEBSIV3, @@ -150,6 +152,7 @@ Future getAndAddCredential({ isLastCall && i + 1 == encodedCredentialOrFutureTokens.length, format: format, openIdConfiguration: openIdConfiguration, + jwtDecode: jwtDecode, ); } } diff --git a/lib/oidc4vc/get_and_add_deffered_credential.dart b/lib/oidc4vc/get_and_add_deffered_credential.dart index 2e2dc6a06..80d36331d 100644 --- a/lib/oidc4vc/get_and_add_deffered_credential.dart +++ b/lib/oidc4vc/get_and_add_deffered_credential.dart @@ -3,6 +3,7 @@ import 'package:altme/credentials/credentials.dart'; import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/oidc4vc/oidc4vc.dart'; +import 'package:jwt_decode/jwt_decode.dart'; import 'package:oidc4vc/oidc4vc.dart'; Future getAndAddDefferedCredential({ @@ -10,6 +11,7 @@ Future getAndAddDefferedCredential({ required CredentialsCubit credentialsCubit, required DioClient dioClient, required OIDC4VC oidc4vc, + required JWTDecode jwtDecode, }) async { final (_, issuer) = await getIssuerAndPreAuthorizedCode( scannedResponse: credentialModel.pendingInfo!.url, @@ -32,5 +34,6 @@ Future getAndAddDefferedCredential({ format: credentialModel.pendingInfo!.format, credentialIdToBeDeleted: credentialModel.id, openIdConfiguration: null, + jwtDecode: jwtDecode, ); } diff --git a/packages/oidc4vc/lib/src/vc_format_type.dart b/packages/oidc4vc/lib/src/vc_format_type.dart index 53e249cba..1654f1099 100644 --- a/packages/oidc4vc/lib/src/vc_format_type.dart +++ b/packages/oidc4vc/lib/src/vc_format_type.dart @@ -28,4 +28,19 @@ extension VCFormatTypeX on VCFormatType { return 'vc+sd-jwt (Experimental)'; } } + + String get value { + switch (this) { + case VCFormatType.ldpVc: + return 'ldp_vc'; + case VCFormatType.jwtVc: + return 'jwt_vc'; + case VCFormatType.jwtVcJson: + return 'jwt_vc_json'; + case VCFormatType.jwtVcJsonLd: + return 'jwt_vc_json-ld'; + case VCFormatType.vcSdJWT: + return 'vc+sd-jwt'; + } + } } diff --git a/pubspec.lock b/pubspec.lock index c7261673c..fe526d711 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -318,10 +318,10 @@ packages: dependency: transitive description: name: camera_platform_interface - sha256: e971ebca970f7cfee396f76ef02070b5e441b4aa04942da9c108d725f57bbd32 + sha256: fceb2c36038b6392317b1d5790c6ba9e6ca9f1da3031181b8bea03882bf9387a url: "https://pub.dev" source: hosted - version: "2.7.2" + version: "2.7.3" camera_web: dependency: transitive description: @@ -856,10 +856,10 @@ packages: dependency: "direct main" description: name: flutter_chat_ui - sha256: "6a4712026429d3b28547bd3d147ded44f8dd53dacc1ff14113693d7b7dd14382" + sha256: c8580c85e2d29359ffc84147e643d08d883eb6e757208652377f0105ef58807f url: "https://pub.dev" source: hosted - version: "1.6.10" + version: "1.6.12" flutter_dotenv: dependency: "direct main" description: @@ -1628,10 +1628,10 @@ packages: dependency: "direct main" description: name: open_filex - sha256: a6c95237767c5647e68b71a476602fcf4f1bfc530c126265e53addae22ef5fc2 + sha256: "74e2280754cf8161e860746c3181db2c996d6c1909c7057b738ede4a469816b8" url: "https://pub.dev" source: hosted - version: "4.3.4" + version: "4.4.0" package_config: dependency: transitive description: @@ -1908,10 +1908,10 @@ packages: dependency: "direct main" description: name: pretty_qr_code - sha256: "2163eb6e2231f3e8b2b2503d94f31d8bd6846bc428e9b5cf499c05fda0b34a16" + sha256: "47a0fde3967e01ea31985d1a11a998fab1ab900becdba592e9abb0a4034b807e" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.1" provider: dependency: transitive description: @@ -2473,26 +2473,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: "18f6690295af52d081f6808f2f7c69f0eed6d7e23a71539d75f4aeb8f0062172" + sha256: "4ac59808bbfca6da38c99f415ff2d3a5d7ca0a6b4809c71d9cf30fba5daf9752" url: "https://pub.dev" source: hosted - version: "1.1.9+2" + version: "1.1.10+1" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: "531d20465c10dfac7f5cd90b60bbe4dd9921f1ec4ca54c83ebb176dbacb7bb2d" + sha256: f3247e7ab0ec77dc759263e68394990edc608fb2b480b80db8aa86ed09279e33 url: "https://pub.dev" source: hosted - version: "1.1.9+2" + version: "1.1.10+1" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: "03012b0a33775c5530576b70240308080e1d5050f0faf000118c20e6463bc0ad" + sha256: "18489bdd8850de3dd7ca8a34e0c446f719ec63e2bab2e7a8cc66a9028dd76c5a" url: "https://pub.dev" source: hosted - version: "1.1.9+2" + version: "1.1.10+1" vector_math: dependency: transitive description: From c3bf9c9620401456d7a42986ba293ee42a756cff Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 7 Feb 2024 18:02:59 +0530 Subject: [PATCH 10/70] version update to 2.2.17+379 --- .vscode/launch.json | 8 +++++++- pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) 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" + ] } ] } diff --git a/pubspec.yaml b/pubspec.yaml index c74167a66..e8ef1881e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.16+378 +version: 2.2.17+379 environment: sdk: ">=3.1.0 <4.0.0" From a4f4b703c0f82d5127d3dbc05bf1bddd9dee6325 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Wed, 7 Feb 2024 17:49:04 +0000 Subject: [PATCH 11/70] When switch Crypto Holder BInding is Off it fails #2359 --- packages/oidc4vc/lib/src/oidc4vc.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index cf1f991cb..e776d9156 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -754,11 +754,10 @@ class OIDC4VC { String? cnonce, Map? credentialDefinition, }) async { - final vcJwt = await getIssuerJwt(issuerTokenParameters, cnonce); - final credentialData = {}; if (cryptoHolderBinding) { + final vcJwt = await getIssuerJwt(issuerTokenParameters, cnonce); credentialData['proof'] = { 'proof_type': 'jwt', 'jwt': vcJwt, From d7b26257f6267e242439fa63a7b7773931143735 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Wed, 7 Feb 2024 17:49:43 +0000 Subject: [PATCH 12/70] version: 2.2.18+380 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index e8ef1881e..f7931923e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.17+379 +version: 2.2.18+380 environment: sdk: ">=3.1.0 <4.0.0" From f7cfbc3d9166c9ea9dc25415f67e94a8c98d279d Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 8 Feb 2024 13:49:31 +0530 Subject: [PATCH 13/70] Draft 13 : issuer metada to display VC of vc+sd-jwt VCs in card details #2351 --- .../detail/view/credentials_details_page.dart | 94 ++++--------------- .../detail/widgets/claims_data.dart | 68 ++++++++++++++ .../widgets/deferred_credential_data.dart | 43 +++++++++ .../detail/widgets/developer_details.dart | 66 +++++++++++++ .../credentials/detail/widgets/widgets.dart | 3 + .../credential_model/credential_model.dart | 6 ++ lib/oidc4vc/add_oidc4vc_credential.dart | 64 +++++++++---- packages/oidc4vc/lib/src/oidc4vc.dart | 14 ++- 8 files changed, 260 insertions(+), 98 deletions(-) create mode 100644 lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart create mode 100644 lib/dashboard/home/tab_bar/credentials/detail/widgets/deferred_credential_data.dart create mode 100644 lib/dashboard/home/tab_bar/credentials/detail/widgets/developer_details.dart diff --git a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart index 53fe3cec3..abe6c6a73 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart @@ -165,14 +165,6 @@ class _CredentialsDetailsViewState extends State { reversedList.removeLast(); } - final String issuerDid = - widget.credentialModel.credentialPreview.issuer; - final String subjectDid = widget - .credentialModel.credentialPreview.credentialSubjectModel.id ?? - ''; - final String type = - widget.credentialModel.credentialPreview.type.toString(); - final vcFormatType = context .read() .state @@ -275,6 +267,7 @@ class _CredentialsDetailsViewState extends State { const SizedBox(height: 10), if (state.credentialDetailTabStatus == CredentialDetailTabStatus.informations) ...[ + /// active status if (isSecure || (!isSecure && state.credentialStatus == @@ -284,6 +277,8 @@ class _CredentialsDetailsViewState extends State { credentialStatus: state.credentialStatus, ), ], + + /// credential manifest details if (credentialManifestSupport && outputDescriptors != null) ...[ const SizedBox(height: 10), @@ -292,6 +287,8 @@ class _CredentialsDetailsViewState extends State { credentialModel: widget.credentialModel, ), ], + + /// display widget if (!credentialManifestSupport && widget.credentialModel.display != null) ...[ const SizedBox(height: 10), @@ -299,6 +296,8 @@ class _CredentialsDetailsViewState extends State { display: widget.credentialModel.display!, ), ], + + //// wallet attestation data if (widget.credentialModel.credentialPreview .credentialSubjectModel is WalletCredentialModel) ...[ @@ -306,79 +305,26 @@ class _CredentialsDetailsViewState extends State { credentialModel: widget.credentialModel, ), ], + + /// developer mode data if (widget.credentialModel.pendingInfo == null && isDeveloperMode) ...[ - const SizedBox(height: 10), - CredentialField( - padding: EdgeInsets.zero, - title: l10n.format, - value: widget.credentialModel.getFormat, - titleColor: - Theme.of(context).colorScheme.titleColor, - valueColor: - Theme.of(context).colorScheme.valueColor, - ), - const SizedBox(height: 10), - CredentialField( - padding: EdgeInsets.zero, - title: l10n.issuerDID, - value: issuerDid, - titleColor: - Theme.of(context).colorScheme.titleColor, - valueColor: - Theme.of(context).colorScheme.valueColor, - ), - if (widget.credentialModel.credentialPreview - .credentialSubjectModel - is! WalletCredentialModel) ...[ - const SizedBox(height: 10), - CredentialField( - padding: EdgeInsets.zero, - title: l10n.subjectDID, - value: subjectDid, - titleColor: - Theme.of(context).colorScheme.titleColor, - valueColor: - Theme.of(context).colorScheme.valueColor, - ), - ], - const SizedBox(height: 10), - CredentialField( - padding: EdgeInsets.zero, - title: l10n.type, - value: type, - titleColor: - Theme.of(context).colorScheme.titleColor, - valueColor: - Theme.of(context).colorScheme.valueColor, + DeveloperDetails( + credentialModel: widget.credentialModel, ), ], + + /// deferred credential data if (widget.credentialModel.pendingInfo != null) ...[ - const SizedBox(height: 10), - CredentialField( - padding: EdgeInsets.zero, - title: l10n.issuer, - value: - widget.credentialModel.pendingInfo!.issuer ?? - '', - titleColor: - Theme.of(context).colorScheme.titleColor, - valueColor: - Theme.of(context).colorScheme.valueColor, - ), - const SizedBox(height: 10), - CredentialField( - padding: EdgeInsets.zero, - title: l10n.dateOfRequest, - value: UiDate.formatDate( - widget.credentialModel.pendingInfo!.requestedAt, - ), - titleColor: - Theme.of(context).colorScheme.titleColor, - valueColor: - Theme.of(context).colorScheme.valueColor, + DeferredCredentialData( + credentialModel: widget.credentialModel, ), ], + + /// claims data , from draft 13 + if (widget.credentialModel.claims != null) ...[ + ClaimsData(credentialModel: widget.credentialModel), + ], ], if (state.credentialDetailTabStatus == CredentialDetailTabStatus.activity) ...[ diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart new file mode 100644 index 000000000..da37a7f51 --- /dev/null +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart @@ -0,0 +1,68 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/theme/theme.dart'; +import 'package:flutter/material.dart'; + +class ClaimsData extends StatelessWidget { + const ClaimsData({ + super.key, + required this.credentialModel, + }); + + final CredentialModel credentialModel; + + @override + Widget build(BuildContext context) { + final claims = credentialModel.claims; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: claims!.entries.map((MapEntry map) { + final key = map.key; + final value = map.value; + + String title = key; + String data = value.toString(); + + if (value is! Map) return Container(); + + if (value.isEmpty) return Container(); + + if (value.containsKey('mandatory')) { + final mandatory = value['mandatory']; + if (mandatory is! bool) return Container(); + + if (!mandatory) return Container(); + } + + if (value.containsKey('display')) { + final displays = value['display']; + if (displays is! List) return Container(); + if (displays.length < 2) return Container(); + + for (final display in displays) { + if (display is! Map) return Container(); + + if (display['name'] == null) return Container(); + } + + title = displays[0]['name'].toString(); + data = displays[1]['name'].toString(); + } else { + return Container(); + } + + return Padding( + padding: const EdgeInsets.only(top: 10), + child: CredentialField( + padding: EdgeInsets.zero, + title: title, + value: data, + titleColor: Theme.of(context).colorScheme.titleColor, + valueColor: Theme.of(context).colorScheme.valueColor, + ), + ); + }).toList(), + ); + } +} diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/deferred_credential_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/deferred_credential_data.dart new file mode 100644 index 000000000..f3423aff8 --- /dev/null +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/deferred_credential_data.dart @@ -0,0 +1,43 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:altme/theme/theme.dart'; +import 'package:flutter/material.dart'; + +class DeferredCredentialData extends StatelessWidget { + const DeferredCredentialData({ + super.key, + required this.credentialModel, + }); + + final CredentialModel credentialModel; + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + CredentialField( + padding: EdgeInsets.zero, + title: l10n.issuer, + value: credentialModel.pendingInfo!.issuer ?? '', + titleColor: Theme.of(context).colorScheme.titleColor, + valueColor: Theme.of(context).colorScheme.valueColor, + ), + const SizedBox(height: 10), + CredentialField( + padding: EdgeInsets.zero, + title: l10n.dateOfRequest, + value: UiDate.formatDate( + credentialModel.pendingInfo!.requestedAt, + ), + titleColor: Theme.of(context).colorScheme.titleColor, + valueColor: Theme.of(context).colorScheme.valueColor, + ), + ], + ); + } +} diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/developer_details.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/developer_details.dart new file mode 100644 index 000000000..e0a78bfdf --- /dev/null +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/developer_details.dart @@ -0,0 +1,66 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:altme/theme/theme.dart'; +import 'package:flutter/material.dart'; + +class DeveloperDetails extends StatelessWidget { + const DeveloperDetails({ + super.key, + required this.credentialModel, + }); + + final CredentialModel credentialModel; + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + + final String issuerDid = credentialModel.credentialPreview.issuer; + final String subjectDid = + credentialModel.credentialPreview.credentialSubjectModel.id ?? ''; + final String type = credentialModel.credentialPreview.type.toString(); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + CredentialField( + padding: EdgeInsets.zero, + title: l10n.format, + value: credentialModel.getFormat, + titleColor: Theme.of(context).colorScheme.titleColor, + valueColor: Theme.of(context).colorScheme.valueColor, + ), + const SizedBox(height: 10), + CredentialField( + padding: EdgeInsets.zero, + title: l10n.issuerDID, + value: issuerDid, + titleColor: Theme.of(context).colorScheme.titleColor, + valueColor: Theme.of(context).colorScheme.valueColor, + ), + if (credentialModel.credentialPreview.credentialSubjectModel + is! WalletCredentialModel && + subjectDid.isNotEmpty) ...[ + const SizedBox(height: 10), + CredentialField( + padding: EdgeInsets.zero, + title: l10n.subjectDID, + value: subjectDid, + titleColor: Theme.of(context).colorScheme.titleColor, + valueColor: Theme.of(context).colorScheme.valueColor, + ), + ], + const SizedBox(height: 10), + CredentialField( + padding: EdgeInsets.zero, + title: l10n.type, + value: type, + titleColor: Theme.of(context).colorScheme.titleColor, + valueColor: Theme.of(context).colorScheme.valueColor, + ), + ], + ); + } +} diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart index 705c4932d..96978f922 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart @@ -1 +1,4 @@ +export 'claims_data.dart'; export 'credential_active_status.dart'; +export 'deferred_credential_data.dart'; +export 'developer_details.dart'; diff --git a/lib/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart b/lib/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart index 4b0ab2e41..c09bc54ff 100644 --- a/lib/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart +++ b/lib/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart @@ -31,6 +31,7 @@ class CredentialModel extends Equatable { this.activities = const [], this.jwt, this.pendingInfo, + this.claims, }); factory CredentialModel.fromJson(Map json) { @@ -75,6 +76,7 @@ class CredentialModel extends Equatable { activities: activities, jwt: oldCredentialModel.jwt, format: oldCredentialModel.format, + claims: oldCredentialModel.claims, ); } @@ -98,6 +100,7 @@ class CredentialModel extends Equatable { final String? jwt; final PendingInfo? pendingInfo; final String? format; + final Map? claims; Map toJson() => _$CredentialModelToJson(this); @@ -117,6 +120,7 @@ class CredentialModel extends Equatable { String? jwt, PendingInfo? pendingInfo, String? format, + Map? claims, }) { return CredentialModel( id: id ?? this.id, @@ -134,6 +138,7 @@ class CredentialModel extends Equatable { jwt: jwt ?? this.jwt, pendingInfo: pendingInfo ?? this.pendingInfo, format: format ?? this.format, + claims: claims ?? this.claims, ); } @@ -259,5 +264,6 @@ class CredentialModel extends Equatable { jwt, pendingInfo, format, + claims, ]; } diff --git a/lib/oidc4vc/add_oidc4vc_credential.dart b/lib/oidc4vc/add_oidc4vc_credential.dart index c2095bc0c..8cf7e48bd 100644 --- a/lib/oidc4vc/add_oidc4vc_credential.dart +++ b/lib/oidc4vc/add_oidc4vc_credential.dart @@ -145,28 +145,60 @@ Future addOIDC4VCCredential({ } } - final newCredentialModel = CredentialModel.fromJson(newCredential); - Display? display; - if (newCredentialModel.credentialManifest == null && - openIdConfiguration?.credentialsSupported != null) { - final credentialsSupported = openIdConfiguration!.credentialsSupported!; - final CredentialsSupported? credSupported = - credentialsSupported.firstWhereOrNull( - (CredentialsSupported credentialsSupported) => - credentialsSupported.id != null && - credentialsSupported.id == credentialType, - ); - - if (credSupported != null && credSupported.display != null) { - display = credSupported.display!.firstWhereOrNull( - (Display display) => - display.locale == 'en-US' || display.locale == 'en-GB', + if (!newCredential.containsKey('credential_manifest')) { + if (openIdConfiguration?.credentialsSupported != null) { + final credentialsSupported = openIdConfiguration!.credentialsSupported!; + final CredentialsSupported? credSupported = + credentialsSupported.firstWhereOrNull( + (CredentialsSupported credentialsSupported) => + credentialsSupported.id != null && + credentialsSupported.id == credentialType, ); + + if (credSupported != null && credSupported.display != null) { + display = credSupported.display!.firstWhereOrNull( + (Display display) => + display.locale == 'en-US' || display.locale == 'en-GB', + ); + } + } else if (openIdConfiguration?.credentialConfigurationsSupported != null) { + final credentialsSupported = + openIdConfiguration!.credentialConfigurationsSupported; + + if ((credentialsSupported is Map) && + credentialsSupported.containsKey(credentialType)) { + final credSupported = credentialsSupported[credentialType]; + + if (credSupported is Map) { + /// claims + if (credSupported.containsKey('claims')) { + newCredential['claims'] = credSupported['claims']; + } + + /// display + if (credSupported.containsKey('display')) { + final displayData = credSupported['display']; + + if (displayData is List) { + final displays = displayData + .map((ele) => Display.fromJson(ele as Map)) + .toList(); + + display = displays.firstWhereOrNull( + (Display display) => + display.locale == 'en-US' || display.locale == 'en-GB', + ); + } + } + } + } } } + final newCredentialModel = CredentialModel.fromJson(newCredential); + final credentialModel = CredentialModel.copyWithData( oldCredentialModel: newCredentialModel, newData: credentialFromOIDC4VC, diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index e776d9156..e6534b1bb 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -517,14 +517,14 @@ class OIDC4VC { data: credentialData, ); - final credentialResponselData = credentialResponse.data; + final credentialResponseData = credentialResponse.data; - if (credentialResponselData is Map && - credentialResponselData.containsKey('c_nonce')) { - cnonce = credentialResponselData['c_nonce'].toString(); + if (credentialResponseData is Map && + credentialResponseData.containsKey('c_nonce')) { + cnonce = credentialResponseData['c_nonce'].toString(); } - return credentialResponselData; + return credentialResponseData; } /// get Deferred credential from url @@ -1383,9 +1383,7 @@ class OIDC4VC { }) async { final url = '$baseUrl/.well-known/openid-configuration'; - if (!isAuthorizationServer && - oidc4vciDraftType != null && - oidc4vciDraftType == OIDC4VCIDraftType.draft11) { + if (!isAuthorizationServer) { final data = await getOpenIdConfigSecondMethod(baseUrl); return data; } From d3dc7a3ef51736e9c2ee278bb67bb79a0d0a84ba Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 9 Feb 2024 13:55:16 +0530 Subject: [PATCH 14/70] Support long client secret #2369 --- .../ssi/oidc4vc_settngs/widget/client_credentials_widget.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_credentials_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_credentials_widget.dart index 4cfd4b3e7..9337b794b 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_credentials_widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_credentials_widget.dart @@ -176,7 +176,6 @@ class ClientCredentialsWidget extends StatelessWidget { controller: clientSecretController, style: Theme.of(context).textTheme.labelMedium, maxLines: 1, - maxLength: 12, decoration: const InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.all( From c6e11bd02475293c2d668e716327c1bc46e4590c Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 9 Feb 2024 13:58:03 +0530 Subject: [PATCH 15/70] Manage authorization server url --- packages/oidc4vc/lib/src/oidc4vc.dart | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index e6534b1bb..1ff2cc62d 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -643,8 +643,12 @@ class OIDC4VC { }) async { var tokenEndPoint = '$issuer/token'; - final authorizationServer = openIdConfiguration.authorizationServer; - if (authorizationServer != null) { + if (openIdConfiguration.tokenEndpoint != null) { + tokenEndPoint = openIdConfiguration.tokenEndpoint!; + } else { + final authorizationServer = + openIdConfiguration.authorizationServer ?? issuer; + final authorizationServerConfiguration = await getOpenIdConfig( baseUrl: authorizationServer, isAuthorizationServer: true, @@ -654,11 +658,8 @@ class OIDC4VC { if (authorizationServerConfiguration.tokenEndpoint != null) { tokenEndPoint = authorizationServerConfiguration.tokenEndpoint!; } - } else { - if (openIdConfiguration.tokenEndpoint != null) { - tokenEndPoint = openIdConfiguration.tokenEndpoint!; - } } + return tokenEndPoint; } @@ -790,11 +791,14 @@ class OIDC4VC { case OIDC4VCIDraftType.draft13: credentialData['format'] = format; - if (credentialDefinition == null) { - throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + if (format == VCFormatType.vcSdJWT.value) { + credentialData['vct'] = 'sth'; + } else { + if (credentialDefinition == null) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } + credentialData['credential_definition'] = credentialDefinition; } - - credentialData['credential_definition'] = credentialDefinition; } return credentialData; From e8ea2118821cf6b7b5adb6b70728c29b82f1de27 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 9 Feb 2024 09:36:36 +0000 Subject: [PATCH 16/70] moving ClientCredentialsWidget after ClientAuthenticationWidget #2369 --- .../drawer/ssi/oidc4vc_settngs/view/oidc4vc_settings_menu.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c24331766..f12ccaaa3 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 @@ -40,7 +40,6 @@ class Oidc4vcSettingMenuView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SecurityLevelWidget(), - const ClientCredentialsWidget(), const SixOrForUserPinWidget(), const DidKeyTypeWidget(), const DraftTypeWidget(), @@ -49,6 +48,7 @@ class Oidc4vcSettingMenuView extends StatelessWidget { const CryptographicHolderBindingWidget(), const ScopeParameterWidget(), const ClientAuthenticationWidget(), + const ClientCredentialsWidget(), const VCFormatWidget(), DrawerItem( title: l10n.clientMetadata, From ec029c8b78c9fdcc4fc00d98e65af9f0c7581595 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 9 Feb 2024 16:37:38 +0530 Subject: [PATCH 17/70] OIDC4VC setting add new switch #2370 --- lib/chat_room/cubit/chat_room_cubit.dart | 4 + .../view/oidc4vc_settings_menu.dart | 1 + .../widget/proof_header_widget.dart | 73 +++++++++++++++++++ .../ssi/oidc4vc_settngs/widget/widget.dart | 1 + .../profile/cubit/profile_cubit.dart | 3 + lib/dashboard/profile/models/profile.dart | 3 + .../profile/models/profile_setting.dart | 6 ++ .../cubit/qr_code_scan_cubit.dart | 2 + lib/l10n/arb/app_en.arb | 4 +- lib/l10n/untranslated.json | 8 ++ lib/oidc4vc/get_and_add_credential.dart | 1 + .../cubit/initialization_cubit.dart | 1 + lib/scan/cubit/scan_cubit.dart | 8 +- packages/oidc4vc/lib/oidc4vc.dart | 1 + .../lib/src/issuer_token_parameters.dart | 1 + packages/oidc4vc/lib/src/oidc4vc.dart | 26 +++++-- .../oidc4vc/lib/src/proof_header_type.dart | 15 ++++ .../oidc4vc/lib/src/token_parameters.dart | 4 + .../lib/src/verifier_token_parameters.dart | 3 +- 19 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/proof_header_widget.dart create mode 100644 packages/oidc4vc/lib/src/proof_header_type.dart diff --git a/lib/chat_room/cubit/chat_room_cubit.dart b/lib/chat_room/cubit/chat_room_cubit.dart index 21c9b0a7c..301d1294c 100644 --- a/lib/chat_room/cubit/chat_room_cubit.dart +++ b/lib/chat_room/cubit/chat_room_cubit.dart @@ -266,11 +266,15 @@ abstract class ChatRoomCubit extends Cubit { if (_roomId == null || _roomId!.isEmpty) { final p256KeyForWallet = await getWalletP256Key(secureStorageProvider); + final customOidc4vcProfile = profileCubit.state.model.profileSetting + .selfSovereignIdentityOptions.customOidc4vcProfile; + final tokenParameters = TokenParameters( privateKey: jsonDecode(p256KeyForWallet) as Map, did: '', // just added as it is required field mediaType: MediaType.basic, // just added as it is required field useJWKThumbPrint: true, // just added as it is required field + proofHeaderType: customOidc4vcProfile.proofHeader, ); final helpCenterOptions = 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 f12ccaaa3..97c6a310e 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 @@ -50,6 +50,7 @@ class Oidc4vcSettingMenuView extends StatelessWidget { const ClientAuthenticationWidget(), const ClientCredentialsWidget(), const VCFormatWidget(), + const ProofHeaderWidget(), DrawerItem( title: l10n.clientMetadata, onTap: () { diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/proof_header_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/proof_header_widget.dart new file mode 100644 index 000000000..121f67bab --- /dev/null +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/proof_header_widget.dart @@ -0,0 +1,73 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:altme/theme/theme.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +class ProofHeaderWidget extends StatelessWidget { + const ProofHeaderWidget({super.key}); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + return BlocBuilder( + builder: (context, state) { + return OptionContainer( + title: l10n.proofHeader, + subtitle: l10n.proofHeaderSubtitle, + body: ListView.builder( + itemCount: ProofHeaderType.values.length, + shrinkWrap: true, + physics: const ScrollPhysics(), + padding: EdgeInsets.zero, + itemBuilder: (context, index) { + final proofHeaderType = ProofHeaderType.values[index]; + return Column( + children: [ + if (index != 0) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Divider( + height: 0, + color: Theme.of(context).colorScheme.borderColor, + ), + ), + ListTile( + onTap: () { + context.read().updateProfileSetting( + proofHeaderType: proofHeaderType, + ); + }, + shape: const RoundedRectangleBorder( + side: BorderSide( + color: Color(0xFFDDDDEE), + width: 0.5, + ), + ), + title: Text( + proofHeaderType.formattedString, + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: Theme.of(context).colorScheme.onPrimary, + ), + ), + trailing: Icon( + state.model.profileSetting.selfSovereignIdentityOptions + .customOidc4vcProfile.proofHeader == + proofHeaderType + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + size: Sizes.icon2x, + color: Theme.of(context).colorScheme.onPrimary, + ), + ), + ], + ); + }, + ), + ); + }, + ); + } +} diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart index fd43026fc..62d9b9e4f 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart @@ -5,6 +5,7 @@ export 'cryptograhic_holder_binding.dart'; export 'did_key_type_widget.dart'; export 'draft_type_widget.dart'; export 'option_container.dart'; +export 'proof_header_widget.dart'; export 'scope_parameter.dart'; export 'security_level_widget.dart'; export 'six_or_four_pin_widget.dart'; diff --git a/lib/dashboard/profile/cubit/profile_cubit.dart b/lib/dashboard/profile/cubit/profile_cubit.dart index 31a45facc..ea8986e4c 100644 --- a/lib/dashboard/profile/cubit/profile_cubit.dart +++ b/lib/dashboard/profile/cubit/profile_cubit.dart @@ -204,6 +204,7 @@ class ProfileCubit extends Cubit { clientSecret: customProfileBackup.containsKey('clientSecret') ? customProfileBackup['clientSecret'].toString() : randomString(12), + proofHeader: ProofHeaderType.kid, ), ), settingsMenu: SettingsMenu.initial(), @@ -467,6 +468,7 @@ class ProfileCubit extends Cubit { OIDC4VCIDraftType? oidc4vciDraftType, SubjectSyntax? subjectSyntax, VCFormatType? vcFormatType, + ProofHeaderType? proofHeaderType, }) async { final profileModel = state.model.copyWith( profileSetting: state.model.profileSetting.copyWith( @@ -486,6 +488,7 @@ class ProfileCubit extends Cubit { userPinDigits: userPinDigits, defaultDid: didKeyType, securityLevel: securityLevel, + proofHeader: proofHeaderType, scope: scope, cryptoHolderBinding: cryptoHolderBinding, credentialManifestSupport: credentialManifestSupport, diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index 5d10824a0..89468cb00 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -62,6 +62,7 @@ class ProfileModel extends Equatable { oidc4vpDraft: OIDC4VPDraftType.draft10, scope: false, securityLevel: false, + proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, subjectSyntaxeType: SubjectSyntax.did, userPinDigits: UserPinDigits.four, @@ -108,6 +109,7 @@ class ProfileModel extends Equatable { oidc4vpDraft: OIDC4VPDraftType.draft10, scope: false, securityLevel: false, + proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, subjectSyntaxeType: SubjectSyntax.did, userPinDigits: UserPinDigits.four, @@ -154,6 +156,7 @@ class ProfileModel extends Equatable { oidc4vpDraft: OIDC4VPDraftType.draft18, scope: false, securityLevel: false, + proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, subjectSyntaxeType: SubjectSyntax.did, userPinDigits: UserPinDigits.four, diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index 63cd62507..99562dcfd 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -522,6 +522,7 @@ class CustomOidc4VcProfile extends Equatable { required this.clientId, required this.clientSecret, this.vcFormatType = VCFormatType.ldpVc, + this.proofHeader = ProofHeaderType.kid, }); factory CustomOidc4VcProfile.initial() => CustomOidc4VcProfile( @@ -532,6 +533,7 @@ class CustomOidc4VcProfile extends Equatable { oidc4vciDraft: OIDC4VCIDraftType.draft11, oidc4vpDraft: OIDC4VPDraftType.draft18, scope: false, + proofHeader: ProofHeaderType.kid, securityLevel: false, siopv2Draft: SIOPV2DraftType.draft12, subjectSyntaxeType: SubjectSyntax.did, @@ -555,6 +557,7 @@ class CustomOidc4VcProfile extends Equatable { final OIDC4VCIDraftType oidc4vciDraft; final OIDC4VPDraftType oidc4vpDraft; final bool scope; + final ProofHeaderType proofHeader; final bool securityLevel; final SIOPV2DraftType siopv2Draft; final SubjectSyntax subjectSyntaxeType; @@ -574,6 +577,7 @@ class CustomOidc4VcProfile extends Equatable { OIDC4VCIDraftType? oidc4vciDraft, OIDC4VPDraftType? oidc4vpDraft, bool? scope, + ProofHeaderType? proofHeader, bool? securityLevel, SIOPV2DraftType? siopv2Draft, SubjectSyntax? subjectSyntaxeType, @@ -589,6 +593,7 @@ class CustomOidc4VcProfile extends Equatable { oidc4vciDraft: oidc4vciDraft ?? this.oidc4vciDraft, oidc4vpDraft: oidc4vpDraft ?? this.oidc4vpDraft, scope: scope ?? this.scope, + proofHeader: proofHeader ?? this.proofHeader, securityLevel: securityLevel ?? this.securityLevel, siopv2Draft: siopv2Draft ?? this.siopv2Draft, subjectSyntaxeType: subjectSyntaxeType ?? this.subjectSyntaxeType, @@ -609,6 +614,7 @@ class CustomOidc4VcProfile extends Equatable { oidc4vciDraft, oidc4vpDraft, scope, + proofHeader, securityLevel, siopv2Draft, subjectSyntaxeType, 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 220f282ff..4a7f473e0 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 @@ -1077,6 +1077,7 @@ class QRCodeScanCubit extends Cubit { nonce: nonce, stateValue: stateValue, useJWKThumbPrint: enableJWKThumbprint, + proofHeaderType: customOidc4vcProfile.proofHeader, ); String? url; @@ -1166,6 +1167,7 @@ class QRCodeScanCubit extends Cubit { mediaType: MediaType.basic, // just added as it is required field useJWKThumbPrint: true, // just added as it is required field + proofHeaderType: customOidc4vcProfile.proofHeader, ); clientId = tokenParameters.thumbprint; case SubjectSyntax.did: diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 88c2f0cc8..6c3e82bf1 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -977,7 +977,9 @@ "clientAuthenticationMethods": "Client Authentication Methods", "clientAuthenticationMethodsSubtitle": "Default: Client id as DID or JWK\nSelect to other authentication methods if needed.", "vcFormatType": "VC Format", - "vcFormatTypeSubtitle": "Default: ldp_vc\nSelect one of the VC formats..", + "vcFormatTypeSubtitle": "Default: ldp_vc\nSelect one of the VC formats.", + "proofHeader": "OIDC4VCI Proof Header", + "proofHeaderSubtitle": "Default: kid\nSwitch if jwk is needed in header.", "theServiceIsNotAvailable": "The service is not available", "issuerDID": "Issuer DID", "subjectDID": "Subject DID", diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index 4e61ff180..c3d6cfa42 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -884,6 +884,8 @@ "clientAuthenticationMethodsSubtitle", "vcFormatType", "vcFormatTypeSubtitle", + "proofHeader", + "proofHeaderSubtitle", "theServiceIsNotAvailable", "issuerDID", "subjectDID", @@ -1823,6 +1825,8 @@ "clientAuthenticationMethodsSubtitle", "vcFormatType", "vcFormatTypeSubtitle", + "proofHeader", + "proofHeaderSubtitle", "theServiceIsNotAvailable", "issuerDID", "subjectDID", @@ -2087,6 +2091,8 @@ "clientAuthenticationMethodsSubtitle", "vcFormatType", "vcFormatTypeSubtitle", + "proofHeader", + "proofHeaderSubtitle", "theServiceIsNotAvailable", "issuerDID", "subjectDID", @@ -3026,6 +3032,8 @@ "clientAuthenticationMethodsSubtitle", "vcFormatType", "vcFormatTypeSubtitle", + "proofHeader", + "proofHeaderSubtitle", "theServiceIsNotAvailable", "issuerDID", "subjectDID", diff --git a/lib/oidc4vc/get_and_add_credential.dart b/lib/oidc4vc/get_and_add_credential.dart index d7103b488..cd102aadd 100644 --- a/lib/oidc4vc/get_and_add_credential.dart +++ b/lib/oidc4vc/get_and_add_credential.dart @@ -87,6 +87,7 @@ Future getAndAddCredential({ authorization: authorization, oidc4vciDraftType: oidc4vciDraftType, useJWKThumbPrint: enableJWKThumbprint, + proofHeaderType: customOidc4vcProfile.proofHeader, ); for (int i = 0; i < encodedCredentialOrFutureTokens.length; i++) { diff --git a/lib/onboarding/enterprise/initialization/cubit/initialization_cubit.dart b/lib/onboarding/enterprise/initialization/cubit/initialization_cubit.dart index 6d2151929..baee2ab98 100644 --- a/lib/onboarding/enterprise/initialization/cubit/initialization_cubit.dart +++ b/lib/onboarding/enterprise/initialization/cubit/initialization_cubit.dart @@ -226,6 +226,7 @@ class EnterpriseInitializationCubit kid: null, mediaType: MediaType.walletAttestation, useJWKThumbPrint: enableJWKThumbprint, + proofHeaderType: customOidc4vcProfile.proofHeader, ); final thumbPrint = tokenParameters.thumbprint; diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index f85040e73..9284e3331 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -856,8 +856,10 @@ class ScanCubit extends Cubit { presentJwtVc = vpFormats.containsKey('jwt_vc'); } - final vcFormatType = profileSetting - .selfSovereignIdentityOptions.customOidc4vcProfile.vcFormatType; + final customOidc4vcProfile = + profileSetting.selfSovereignIdentityOptions.customOidc4vcProfile; + + final vcFormatType = customOidc4vcProfile.vcFormatType; if (!presentLdpVc && vcFormatType == VCFormatType.ldpVc) { presentLdpVc = true; @@ -907,6 +909,7 @@ class ScanCubit extends Cubit { kid: kid, privateKey: privateKey, nonce: nonce, + proofHeaderType: customOidc4vcProfile.proofHeader, ); return vpToken; @@ -943,6 +946,7 @@ class ScanCubit extends Cubit { privateKey: privateKey, nonce: nonce, useJWKThumbPrint: enableJWKThumbprint, + proofHeaderType: customOidc4vcProfile.proofHeader, ); return idToken; diff --git a/packages/oidc4vc/lib/oidc4vc.dart b/packages/oidc4vc/lib/oidc4vc.dart index 1c4d112db..3eda045ad 100644 --- a/packages/oidc4vc/lib/oidc4vc.dart +++ b/packages/oidc4vc/lib/oidc4vc.dart @@ -16,6 +16,7 @@ export 'src/oidc4vc.dart'; export 'src/oidc4vci_draft_type.dart'; export 'src/oidc4vp_draft_type.dart'; export 'src/pkce_dart.dart'; +export 'src/proof_header_type.dart'; export 'src/soipv2_draft_type.dart'; export 'src/token_parameters.dart'; export 'src/vc_format_type.dart'; diff --git a/packages/oidc4vc/lib/src/issuer_token_parameters.dart b/packages/oidc4vc/lib/src/issuer_token_parameters.dart index 6f3c29408..f8b6bcaff 100644 --- a/packages/oidc4vc/lib/src/issuer_token_parameters.dart +++ b/packages/oidc4vc/lib/src/issuer_token_parameters.dart @@ -8,6 +8,7 @@ class IssuerTokenParameters extends TokenParameters { required super.privateKey, required super.did, required super.mediaType, + required super.proofHeaderType, required super.useJWKThumbPrint, required this.issuer, super.kid, diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 1ff2cc62d..446612748 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -348,6 +348,7 @@ class OIDC4VC { required String privateKey, required bool cryptoHolderBinding, required bool useJWKThumbPrint, + required ProofHeaderType proofHeaderType, required OIDC4VCIDraftType oidc4vciDraftType, String? preAuthorizedCode, String? userPin, @@ -400,6 +401,7 @@ class OIDC4VC { issuer: issuer, mediaType: MediaType.proofOfOwnership, useJWKThumbPrint: useJWKThumbPrint, + proofHeaderType: proofHeaderType, ); String? deferredCredentialEndpoint; @@ -1127,6 +1129,7 @@ class OIDC4VC { required String did, required String kid, required String privateKey, + required ProofHeaderType proofHeaderType, }) async { try { final private = jsonDecode(privateKey) as Map; @@ -1140,6 +1143,7 @@ class OIDC4VC { nonce: nonce, mediaType: MediaType.basic, useJWKThumbPrint: false, + proofHeaderType: proofHeaderType, ); final vpToken = await getVpToken(tokenParameters); @@ -1158,6 +1162,7 @@ class OIDC4VC { required String nonce, required bool useJWKThumbPrint, required String privateKey, + required ProofHeaderType proofHeaderType, }) async { try { final private = jsonDecode(privateKey) as Map; @@ -1170,6 +1175,7 @@ class OIDC4VC { nonce: nonce, mediaType: MediaType.basic, useJWKThumbPrint: useJWKThumbPrint, + proofHeaderType: proofHeaderType, ); final verifierIdToken = await getIdToken(tokenParameters); @@ -1189,6 +1195,7 @@ class OIDC4VC { required String privateKey, required String? stateValue, required bool useJWKThumbPrint, + required ProofHeaderType proofHeaderType, }) async { try { final private = jsonDecode(privateKey) as Map; @@ -1202,6 +1209,7 @@ class OIDC4VC { nonce: nonce, mediaType: MediaType.basic, useJWKThumbPrint: useJWKThumbPrint, + proofHeaderType: proofHeaderType, ); // structures @@ -1292,11 +1300,19 @@ class OIDC4VC { // add a key to sign, can only add one for JWT ..addRecipient(key, algorithm: tokenParameters.alg); - if (!tokenParameters.useJWKThumbPrint) { - vpBuilder.setProtectedHeader( - 'kid', - tokenParameters.kid ?? tokenParameters.thumbprint, - ); + switch (tokenParameters.proofHeaderType) { + case ProofHeaderType.kid: + if (!tokenParameters.useJWKThumbPrint) { + vpBuilder.setProtectedHeader( + 'kid', + tokenParameters.kid ?? tokenParameters.thumbprint, + ); + } + case ProofHeaderType.jwk: + vpBuilder.setProtectedHeader( + 'jwk', + tokenParameters.publicJWK, + ); } // build the jws diff --git a/packages/oidc4vc/lib/src/proof_header_type.dart b/packages/oidc4vc/lib/src/proof_header_type.dart new file mode 100644 index 000000000..7723084e3 --- /dev/null +++ b/packages/oidc4vc/lib/src/proof_header_type.dart @@ -0,0 +1,15 @@ +enum ProofHeaderType { + kid, + jwk, +} + +extension ProofHeaderTypeX on ProofHeaderType { + String get formattedString { + switch (this) { + case ProofHeaderType.kid: + return 'kid'; + case ProofHeaderType.jwk: + return 'jwk'; + } + } +} diff --git a/packages/oidc4vc/lib/src/token_parameters.dart b/packages/oidc4vc/lib/src/token_parameters.dart index 3aaabb212..d6906a24f 100644 --- a/packages/oidc4vc/lib/src/token_parameters.dart +++ b/packages/oidc4vc/lib/src/token_parameters.dart @@ -13,6 +13,7 @@ class TokenParameters { required this.privateKey, required this.did, required this.mediaType, + required this.proofHeaderType, required this.useJWKThumbPrint, this.kid, }); @@ -35,6 +36,9 @@ class TokenParameters { return Map.of(privateKey)..removeWhere((key, value) => key == 'd'); } + ///[proofHeaderType] use Jwk or kid + ProofHeaderType proofHeaderType; + /// [alg] is computed from crv of [privateKey]'s fingerprint String get alg { if (privateKey['alg'] != null) { diff --git a/packages/oidc4vc/lib/src/verifier_token_parameters.dart b/packages/oidc4vc/lib/src/verifier_token_parameters.dart index 5541a06ea..7e6b54a4f 100644 --- a/packages/oidc4vc/lib/src/verifier_token_parameters.dart +++ b/packages/oidc4vc/lib/src/verifier_token_parameters.dart @@ -9,10 +9,11 @@ class VerifierTokenParameters extends TokenParameters { VerifierTokenParameters({ required super.privateKey, required super.did, + required super.proofHeaderType, required super.mediaType, required this.audience, - required this.credentials, required super.useJWKThumbPrint, + required this.credentials, this.nonce, super.kid, }); From 6e6e5e5085d98a46a85bae006c08e6fe8969daa6 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 9 Feb 2024 17:43:32 +0530 Subject: [PATCH 18/70] Draft 13 with vc+sd-jwt : error in the credential request #2371 --- packages/oidc4vc/lib/src/oidc4vc.dart | 49 ++++++++++++++++----------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 446612748..83286ad0d 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -411,7 +411,7 @@ class OIDC4VC { openIdConfiguration.deferredCredentialEndpoint; } - final (credentialType, types, credentialDefinition, format) = + final (credentialType, types, credentialDefinition, vct, format) = await getCredentialData( openIdConfiguration: openIdConfiguration, credential: credential, @@ -450,6 +450,7 @@ class OIDC4VC { cryptoHolderBinding: cryptoHolderBinding, oidc4vciDraftType: oidc4vciDraftType, credentialDefinition: credentialDefinition, + vct: vct, ); credentialResponseData.add(credentialResponseDataValue); @@ -465,6 +466,8 @@ class OIDC4VC { cryptoHolderBinding: cryptoHolderBinding, oidc4vciDraftType: oidc4vciDraftType, credentialDefinition: credentialDefinition, + vct: vct, + credentialIdentifier: null, ); credentialResponseData.add(credentialResponseDataValue); @@ -486,8 +489,9 @@ class OIDC4VC { required String format, required bool cryptoHolderBinding, required OIDC4VCIDraftType oidc4vciDraftType, - String? credentialIdentifier, - Map? credentialDefinition, + required String? credentialIdentifier, + required Map? credentialDefinition, + required String? vct, }) async { final credentialData = await buildCredentialData( cnonce: cnonce, @@ -500,6 +504,7 @@ class OIDC4VC { cryptoHolderBinding: cryptoHolderBinding, oidc4vciDraftType: oidc4vciDraftType, credentialDefinition: credentialDefinition, + vct: vct, ); /// sign proof @@ -753,9 +758,10 @@ class OIDC4VC { required String format, required bool cryptoHolderBinding, required OIDC4VCIDraftType oidc4vciDraftType, - String? credentialIdentifier, - String? cnonce, - Map? credentialDefinition, + required String? credentialIdentifier, + required String? cnonce, + required String? vct, + required Map? credentialDefinition, }) async { final credentialData = {}; @@ -793,21 +799,20 @@ class OIDC4VC { case OIDC4VCIDraftType.draft13: credentialData['format'] = format; - if (format == VCFormatType.vcSdJWT.value) { - credentialData['vct'] = 'sth'; - } else { - if (credentialDefinition == null) { - throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); - } + if (credentialDefinition != null) { credentialData['credential_definition'] = credentialDefinition; } + + if (vct != null) { + credentialData['vct'] = vct; + } } return credentialData; } - /// (credentialType, types, credential_definition, format) - Future<(String, List?, Map?, String)> + /// (credentialType, types, credential_definition, vct, format) + Future<(String, List?, Map?, String?, String)> getCredentialData({ required OpenIdConfiguration openIdConfiguration, required dynamic credential, @@ -815,6 +820,7 @@ class OIDC4VC { String? credentialType; List? types; Map? credentialDefinition; + String? vct; String? format; if (credential is String) { @@ -885,10 +891,15 @@ class OIDC4VC { format = credentialSupported['format'].toString(); - if ((credentialSupported is Map) && - (credentialSupported.containsKey('credential_definition'))) { - credentialDefinition = credentialSupported['credential_definition'] - as Map; + if (credentialSupported is Map) { + if (credentialSupported.containsKey('credential_definition')) { + credentialDefinition = credentialSupported['credential_definition'] + as Map; + } + + if (credentialSupported.containsKey('vct')) { + vct = credentialSupported['vct'].toString(); + } } } else { throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); @@ -903,7 +914,7 @@ class OIDC4VC { throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); } - return (credentialType, types, credentialDefinition, format); + return (credentialType, types, credentialDefinition, vct, format); } Future verifyEncodedData({ From 121ad80248a6751d78eba364213750ebbcf783e5 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 9 Feb 2024 18:37:16 +0530 Subject: [PATCH 19/70] feat: Show selective disclosure data --- .../shared/extension/string_extension.dart | 7 +++ .../detail/view/credentials_details_page.dart | 8 +++ .../widgets/selective_disclosure_data.dart | 57 +++++++++++++++++++ .../credentials/detail/widgets/widgets.dart | 1 + 4 files changed, 73 insertions(+) create mode 100644 lib/dashboard/home/tab_bar/credentials/detail/widgets/selective_disclosure_data.dart diff --git a/lib/app/shared/extension/string_extension.dart b/lib/app/shared/extension/string_extension.dart index e57dcc269..fea95a8fa 100644 --- a/lib/app/shared/extension/string_extension.dart +++ b/lib/app/shared/extension/string_extension.dart @@ -34,4 +34,11 @@ extension StringExtension on String { } Characters get characters => Characters(this); + + String get beautityTitle { + List words = split('_'); + words = + words.map((word) => word[0].toUpperCase() + word.substring(1)).toList(); + return words.join(''); + } } diff --git a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart index abe6c6a73..7bdb162d5 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart @@ -325,6 +325,14 @@ class _CredentialsDetailsViewState extends State { if (widget.credentialModel.claims != null) ...[ ClaimsData(credentialModel: widget.credentialModel), ], + + /// selective disclouse data - _sd + if (widget.credentialModel.jwt != null && + widget.credentialModel.jwt!.contains('~')) ...[ + SelectiveDisclosureData( + credentialModel: widget.credentialModel, + ), + ], ], if (state.credentialDetailTabStatus == CredentialDetailTabStatus.activity) ...[ diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/selective_disclosure_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/selective_disclosure_data.dart new file mode 100644 index 000000000..35a994636 --- /dev/null +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/selective_disclosure_data.dart @@ -0,0 +1,57 @@ +import 'dart:convert'; + +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/theme/theme.dart'; +import 'package:flutter/material.dart'; + +class SelectiveDisclosureData extends StatelessWidget { + const SelectiveDisclosureData({ + super.key, + required this.credentialModel, + }); + + final CredentialModel credentialModel; + + @override + Widget build(BuildContext context) { + final encryptedDatas = credentialModel.jwt!.split('~'); + encryptedDatas.removeAt(0); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: encryptedDatas.map((dynamic element) { + dynamic decryptedData; + + try { + decryptedData = utf8.decode(base64Decode(element.toString())); + } catch (e) { + return Container(); + } + + if (decryptedData.toString().isEmpty) return Container(); + + final lisString = decryptedData + .toString() + .substring(1, decryptedData.toString().length - 1) + .replaceAll('"', '') + .split(','); + + if (lisString.length < 3) { + return Container(); + } + + return Padding( + padding: const EdgeInsets.only(top: 10), + child: CredentialField( + padding: EdgeInsets.zero, + title: lisString[1].beautityTitle, + value: lisString[2], + titleColor: Theme.of(context).colorScheme.titleColor, + valueColor: Theme.of(context).colorScheme.valueColor, + ), + ); + }).toList(), + ); + } +} diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart index 96978f922..873be99a7 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart @@ -2,3 +2,4 @@ export 'claims_data.dart'; export 'credential_active_status.dart'; export 'deferred_credential_data.dart'; export 'developer_details.dart'; +export 'selective_disclosure_data.dart'; From f346631b4847ff70a55219cb105e7beccb2f3680 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 9 Feb 2024 18:39:06 +0530 Subject: [PATCH 20/70] version update 2.2.19+381 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index f7931923e..b687f0398 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.18+380 +version: 2.2.19+381 environment: sdk: ">=3.1.0 <4.0.0" From 7a497b7d24fab2263584123fef605318924d24fd Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 9 Feb 2024 15:40:54 +0000 Subject: [PATCH 21/70] sicpa presentation issue --- lib/scan/cubit/scan_cubit.dart | 48 ++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index 9284e3331..065fb2de3 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -711,7 +711,7 @@ class ScanCubit extends Cubit { } if (credentialsToBePresented.length == 1) { - late InputDescriptor descriptor; + InputDescriptor? descriptor; for (final InputDescriptor inputDescriptor in presentationDefinition.inputDescriptors) { @@ -746,20 +746,21 @@ class ScanCubit extends Cubit { } } } - - inputDescriptors.add({ - 'id': descriptor.id, - 'format': vpFormat, - 'path': r'$', - 'path_nested': { + if (descriptor != null) { + inputDescriptors.add({ 'id': descriptor.id, - 'format': vcFormat, - 'path': r'$.verifiableCredential', - }, - }); + 'format': vpFormat, + 'path': r'$', + 'path_nested': { + 'id': descriptor.id, + 'format': vcFormat, + 'path': r'$.verifiableCredential', + }, + }); + } } else { for (int i = 0; i < credentialsToBePresented.length; i++) { - late InputDescriptor descriptor; + InputDescriptor? descriptor; for (final InputDescriptor inputDescriptor in presentationDefinition.inputDescriptors) { @@ -774,18 +775,19 @@ class ScanCubit extends Cubit { } } } - - inputDescriptors.add({ - 'id': descriptor.id, - 'format': vpFormat, - 'path': r'$', - 'path_nested': { + if (descriptor != null) { + inputDescriptors.add({ 'id': descriptor.id, - 'format': vcFormat, - // ignore: prefer_interpolation_to_compose_strings - 'path': r'$.verifiableCredential[' + i.toString() + ']', - }, - }); + 'format': vpFormat, + 'path': r'$', + 'path_nested': { + 'id': descriptor.id, + 'format': vcFormat, + // ignore: prefer_interpolation_to_compose_strings + 'path': r'$.verifiableCredential[' + i.toString() + ']', + }, + }); + } } } From 892abe41e19832c95e1e5219b16b4e832465ef4a Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 9 Feb 2024 16:26:32 +0000 Subject: [PATCH 22/70] version: 2.2.20+382 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index b687f0398..cc953fd46 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.19+381 +version: 2.2.20+382 environment: sdk: ">=3.1.0 <4.0.0" From 5af160b0b7343e3b0de7622b83749efcfab39837 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 12 Feb 2024 13:37:51 +0545 Subject: [PATCH 23/70] Profile GAIN-POC to rename OWF Baseline Profile and change logo #2360 --- assets/image/gainPOCExperimental.png | Bin 17026 -> 0 bytes assets/image/owfBaselineProfileLogo.jpg | Bin 0 -> 57396 bytes lib/app/shared/constants/image_strings.dart | 4 ++-- .../shared/enum/type/profile/profile_type.dart | 8 ++++---- lib/app/shared/widget/wallet_logo.dart | 4 ++-- lib/dashboard/profile/cubit/profile_cubit.dart | 8 ++++---- lib/dashboard/profile/models/profile.dart | 6 +++--- 7 files changed, 15 insertions(+), 15 deletions(-) delete mode 100644 assets/image/gainPOCExperimental.png create mode 100644 assets/image/owfBaselineProfileLogo.jpg diff --git a/assets/image/gainPOCExperimental.png b/assets/image/gainPOCExperimental.png deleted file mode 100644 index 76c98fb3d753092c6b5c74f5579315030b3d0462..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17026 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ӯ` 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 Z3-TWtSR+r;q;%XdLPbltMDbDh{{cSx!5jbp diff --git a/assets/image/owfBaselineProfileLogo.jpg b/assets/image/owfBaselineProfileLogo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5ebd54deedf0f0e6dd2c9215496758ba9a3f8f0f GIT binary patch literal 57396 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 Ap#T5? literal 0 HcmV?d00001 diff --git a/lib/app/shared/constants/image_strings.dart b/lib/app/shared/constants/image_strings.dart index 44adc9fb5..522c77044 100644 --- a/lib/app/shared/constants/image_strings.dart +++ b/lib/app/shared/constants/image_strings.dart @@ -7,8 +7,8 @@ class ImageStrings { static const String imagePath = 'assets/image'; static const String ebsiLogo = '$imagePath/ebsi_logo.png'; - static const String gainPOCExperimentalLogo = - '$imagePath/gainPOCExperimental.png'; + static const String owfBaselineProfileLogo = + '$imagePath/owfBaselineProfileLogo.jpg'; static const String cardMissing = '$imagePath/card_missing.png'; static const String employmentCertificateFront = diff --git a/lib/app/shared/enum/type/profile/profile_type.dart b/lib/app/shared/enum/type/profile/profile_type.dart index 9a7e09c95..6db79dd0c 100644 --- a/lib/app/shared/enum/type/profile/profile_type.dart +++ b/lib/app/shared/enum/type/profile/profile_type.dart @@ -1,6 +1,6 @@ import 'package:altme/l10n/l10n.dart'; -enum ProfileType { custom, ebsiV3, dutch, enterprise, gainPOCExperimental } +enum ProfileType { custom, ebsiV3, dutch, enterprise, owfBaselineProfile } extension ProfileTypeX on ProfileType { String getTitle({ @@ -16,8 +16,8 @@ extension ProfileTypeX on ProfileType { return l10n.decentralizedIdentityInteropProfile; case ProfileType.enterprise: return name.isEmpty ? 'Enterprise' : name; - case ProfileType.gainPOCExperimental: - return 'GAIN POC (Experimental)'; + case ProfileType.owfBaselineProfile: + return 'OWF Baseline Profile'; } } @@ -28,7 +28,7 @@ extension ProfileTypeX on ProfileType { return false; case ProfileType.ebsiV3: case ProfileType.enterprise: - case ProfileType.gainPOCExperimental: + case ProfileType.owfBaselineProfile: return true; } } diff --git a/lib/app/shared/widget/wallet_logo.dart b/lib/app/shared/widget/wallet_logo.dart index 55382d13a..9f79b655a 100644 --- a/lib/app/shared/widget/wallet_logo.dart +++ b/lib/app/shared/widget/wallet_logo.dart @@ -35,8 +35,8 @@ class WalletLogo extends StatelessWidget { image = ImageStrings.ebsiLogo; case ProfileType.enterprise: image = profileModel.profileSetting.generalOptions.companyLogo; - case ProfileType.gainPOCExperimental: - image = ImageStrings.gainPOCExperimentalLogo; + case ProfileType.owfBaselineProfile: + image = ImageStrings.owfBaselineProfileLogo; } return Column( diff --git a/lib/dashboard/profile/cubit/profile_cubit.dart b/lib/dashboard/profile/cubit/profile_cubit.dart index ea8986e4c..d1634367f 100644 --- a/lib/dashboard/profile/cubit/profile_cubit.dart +++ b/lib/dashboard/profile/cubit/profile_cubit.dart @@ -306,7 +306,7 @@ class ProfileCubit extends Cubit { clientSecret: randomString(12), ); - case ProfileType.gainPOCExperimental: + case ProfileType.owfBaselineProfile: final privateKey = await getPrivateKey( secureStorage: secureStorageProvider, didKeyType: DidKeyType.p256, @@ -320,7 +320,7 @@ class ProfileCubit extends Cubit { didKitProvider: didKitProvider, ); - profileModel = ProfileModel.gainPOCExperimental( + profileModel = ProfileModel.owfBaselineProfile( polygonIdNetwork: polygonIdNetwork, walletType: walletType, walletProtectionType: walletProtectionType, @@ -575,9 +575,9 @@ class ProfileCubit extends Cubit { .selfSovereignIdentityOptions.customOidc4vcProfile.clientSecret, ), ); - case ProfileType.gainPOCExperimental: + case ProfileType.owfBaselineProfile: await update( - ProfileModel.gainPOCExperimental( + ProfileModel.owfBaselineProfile( polygonIdNetwork: state.model.polygonIdNetwork, walletProtectionType: state.model.walletProtectionType, isDeveloperMode: state.model.isDeveloperMode, diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index 89468cb00..18e086444 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -124,7 +124,7 @@ class ProfileModel extends Equatable { ), ); - factory ProfileModel.gainPOCExperimental({ + factory ProfileModel.owfBaselineProfile({ required PolygonIdNetwork polygonIdNetwork, required WalletType walletType, required WalletProtectionType walletProtectionType, @@ -139,7 +139,7 @@ class ProfileModel extends Equatable { walletType: walletType, walletProtectionType: walletProtectionType, isDeveloperMode: isDeveloperMode, - profileType: ProfileType.gainPOCExperimental, + profileType: ProfileType.owfBaselineProfile, profileSetting: ProfileSetting( blockchainOptions: BlockchainOptions.initial(), generalOptions: GeneralOptions.empty(), @@ -151,7 +151,7 @@ class ProfileModel extends Equatable { clientAuthentication: ClientAuthentication.clientId, credentialManifestSupport: true, cryptoHolderBinding: true, - defaultDid: DidKeyType.p256, + defaultDid: DidKeyType.jwkP256, oidc4vciDraft: OIDC4VCIDraftType.draft13, oidc4vpDraft: OIDC4VPDraftType.draft18, scope: false, From 29f60c937ab32ebf669d13de877b3ba778e82d6c Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 12 Feb 2024 17:33:24 +0545 Subject: [PATCH 24/70] Display labels and claims value depending on the issuer metadata in card details #2355 --- .../detail/view/credentials_details_page.dart | 10 +- .../detail/widgets/claims_data.dart | 12 ++- .../widgets/credential_subject_data.dart | 91 +++++++++++++++++++ .../credentials/detail/widgets/widgets.dart | 1 + .../credential_model/credential_model.dart | 10 +- .../verifiable_identity_card_model.dart | 3 + lib/oidc4vc/add_oidc4vc_credential.dart | 10 +- 7 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart diff --git a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart index 7bdb162d5..2e2bc0c99 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart @@ -297,6 +297,11 @@ class _CredentialsDetailsViewState extends State { ), ], + /// credentialSubjectData + CredentialSubjectData( + credentialModel: widget.credentialModel, + ), + //// wallet attestation data if (widget.credentialModel.credentialPreview .credentialSubjectModel @@ -322,7 +327,10 @@ class _CredentialsDetailsViewState extends State { ], /// claims data , from draft 13 - if (widget.credentialModel.claims != null) ...[ + if (widget.credentialModel.credentialSupported != + null && + widget.credentialModel.credentialSupported! + .containsKey('claims')) ...[ ClaimsData(credentialModel: widget.credentialModel), ], diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart index da37a7f51..67315a95d 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart @@ -13,11 +13,19 @@ class ClaimsData extends StatelessWidget { @override Widget build(BuildContext context) { - final claims = credentialModel.claims; + final credentialSupported = credentialModel.credentialSupported; + + final claims = credentialSupported!['claims']; + + if (claims! is Map) { + return Container(); + } return Column( crossAxisAlignment: CrossAxisAlignment.start, - children: claims!.entries.map((MapEntry map) { + children: (claims as Map) + .entries + .map((MapEntry map) { final key = map.key; final value = map.value; 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 new file mode 100644 index 000000000..b6ec0a26f --- /dev/null +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/credential_subject_data.dart @@ -0,0 +1,91 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/theme/theme.dart'; +import 'package:flutter/material.dart'; +import 'package:json_path/json_path.dart'; + +class CredentialSubjectData extends StatelessWidget { + const CredentialSubjectData({ + super.key, + required this.credentialModel, + }); + + final CredentialModel credentialModel; + + @override + Widget build(BuildContext context) { + final credentialSupported = credentialModel.credentialSupported; + + final credentialSubjectReference = JsonPath(r'$..credentialSubject') + .read(credentialSupported) + .firstOrNull + ?.value; + + if (credentialSubjectReference == null) return Container(); + if (credentialSubjectReference is! Map) return Container(); + + final credentialSubjectData = credentialModel.data['credentialSubject']; + + if (credentialSubjectData == null) return Container(); + if (credentialSubjectData is! Map) return Container(); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: credentialSubjectReference.entries + .map((MapEntry map) { + String? title; + String? data; + + final key = map.key; + final value = map.value; + + if (value is! Map) return Container(); + + if (value.isEmpty) return Container(); + + if (value.containsKey('mandatory')) { + final mandatory = value['mandatory']; + if (mandatory is! bool) return Container(); + + if (!mandatory) return Container(); + } + + if (value.containsKey('display')) { + final displays = value['display']; + if (displays is! List) return Container(); + + final display = displays.where((element) { + if (element is Map && + element.containsKey('locale') && + element['locale'] == 'en-US') { + return true; + } + return false; + }).firstOrNull; + + if (display == null) return Container(); + + if (credentialSubjectData.containsKey(key)) { + title = display['name'].toString(); + data = credentialSubjectData[key].toString(); + } + } else { + return Container(); + } + + if (title == null || data == null) return Container(); + + return Padding( + padding: const EdgeInsets.only(top: 10), + child: CredentialField( + padding: EdgeInsets.zero, + title: title, + value: data, + titleColor: Theme.of(context).colorScheme.titleColor, + valueColor: Theme.of(context).colorScheme.valueColor, + ), + ); + }).toList(), + ); + } +} diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart index 873be99a7..432db56ff 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart @@ -1,5 +1,6 @@ export 'claims_data.dart'; export 'credential_active_status.dart'; +export 'credential_subject_data.dart'; export 'deferred_credential_data.dart'; export 'developer_details.dart'; export 'selective_disclosure_data.dart'; diff --git a/lib/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart b/lib/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart index c09bc54ff..b5d3be039 100644 --- a/lib/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart +++ b/lib/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart @@ -31,7 +31,7 @@ class CredentialModel extends Equatable { this.activities = const [], this.jwt, this.pendingInfo, - this.claims, + this.credentialSupported, }); factory CredentialModel.fromJson(Map json) { @@ -76,7 +76,7 @@ class CredentialModel extends Equatable { activities: activities, jwt: oldCredentialModel.jwt, format: oldCredentialModel.format, - claims: oldCredentialModel.claims, + credentialSupported: oldCredentialModel.credentialSupported, ); } @@ -100,7 +100,7 @@ class CredentialModel extends Equatable { final String? jwt; final PendingInfo? pendingInfo; final String? format; - final Map? claims; + final Map? credentialSupported; Map toJson() => _$CredentialModelToJson(this); @@ -138,7 +138,7 @@ class CredentialModel extends Equatable { jwt: jwt ?? this.jwt, pendingInfo: pendingInfo ?? this.pendingInfo, format: format ?? this.format, - claims: claims ?? this.claims, + credentialSupported: credentialSupported ?? this.credentialSupported, ); } @@ -264,6 +264,6 @@ class CredentialModel extends Equatable { jwt, pendingInfo, format, - claims, + credentialSupported, ]; } diff --git a/lib/dashboard/home/tab_bar/credentials/models/verifiable_identity_card/verifiable_identity_card_model.dart b/lib/dashboard/home/tab_bar/credentials/models/verifiable_identity_card/verifiable_identity_card_model.dart index 0cb34e67f..28b1cd607 100644 --- a/lib/dashboard/home/tab_bar/credentials/models/verifiable_identity_card/verifiable_identity_card_model.dart +++ b/lib/dashboard/home/tab_bar/credentials/models/verifiable_identity_card/verifiable_identity_card_model.dart @@ -11,6 +11,7 @@ class VerifiableIdCardModel extends CredentialSubjectModel { this.firstName, this.bithPlace, this.birthDate, + this.dateOfBirth, this.addressCountry, super.issuedBy, super.offeredBy, @@ -31,6 +32,8 @@ class VerifiableIdCardModel extends CredentialSubjectModel { @JsonKey(defaultValue: '') String? birthDate; @JsonKey(defaultValue: '') + String? dateOfBirth; + @JsonKey(defaultValue: '') String? bithPlace; @JsonKey(defaultValue: '') String? addressCountry; diff --git a/lib/oidc4vc/add_oidc4vc_credential.dart b/lib/oidc4vc/add_oidc4vc_credential.dart index 8cf7e48bd..3bbbbe1a5 100644 --- a/lib/oidc4vc/add_oidc4vc_credential.dart +++ b/lib/oidc4vc/add_oidc4vc_credential.dart @@ -157,6 +157,8 @@ Future addOIDC4VCCredential({ credentialsSupported.id == credentialType, ); + newCredential['credentialSupported'] = credentialsSupported; + if (credSupported != null && credSupported.display != null) { display = credSupported.display!.firstWhereOrNull( (Display display) => @@ -171,12 +173,10 @@ Future addOIDC4VCCredential({ credentialsSupported.containsKey(credentialType)) { final credSupported = credentialsSupported[credentialType]; - if (credSupported is Map) { - /// claims - if (credSupported.containsKey('claims')) { - newCredential['claims'] = credSupported['claims']; - } + /// credentialSupported + newCredential['credentialSupported'] = credSupported; + if (credSupported is Map) { /// display if (credSupported.containsKey('display')) { final displayData = credSupported['display']; From 89a64f542042dbd97fb206de4e2fe4a8a41ef879 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 12 Feb 2024 18:48:46 +0545 Subject: [PATCH 25/70] Handle some incompatibility #2368 --- .../widget/did_key_type_widget.dart | 41 +++++++++++++++++++ .../widget/vc_format_widget.dart | 3 ++ lib/l10n/arb/app_en.arb | 5 ++- lib/l10n/untranslated.json | 20 +++++++-- 4 files changed, 64 insertions(+), 5 deletions(-) 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 bb892f970..07ad625e8 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 @@ -4,6 +4,7 @@ import 'package:altme/l10n/l10n.dart'; import 'package:altme/theme/theme.dart'; 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}); @@ -35,6 +36,46 @@ class DidKeyTypeWidget extends StatelessWidget { ), ListTile( onTap: () { + final customOidc4vcProfile = state.model.profileSetting + .selfSovereignIdentityOptions.customOidc4vcProfile; + + /// if user chooses VC format ldp_vc with did:ebsi or + /// did:jwk - Display message "The ldp_format is not + /// supported by this DID method" + final isldpVc = customOidc4vcProfile.vcFormatType == + VCFormatType.ldpVc; + + final isUnmatchedDid = didKeyType == DidKeyType.ebsiv3 || + didKeyType == DidKeyType.jwkP256; + + if (isldpVc && isUnmatchedDid) { + showDialog( + context: context, + builder: (context) => ErrorDetailsDialog( + erroDescription: + l10n.theLdpFormatIsNotSupportedByThisDIDMethod, + ), + ); + + return; + } + + ///if DID method is did eddsa then Cryrto Holder Binding + ///must be Off -> display message "Switch off Crypto + ///Holder Binding for that DID Method" + if (didKeyType == DidKeyType.edDSA && + customOidc4vcProfile.cryptoHolderBinding) { + showDialog( + context: context, + builder: (context) => ErrorDetailsDialog( + erroDescription: l10n + .switchOffCryptoHolderBindingForThatDIDMethod, + ), + ); + + return; + } + context.read().updateProfileSetting( didKeyType: didKeyType, ); diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart index c974b7340..bdd131edd 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart @@ -36,6 +36,9 @@ class VCFormatWidget extends StatelessWidget { ), ListTile( onTap: () { + final customOidc4vcProfile = state.model.profileSetting + .selfSovereignIdentityOptions.customOidc4vcProfile; + context.read().updateProfileSetting( vcFormatType: vcFormatType, ); diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 6c3e82bf1..4daa60199 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1032,5 +1032,8 @@ "congrats": "Congrats !", "yourWalletConfigurationHasBeenSuccessfullyUpdated": "Your wallet configuration has been successfully updated", "continueString": "Continue", - "walletProvider": "Wallet Provider" + "walletProvider": "Wallet Provider", + "theLdpFormatIsNotSupportedByThisDIDMethod": "The ldp_format is not supported by this DID method.", + "switchOffCryptoHolderBindingForThatDIDMethod": "Switch off Crypto Holder Binding for that DID Method.", + "thisTypeProofCannotBeUsedWithThisVCFormat": "This type proof cannot be used with this VC Format." } \ No newline at end of file diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index c3d6cfa42..d165b86d7 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -937,7 +937,10 @@ "congrats", "yourWalletConfigurationHasBeenSuccessfullyUpdated", "continueString", - "walletProvider" + "walletProvider", + "theLdpFormatIsNotSupportedByThisDIDMethod", + "switchOffCryptoHolderBindingForThatDIDMethod", + "thisTypeProofCannotBeUsedWithThisVCFormat" ], "es": [ @@ -1878,7 +1881,10 @@ "congrats", "yourWalletConfigurationHasBeenSuccessfullyUpdated", "continueString", - "walletProvider" + "walletProvider", + "theLdpFormatIsNotSupportedByThisDIDMethod", + "switchOffCryptoHolderBindingForThatDIDMethod", + "thisTypeProofCannotBeUsedWithThisVCFormat" ], "fr": [ @@ -2144,7 +2150,10 @@ "congrats", "yourWalletConfigurationHasBeenSuccessfullyUpdated", "continueString", - "walletProvider" + "walletProvider", + "theLdpFormatIsNotSupportedByThisDIDMethod", + "switchOffCryptoHolderBindingForThatDIDMethod", + "thisTypeProofCannotBeUsedWithThisVCFormat" ], "it": [ @@ -3085,6 +3094,9 @@ "congrats", "yourWalletConfigurationHasBeenSuccessfullyUpdated", "continueString", - "walletProvider" + "walletProvider", + "theLdpFormatIsNotSupportedByThisDIDMethod", + "switchOffCryptoHolderBindingForThatDIDMethod", + "thisTypeProofCannotBeUsedWithThisVCFormat" ] } From d1deabf31a71305818f8a505e7d1554b37412f9b Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 12 Feb 2024 18:52:42 +0545 Subject: [PATCH 26/70] Update wording #2378 #2374 --- .../drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart | 3 --- lib/l10n/arb/app_en.arb | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart index bdd131edd..c974b7340 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/vc_format_widget.dart @@ -36,9 +36,6 @@ class VCFormatWidget extends StatelessWidget { ), ListTile( onTap: () { - final customOidc4vcProfile = state.model.profileSetting - .selfSovereignIdentityOptions.customOidc4vcProfile; - context.read().updateProfileSetting( vcFormatType: vcFormatType, ); diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 4daa60199..6225d2b44 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -971,14 +971,14 @@ "subjectSyntaxType": "Subject Syntax Type", "enableToUseTheJWKThumprintOfTheKey": "Default: DID\nEnable to use the JWK thumprint of the key", "cryptographicHolderBinding": "Cryptographic Holder Binding", - "cryptographicHolderBindingSubtitle": "Default : On\nDisable to accept Bearer credentials as tickets with low assurance.", + "cryptographicHolderBindingSubtitle": "Default : On\nDisable cryptographic binding for claim based binding credentials.", "scopeParameters": "Scope Parameters", "scopeParametersSubtitle": "Default : Off\nEnable to force wallet to use scope instead of authorization_details.", "clientAuthenticationMethods": "Client Authentication Methods", "clientAuthenticationMethodsSubtitle": "Default: Client id as DID or JWK\nSelect to other authentication methods if needed.", "vcFormatType": "VC Format", "vcFormatTypeSubtitle": "Default: ldp_vc\nSelect one of the VC formats.", - "proofHeader": "OIDC4VCI Proof Header", + "proofHeader": "OIDC4VCI Jwt Proof Type", "proofHeaderSubtitle": "Default: kid\nSwitch if jwk is needed in header.", "theServiceIsNotAvailable": "The service is not available", "issuerDID": "Issuer DID", From 0cec1eabc5494d65bf2c9fbcea36099d0bfdcb0d Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 12 Feb 2024 16:49:05 +0000 Subject: [PATCH 27/70] OIDC4VP with same credential filtering in selection and presentation --- lib/credentials/cubit/credentials_cubit.dart | 3 - .../filter_credential_list_by_format.dart | 36 +++++++ .../get_credentials_from_filter_list.dart | 28 +----- ...dentials_from_presentation_definition.dart | 15 ++- lib/scan/cubit/scan_cubit.dart | 99 ++++++------------- .../lib/credential_manifest.dart | 1 + pubspec.lock | 48 ++++----- 7 files changed, 98 insertions(+), 132 deletions(-) create mode 100644 lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/filter_credential_list_by_format.dart diff --git a/lib/credentials/cubit/credentials_cubit.dart b/lib/credentials/cubit/credentials_cubit.dart index 8056b9911..2061c38dd 100644 --- a/lib/credentials/cubit/credentials_cubit.dart +++ b/lib/credentials/cubit/credentials_cubit.dart @@ -483,9 +483,6 @@ class CredentialsCubit extends Cubit { ), ], credentialList: oldCredentialList, - isJwtVpInJwtVCRequired: null, - presentJwtVc: null, - presentLdpVc: null, ); /// update or create AssociatedAddres credential with new name diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/filter_credential_list_by_format.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/filter_credential_list_by_format.dart new file mode 100644 index 000000000..f2c55ffa3 --- /dev/null +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/filter_credential_list_by_format.dart @@ -0,0 +1,36 @@ +import 'package:altme/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart'; +import 'package:credential_manifest/credential_manifest.dart'; + +List filterCredenialListByFormat( + List credentialList, + Format? format, + List filterList, +) { + if (filterList.isNotEmpty) { + final isJwtVpInJwtVCRequired = format?.jwtVp != null; + + final presentLdpVc = format?.ldpVc != null; + final presentJwtVc = format?.jwtVc != null; + + if (isJwtVpInJwtVCRequired) { + credentialList.removeWhere( + (CredentialModel credentialModel) => credentialModel.jwt == null, + ); + } + + /// remove ldp_vc + if (presentJwtVc) { + credentialList.removeWhere( + (CredentialModel credentialModel) => credentialModel.jwt == null, + ); + } + + /// remove jwt_vc + if (presentLdpVc) { + credentialList.removeWhere( + (CredentialModel credentialModel) => credentialModel.jwt != null, + ); + } + } + return credentialList; +} diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_filter_list.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_filter_list.dart index bbcfe3994..dd5692bda 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_filter_list.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_filter_list.dart @@ -1,39 +1,16 @@ import 'package:altme/dashboard/home/tab_bar/credentials/credential.dart'; import 'package:credential_manifest/credential_manifest.dart'; -List getCredentialsFromFilterList({ +List getCredentialsFromFilterList({ required List filterList, required List credentialList, - required bool? isJwtVpInJwtVCRequired, - required bool? presentLdpVc, - required bool? presentJwtVc, }) { /// If we have some instructions we filter the wallet's /// crendential list whith it if (filterList.isNotEmpty) { - final selectedCredential = []; - /// remove ldp_vp if jwt_vp is required - if (isJwtVpInJwtVCRequired != null && isJwtVpInJwtVCRequired) { - credentialList.removeWhere( - (CredentialModel credentialModel) => credentialModel.jwt == null, - ); - } - - /// remove ldp_vc - if (presentJwtVc != null && presentJwtVc) { - credentialList.removeWhere( - (CredentialModel credentialModel) => credentialModel.jwt == null, - ); - } - - /// remove jwt_vc - if (presentLdpVc != null && presentLdpVc) { - credentialList.removeWhere( - (CredentialModel credentialModel) => credentialModel.jwt != null, - ); - } + final selectedCredential = []; for (final field in filterList) { for (final credential in credentialList) { for (final path in field.path) { @@ -74,7 +51,6 @@ List getCredentialsFromFilterList({ } } } - return selectedCredential; } return credentialList; diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_presentation_definition.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_presentation_definition.dart index e7f5bd258..61a2f1882 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_presentation_definition.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/get_credentials_from_presentation_definition.dart @@ -1,4 +1,5 @@ import 'package:altme/dashboard/home/tab_bar/credentials/credential.dart'; +import 'package:altme/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/helpers/filter_credential_list_by_format.dart'; import 'package:credential_manifest/credential_manifest.dart'; List getCredentialsFromPresentationDefinition({ @@ -10,19 +11,17 @@ List getCredentialsFromPresentationDefinition({ .inputDescriptors[inputDescriptorIndex].constraints?.fields ?? []; - final isJwtVpInJwtVCRequired = presentationDefinition.format?.jwtVp != null; - - final presentLdpVc = presentationDefinition.format?.ldpVc != null; - final presentJwtVc = presentationDefinition.format?.jwtVc != null; + final credentialListFilteredByFormat = filterCredenialListByFormat( + List.from(credentialList), + presentationDefinition.format, + filterList, + ); /// If we have some instructions we filter the wallet's /// crendential list whith it final filteredCredentialList = getCredentialsFromFilterList( filterList: filterList, - credentialList: credentialList, - isJwtVpInJwtVCRequired: isJwtVpInJwtVCRequired, - presentLdpVc: presentLdpVc, - presentJwtVc: presentJwtVc, + credentialList: List.from(credentialListFilteredByFormat), ); return filteredCredentialList; } diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index 065fb2de3..c0591ebd9 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -710,84 +710,41 @@ class ScanCubit extends Cubit { ); } - if (credentialsToBePresented.length == 1) { - InputDescriptor? descriptor; - + for (int i = 0; i < credentialsToBePresented.length; i++) { for (final InputDescriptor inputDescriptor in presentationDefinition.inputDescriptors) { - for (final Field field in inputDescriptor.constraints!.fields!) { - final element = - credentialsToBePresented[0].credentialPreview.type.last; - - String? pattern; + final filterList = inputDescriptor.constraints?.fields ?? []; - if (field.filter?.pattern != null) { - pattern = field.filter!.pattern; - } else if (field.filter?.contains?.containsConst != null) { - pattern = field.filter?.contains?.containsConst; - } - - if (pattern == null) { - throw ResponseMessage( - data: { - 'error': 'invalid_request', - 'error_description': 'pattern or containsConst is missing', + final credential = getCredentialsFromFilterList( + filterList: filterList, + credentialList: [credentialsToBePresented[i]], + ); + if (credential.isNotEmpty) { + if (credentialsToBePresented.length == 1) { + inputDescriptors.add({ + 'id': inputDescriptor.id, + 'format': vpFormat, + 'path': r'$', + 'path_nested': { + 'id': inputDescriptor.id, + 'format': vcFormat, + 'path': r'$.verifiableCredential', }, - ); - } - - if (pattern.endsWith(r'$')) { - final RegExp regEx = RegExp(pattern); - final Match? match = regEx.firstMatch(element); - - if (match != null) descriptor = inputDescriptor; + }); } else { - if (element == pattern) descriptor = inputDescriptor; - } - } - } - if (descriptor != null) { - inputDescriptors.add({ - 'id': descriptor.id, - 'format': vpFormat, - 'path': r'$', - 'path_nested': { - 'id': descriptor.id, - 'format': vcFormat, - 'path': r'$.verifiableCredential', - }, - }); - } - } else { - for (int i = 0; i < credentialsToBePresented.length; i++) { - InputDescriptor? descriptor; - - for (final InputDescriptor inputDescriptor - in presentationDefinition.inputDescriptors) { - for (final Field field in inputDescriptor.constraints!.fields!) { - final credentialName = - field.filter!.pattern ?? field.filter!.contains!.containsConst; - if (credentialsToBePresented[i] - .credentialPreview - .type - .contains(credentialName)) { - descriptor = inputDescriptor; - } + inputDescriptors.add({ + 'id': inputDescriptor.id, + 'format': vpFormat, + 'path': r'$', + 'path_nested': { + 'id': inputDescriptor.id, + 'format': vcFormat, + // ignore: prefer_interpolation_to_compose_strings + 'path': r'$.verifiableCredential[' + i.toString() + ']', + }, + }); } } - if (descriptor != null) { - inputDescriptors.add({ - 'id': descriptor.id, - 'format': vpFormat, - 'path': r'$', - 'path_nested': { - 'id': descriptor.id, - 'format': vcFormat, - // ignore: prefer_interpolation_to_compose_strings - 'path': r'$.verifiableCredential[' + i.toString() + ']', - }, - }); - } } } diff --git a/packages/credential_manifest/lib/credential_manifest.dart b/packages/credential_manifest/lib/credential_manifest.dart index 2ffd64656..b0db099d7 100644 --- a/packages/credential_manifest/lib/credential_manifest.dart +++ b/packages/credential_manifest/lib/credential_manifest.dart @@ -14,6 +14,7 @@ export 'src/models/display_mapping_text.dart'; export 'src/models/display_object.dart'; export 'src/models/field.dart'; export 'src/models/filter.dart'; +export 'src/models/format.dart'; export 'src/models/image_object.dart'; export 'src/models/input_descriptor.dart'; export 'src/models/issued_by.dart'; diff --git a/pubspec.lock b/pubspec.lock index fe526d711..b4a52d252 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -150,18 +150,18 @@ packages: dependency: "direct main" description: name: bloc - sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49" + sha256: f53a110e3b48dcd78136c10daa5d51512443cea5e1348c9d80a320095fa2db9e url: "https://pub.dev" source: hosted - version: "8.1.2" + version: "8.1.3" bloc_test: dependency: "direct dev" description: name: bloc_test - sha256: "02f04270be5abae8df171143e61a0058a7acbce5dcac887612e89bb40cca4c33" + sha256: "55a48f69e0d480717067c5377c8485a3fcd41f1701a820deef72fa0f4ee7215f" url: "https://pub.dev" source: hosted - version: "9.1.5" + version: "9.1.6" blurhash_dart: dependency: transitive description: @@ -492,10 +492,10 @@ packages: dependency: "direct main" description: name: dart_jsonwebtoken - sha256: "063c20d3cee2b626d8a789ba9df0ad21f35012c4e9bd846ce50e921d77123df7" + sha256: "40dc3a4788c02a44bc97ea0c8c4a078ae58c9a45acc2312ee6a689b0e8f5b5b9" url: "https://pub.dev" source: hosted - version: "2.12.2" + version: "2.13.0" dart_style: dependency: transitive description: @@ -832,10 +832,10 @@ packages: dependency: "direct main" description: name: flutter_bloc - sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae + sha256: "87325da1ac757fcc4813e6b34ed5dd61169973871fdf181d6c2109dd6935ece1" url: "https://pub.dev" source: hosted - version: "8.1.3" + version: "8.1.4" flutter_cache_manager: dependency: transitive description: @@ -1231,10 +1231,10 @@ packages: dependency: "direct main" description: name: image - sha256: "49a0d4b0c12402853d3f227fe7c315601b238d126aa4caa5dbb2dcf99421aa4a" + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" url: "https://pub.dev" source: hosted - version: "4.1.6" + version: "4.1.7" image_picker: dependency: "direct main" description: @@ -1421,10 +1421,10 @@ packages: dependency: transitive description: name: local_auth_ios - sha256: eb283b530029b334698918f1e282d4483737cbca972ff21b9193be3d6de8e2b8 + sha256: "6dde47dc852bc0c8343cb58e66a46efb16b62eddf389ce103d4dacb0c6c40c71" url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "1.1.7" local_auth_platform_interface: dependency: transitive description: @@ -1732,26 +1732,26 @@ packages: dependency: "direct main" description: name: permission_handler - sha256: "45ff3fbcb99040fde55c528d5e3e6ca29171298a85436274d49c6201002087d6" + sha256: "3c84d49f0a5e1915364707159ab71f11b3b8a429532176d3a6248a45718ad4f9" url: "https://pub.dev" source: hosted - version: "11.2.0" + version: "11.2.1" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: "758284a0976772f9c744d6384fc5dc4834aa61e3f7aa40492927f244767374eb" + sha256: a5ebaa420cee8fd880ef10dedd42c6b3f493e7dbe27d7e0a7e1798669373082a url: "https://pub.dev" source: hosted - version: "12.0.3" + version: "12.0.4" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: c6bf440f80acd2a873d3d91a699e4cc770f86e7e6b576dda98759e8b92b39830 + sha256: "6ca25ee52518a8a26e80aaefe3c71caf6e2dfd809c1b20900d0882df6faed36e" url: "https://pub.dev" source: hosted - version: "9.3.0" + version: "9.3.1" permission_handler_html: dependency: transitive description: @@ -2593,18 +2593,18 @@ packages: dependency: "direct main" description: name: webview_flutter - sha256: d81b68e88cc353e546afb93fb38958e3717282c5ac6e5d3be4a4aef9fc3c1413 + sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932" url: "https://pub.dev" source: hosted - version: "4.5.0" + version: "4.7.0" webview_flutter_android: dependency: "direct main" description: name: webview_flutter_android - sha256: "4ea3c4e1b8ed590162b15b8a61b41b1ef3ff179a314627c16ce40c086d94b8af" + sha256: "3e5f4e9d818086b0d01a66fb1ff9cc72ab0cc58c71980e3d3661c5685ea0efb0" url: "https://pub.dev" source: hosted - version: "3.14.0" + version: "3.15.0" webview_flutter_platform_interface: dependency: transitive description: @@ -2617,10 +2617,10 @@ packages: dependency: "direct main" description: name: webview_flutter_wkwebview - sha256: b99ca8d8bae9c6b43d568218691aa537fb0aeae1d7d34eadf112a6aa36d26506 + sha256: "9bf168bccdf179ce90450b5f37e36fe263f591c9338828d6bf09b6f8d0f57f86" url: "https://pub.dev" source: hosted - version: "3.11.0" + version: "3.12.0" win32: dependency: transitive description: From c2e53fa90604f9e27366b582480f7e27dc5818f2 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 12 Feb 2024 16:50:18 +0000 Subject: [PATCH 28/70] version: 2.2.21+383 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index cc953fd46..eace5b719 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.20+382 +version: 2.2.21+383 environment: sdk: ">=3.1.0 <4.0.0" From b3905c88333799c09287878ecae413c9a9db3a9a Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 12 Feb 2024 17:45:50 +0000 Subject: [PATCH 29/70] version: 2.2.22+384 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index eace5b719..ada8c5744 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.21+383 +version: 2.2.22+384 environment: sdk: ">=3.1.0 <4.0.0" From 7f5e7d6a8482b22ea5258988f9e2adb529004272 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 13 Feb 2024 11:58:57 +0545 Subject: [PATCH 30/70] Remove switch PIN digits from oidc4vc settings and take 4 digits as default #2382 --- lib/app/shared/enum/type/profile/profile.dart | 1 - .../enum/type/profile/user_pin_digits.dart | 20 --------- .../view/oidc4vc_settings_menu.dart | 1 - .../widget/six_or_four_pin_widget.dart | 41 ------------------- .../ssi/oidc4vc_settngs/widget/widget.dart | 1 - .../profile/cubit/profile_cubit.dart | 7 ---- lib/dashboard/profile/models/profile.dart | 3 -- .../profile/models/profile_setting.dart | 6 --- .../user_pin/view/user_pin_page.dart | 4 +- 9 files changed, 1 insertion(+), 83 deletions(-) delete mode 100644 lib/app/shared/enum/type/profile/user_pin_digits.dart delete mode 100644 lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/six_or_four_pin_widget.dart diff --git a/lib/app/shared/enum/type/profile/profile.dart b/lib/app/shared/enum/type/profile/profile.dart index 4a54675ea..38619749c 100644 --- a/lib/app/shared/enum/type/profile/profile.dart +++ b/lib/app/shared/enum/type/profile/profile.dart @@ -1,5 +1,4 @@ export 'did_key_type.dart'; export 'profile_type.dart'; export 'subject_syntax.dart'; -export 'user_pin_digits.dart'; export 'wallet_app_type.dart'; diff --git a/lib/app/shared/enum/type/profile/user_pin_digits.dart b/lib/app/shared/enum/type/profile/user_pin_digits.dart deleted file mode 100644 index f687dd1ea..000000000 --- a/lib/app/shared/enum/type/profile/user_pin_digits.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -enum UserPinDigits { - @JsonValue('4') - four, - - @JsonValue('6') - six, -} - -extension UserPinDigitsX on UserPinDigits { - int get value { - switch (this) { - case UserPinDigits.four: - return 4; - case UserPinDigits.six: - return 6; - } - } -} 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 97c6a310e..38f8078b0 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 @@ -40,7 +40,6 @@ class Oidc4vcSettingMenuView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SecurityLevelWidget(), - const SixOrForUserPinWidget(), const DidKeyTypeWidget(), const DraftTypeWidget(), const SubjectSyntaxTypeWidget(), diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/six_or_four_pin_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/six_or_four_pin_widget.dart deleted file mode 100644 index 93cceef85..000000000 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/six_or_four_pin_widget.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:altme/app/app.dart'; -import 'package:altme/dashboard/dashboard.dart'; -import 'package:altme/l10n/l10n.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -class SixOrForUserPinWidget extends StatelessWidget { - const SixOrForUserPinWidget({super.key}); - - @override - Widget build(BuildContext context) { - final l10n = context.l10n; - return BlocBuilder( - builder: (context, state) { - return DrawerItem2( - title: l10n.userPinTitle, - subtitle: l10n.userPinSubtitle, - trailing: SizedBox( - height: 25, - child: BlocBuilder( - builder: (context, state) { - return Switch( - onChanged: (value) async { - await context.read().updateProfileSetting( - userPinDigits: - value ? UserPinDigits.four : UserPinDigits.six, - ); - }, - value: state.model.profileSetting.selfSovereignIdentityOptions - .customOidc4vcProfile.userPinDigits == - UserPinDigits.four, - activeColor: Theme.of(context).colorScheme.primary, - ); - }, - ), - ), - ); - }, - ); - } -} diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart index 62d9b9e4f..de2ca74d6 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart @@ -8,6 +8,5 @@ export 'option_container.dart'; export 'proof_header_widget.dart'; export 'scope_parameter.dart'; export 'security_level_widget.dart'; -export 'six_or_four_pin_widget.dart'; export 'subject_syntax_type_widget.dart'; export 'vc_format_widget.dart'; diff --git a/lib/dashboard/profile/cubit/profile_cubit.dart b/lib/dashboard/profile/cubit/profile_cubit.dart index d1634367f..626578322 100644 --- a/lib/dashboard/profile/cubit/profile_cubit.dart +++ b/lib/dashboard/profile/cubit/profile_cubit.dart @@ -193,11 +193,6 @@ class ProfileCubit extends Cubit { customProfileBackup['enableJWKThumbprint'] == 'true' ? SubjectSyntax.jwkThumbprint : SubjectSyntax.did, - userPinDigits: - customProfileBackup.containsKey('enable4DigitPINCode') && - customProfileBackup['enable4DigitPINCode'] == 'true' - ? UserPinDigits.four - : UserPinDigits.six, clientId: customProfileBackup.containsKey('clientId') ? customProfileBackup['clientId'].toString() : Parameters.clientId, @@ -455,7 +450,6 @@ class ProfileCubit extends Cubit { Future updateProfileSetting({ DidKeyType? didKeyType, bool? securityLevel, - UserPinDigits? userPinDigits, bool? scope, bool? cryptoHolderBinding, bool? credentialManifestSupport, @@ -485,7 +479,6 @@ class ProfileCubit extends Cubit { customOidc4vcProfile: state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile .copyWith( - userPinDigits: userPinDigits, defaultDid: didKeyType, securityLevel: securityLevel, proofHeader: proofHeaderType, diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index 18e086444..fd4102347 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -65,7 +65,6 @@ class ProfileModel extends Equatable { proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, subjectSyntaxeType: SubjectSyntax.did, - userPinDigits: UserPinDigits.four, clientId: clientId, clientSecret: clientSecret, vcFormatType: VCFormatType.jwtVc, @@ -112,7 +111,6 @@ class ProfileModel extends Equatable { proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, subjectSyntaxeType: SubjectSyntax.did, - userPinDigits: UserPinDigits.four, clientId: clientId, clientSecret: clientSecret, vcFormatType: VCFormatType.jwtVcJson, @@ -159,7 +157,6 @@ class ProfileModel extends Equatable { proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, subjectSyntaxeType: SubjectSyntax.did, - userPinDigits: UserPinDigits.four, clientId: clientId, clientSecret: clientSecret, vcFormatType: VCFormatType.vcSdJWT, diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index 99562dcfd..62cdd2438 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -518,7 +518,6 @@ class CustomOidc4VcProfile extends Equatable { required this.securityLevel, required this.siopv2Draft, required this.subjectSyntaxeType, - required this.userPinDigits, required this.clientId, required this.clientSecret, this.vcFormatType = VCFormatType.ldpVc, @@ -537,7 +536,6 @@ class CustomOidc4VcProfile extends Equatable { securityLevel: false, siopv2Draft: SIOPV2DraftType.draft12, subjectSyntaxeType: SubjectSyntax.did, - userPinDigits: UserPinDigits.six, clientId: Parameters.clientId, clientSecret: randomString(12), vcFormatType: VCFormatType.ldpVc, @@ -561,7 +559,6 @@ class CustomOidc4VcProfile extends Equatable { final bool securityLevel; final SIOPV2DraftType siopv2Draft; final SubjectSyntax subjectSyntaxeType; - final UserPinDigits userPinDigits; @JsonKey(name: 'vcFormat') final VCFormatType vcFormatType; @@ -581,7 +578,6 @@ class CustomOidc4VcProfile extends Equatable { bool? securityLevel, SIOPV2DraftType? siopv2Draft, SubjectSyntax? subjectSyntaxeType, - UserPinDigits? userPinDigits, VCFormatType? vcFormatType, }) => CustomOidc4VcProfile( @@ -597,7 +593,6 @@ class CustomOidc4VcProfile extends Equatable { securityLevel: securityLevel ?? this.securityLevel, siopv2Draft: siopv2Draft ?? this.siopv2Draft, subjectSyntaxeType: subjectSyntaxeType ?? this.subjectSyntaxeType, - userPinDigits: userPinDigits ?? this.userPinDigits, clientId: clientId ?? this.clientId, clientSecret: clientSecret ?? this.clientSecret, vcFormatType: vcFormatType ?? this.vcFormatType, @@ -618,7 +613,6 @@ class CustomOidc4VcProfile extends Equatable { securityLevel, siopv2Draft, subjectSyntaxeType, - userPinDigits, vcFormatType, ]; } diff --git a/lib/dashboard/user_pin/view/user_pin_page.dart b/lib/dashboard/user_pin/view/user_pin_page.dart index edf904ce9..fd119ac7a 100644 --- a/lib/dashboard/user_pin/view/user_pin_page.dart +++ b/lib/dashboard/user_pin/view/user_pin_page.dart @@ -90,9 +90,7 @@ class _UserPinViewState extends State { title: widget.txCode?.description ?? l10n.pleaseInsertTheSecredCodeReceived, passwordEnteredCallback: _onPasscodeEntered, - passwordDigits: widget.txCode?.length ?? - state.model.profileSetting.selfSovereignIdentityOptions - .customOidc4vcProfile.userPinDigits.value, + passwordDigits: widget.txCode?.length ?? 4, deleteButton: Text( l10n.delete, style: Theme.of(context).textTheme.labelLarge, From f35d44dca88410fd325cf906aaf66c7823455efb Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 13 Feb 2024 12:26:54 +0545 Subject: [PATCH 31/70] Display of the preview image of the VC in the OIDC4VCI flow (display attribute) #2343 --- .../view/oid4c4vc_credential_pick_page.dart | 1 + .../widgets/credential_display.dart | 3 ++ .../default_credential_widget.dart | 3 ++ .../widgets/default_display_descriptor.dart | 39 ++++++++++++------- 4 files changed, 31 insertions(+), 15 deletions(-) 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 0db3cca0f..99999aa1d 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,6 +167,7 @@ class Oidc4vcCredentialPickView extends StatelessWidget { ), credDisplayType: CredDisplayType.List, vcFormatType: vcFormatType, + displyalDescription: false, ) else DummyCredentialImage( diff --git a/lib/dashboard/home/tab_bar/credentials/widgets/credential_display.dart b/lib/dashboard/home/tab_bar/credentials/widgets/credential_display.dart index 4ff673ffb..8b821d0e0 100644 --- a/lib/dashboard/home/tab_bar/credentials/widgets/credential_display.dart +++ b/lib/dashboard/home/tab_bar/credentials/widgets/credential_display.dart @@ -9,11 +9,13 @@ class CredentialDisplay extends StatelessWidget { required this.credentialModel, required this.credDisplayType, required this.vcFormatType, + this.displyalDescription = true, }); final CredentialModel credentialModel; final CredDisplayType credDisplayType; final VCFormatType vcFormatType; + final bool displyalDescription; @override Widget build(BuildContext context) { @@ -83,6 +85,7 @@ class CredentialDisplay extends StatelessWidget { return DefaultCredentialWidget( credentialModel: credentialModel, showBgDecoration: false, + displyalDescription: displyalDescription, ); case CredDisplayType.Detail: return DefaultCredentialWidget( diff --git a/lib/dashboard/home/tab_bar/credentials/widgets/credential_widget/default_credential_widget.dart b/lib/dashboard/home/tab_bar/credentials/widgets/credential_widget/default_credential_widget.dart index 940c8510e..0ab257272 100644 --- a/lib/dashboard/home/tab_bar/credentials/widgets/credential_widget/default_credential_widget.dart +++ b/lib/dashboard/home/tab_bar/credentials/widgets/credential_widget/default_credential_widget.dart @@ -7,11 +7,13 @@ class DefaultCredentialWidget extends StatelessWidget { required this.credentialModel, this.showBgDecoration = true, this.descriptionMaxLine = 2, + this.displyalDescription = true, }); final CredentialModel credentialModel; final int descriptionMaxLine; final bool showBgDecoration; + final bool displyalDescription; @override Widget build(BuildContext context) { @@ -25,6 +27,7 @@ class DefaultCredentialWidget extends StatelessWidget { credentialModel: credentialModel, descriptionMaxLine: descriptionMaxLine, showBgDecoration: showBgDecoration, + displyalDescription: displyalDescription, ); } else { return CredentialManifestCard( diff --git a/lib/dashboard/home/tab_bar/credentials/widgets/default_display_descriptor.dart b/lib/dashboard/home/tab_bar/credentials/widgets/default_display_descriptor.dart index efbdf6b3e..8b82e5ea5 100644 --- a/lib/dashboard/home/tab_bar/credentials/widgets/default_display_descriptor.dart +++ b/lib/dashboard/home/tab_bar/credentials/widgets/default_display_descriptor.dart @@ -10,11 +10,13 @@ class DefaultDisplayDescriptor extends StatelessWidget { this.showBgDecoration = true, required this.credentialModel, required this.descriptionMaxLine, + this.displyalDescription = true, }); final CredentialModel credentialModel; final int descriptionMaxLine; final bool showBgDecoration; + final bool displyalDescription; @override Widget build(BuildContext context) { @@ -29,6 +31,7 @@ class DefaultDisplayDescriptor extends StatelessWidget { child: DefaultCardBody( credentialModel: credentialModel, descriptionMaxLine: descriptionMaxLine, + displyalDescription: displyalDescription, ), ), ) @@ -42,6 +45,7 @@ class DefaultDisplayDescriptor extends StatelessWidget { child: DefaultCardBody( credentialModel: credentialModel, descriptionMaxLine: descriptionMaxLine, + displyalDescription: displyalDescription, ), ), ) @@ -52,6 +56,7 @@ class DefaultDisplayDescriptor extends StatelessWidget { child: DefaultCardBody( credentialModel: credentialModel, descriptionMaxLine: descriptionMaxLine, + displyalDescription: displyalDescription, ), ), ); @@ -64,12 +69,15 @@ class DefaultCardBody extends StatelessWidget { required this.credentialModel, required this.descriptionMaxLine, this.showBgDecoration = true, + this.displyalDescription = true, }); final CredentialModel credentialModel; final int descriptionMaxLine; final bool showBgDecoration; + final bool displyalDescription; + @override Widget build(BuildContext context) { final l10n = context.l10n; @@ -160,24 +168,25 @@ class DefaultCardBody extends StatelessWidget { ), ), ), - LayoutId( - id: 'value', - child: FractionallySizedBox( - widthFactor: 0.8, - heightFactor: 0.15, - child: Container( - alignment: Alignment.centerLeft, - child: DisplayDescriptionCard( - credentialModel: credentialModel, - style: Theme.of(context) - .textTheme - .credentialBaseBoldText - .copyWith(color: textColor), - maxLines: descriptionMaxLine, + if (displyalDescription) + LayoutId( + id: 'value', + child: FractionallySizedBox( + widthFactor: 0.8, + heightFactor: 0.15, + child: Container( + alignment: Alignment.centerLeft, + child: DisplayDescriptionCard( + credentialModel: credentialModel, + style: Theme.of(context) + .textTheme + .credentialBaseBoldText + .copyWith(color: textColor), + maxLines: descriptionMaxLine, + ), ), ), ), - ), if (credentialModel.credentialPreview.issuanceDate != '') LayoutId( id: 'issued-on', From ff4bc8934a78934ae87cc280ad48f5ed04d6fa6c Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 13 Feb 2024 14:27:10 +0545 Subject: [PATCH 32/70] Show credential subject data for other tests --- .../detail/view/credentials_details_page.dart | 16 ++-- lib/oidc4vc/add_oidc4vc_credential.dart | 78 +++++++++---------- .../lib/src/models/openid_configuration.dart | 3 + 3 files changed, 50 insertions(+), 47 deletions(-) diff --git a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart index 2e2bc0c99..8d945e7a8 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart @@ -302,6 +302,14 @@ class _CredentialsDetailsViewState extends State { credentialModel: widget.credentialModel, ), + /// claims data , from draft 13 + if (widget.credentialModel.credentialSupported != + null && + widget.credentialModel.credentialSupported! + .containsKey('claims')) ...[ + ClaimsData(credentialModel: widget.credentialModel), + ], + //// wallet attestation data if (widget.credentialModel.credentialPreview .credentialSubjectModel @@ -326,14 +334,6 @@ class _CredentialsDetailsViewState extends State { ), ], - /// claims data , from draft 13 - if (widget.credentialModel.credentialSupported != - null && - widget.credentialModel.credentialSupported! - .containsKey('claims')) ...[ - ClaimsData(credentialModel: widget.credentialModel), - ], - /// selective disclouse data - _sd if (widget.credentialModel.jwt != null && widget.credentialModel.jwt!.contains('~')) ...[ diff --git a/lib/oidc4vc/add_oidc4vc_credential.dart b/lib/oidc4vc/add_oidc4vc_credential.dart index 3bbbbe1a5..f4e22efd6 100644 --- a/lib/oidc4vc/add_oidc4vc_credential.dart +++ b/lib/oidc4vc/add_oidc4vc_credential.dart @@ -147,50 +147,50 @@ Future addOIDC4VCCredential({ Display? display; - if (!newCredential.containsKey('credential_manifest')) { - if (openIdConfiguration?.credentialsSupported != null) { - final credentialsSupported = openIdConfiguration!.credentialsSupported!; - final CredentialsSupported? credSupported = - credentialsSupported.firstWhereOrNull( - (CredentialsSupported credentialsSupported) => - credentialsSupported.id != null && - credentialsSupported.id == credentialType, - ); - - newCredential['credentialSupported'] = credentialsSupported; - - if (credSupported != null && credSupported.display != null) { + if (openIdConfiguration?.credentialsSupported != null) { + final credentialsSupported = openIdConfiguration!.credentialsSupported!; + final CredentialsSupported? credSupported = + credentialsSupported.firstWhereOrNull( + (CredentialsSupported credentialsSupported) => + credentialsSupported.id != null && + credentialsSupported.id == credentialType, + ); + + if (credSupported != null) { + newCredential['credentialSupported'] = credSupported.toJson(); + + if (credSupported.display != null) { display = credSupported.display!.firstWhereOrNull( (Display display) => display.locale == 'en-US' || display.locale == 'en-GB', ); } - } else if (openIdConfiguration?.credentialConfigurationsSupported != null) { - final credentialsSupported = - openIdConfiguration!.credentialConfigurationsSupported; - - if ((credentialsSupported is Map) && - credentialsSupported.containsKey(credentialType)) { - final credSupported = credentialsSupported[credentialType]; - - /// credentialSupported - newCredential['credentialSupported'] = credSupported; - - if (credSupported is Map) { - /// display - if (credSupported.containsKey('display')) { - final displayData = credSupported['display']; - - if (displayData is List) { - final displays = displayData - .map((ele) => Display.fromJson(ele as Map)) - .toList(); - - display = displays.firstWhereOrNull( - (Display display) => - display.locale == 'en-US' || display.locale == 'en-GB', - ); - } + } + } else if (openIdConfiguration?.credentialConfigurationsSupported != null) { + final credentialsSupported = + openIdConfiguration!.credentialConfigurationsSupported; + + if ((credentialsSupported is Map) && + credentialsSupported.containsKey(credentialType)) { + final credSupported = credentialsSupported[credentialType]; + + /// credentialSupported + newCredential['credentialSupported'] = credSupported; + + if (credSupported is Map) { + /// display + if (credSupported.containsKey('display')) { + final displayData = credSupported['display']; + + if (displayData is List) { + final displays = displayData + .map((ele) => Display.fromJson(ele as Map)) + .toList(); + + display = displays.firstWhereOrNull( + (Display display) => + display.locale == 'en-US' || display.locale == 'en-GB', + ); } } } diff --git a/packages/oidc4vc/lib/src/models/openid_configuration.dart b/packages/oidc4vc/lib/src/models/openid_configuration.dart index fc1aa587c..78c688b9e 100644 --- a/packages/oidc4vc/lib/src/models/openid_configuration.dart +++ b/packages/oidc4vc/lib/src/models/openid_configuration.dart @@ -92,6 +92,7 @@ class CredentialsSupported extends Equatable { this.types, this.id, this.scope, + this.credentialSubject, }); factory CredentialsSupported.fromJson(Map json) => @@ -104,6 +105,7 @@ class CredentialsSupported extends Equatable { final List? types; final String? id; final String? scope; + final dynamic credentialSubject; Map toJson() => _$CredentialsSupportedToJson(this); @@ -115,6 +117,7 @@ class CredentialsSupported extends Equatable { types, id, scope, + credentialSubject, ]; } From ec289dc5ae24cc25458fe149c8193ebd91b0bfb3 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Tue, 13 Feb 2024 20:21:02 +0545 Subject: [PATCH 33/70] Handle claims data both encrypted and non-encrypted and handled data based on language --- .../shared/extension/string_extension.dart | 7 -- lib/app/view/app.dart | 2 +- .../detail/view/credentials_details_page.dart | 25 +++--- .../detail/widgets/claims_data.dart | 80 +++++++++++++++---- .../widgets/credential_subject_data.dart | 15 +++- .../widgets/selective_disclosure_data.dart | 57 ------------- .../credentials/detail/widgets/widgets.dart | 1 - lib/lang/cubit/lang_cubit.dart | 5 +- 8 files changed, 93 insertions(+), 99 deletions(-) delete mode 100644 lib/dashboard/home/tab_bar/credentials/detail/widgets/selective_disclosure_data.dart diff --git a/lib/app/shared/extension/string_extension.dart b/lib/app/shared/extension/string_extension.dart index fea95a8fa..e57dcc269 100644 --- a/lib/app/shared/extension/string_extension.dart +++ b/lib/app/shared/extension/string_extension.dart @@ -34,11 +34,4 @@ extension StringExtension on String { } Characters get characters => Characters(this); - - String get beautityTitle { - List words = split('_'); - words = - words.map((word) => word[0].toUpperCase() + word.substring(1)).toList(); - return words.join(''); - } } diff --git a/lib/app/view/app.dart b/lib/app/view/app.dart index f54f771f5..dfc8ed035 100644 --- a/lib/app/view/app.dart +++ b/lib/app/view/app.dart @@ -242,7 +242,7 @@ class MaterialAppDefinition extends StatelessWidget { create: (context) => LangCubit(), child: BlocBuilder( builder: (context, lang) { - //context.read().fetchLocale(); + context.read().fetchLocale(); return MaterialApp( builder: isStaging ? DevicePreview.appBuilder : null, locale: isStaging ? DevicePreview.locale(context) : lang, diff --git a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart index 8d945e7a8..f500586b9 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/view/credentials_details_page.dart @@ -302,14 +302,27 @@ class _CredentialsDetailsViewState extends State { credentialModel: widget.credentialModel, ), - /// claims data , from draft 13 + /// selective disclouse data - _sd + /// and normal data too if (widget.credentialModel.credentialSupported != null && widget.credentialModel.credentialSupported! .containsKey('claims')) ...[ - ClaimsData(credentialModel: widget.credentialModel), + ClaimsData( + credentialModel: widget.credentialModel, + ), ], + // /// normal claims data + // if (widget.credentialModel.credentialSupported != + // null && + // widget.credentialModel.credentialSupported! + // .containsKey('claims')) ...[ + // NormalClaimsData( + // credentialModel: widget.credentialModel, + // ), + // ], + //// wallet attestation data if (widget.credentialModel.credentialPreview .credentialSubjectModel @@ -333,14 +346,6 @@ class _CredentialsDetailsViewState extends State { credentialModel: widget.credentialModel, ), ], - - /// selective disclouse data - _sd - if (widget.credentialModel.jwt != null && - widget.credentialModel.jwt!.contains('~')) ...[ - SelectiveDisclosureData( - credentialModel: widget.credentialModel, - ), - ], ], if (state.credentialDetailTabStatus == CredentialDetailTabStatus.activity) ...[ diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart index 67315a95d..8d806096b 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart @@ -1,7 +1,11 @@ +import 'dart:convert'; + import 'package:altme/app/app.dart'; import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/lang/cubit/lang_cubit.dart'; import 'package:altme/theme/theme.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; class ClaimsData extends StatelessWidget { const ClaimsData({ @@ -17,21 +21,49 @@ class ClaimsData extends StatelessWidget { final claims = credentialSupported!['claims']; - if (claims! is Map) { + if (claims is! Map) { return Container(); } + final encryptedDatas = credentialModel.jwt?.split('~'); + + final credentialSubjectData = {}; + + if (encryptedDatas != null) { + encryptedDatas.removeAt(0); + + for (final element in encryptedDatas) { + try { + final decryptedData = utf8.decode(base64Decode(element)); + if (decryptedData.isNotEmpty) { + final lisString = decryptedData + .substring(1, decryptedData.length - 1) + .replaceAll('"', '') + .split(','); + + if (lisString.length == 3) { + credentialSubjectData[lisString[1].trim()] = lisString[2].trim(); + } + } + } catch (e) { + // + } + } + } + + final locale = context.read().state; + + final localeString = '${locale.languageCode}-${locale.countryCode}'; + return Column( crossAxisAlignment: CrossAxisAlignment.start, - children: (claims as Map) - .entries - .map((MapEntry map) { + children: claims.entries.map((MapEntry map) { + String? title; + String? data; + final key = map.key; final value = map.value; - String title = key; - String data = value.toString(); - if (value is! Map) return Container(); if (value.isEmpty) return Container(); @@ -46,20 +78,36 @@ class ClaimsData extends StatelessWidget { if (value.containsKey('display')) { final displays = value['display']; if (displays is! List) return Container(); - if (displays.length < 2) return Container(); - - for (final display in displays) { - if (display is! Map) return Container(); - - if (display['name'] == null) return Container(); + if (displays.isEmpty) return Container(); + + final display = displays.where((element) { + if (element is Map && + element.containsKey('locale')) { + if (element['locale'] == localeString) { + return true; + } else if (element['locale'] == 'en-US') { + return true; + } + } + return false; + }).firstOrNull; + + if (display == null) return Container(); + + if (credentialSubjectData.isNotEmpty && + credentialSubjectData.containsKey(key)) { + title = display['name'].toString(); + data = credentialSubjectData[key].toString(); + } else if (credentialModel.data.containsKey(key)) { + title = display['name'].toString(); + data = credentialModel.data[key].toString(); } - - title = displays[0]['name'].toString(); - data = displays[1]['name'].toString(); } else { return Container(); } + if (title == null || data == null) return Container(); + return Padding( padding: const EdgeInsets.only(top: 10), child: CredentialField( 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 b6ec0a26f..7ff2f8398 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 @@ -1,7 +1,9 @@ import 'package:altme/app/app.dart'; import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/lang/cubit/lang_cubit.dart'; import 'package:altme/theme/theme.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:json_path/json_path.dart'; class CredentialSubjectData extends StatelessWidget { @@ -29,6 +31,10 @@ class CredentialSubjectData extends StatelessWidget { if (credentialSubjectData == null) return Container(); if (credentialSubjectData is! Map) return Container(); + final locale = context.read().state; + + final localeString = '${locale.languageCode}-${locale.countryCode}'; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: credentialSubjectReference.entries @@ -56,9 +62,12 @@ class CredentialSubjectData extends StatelessWidget { final display = displays.where((element) { if (element is Map && - element.containsKey('locale') && - element['locale'] == 'en-US') { - return true; + element.containsKey('locale')) { + if (element['locale'] == localeString) { + return true; + } else if (element['locale'] == 'en-US') { + return true; + } } return false; }).firstOrNull; diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/selective_disclosure_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/selective_disclosure_data.dart deleted file mode 100644 index 35a994636..000000000 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/selective_disclosure_data.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'dart:convert'; - -import 'package:altme/app/app.dart'; -import 'package:altme/dashboard/dashboard.dart'; -import 'package:altme/theme/theme.dart'; -import 'package:flutter/material.dart'; - -class SelectiveDisclosureData extends StatelessWidget { - const SelectiveDisclosureData({ - super.key, - required this.credentialModel, - }); - - final CredentialModel credentialModel; - - @override - Widget build(BuildContext context) { - final encryptedDatas = credentialModel.jwt!.split('~'); - encryptedDatas.removeAt(0); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: encryptedDatas.map((dynamic element) { - dynamic decryptedData; - - try { - decryptedData = utf8.decode(base64Decode(element.toString())); - } catch (e) { - return Container(); - } - - if (decryptedData.toString().isEmpty) return Container(); - - final lisString = decryptedData - .toString() - .substring(1, decryptedData.toString().length - 1) - .replaceAll('"', '') - .split(','); - - if (lisString.length < 3) { - return Container(); - } - - return Padding( - padding: const EdgeInsets.only(top: 10), - child: CredentialField( - padding: EdgeInsets.zero, - title: lisString[1].beautityTitle, - value: lisString[2], - titleColor: Theme.of(context).colorScheme.titleColor, - valueColor: Theme.of(context).colorScheme.valueColor, - ), - ); - }).toList(), - ); - } -} diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart index 432db56ff..e8518d68b 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/widgets.dart @@ -3,4 +3,3 @@ export 'credential_active_status.dart'; export 'credential_subject_data.dart'; export 'deferred_credential_data.dart'; export 'developer_details.dart'; -export 'selective_disclosure_data.dart'; diff --git a/lib/lang/cubit/lang_cubit.dart b/lib/lang/cubit/lang_cubit.dart index 40bc39700..1bc883ac1 100644 --- a/lib/lang/cubit/lang_cubit.dart +++ b/lib/lang/cubit/lang_cubit.dart @@ -10,14 +10,11 @@ class LangCubit extends Cubit { Future fetchLocale() async { final Locale? locale = await Devicelocale.currentAsLocale; - const Locale frenchLocale = Locale('fr', 'FR'); final langauageCode = locale!.languageCode; if (AppLocalizations.supportedLocales.contains(Locale(langauageCode))) { - if (langauageCode == frenchLocale.languageCode) { - emit(locale); - } + emit(locale); } } } From ba8b34daf85fb3c6a8d9829f40e5bad5654b7e8f Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Tue, 13 Feb 2024 17:29:10 +0000 Subject: [PATCH 34/70] version: 2.2.23+385 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index ada8c5744..bcb123225 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.22+384 +version: 2.2.23+385 environment: sdk: ">=3.1.0 <4.0.0" From aace929c4046d81302f8112c3c053b9773804750 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 14 Feb 2024 13:07:15 +0545 Subject: [PATCH 35/70] feat: New profile Default #2385 --- .vscode/launch.json | 8 +- lib/app/shared/constants/parameters.dart | 6 + .../enum/type/profile/profile_type.dart | 16 +- lib/app/shared/widget/wallet_logo.dart | 1 + .../profile/cubit/profile_cubit.dart | 137 +++++++----------- lib/dashboard/profile/models/profile.dart | 80 +++++++++- .../profile/models/profile_setting.dart | 32 +++- lib/l10n/arb/app_en.arb | 5 +- lib/l10n/untranslated.json | 20 ++- .../helper_function/helper_function.dart | 3 + lib/onboarding/starter/view/starter_page.dart | 2 +- lib/wallet/cubit/wallet_cubit.dart | 2 +- pubspec.lock | 28 ++-- 13 files changed, 211 insertions(+), 129 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"] } ] } diff --git a/lib/app/shared/constants/parameters.dart b/lib/app/shared/constants/parameters.dart index 9a7a6f103..e48f5107f 100644 --- a/lib/app/shared/constants/parameters.dart +++ b/lib/app/shared/constants/parameters.dart @@ -1,3 +1,4 @@ +import 'package:altme/app/shared/enum/enum.dart'; import 'package:altme/dashboard/dashboard.dart'; class Parameters { @@ -67,4 +68,9 @@ class Parameters { static const int maxEntries = 3; static const String appName = 'Altme'; + + static const DidKeyType didKeyTypeForEbsiV3 = DidKeyType.ebsiv3; + static const DidKeyType didKeyTypeForDefault = DidKeyType.edDSA; + static const DidKeyType didKeyTypeForDutch = DidKeyType.jwkP256; + static const DidKeyType didKeyTypeForOwfBaselineProfile = DidKeyType.jwkP256; } diff --git a/lib/app/shared/enum/type/profile/profile_type.dart b/lib/app/shared/enum/type/profile/profile_type.dart index 6db79dd0c..90104e4c3 100644 --- a/lib/app/shared/enum/type/profile/profile_type.dart +++ b/lib/app/shared/enum/type/profile/profile_type.dart @@ -1,6 +1,13 @@ import 'package:altme/l10n/l10n.dart'; -enum ProfileType { custom, ebsiV3, dutch, enterprise, owfBaselineProfile } +enum ProfileType { + custom, + ebsiV3, + dutch, + enterprise, + owfBaselineProfile, + defaultOne +} extension ProfileTypeX on ProfileType { String getTitle({ @@ -15,15 +22,18 @@ extension ProfileTypeX on ProfileType { case ProfileType.dutch: return l10n.decentralizedIdentityInteropProfile; case ProfileType.enterprise: - return name.isEmpty ? 'Enterprise' : name; + return name.isEmpty ? l10n.enterprise : name; case ProfileType.owfBaselineProfile: - return 'OWF Baseline Profile'; + return l10n.oWFBaselineProfile; + case ProfileType.defaultOne: + return l10n.defaultProfile; } } bool get showSponseredBy { switch (this) { case ProfileType.custom: + case ProfileType.defaultOne: case ProfileType.dutch: return false; case ProfileType.ebsiV3: diff --git a/lib/app/shared/widget/wallet_logo.dart b/lib/app/shared/widget/wallet_logo.dart index 9f79b655a..41f58bdc4 100644 --- a/lib/app/shared/widget/wallet_logo.dart +++ b/lib/app/shared/widget/wallet_logo.dart @@ -26,6 +26,7 @@ class WalletLogo extends StatelessWidget { switch (profileModel.profileType) { case ProfileType.custom: case ProfileType.dutch: + case ProfileType.defaultOne: image = flavorCubit.state == FlavorMode.development ? ImageStrings.appLogoDev : flavorCubit.state == FlavorMode.staging diff --git a/lib/dashboard/profile/cubit/profile_cubit.dart b/lib/dashboard/profile/cubit/profile_cubit.dart index 626578322..8dc3f365f 100644 --- a/lib/dashboard/profile/cubit/profile_cubit.dart +++ b/lib/dashboard/profile/cubit/profile_cubit.dart @@ -58,6 +58,11 @@ class ProfileCubit extends Cubit { } Future load() async { + final ssiKey = await getSecureStorage.get(SecureStorageKeys.ssiKey); + if (ssiKey == null) { + return emit(state.copyWith(status: AppStatus.success)); + } + emit(state.loading()); final log = getLogger('ProfileCubit - load'); @@ -117,7 +122,7 @@ class ProfileCubit extends Cubit { /// profileType - var profileType = ProfileType.custom; + var profileType = ProfileType.defaultOne; final profileTypeString = await secureStorageProvider.get(SecureStorageKeys.profileType); @@ -134,90 +139,9 @@ class ProfileCubit extends Cubit { /// profileSetting late ProfileSetting profileSetting; - /// migration - remove later - final customProfileBackupValue = await secureStorageProvider.get( - 'customProfileBackup', - ); - - if (customProfileBackupValue != null) { - try { - final customProfileBackup = - json.decode(customProfileBackupValue) as Map; - - // // didKeyType: customProfileBackup.didKeyType, - - var didKeyType = DidKeyType.p256; - - if (customProfileBackup.containsKey('didKeyType')) { - for (final value in DidKeyType.values) { - if (value.toString() == - customProfileBackup.containsKey('didKeyType').toString()) { - didKeyType = value; - } - } - } - - profileSetting = ProfileSetting( - blockchainOptions: BlockchainOptions.initial(), - generalOptions: GeneralOptions.empty(), - helpCenterOptions: HelpCenterOptions.initial(), - selfSovereignIdentityOptions: SelfSovereignIdentityOptions( - displayManageDecentralizedId: true, - customOidc4vcProfile: CustomOidc4VcProfile( - clientAuthentication: customProfileBackup - .containsKey('useBasicClientAuthentication') && - customProfileBackup['useBasicClientAuthentication'] == - 'true' - ? ClientAuthentication.clientSecretBasic - : ClientAuthentication.none, - credentialManifestSupport: customProfileBackup - .containsKey('enableCredentialManifestSupport') && - customProfileBackup['enableCredentialManifestSupport'] == - 'true', - cryptoHolderBinding: customProfileBackup - .containsKey('enableCryptographicHolderBinding') && - customProfileBackup['enableCryptographicHolderBinding'] == - 'true', - defaultDid: didKeyType, - oidc4vciDraft: OIDC4VCIDraftType.draft11, - oidc4vpDraft: OIDC4VPDraftType.draft18, - scope: - customProfileBackup.containsKey('enableScopeParameter') && - customProfileBackup['enableScopeParameter'] == 'true', - securityLevel: - customProfileBackup.containsKey('enableSecurity') && - customProfileBackup['enableSecurity'] == 'true', - siopv2Draft: SIOPV2DraftType.draft12, - subjectSyntaxeType: - customProfileBackup.containsKey('enableJWKThumbprint') && - customProfileBackup['enableJWKThumbprint'] == 'true' - ? SubjectSyntax.jwkThumbprint - : SubjectSyntax.did, - clientId: customProfileBackup.containsKey('clientId') - ? customProfileBackup['clientId'].toString() - : Parameters.clientId, - clientSecret: customProfileBackup.containsKey('clientSecret') - ? customProfileBackup['clientSecret'].toString() - : randomString(12), - proofHeader: ProofHeaderType.kid, - ), - ), - settingsMenu: SettingsMenu.initial(), - version: '', - walletSecurityOptions: WalletSecurityOptions.initial(), - ); - } catch (e) { - await secureStorageProvider.delete('customProfileBackup'); - } - await secureStorageProvider.delete('customProfileBackup'); - } - - /// migration - remove upto here - late ProfileModel profileModel; /// based on profileType set the profile setting - switch (profileType) { case ProfileType.custom: final customProfileSettingJsonString = await secureStorageProvider @@ -255,15 +179,38 @@ class ProfileCubit extends Cubit { profileSetting: profileSetting, ); + case ProfileType.defaultOne: + final privateKey = await getPrivateKey( + secureStorage: secureStorageProvider, + didKeyType: Parameters.didKeyTypeForDefault, + oidc4vc: oidc4vc, + ); + + final (did, _) = await getDidAndKid( + didKeyType: Parameters.didKeyTypeForDefault, + privateKey: privateKey, + secureStorage: secureStorageProvider, + didKitProvider: didKitProvider, + ); + + profileModel = ProfileModel.defaultOne( + polygonIdNetwork: polygonIdNetwork, + walletType: walletType, + walletProtectionType: walletProtectionType, + isDeveloperMode: isDeveloperMode, + clientId: did, + clientSecret: randomString(12), + ); + case ProfileType.ebsiV3: final privateKey = await getPrivateKey( secureStorage: secureStorageProvider, - didKeyType: DidKeyType.ebsiv3, + didKeyType: Parameters.didKeyTypeForEbsiV3, oidc4vc: oidc4vc, ); final (did, _) = await getDidAndKid( - didKeyType: DidKeyType.ebsiv3, + didKeyType: Parameters.didKeyTypeForEbsiV3, privateKey: privateKey, secureStorage: secureStorageProvider, didKitProvider: didKitProvider, @@ -281,12 +228,12 @@ class ProfileCubit extends Cubit { case ProfileType.dutch: final privateKey = await getPrivateKey( secureStorage: secureStorageProvider, - didKeyType: DidKeyType.jwkP256, + didKeyType: Parameters.didKeyTypeForDutch, oidc4vc: oidc4vc, ); final (did, _) = await getDidAndKid( - didKeyType: DidKeyType.jwkP256, + didKeyType: Parameters.didKeyTypeForDutch, privateKey: privateKey, secureStorage: secureStorageProvider, didKitProvider: didKitProvider, @@ -304,12 +251,12 @@ class ProfileCubit extends Cubit { case ProfileType.owfBaselineProfile: final privateKey = await getPrivateKey( secureStorage: secureStorageProvider, - didKeyType: DidKeyType.p256, + didKeyType: Parameters.didKeyTypeForOwfBaselineProfile, oidc4vc: oidc4vc, ); final (did, _) = await getDidAndKid( - didKeyType: DidKeyType.p256, + didKeyType: Parameters.didKeyTypeForOwfBaselineProfile, privateKey: privateKey, secureStorage: secureStorageProvider, didKitProvider: didKitProvider, @@ -554,6 +501,20 @@ class ProfileCubit extends Cubit { .selfSovereignIdentityOptions.customOidc4vcProfile.clientSecret, ), ); + case ProfileType.defaultOne: + await update( + ProfileModel.defaultOne( + polygonIdNetwork: state.model.polygonIdNetwork, + walletProtectionType: state.model.walletProtectionType, + isDeveloperMode: state.model.isDeveloperMode, + walletType: state.model.walletType, + enterpriseWalletName: state.model.enterpriseWalletName, + clientId: state.model.profileSetting.selfSovereignIdentityOptions + .customOidc4vcProfile.clientId, + clientSecret: state.model.profileSetting + .selfSovereignIdentityOptions.customOidc4vcProfile.clientSecret, + ), + ); case ProfileType.dutch: await update( ProfileModel.dutch( diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index fd4102347..cf0d86105 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -50,14 +50,14 @@ class ProfileModel extends Equatable { blockchainOptions: BlockchainOptions.initial(), generalOptions: GeneralOptions.empty(), helpCenterOptions: HelpCenterOptions.initial(), - discoverCardsOptions: DiscoverCardsOptions.initial(), + discoverCardsOptions: DiscoverCardsOptions.none(), selfSovereignIdentityOptions: SelfSovereignIdentityOptions( displayManageDecentralizedId: true, customOidc4vcProfile: CustomOidc4VcProfile( clientAuthentication: ClientAuthentication.clientId, credentialManifestSupport: false, cryptoHolderBinding: true, - defaultDid: DidKeyType.ebsiv3, + defaultDid: Parameters.didKeyTypeForEbsiV3, oidc4vciDraft: OIDC4VCIDraftType.draft11, oidc4vpDraft: OIDC4VPDraftType.draft10, scope: false, @@ -76,6 +76,52 @@ class ProfileModel extends Equatable { ), ); + factory ProfileModel.defaultOne({ + required PolygonIdNetwork polygonIdNetwork, + required WalletType walletType, + required WalletProtectionType walletProtectionType, + required bool isDeveloperMode, + required String? clientId, + required String? clientSecret, + String? enterpriseWalletName, + }) => + ProfileModel( + enterpriseWalletName: enterpriseWalletName, + polygonIdNetwork: polygonIdNetwork, + walletType: walletType, + walletProtectionType: walletProtectionType, + isDeveloperMode: isDeveloperMode, + profileType: ProfileType.defaultOne, + profileSetting: ProfileSetting( + blockchainOptions: BlockchainOptions.initial(), + generalOptions: GeneralOptions.empty(), + helpCenterOptions: HelpCenterOptions.initial(), + discoverCardsOptions: DiscoverCardsOptions.initial(), + selfSovereignIdentityOptions: SelfSovereignIdentityOptions( + displayManageDecentralizedId: true, + customOidc4vcProfile: CustomOidc4VcProfile( + clientAuthentication: ClientAuthentication.clientId, + credentialManifestSupport: true, + cryptoHolderBinding: true, + defaultDid: Parameters.didKeyTypeForDefault, + oidc4vciDraft: OIDC4VCIDraftType.draft11, + oidc4vpDraft: OIDC4VPDraftType.draft18, + scope: false, + securityLevel: false, + proofHeader: ProofHeaderType.kid, // N/A + siopv2Draft: SIOPV2DraftType.draft12, + subjectSyntaxeType: SubjectSyntax.did, + clientId: clientId, + clientSecret: clientSecret, + vcFormatType: VCFormatType.ldpVc, + ), + ), + settingsMenu: SettingsMenu.initial(), + version: '', + walletSecurityOptions: WalletSecurityOptions.initial(), + ), + ); + factory ProfileModel.dutch({ required PolygonIdNetwork polygonIdNetwork, required WalletType walletType, @@ -96,14 +142,36 @@ class ProfileModel extends Equatable { blockchainOptions: BlockchainOptions.initial(), generalOptions: GeneralOptions.empty(), helpCenterOptions: HelpCenterOptions.initial(), - discoverCardsOptions: DiscoverCardsOptions.initial(), + discoverCardsOptions: const DiscoverCardsOptions( + displayDefi: false, + displayHumanity: false, + displayHumanityJwt: false, + displayOver13: false, + displayOver15: false, + displayOver18: false, + displayOver18Jwt: false, + displayOver21: false, + displayOver50: false, + displayChainborn: false, + displayTezotopia: false, + displayVerifiableId: true, + displayVerifiableIdJwt: true, + displayOver65: false, + displayEmailPass: true, + displayEmailPassJwt: true, + displayPhonePass: false, + displayPhonePassJwt: false, + displayAgeRange: false, + displayGender: false, + displayExternalIssuer: [], + ), selfSovereignIdentityOptions: SelfSovereignIdentityOptions( displayManageDecentralizedId: true, customOidc4vcProfile: CustomOidc4VcProfile( clientAuthentication: ClientAuthentication.clientId, credentialManifestSupport: false, cryptoHolderBinding: true, - defaultDid: DidKeyType.jwkP256, + defaultDid: Parameters.didKeyTypeForDutch, oidc4vciDraft: OIDC4VCIDraftType.draft11, oidc4vpDraft: OIDC4VPDraftType.draft10, scope: false, @@ -142,14 +210,14 @@ class ProfileModel extends Equatable { blockchainOptions: BlockchainOptions.initial(), generalOptions: GeneralOptions.empty(), helpCenterOptions: HelpCenterOptions.initial(), - discoverCardsOptions: DiscoverCardsOptions.initial(), + discoverCardsOptions: DiscoverCardsOptions.none(), selfSovereignIdentityOptions: SelfSovereignIdentityOptions( displayManageDecentralizedId: true, customOidc4vcProfile: CustomOidc4VcProfile( clientAuthentication: ClientAuthentication.clientId, credentialManifestSupport: true, cryptoHolderBinding: true, - defaultDid: DidKeyType.jwkP256, + defaultDid: Parameters.didKeyTypeForOwfBaselineProfile, oidc4vciDraft: OIDC4VCIDraftType.draft13, oidc4vpDraft: OIDC4VPDraftType.draft18, scope: false, diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index 62cdd2438..0c64f695b 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -195,12 +195,12 @@ class DiscoverCardsOptions extends Equatable { factory DiscoverCardsOptions.initial() => const DiscoverCardsOptions( displayDefi: true, - displayHumanity: false, - displayHumanityJwt: false, + displayHumanity: true, + displayHumanityJwt: true, displayOver13: false, - displayOver15: true, + displayOver15: false, displayOver18: true, - displayOver18Jwt: true, + displayOver18Jwt: false, displayOver21: false, displayOver50: false, displayChainborn: false, @@ -217,6 +217,30 @@ class DiscoverCardsOptions extends Equatable { displayExternalIssuer: [], ); + factory DiscoverCardsOptions.none() => const DiscoverCardsOptions( + displayDefi: false, + displayHumanity: false, + displayHumanityJwt: false, + displayOver13: false, + displayOver15: false, + displayOver18: false, + displayOver18Jwt: false, + displayOver21: false, + displayOver50: false, + displayChainborn: false, + displayTezotopia: false, + displayVerifiableId: false, + displayVerifiableIdJwt: false, + displayOver65: false, + displayEmailPass: false, + displayEmailPassJwt: false, + displayPhonePass: false, + displayPhonePassJwt: false, + displayAgeRange: false, + displayGender: false, + displayExternalIssuer: [], + ); + final bool displayDefi; final bool displayHumanity; final bool displayHumanityJwt; diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 6225d2b44..6ec5795a6 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1035,5 +1035,8 @@ "walletProvider": "Wallet Provider", "theLdpFormatIsNotSupportedByThisDIDMethod": "The ldp_format is not supported by this DID method.", "switchOffCryptoHolderBindingForThatDIDMethod": "Switch off Crypto Holder Binding for that DID Method.", - "thisTypeProofCannotBeUsedWithThisVCFormat": "This type proof cannot be used with this VC Format." + "thisTypeProofCannotBeUsedWithThisVCFormat": "This type proof cannot be used with this VC Format.", + "enterprise": "Enterprise", + "oWFBaselineProfile": "OWF Baseline Profile", + "defaultProfile":"Default" } \ No newline at end of file diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index d165b86d7..33b2dd563 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -940,7 +940,10 @@ "walletProvider", "theLdpFormatIsNotSupportedByThisDIDMethod", "switchOffCryptoHolderBindingForThatDIDMethod", - "thisTypeProofCannotBeUsedWithThisVCFormat" + "thisTypeProofCannotBeUsedWithThisVCFormat", + "enterprise", + "oWFBaselineProfile", + "defaultProfile" ], "es": [ @@ -1884,7 +1887,10 @@ "walletProvider", "theLdpFormatIsNotSupportedByThisDIDMethod", "switchOffCryptoHolderBindingForThatDIDMethod", - "thisTypeProofCannotBeUsedWithThisVCFormat" + "thisTypeProofCannotBeUsedWithThisVCFormat", + "enterprise", + "oWFBaselineProfile", + "defaultProfile" ], "fr": [ @@ -2153,7 +2159,10 @@ "walletProvider", "theLdpFormatIsNotSupportedByThisDIDMethod", "switchOffCryptoHolderBindingForThatDIDMethod", - "thisTypeProofCannotBeUsedWithThisVCFormat" + "thisTypeProofCannotBeUsedWithThisVCFormat", + "enterprise", + "oWFBaselineProfile", + "defaultProfile" ], "it": [ @@ -3097,6 +3106,9 @@ "walletProvider", "theLdpFormatIsNotSupportedByThisDIDMethod", "switchOffCryptoHolderBindingForThatDIDMethod", - "thisTypeProofCannotBeUsedWithThisVCFormat" + "thisTypeProofCannotBeUsedWithThisVCFormat", + "enterprise", + "oWFBaselineProfile", + "defaultProfile" ] } diff --git a/lib/onboarding/helper_function/helper_function.dart b/lib/onboarding/helper_function/helper_function.dart index ae32a4780..37d85aa75 100644 --- a/lib/onboarding/helper_function/helper_function.dart +++ b/lib/onboarding/helper_function/helper_function.dart @@ -33,6 +33,9 @@ Future generateAccount({ await secureStorageProvider.set(SecureStorageKeys.ssiKey, ssiKey); + /// create profile + await profileCubit.load(); + /// what's new popup disabled splashCubit.disableWhatsNewPopUp(); diff --git a/lib/onboarding/starter/view/starter_page.dart b/lib/onboarding/starter/view/starter_page.dart index d80e10785..502cfe51a 100644 --- a/lib/onboarding/starter/view/starter_page.dart +++ b/lib/onboarding/starter/view/starter_page.dart @@ -69,7 +69,7 @@ class StarterPage extends StatelessWidget { ); await profileCubit.setProfileSetting( profileSetting: ProfileSetting.initial(), - profileType: ProfileType.custom, + profileType: ProfileType.defaultOne, ); await showDialog( context: context, diff --git a/lib/wallet/cubit/wallet_cubit.dart b/lib/wallet/cubit/wallet_cubit.dart index af9f22ae6..82439b810 100644 --- a/lib/wallet/cubit/wallet_cubit.dart +++ b/lib/wallet/cubit/wallet_cubit.dart @@ -30,7 +30,7 @@ class WalletCubit extends Cubit { final HomeCubit homeCubit; final KeyGenerator keyGenerator; final CredentialsCubit credentialsCubit; - WalletConnectCubit walletConnectCubit; + final WalletConnectCubit walletConnectCubit; final log = getLogger('WalletCubit'); diff --git a/pubspec.lock b/pubspec.lock index b4a52d252..9780e815d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -973,10 +973,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "30088ce826b5b9cfbf9e8bece34c716c8a59fa54461dcae1e4ac01a94639e762" + sha256: "21b085a1c185e46701373866144ced56cfb7a0c33f63c916bb8fe2d0c1491278" url: "https://pub.dev" source: hosted - version: "0.6.18+3" + version: "0.6.19" flutter_native_timezone: dependency: "direct main" description: @@ -1732,26 +1732,26 @@ packages: dependency: "direct main" description: name: permission_handler - sha256: "3c84d49f0a5e1915364707159ab71f11b3b8a429532176d3a6248a45718ad4f9" + sha256: "74e962b7fad7ff75959161bb2c0ad8fe7f2568ee82621c9c2660b751146bfe44" url: "https://pub.dev" source: hosted - version: "11.2.1" + version: "11.3.0" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: a5ebaa420cee8fd880ef10dedd42c6b3f493e7dbe27d7e0a7e1798669373082a + sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474" url: "https://pub.dev" source: hosted - version: "12.0.4" + version: "12.0.5" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: "6ca25ee52518a8a26e80aaefe3c71caf6e2dfd809c1b20900d0882df6faed36e" + sha256: bdafc6db74253abb63907f4e357302e6bb786ab41465e8635f362ee71fd8707b url: "https://pub.dev" source: hosted - version: "9.3.1" + version: "9.4.0" permission_handler_html: dependency: transitive description: @@ -1764,10 +1764,10 @@ packages: dependency: transitive description: name: permission_handler_platform_interface - sha256: "5c43148f2bfb6d14c5a8162c0a712afe891f2d847f35fcff29c406b37da43c3c" + sha256: "23dfba8447c076ab5be3dee9ceb66aad345c4a648f0cac292c77b1eb0e800b78" url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "4.2.0" permission_handler_windows: dependency: transitive description: @@ -2240,10 +2240,10 @@ packages: dependency: transitive description: name: sqlite3 - sha256: c4a4c5a4b2a32e2d0f6837b33d7c91a67903891a5b7dbe706cf4b1f6b0c798c5 + sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" stack_trace: dependency: transitive description: @@ -2409,10 +2409,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" + sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.3.0" url_launcher_ios: dependency: transitive description: From ba99d67c4af0d86c931e753f04dd287341337363 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 14 Feb 2024 14:01:23 +0545 Subject: [PATCH 36/70] Handle language with language code only --- lib/app/view/app.dart | 12 ++++++++++-- .../credentials/detail/widgets/claims_data.dart | 6 ++---- .../detail/widgets/credential_subject_data.dart | 6 ++---- lib/lang/cubit/lang_cubit.dart | 8 +++++++- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/app/view/app.dart b/lib/app/view/app.dart index dfc8ed035..55e6ab974 100644 --- a/lib/app/view/app.dart +++ b/lib/app/view/app.dart @@ -242,10 +242,18 @@ class MaterialAppDefinition extends StatelessWidget { create: (context) => LangCubit(), child: BlocBuilder( builder: (context, lang) { - context.read().fetchLocale(); + if (isStaging) { + final locale = DevicePreview.locale(context); + if (locale != null) { + context.read().setLocale(locale); + } + } else { + context.read().fetchLocale(); + } + return MaterialApp( builder: isStaging ? DevicePreview.appBuilder : null, - locale: isStaging ? DevicePreview.locale(context) : lang, + locale: lang, title: 'AltMe', darkTheme: AppTheme.darkThemeData, navigatorObservers: [MyRouteObserver(context)], diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart index 8d806096b..54f015d5f 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart @@ -51,9 +51,7 @@ class ClaimsData extends StatelessWidget { } } - final locale = context.read().state; - - final localeString = '${locale.languageCode}-${locale.countryCode}'; + final languageCode = context.read().state.languageCode; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -83,7 +81,7 @@ class ClaimsData extends StatelessWidget { final display = displays.where((element) { if (element is Map && element.containsKey('locale')) { - if (element['locale'] == localeString) { + if (element['locale'].toString().contains(languageCode)) { return true; } else if (element['locale'] == 'en-US') { return true; 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 7ff2f8398..5a68eb652 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 @@ -31,9 +31,7 @@ class CredentialSubjectData extends StatelessWidget { if (credentialSubjectData == null) return Container(); if (credentialSubjectData is! Map) return Container(); - final locale = context.read().state; - - final localeString = '${locale.languageCode}-${locale.countryCode}'; + final languageCode = context.read().state.languageCode; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -63,7 +61,7 @@ class CredentialSubjectData extends StatelessWidget { final display = displays.where((element) { if (element is Map && element.containsKey('locale')) { - if (element['locale'] == localeString) { + if (element['locale'].toString().contains(languageCode)) { return true; } else if (element['locale'] == 'en-US') { return true; diff --git a/lib/lang/cubit/lang_cubit.dart b/lib/lang/cubit/lang_cubit.dart index 1bc883ac1..2b509497b 100644 --- a/lib/lang/cubit/lang_cubit.dart +++ b/lib/lang/cubit/lang_cubit.dart @@ -14,7 +14,13 @@ class LangCubit extends Cubit { final langauageCode = locale!.languageCode; if (AppLocalizations.supportedLocales.contains(Locale(langauageCode))) { - emit(locale); + setLocale(locale); + } else { + setLocale(const Locale('en', 'US')); } } + + void setLocale(Locale locale) { + emit(locale); + } } From dcef6e67e024b7d16546bc95a3499b5601bc67f8 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 14 Feb 2024 15:35:41 +0545 Subject: [PATCH 37/70] Value of the attribute iss of the Proof of key ownership in the credential request must be the value of client_id #2380 --- .../cubit/qr_code_scan_cubit.dart | 6 +-- lib/oidc4vc/get_and_add_credential.dart | 3 +- .../initiate_oidv4vc_credential_issuance.dart | 2 +- .../lib/src/issuer_token_parameters.dart | 4 ++ packages/oidc4vc/lib/src/oidc4vc.dart | 37 ++++++++++++++++--- 5 files changed, 41 insertions(+), 11 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 4a7f473e0..2c7e674aa 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 @@ -1185,7 +1185,7 @@ class QRCodeScanCubit extends Cubit { codeForAuthorisedFlow: null, codeVerifier: null, authorization: authorization, - clientId: clientId, + clientId: clientId ?? '', clientSecret: clientSecret, ); } else { @@ -1221,7 +1221,7 @@ class QRCodeScanCubit extends Cubit { required String? codeForAuthorisedFlow, required String? codeVerifier, required String? authorization, - required String? clientId, + required String clientId, required String? clientSecret, }) async { try { @@ -1323,7 +1323,7 @@ class QRCodeScanCubit extends Cubit { codeForAuthorisedFlow: codeForAuthorisedFlow, codeVerifier: codeVerifier, authorization: authorization, - clientId: clientId, + clientId: clientId ?? '', clientSecret: clientSecret, ); } catch (e) { diff --git a/lib/oidc4vc/get_and_add_credential.dart b/lib/oidc4vc/get_and_add_credential.dart index cd102aadd..ce8d2a7fc 100644 --- a/lib/oidc4vc/get_and_add_credential.dart +++ b/lib/oidc4vc/get_and_add_credential.dart @@ -29,7 +29,7 @@ Future getAndAddCredential({ required String? authorization, required OIDC4VCIDraftType oidc4vciDraftType, required DidKeyType didKeyType, - required String? clientId, + required String clientId, required String? clientSecret, required JWTDecode jwtDecode, }) async { @@ -88,6 +88,7 @@ Future getAndAddCredential({ oidc4vciDraftType: oidc4vciDraftType, useJWKThumbPrint: enableJWKThumbprint, proofHeaderType: customOidc4vcProfile.proofHeader, + clientAuthentication: customOidc4vcProfile.clientAuthentication, ); for (int i = 0; i < encodedCredentialOrFutureTokens.length; i++) { diff --git a/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart b/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart index 0dfb29cab..e70fd2934 100644 --- a/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart +++ b/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart @@ -131,7 +131,7 @@ Future initiateOIDC4VCCredentialIssuance({ codeForAuthorisedFlow: codeForAuthorisedFlow, codeVerifier: codeVerifier, authorization: authorization, - clientId: clientId, + clientId: clientId ?? '', clientSecret: clientSecret, ); } diff --git a/packages/oidc4vc/lib/src/issuer_token_parameters.dart b/packages/oidc4vc/lib/src/issuer_token_parameters.dart index f8b6bcaff..09b167d91 100644 --- a/packages/oidc4vc/lib/src/issuer_token_parameters.dart +++ b/packages/oidc4vc/lib/src/issuer_token_parameters.dart @@ -11,9 +11,13 @@ class IssuerTokenParameters extends TokenParameters { required super.proofHeaderType, required super.useJWKThumbPrint, required this.issuer, + required this.clientId, super.kid, }); /// [issuer] is id of credential we are aquiring. final String issuer; + + /// [clientId] is clientId. + final String clientId; } diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 83286ad0d..72f090149 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -341,7 +341,7 @@ class OIDC4VC { required String issuer, required dynamic credential, required String did, - required String? clientId, + required String clientId, required String? clientSecret, required String kid, required int indexValue, @@ -350,6 +350,7 @@ class OIDC4VC { required bool useJWKThumbPrint, required ProofHeaderType proofHeaderType, required OIDC4VCIDraftType oidc4vciDraftType, + required ClientAuthentication clientAuthentication, String? preAuthorizedCode, String? userPin, String? code, @@ -402,6 +403,7 @@ class OIDC4VC { mediaType: MediaType.proofOfOwnership, useJWKThumbPrint: useJWKThumbPrint, proofHeaderType: proofHeaderType, + clientId: clientId, ); String? deferredCredentialEndpoint; @@ -450,6 +452,7 @@ class OIDC4VC { cryptoHolderBinding: cryptoHolderBinding, oidc4vciDraftType: oidc4vciDraftType, credentialDefinition: credentialDefinition, + clientAuthentication: clientAuthentication, vct: vct, ); @@ -466,6 +469,7 @@ class OIDC4VC { cryptoHolderBinding: cryptoHolderBinding, oidc4vciDraftType: oidc4vciDraftType, credentialDefinition: credentialDefinition, + clientAuthentication: clientAuthentication, vct: vct, credentialIdentifier: null, ); @@ -489,6 +493,7 @@ class OIDC4VC { required String format, required bool cryptoHolderBinding, required OIDC4VCIDraftType oidc4vciDraftType, + required ClientAuthentication clientAuthentication, required String? credentialIdentifier, required Map? credentialDefinition, required String? vct, @@ -504,6 +509,7 @@ class OIDC4VC { cryptoHolderBinding: cryptoHolderBinding, oidc4vciDraftType: oidc4vciDraftType, credentialDefinition: credentialDefinition, + clientAuthentication: clientAuthentication, vct: vct, ); @@ -758,6 +764,7 @@ class OIDC4VC { required String format, required bool cryptoHolderBinding, required OIDC4VCIDraftType oidc4vciDraftType, + required ClientAuthentication clientAuthentication, required String? credentialIdentifier, required String? cnonce, required String? vct, @@ -766,7 +773,12 @@ class OIDC4VC { final credentialData = {}; if (cryptoHolderBinding) { - final vcJwt = await getIssuerJwt(issuerTokenParameters, cnonce); + final vcJwt = await getIssuerJwt( + tokenParameters: issuerTokenParameters, + clientAuthentication: clientAuthentication, + oidc4vciDraftType: oidc4vciDraftType, + cnonce: cnonce, + ); credentialData['proof'] = { 'proof_type': 'jwt', 'jwt': vcJwt, @@ -1030,13 +1042,26 @@ class OIDC4VC { } @visibleForTesting - Future getIssuerJwt( - IssuerTokenParameters tokenParameters, + Future getIssuerJwt({ + required IssuerTokenParameters tokenParameters, + required ClientAuthentication clientAuthentication, + required OIDC4VCIDraftType oidc4vciDraftType, String? cnonce, - ) async { + }) async { final iat = (DateTime.now().millisecondsSinceEpoch / 1000).round(); + + var iss = tokenParameters.did; + + if (clientAuthentication == ClientAuthentication.clientSecretPost || + clientAuthentication == ClientAuthentication.clientSecretBasic) { + if (oidc4vciDraftType == OIDC4VCIDraftType.draft11 || + oidc4vciDraftType == OIDC4VCIDraftType.draft13) { + iss = tokenParameters.clientId; + } + } + final payload = { - 'iss': tokenParameters.did, + 'iss': iss, 'iat': iat, 'aud': tokenParameters.issuer, }; From cae1232b89307ed3495a013285064e3a84b3c73d Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 14 Feb 2024 17:33:22 +0545 Subject: [PATCH 38/70] feat: Several changes for switch client type #2381 --- .vscode/launch.json | 8 +- lib/app/shared/enum/type/profile/profile.dart | 1 - .../enum/type/profile/subject_syntax.dart | 8 -- lib/chat_room/cubit/chat_room_cubit.dart | 4 +- .../view/oidc4vc_settings_menu.dart | 2 +- .../widget/client_type_widget.dart | 73 +++++++++++++++++++ .../widget/subject_syntax_type_widget.dart | 34 --------- .../ssi/oidc4vc_settngs/widget/widget.dart | 2 +- .../profile/cubit/profile_cubit.dart | 4 +- lib/dashboard/profile/models/profile.dart | 8 +- .../profile/models/profile_setting.dart | 13 ++-- .../cubit/qr_code_scan_cubit.dart | 19 ++--- lib/l10n/arb/app_en.arb | 4 +- lib/l10n/untranslated.json | 16 ++-- lib/oidc4vc/get_and_add_credential.dart | 5 +- .../cubit/initialization_cubit.dart | 6 +- lib/scan/cubit/scan_cubit.dart | 5 +- packages/oidc4vc/lib/oidc4vc.dart | 1 + packages/oidc4vc/lib/src/client_type.dart | 23 ++++++ .../lib/src/issuer_token_parameters.dart | 7 +- packages/oidc4vc/lib/src/oidc4vc.dart | 47 +++++++----- .../oidc4vc/lib/src/token_parameters.dart | 10 ++- .../lib/src/verifier_token_parameters.dart | 5 +- pubspec.lock | 4 +- 24 files changed, 189 insertions(+), 120 deletions(-) delete mode 100644 lib/app/shared/enum/type/profile/subject_syntax.dart create mode 100644 lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_type_widget.dart delete mode 100644 lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/subject_syntax_type_widget.dart create mode 100644 packages/oidc4vc/lib/src/client_type.dart 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" + ] } ] } diff --git a/lib/app/shared/enum/type/profile/profile.dart b/lib/app/shared/enum/type/profile/profile.dart index 38619749c..b52373de9 100644 --- a/lib/app/shared/enum/type/profile/profile.dart +++ b/lib/app/shared/enum/type/profile/profile.dart @@ -1,4 +1,3 @@ export 'did_key_type.dart'; export 'profile_type.dart'; -export 'subject_syntax.dart'; export 'wallet_app_type.dart'; diff --git a/lib/app/shared/enum/type/profile/subject_syntax.dart b/lib/app/shared/enum/type/profile/subject_syntax.dart deleted file mode 100644 index 72a06c5d6..000000000 --- a/lib/app/shared/enum/type/profile/subject_syntax.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -enum SubjectSyntax { - @JsonValue('urn:ietf:params:oauth:jwk-thumbprint') - jwkThumbprint, - - did, -} diff --git a/lib/chat_room/cubit/chat_room_cubit.dart b/lib/chat_room/cubit/chat_room_cubit.dart index 301d1294c..ee43d9d3a 100644 --- a/lib/chat_room/cubit/chat_room_cubit.dart +++ b/lib/chat_room/cubit/chat_room_cubit.dart @@ -273,8 +273,10 @@ abstract class ChatRoomCubit extends Cubit { privateKey: jsonDecode(p256KeyForWallet) as Map, did: '', // just added as it is required field mediaType: MediaType.basic, // just added as it is required field - useJWKThumbPrint: true, // just added as it is required field + clientType: + ClientType.jwkThumbprint, // just added as it is required field proofHeaderType: customOidc4vcProfile.proofHeader, + clientId: customOidc4vcProfile.clientId ?? '', ); final helpCenterOptions = 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 38f8078b0..87b667cfb 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 @@ -42,11 +42,11 @@ class Oidc4vcSettingMenuView extends StatelessWidget { const SecurityLevelWidget(), const DidKeyTypeWidget(), const DraftTypeWidget(), - const SubjectSyntaxTypeWidget(), const CredentialManifestSupportWidget(), const CryptographicHolderBindingWidget(), const ScopeParameterWidget(), const ClientAuthenticationWidget(), + const ClientTypeWidget(), const ClientCredentialsWidget(), const VCFormatWidget(), const ProofHeaderWidget(), 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 new file mode 100644 index 000000000..d154ccbef --- /dev/null +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/client_type_widget.dart @@ -0,0 +1,73 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:altme/theme/theme.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:oidc4vc/oidc4vc.dart'; + +class ClientTypeWidget extends StatelessWidget { + const ClientTypeWidget({super.key}); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + return BlocBuilder( + builder: (context, state) { + return OptionContainer( + title: l10n.clientTypeTitle, + subtitle: l10n.clientTypeSubtitle, + body: ListView.builder( + itemCount: ClientType.values.length, + shrinkWrap: true, + physics: const ScrollPhysics(), + padding: EdgeInsets.zero, + itemBuilder: (context, index) { + final clientType = ClientType.values[index]; + return Column( + children: [ + if (index != 0) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Divider( + height: 0, + color: Theme.of(context).colorScheme.borderColor, + ), + ), + ListTile( + onTap: () { + context.read().updateProfileSetting( + clientType: clientType, + ); + }, + shape: const RoundedRectangleBorder( + side: BorderSide( + color: Color(0xFFDDDDEE), + width: 0.5, + ), + ), + title: Text( + clientType.getTitle, + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: Theme.of(context).colorScheme.onPrimary, + ), + ), + trailing: Icon( + state.model.profileSetting.selfSovereignIdentityOptions + .customOidc4vcProfile.clientType == + clientType + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + size: Sizes.icon2x, + color: Theme.of(context).colorScheme.onPrimary, + ), + ), + ], + ); + }, + ), + ); + }, + ); + } +} diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/subject_syntax_type_widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/subject_syntax_type_widget.dart deleted file mode 100644 index 66eac25e1..000000000 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/subject_syntax_type_widget.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:altme/app/app.dart'; -import 'package:altme/dashboard/dashboard.dart'; -import 'package:altme/l10n/l10n.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -class SubjectSyntaxTypeWidget extends StatelessWidget { - const SubjectSyntaxTypeWidget({super.key}); - - @override - Widget build(BuildContext context) { - final l10n = context.l10n; - return BlocBuilder( - builder: (context, state) { - return OptionContainer( - title: l10n.subjectSyntaxType, - subtitle: l10n.enableToUseTheJWKThumprintOfTheKey, - body: Switch( - onChanged: (value) async { - await context.read().updateProfileSetting( - subjectSyntax: - value ? SubjectSyntax.jwkThumbprint : SubjectSyntax.did, - ); - }, - value: state.model.profileSetting.selfSovereignIdentityOptions - .customOidc4vcProfile.subjectSyntaxeType == - SubjectSyntax.jwkThumbprint, - activeColor: Theme.of(context).colorScheme.primary, - ), - ); - }, - ); - } -} diff --git a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart index de2ca74d6..22a8f1a9d 100644 --- a/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart +++ b/lib/dashboard/drawer/ssi/oidc4vc_settngs/widget/widget.dart @@ -1,5 +1,6 @@ export 'client_authentication_widget.dart'; export 'client_credentials_widget.dart'; +export 'client_type_widget.dart'; export 'credential_manifest_support.dart'; export 'cryptograhic_holder_binding.dart'; export 'did_key_type_widget.dart'; @@ -8,5 +9,4 @@ export 'option_container.dart'; export 'proof_header_widget.dart'; export 'scope_parameter.dart'; export 'security_level_widget.dart'; -export 'subject_syntax_type_widget.dart'; export 'vc_format_widget.dart'; diff --git a/lib/dashboard/profile/cubit/profile_cubit.dart b/lib/dashboard/profile/cubit/profile_cubit.dart index 8dc3f365f..83b5d4f74 100644 --- a/lib/dashboard/profile/cubit/profile_cubit.dart +++ b/lib/dashboard/profile/cubit/profile_cubit.dart @@ -407,7 +407,7 @@ class ProfileCubit extends Cubit { bool? secureSecurityAuthenticationWithPinCode, bool? verifySecurityIssuerWebsiteIdentity, OIDC4VCIDraftType? oidc4vciDraftType, - SubjectSyntax? subjectSyntax, + ClientType? clientType, VCFormatType? vcFormatType, ProofHeaderType? proofHeaderType, }) async { @@ -436,7 +436,7 @@ class ProfileCubit extends Cubit { clientId: clientId, clientSecret: clientSecret, oidc4vciDraft: oidc4vciDraftType, - subjectSyntaxeType: subjectSyntax, + clientType: clientType, vcFormatType: vcFormatType, ), ), diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index cf0d86105..cb8a102d7 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -64,7 +64,7 @@ class ProfileModel extends Equatable { securityLevel: false, proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, - subjectSyntaxeType: SubjectSyntax.did, + clientType: ClientType.did, clientId: clientId, clientSecret: clientSecret, vcFormatType: VCFormatType.jwtVc, @@ -110,7 +110,7 @@ class ProfileModel extends Equatable { securityLevel: false, proofHeader: ProofHeaderType.kid, // N/A siopv2Draft: SIOPV2DraftType.draft12, - subjectSyntaxeType: SubjectSyntax.did, + clientType: ClientType.did, clientId: clientId, clientSecret: clientSecret, vcFormatType: VCFormatType.ldpVc, @@ -178,7 +178,7 @@ class ProfileModel extends Equatable { securityLevel: false, proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, - subjectSyntaxeType: SubjectSyntax.did, + clientType: ClientType.did, clientId: clientId, clientSecret: clientSecret, vcFormatType: VCFormatType.jwtVcJson, @@ -224,7 +224,7 @@ class ProfileModel extends Equatable { securityLevel: false, proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, - subjectSyntaxeType: SubjectSyntax.did, + clientType: ClientType.did, clientId: clientId, clientSecret: clientSecret, vcFormatType: VCFormatType.vcSdJWT, diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index 0c64f695b..ee63fea74 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -541,7 +541,7 @@ class CustomOidc4VcProfile extends Equatable { required this.scope, required this.securityLevel, required this.siopv2Draft, - required this.subjectSyntaxeType, + required this.clientType, required this.clientId, required this.clientSecret, this.vcFormatType = VCFormatType.ldpVc, @@ -559,7 +559,7 @@ class CustomOidc4VcProfile extends Equatable { proofHeader: ProofHeaderType.kid, securityLevel: false, siopv2Draft: SIOPV2DraftType.draft12, - subjectSyntaxeType: SubjectSyntax.did, + clientType: ClientType.did, clientId: Parameters.clientId, clientSecret: randomString(12), vcFormatType: VCFormatType.ldpVc, @@ -582,7 +582,8 @@ class CustomOidc4VcProfile extends Equatable { final ProofHeaderType proofHeader; final bool securityLevel; final SIOPV2DraftType siopv2Draft; - final SubjectSyntax subjectSyntaxeType; + @JsonKey(name: 'subjectSyntaxeType') + final ClientType clientType; @JsonKey(name: 'vcFormat') final VCFormatType vcFormatType; @@ -601,7 +602,7 @@ class CustomOidc4VcProfile extends Equatable { ProofHeaderType? proofHeader, bool? securityLevel, SIOPV2DraftType? siopv2Draft, - SubjectSyntax? subjectSyntaxeType, + ClientType? clientType, VCFormatType? vcFormatType, }) => CustomOidc4VcProfile( @@ -616,7 +617,7 @@ class CustomOidc4VcProfile extends Equatable { proofHeader: proofHeader ?? this.proofHeader, securityLevel: securityLevel ?? this.securityLevel, siopv2Draft: siopv2Draft ?? this.siopv2Draft, - subjectSyntaxeType: subjectSyntaxeType ?? this.subjectSyntaxeType, + clientType: clientType ?? this.clientType, clientId: clientId ?? this.clientId, clientSecret: clientSecret ?? this.clientSecret, vcFormatType: vcFormatType ?? this.vcFormatType, @@ -636,7 +637,7 @@ class CustomOidc4VcProfile extends Equatable { proofHeader, securityLevel, siopv2Draft, - subjectSyntaxeType, + clientType, vcFormatType, ]; } 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 2c7e674aa..52dfaa4ba 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 @@ -991,7 +991,7 @@ class QRCodeScanCubit extends Cubit { final isSecurityEnabled = customOidc4vcProfile.securityLevel; final enableJWKThumbprint = - customOidc4vcProfile.subjectSyntaxeType == SubjectSyntax.jwkThumbprint; + customOidc4vcProfile.clientType == ClientType.jwkThumbprint; if (isSecurityEnabled && enableJWKThumbprint) { final Map payload = @@ -1065,9 +1065,6 @@ class QRCodeScanCubit extends Cubit { final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; - final enableJWKThumbprint = customOidc4vcProfile.subjectSyntaxeType == - SubjectSyntax.jwkThumbprint; - final Response response = await oidc4vc.siopv2Flow( clientId: clientId, privateKey: privateKey, @@ -1076,7 +1073,7 @@ class QRCodeScanCubit extends Cubit { redirectUri: redirectUri!, nonce: nonce, stateValue: stateValue, - useJWKThumbPrint: enableJWKThumbprint, + clientType: customOidc4vcProfile.clientType, proofHeaderType: customOidc4vcProfile.proofHeader, ); @@ -1159,19 +1156,23 @@ class QRCodeScanCubit extends Cubit { secureStorage: secureStorageProvider, didKeyType: didKeyType, ); - switch (customOidc4vcProfile.subjectSyntaxeType) { - case SubjectSyntax.jwkThumbprint: + switch (customOidc4vcProfile.clientType) { + case ClientType.jwkThumbprint: final tokenParameters = TokenParameters( privateKey: jsonDecode(privateKey) as Map, did: '', // just added as it is required field mediaType: MediaType.basic, // just added as it is required field - useJWKThumbPrint: true, // just added as it is required field + clientType: ClientType + .jwkThumbprint, // just added as it is required field proofHeaderType: customOidc4vcProfile.proofHeader, + clientId: '', ); clientId = tokenParameters.thumbprint; - case SubjectSyntax.did: + case ClientType.did: clientId = did; + case ClientType.confidential: + clientId = customOidc4vcProfile.clientId; } } diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 6ec5795a6..fe06ee47a 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -968,8 +968,8 @@ "jwkDecentralizedIDP256": "JWK Decentralized ID P-256", "defaultDid": "Default DID", "selectOneOfTheDid": "Select one of the DIDs", - "subjectSyntaxType": "Subject Syntax Type", - "enableToUseTheJWKThumprintOfTheKey": "Default: DID\nEnable to use the JWK thumprint of the key", + "clientTypeTitle": "OIDC4VCI Client Type", + "clientTypeSubtitle": "Default: DID\nSwitch to change the client type", "cryptographicHolderBinding": "Cryptographic Holder Binding", "cryptographicHolderBindingSubtitle": "Default : On\nDisable cryptographic binding for claim based binding credentials.", "scopeParameters": "Scope Parameters", diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index 33b2dd563..0cba527bd 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -874,8 +874,8 @@ "jwkDecentralizedIDP256", "defaultDid", "selectOneOfTheDid", - "subjectSyntaxType", - "enableToUseTheJWKThumprintOfTheKey", + "clientTypeTitle", + "clientTypeSubtitle", "cryptographicHolderBinding", "cryptographicHolderBindingSubtitle", "scopeParameters", @@ -1821,8 +1821,8 @@ "jwkDecentralizedIDP256", "defaultDid", "selectOneOfTheDid", - "subjectSyntaxType", - "enableToUseTheJWKThumprintOfTheKey", + "clientTypeTitle", + "clientTypeSubtitle", "cryptographicHolderBinding", "cryptographicHolderBindingSubtitle", "scopeParameters", @@ -2093,8 +2093,8 @@ "jwkDecentralizedIDP256", "defaultDid", "selectOneOfTheDid", - "subjectSyntaxType", - "enableToUseTheJWKThumprintOfTheKey", + "clientTypeTitle", + "clientTypeSubtitle", "cryptographicHolderBinding", "cryptographicHolderBindingSubtitle", "scopeParameters", @@ -3040,8 +3040,8 @@ "jwkDecentralizedIDP256", "defaultDid", "selectOneOfTheDid", - "subjectSyntaxType", - "enableToUseTheJWKThumprintOfTheKey", + "clientTypeTitle", + "clientTypeSubtitle", "cryptographicHolderBinding", "cryptographicHolderBindingSubtitle", "scopeParameters", diff --git a/lib/oidc4vc/get_and_add_credential.dart b/lib/oidc4vc/get_and_add_credential.dart index ce8d2a7fc..590117e9a 100644 --- a/lib/oidc4vc/get_and_add_credential.dart +++ b/lib/oidc4vc/get_and_add_credential.dart @@ -60,9 +60,6 @@ Future getAndAddCredential({ final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; - final enableJWKThumbprint = - customOidc4vcProfile.subjectSyntaxeType == SubjectSyntax.jwkThumbprint; - final index = getIndexValue(isEBSIV3: isEBSIV3, didKeyType: didKeyType); final ( @@ -86,7 +83,7 @@ Future getAndAddCredential({ cryptoHolderBinding: cryptoHolderBinding, authorization: authorization, oidc4vciDraftType: oidc4vciDraftType, - useJWKThumbPrint: enableJWKThumbprint, + clientType: customOidc4vcProfile.clientType, proofHeaderType: customOidc4vcProfile.proofHeader, clientAuthentication: customOidc4vcProfile.clientAuthentication, ); diff --git a/lib/onboarding/enterprise/initialization/cubit/initialization_cubit.dart b/lib/onboarding/enterprise/initialization/cubit/initialization_cubit.dart index baee2ab98..d95d5e757 100644 --- a/lib/onboarding/enterprise/initialization/cubit/initialization_cubit.dart +++ b/lib/onboarding/enterprise/initialization/cubit/initialization_cubit.dart @@ -217,16 +217,14 @@ class EnterpriseInitializationCubit final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; - final enableJWKThumbprint = - customOidc4vcProfile.subjectSyntaxeType == SubjectSyntax.jwkThumbprint; - final tokenParameters = TokenParameters( privateKey: privateKey, did: '', kid: null, mediaType: MediaType.walletAttestation, - useJWKThumbPrint: enableJWKThumbprint, + clientType: customOidc4vcProfile.clientType, proofHeaderType: customOidc4vcProfile.proofHeader, + clientId: customOidc4vcProfile.clientId ?? '', ); final thumbPrint = tokenParameters.thumbprint; diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index c0591ebd9..1931048d6 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -894,9 +894,6 @@ class ScanCubit extends Cubit { final customOidc4vcProfile = profileCubit.state.model.profileSetting .selfSovereignIdentityOptions.customOidc4vcProfile; - final enableJWKThumbprint = - customOidc4vcProfile.subjectSyntaxeType == SubjectSyntax.jwkThumbprint; - final idToken = await oidc4vc.extractIdToken( clientId: clientId, credentialsToBePresented: credentialList, @@ -904,7 +901,7 @@ class ScanCubit extends Cubit { kid: kid, privateKey: privateKey, nonce: nonce, - useJWKThumbPrint: enableJWKThumbprint, + clientType: customOidc4vcProfile.clientType, proofHeaderType: customOidc4vcProfile.proofHeader, ); diff --git a/packages/oidc4vc/lib/oidc4vc.dart b/packages/oidc4vc/lib/oidc4vc.dart index 3eda045ad..1540301b2 100644 --- a/packages/oidc4vc/lib/oidc4vc.dart +++ b/packages/oidc4vc/lib/oidc4vc.dart @@ -9,6 +9,7 @@ library ebsi; export 'src/client_authentication.dart'; +export 'src/client_type.dart'; export 'src/issuer_token_parameters.dart'; export 'src/media_type.dart'; export 'src/models/models.dart'; diff --git a/packages/oidc4vc/lib/src/client_type.dart b/packages/oidc4vc/lib/src/client_type.dart new file mode 100644 index 000000000..466a3352c --- /dev/null +++ b/packages/oidc4vc/lib/src/client_type.dart @@ -0,0 +1,23 @@ +import 'package:json_annotation/json_annotation.dart'; + +enum ClientType { + @JsonValue('urn:ietf:params:oauth:jwk-thumbprint') + jwkThumbprint, + + did, + + confidential, +} + +extension ClientTypeX on ClientType { + String get getTitle { + switch (this) { + case ClientType.jwkThumbprint: + return 'JWK Thumbprint'; + case ClientType.did: + return 'DID'; + case ClientType.confidential: + return 'Confidential Client'; + } + } +} diff --git a/packages/oidc4vc/lib/src/issuer_token_parameters.dart b/packages/oidc4vc/lib/src/issuer_token_parameters.dart index 09b167d91..289e7cb1a 100644 --- a/packages/oidc4vc/lib/src/issuer_token_parameters.dart +++ b/packages/oidc4vc/lib/src/issuer_token_parameters.dart @@ -9,15 +9,12 @@ class IssuerTokenParameters extends TokenParameters { required super.did, required super.mediaType, required super.proofHeaderType, - required super.useJWKThumbPrint, + required super.clientType, + required super.clientId, required this.issuer, - required this.clientId, super.kid, }); /// [issuer] is id of credential we are aquiring. final String issuer; - - /// [clientId] is clientId. - final String clientId; } diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 72f090149..ca5bf54e7 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -324,7 +324,7 @@ class OIDC4VC { ], 'subject_syntax_types_discriminations': [ 'did:key:jwk_jcs-pub', - 'did:ebsi:v1' + 'did:ebsi:v1', ], 'subject_trust_frameworks_supported': ['ebsi'], 'id_token_types_supported': ['subject_signed_id_token'], @@ -347,7 +347,7 @@ class OIDC4VC { required int indexValue, required String privateKey, required bool cryptoHolderBinding, - required bool useJWKThumbPrint, + required ClientType clientType, required ProofHeaderType proofHeaderType, required OIDC4VCIDraftType oidc4vciDraftType, required ClientAuthentication clientAuthentication, @@ -401,7 +401,7 @@ class OIDC4VC { kid: kid, issuer: issuer, mediaType: MediaType.proofOfOwnership, - useJWKThumbPrint: useJWKThumbPrint, + clientType: clientType, proofHeaderType: proofHeaderType, clientId: clientId, ); @@ -1178,8 +1178,9 @@ class OIDC4VC { credentials: credentialsToBePresented, nonce: nonce, mediaType: MediaType.basic, - useJWKThumbPrint: false, + clientType: ClientType.did, proofHeaderType: proofHeaderType, + clientId: clientId, ); final vpToken = await getVpToken(tokenParameters); @@ -1196,7 +1197,7 @@ class OIDC4VC { required String did, required String kid, required String nonce, - required bool useJWKThumbPrint, + required ClientType clientType, required String privateKey, required ProofHeaderType proofHeaderType, }) async { @@ -1210,8 +1211,9 @@ class OIDC4VC { credentials: credentialsToBePresented, nonce: nonce, mediaType: MediaType.basic, - useJWKThumbPrint: useJWKThumbPrint, + clientType: clientType, proofHeaderType: proofHeaderType, + clientId: clientId, ); final verifierIdToken = await getIdToken(tokenParameters); @@ -1230,7 +1232,7 @@ class OIDC4VC { required String? nonce, required String privateKey, required String? stateValue, - required bool useJWKThumbPrint, + required ClientType clientType, required ProofHeaderType proofHeaderType, }) async { try { @@ -1244,8 +1246,9 @@ class OIDC4VC { credentials: [], nonce: nonce, mediaType: MediaType.basic, - useJWKThumbPrint: useJWKThumbPrint, + clientType: clientType, proofHeaderType: proofHeaderType, + clientId: clientId, ); // structures @@ -1338,12 +1341,11 @@ class OIDC4VC { switch (tokenParameters.proofHeaderType) { case ProofHeaderType.kid: - if (!tokenParameters.useJWKThumbPrint) { - vpBuilder.setProtectedHeader( - 'kid', - tokenParameters.kid ?? tokenParameters.thumbprint, - ); - } + vpBuilder.setProtectedHeader( + 'kid', + tokenParameters.kid ?? tokenParameters.thumbprint, + ); + case ProofHeaderType.jwk: vpBuilder.setProtectedHeader( 'jwk', @@ -1362,9 +1364,18 @@ class OIDC4VC { @visibleForTesting Future getIdToken(VerifierTokenParameters tokenParameters) async { /// build id token - final issAndSub = tokenParameters.useJWKThumbPrint - ? tokenParameters.thumbprint - : tokenParameters.did; + + var issAndSub = tokenParameters.thumbprint; + + switch (tokenParameters.clientType) { + case ClientType.jwkThumbprint: + issAndSub = tokenParameters.thumbprint; + case ClientType.did: + issAndSub = tokenParameters.did; + case ClientType.confidential: + issAndSub = tokenParameters.clientId; + } + final iat = (DateTime.now().millisecondsSinceEpoch / 1000).round(); final payload = { 'iat': iat, @@ -1378,7 +1389,7 @@ class OIDC4VC { payload['nonce'] = tokenParameters.nonce!; } - if (tokenParameters.useJWKThumbPrint) { + if (tokenParameters.clientType == ClientType.jwkThumbprint) { payload['sub_jwk'] = tokenParameters.publicJWK; } diff --git a/packages/oidc4vc/lib/src/token_parameters.dart b/packages/oidc4vc/lib/src/token_parameters.dart index d6906a24f..3460973da 100644 --- a/packages/oidc4vc/lib/src/token_parameters.dart +++ b/packages/oidc4vc/lib/src/token_parameters.dart @@ -14,13 +14,17 @@ class TokenParameters { required this.did, required this.mediaType, required this.proofHeaderType, - required this.useJWKThumbPrint, + required this.clientType, + required this.clientId, this.kid, }); /// [privateKey] is JWK (Json Web Key) of user private key final Map privateKey; + /// [clientId] is clientId. + final String clientId; + /// [did] did String did; @@ -47,8 +51,8 @@ class TokenParameters { return privateKey['crv'] == 'P-256' ? 'ES256' : 'ES256K'; } - /// whether to use did or thumbprint - bool useJWKThumbPrint; + /// client type + ClientType clientType; /// [thumbprint] of JWK as defined in https://www.rfc-editor.org/rfc/rfc7638 String get thumbprint { diff --git a/packages/oidc4vc/lib/src/verifier_token_parameters.dart b/packages/oidc4vc/lib/src/verifier_token_parameters.dart index 7e6b54a4f..216806cc6 100644 --- a/packages/oidc4vc/lib/src/verifier_token_parameters.dart +++ b/packages/oidc4vc/lib/src/verifier_token_parameters.dart @@ -11,9 +11,10 @@ class VerifierTokenParameters extends TokenParameters { required super.did, required super.proofHeaderType, required super.mediaType, - required this.audience, - required super.useJWKThumbPrint, + required super.clientType, + required super.clientId, required this.credentials, + required this.audience, this.nonce, super.kid, }); diff --git a/pubspec.lock b/pubspec.lock index 9780e815d..8bd37bdf7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1485,10 +1485,10 @@ packages: dependency: "direct main" description: name: matrix - sha256: "187390203f6a5a7370490b7036f2defc306fda240f8d744191d406692c128469" + sha256: "90e8743a3836414751400ecb24c9b41a20472b316f77010dc4ddcf300d511906" url: "https://pub.dev" source: hosted - version: "0.25.8" + version: "0.25.9" matrix_api_lite: dependency: transitive description: From 8d74ac03e7d8cfa6bcb3529d79a2d016cd8861ba Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 14 Feb 2024 18:30:00 +0545 Subject: [PATCH 39/70] feat: Add issuer VerifiableID in Discover for profile OWF Baseline with vc+sd-jwt #2384 --- lib/app/shared/constants/urls.dart | 2 ++ .../credential_subject_type_extension.dart | 9 ++++++- lib/credentials/cubit/credentials_cubit.dart | 3 ++- lib/dashboard/profile/models/profile.dart | 24 ++++++++++++++++++- .../cubit/kyc_verification_cubit.dart | 22 ++++++++++------- 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/lib/app/shared/constants/urls.dart b/lib/app/shared/constants/urls.dart index 099997679..799a27bd2 100644 --- a/lib/app/shared/constants/urls.dart +++ b/lib/app/shared/constants/urls.dart @@ -55,6 +55,8 @@ class Urls { 'https://issuer.talao.co/passbase/endpoint/verifiableid/'; static const String identityCardUrlJWTVCJSON = 'https://talao.co/id360/oidc4vc/'; + static const String identityCardUrlVCSDJWT = + 'https://talao.co/id360/oidc4vc?format=vcsd-jwt&type=identitycredential'; static const String over18JWTVCJSON = 'https://talao.co/id360/oidc4vc?type=over18'; 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 f67a19693..cf9340d99 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 @@ -645,6 +645,12 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { return [VCFormatType.ldpVc]; case CredentialSubjectType.verifiableIdCard: + return [ + VCFormatType.ldpVc, + VCFormatType.jwtVcJson, + VCFormatType.vcSdJWT, + ]; + case CredentialSubjectType.over18: case CredentialSubjectType.livenessCard: case CredentialSubjectType.emailPass: @@ -839,8 +845,9 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { link = Urls.identityCardUrlJWTVCJSON; case VCFormatType.jwtVc: case VCFormatType.jwtVcJsonLd: - case VCFormatType.vcSdJWT: link = ''; + case VCFormatType.vcSdJWT: + link = Urls.identityCardUrlVCSDJWT; } whyGetThisCard = diff --git a/lib/credentials/cubit/credentials_cubit.dart b/lib/credentials/cubit/credentials_cubit.dart index 2061c38dd..17a273f56 100644 --- a/lib/credentials/cubit/credentials_cubit.dart +++ b/lib/credentials/cubit/credentials_cubit.dart @@ -632,7 +632,8 @@ class CredentialsCubit extends Cubit { final displayVerifiableId = vcFormatType == VCFormatType.ldpVc && discoverCardsOptions.displayVerifiableId; final displayVerifiableIdJwt = - vcFormatType == VCFormatType.jwtVcJson && + (vcFormatType == VCFormatType.jwtVcJson || + vcFormatType == VCFormatType.vcSdJWT) && discoverCardsOptions.displayVerifiableIdJwt; if (displayVerifiableId || displayVerifiableIdJwt) { diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index cb8a102d7..cb36a8122 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -210,7 +210,29 @@ class ProfileModel extends Equatable { blockchainOptions: BlockchainOptions.initial(), generalOptions: GeneralOptions.empty(), helpCenterOptions: HelpCenterOptions.initial(), - discoverCardsOptions: DiscoverCardsOptions.none(), + discoverCardsOptions: const DiscoverCardsOptions( + displayDefi: false, + displayHumanity: false, + displayHumanityJwt: false, + displayOver13: false, + displayOver15: false, + displayOver18: false, + displayOver18Jwt: false, + displayOver21: false, + displayOver50: false, + displayChainborn: false, + displayTezotopia: false, + displayVerifiableId: false, + displayVerifiableIdJwt: true, + displayOver65: false, + displayEmailPass: false, + displayEmailPassJwt: false, + displayPhonePass: false, + displayPhonePassJwt: false, + displayAgeRange: false, + displayGender: false, + displayExternalIssuer: [], + ), selfSovereignIdentityOptions: SelfSovereignIdentityOptions( displayManageDecentralizedId: true, customOidc4vcProfile: CustomOidc4VcProfile( diff --git a/lib/kyc_verification/cubit/kyc_verification_cubit.dart b/lib/kyc_verification/cubit/kyc_verification_cubit.dart index 213b81bdb..184792815 100644 --- a/lib/kyc_verification/cubit/kyc_verification_cubit.dart +++ b/lib/kyc_verification/cubit/kyc_verification_cubit.dart @@ -71,10 +71,14 @@ class KycVerificationCubit extends Cubit { required String link, dynamic Function()? onKycApproved, }) async { - await startKycVerifcation(vcType: vcType); + await startKycVerifcation( + vcType: vcType, + link: link, + ); } Future startKycVerifcation({ + String? link, KycVcType vcType = KycVcType.verifiableId, }) async { emit(state.copyWith(status: KycVerificationStatus.loading)); @@ -85,13 +89,15 @@ class KycVerificationCubit extends Cubit { } //emit(state.copyWith(status: KycVerificationStatus.pending)); const walletId = AltMeStrings.clientIdForID360; - final url = '${Urls.authenticateForId360}/$code?vc_type=${vcType.value}' - '&client_id=$walletId&callback=${Urls.appDeepLink}'; - await LaunchUrl.launchUri( - Uri.parse( - url, - ), - ); + late String url; + + if (link == null) { + url = '${Urls.authenticateForId360}/$code?vc_type=${vcType.value}' + '&client_id=$walletId&callback=${Urls.appDeepLink}'; + } else { + url = link; + } + await LaunchUrl.launchUri(Uri.parse(url)); emit(state.copyWith(status: KycVerificationStatus.unkown)); } } From 8f9c8a4fee884d06d485e9931f0f7ae6e7b748c2 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Wed, 14 Feb 2024 18:32:46 +0545 Subject: [PATCH 40/70] update version 2.2.24+386 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index bcb123225..2d76addc7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.23+385 +version: 2.2.24+386 environment: sdk: ">=3.1.0 <4.0.0" From 30319b4dc7752f17708361ed6d5b498fd7e2588e Mon Sep 17 00:00:00 2001 From: HugoNDO <108657151+HugoNDO@users.noreply.github.com> Date: Wed, 14 Feb 2024 22:30:45 +0800 Subject: [PATCH 41/70] Update app_en.arb (#2393) --- lib/l10n/arb/app_en.arb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 6225d2b44..c5ed071a4 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -775,9 +775,9 @@ "thereIsNoAccountInYourWallet": "There is no account in your wallet", "exportToLinkedIn": "Export To LinkedIn", "addLinkedInInfo": "Add LinkedIn Info", - "whatsYourLinkedinProfileUrl": "What's your linkedIn profile url?", - "invalidUrlError": "Please enter valid linkedIn url", - "linkedInBannerSuccessfullyExported": "Your linkedin banner has been successfully exported.", + "whatsYourLinkedinProfileUrl": "What's your LinkedIn profile URL?", + "invalidUrlError": "Please enter a valid LinkedIn URL", + "linkedInBannerSuccessfullyExported": "Your LinkedIn banner has been successfully exported.", "credentialSuccessfullyExported": "Your credential has been successfully exported.", "linkedInBanner": "Linkedin Banner", "linkedInProfile": "Linkedin Profile", @@ -786,9 +786,9 @@ "whatsNew": "What's new", "okGotIt": "OK, GOT IT!", "support": "support", - "transactionDoneDialogDescription": "It can take a few minutes for the transfer to complete", - "withdrawalFailedMessage": "The withdrawal from the account was unsuccessful", - "credentialRequiredMessage": "You need to get those credentials in your wallet to acquire this card:", + "transactionDoneDialogDescription": "The transfer may take a few minutes to complete", + "withdrawalFailedMessage": "The account withdrawal was unsuccessful", + "credentialRequiredMessage": "You must have the required credentials in your wallet to acquire this card:", "keyDecentralizedIdEdSA": "Key Decentralized ID EdDSA", "keyDecentralizedIDSecp256k1": "Key Decentralized ID Secp256k1", "polygonIdDecentralizedId": "Polygon Decentralized ID", @@ -1036,4 +1036,4 @@ "theLdpFormatIsNotSupportedByThisDIDMethod": "The ldp_format is not supported by this DID method.", "switchOffCryptoHolderBindingForThatDIDMethod": "Switch off Crypto Holder Binding for that DID Method.", "thisTypeProofCannotBeUsedWithThisVCFormat": "This type proof cannot be used with this VC Format." -} \ No newline at end of file +} From 8b13abf5678a093d8c308bb74599d6ccfb89e756 Mon Sep 17 00:00:00 2001 From: HugoNDO <108657151+HugoNDO@users.noreply.github.com> Date: Wed, 14 Feb 2024 22:32:26 +0800 Subject: [PATCH 42/70] Update app_fr.arb (#2394) --- lib/l10n/arb/app_fr.arb | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index 4d9a555c2..a85285b40 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -108,7 +108,7 @@ "warningDialogTitle": "Soyez prudent", "warningDialogSubtitle": "La page de récupération contient des informations sensibles qui pourraient compromettre votre identifiant entre de mauvaises mains. Vous ne devez pas ouvrir cette page en public ni la partager avec qui que ce soit.", "recoveryText": "Veuillez entrer votre phrase de récupération", - "recoveryMnemonicHintText": "Saisissez votre phrase de récupération ici. Une fois que vous avez saisi vos 12 mots, tappuyez sur Importer.", + "recoveryMnemonicHintText": "Saisissez votre phrase de récupération ici. Une fois que vous avez saisi vos 12 mots, appuyez sur Importer.", "recoveryMnemonicError": "Veuillez entrer une phrase mnémonique valide", "showDialogYes": "Continuer", "showDialogNo": "Annuler", @@ -128,7 +128,7 @@ "documentHeaderTooltipLabel": "Statut :", "documentHeaderTooltipValue": "Valide", "didDisplayId": "DID", - "blockChainDisplayMethod": "Chaîne de blocs", + "blockChainDisplayMethod": "Blockchain", "blockChainAdress": "Adresse", "didDisplayCopy": "Copier DID dans le presse-papiers", "adressDisplayCopy": "Copier l'adresse dans le presse-papiers", @@ -328,7 +328,7 @@ "drawerTalaoCommunityCard": "Carte de communauté Talao", "drawerTalaoCommunityCardTitle": "Importez votre adresse Ethereum et obtenez votre carte communautaire.", "drawerTalaoCommunityCardSubtitle": "Elle vous donnera accès aux meilleures réductions, adhésions et cartes de bons d'achat de notre écosystème de partenaires.", - "drawerTalaoCommunityCardTextBoxMessage": "Une fois que vous avez entré votre clé privée, appuyez sur Importer. Veuillez vous assurer d'entrer la clé privée Ethereum qui contient votre jeton Talao.", + "drawerTalaoCommunityCardTextBoxMessage": "Une fois que vous avez entré votre clé privée, appuyez sur Importer. Veuillez vous assurer d'entrer la clé privée Ethereum qui contient votre cryptomonnaie Talao.", "drawerTalaoCommunityCardSubtitle2": "Le portefeuille Altme est auto-dépositaire. Nous n'avons jamais accès à vos clés privées ou à vos fonds.", "drawerTalaoCommunityCardKeyError": "Veuillez saisir une clé privée valide", "loginWithBiometricsMessage": "Déverrouillez rapidement votre portefeuille sans avoir à saisir de mot de passe ou de code PIN", @@ -474,7 +474,7 @@ "edit": "Editer", "networkFee": "Frais de réseau", "totalAmount": "Montant total", - "selectToken": "Sélectionner le jeton", + "selectToken": "Sélectionner le token", "insufficientBalance": "Solde insuffisant", "slow": "Lent", "average": "Moyenne", @@ -483,12 +483,12 @@ "sent": "Envoyé", "done": "fait", "link": "Cliquez pour accéder", - "myTokens": "Mes jetons", + "myTokens": "Mes Cryptos", "tezosMainNetwork": "Réseau principal Tezos", "send": "Envoyer", "receive": "Recevoir", "recentTransactions": "Transactions récentes", - "sendOnlyToThisAddressDescription": "Envoyez uniquement {symbol} à cette adresse. L'envoi d'autres jetons peut entraîner une perte permanente.", + "sendOnlyToThisAddressDescription": "Envoyez uniquement {symbol} à cette adresse. L'envoi d'autres cryptomonnaie peut entraîner une perte permanente.", "@sendOnlyToThisAddressDescription": { "description": "Nom du symbole lors de l'affichage de l'adresse dans la page de réception", "type": "text", @@ -496,7 +496,7 @@ "symbol": {} } }, - "addTokens": "Ajouter des jetons", + "addTokens": "Ajouter des Cryptos", "providedBy": "Fourni par", "issuedOn": "Émis le", "expirationDate": "Date d'expiration", @@ -551,7 +551,7 @@ "identityCredentialHomeSubtitle": "Prouvez des choses sur vous tout en protégeant vos données.", "identityCredentialDiscoverSubtitle": "Prouvez des choses sur vous tout en protégeant vos données.", "myProfessionalCredentialDiscoverSubtitle": "Utilisez vos cartes professionnelles en toute sécurité.", - "blockchainAccountsCredentialHomeSubtitle": "Utilisez vos comptes blockchain en toute sécurité.", + "blockchainAccountsCredentialHomeSubtitle": "Utilisez vos comptes blockchains en toute sécurité.", "passCredentialHomeSubtitle": "Utilisez des pass exclusifs : améliorez votre expérience Web3.", "communityCredentialHomeSubtitle": "Bénéficiez des avantages offerts par les Communautés que vous aimez.", "communityCredentialDiscoverSubtitle": "Obtenez des avantages exclusifs offerts par les communautés que vous aimez.", @@ -561,7 +561,7 @@ "showLess": "Afficher moins...", "youHaveReceivedARewardOf": "Vous avez reçu une récompense de", "gotIt": "J'ai compris", - "transactionErrorBalanceTooLow": "Une opération a tenté de dépenser plus de jetons que le contrat n'en a", + "transactionErrorBalanceTooLow": "Une opération a tenté de dépenser plus de cryptomonnaie que le contrat n'en a", "transactionErrorCannotPayStorageFee": "Les frais de stockage sont supérieurs au solde du contrat", "transactionErrorFeeTooLow": "Les frais de fonctionnement sont trop bas", "transactionErrorFeeTooLowForMempool": "Les frais de fonctionnement sont trop faibles pour être pris en compte dans le mempool complet", @@ -622,7 +622,7 @@ "nftTooBigToLoad": "NFT trop gros pour être chargé", "seeTransaction": "Voir la transaction", "nftListSubtitle": "Voici tous les NFT et objets de collection de votre compte.", - "tokenListSubtitle": "Voici tous les jetons de votre compte.", + "tokenListSubtitle": "Voici toutes les cryptomonnaies de votre compte.", "my": "Mon", "get": "Obtenir", "emailProofDummyDescription": "Prouvez la propriété de votre e-mail dans Web 3.", @@ -688,7 +688,7 @@ "trooperzPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Réclamez-les en suivant la vérification KYC d'Altme.", "walletSecurity": "Sécurité du portefeuille", "walletSecurityDescription": "Protégez votre portefeuille avec le code PIN et l'authentification biométrique", - "blockchainSettings": "Paramètres de la chaîne de blocs", + "blockchainSettings": "Paramètres de la blockchain", "blockchainSettingsDescription": "Gérer les comptes, la phrase de récupération, les dApps et les réseaux connectés", "ssi": "Identité auto-souveraine (DID)", "ssiDescription": "Gérez votre identifiant décentralisé et sauvegardez ou restaurez vos identifiants", @@ -729,7 +729,7 @@ "polygonAccount": "Compte polygone", "polygonAccountDescription": "Créer une nouvelle adresse blockchain Polygon", "binanceAccount": "Compte BNB Chain", - "binanceAccountDescription": "Créer une nouvelle adresse blockchain Binance", + "binanceAccountDescription": "Créer une nouvelle adresse blockchain BNB", "setAccountNameDescription": "Voulez-vous donner un nom à ce nouveau compte ? Utile si vous en avez plusieurs.", "letsGo": "Allons-y !", "congratulations": "Félicitations !", @@ -737,7 +737,7 @@ "ethereumAccountCreationCongratulations": "Votre nouveau compte Ethereum a été créé avec succès.", "fantomAccountCreationCongratulations": "Votre nouveau compte Fantom a été créé avec succès.", "polygonAccountCreationCongratulations": "Votre nouveau compte Polygon a été créé avec succès.", - "binanceAccountCreationCongratulations": "Votre nouveau compte Binance a été créé avec succès.", + "binanceAccountCreationCongratulations": "Votre nouveau compte BNB Chain a été créé avec succès.", "accountImportCongratulations": "Votre compte a été importé avec succès.", "saveBackupCredentialTitle": "Téléchargez le fichier de sauvegarde. Conservez-le en lieu sûr.", "saveBackupCredentialSubtitle": "Pour récupérer tous vos identifiants, vous aurez besoin de la phrase de récupération ET de ce fichier de sauvegarde.", @@ -762,7 +762,7 @@ "transactionIsLikelyToFail": "La transaction est susceptible d'échouer.", "buy": "acheter", "thisFeatureIsNotSupportedYetForFantom": "Cette fonctionnalité n'est pas encore prise en charge pour Fantom.", - "thisFeatureIsNotSupportedYetForBinance": "Cette fonctionnalité n'est pas encore prise en charge pour Binance.", + "thisFeatureIsNotSupportedYetForBinance": "Cette fonctionnalité n'est pas encore prise en charge pour BNB Chain.", "faqs": "FAQ", "softwareLicenses": "Licences logicielles", "notAValidWalletAddress": "L'adresse de portefeuille n'est pas valide !", @@ -787,4 +787,4 @@ "proceed": "Continue", "import": "Importer", "community": "Communauté" -} \ No newline at end of file +} From 3e79fbe179cfa5997b752224da15226cee8b9170 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Wed, 14 Feb 2024 16:00:49 +0000 Subject: [PATCH 43/70] set language to english --- lib/lang/cubit/lang_cubit.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/lang/cubit/lang_cubit.dart b/lib/lang/cubit/lang_cubit.dart index 2b509497b..7367e5c06 100644 --- a/lib/lang/cubit/lang_cubit.dart +++ b/lib/lang/cubit/lang_cubit.dart @@ -2,16 +2,16 @@ import 'dart:async'; import 'package:altme/l10n/l10n.dart'; import 'package:bloc/bloc.dart'; -import 'package:devicelocale/devicelocale.dart'; +// import 'package:devicelocale/devicelocale.dart'; import 'package:flutter/material.dart'; class LangCubit extends Cubit { LangCubit() : super(const Locale('en', 'US')); Future fetchLocale() async { - final Locale? locale = await Devicelocale.currentAsLocale; + const Locale locale = Locale('en', 'US'); - final langauageCode = locale!.languageCode; + final langauageCode = locale.languageCode; if (AppLocalizations.supportedLocales.contains(Locale(langauageCode))) { setLocale(locale); From 9e2e7234c4898955c13abdba21220ccda043440a Mon Sep 17 00:00:00 2001 From: HugoNDO <108657151+HugoNDO@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:17:42 +0800 Subject: [PATCH 44/70] Update app_en.arb (#2402) --- lib/l10n/arb/app_en.arb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 69f869434..48bd37115 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -289,7 +289,7 @@ "myAssets": "My assets", "search": "Search", "professional": "Professional", - "splashSubtitle": "Own your digital identity and digital assets.", + "splashSubtitle": "Own your digital identity and digital assets", "poweredBy": "Powered By", "splashLoading": "Loading...", "version": "Version", @@ -642,7 +642,7 @@ "rewardDialogDescPart1": "You just received", "rewardDialogDescPart2": "on your account", "origin": "Origin", - "nftTooBigToLoad": "NFT too big to Load", + "nftTooBigToLoad": "NFT loading", "seeTransaction": "See transaction", "nftListSubtitle": "Here are all NFTs and collectibles in your account.", "tokenListSubtitle": "Here are all tokens in your account.", From b6f0c0a4b5db15e50659d715addccf1ee160410c Mon Sep 17 00:00:00 2001 From: HugoNDO <108657151+HugoNDO@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:25:22 +0800 Subject: [PATCH 45/70] Update app_fr.arb (#2403) --- lib/l10n/arb/app_fr.arb | 216 ++++++++++++++++++++-------------------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index a85285b40..b6576d1a0 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -280,7 +280,7 @@ "cardsActive": "Carte active", "cardsProblem": "Problème de carte", "unableToProcessTheData": "Impossible de traiter les données", - "unimplementedQueryType": "Type de requête non implémenté", + "unimplementedQueryType": "Type de requête non implémentée", "onSubmittedPassBasePopUp": "Vous allez recevoir un e-mail", "myCollection": "Ma collection", "items": "articles", @@ -288,14 +288,14 @@ "generate": "générer", "myAssets": "Mes actifs", "search": "Rechercher", - "splashTitle": "Portefeuille Altme", - "splashSubtitle": "Gérez les informations d'identification, les NFT et les pièces dans une seule application.", + "splashTitle": "Altme Wallet", + "splashSubtitle": "Prenez le contrôle de vos données", "splashLoading": "Chargement...", "version": "Version", "cards": "Cartes", - "nfts": "NFT", - "tokens": "Tokens", - "getCards": "Obtenir les identifiants", + "nfts": "NFTs", + "tokens": "Coins", + "getCards": "Obtenir", "close": "Fermer", "profile": "Profil", "infos": "Infos", @@ -323,7 +323,7 @@ "details": "Détails", "getIt": "Obtenir", "getItNow": "Obtenez-le maintenant", - "getThisCard": "Obtenir cette carte", + "getThisCard": "Obtenir maintenant", "drawerBiometrics": "Authentification biométrique", "drawerTalaoCommunityCard": "Carte de communauté Talao", "drawerTalaoCommunityCardTitle": "Importez votre adresse Ethereum et obtenez votre carte communautaire.", @@ -405,22 +405,22 @@ "numberCharacters": {} } }, - "kycDialogTitle": "Pour obtenir cette carte et d'autres cartes d'identité, vous devez vérifier votre identité", + "kycDialogTitle": "Pour obtenir ce justificatif d'identité numérique, vous devez vérifier votre identité", "idVerificationProcess": "Processus de vérification d'identité", "idCheck": "Vérification d'identité", "facialRecognition": "Reconnaissance faciale", "kycDialogButton": "Démarrer la vérification de l'ID", "kycDialogFooter": "Conforme GDPR et CCPA + Niveau de sécurité SOC2", "finishedVerificationTitle": "Vérification d'identité en cours", - "finishedVerificationDescription": "Vous recevrez un e-mail pour confirmer que votre identifiant a été vérifié", + "finishedVerificationDescription": "Vous recevrez un e-mail une fois que votre identité aura été vérifiée", "verificationPendingTitle": "Votre vérification d'identité est en attente", "verificationPendingDescription": "En général, la vérification prend moins de 5 minutes. Vous recevrez un e-mail une fois la vérification terminée.", - "verificationDeclinedTitle": "Votre vérification a refusé", + "verificationDeclinedTitle": "La vérification n'a pas abouti", "restartVerification": "Redémarrer la vérification d'identité", - "verificationDeclinedDescription": "Votre vérification a été refusée. Veuillez redémarrer votre vérification d'identité.", - "verifiedTitle": "Bravo ! Votre vérification a réussi.", - "verifiedDescription": "Vous pouvez maintenant commencer à ajouter votre carte 'over18'. Commençons.", - "verfiedButton": "Ajout de la carte de plus de 18 ans", + "verificationDeclinedDescription": "La vérification n'a pas abouti. Veuillez redémarrer votre vérification d'identité.", + "verifiedTitle": "Bravo ! La vérification est réussie.", + "verifiedDescription": "Vous pouvez ajouter votre preuve d'âge. Commençons.", + "verfiedButton": "Ajout de la preuve d'âge : + de 18 ans", "verifiedNotificationTitle": "Vérification terminée !", "verifiedNotificationDescription": "Félicitations ! Vous avez été vérifié avec succès.", "showDecentralizedID": "Afficher l'ID décentralisé", @@ -432,15 +432,15 @@ "privateKeyDescriptions": "Une clé privée est un numéro secret utilisé pour signer des transactions et prouver la propriété d'une adresse blockchain. Sur Tezos, la clé privée comporte généralement 54 caractères.", "importAccount": "Importer un compte", "imported": "Importé", - "cardDetails": "Détails de la carte", + "cardDetails": "Détails", "publicAddress": "Adresse publique", "didKey": "Clé SDA", "export": "Exporter", "copy": "Copier", "didPrivateKey": "Clé privée SDA", "reveal": "Révéler", - "didPrivateKeyDescription": "Veuillez être très prudent avec vos clés privées, car elles contrôlent l'accès à vos informations d'identification.", - "didPrivateKeyDescriptionAlert": "Veuillez ne partager votre clé privée avec personne. Altme n'est pas dépositaire, nous ne le demanderons jamais.", + "didPrivateKeyDescription": "Soyez prudent avec vos clés privées, car elles contrôlent l'accès à vos informations d'identification.", + "didPrivateKeyDescriptionAlert": "Ne partagez votre clé privée avec personne.", "iReadTheMessageCorrectly": "J'ai bien lu le message", "beCareful": "Soyez prudent", "decentralizedIDKey": "Clé d'identification décentralisée", @@ -454,7 +454,7 @@ "privateKey": "Clé privée", "decentralizedID": "Identifiant décentralisé", "did": "DID", - "accountPrivateKeyAlert": "Veuillez ne partager votre phrase de récupération avec personne. Altme n'est pas dépositaire, nous ne le demanderons jamais. Le partage de votre phrase de récupération peut entraîner une perte de vos fonds", + "accountPrivateKeyAlert": "Ne partagez jamais votre phrase de récupération. Le partage de votre phrase de récupération peut entraîner une perte de vos fonds.", "sameAccountNameError": "Ce nom de compte a déjà été utilisé ; entrez un nom de compte différent, s'il vous plaît", "unknown": "Inconnu", "credentialManifestDescription": "Description", @@ -504,20 +504,20 @@ "connection": "Connexion", "selectAccountToGrantAccess": "Sélectionnez le compte auquel accorder l'accès :", "requestPersmissionTo": "Demander l'autorisation à :", - "viewAccountBalanceAndNFTs": "Afficher le solde du compte et les NFT", + "viewAccountBalanceAndNFTs": "Afficher le solde du compte et les NFTs", "requestApprovalForTransaction": "Demande d'approbation pour la transaction", - "connectedWithBeacon": "Connexion réussie avec dApp", - "failedToConnectWithBeacon": "Échec de la connexion avec dApp", + "connectedWithBeacon": "Connexion réussie", + "failedToConnectWithBeacon": "Échec de la connexion", "tezosNetwork": "Réseau Tezos", "confirm_sign": "Confirmer la signature", "sign": "Signe", - "payload_to_sign": "Charge utile à signer", - "signedPayload": "Charge utile signée avec succès", - "failedToSignPayload": "Échec de la signature de la charge utile", + "payload_to_sign": "Transaction à signer", + "signedPayload": "Transaction signée avec succès", + "failedToSignPayload": "Échec de la signature", "voucher": "Voucher", "tezotopia": "Tezotopia", - "operationCompleted": "Votre opération demandée est terminée. La transaction peut mettre quelques minutes à s'afficher dans le portefeuille.", - "operationFailed": "Votre opération demandée a échoué", + "operationCompleted": "Votre demande a été prise en compte. La transaction peut mettre quelques minutes à s'afficher dans le portefeuille.", + "operationFailed": "L'opération a échoué", "membership": "Adhésion", "switchNetworkMessage": "Veuillez basculer votre réseau vers", "fee": "Frais", @@ -525,10 +525,10 @@ "gaming": "Jeux", "identity": "identité", "payment": "Paiement", - "socialMedia": "Médias sociaux", + "socialMedia": "Réseaux sociaux", "advanceSettings": "Paramètres avancés", "categories": "Catégories", - "selectCredentialCategoryWhichYouWantToShowInCredentialList": "Sélectionnez les catégories d'informations d'identification que vous souhaitez afficher dans la liste des informations d'identification :", + "selectCredentialCategoryWhichYouWantToShowInCredentialList": "Sélectionnez les types de justificatifs numériques que vous souhaitez afficher dans la liste :", "communauté": "Communauté", "tezos": "Tezos", "rights": "Droits", @@ -536,90 +536,90 @@ "revokeAllRights": "Révoquer tous les droits", "revokeSubtitleMessage": "Êtes-vous sûr de vouloir révoquer tous les droits", "revokeAll": "Révoquer tout", - "succesfullyDisconnected": "déconnexion réussie de dApp.", + "succesfullyDisconnected": "Déconnexion réussie.", "connectedApps": "Apps connectées", "manageConnectedApps": "Gérer les dApps connectées", "noDappConnected": "Aucune dApp connectée pour le moment", - "nftDetails": "Détails de NFT", + "nftDetails": "Détails", "failedToDoOperation": "Échec de l'opération", "nft": "NFT", "receiveNft": "Recevoir NFT", - "sendOnlyNftToThisAddressDescription": "Envoyez uniquement des NFT Tezos à cette adresse. L'envoi de NFT depuis un autre réseau peut entraîner une perte permanente.", - "beaconShareMessage": "Envoyez uniquement des Tezos (XTZ) et des Tezos NFT (FA2 Standard) à cette adresse. L'envoi de Tezos et de NFT depuis d'autres réseaux peut entraîner une perte permanente", - "gamingCredentialHomeSubtitle": "Bénéficiez d'avantages exclusifs offerts par Web3 Games.", - "gamingCredentialDiscoverSubtitle": "Bénéficiez d'avantages exclusifs offerts par Web3 Games.", - "identityCredentialHomeSubtitle": "Prouvez des choses sur vous tout en protégeant vos données.", - "identityCredentialDiscoverSubtitle": "Prouvez des choses sur vous tout en protégeant vos données.", - "myProfessionalCredentialDiscoverSubtitle": "Utilisez vos cartes professionnelles en toute sécurité.", + "sendOnlyNftToThisAddressDescription": "Envoyez uniquement des NFTs Tezos à cette adresse. L'envoi de NFT depuis un autre réseau peut entraîner une perte permanente.", + "beaconShareMessage": "Envoyez uniquement des tokens et NFTs Tezos (FA2 Standard) à cette adresse. L'envoi de Tezos et de NFT depuis d'autres réseaux peut entraîner une perte permanente", + "gamingCredentialHomeSubtitle": "Bénéficiez d'avantages offerts par les jeux Web3.", + "gamingCredentialDiscoverSubtitle": "Bénéficiez d'avantages offerts par les jeux Web3.", + "identityCredentialHomeSubtitle": "Prouvez qui vous êtes tout en protégeant vos données.", + "identityCredentialDiscoverSubtitle": "Prouvez qui vous êtes tout en protégeant vos données.", + "myProfessionalCredentialDiscoverSubtitle": "Utilisez vos justifs professionnels en toute sécurité.", "blockchainAccountsCredentialHomeSubtitle": "Utilisez vos comptes blockchains en toute sécurité.", "passCredentialHomeSubtitle": "Utilisez des pass exclusifs : améliorez votre expérience Web3.", - "communityCredentialHomeSubtitle": "Bénéficiez des avantages offerts par les Communautés que vous aimez.", - "communityCredentialDiscoverSubtitle": "Obtenez des avantages exclusifs offerts par les communautés que vous aimez.", - "otherCredentialHomeSubtitle": "Autres types de cartes dans votre portefeuille : Ticket", - "otherCredentialDiscoverSubtitle": "Autres types de cartes que vous pouvez ajouter : Ticket", + "communityCredentialHomeSubtitle": "Bénéficiez d'avantages offerts par les Communautés que vous aimez.", + "communityCredentialDiscoverSubtitle": "Obtenez des avantages offerts par les communautés que vous aimez.", + "otherCredentialHomeSubtitle": "Autres types de justificatifs numériques dans votre portefeuille", + "otherCredentialDiscoverSubtitle": "Autres types de justificatifs numériques que vous pouvez ajouter", "showMore": "...Afficher plus", "showLess": "Afficher moins...", "youHaveReceivedARewardOf": "Vous avez reçu une récompense de", "gotIt": "J'ai compris", - "transactionErrorBalanceTooLow": "Une opération a tenté de dépenser plus de cryptomonnaie que le contrat n'en a", - "transactionErrorCannotPayStorageFee": "Les frais de stockage sont supérieurs au solde du contrat", - "transactionErrorFeeTooLow": "Les frais de fonctionnement sont trop bas", - "transactionErrorFeeTooLowForMempool": "Les frais de fonctionnement sont trop faibles pour être pris en compte dans le mempool complet", - "transactionErrorTxRollupBalanceTooLow": "Tentative de dépenser un index de ticket à partir d'un index sans le solde requis", - "transactionErrorTxRollupInvalidZeroTransfer": "Le montant d'un virement doit être supérieur à zéro.", - "transactionErrorTxRollupUnknownAddress": "L'adresse doit exister dans le contexte lors de la signature d'un transfert avec elle.", - "transactionErrorInactiveChain": "Tentative de validation d'un bloc d'une chaîne inactive.", - "whyGetThisCard": "Pourquoi obtenir cette carte", + "transactionErrorBalanceTooLow": "Votre solde n'est pas suffisant", + "transactionErrorCannotPayStorageFee": "Les frais sont supérieurs à votre solde", + "transactionErrorFeeTooLow": "Les frais de transaction ne sont pas assez élevés", + "transactionErrorFeeTooLowForMempool": "Les frais sont trop faibles pour être pris en compte dans le mempool", + "transactionErrorTxRollupBalanceTooLow": "Vous n'avez pas le solde requis", + "transactionErrorTxRollupInvalidZeroTransfer": "Le montant doit être supérieur à zéro.", + "transactionErrorTxRollupUnknownAddress": "L'adresse n'est pas reconnue.", + "transactionErrorInactiveChain": "Blockchain incative actuellement.", + "whyGetThisCard": "Description", "howToGetIt": "Comment l'obtenir", - "emailPassWhyGetThisCard": "Ce justificatif peut être exigé par certaines Apps / Sites Web du Web 3 pour accéder à leur service ou réclamer des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", - "emailPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "emailPassHowToGetIt": "C'est super facile. Altme vérifiera la propriété de votre e-mail en envoyant un code par e-mail.", - "tezotopiaMembershipWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", + "emailPassWhyGetThisCard": "Ce justificatif peut être exigé par certaines Apps / Sites Web 3 pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", + "emailPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 an.", + "emailPassHowToGetIt": "C'est facile. Altme vérifiera que vous possédez cet email en envoyant un code sur votre email.", + "tezotopiaMembershipWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou mintez un NFT sur starbase.", "tezotopiaMembershipExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "chainbornMembershipHowToGetIt": "Pour obtenir cette carte, vous devez invoquer un \"héros\" dans le jeu Chainborn et une preuve par e-mail. Vous pouvez trouver la carte \"preuve par e-mail\" dans la section \"Découvrir\" d'Altme.", - "chainbornMembershipWhyGetThisCard": "Soyez parmi les rares à avoir accès au contenu exclusif de la boutique Chainborn, aux airdrops et à d'autres avantages réservés aux membres !", + "chainbornMembershipHowToGetIt": "Pour obtenir cette carte, vous devez invoquer un \"héros\" dans le jeu Chainborn et partager une preuve d'e-mail. Vous pouvez trouver la carte \"preuve d'email\" dans la section \"Découvrir\".", + "chainbornMembershipWhyGetThisCard": "Soyez parmi les premiers à accéder au contenu exclusif de la boutique Chainborn, aux airdrops et aux autres avantages réservés aux membres !", "chainbornMembershipExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "twitterHowToGetIt": "Suivez les étapes sur TezosProfiles https://tzprofiles.com/connect. Ensuite, réclamez la carte \"compte Twitter\" dans Altme. Assurez-vous de signer la transaction sur TZPROFILES avec le même compte que vous utilisez dans Altme. ", + "twitterHowToGetIt": "Suivez les étapes sur TezosProfiles https://tzprofiles.com/connect. Ensuite, obtenez la carte \"compte Twitter\" dans Altme. Assurez-vous de signer la transaction sur TZPROFILES avec le même compte que vous utilisez dans Altme. ", "twitterWhyGetThisCard": "Cette carte est une preuve que vous possédez votre compte Twitter. Utilisez-la pour prouver la propriété de votre compte Twitter chaque fois que vous en avez besoin.", "twitterExpirationDate": "Cette carte sera active pendant 1 an.", "twitterDummyDesc": "Prouvez la propriété de votre compte Twitter", - "linkedinCardHowToGetIt": "Vous pouvez réclamer cette carte en suivant la vérification KYC d'Altme. Seules les informations relatives à votre prénom, nom, nationalité et année de naissance seront accessibles depuis votre profil LinkedIn.", + "linkedinCardHowToGetIt": "Vous pouvez obtenir ce justificatif en suivant une vérification d'identité. Seules les informations relatives à votre prénom, nom, nationalité et année de naissance seront accessibles depuis votre profil LinkedIn.", "linkedinCardWhyGetThisCard": "Cette carte est une preuve de votre identité pour votre profil LinkedIn. A partir de cette carte, vous pouvez exporter un QR code et l'afficher dans la bannière de votre compte LinkedIn. En scannant le QR code avec son portefeuille Altme, n'importe qui pourra vérifier que votre identité correspond à l'URL de votre profil LinkedIn, et pourra également accéder à 2 informations complémentaires : votre nationalité et votre année de naissance.", "linkedinCardExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "tezotopiaMembershipHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Réclamez-les en suivant la vérification KYC d'Altme.", - "over18WhyGetThisCard": "Ce justificatif peut être exigé par certaines Applications / Sites Web du Web 3 pour accéder à leur service ou réclamer des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", + "tezotopiaMembershipHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant le KYC d'Altme.", + "over18WhyGetThisCard": "Ce justificatif peut être exigé par certaines Applications / Sites Web du Web 3 pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", "over18ExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "over18HowToGetIt": "Vous pouvez réclamer cette carte en suivant la vérification KYC d'Altme.", - "over13WhyGetThisCard": "Ce justificatif peut être exigé par certaines Applications / Sites Web du Web 3 pour accéder à leur service ou réclamer des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", + "over18HowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", + "over13WhyGetThisCard": "Ce justificatif peut être exigé par certaines Applications / Sites Web du Web 3 pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", "over13ExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "over13HowToGetIt": "Vous pouvez réclamer cette carte en suivant la vérification KYC d'Altme.", - "passportFootprintWhyGetThisCard": "Ce justificatif peut être exigé par certaines Web 3 Apps / Sites Internet pour accéder à leur service ou réclamer des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", + "over13HowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", + "passportFootprintWhyGetThisCard": "Ce justificatif peut être exigé par certaines Web 3 Apps / Sites Internet pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", "passportFootprintExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "passportFootprintHowToGetIt": "Vous pouvez réclamer cette carte en suivant la vérification KYC d'Altme.", - "verifiableIdCardWhyGetThisCard": "Cette carte d'identité numérique contient les mêmes informations que votre carte d'identité physique. Vous pouvez l'utiliser dans Web 3 pour un contrôle KYC par exemple.", + "passportFootprintHowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", + "verifiableIdCardWhyGetThisCard": "Cette carte d'identité numérique contient les mêmes informations que votre carte d'identité physique. Vous pouvez l'utiliser dans le Web 3 pour prouver votre identité.", "verifiableIdCardExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "verifiableIdCardHowToGetIt": "Vous pouvez réclamer cette carte en suivant la vérification KYC d'Altme.", + "verifiableIdCardHowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", "verifiableIdCardDummyDesc": "Obtenez votre carte d'identité numérique.", - "phoneProofWhyGetThisCard": "Ce justificatif peut être exigé par certaines Applications / Sites Web Web 3 pour accéder à leur service ou réclamer des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", + "phoneProofWhyGetThisCard": "Ce justificatif peut être exigé par certaines Applications / Sites Web Web 3 pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", "phoneProofExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "phoneProofHowToGetIt": "C'est super simple. Altme vérifiera la propriété de votre numéro de téléphone en envoyant un code par SMS.", + "phoneProofHowToGetIt": "C'est simple. Altme vérifiera la propriété de votre numéro de téléphone en envoyant un code par SMS.", "tezVoucherWhyGetThisCard": "Cette carte vous donnera 10 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", "tezVoucherExpirationDate": "Cette carte restera active et réutilisable pendant 30 jours.", - "tezVoucherHowToGetIt": " C'est super facile. Vous pouvez le réclamer gratuitement dès maintenant.", - "genderWhyGetThisCard": "Cette preuve de genre est utile pour prouver votre sexe (Homme / Femme) sans révéler aucune autre information vous concernant. Elle peut être utilisée dans une enquête auprès des utilisateurs, etc.", + "tezVoucherHowToGetIt": " C'est super facile. Vous pouvez l'obtenir gratuitement dès maintenant.", + "genderWhyGetThisCard": "Cette preuve de genre est utile pour prouver votre sexe (Homme / Femme) sans révéler aucune autre information vous concernant. Elle peut être utilisée dans une enquête auprès d'utilisateurs, etc.", "genderExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "genderHowToGetIt": "Vous pouvez réclamer cette carte en suivant la vérification KYC d'Altme.", - "nationalityWhyGetThisCard": "Cette information d'identification est utile pour prouver votre nationalité sans révéler aucune autre information vous concernant. Elle peut être requise par Web 3 Apps dans une enquête auprès des utilisateurs, etc.", + "genderHowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", + "nationalityWhyGetThisCard": "Cette information d'identification est utile pour prouver votre nationalité sans révéler aucune autre information vous concernant. Elle peut être requise par certains sites ou apps Web 3.", "nationalityExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "nationalityHowToGetIt": "Vous pouvez réclamer cette carte en suivant la vérification KYC d'Altme.", - "ageRangeWhyGetThisCard": "Cet identifiant est utile pour prouver votre tranche d'âge sans révéler aucune autre information vous concernant. Il peut être requis par Web 3 Apps dans une enquête auprès des utilisateurs ou pour réclamer des avantages : carte de membre, etc.", + "nationalityHowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", + "ageRangeWhyGetThisCard": "Cet identifiant est utile pour prouver votre tranche d'âge sans révéler aucune autre information vous concernant. Il peut être requis par certains sites ou apps Web 3 ou pour obtenir des avantages : carte de membre, etc.", "ageRangeExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "ageRangeHowToGetIt": "Vous pouvez réclamer cette carte en suivant la vérification KYC d'Altme.", + "ageRangeHowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", "rewardDialogTitle": "Bravo 🥳", "rewardDialogDescPart1": "Vous venez de recevoir", "rewardDialogDescPart2": "sur votre compte", "origin": "Origine", - "nftTooBigToLoad": "NFT trop gros pour être chargé", + "nftTooBigToLoad": "Chargement en cours", "seeTransaction": "Voir la transaction", "nftListSubtitle": "Voici tous les NFT et objets de collection de votre compte.", "tokenListSubtitle": "Voici toutes les cryptomonnaies de votre compte.", @@ -628,64 +628,64 @@ "emailProofDummyDescription": "Prouvez la propriété de votre e-mail dans Web 3.", "ageProofDummyDescription": "Prouvez votre tranche d'âge dans Web 3.", "genderProofDummyDescription": "Cette carte est utile pour prouver votre sexe (M/F) aux Web 3 Apps.", - "ageRangeProofDummyDescription": "Cette carte est utile pour prouver votre tranche d'âge aux applications Web 3.", + "ageRangeProofDummyDescription": "Cette carte est utile pour prouver votre tranche d'âge dans des Apps Web 3.", "nationalityProofDummyDescription": "Prouvez votre nationalité dans Web 3.", - "over18ProofDummyDescription": "Prouvez que vous avez plus de 18 ans.", - "over13ProofDummyDescription": "Prouvez que vous avez plus de 13 ans.", - "identityProofDummyDescription": "Obtenez votre carte d'identité numérique complète.", - "phoneProofDummyDescription": "Prouvez votre numéro de téléphone dans Web 3.", + "over18ProofDummyDescription": "Prouvez que vous avez + de 18 ans.", + "over13ProofDummyDescription": "Prouvez que vous avez + de 13 ans.", + "identityProofDummyDescription": "Obtenez votre carte d'identité numérique.", + "phoneProofDummyDescription": "Prouvez votre numéro de téléphone.", "passportFootprintDummyDescription": "Obtenez un numéro d'identification unique à partager.", - "seeMoreNFTInformationOn": "Voir plus d'informations sur NFT", + "seeMoreNFTInformationOn": "Voir plus d'informations", "credentialStatus": "Statut", "pass": "passe", "payloadFormatErrorMessage": "Le format du paylod est incorrect.", "thisFeatureIsNotSupportedMessage": "Cette fonctionnalité n'est pas encore prise en charge", "myWallet": "Mon portefeuille", "ethereumNetwork": "Réseau Ethereum", - "fantomNetwork": "Réseau fantôme", - "polygonNetwork": "Réseau de polygones", + "fantomNetwork": "Réseau Fantom", + "polygonNetwork": "Réseau Polygon", "binanceNetwork": "Réseau BNB Chain", "step": "Etape", - "activateBiometricsTitle": "Activer la biométrie pour ajouter une couche de sécurité", + "activateBiometricsTitle": "Activer la biométrie pour renforer la sécurité", "loginWithBiometricsOnBoarding": "Se connecter avec la biométrie", "option": "Option", "start": "Démarrer", "iAgreeToThe": "J'accepte les ", "termsAndConditions": "Termes et conditions", "walletReadyTitle": "Votre portefeuille est prêt !", - "walletReadySubtitle": "Découvrons tout ce que Web 3 a à offrir.", + "walletReadySubtitle": "Découvrez l'univers Web3.", "failedToInitCamera": "L'initialisation de la caméra a échoué !", - "chooseMethodPageOver18Title": "Choisissez une méthode pour obtenir votre preuve de plus de 18 ans", - "chooseMethodPageOver13Title": "Choisissez une méthode pour obtenir votre preuve de plus de 13 ans", - "chooseMethodPageSubtitle": "Faites-vous vérifier en prenant une photo en temps réel ou par une vérification de document .", - "idDocumentCheck": "Vérification des documents d'identité + Photo en temps réel", + "chooseMethodPageOver18Title": "Choisissez une méthode pour vérifier que vous avez + de 18 ans", + "chooseMethodPageOver13Title": "Choisissez une méthode pour vérifier que vous avez + de 13 ans", + "chooseMethodPageSubtitle": "Faites-vous vérifier en prenant une photo ou par une vérification de document .", + "idDocumentCheck": "Vérification des documents d'identité + Photo en temps réel", "idDocumentCheckDescription": "Faites-vous vérifier en utilisant une carte d'identité ou un passeport.", - "realTimePhoto": "Photo en temps réel", - "realTimePhotoDescription": "Faites-vous vérifier en prenant une photo de vous-même.", + "realTimePhoto": "Photo selfie", + "realTimePhotoDescription": "Faites-vous vérifier en prenant un selfie.", "verifyYourAge": "Vérifiez votre âge", - "verifyYourAgeSubtitle": "Ce processus de vérification de l'âge est très facile et simple. Il suffit d'une photo en temps réel.", - "verifyYourAgeDescription": "En acceptant, vous acceptez que nous utilisions une photo pour estimer votre âge. L'estimation est effectuée par notre partenaire Yoti qui utilise votre photo uniquement à cette fin et la supprime immédiatement. Pour plus d'informations, consultez notre Politique de confidentialité.", + "verifyYourAgeSubtitle": "Ce processus de vérification de l'âge est très simple. Il suffit d'une photo selfie.", + "verifyYourAgeDescription": "En acceptant, vous acceptez que nous utilisions votre photo pour estimer votre âge. L'estimation est effectuée par notre partenaire Yoti qui utilise votre photo uniquement à cette fin et la supprime immédiatement après. Pour plus d'informations, consultez notre Politique de confidentialité.", "accept": "Accepter", "decline": "Refuser", - "placeYourFaceInTheOval": "Placez votre visage dans l'ovale", - "cameraSubtitle": "Vous avez 5 secondes pour prendre votre photo. Assurez-vous qu'il y a suffisamment de lumière avant de commencer.", + "placeYourFaceInTheOval": "Placez votre visage le plus proche possible", + "cameraSubtitle": "Vous avez 5 secondes pour prendre votre photo. Assurez-vous qu'il y a suffisamment de lumière avant de commencer.", "todoImportant": "TODO(all): mettre à jour le texte des clés ci-dessous", - "soonCardDescription": "Cette carte avantage n'est pas encore prête. C'est pourquoi il y a une étiquette \"Bientôt \" dessus. Nous travaillons dur pour la mettre en ligne dès que possible. Restez à l'écoute !", + "soonCardDescription": "Cette carte n'est pas encore prête. C'est pourquoi il y a une étiquette \"Bientôt \" dessus. Nous travaillons dur pour la mettre en ligne dès que possible. Restez à l'écoute !", "bunnyPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", "bunnyPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "bunnyPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Réclamez-les en suivant la vérification KYC d'Altme.", + "bunnyPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", "dogamiPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", "dogamiPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "dogamiPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Réclamez-les en suivant la vérification KYC d'Altme.", + "dogamiPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", "matterlightPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", "matterlightPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "matterlightPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Réclamez-les en suivant la vérification KYC d'Altme.", + "matterlightPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", "pigsPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", "pigsPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "pigsPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Réclamez-les en suivant la vérification KYC d'Altme.", + "pigsPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", "trooperzPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", "trooperzPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "trooperzPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Réclamez-les en suivant la vérification KYC d'Altme.", + "trooperzPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", "walletSecurity": "Sécurité du portefeuille", "walletSecurityDescription": "Protégez votre portefeuille avec le code PIN et l'authentification biométrique", "blockchainSettings": "Paramètres de la blockchain", @@ -770,8 +770,8 @@ "thereIsNoAccountInYourWallet": "Il n'y a pas de compte dans votre portefeuille", "exportToLinkedIn": "Exporter vers LinkedIn", "addLinkedInInfo": "Ajouter des informations LinkedIn", - "whatsYourLinkedinProfileUrl": "Quelle est l'url de votre profil linkedIn ?", - "invalidUrlError": "Veuillez saisir une URL linkée valide", + "whatsYourLinkedinProfileUrl": "Quelle est l'url de votre profil LinkedIn ?", + "invalidUrlError": "Veuillez saisir une URL LinkedIn valide", "linkedInBannerSuccessfullyExported": "Votre bannière LinkedIn a été exportée avec succès.", "credentialSuccessfullyExported": "Votre identifiant a été exporté avec succès.", "linkedInBanner": "Bannière Linkedin", @@ -779,9 +779,9 @@ "checkLinkedinProfile": "Vérifier un profil Linkedin", "scanAndDisplay": "Numériser et afficher", "whatsNew": "Quoi de neuf", - "okGotIt": "OK, COMPRIS !", - "transactionDoneDialogDescription": "Cela peut prendre quelques minutes pour que le transfert se termine", - "withdrawalFailedMessage": "Le retrait du compte a échoué", + "okGotIt": "OK, compris !", + "transactionDoneDialogDescription": "Cela peut prendre quelques minutes", + "withdrawalFailedMessage": "Le retrait a échoué", "credentialRequiredMessage": "Vous devez obtenir ces informations d'identification dans votre portefeuille pour acquérir cette carte :", "needStoragePermission": "Désolé, vous avez besoin d'une autorisation de stockage pour télécharger ce fichier.", "proceed": "Continue", From 0b9f1a6194e8ac15e689eae955dadb1ab87e0332 Mon Sep 17 00:00:00 2001 From: HugoNDO <108657151+HugoNDO@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:28:28 +0800 Subject: [PATCH 46/70] Update app_fr.arb (#2404) Co-authored-by: hawkbee <49282360+hawkbee1@users.noreply.github.com> --- lib/l10n/arb/app_fr.arb | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index b6576d1a0..0fac8d39f 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -638,7 +638,7 @@ "seeMoreNFTInformationOn": "Voir plus d'informations", "credentialStatus": "Statut", "pass": "passe", - "payloadFormatErrorMessage": "Le format du paylod est incorrect.", + "payloadFormatErrorMessage": "Le format est incorrect.", "thisFeatureIsNotSupportedMessage": "Cette fonctionnalité n'est pas encore prise en charge", "myWallet": "Mon portefeuille", "ethereumNetwork": "Réseau Ethereum", @@ -689,7 +689,7 @@ "walletSecurity": "Sécurité du portefeuille", "walletSecurityDescription": "Protégez votre portefeuille avec le code PIN et l'authentification biométrique", "blockchainSettings": "Paramètres de la blockchain", - "blockchainSettingsDescription": "Gérer les comptes, la phrase de récupération, les dApps et les réseaux connectés", + "blockchainSettingsDescription": "Gérer vos comptes, votre phrase de récupération, et les dApps", "ssi": "Identité auto-souveraine (DID)", "ssiDescription": "Gérez votre identifiant décentralisé et sauvegardez ou restaurez vos identifiants", "helpCenter": "Centre d'aide", @@ -704,32 +704,32 @@ "officialWebsite": "Site officiel", "yourAppVersion": "La version de votre application Altme", "resetWalletTitle": "Êtes-vous sûr de vouloir réinitialiser votre portefeuille ?", - "resetWalletSubtitle": "Cette action effacera vos données. Veuillez vous assurer d'avoir enregistré votre phrase de récupération et le fichier de sauvegarde des informations d'identification avant de les supprimer.", - "resetWalletSubtitle2": "Altme est auto-dépositaire, nous ne sommes donc pas en mesure de récupérer vos fonds ou vos informations d'identification pour vous.", + "resetWalletSubtitle": "Cette action effacera vos données. Veuillez vous assurer d'avoir enregistré votre phrase de récupération et le fichier de sauvegarde de vos justifs numériques avant de les supprimer.", + "resetWalletSubtitle2": "Altme est 100% décentralisé, nous ne sommes donc pas en mesure de récupérer vos fonds ou vos justificatifs numériques à votre place.", "resetWalletCheckBox1": "J'ai noté ma phrase de récupération", - "resetWalletCheckBox2": "J'ai enregistré mon fichier d'informations d'identification de sauvegarde", + "resetWalletCheckBox2": "J'ai enregistré le fichier contenant mes justifs numériques", "email": "E-mail", "fillingThisFieldIsMandatory": "Remplir ce champ est obligatoire.", "yourMessage": "Votre message", "message": "message", "subject": "Sujet", "enterAValidEmail": "Entrez un email valide.", - "failedToSendEmail": "Échec de l'envoi de l'e-mail.", + "failedToSendEmail": "Échec de l'envoi de l'email.", "selectAMethodToAddAccount": "Sélectionnez une méthode pour ajouter un compte", "createAccount": "Créer un compte", "createAccountDescription": "Créez un compte protégé par votre phrase de récupération", "importAccountDescription": "Importer un compte depuis un portefeuille existant", "chooseABlockchainForAccountCreation": "Choisissez la blockchain sur laquelle vous souhaitez créer un nouveau compte.", "tezosAccount": "Compte Tezos", - "tezosAccountDescription": "Créer une nouvelle adresse blockchain Tezos", + "tezosAccountDescription": "Créer une nouvelle adresse Tezos", "ethereumAccount": "Compte Ethereum", - "ethereumAccountDescription": "Créer une nouvelle adresse blockchain Ethereum", + "ethereumAccountDescription": "Créer une nouvelle adresse Ethereum", "fantomAccount": "Compte fantôme", - "fantomAccountDescription": "Créer une nouvelle adresse blockchain Fantom", + "fantomAccountDescription": "Créer une nouvelle adresse Fantom", "polygonAccount": "Compte polygone", - "polygonAccountDescription": "Créer une nouvelle adresse blockchain Polygon", + "polygonAccountDescription": "Créer une nouvelle adresse Polygon", "binanceAccount": "Compte BNB Chain", - "binanceAccountDescription": "Créer une nouvelle adresse blockchain BNB", + "binanceAccountDescription": "Créer une nouvelle adresse BNB", "setAccountNameDescription": "Voulez-vous donner un nom à ce nouveau compte ? Utile si vous en avez plusieurs.", "letsGo": "Allons-y !", "congratulations": "Félicitations !", @@ -740,17 +740,17 @@ "binanceAccountCreationCongratulations": "Votre nouveau compte BNB Chain a été créé avec succès.", "accountImportCongratulations": "Votre compte a été importé avec succès.", "saveBackupCredentialTitle": "Téléchargez le fichier de sauvegarde. Conservez-le en lieu sûr.", - "saveBackupCredentialSubtitle": "Pour récupérer tous vos identifiants, vous aurez besoin de la phrase de récupération ET de ce fichier de sauvegarde.", + "saveBackupCredentialSubtitle": "Pour récupérer tous vos justificatifs numériques, vous aurez besoin de votre phrase de récupération ET de ce fichier de sauvegarde.", "restoreCredentialStep1Title": "Etape 1 : Entrez vos 12 mots de phrase de récupération", "restorePhraseTextFieldHint": "Entrez votre phrase de récupération (ou phrase mnémonique) ici...", - "restoreCredentialStep2Title": "Etape 2 : Téléchargez votre fichier de sauvegarde des identifiants", + "restoreCredentialStep2Title": "Etape 2 : Téléchargez votre fichier de sauvegarde contenant vos justificatifs numériques", "loadFile": "Charger le fichier", "uploadFile": "Télécharger le fichier", "creators": "Créateurs", "publishers": "Éditeurs", "createDate": "Créer une date", - "myProfessionalrCards": "cartes professionnelles", - "myProfessionalrCardsSubtitle": "Utilisez vos cartes professionnelles en toute sécurité.", + "myProfessionalrCards": "Justificatifs professionnelles", + "myProfessionalrCardsSubtitle": "Utilisez vos justificatifs professionnelles facilement.", "guardaWallet": "Portefeuille Guarda", "exodusWallet": "Portefeuille Exodus", "trustWallet": "Portefeuille de confiance", @@ -758,31 +758,31 @@ "skip": "Ignorer", "userNotFitErrorMessage": "Vous ne pouvez pas obtenir cette carte car certaines conditions ne sont pas remplies.", "youAreMissing": "Vous êtes absent", - "credentialsRequestedBy": "informations d'identification demandées par", + "credentialsRequestedBy": "informations demandées par", "transactionIsLikelyToFail": "La transaction est susceptible d'échouer.", "buy": "acheter", "thisFeatureIsNotSupportedYetForFantom": "Cette fonctionnalité n'est pas encore prise en charge pour Fantom.", "thisFeatureIsNotSupportedYetForBinance": "Cette fonctionnalité n'est pas encore prise en charge pour BNB Chain.", "faqs": "FAQ", "softwareLicenses": "Licences logicielles", - "notAValidWalletAddress": "L'adresse de portefeuille n'est pas valide !", + "notAValidWalletAddress": "L'adresse n'est pas valide !", "otherAccount": "Autre compte", "thereIsNoAccountInYourWallet": "Il n'y a pas de compte dans votre portefeuille", "exportToLinkedIn": "Exporter vers LinkedIn", "addLinkedInInfo": "Ajouter des informations LinkedIn", - "whatsYourLinkedinProfileUrl": "Quelle est l'url de votre profil LinkedIn ?", - "invalidUrlError": "Veuillez saisir une URL LinkedIn valide", + "whatsYourLinkedinProfileUrl": "Quelle est l'URL de votre profil linkedIn ?", + "invalidUrlError": "Veuillez saisir une URL linkdin valide", "linkedInBannerSuccessfullyExported": "Votre bannière LinkedIn a été exportée avec succès.", "credentialSuccessfullyExported": "Votre identifiant a été exporté avec succès.", "linkedInBanner": "Bannière Linkedin", "linkedInProfile": "Profil Linkedin", "checkLinkedinProfile": "Vérifier un profil Linkedin", "scanAndDisplay": "Numériser et afficher", - "whatsNew": "Quoi de neuf", - "okGotIt": "OK, compris !", + "whatsNew": "Nouveautés", + "okGotIt": "Ok, compris !", "transactionDoneDialogDescription": "Cela peut prendre quelques minutes", "withdrawalFailedMessage": "Le retrait a échoué", - "credentialRequiredMessage": "Vous devez obtenir ces informations d'identification dans votre portefeuille pour acquérir cette carte :", + "credentialRequiredMessage": "Vous devez d'abord posséder ces justificatifs pour acquérir cette carte :", "needStoragePermission": "Désolé, vous avez besoin d'une autorisation de stockage pour télécharger ce fichier.", "proceed": "Continue", "import": "Importer", From 5da4e0a86430c77cd84fec301c01537bd0640a66 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 15 Feb 2024 16:01:40 +0545 Subject: [PATCH 47/70] feat: Draft 13, authorization code flow fails with scope #2388 --- packages/oidc4vc/lib/src/oidc4vc.dart | 90 +++++++++++++++++++-------- 1 file changed, 65 insertions(+), 25 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index ca5bf54e7..beade19c7 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -203,38 +203,78 @@ class OIDC4VC { for (final credential in selectedCredentials) { late Map data; if (credential is String) { - // - final credentialsSupported = openIdConfiguration.credentialsSupported; + if (openIdConfiguration.credentialsSupported != null) { + final credentialsSupported = openIdConfiguration.credentialsSupported; + + dynamic credentailData; + + for (final dynamic cred in credentialsSupported!) { + if (cred is Map && + ((cred.containsKey('scope') && + cred['scope'].toString() == credential) || + (cred.containsKey('id') && + cred['id'].toString() == credential))) { + credentailData = cred; + break; + } + } - if (credentialsSupported == null) { - throw Exception(); - } + if (credentailData == null) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } + + data = { + 'type': 'openid_credential', + 'locations': [issuer], + 'format': credentailData['format'], + 'types': credentailData['types'], + }; + + credentials.add((credentailData['types'] as List).last); + } else if (openIdConfiguration.credentialConfigurationsSupported != + null) { + // draft 13 case + final credentialsSupported = + openIdConfiguration.credentialConfigurationsSupported; + + if (credentialsSupported is! Map) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } + + final credentialSupportedMapEntry = + credentialsSupported.entries.where( + (entry) { + final dynamic ele = entry.key; + + if (ele == credential) return true; - dynamic credentailData; + return false; + }, + ).firstOrNull; - for (final dynamic cred in credentialsSupported) { - if (cred is Map && - ((cred.containsKey('scope') && - cred['scope'].toString() == credential) || - (cred.containsKey('id') && - cred['id'].toString() == credential))) { - credentailData = cred; - break; + if (credentialSupportedMapEntry == null) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); } - } - if (credentailData == null) { - throw Exception(); - } + final credentialSupported = credentialSupportedMapEntry.value; - data = { - 'type': 'openid_credential', - 'locations': [issuer], - 'format': credentailData['format'], - 'types': credentailData['types'], - }; + data = { + 'type': 'openid_credential', + 'locations': [issuer], + 'format': credentialSupported['format'], + //'types': credential['types'], + }; - credentials.add((credentailData['types'] as List).last); + final scope = credentialSupported['scope']; + + if (scope == null) { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } + + credentials.add(scope); + } else { + throw Exception('CREDENTIAL_SUPPORT_DATA_ERROR'); + } } else if (credential is Map) { data = { 'type': 'openid_credential', From 4ca6714bba6076d98255f3a2751323b018cc9c18 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 15 Feb 2024 16:21:56 +0545 Subject: [PATCH 48/70] Modification of Wallet Profiles list #2391 --- lib/app/shared/enum/type/profile/profile_type.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/app/shared/enum/type/profile/profile_type.dart b/lib/app/shared/enum/type/profile/profile_type.dart index 90104e4c3..cff571896 100644 --- a/lib/app/shared/enum/type/profile/profile_type.dart +++ b/lib/app/shared/enum/type/profile/profile_type.dart @@ -1,12 +1,12 @@ import 'package:altme/l10n/l10n.dart'; enum ProfileType { - custom, + defaultOne, ebsiV3, dutch, enterprise, owfBaselineProfile, - defaultOne + custom, } extension ProfileTypeX on ProfileType { From f74a828925105566408248afec016cd896be2a7d Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 15 Feb 2024 16:26:26 +0545 Subject: [PATCH 49/70] Profile Default - disable developer and help option - #2392 --- lib/dashboard/drawer/src/view/drawer_page.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/dashboard/drawer/src/view/drawer_page.dart b/lib/dashboard/drawer/src/view/drawer_page.dart index 182669c87..da38868c4 100644 --- a/lib/dashboard/drawer/src/view/drawer_page.dart +++ b/lib/dashboard/drawer/src/view/drawer_page.dart @@ -116,7 +116,8 @@ class DrawerView extends StatelessWidget { ], if (profileModel - .profileSetting.settingsMenu.displayDeveloperMode) ...[ + .profileSetting.settingsMenu.displayDeveloperMode && + profileModel.profileType != ProfileType.defaultOne) ...[ DrawerCategoryItem( title: l10n.developerMode, subTitle: l10n.developerModeSubtitle, @@ -152,7 +153,8 @@ class DrawerView extends StatelessWidget { //const SizedBox(height: Sizes.spaceSmall), if (profileModel - .profileSetting.settingsMenu.displayHelpCenter) ...[ + .profileSetting.settingsMenu.displayHelpCenter && + profileModel.profileType != ProfileType.defaultOne) ...[ DrawerCategoryItem( title: l10n.helpCenter, subTitle: l10n.helpCenterDescription, From c9e136421fd54d9bb4595533dc96665ae55292c4 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Thu, 15 Feb 2024 10:45:53 +0000 Subject: [PATCH 50/70] merge english and french arb files --- lib/l10n/arb/app_fr.arb | 341 ++++++++++++++++++++++++++++++++++------ 1 file changed, 297 insertions(+), 44 deletions(-) diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index 0fac8d39f..6608ad56e 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -290,6 +290,7 @@ "search": "Rechercher", "splashTitle": "Altme Wallet", "splashSubtitle": "Prenez le contrôle de vos données", + "poweredBy": "Powered By", "splashLoading": "Chargement...", "version": "Version", "cards": "Cartes", @@ -315,8 +316,11 @@ "trustedIssuer": "Cet émetteur est approuvé par EBSI.", "yourPinCodeChangedSuccessfully": "Votre code PIN a bien été modifié", "advantagesCards": "Cartes de jeu", - "identityCards": "Cartes d'identité", - "contactInfoCredentials": "Cartes communautaires", + "advantagesDiscoverCards": "Unlock exclusive rewards", + "identityCards": "Cartes d'identité", + "identityDiscoverCards": "Simplify ID verification", + "contactInfoCredentials": "Cartes communautaires", + "contactInfoDiscoverCredentials": "Verify your contact information", "myProfessionalCards": "Cartes professionnelles", "otherCards": "Autres cartes", "inMyWallet": "Dans mon portefeuille", @@ -336,6 +340,9 @@ "wallet": "Portefeuille", "manageAccounts": "Gérer les comptes blockchain", "blockchainAccounts": "Comptes blockchain", + "educationCredentials": "Education credentials", + "educationDiscoverCredentials": "Verify your education background", + "educationCredentialsDiscoverSubtitle": "Get your digital diploma (EBSI)", "security": "Sécurité", "networkAndRegistries": "Réseau et registres", "chooseNetwork": "Choisir un réseau", @@ -343,7 +350,7 @@ "chooseIssuersRegistry": "Choisir le registre des émetteurs", "network": "Réseau", "issuerRegistry": "Registre des émetteurs", - "about": "à propos", + "about": "À propos", "termsOfUse": "Conditions d'utilisation et confidentialité", "scanFingerprintToAuthenticate": "Scanner l'empreinte digitale pour s'authentifier", "biometricsNotSupported": "La biométrie n'est pas prise en charge", @@ -378,7 +385,9 @@ "selectAccount": "Sélectionner un compte", "onbordingSeedPhrase": "Phrase de départ", "onboardingPleaseStoreMessage": "Veuillez noter votre phrase de récupération", + "onboardingVerifyPhraseMessage": "Confirm Recovery Words", "onboardingAltmeMessage": "Altme n'est pas dépositaire. Votre phrase de récupération est le seul moyen de récupérer votre compte.", + "onboardingAltmeMessage": "The wallet is non-custodial. Your Recovery Phrase is the only way to recover your account.", "onboardingWroteDownMessage": "J'ai écrit ma phrase de récupération", "copyToClipboard": "Copier dans le presse-papiers", "pinCodeMessage": "Le code PIN empêche l'accès non autorisé à votre portefeuille Altme. Vous pouvez le modifier à tout moment.", @@ -387,6 +396,7 @@ "importer": "Importer", "accountName": "Nom du compte", "importWalletText": "Entrez ici votre phrase de récupération ou votre clé privée.", + "importWalletTextRecoveryPhraseOnly": "Enter your recovery phrase here.", "recoveryPhraseDescriptions": "Une phrase de récupération (parfois appelée phrase de départ, clé privée ou phrase de sauvegarde) est une liste de 12 mots générés par votre portefeuille de crypto-monnaie qui vous donne accès à vos fonds", "importEasilyFrom": "Importez votre compte depuis :", "templeWallet": "Portefeuille du temple", @@ -405,6 +415,7 @@ "numberCharacters": {} } }, + "importWalletHintTextRecoveryPhraseOnly": "Once you have entered your 12 words (recovery phrase), tap Import.", "kycDialogTitle": "Pour obtenir ce justificatif d'identité numérique, vous devez vérifier votre identité", "idVerificationProcess": "Processus de vérification d'identité", "idCheck": "Vérification d'identité", @@ -470,6 +481,7 @@ "next": "Suivant", "withdrawalInputHint": "Copier l'adresse, scanner ou liste blanche", "amount": "Montant", + "amountSent": "Amount sent", "max": "Max", "edit": "Editer", "networkFee": "Frais de réseau", @@ -552,9 +564,12 @@ "identityCredentialDiscoverSubtitle": "Prouvez qui vous êtes tout en protégeant vos données.", "myProfessionalCredentialDiscoverSubtitle": "Utilisez vos justifs professionnels en toute sécurité.", "blockchainAccountsCredentialHomeSubtitle": "Utilisez vos comptes blockchains en toute sécurité.", + "educationCredentialHomeSubtitle": "Prove your education background instantly", "passCredentialHomeSubtitle": "Utilisez des pass exclusifs : améliorez votre expérience Web3.", - "communityCredentialHomeSubtitle": "Bénéficiez d'avantages offerts par les Communautés que vous aimez.", - "communityCredentialDiscoverSubtitle": "Obtenez des avantages offerts par les communautés que vous aimez.", + "financeCardsCredentialHomeSubtitle": "Access new investment opportunities in web3", + "financeCardsCredentialDiscoverSubtitle": "Get exclusive advantages offered by Communities you like", + "contactInfoCredentialHomeSubtitle": "Share your contact information instantly", + "contactInfoCredentialDiscoverSubtitle": "Obtain easy-to-share credentials", "otherCredentialHomeSubtitle": "Autres types de justificatifs numériques dans votre portefeuille", "otherCredentialDiscoverSubtitle": "Autres types de justificatifs numériques que vous pouvez ajouter", "showMore": "...Afficher plus", @@ -569,6 +584,7 @@ "transactionErrorTxRollupInvalidZeroTransfer": "Le montant doit être supérieur à zéro.", "transactionErrorTxRollupUnknownAddress": "L'adresse n'est pas reconnue.", "transactionErrorInactiveChain": "Blockchain incative actuellement.", + "website": "Website", "whyGetThisCard": "Description", "howToGetIt": "Comment l'obtenir", "emailPassWhyGetThisCard": "Ce justificatif peut être exigé par certaines Apps / Sites Web 3 pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", @@ -576,9 +592,11 @@ "emailPassHowToGetIt": "C'est facile. Altme vérifiera que vous possédez cet email en envoyant un code sur votre email.", "tezotopiaMembershipWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou mintez un NFT sur starbase.", "tezotopiaMembershipExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", + "tezotopiaMembershipLongDescription": "Tezotopia is a real-time metaverse NFT game on Tezos, where players yield farm with Tezotops, engage in battles for rewards, and claim land in an immersive blockchain space adventure. Explore the metaverse, collect NFTs and conquer Tezotopia.", "chainbornMembershipHowToGetIt": "Pour obtenir cette carte, vous devez invoquer un \"héros\" dans le jeu Chainborn et partager une preuve d'e-mail. Vous pouvez trouver la carte \"preuve d'email\" dans la section \"Découvrir\".", "chainbornMembershipWhyGetThisCard": "Soyez parmi les premiers à accéder au contenu exclusif de la boutique Chainborn, aux airdrops et aux autres avantages réservés aux membres !", "chainbornMembershipExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", + "chainbornMembershipLongDescription": "Chainborn is an exciting NFT battle game where players use their own NFTs as heroes, competing for loot and glory. Engage in thrilling fights, gain experience points to boost your hero's strength and health, and enhance the value of your NFTs in this captivating Tezos-based adventure.", "twitterHowToGetIt": "Suivez les étapes sur TezosProfiles https://tzprofiles.com/connect. Ensuite, obtenez la carte \"compte Twitter\" dans Altme. Assurez-vous de signer la transaction sur TZPROFILES avec le même compte que vous utilisez dans Altme. ", "twitterWhyGetThisCard": "Cette carte est une preuve que vous possédez votre compte Twitter. Utilisez-la pour prouver la propriété de votre compte Twitter chaque fois que vous en avez besoin.", "twitterExpirationDate": "Cette carte sera active pendant 1 an.", @@ -591,6 +609,9 @@ "over18ExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", "over18HowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", "over13WhyGetThisCard": "Ce justificatif peut être exigé par certaines Applications / Sites Web du Web 3 pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", + "over13ExpirationDate": "This card will remain active and reusable for 1 YEAR.", + "over13HowToGetIt": "You can claim this card by following Altme’s KYC check.", + "over15WhyGetThisCard": "This proof may be required by some Web 3 Apps / Websites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", "over13ExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", "over13HowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", "passportFootprintWhyGetThisCard": "Ce justificatif peut être exigé par certaines Web 3 Apps / Sites Internet pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", @@ -615,6 +636,9 @@ "ageRangeWhyGetThisCard": "Cet identifiant est utile pour prouver votre tranche d'âge sans révéler aucune autre information vous concernant. Il peut être requis par certains sites ou apps Web 3 ou pour obtenir des avantages : carte de membre, etc.", "ageRangeExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", "ageRangeHowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", + "defiComplianceWhyGetThisCard": "Obtain verifiable proof of KYC/AML compliance, requested by compliant DeFi protocols and Web3 dApps. Once obtained, you can mint a privacy-preserving, non-transferable NFT for on-chain verification without revealing personal data.", + "defiComplianceExpirationDate": "This credential remains active for 3 months. Renewal requires a straightforward compliance check, without new KYC.", + "defiComplianceHowToGetIt": "It's easy! Complete a one-time KYC check in Altme wallet (powered by ID360) and request your DeFi compliance credential.", "rewardDialogTitle": "Bravo 🥳", "rewardDialogDescPart1": "Vous venez de recevoir", "rewardDialogDescPart2": "sur votre compte", @@ -625,18 +649,8 @@ "tokenListSubtitle": "Voici toutes les cryptomonnaies de votre compte.", "my": "Mon", "get": "Obtenir", - "emailProofDummyDescription": "Prouvez la propriété de votre e-mail dans Web 3.", - "ageProofDummyDescription": "Prouvez votre tranche d'âge dans Web 3.", - "genderProofDummyDescription": "Cette carte est utile pour prouver votre sexe (M/F) aux Web 3 Apps.", - "ageRangeProofDummyDescription": "Cette carte est utile pour prouver votre tranche d'âge dans des Apps Web 3.", - "nationalityProofDummyDescription": "Prouvez votre nationalité dans Web 3.", - "over18ProofDummyDescription": "Prouvez que vous avez + de 18 ans.", - "over13ProofDummyDescription": "Prouvez que vous avez + de 13 ans.", - "identityProofDummyDescription": "Obtenez votre carte d'identité numérique.", - "phoneProofDummyDescription": "Prouvez votre numéro de téléphone.", - "passportFootprintDummyDescription": "Obtenez un numéro d'identification unique à partager.", - "seeMoreNFTInformationOn": "Voir plus d'informations", - "credentialStatus": "Statut", + "seeMoreNFTInformationOn": "See more NFT information on", + "credentialStatus": "Status", "pass": "passe", "payloadFormatErrorMessage": "Le format est incorrect.", "thisFeatureIsNotSupportedMessage": "Cette fonctionnalité n'est pas encore prise en charge", @@ -657,36 +671,26 @@ "failedToInitCamera": "L'initialisation de la caméra a échoué !", "chooseMethodPageOver18Title": "Choisissez une méthode pour vérifier que vous avez + de 18 ans", "chooseMethodPageOver13Title": "Choisissez une méthode pour vérifier que vous avez + de 13 ans", + "chooseMethodPageOver15Title": "Choose a method to get your Over 15 Proof", + "chooseMethodPageOver21Title": "Choose a method to get your Over 21 Proof", + "chooseMethodPageOver50Title": "Choose a method to get your Over 50 Proof", + "chooseMethodPageOver65Title": "Choose a method to get your Over 65 Proof", + "chooseMethodPageAgeRangeTitle": "Choose a method to get your Age Range Proof", + "chooseMethodPageVerifiableIdTitle": "Choose a method to get your Verifiable Id Proof", + "chooseMethodPageDefiComplianceTitle": "Choose a method to get your Defi Compliance Proof", "chooseMethodPageSubtitle": "Faites-vous vérifier en prenant une photo ou par une vérification de document .", - "idDocumentCheck": "Vérification des documents d'identité + Photo en temps réel", - "idDocumentCheckDescription": "Faites-vous vérifier en utilisant une carte d'identité ou un passeport.", - "realTimePhoto": "Photo selfie", - "realTimePhotoDescription": "Faites-vous vérifier en prenant un selfie.", + "kycTitle": "Quick photo of you (1min)", + "kycSubtitle": "Get instantly verified by taking a photo of yourself.", + "passbaseTitle": "Full ID document check", + "passbaseSubtitle": "Get verified with an ID card, passport or driving license.", "verifyYourAge": "Vérifiez votre âge", "verifyYourAgeSubtitle": "Ce processus de vérification de l'âge est très simple. Il suffit d'une photo selfie.", "verifyYourAgeDescription": "En acceptant, vous acceptez que nous utilisions votre photo pour estimer votre âge. L'estimation est effectuée par notre partenaire Yoti qui utilise votre photo uniquement à cette fin et la supprime immédiatement après. Pour plus d'informations, consultez notre Politique de confidentialité.", "accept": "Accepter", "decline": "Refuser", - "placeYourFaceInTheOval": "Placez votre visage le plus proche possible", + "yotiCameraAppbarTitle": "Please, position your face in the center", "cameraSubtitle": "Vous avez 5 secondes pour prendre votre photo. Assurez-vous qu'il y a suffisamment de lumière avant de commencer.", - "todoImportant": "TODO(all): mettre à jour le texte des clés ci-dessous", - "soonCardDescription": "Cette carte n'est pas encore prête. C'est pourquoi il y a une étiquette \"Bientôt \" dessus. Nous travaillons dur pour la mettre en ligne dès que possible. Restez à l'écoute !", - "bunnyPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", - "bunnyPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "bunnyPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", - "dogamiPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", - "dogamiPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "dogamiPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", - "matterlightPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", - "matterlightPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "matterlightPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", - "pigsPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", - "pigsPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "pigsPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", - "trooperzPassWhyGetThisCard": "Cette carte de membre vous donnera 25 % de remise en argent sur TOUTES les transactions du jeu Tezotopia lorsque vous achetez un Drops sur le marché ou frappez un NFT sur starbase.", - "trooperzPassExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", - "trooperzPassHowToGetIt": "Vous devez présenter une preuve de nationalité et une preuve de tranche d'âge. Obtenez-les en suivant la vérification KYC d'Altme.", - "walletSecurity": "Sécurité du portefeuille", + "todoImportant": "TODO(all): update the text of below keys","walletSecurity": "Wallet Security", "walletSecurityDescription": "Protégez votre portefeuille avec le code PIN et l'authentification biométrique", "blockchainSettings": "Paramètres de la blockchain", "blockchainSettingsDescription": "Gérer vos comptes, votre phrase de récupération, et les dApps", @@ -699,6 +703,7 @@ "resetWallet": "Réinitialiser le portefeuille", "resetWalletDescription": "Effacez toutes les données stockées sur votre téléphone et réinitialisez le portefeuille Altme.", "showWalletRecoveryPhrase": "Afficher la phrase de récupération du portefeuille", + "showWalletRecoveryPhraseSubtitle": "The recovery phrase acts as a backup key to restore access to a your wallet.", "blockchainNetwork": "Réseau Blockchain (par défaut)", "contactUs": "Contactez-nous", "officialWebsite": "Site officiel", @@ -741,6 +746,7 @@ "accountImportCongratulations": "Votre compte a été importé avec succès.", "saveBackupCredentialTitle": "Téléchargez le fichier de sauvegarde. Conservez-le en lieu sûr.", "saveBackupCredentialSubtitle": "Pour récupérer tous vos justificatifs numériques, vous aurez besoin de votre phrase de récupération ET de ce fichier de sauvegarde.", + "saveBackupPolygonCredentialSubtitle": "To recover all your polygon id credentials you will need the Recovery Phrase AND this backup file.", "restoreCredentialStep1Title": "Etape 1 : Entrez vos 12 mots de phrase de récupération", "restorePhraseTextFieldHint": "Entrez votre phrase de récupération (ou phrase mnémonique) ici...", "restoreCredentialStep2Title": "Etape 2 : Téléchargez votre fichier de sauvegarde contenant vos justificatifs numériques", @@ -780,11 +786,258 @@ "scanAndDisplay": "Numériser et afficher", "whatsNew": "Nouveautés", "okGotIt": "Ok, compris !", + "support": "support", "transactionDoneDialogDescription": "Cela peut prendre quelques minutes", "withdrawalFailedMessage": "Le retrait a échoué", "credentialRequiredMessage": "Vous devez d'abord posséder ces justificatifs pour acquérir cette carte :", - "needStoragePermission": "Désolé, vous avez besoin d'une autorisation de stockage pour télécharger ce fichier.", - "proceed": "Continue", - "import": "Importer", - "community": "Communauté" + "keyDecentralizedIdEdSA": "Key Decentralized ID EdDSA", + "keyDecentralizedIDSecp256k1": "Key Decentralized ID Secp256k1", + "polygonIdDecentralizedId": "Polygon Decentralized ID", + "ebsiV3DecentralizedId": "EBSI V3 Decentralized ID", + "requiredCredentialNotFoundTitle": "We are unable to find the credential\nyou need in your wallet.", + "requiredCredentialNotFoundSubTitle": "The required credential is not in your wallet", + "requiredCredentialNotFoundDescription": "Please contact us on :", + "backToHome": "Back to home", + "help": "Help", + "searchCredentials": "Search credentials", + "supportChatWelcomeMessage": "Welcome to our chat support! We're here to assist you with any questions or concerns you may have about our wallet.", + "cardChatWelcomeMessage": "Welcome to our chat support! We're here to assist you with any questions or concerns.", + "creator": "Creator", + "contractAddress": "Contract address", + "lastMetadataSync": "Last metadata sync", + "e2eEncyptedChat": "Chat is encrypted from end to end.", + "pincodeAttemptMessage": "You have entered an incorrect PIN code three times. For security reasons, please wait for one minute before trying again.", + "verifyNow": "Verify Now", + "verifyLater": "Verify Later", + "welDone": "Well done!", + "mnemonicsVerifiedMessage": "Your revovery phrase is saved correctly.", + "chatWith": "Chat with", + "sendAnEmail": "Send an email", + "livenessCardHowToGetIt": "It's easy! Complete a one-time KYC check in Altme wallet (powered by ID360) and request a Liveness credential.", + "livenessCardExpirationDate": "This credential will remain active for 1 year. Renewal is straightforward.", + "livenessCardWhyGetThisCard": "Obtain verifiable proof of humanity, requested by most DeFi, GameFi protocols and Web3 dApps. Once obtained, you can mint a privacy-preserving, non-transferable NFT for on-chain verification without revealing personal data.", + "livenessCardLongDescription": "This credential is a verifiable proof of humanity. Use it to prove you are not a bot when requested by DeFi protocols, Onchain games or Web3 dApps.", + "chat": "Chat", + "polygonDecentralizedID": "Polygon Decentralized ID", + "needMnemonicVerificatinoDescription": "You need to verify your wallet seed phrases to protect your assets!", + "succesfullyAuthenticated": "Successfully Authenticated.", + "authenticationFailed": "Authentication Failed.", + "documentType": "Document Type", + "countryCode": "Country Code", + "deviceIncompatibilityMessage": "Sorry, your device is not compatible for this feature.", + "tezosProofMessage": "", + "ethereumProofMessage": "", + "fantomProofMessage": "", + "polygonProofMessage": "", + "binanceProofMessage": "", + "yearsOld": "years old", + "youAreOver13": "You are over 13 years old", + "youAreOver15": "You are over 15 years old", + "youAreOver18": "You are over 18 years old", + "youAreOver21": "You are over 21 years old", + "youAreOver50": "You are over 50 years old", + "youAreOver65": "You are over 65 years old", + "polygon": "Polygon", + "ebsi": "EBSI", + "backupPolygonIdIdentity": "Backup PolygonId Identity", + "restorePolygonIdCredentials": "Restore PolygonId Credentials", + "comingSoon": "Coming Soon", + "financeCredentialsHomeTitle": "My financial credentials", + "financeCredentialsDiscoverTitle": "Get verified financial credentials", + "financeCredentialsDiscoverSubtitle": "Access new investment opportunities in web3.", + "financeCredentialsHomeSubtitle": "Access new investment opportunities in web3", + "hummanityProofCredentialsHomeTitle": "My proof of humanity", + "hummanityProofCredentialsHomeSubtitle": "Easily prove you are a human and not a bot.", + "hummanityProofCredentialsDiscoverTitle": "Prove you are not a bot or AI", + "hummanityProofCredentialsDiscoverSubtitle": "Get a reusable proof of humanity to share", + "socialMediaCredentialsHomeTitle": "My social media accounts", + "socialMediaCredentialsHomeSubtitle": "Prove your accounts ownership instantly Proof of humanity", + "socialMediaCredentialsDiscoverTitle": "Verify your social media accounts", + "socialMediaCredentialsDiscoverSubtitle": "Prove your accounts ownership when required", + "walletIntegrityCredentialsHomeTitle": "Wallet integrity", + "walletIntegrityCredentialsHomeSubtitle": "TBD", + "walletIntegrityCredentialsDiscoverTitle": "WAllet integrity", + "walletIntegrityCredentialsDiscoverSubtitle": "TBD", + "polygonCredentialsHomeTitle": "My PolygonID credentials", + "polygonCredentialsHomeSubtitle": "Prove your access rights in the Polygon ecosystem", + "polygonCredentialsDiscoverTitle": "Get PolygonID credentials", + "polygonCredentialsDiscoverSubtitle": "Prove your access rights in the Polygon ecosystem", + "pendingCredentialsHomeTitle": "My Pending credentials", + "pendingCredentialsHomeSubtitle": "Prove your access rights.", + "restore": "Restore", + "backup": "Backup", + "takePicture": "Take a picture", + "kyc": "KYC", + "aiSystemWasNotAbleToEstimateYourAge": "AI system was not able to estimate your age", + "youGotAgeCredentials": "You got your {credential} credential.", + "@youGotAgeCredentials": { + "description": "the description for the getting credentials", + "placeholders": { + "credential": {} + } + }, + "yourAgeEstimationIs": "Your AI age estimation is {ageEstimate} years", + "@yourAgeEstimationIs": { + "description": "", + "placeholders": { + "ageEstimate": {} + } + }, + "credentialNotFound": "Credential Not Found", + "cryptographicProof": "Cryptographic Proof", + "downloadingCircuitLoadingMessage": "Downloading circuits. It may take some time. Please wait.", + "cryptoAccountAlreadyExistMessage": "It appears that an account with this crypto information already exists", + "errorGeneratingProof": "Error Generating Proof", + "createWalletMessage": "Please create your wallet first.", + "successfullyGeneratingProof": "Successfully Generated Proof", + "wouldYouLikeToAcceptThisCredentialsFromThisOrganisation": "Would you like to accept this credential(s) from this organisation?", + "thisOrganisationRequestsThisInformation": "This organisation requests this information", + "iS": "is", + "isSmallerThan": "is smaller than", + "isBiggerThan": "is bigger than", + "isOneOfTheFollowingValues": "is one of the following values", + "isNotOneOfTheFollowingValues": "is not one of the following values", + "isNot": "is not", + "approve": "Approve", + "noInformationWillBeSharedFromThisCredentialMessage": "No information will be shared from this credential (Zero Knowledge Proof).", + "burn": "Burn", + "wouldYouLikeToConfirmThatYouIntendToBurnThisNFT": "Do you really want to burn this NFT ?", + "pleaseAddXtoConnectToTheDapp": "Please add {chain} account to connect to the dapp.", + "@pleaseAddXtoConnectToTheDapp": { + "description": "", + "placeholders": { + "chain": {} + } + }, + "pleaseSwitchPolygonNetwork": "Please switch to polygon {networkType} to perform this action.", + "@pleaseSwitchPolygonNetwork": { + "description": "", + "placeholders": { + "networkType": {} + } + }, + "oidc4vcProfile": "OIDC4VC Profile", + "pleaseSwitchToCorrectOIDC4VCProfile": "Please switch to correct OIDC4VC profile.", + "authenticationSuccess": "Authentication Success", + "format": "Format", + "pleaseInsertTheSecredCodeReceived": "Please insert the secret code received.", + "verifyIssuerWebsiteIdentity": "Verify issuer website identity", + "verifyIssuerWebsiteIdentitySubtitle": "Default: Off\nEnable to verify website identity before access.", + "developerMode": "Developer Mode", + "developerModeSubtitle": "Enable developer mode to access advanced debugging tools", + "confirmVerifierAccess": "Confirm verifier access", + "confirmVerifierAccessSubtitle": "Default: On\nDisable to skip confirmation when you share your verifiable credentials.", + "credentialManifestSupport": "Credential Manifest Support", + "credentialManifestSupportSubtitle": "Default: Off\nUse DIF Wallet Rendering syntax instead of the 'display' attribute.", + "secureAuthenticationWithPINCode": "Secure Authentication with PIN Code", + "secureAuthenticationWithPINCodeSubtitle": "Default: On\nTurn off to skip PIN code for website authentication (not recommended).", + "youcanSelectOnlyXCredential": "You can select only {count} credential(s).", + "@youcanSelectOnlyXCredential": { + "description": "", + "placeholders": { + "count": {} + } + }, + "theCredentialIsNotReady": "The credential is not ready.", + "theCredentialIsNoMoreReady": "The ceredential is no more available.", + "lowSecurity": "Low Security", + "highSecurity": "High Security", + "theRequestIsRejected": "The request is rejected.", + "userPinIsIncorrect": "User pin is incorrect", + "security_level": "Security Level", + "oidc4vc_settings": "OIDC4VC Settings", + "userPinTitle": "User PIN Digits pre-authorized_code Flow", + "userPinSubtitle": "Default: 6 digits\nEnable to manage 4 digits PIN code", + "securityLevelTitle": "Wallet Level", + "securityLevelSubTitle": "Default: Permissive\nSet to Strict to strengthen controls for issuers and verifiers", + "responseTypeNotSupported": "The response type is not supported", + "invalidRequest": "The request is invalid", + "subjectSyntaxTypeNotSupported": "The subject syntax type is not supported.", + "accessDenied": "Access denied", + "thisRequestIsNotSupported": "This request is not supported", + "unsupportedCredential": "Unsupported credential", + "aloginIsRequired": "A login is required", + "userConsentIsRequired": "User consent is required", + "theWalletIsNotRegistered": "The wallet is not registered", + "credentialIssuanceDenied": "Credential issuance denied", + "thisCredentialFormatIsNotSupported": "This credential format is not supported", + "thisFormatIsNotSupported": "This format is not supported", + "moreDetails": "More Details", + "theCredentialOfferIsInvalid": "The credential offer is invalid", + "dateOfRequest": "Date of Request", + "keyDecentralizedIDP256": "Key Decentralized ID P-256", + "jwkDecentralizedIDP256": "JWK Decentralized ID P-256", + "defaultDid": "Default DID", + "selectOneOfTheDid": "Select one of the DIDs", + "clientTypeTitle": "OIDC4VCI Client Type", + "clientTypeSubtitle": "Default: DID\nSwitch to change the client type", + "cryptographicHolderBinding": "Cryptographic Holder Binding", + "cryptographicHolderBindingSubtitle": "Default : On\nDisable cryptographic binding for claim based binding credentials.", + "scopeParameters": "Scope Parameters", + "scopeParametersSubtitle": "Default : Off\nEnable to force wallet to use scope instead of authorization_details.", + "clientAuthenticationMethods": "Client Authentication Methods", + "clientAuthenticationMethodsSubtitle": "Default: Client id as DID or JWK\nSelect to other authentication methods if needed.", + "vcFormatType": "VC Format", + "vcFormatTypeSubtitle": "Default: ldp_vc\nSelect one of the VC formats.", + "proofHeader": "OIDC4VCI Jwt Proof Type", + "proofHeaderSubtitle": "Default: kid\nSwitch if jwk is needed in header.", + "theServiceIsNotAvailable": "The service is not available", + "issuerDID": "Issuer DID", + "subjectDID": "Subject DID", + "type": "Type", + "credentialExpired": "Credential Expired", + "incorrectSignature": "Incorrect Signature", + "revokedOrSuspendedCredential": "Revoked or Suspended Credential", + "display": "Display", + "download": "Download", + "successfullyDownloaded": "Successfully Downloaded", + "advancedSecuritySettings": "Advanced Security Settings", + "clientMetadata": "Wallet metadata", + "theIssuanceOfThisCredentialIsPending": "The issuance of this credential is pending", + "clientId": "Client Id", + "clientSecret": "Client Secret", + "walletProfiles": "Wallet Profiles", + "walletProfilesDescription": "Choose your SSI profile or customize your own", + "profileCustom": "Custom", + "profileEbsiV3": "European Blockchain Services Infrastructure", + "decentralizedIdentityInteropProfile": "Decentralized Identity Interop Profile", + "protectYourWallet": "Protect your wallet", + "protectYourWalletMessage": "Use your fingerprint, face, or device PIN to secure and unlock your wallet. Your data is securely encrypted on this device.", + "pinUnlock": "PIN unlock", + "secureWithDevicePINOnly": "Secure with Device PIN only", + "biometricUnlock": "Biometric unlock", + "secureWithFingerprint": "Secure with Fingerprint", + "pinUnlockAndBiometric2FA": "PIN unlock + Biometric (2FA)", + "secureWithFingerprintAndPINBackup": "Secure with Fingerprint + PIN backup", + "secureYourWalletWithPINCodeAndBiometrics": "Secure your wallet with PIN code and Biometrics", + "twoFactorAuthenticationHasBeenEnabled": "Two factor authentication has been enabled.", + "createAnProfessionalWallet": "Create Enterprise Wallet", + "initialization": "Initialization", + "login": "Login", + "password": "Password", + "pleaseEnterYourEmailAndYourCompanyPasswordToCreateYourAccount": "Please enter your email and your company password to create your account", + "enterTheSecurityCodeThatWeSentYouByEmail": "Enter the security code that we sent you by email", + "enterTheSecurityCode": "Enter the security code", + "yourEmail": "Your email", + "publicKeyOfWalletInstance": "Public Key of Wallet Instance", + "walletInstanceKey": "Wallet Instance Key", + "protocoleStandardRelease": "Protocole standard release", + "organizationProfile": "Organization Profile", + "profileName": "Profile Name", + "companyName": "Company Name", + "configFileIdentifier": "Config file identifier", + "clientCredentials": "Client Credentials", + "updateYourWalletConfigNow": "Update your wallet config now", + "updateConfigurationNow": "Update configuration now", + "pleaseEnterYourEmailAndPasswordToUpdateYourOrganizationWalletConfiguration": "Please enter your email and password to update your organization wallet configuration", + "congrats": "Congrats !", + "yourWalletConfigurationHasBeenSuccessfullyUpdated": "Your wallet configuration has been successfully updated", + "continueString": "Continue", + "walletProvider": "Wallet Provider", + "theLdpFormatIsNotSupportedByThisDIDMethod": "The ldp_format is not supported by this DID method.", + "switchOffCryptoHolderBindingForThatDIDMethod": "Switch off Crypto Holder Binding for that DID Method.", + "thisTypeProofCannotBeUsedWithThisVCFormat": "This type proof cannot be used with this VC Format.", + "enterprise": "Enterprise", + "oWFBaselineProfile": "OWF Baseline Profile", + "defaultProfile":"Default" } From 9830e29f9930dbaab5ac9a59a051ed719adf713f Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Thu, 15 Feb 2024 11:01:17 +0000 Subject: [PATCH 51/70] update french arb merge --- lib/l10n/arb/app_fr.arb | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index 6608ad56e..fac41546d 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -164,7 +164,7 @@ "credential": "informations d'identification", "issuanceDate": "Date d'émission", "appContactWebsite": "Site web", - "chooseIssuerRegistryDescription": "Un registre d'émetteurs ou de vérificateurs est un stockage en ligne contenant des informations sur les émetteurs et les vérificateurs de confiance. Selon l'écosystème, ces informations sont stockées sur une chaîne ou sur des serveurs.", + "trustFrameworkDescription": "The trust framework is formed by a set of registries that provide a secure and reliable basis for entities within the system to trust and interact with each other.", "confimrDIDAuth": "Voulez-vous vous connecter au site ?", "evidenceLabel": "Preuve", "networkErrorBadRequest": "Mauvaise requête", @@ -200,8 +200,8 @@ "backupCredentialPhrase": "Écrivez ces mots, téléchargez le fichier de sauvegarde et conservez-les en lieu sûr", "backupCredentialPhraseExplanation": "Pour sauvegarder vos informations d'identification, notez votre phrase de récupération et conservez-la en lieu sûr.", "backupCredentialButtonTitle": "Enregistrer le fichier", - "backupCredentialEmptyError": "Vous n'avez aucun identifiant dans votre portefeuille.", - "backupCredentialPermissionDeniedMessage": "Vous avez besoin d'une autorisation pour télécharger ce fichier.", + "backupPolygonIdCredentialEmptyError": "You do not have any polygon id credential in your wallet.", + "needStoragePermission": "Sorry, You need storage permission to download this file.", "backupCredentialNotificationTitle": "Succès", "backupCredentialNotificationMessage": "Le fichier a été téléchargé avec succès. Appuyez pour ouvrir le fichier.", "backupCredentialError": "Une erreur s'est produite. Veuillez réessayer plus tard.", @@ -237,7 +237,7 @@ "anUnknownErrorHappened": "Une erreur inconnue s'est produite", "walletType": "Type de portefeuille", "chooseYourWalletType": "Choisissez votre type de portefeuille", - "continuer": "Continuer", + "proceed": "Continuer", "enterpriseWallet": "Portefeuille d'entreprise", "personalWallet": "Portefeuille personnel", "failedToVerifySelfIssuedCredential": "Échec de la vérification de l'identifiant émis", @@ -288,14 +288,14 @@ "generate": "générer", "myAssets": "Mes actifs", "search": "Rechercher", - "splashTitle": "Altme Wallet", + "professional": "Professional", "splashSubtitle": "Prenez le contrôle de vos données", "poweredBy": "Powered By", "splashLoading": "Chargement...", "version": "Version", "cards": "Cartes", "nfts": "NFTs", - "tokens": "Coins", + "coins": "Coins", "getCards": "Obtenir", "close": "Fermer", "profile": "Profil", @@ -305,10 +305,9 @@ "enterNewPinCode": "Créez un code PIN pour protéger votre portefeuille", "confirmYourPinCode": "Confirmez votre code PIN", "walletAltme": "Portefeuille Altme", + "createPersonalWallet": "Create Personal Wallet", "createTitle": "Créez ou importez votre adresse de portefeuille", "createSubtitle": "Altme n'a jamais accès à vos fonds ou à votre phase de récupération. Rien ne sort de votre téléphone.", - "create_wallet": "Créer un portefeuille", - "import_wallet": "Importer un portefeuille", "enterYourPinCode": "Entrez votre code PIN", "changePinCode": "Modifier le code PIN", "tryAgain": "Réessayez", @@ -347,7 +346,7 @@ "networkAndRegistries": "Réseau et registres", "chooseNetwork": "Choisir un réseau", "chooseRegistry": "Choisir le registre", - "chooseIssuersRegistry": "Choisir le registre des émetteurs", + "trustFramework": "Trust Framework", "network": "Réseau", "issuerRegistry": "Registre des émetteurs", "about": "À propos", @@ -386,14 +385,14 @@ "onbordingSeedPhrase": "Phrase de départ", "onboardingPleaseStoreMessage": "Veuillez noter votre phrase de récupération", "onboardingVerifyPhraseMessage": "Confirm Recovery Words", + "onboardingVerifyPhraseMessageDetails": "To ensure your Recovery Phrase is written correctly, select the words in correct order.", "onboardingAltmeMessage": "Altme n'est pas dépositaire. Votre phrase de récupération est le seul moyen de récupérer votre compte.", - "onboardingAltmeMessage": "The wallet is non-custodial. Your Recovery Phrase is the only way to recover your account.", "onboardingWroteDownMessage": "J'ai écrit ma phrase de récupération", "copyToClipboard": "Copier dans le presse-papiers", "pinCodeMessage": "Le code PIN empêche l'accès non autorisé à votre portefeuille Altme. Vous pouvez le modifier à tout moment.", "enterNameForYourNewAccount": "Entrez un nom pour votre nouveau compte", "create": "Créer", - "importer": "Importer", + "import": "Importer", "accountName": "Nom du compte", "importWalletText": "Entrez ici votre phrase de récupération ou votre clé privée.", "importWalletTextRecoveryPhraseOnly": "Enter your recovery phrase here.", @@ -541,7 +540,7 @@ "advanceSettings": "Paramètres avancés", "categories": "Catégories", "selectCredentialCategoryWhichYouWantToShowInCredentialList": "Sélectionnez les types de justificatifs numériques que vous souhaitez afficher dans la liste :", - "communauté": "Communauté", + "community": "Communauté", "tezos": "Tezos", "rights": "Droits", "disconnectAndRevokeRights": "Déconnecter et révoquer les droits", @@ -558,8 +557,8 @@ "receiveNft": "Recevoir NFT", "sendOnlyNftToThisAddressDescription": "Envoyez uniquement des NFTs Tezos à cette adresse. L'envoi de NFT depuis un autre réseau peut entraîner une perte permanente.", "beaconShareMessage": "Envoyez uniquement des tokens et NFTs Tezos (FA2 Standard) à cette adresse. L'envoi de Tezos et de NFT depuis d'autres réseaux peut entraîner une perte permanente", - "gamingCredentialHomeSubtitle": "Bénéficiez d'avantages offerts par les jeux Web3.", - "gamingCredentialDiscoverSubtitle": "Bénéficiez d'avantages offerts par les jeux Web3.", + "advantagesCredentialHomeSubtitle": "Bénéficiez d'avantages offerts par les jeux Web3.", + "advantagesCredentialDiscoverSubtitle": "Bénéficiez d'avantages offerts par les jeux Web3.", "identityCredentialHomeSubtitle": "Prouvez qui vous êtes tout en protégeant vos données.", "identityCredentialDiscoverSubtitle": "Prouvez qui vous êtes tout en protégeant vos données.", "myProfessionalCredentialDiscoverSubtitle": "Utilisez vos justifs professionnels en toute sécurité.", @@ -609,11 +608,11 @@ "over18ExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", "over18HowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", "over13WhyGetThisCard": "Ce justificatif peut être exigé par certaines Applications / Sites Web du Web 3 pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", - "over13ExpirationDate": "This card will remain active and reusable for 1 YEAR.", - "over13HowToGetIt": "You can claim this card by following Altme’s KYC check.", - "over15WhyGetThisCard": "This proof may be required by some Web 3 Apps / Websites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", "over13ExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", "over13HowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", + "over15WhyGetThisCard": "This proof may be required by some Web 3 Apps / Websites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", + "over15ExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", + "over15HowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", "passportFootprintWhyGetThisCard": "Ce justificatif peut être exigé par certaines Web 3 Apps / Sites Internet pour accéder à leur service ou obtenir des avantages : Carte de membre, Carte de fidélité, Rewards, etc.", "passportFootprintExpirationDate": "Cette carte restera active et réutilisable pendant 1 AN.", "passportFootprintHowToGetIt": "Vous pouvez obtenir cette carte en suivant la vérification KYC d'Altme.", @@ -754,7 +753,7 @@ "uploadFile": "Télécharger le fichier", "creators": "Créateurs", "publishers": "Éditeurs", - "createDate": "Créer une date", + "creationDate": "Créer une date", "myProfessionalrCards": "Justificatifs professionnelles", "myProfessionalrCardsSubtitle": "Utilisez vos justificatifs professionnelles facilement.", "guardaWallet": "Portefeuille Guarda", From ce44e9d7bf6bfc3916f68f579ef405c284b990f6 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 15 Feb 2024 16:49:37 +0545 Subject: [PATCH 52/70] Draft 13 , authorization code flow fails with authorization_details #2387 --- packages/oidc4vc/lib/src/oidc4vc.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index beade19c7..b3ca344aa 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -260,9 +260,7 @@ class OIDC4VC { data = { 'type': 'openid_credential', - 'locations': [issuer], - 'format': credentialSupported['format'], - //'types': credential['types'], + 'credential_configuration_id': credential, }; final scope = credentialSupported['scope']; From 411a4c067e4bf824fc0c3c30f92bce6a6473b7e8 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 15 Feb 2024 18:14:49 +0545 Subject: [PATCH 53/70] OIDC4VP test 8 presentation submission is not correct #2390 --- lib/scan/cubit/scan_cubit.dart | 35 +++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/scan/cubit/scan_cubit.dart b/lib/scan/cubit/scan_cubit.dart index 1931048d6..08c3c506a 100644 --- a/lib/scan/cubit/scan_cubit.dart +++ b/lib/scan/cubit/scan_cubit.dart @@ -719,29 +719,42 @@ class ScanCubit extends Cubit { filterList: filterList, credentialList: [credentialsToBePresented[i]], ); + + final pathNested = { + 'id': inputDescriptor.id, + 'format': vcFormat, + }; + if (credential.isNotEmpty) { if (credentialsToBePresented.length == 1) { + if (vpFormat == 'ldp_vp') { + pathNested['path'] = r'$.verifiableCredential'; + } else { + pathNested['path'] = r'$.vp.verifiableCredential[0]'; + } + inputDescriptors.add({ 'id': inputDescriptor.id, 'format': vpFormat, 'path': r'$', - 'path_nested': { - 'id': inputDescriptor.id, - 'format': vcFormat, - 'path': r'$.verifiableCredential', - }, + 'path_nested': pathNested, }); } else { + if (vpFormat == 'ldp_vp') { + pathNested['path'] = + // ignore: prefer_interpolation_to_compose_strings + r'$.verifiableCredential[' + i.toString() + ']'; + } else { + pathNested['path'] = + // ignore: prefer_interpolation_to_compose_strings + r'$.vp.verifiableCredential[' + i.toString() + ']'; + } + inputDescriptors.add({ 'id': inputDescriptor.id, 'format': vpFormat, 'path': r'$', - 'path_nested': { - 'id': inputDescriptor.id, - 'format': vcFormat, - // ignore: prefer_interpolation_to_compose_strings - 'path': r'$.verifiableCredential[' + i.toString() + ']', - }, + 'path_nested': pathNested, }); } } From 394037e6825e3c241dadce15193715d89b3187ac Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 15 Feb 2024 18:43:46 +0545 Subject: [PATCH 54/70] version update to 2.2.25+387 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 2d76addc7..0fb6a7859 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.24+386 +version: 2.2.25+387 environment: sdk: ">=3.1.0 <4.0.0" From 399c6771eb58ef9e43387635237801129a127c51 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 16 Feb 2024 13:49:05 +0545 Subject: [PATCH 55/70] Update Default value for Custom profile #2414 --- lib/app/shared/constants/parameters.dart | 2 +- lib/dashboard/profile/models/profile.dart | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/app/shared/constants/parameters.dart b/lib/app/shared/constants/parameters.dart index e48f5107f..658130af2 100644 --- a/lib/app/shared/constants/parameters.dart +++ b/lib/app/shared/constants/parameters.dart @@ -70,7 +70,7 @@ class Parameters { static const String appName = 'Altme'; static const DidKeyType didKeyTypeForEbsiV3 = DidKeyType.ebsiv3; - static const DidKeyType didKeyTypeForDefault = DidKeyType.edDSA; + static const DidKeyType didKeyTypeForDefault = DidKeyType.p256; static const DidKeyType didKeyTypeForDutch = DidKeyType.jwkP256; static const DidKeyType didKeyTypeForOwfBaselineProfile = DidKeyType.jwkP256; } diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index cb36a8122..4d92ae762 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -101,19 +101,19 @@ class ProfileModel extends Equatable { displayManageDecentralizedId: true, customOidc4vcProfile: CustomOidc4VcProfile( clientAuthentication: ClientAuthentication.clientId, - credentialManifestSupport: true, + credentialManifestSupport: false, cryptoHolderBinding: true, defaultDid: Parameters.didKeyTypeForDefault, oidc4vciDraft: OIDC4VCIDraftType.draft11, oidc4vpDraft: OIDC4VPDraftType.draft18, scope: false, securityLevel: false, - proofHeader: ProofHeaderType.kid, // N/A + proofHeader: ProofHeaderType.kid, siopv2Draft: SIOPV2DraftType.draft12, clientType: ClientType.did, clientId: clientId, clientSecret: clientSecret, - vcFormatType: VCFormatType.ldpVc, + vcFormatType: VCFormatType.jwtVcJson, ), ), settingsMenu: SettingsMenu.initial(), From 5ac85c80e2d50a8646fa21b57506bceb221680ab Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 16 Feb 2024 13:55:38 +0545 Subject: [PATCH 56/70] Wording switch OIDC4VCI Jwt Proof Type #2413 --- lib/l10n/arb/app_en.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 69f869434..0759df04a 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -978,7 +978,7 @@ "clientAuthenticationMethodsSubtitle": "Default: Client id as DID or JWK\nSelect to other authentication methods if needed.", "vcFormatType": "VC Format", "vcFormatTypeSubtitle": "Default: ldp_vc\nSelect one of the VC formats.", - "proofHeader": "OIDC4VCI Jwt Proof Type", + "proofHeader": "Proof of Possession Header", "proofHeaderSubtitle": "Default: kid\nSwitch if jwk is needed in header.", "theServiceIsNotAvailable": "The service is not available", "issuerDID": "Issuer DID", From dad0f5df315b1d5106b6a04bc9353573af710e5e Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 16 Feb 2024 14:23:56 +0545 Subject: [PATCH 57/70] Claims not shown correctly #2408 #2412 --- .../tab_bar/credentials/detail/widgets/claims_data.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart index 54f015d5f..7c613ed43 100644 --- a/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart +++ b/lib/dashboard/home/tab_bar/credentials/detail/widgets/claims_data.dart @@ -32,9 +32,14 @@ class ClaimsData extends StatelessWidget { if (encryptedDatas != null) { encryptedDatas.removeAt(0); - for (final element in encryptedDatas) { + for (var element in encryptedDatas) { try { + while (element.length % 4 != 0) { + element += '='; + } + final decryptedData = utf8.decode(base64Decode(element)); + if (decryptedData.isNotEmpty) { final lisString = decryptedData .substring(1, decryptedData.length - 1) From 55fbf47e4ea56cf0afbda4b22036cdf980d3565a Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 16 Feb 2024 14:52:15 +0545 Subject: [PATCH 58/70] Bug fix custom profile #2400 --- lib/dashboard/profile/cubit/profile_cubit.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/dashboard/profile/cubit/profile_cubit.dart b/lib/dashboard/profile/cubit/profile_cubit.dart index 83b5d4f74..2209ebda8 100644 --- a/lib/dashboard/profile/cubit/profile_cubit.dart +++ b/lib/dashboard/profile/cubit/profile_cubit.dart @@ -480,12 +480,14 @@ class ProfileCubit extends Cubit { } Future setProfile(ProfileType profileType) async { - if (profileType != ProfileType.custom) { + final previousProfileType = state.model.profileType; + if (previousProfileType == ProfileType.custom) { await secureStorageProvider.set( SecureStorageKeys.customProfileSettings, jsonEncode(state.model.profileSetting.toJson()), ); } + switch (profileType) { case ProfileType.ebsiV3: await update( From 1f300d46b30bfd667715672a26b4271ca800d30d Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 16 Feb 2024 15:49:30 +0545 Subject: [PATCH 59/70] Good authorization endpoint for Authlete issuer #2409 --- packages/oidc4vc/lib/src/oidc4vc.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index b3ca344aa..f32d1a5b4 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -721,8 +721,12 @@ class OIDC4VC { }) async { var authorizationEndpoint = '$issuer/authorize'; - final authorizationServer = openIdConfiguration.authorizationServer; - if (authorizationServer != null) { + if (openIdConfiguration.authorizationEndpoint != null) { + authorizationEndpoint = openIdConfiguration.authorizationEndpoint!; + } else { + final authorizationServer = + openIdConfiguration.authorizationServer ?? issuer; + final authorizationServerConfiguration = await getOpenIdConfig( baseUrl: authorizationServer, isAuthorizationServer: true, @@ -733,10 +737,6 @@ class OIDC4VC { authorizationEndpoint = authorizationServerConfiguration.authorizationEndpoint!; } - } else { - if (openIdConfiguration.authorizationEndpoint != null) { - authorizationEndpoint = openIdConfiguration.authorizationEndpoint!; - } } return authorizationEndpoint; } From cfcad1b4919238c3d3f8966eace4009171ddfaf2 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Fri, 16 Feb 2024 18:50:00 +0545 Subject: [PATCH 60/70] Revert changes in default and implement change in custom #2414 --- lib/dashboard/profile/models/profile.dart | 6 +++--- lib/dashboard/profile/models/profile_setting.dart | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/dashboard/profile/models/profile.dart b/lib/dashboard/profile/models/profile.dart index 4d92ae762..cb36a8122 100644 --- a/lib/dashboard/profile/models/profile.dart +++ b/lib/dashboard/profile/models/profile.dart @@ -101,19 +101,19 @@ class ProfileModel extends Equatable { displayManageDecentralizedId: true, customOidc4vcProfile: CustomOidc4VcProfile( clientAuthentication: ClientAuthentication.clientId, - credentialManifestSupport: false, + credentialManifestSupport: true, cryptoHolderBinding: true, defaultDid: Parameters.didKeyTypeForDefault, oidc4vciDraft: OIDC4VCIDraftType.draft11, oidc4vpDraft: OIDC4VPDraftType.draft18, scope: false, securityLevel: false, - proofHeader: ProofHeaderType.kid, + proofHeader: ProofHeaderType.kid, // N/A siopv2Draft: SIOPV2DraftType.draft12, clientType: ClientType.did, clientId: clientId, clientSecret: clientSecret, - vcFormatType: VCFormatType.jwtVcJson, + vcFormatType: VCFormatType.ldpVc, ), ), settingsMenu: SettingsMenu.initial(), diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index ee63fea74..b2f51eb70 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -544,15 +544,15 @@ class CustomOidc4VcProfile extends Equatable { required this.clientType, required this.clientId, required this.clientSecret, - this.vcFormatType = VCFormatType.ldpVc, + this.vcFormatType = VCFormatType.jwtVcJson, this.proofHeader = ProofHeaderType.kid, }); factory CustomOidc4VcProfile.initial() => CustomOidc4VcProfile( clientAuthentication: ClientAuthentication.clientId, - credentialManifestSupport: true, + credentialManifestSupport: false, cryptoHolderBinding: true, - defaultDid: DidKeyType.edDSA, + defaultDid: DidKeyType.p256, oidc4vciDraft: OIDC4VCIDraftType.draft11, oidc4vpDraft: OIDC4VPDraftType.draft18, scope: false, @@ -562,7 +562,7 @@ class CustomOidc4VcProfile extends Equatable { clientType: ClientType.did, clientId: Parameters.clientId, clientSecret: randomString(12), - vcFormatType: VCFormatType.ldpVc, + vcFormatType: VCFormatType.jwtVcJson, ); factory CustomOidc4VcProfile.fromJson(Map json) => From c0707c17cb1515142aac362ec7c5d184be16e7c2 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Fri, 16 Feb 2024 17:36:18 +0000 Subject: [PATCH 61/70] version: 2.3.0+388 --- lib/l10n/untranslated.json | 272 ------------------------------------- pubspec.lock | 20 +-- pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 283 deletions(-) diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index 0cba527bd..0c29c8d49 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -1893,278 +1893,6 @@ "defaultProfile" ], - "fr": [ - "trustFrameworkDescription", - "backupPolygonIdCredentialEmptyError", - "professional", - "poweredBy", - "coins", - "createPersonalWallet", - "advantagesDiscoverCards", - "identityDiscoverCards", - "contactInfoDiscoverCredentials", - "educationCredentials", - "educationDiscoverCredentials", - "educationCredentialsDiscoverSubtitle", - "trustFramework", - "onboardingVerifyPhraseMessage", - "onboardingVerifyPhraseMessageDetails", - "importWalletTextRecoveryPhraseOnly", - "importWalletHintTextRecoveryPhraseOnly", - "amountSent", - "advantagesCredentialHomeSubtitle", - "advantagesCredentialDiscoverSubtitle", - "educationCredentialHomeSubtitle", - "financeCardsCredentialHomeSubtitle", - "financeCardsCredentialDiscoverSubtitle", - "contactInfoCredentialHomeSubtitle", - "contactInfoCredentialDiscoverSubtitle", - "website", - "tezotopiaMembershipLongDescription", - "chainbornMembershipLongDescription", - "over15WhyGetThisCard", - "over15ExpirationDate", - "over15HowToGetIt", - "defiComplianceWhyGetThisCard", - "defiComplianceExpirationDate", - "defiComplianceHowToGetIt", - "chooseMethodPageOver15Title", - "chooseMethodPageOver21Title", - "chooseMethodPageOver50Title", - "chooseMethodPageOver65Title", - "chooseMethodPageAgeRangeTitle", - "chooseMethodPageVerifiableIdTitle", - "chooseMethodPageDefiComplianceTitle", - "kycTitle", - "kycSubtitle", - "passbaseTitle", - "passbaseSubtitle", - "yotiCameraAppbarTitle", - "showWalletRecoveryPhraseSubtitle", - "saveBackupPolygonCredentialSubtitle", - "creationDate", - "support", - "keyDecentralizedIdEdSA", - "keyDecentralizedIDSecp256k1", - "polygonIdDecentralizedId", - "ebsiV3DecentralizedId", - "requiredCredentialNotFoundTitle", - "requiredCredentialNotFoundSubTitle", - "requiredCredentialNotFoundDescription", - "backToHome", - "help", - "searchCredentials", - "supportChatWelcomeMessage", - "cardChatWelcomeMessage", - "creator", - "contractAddress", - "lastMetadataSync", - "e2eEncyptedChat", - "pincodeAttemptMessage", - "verifyNow", - "verifyLater", - "welDone", - "mnemonicsVerifiedMessage", - "chatWith", - "sendAnEmail", - "livenessCardHowToGetIt", - "livenessCardExpirationDate", - "livenessCardWhyGetThisCard", - "livenessCardLongDescription", - "chat", - "polygonDecentralizedID", - "needMnemonicVerificatinoDescription", - "succesfullyAuthenticated", - "authenticationFailed", - "documentType", - "countryCode", - "deviceIncompatibilityMessage", - "tezosProofMessage", - "ethereumProofMessage", - "fantomProofMessage", - "polygonProofMessage", - "binanceProofMessage", - "yearsOld", - "youAreOver13", - "youAreOver15", - "youAreOver18", - "youAreOver21", - "youAreOver50", - "youAreOver65", - "polygon", - "ebsi", - "backupPolygonIdIdentity", - "restorePolygonIdCredentials", - "comingSoon", - "financeCredentialsHomeTitle", - "financeCredentialsDiscoverTitle", - "financeCredentialsDiscoverSubtitle", - "financeCredentialsHomeSubtitle", - "hummanityProofCredentialsHomeTitle", - "hummanityProofCredentialsHomeSubtitle", - "hummanityProofCredentialsDiscoverTitle", - "hummanityProofCredentialsDiscoverSubtitle", - "socialMediaCredentialsHomeTitle", - "socialMediaCredentialsHomeSubtitle", - "socialMediaCredentialsDiscoverTitle", - "socialMediaCredentialsDiscoverSubtitle", - "walletIntegrityCredentialsHomeTitle", - "walletIntegrityCredentialsHomeSubtitle", - "walletIntegrityCredentialsDiscoverTitle", - "walletIntegrityCredentialsDiscoverSubtitle", - "polygonCredentialsHomeTitle", - "polygonCredentialsHomeSubtitle", - "polygonCredentialsDiscoverTitle", - "polygonCredentialsDiscoverSubtitle", - "pendingCredentialsHomeTitle", - "pendingCredentialsHomeSubtitle", - "restore", - "backup", - "takePicture", - "kyc", - "aiSystemWasNotAbleToEstimateYourAge", - "youGotAgeCredentials", - "yourAgeEstimationIs", - "credentialNotFound", - "cryptographicProof", - "downloadingCircuitLoadingMessage", - "cryptoAccountAlreadyExistMessage", - "errorGeneratingProof", - "createWalletMessage", - "successfullyGeneratingProof", - "wouldYouLikeToAcceptThisCredentialsFromThisOrganisation", - "thisOrganisationRequestsThisInformation", - "iS", - "isSmallerThan", - "isBiggerThan", - "isOneOfTheFollowingValues", - "isNotOneOfTheFollowingValues", - "isNot", - "approve", - "noInformationWillBeSharedFromThisCredentialMessage", - "burn", - "wouldYouLikeToConfirmThatYouIntendToBurnThisNFT", - "pleaseAddXtoConnectToTheDapp", - "pleaseSwitchPolygonNetwork", - "oidc4vcProfile", - "pleaseSwitchToCorrectOIDC4VCProfile", - "authenticationSuccess", - "format", - "pleaseInsertTheSecredCodeReceived", - "verifyIssuerWebsiteIdentity", - "verifyIssuerWebsiteIdentitySubtitle", - "developerMode", - "developerModeSubtitle", - "confirmVerifierAccess", - "confirmVerifierAccessSubtitle", - "credentialManifestSupport", - "credentialManifestSupportSubtitle", - "secureAuthenticationWithPINCode", - "secureAuthenticationWithPINCodeSubtitle", - "youcanSelectOnlyXCredential", - "theCredentialIsNotReady", - "theCredentialIsNoMoreReady", - "lowSecurity", - "highSecurity", - "theRequestIsRejected", - "userPinIsIncorrect", - "security_level", - "oidc4vc_settings", - "userPinTitle", - "userPinSubtitle", - "securityLevelTitle", - "securityLevelSubTitle", - "responseTypeNotSupported", - "invalidRequest", - "subjectSyntaxTypeNotSupported", - "accessDenied", - "thisRequestIsNotSupported", - "unsupportedCredential", - "aloginIsRequired", - "userConsentIsRequired", - "theWalletIsNotRegistered", - "credentialIssuanceDenied", - "thisCredentialFormatIsNotSupported", - "thisFormatIsNotSupported", - "moreDetails", - "theCredentialOfferIsInvalid", - "dateOfRequest", - "keyDecentralizedIDP256", - "jwkDecentralizedIDP256", - "defaultDid", - "selectOneOfTheDid", - "clientTypeTitle", - "clientTypeSubtitle", - "cryptographicHolderBinding", - "cryptographicHolderBindingSubtitle", - "scopeParameters", - "scopeParametersSubtitle", - "clientAuthenticationMethods", - "clientAuthenticationMethodsSubtitle", - "vcFormatType", - "vcFormatTypeSubtitle", - "proofHeader", - "proofHeaderSubtitle", - "theServiceIsNotAvailable", - "issuerDID", - "subjectDID", - "type", - "credentialExpired", - "incorrectSignature", - "revokedOrSuspendedCredential", - "display", - "download", - "successfullyDownloaded", - "advancedSecuritySettings", - "clientMetadata", - "theIssuanceOfThisCredentialIsPending", - "clientId", - "clientSecret", - "walletProfiles", - "walletProfilesDescription", - "profileCustom", - "profileEbsiV3", - "decentralizedIdentityInteropProfile", - "protectYourWallet", - "protectYourWalletMessage", - "pinUnlock", - "secureWithDevicePINOnly", - "biometricUnlock", - "secureWithFingerprint", - "pinUnlockAndBiometric2FA", - "secureWithFingerprintAndPINBackup", - "secureYourWalletWithPINCodeAndBiometrics", - "twoFactorAuthenticationHasBeenEnabled", - "createAnProfessionalWallet", - "initialization", - "login", - "password", - "pleaseEnterYourEmailAndYourCompanyPasswordToCreateYourAccount", - "enterTheSecurityCodeThatWeSentYouByEmail", - "enterTheSecurityCode", - "yourEmail", - "publicKeyOfWalletInstance", - "walletInstanceKey", - "protocoleStandardRelease", - "organizationProfile", - "profileName", - "configFileIdentifier", - "clientCredentials", - "updateYourWalletConfigNow", - "updateConfigurationNow", - "pleaseEnterYourEmailAndPasswordToUpdateYourOrganizationWalletConfiguration", - "congrats", - "yourWalletConfigurationHasBeenSuccessfullyUpdated", - "continueString", - "walletProvider", - "theLdpFormatIsNotSupportedByThisDIDMethod", - "switchOffCryptoHolderBindingForThatDIDMethod", - "thisTypeProofCannotBeUsedWithThisVCFormat", - "enterprise", - "oWFBaselineProfile", - "defaultProfile" - ], - "it": [ "genericError", "credentialListTitle", diff --git a/pubspec.lock b/pubspec.lock index 8bd37bdf7..7ab3deb6d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -310,10 +310,10 @@ packages: dependency: transitive description: name: camera_avfoundation - sha256: "7d0763dfcbf060f56aa254a68c103210280bee9e97bbe4fdef23e257a4f70ab9" + sha256: "608b56b0880722f703871329c4d7d4c2f379c8e2936940851df7fc041abc6f51" url: "https://pub.dev" source: hosted - version: "0.9.14" + version: "0.9.13+10" camera_platform_interface: dependency: transitive description: @@ -1421,10 +1421,10 @@ packages: dependency: transitive description: name: local_auth_ios - sha256: "6dde47dc852bc0c8343cb58e66a46efb16b62eddf389ce103d4dacb0c6c40c71" + sha256: eb283b530029b334698918f1e282d4483737cbca972ff21b9193be3d6de8e2b8 url: "https://pub.dev" source: hosted - version: "1.1.7" + version: "1.1.6" local_auth_platform_interface: dependency: transitive description: @@ -2593,10 +2593,10 @@ packages: dependency: "direct main" description: name: webview_flutter - sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932" + sha256: d81b68e88cc353e546afb93fb38958e3717282c5ac6e5d3be4a4aef9fc3c1413 url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.5.0" webview_flutter_android: dependency: "direct main" description: @@ -2617,10 +2617,10 @@ packages: dependency: "direct main" description: name: webview_flutter_wkwebview - sha256: "9bf168bccdf179ce90450b5f37e36fe263f591c9338828d6bf09b6f8d0f57f86" + sha256: "4d062ad505390ecef1c4bfb6001cd857a51e00912cc9dfb66edb1886a9ebd80c" url: "https://pub.dev" source: hosted - version: "3.12.0" + version: "3.10.2" win32: dependency: transitive description: @@ -2686,5 +2686,5 @@ packages: source: hosted version: "2.1.1" sdks: - dart: ">=3.2.3 <4.0.0" - flutter: ">=3.16.6" + dart: ">=3.2.0 <4.0.0" + flutter: ">=3.16.0" diff --git a/pubspec.yaml b/pubspec.yaml index 0fb6a7859..79759b6ce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.2.25+387 +version: 2.3.0+388 environment: sdk: ">=3.1.0 <4.0.0" From 21f9be852b3de45258f6583979ab89a9dd94c55f Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 19 Feb 2024 12:10:48 +0545 Subject: [PATCH 62/70] Default value for Custom profile #2414 --- .../profile/cubit/profile_cubit.dart | 32 +++++++---------- .../profile/models/profile_setting.dart | 34 ++++++------------- pubspec.lock | 16 ++++----- 3 files changed, 32 insertions(+), 50 deletions(-) diff --git a/lib/dashboard/profile/cubit/profile_cubit.dart b/lib/dashboard/profile/cubit/profile_cubit.dart index 2209ebda8..b771a4d84 100644 --- a/lib/dashboard/profile/cubit/profile_cubit.dart +++ b/lib/dashboard/profile/cubit/profile_cubit.dart @@ -152,19 +152,6 @@ class ProfileCubit extends Cubit { jsonDecode(customProfileSettingJsonString) as Map; - if (customProfileSettingMap['selfSovereignIdentityOptions'] - ['customOidc4vcProfile']['client_id'] == - null) { - customProfileSettingMap['selfSovereignIdentityOptions'] - ['customOidc4vcProfile']['client_id'] = Parameters.clientId; - } - if (customProfileSettingMap['selfSovereignIdentityOptions'] - ['customOidc4vcProfile']['client_secret'] == - null) { - customProfileSettingMap['selfSovereignIdentityOptions'] - ['customOidc4vcProfile']['client_secret'] = randomString(12); - } - profileSetting = ProfileSetting.fromJson(customProfileSettingMap); } else { profileSetting = ProfileSetting.initial(); @@ -546,15 +533,22 @@ class ProfileCubit extends Cubit { ), ); case ProfileType.custom: - final String customProfileSettingBackup = + final String? customProfileSettingBackup = await secureStorageProvider.get( - SecureStorageKeys.customProfileSettings, - ) ?? - jsonEncode(state.model.profileSetting); - final customProfileSetting = ProfileSetting.fromJson( - json.decode(customProfileSettingBackup) as Map, + SecureStorageKeys.customProfileSettings, ); + late ProfileSetting customProfileSetting; + + if (customProfileSettingBackup == null) { + customProfileSetting = ProfileSetting.initial(); + } else { + final profileJson = + json.decode(customProfileSettingBackup) as Map; + + customProfileSetting = ProfileSetting.fromJson(profileJson); + } + await update( state.model.copyWith( profileType: profileType, diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index b2f51eb70..53b01e34b 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -173,21 +173,21 @@ class DiscoverCardsOptions extends Equatable { required this.displayGender, required this.displayDefi, required this.displayHumanity, - required this.displayHumanityJwt, required this.displayOver13, required this.displayOver15, required this.displayOver18, - required this.displayOver18Jwt, required this.displayOver50, - required this.displayEmailPass, - required this.displayEmailPassJwt, - required this.displayPhonePass, - required this.displayPhonePassJwt, required this.displayVerifiableId, - required this.displayVerifiableIdJwt, required this.displayExternalIssuer, - required this.displayChainborn, - required this.displayTezotopia, + this.displayOver18Jwt = false, + this.displayVerifiableIdJwt = true, + this.displayEmailPass = true, + this.displayEmailPassJwt = true, + this.displayPhonePass = true, + this.displayPhonePassJwt = true, + this.displayChainborn = false, + this.displayTezotopia = false, + this.displayHumanityJwt = true, }); factory DiscoverCardsOptions.fromJson(Map json) => @@ -196,22 +196,13 @@ class DiscoverCardsOptions extends Equatable { factory DiscoverCardsOptions.initial() => const DiscoverCardsOptions( displayDefi: true, displayHumanity: true, - displayHumanityJwt: true, displayOver13: false, displayOver15: false, displayOver18: true, - displayOver18Jwt: false, displayOver21: false, displayOver50: false, - displayChainborn: false, - displayTezotopia: false, displayVerifiableId: true, - displayVerifiableIdJwt: true, displayOver65: false, - displayEmailPass: true, - displayEmailPassJwt: true, - displayPhonePass: true, - displayPhonePassJwt: true, displayAgeRange: false, displayGender: false, displayExternalIssuer: [], @@ -542,8 +533,8 @@ class CustomOidc4VcProfile extends Equatable { required this.securityLevel, required this.siopv2Draft, required this.clientType, - required this.clientId, - required this.clientSecret, + this.clientId = Parameters.clientId, + this.clientSecret = 'FGbzMrvUpeFr', this.vcFormatType = VCFormatType.jwtVcJson, this.proofHeader = ProofHeaderType.kid, }); @@ -556,13 +547,11 @@ class CustomOidc4VcProfile extends Equatable { oidc4vciDraft: OIDC4VCIDraftType.draft11, oidc4vpDraft: OIDC4VPDraftType.draft18, scope: false, - proofHeader: ProofHeaderType.kid, securityLevel: false, siopv2Draft: SIOPV2DraftType.draft12, clientType: ClientType.did, clientId: Parameters.clientId, clientSecret: randomString(12), - vcFormatType: VCFormatType.jwtVcJson, ); factory CustomOidc4VcProfile.fromJson(Map json) => @@ -658,7 +647,6 @@ class SettingsMenu extends Equatable { displayDeveloperMode: true, displayHelpCenter: true, displayProfile: true, - displaySelfSovereignIdentity: true, ); final bool displayDeveloperMode; diff --git a/pubspec.lock b/pubspec.lock index 8bd37bdf7..83b61f4c8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -619,10 +619,10 @@ packages: dependency: "direct main" description: name: dio - sha256: "797e1e341c3dd2f69f2dad42564a6feff3bfb87187d05abb93b9609e6f1645c3" + sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8" url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "5.4.1" dio_cache_interceptor: dependency: transitive description: @@ -779,10 +779,10 @@ packages: dependency: "direct main" description: name: file_saver - sha256: "8ffd91ae9f543c5ebbfec71a814ee5aa9e21176d31335133308abf63f4c42e8a" + sha256: f66e1732f6dbbef256171a18b8e493cd360c4fd53b2098eb48d47a6fd676f9ee url: "https://pub.dev" source: hosted - version: "0.2.9" + version: "0.2.10" file_selector_linux: dependency: transitive description: @@ -1413,10 +1413,10 @@ packages: dependency: transitive description: name: local_auth_android - sha256: "54e9c35ce52c06333355ab0d0f41e4c06dbca354b23426765ba41dfb1de27598" + sha256: "3bcd732dda7c75fcb7ddaef12e131230f53dcc8c00790d0d6efb3aa0fbbeda57" url: "https://pub.dev" source: hosted - version: "1.0.36" + version: "1.0.37" local_auth_ios: dependency: transitive description: @@ -2441,10 +2441,10 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" url_launcher_web: dependency: transitive description: From 6fdd9f255cf4ed7d673afd85ffbb54a24b72b3aa Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 19 Feb 2024 16:15:59 +0545 Subject: [PATCH 63/70] Support single credential for single format and logic moved to cubit #2384 --- lib/app/shared/constants/urls.dart | 4 +- .../credential_subject_type_extension.dart | 1 - lib/credentials/cubit/credentials_cubit.dart | 37 ++++++++++++------- .../discover_credential_category_item.dart | 13 ------- .../discover_dummy_credential.dart | 3 -- pubspec.lock | 4 +- 6 files changed, 29 insertions(+), 33 deletions(-) diff --git a/lib/app/shared/constants/urls.dart b/lib/app/shared/constants/urls.dart index 799a27bd2..9c97a8d76 100644 --- a/lib/app/shared/constants/urls.dart +++ b/lib/app/shared/constants/urls.dart @@ -52,9 +52,11 @@ class Urls { static const String twitterCardUrl = 'https://issuer.talao.co/twitter/'; static const String identityCardUrlLDPVC = - 'https://issuer.talao.co/passbase/endpoint/verifiableid/'; + 'https://talao.co/id360/oidc4vc?format=ldp_vc&type=verifiableid'; + static const String identityCardUrlJWTVCJSON = 'https://talao.co/id360/oidc4vc/'; + static const String identityCardUrlVCSDJWT = 'https://talao.co/id360/oidc4vc?format=vcsd-jwt&type=identitycredential'; 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 cf9340d99..d7c213a58 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 @@ -993,7 +993,6 @@ extension CredentialSubjectTypeExtension on CredentialSubjectType { longDescription: longDescription == null ? null : ResponseMessage(message: longDescription), - vcFormatTypes: getVCFormatType, ); } diff --git a/lib/credentials/cubit/credentials_cubit.dart b/lib/credentials/cubit/credentials_cubit.dart index 17a273f56..659d1cdf3 100644 --- a/lib/credentials/cubit/credentials_cubit.dart +++ b/lib/credentials/cubit/credentials_cubit.dart @@ -568,14 +568,6 @@ class CredentialsCubit extends Cubit { profileSetting.discoverCardsOptions?.displayExternalIssuer; for (final CredentialCategory category in getCredentialCategorySorted) { - final List currentCredentialsSubjectTypeList = - credentials - .map( - (e) => e.credentialPreview.credentialSubjectModel - .credentialSubjectType, - ) - .toList(); - final allSubjectTypeForCategory = []; /// tezVoucher is available only on Android platform @@ -745,11 +737,30 @@ class CredentialsCubit extends Cubit { final List requiredDummySubjects = []; for (final subjectType in allSubjectTypeForCategory) { - if (currentCredentialsSubjectTypeList.contains(subjectType)) { - if (subjectType.weCanRemoveItIfCredentialExist) { - continue; - } else { - requiredDummySubjects.add(subjectType); + /// remove if format is not matching + if (!subjectType.getVCFormatType.contains(vcFormatType)) { + continue; + } + + final credentialsOfSameType = credentials + .where( + (element) => + element.credentialPreview.credentialSubjectModel + .credentialSubjectType == + subjectType, + ) + .toList(); + + /// if repetition is not allowed + if (subjectType.weCanRemoveItIfCredentialExist && + credentialsOfSameType.isNotEmpty) { + for (final credential in credentialsOfSameType) { + if (vcFormatType.value == credential.getFormat) { + /// remove if format matched + continue; + } else { + requiredDummySubjects.add(subjectType); + } } } else { requiredDummySubjects.add(subjectType); diff --git a/lib/dashboard/discover/widgets/discover_credential_category_item.dart b/lib/dashboard/discover/widgets/discover_credential_category_item.dart index 0f2f20ef2..45265578a 100644 --- a/lib/dashboard/discover/widgets/discover_credential_category_item.dart +++ b/lib/dashboard/discover/widgets/discover_credential_category_item.dart @@ -2,7 +2,6 @@ import 'package:altme/app/app.dart'; import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/theme/theme.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; class DiscoverCredentialCategoryItem extends StatelessWidget { const DiscoverCredentialCategoryItem({ @@ -18,18 +17,6 @@ class DiscoverCredentialCategoryItem extends StatelessWidget { @override Widget build(BuildContext context) { - final profileSetting = - context.read().state.model.profileSetting; - - final vcFormatType = profileSetting - .selfSovereignIdentityOptions.customOidc4vcProfile.vcFormatType; - - /// remove dummy credential if format is not matched - dummyCredentials.removeWhere((element) { - final vcFormatTypes = element.vcFormatTypes; - return vcFormatTypes != null && !vcFormatTypes.contains(vcFormatType); - }); - final credentialCategoryConfig = credentialCategory.config(context); //sort credentials by order dummyCredentials.sort( diff --git a/lib/dashboard/home/tab_bar/credentials/models/discover_dummy_credential/discover_dummy_credential.dart b/lib/dashboard/home/tab_bar/credentials/models/discover_dummy_credential/discover_dummy_credential.dart index 2e0980620..5cd3e95a1 100644 --- a/lib/dashboard/home/tab_bar/credentials/models/discover_dummy_credential/discover_dummy_credential.dart +++ b/lib/dashboard/home/tab_bar/credentials/models/discover_dummy_credential/discover_dummy_credential.dart @@ -22,7 +22,6 @@ class DiscoverDummyCredential extends Equatable { this.howToGetItExtern, this.longDescriptionExtern, this.websiteLinkExtern, - this.vcFormatTypes, }); factory DiscoverDummyCredential.fromJson(Map json) => @@ -46,7 +45,6 @@ class DiscoverDummyCredential extends Equatable { final String? howToGetItExtern; final String? longDescriptionExtern; final String? websiteLinkExtern; - final List? vcFormatTypes; Map toJson() => _$DiscoverDummyCredentialToJson(this); @override @@ -65,6 +63,5 @@ class DiscoverDummyCredential extends Equatable { howToGetItExtern, longDescriptionExtern, websiteLinkExtern, - vcFormatTypes, ]; } diff --git a/pubspec.lock b/pubspec.lock index 83b61f4c8..458af79e7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -262,10 +262,10 @@ packages: dependency: transitive description: name: built_value - sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 + sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e url: "https://pub.dev" source: hosted - version: "8.9.0" + version: "8.9.1" cached_network_image: dependency: "direct main" description: From aefdedb91857f57af54888a4774808008587cd15 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 19 Feb 2024 16:18:20 +0545 Subject: [PATCH 64/70] url update --- lib/app/shared/constants/urls.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app/shared/constants/urls.dart b/lib/app/shared/constants/urls.dart index 9c97a8d76..bf29406b7 100644 --- a/lib/app/shared/constants/urls.dart +++ b/lib/app/shared/constants/urls.dart @@ -55,7 +55,7 @@ class Urls { 'https://talao.co/id360/oidc4vc?format=ldp_vc&type=verifiableid'; static const String identityCardUrlJWTVCJSON = - 'https://talao.co/id360/oidc4vc/'; + 'https://talao.co/id360/oidc4vc?format=jwt_vc_json&type=verifiableid'; static const String identityCardUrlVCSDJWT = 'https://talao.co/id360/oidc4vc?format=vcsd-jwt&type=identitycredential'; From ff2b4d995864fdbdd48fa6ce6646048476d14a46 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Mon, 19 Feb 2024 16:24:08 +0545 Subject: [PATCH 65/70] feat: remove = in the Authorization Basic xxxx for client_secret_basic #2215 --- .../qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 52dfaa4ba..623fd557f 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 @@ -1138,7 +1138,8 @@ class QRCodeScanCubit extends Cubit { clientId = customOidc4vcProfile.clientId; clientSecret = customOidc4vcProfile.clientSecret; authorization = - base64UrlEncode(utf8.encode('$clientId:$clientSecret')); + base64UrlEncode(utf8.encode('$clientId:$clientSecret')) + .replaceAll('=', ''); case ClientAuthentication.clientId: final didKeyType = customOidc4vcProfile.defaultDid; From 3d7d1cf374bb951c1e5fbfa6246d56da5348ed61 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 19 Feb 2024 13:57:56 +0000 Subject: [PATCH 66/70] add redirect_uri to get token in authorized flow --- lib/oidc4vc/get_and_add_credential.dart | 1 + packages/oidc4vc/lib/src/oidc4vc.dart | 61 ++----------------------- 2 files changed, 5 insertions(+), 57 deletions(-) diff --git a/lib/oidc4vc/get_and_add_credential.dart b/lib/oidc4vc/get_and_add_credential.dart index 590117e9a..d0bbecff8 100644 --- a/lib/oidc4vc/get_and_add_credential.dart +++ b/lib/oidc4vc/get_and_add_credential.dart @@ -86,6 +86,7 @@ Future getAndAddCredential({ clientType: customOidc4vcProfile.clientType, proofHeaderType: customOidc4vcProfile.proofHeader, clientAuthentication: customOidc4vcProfile.clientAuthentication, + redirectUri: Parameters.oidc4vcUniversalLink, ); for (int i = 0; i < encodedCredentialOrFutureTokens.length; i++) { diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index f32d1a5b4..c9a10edec 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -389,6 +389,7 @@ class OIDC4VC { required ProofHeaderType proofHeaderType, required OIDC4VCIDraftType oidc4vciDraftType, required ClientAuthentication clientAuthentication, + required String redirectUri, String? preAuthorizedCode, String? userPin, String? code, @@ -416,6 +417,7 @@ class OIDC4VC { clientId: clientId, clientSecret: clientSecret, authorization: authorization, + redirectUri: redirectUri, ); final response = await getToken( @@ -603,6 +605,7 @@ class OIDC4VC { } Map buildTokenData({ + required String redirectUri, String? preAuthorizedCode, String? userPin, String? code, @@ -623,6 +626,7 @@ class OIDC4VC { 'code': code, 'grant_type': 'authorization_code', 'code_verifier': codeVerifier, + 'redirect_uri': redirectUri, }; } else { throw Exception(); @@ -1138,63 +1142,6 @@ class OIDC4VC { return tokenResponse.data; } - // Future sendPresentation({ - // required String clientId, - // required String redirectUrl, - // required String did, - // required String kid, - // required List credentialsToBePresented, - // required String nonce, - // required int indexValue, - // required String? stateValue, - // String? mnemonic, - // String? privateKey, - // }) async { - // try { - // final private = await getPrivateKey( - // mnemonic: mnemonic, - // privateKey: privateKey, - // indexValue: indexValue, - // ); - - // final tokenParameters = VerifierTokenParameters( - // privateKey: private, - // did: did, - // kid: kid, - // audience: clientId, - // credentials: credentialsToBePresented, - // nonce: nonce, - // ); - - // // structures - // final verifierIdToken = await getIdToken(tokenParameters); - - // /// build vp token - - // final vpToken = await getVpToken(tokenParameters); - - // final responseHeaders = { - // 'Content-Type': 'application/x-www-form-urlencoded', - // }; - - // final responseData = { - // 'id_token': verifierIdToken, - // 'vp_token': vpToken, - // }; - - // if (stateValue != null) { - // responseData['state'] = stateValue; - // } - - // await client.post( - // redirectUrl, - // options: Options(headers: responseHeaders), - // data: responseData, - // ); - // } catch (e) { - // throw Exception(e); - // } - // } Future extractVpToken({ required String clientId, From 63950cb16a86961d44ec252b2adf7942a7e11218 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 19 Feb 2024 17:42:56 +0000 Subject: [PATCH 67/70] Authlete issuer with authorization code flow fails #2409 --- packages/oidc4vc/lib/src/oidc4vc.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index c9a10edec..86ec53ffb 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -626,7 +626,7 @@ class OIDC4VC { 'code': code, 'grant_type': 'authorization_code', 'code_verifier': codeVerifier, - 'redirect_uri': redirectUri, + 'redirect_uri': redirectUri, }; } else { throw Exception(); @@ -1090,7 +1090,7 @@ class OIDC4VC { required OIDC4VCIDraftType oidc4vciDraftType, String? cnonce, }) async { - final iat = (DateTime.now().millisecondsSinceEpoch / 1000).round(); + final iat = (DateTime.now().millisecondsSinceEpoch / 1000).round() - 30; var iss = tokenParameters.did; @@ -1142,7 +1142,6 @@ class OIDC4VC { return tokenResponse.data; } - Future extractVpToken({ required String clientId, required String nonce, From b389672fd4a8c1184e268610322e9eb22c13b6e9 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 19 Feb 2024 21:01:52 +0000 Subject: [PATCH 68/70] Authorization flow fails with Meeco #2417 --- packages/oidc4vc/lib/src/oidc4vc.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 86ec53ffb..03f4714d9 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -168,8 +168,9 @@ class OIDC4VC { authorizationEndPoint: authorizationEndPoint, scope: scope, clientAuthentication: clientAuthentication, + oidc4vciDraftType: oidc4vciDraftType, ); - + final url = Uri.parse(authorizationEndpoint); final authorizationUri = Uri.https(url.authority, url.path, authorizationRequestParemeters); @@ -194,6 +195,7 @@ class OIDC4VC { required String state, required bool scope, required ClientAuthentication clientAuthentication, + required OIDC4VCIDraftType oidc4vciDraftType, }) { //https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-successful-authorization-re @@ -262,7 +264,13 @@ class OIDC4VC { 'type': 'openid_credential', 'credential_configuration_id': credential, }; - + if (oidc4vciDraftType == OIDC4VCIDraftType.draft13) { + data = { + 'type': 'openid_credential', + 'format': 'vc+sd-jwt', + 'vct': credentialSupported['vct'].toString(), + }; + } final scope = credentialSupported['scope']; if (scope == null) { From 7c6a927e04015af74d9a4f0a47618decdd91df01 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 19 Feb 2024 21:02:27 +0000 Subject: [PATCH 69/70] Authorization flow fails with Meeco #2417 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 79759b6ce..f16a63665 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: altme description: AltMe Flutter App -version: 2.3.0+388 +version: 2.3.1+389 environment: sdk: ">=3.1.0 <4.0.0" From f643307daa10d8cbe1114db4070d3e3309067e84 Mon Sep 17 00:00:00 2001 From: hawkbee1 Date: Mon, 19 Feb 2024 21:55:19 +0000 Subject: [PATCH 70/70] Authorization flow fails with Meeco #2417 --- .../cubit/qr_code_scan_cubit.dart | 1 + .../get_authorization_uri_for_issuer.dart | 3 +- packages/oidc4vc/lib/src/oidc4vc.dart | 37 ++++++++++--------- 3 files changed, 23 insertions(+), 18 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 623fd557f..915103b89 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 @@ -1206,6 +1206,7 @@ class QRCodeScanCubit extends Cubit { clientSecret: clientSecret, clientAuthentication: customOidc4vcProfile.clientAuthentication, oidc4vciDraftType: customOidc4vcProfile.oidc4vciDraft, + vcFormatType: customOidc4vcProfile.vcFormatType, ); goBack(); } diff --git a/lib/oidc4vc/get_authorization_uri_for_issuer.dart b/lib/oidc4vc/get_authorization_uri_for_issuer.dart index 0cbf76cdf..1ba743705 100644 --- a/lib/oidc4vc/get_authorization_uri_for_issuer.dart +++ b/lib/oidc4vc/get_authorization_uri_for_issuer.dart @@ -21,6 +21,7 @@ Future getAuthorizationUriForIssuer({ required String? clientSecret, required ClientAuthentication clientAuthentication, required OIDC4VCIDraftType oidc4vciDraftType, + required VCFormatType vcFormatType, }) async { /// this is first phase flow for authorization_code @@ -72,7 +73,7 @@ Future getAuthorizationUriForIssuer({ authorizationEndPoint: Parameters.authorizeEndPoint, scope: scope, clientAuthentication: clientAuthentication, - oidc4vciDraftType: oidc4vciDraftType, + oidc4vciDraftType: oidc4vciDraftType, vcFormatType: vcFormatType, ); await LaunchUrl.launchUri(oidc4vcAuthenticationUri); diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 03f4714d9..dab9a422e 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -140,6 +140,7 @@ class OIDC4VC { required bool scope, required ClientAuthentication clientAuthentication, required OIDC4VCIDraftType oidc4vciDraftType, + required VCFormatType vcFormatType, }) async { try { final openIdConfiguration = await getOpenIdConfig( @@ -155,22 +156,22 @@ class OIDC4VC { ); final authorizationRequestParemeters = getAuthorizationRequestParemeters( - selectedCredentials: selectedCredentials, - openIdConfiguration: openIdConfiguration, - clientId: clientId, - clientSecret: clientSecret, - issuer: issuer, - redirectUri: redirectUri, - issuerState: issuerState, - nonce: nonce, - pkcePair: pkcePair, - state: state, - authorizationEndPoint: authorizationEndPoint, - scope: scope, - clientAuthentication: clientAuthentication, - oidc4vciDraftType: oidc4vciDraftType, - ); - + selectedCredentials: selectedCredentials, + openIdConfiguration: openIdConfiguration, + clientId: clientId, + clientSecret: clientSecret, + issuer: issuer, + redirectUri: redirectUri, + issuerState: issuerState, + nonce: nonce, + pkcePair: pkcePair, + state: state, + authorizationEndPoint: authorizationEndPoint, + scope: scope, + clientAuthentication: clientAuthentication, + oidc4vciDraftType: oidc4vciDraftType, + vcFormatType: vcFormatType); + final url = Uri.parse(authorizationEndpoint); final authorizationUri = Uri.https(url.authority, url.path, authorizationRequestParemeters); @@ -196,6 +197,7 @@ class OIDC4VC { required bool scope, required ClientAuthentication clientAuthentication, required OIDC4VCIDraftType oidc4vciDraftType, + required VCFormatType vcFormatType, }) { //https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-successful-authorization-re @@ -264,7 +266,8 @@ class OIDC4VC { 'type': 'openid_credential', 'credential_configuration_id': credential, }; - if (oidc4vciDraftType == OIDC4VCIDraftType.draft13) { + if (oidc4vciDraftType == OIDC4VCIDraftType.draft13 && + vcFormatType == VCFormatType.vcSdJWT) { data = { 'type': 'openid_credential', 'format': 'vc+sd-jwt',