From 64dd26292172fb08c555a570ee2c3dae2c74358e Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 12 Dec 2024 14:44:25 +0545 Subject: [PATCH 1/6] feat: Implement oidc4vci draft 14 #3180 #3181 --- .../helper_functions/helper_functions.dart | 7 +++ .../profile/models/profile_setting.dart | 20 ------- .../profile/models/profile_setting.g.dart | 13 ++-- .../cubit/qr_code_scan_cubit.dart | 39 ++++++++++++ .../get_and_add_deffered_credential.dart | 1 + .../get_authorization_uri_for_issuer.dart | 1 + .../initiate_oidv4vc_credential_issuance.dart | 9 +++ .../lib/src/models/openid_configuration.dart | 4 ++ .../src/models/openid_configuration.g.dart | 2 + packages/oidc4vc/lib/src/oidc4vc.dart | 59 +++++++++++++++++++ .../oidc4vc/lib/src/oidc4vci_draft_type.dart | 18 ++++++ 11 files changed, 147 insertions(+), 26 deletions(-) diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index b916339a9..7f02fdb75 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -1301,6 +1301,13 @@ MessageHandler getMessageHandler(dynamic e) { 'error_description': 'Kid does not match the did document.', }, ); + } else if (stringException.contains('C_NONCE_NOT_AVAILABLE')) { + return ResponseMessage( + data: { + 'error': 'invalid_request', + 'error_description': 'c_nonce is not avaiable.', + }, + ); } else { return ResponseMessage( message: diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index 15d9fd59d..56fbbd9fe 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -746,11 +746,6 @@ class CustomOidc4VcProfile extends Equatable { final String? clientSecret; final bool cryptoHolderBinding; final DidKeyType defaultDid; - // TODO(bibash): temporary solution to avoid who have chosen 12 - @JsonKey( - includeFromJson: true, - fromJson: oidc4vciDraftFromJson, - ) final OIDC4VCIDraftType oidc4vciDraft; final OIDC4VPDraftType oidc4vpDraft; final bool scope; @@ -769,21 +764,6 @@ class CustomOidc4VcProfile extends Equatable { Map toJson() => _$CustomOidc4VcProfileToJson(this); - static OIDC4VCIDraftType oidc4vciDraftFromJson(dynamic value) { - if (value == '11') { - return OIDC4VCIDraftType.draft11; - } else if (value == '12' || value == '13') { - return OIDC4VCIDraftType.draft13; - } else { - throw ResponseMessage( - data: { - 'error': 'invalid_format', - 'error_description': 'Error with oidc4vc draft type.', - }, - ); - } - } - CustomOidc4VcProfile copyWith({ ClientAuthentication? clientAuthentication, bool? credentialManifestSupport, diff --git a/lib/dashboard/profile/models/profile_setting.g.dart b/lib/dashboard/profile/models/profile_setting.g.dart index 150c46104..26ca0af4f 100644 --- a/lib/dashboard/profile/models/profile_setting.g.dart +++ b/lib/dashboard/profile/models/profile_setting.g.dart @@ -243,7 +243,7 @@ CustomOidc4VcProfile _$CustomOidc4VcProfileFromJson( cryptoHolderBinding: json['cryptoHolderBinding'] as bool, defaultDid: $enumDecode(_$DidKeyTypeEnumMap, json['defaultDid']), oidc4vciDraft: - CustomOidc4VcProfile.oidc4vciDraftFromJson(json['oidc4vciDraft']), + $enumDecode(_$OIDC4VCIDraftTypeEnumMap, json['oidc4vciDraft']), oidc4vpDraft: $enumDecode(_$OIDC4VPDraftTypeEnumMap, json['oidc4vpDraft']), scope: json['scope'] as bool, @@ -316,6 +316,12 @@ const _$DidKeyTypeEnumMap = { 'urn:ietf:params:oauth:client-assertion-type:jwt-client-attestation', }; +const _$OIDC4VCIDraftTypeEnumMap = { + OIDC4VCIDraftType.draft11: '11', + OIDC4VCIDraftType.draft13: '13', + OIDC4VCIDraftType.draft14: '14', +}; + const _$OIDC4VPDraftTypeEnumMap = { OIDC4VPDraftType.draft10: '10', OIDC4VPDraftType.draft13: '13', @@ -343,11 +349,6 @@ const _$ProofTypeEnumMap = { ProofType.jwt: 'jwt', }; -const _$OIDC4VCIDraftTypeEnumMap = { - OIDC4VCIDraftType.draft11: '11', - OIDC4VCIDraftType.draft13: '13', -}; - SettingsMenu _$SettingsMenuFromJson(Map json) => SettingsMenu( displayDeveloperMode: json['displayDeveloperMode'] as bool, displayHelpCenter: json['displayHelpCenter'] as bool, 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 25ded7767..cb33a5533 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 @@ -1311,6 +1311,7 @@ class QRCodeScanCubit extends Cubit { oAuthClientAttestationPop: oAuthClientAttestationPop, qrCodeScanCubit: qrCodeScanCubit, publicKeyForDPop: publicKeyForDPop, + oidc4vciDraftType: customOidc4vcProfile.oidc4vciDraft, ); } else { emit(state.loading()); @@ -1372,6 +1373,7 @@ class QRCodeScanCubit extends Cubit { required String? clientSecret, required QRCodeScanCubit qrCodeScanCubit, required String publicKeyForDPop, + required OIDC4VCIDraftType oidc4vciDraftType, String? oAuthClientAttestation, String? oAuthClientAttestationPop, }) async { @@ -1464,6 +1466,7 @@ class QRCodeScanCubit extends Cubit { dio: client.dio, tokenData: tokenData, dPop: dPop, + issuer: issuer, ); savedAccessToken = accessToken; @@ -1496,6 +1499,33 @@ class QRCodeScanCubit extends Cubit { ); } + if (oidc4vciDraftType.getNonce) { + final nonceEndpoint = await oidc4vc.getNonceEndPoint( + issuer: issuer, + openIdConfiguration: + OpenIdConfiguration.fromJson(openIdConfigurationData), + dio: client.dio, + useOAuthAuthorizationServerLink: + useOauthServerAuthEndPoint(profileCubit.state.model), + ); + + final nonce = await oidc4vc.getNonceReponse( + dio: client.dio, + nonceEndpoint: nonceEndpoint, + ); + + if (nonce == null) { + throw ResponseMessage( + data: { + 'error': 'invalid_request', + 'error_description': 'c_nonce is not avaiable.', + }, + ); + } + + savedNonce = nonce; + } + /// get credentials final result = await getCredential( isEBSI: isEBSI, @@ -1766,6 +1796,14 @@ ${state.uri} statePayload['oAuthClientAttestationPop'] as String?; final String publicKeyForDPop = statePayload['publicKeyForDPop'].toString(); + final String oidc4vciDraft = statePayload['oidc4vciDraft'].toString(); + + final OIDC4VCIDraftType? oidc4vciDraftType = OIDC4VCIDraftType.values + .firstWhereOrNull((ele) => ele.numbering == oidc4vciDraft); + + if (oidc4vciDraftType == null) { + throw Exception(); + } await addCredentialsInLoop( selectedCredentials: selectedCredentials, @@ -1783,6 +1821,7 @@ ${state.uri} oAuthClientAttestationPop: oAuthClientAttestationPop, qrCodeScanCubit: qrCodeScanCubit, publicKeyForDPop: publicKeyForDPop, + oidc4vciDraftType: oidc4vciDraftType, ); } catch (e) { emitError(e); diff --git a/lib/oidc4vc/get_and_add_deffered_credential.dart b/lib/oidc4vc/get_and_add_deffered_credential.dart index 8607f75cc..3f2809080 100644 --- a/lib/oidc4vc/get_and_add_deffered_credential.dart +++ b/lib/oidc4vc/get_and_add_deffered_credential.dart @@ -34,6 +34,7 @@ Future getAndAddDefferedCredential({ 'Authorization': 'Bearer $acceptanceToken', }; case OIDC4VCIDraftType.draft13: + case OIDC4VCIDraftType.draft14: /// trasanction_id is NEW for draft 13. it was /// acceptance_token for draft 11 diff --git a/lib/oidc4vc/get_authorization_uri_for_issuer.dart b/lib/oidc4vc/get_authorization_uri_for_issuer.dart index e56fe99a3..98fedc4fe 100644 --- a/lib/oidc4vc/get_authorization_uri_for_issuer.dart +++ b/lib/oidc4vc/get_authorization_uri_for_issuer.dart @@ -59,6 +59,7 @@ Future getAuthorizationUriForIssuer({ 'issuer': issuer, 'isEBSI': isEBSI, 'publicKeyForDPop': publicKeyForDPop, + 'oidc4vciDraft': oidc4vciDraftType.numbering, }; switch (clientAuthentication) { diff --git a/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart b/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart index c0dcc52c5..a2c69a295 100644 --- a/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart +++ b/lib/oidc4vc/initiate_oidv4vc_credential_issuance.dart @@ -125,6 +125,14 @@ Future initiateOIDC4VCCredentialIssuance({ final String? oAuthClientAttestationPop = jwt['oAuthClientAttestationPop'] as String?; final String publicKeyForDPop = jwt['publicKeyForDPop'].toString(); + final String oidc4vciDraft = jwt['oidc4vciDraft'].toString(); + + final OIDC4VCIDraftType? oidc4vciDraftType = OIDC4VCIDraftType.values + .firstWhereOrNull((ele) => ele.numbering == oidc4vciDraft); + + if (oidc4vciDraftType == null) { + throw Exception(); + } final selectedCredentials = stateOfCredentialsSelected .map((index) => credentials[index]) @@ -146,6 +154,7 @@ Future initiateOIDC4VCCredentialIssuance({ oAuthClientAttestationPop: oAuthClientAttestationPop, qrCodeScanCubit: qrCodeScanCubit, publicKeyForDPop: publicKeyForDPop, + oidc4vciDraftType: oidc4vciDraftType, ); } } diff --git a/packages/oidc4vc/lib/src/models/openid_configuration.dart b/packages/oidc4vc/lib/src/models/openid_configuration.dart index 66a543102..8ed045b01 100644 --- a/packages/oidc4vc/lib/src/models/openid_configuration.dart +++ b/packages/oidc4vc/lib/src/models/openid_configuration.dart @@ -18,6 +18,7 @@ class OpenIdConfiguration extends Equatable { this.display, this.subjectSyntaxTypesSupported, this.tokenEndpoint, + this.nonceEndpoint, this.batchEndpoint, this.authorizationEndpoint, this.subjectTrustFrameworksSupported, @@ -47,6 +48,8 @@ class OpenIdConfiguration extends Equatable { final List? subjectSyntaxTypesSupported; @JsonKey(name: 'token_endpoint') final String? tokenEndpoint; + @JsonKey(name: 'nonce_endpoint') + final String? nonceEndpoint; @JsonKey(name: 'batch_endpoint') final String? batchEndpoint; @JsonKey(name: 'authorization_endpoint') @@ -87,6 +90,7 @@ class OpenIdConfiguration extends Equatable { display, subjectSyntaxTypesSupported, tokenEndpoint, + nonceEndpoint, batchEndpoint, authorizationEndpoint, subjectTrustFrameworksSupported, diff --git a/packages/oidc4vc/lib/src/models/openid_configuration.g.dart b/packages/oidc4vc/lib/src/models/openid_configuration.g.dart index 7ed767c28..aaefad1c8 100644 --- a/packages/oidc4vc/lib/src/models/openid_configuration.g.dart +++ b/packages/oidc4vc/lib/src/models/openid_configuration.g.dart @@ -29,6 +29,7 @@ OpenIdConfiguration _$OpenIdConfigurationFromJson(Map json) => subjectSyntaxTypesSupported: json['subject_syntax_types_supported'] as List?, tokenEndpoint: json['token_endpoint'] as String?, + nonceEndpoint: json['nonce_endpoint'] as String?, batchEndpoint: json['batch_endpoint'] as String?, authorizationEndpoint: json['authorization_endpoint'] as String?, subjectTrustFrameworksSupported: @@ -61,6 +62,7 @@ Map _$OpenIdConfigurationToJson( 'display': instance.display, 'subject_syntax_types_supported': instance.subjectSyntaxTypesSupported, 'token_endpoint': instance.tokenEndpoint, + 'nonce_endpoint': instance.nonceEndpoint, 'batch_endpoint': instance.batchEndpoint, 'authorization_endpoint': instance.authorizationEndpoint, 'pushed_authorization_request_endpoint': diff --git a/packages/oidc4vc/lib/src/oidc4vc.dart b/packages/oidc4vc/lib/src/oidc4vc.dart index 1a0702747..99b0fd135 100644 --- a/packages/oidc4vc/lib/src/oidc4vc.dart +++ b/packages/oidc4vc/lib/src/oidc4vc.dart @@ -481,6 +481,7 @@ class OIDC4VC { required String? oAuthClientAttestation, required String? oAuthClientAttestationPop, required String? dPop, + required String issuer, }) async { Map? tokenResponse; String? accessToken; @@ -508,6 +509,28 @@ class OIDC4VC { return (tokenResponse, accessToken, cnonce, authorizationDetails); } + /// nonce + Future getNonceReponse({ + required Dio dio, + required String nonceEndpoint, + }) async { + String? cnonce; + + final headers = {'Content-Type': 'application/json; charset=UTF-8'}; + final dynamic response = await dio.post( + nonceEndpoint, + options: Options(headers: headers), + ); + + final data = response.data; + + if (data is Map && data.containsKey('c_nonce')) { + cnonce = data['c_nonce'] as String; + } + + return cnonce; + } + int count = 0; Future getSingleCredential({ @@ -792,6 +815,40 @@ class OIDC4VC { return tokenEndPoint; } + Future getNonceEndPoint({ + required OpenIdConfiguration openIdConfiguration, + required String issuer, + required Dio dio, + required bool useOAuthAuthorizationServerLink, + SecureStorageProvider? secureStorage, + }) async { + var nonceEndPoint = '$issuer/nonce'; + + if (openIdConfiguration.nonceEndpoint != null) { + nonceEndPoint = openIdConfiguration.nonceEndpoint!; + } else { + final authorizationServer = + openIdConfiguration.authorizationServer ?? issuer; + + final authorizationServerConfigurationData = + await getAuthorizationServerMetaData( + baseUrl: authorizationServer, + dio: dio, + secureStorage: secureStorage, + useOAuthAuthorizationServerLink: useOAuthAuthorizationServerLink, + ); + + final authorizationServerConfiguration = + OpenIdConfiguration.fromJson(authorizationServerConfigurationData); + + if (authorizationServerConfiguration.nonceEndpoint != null) { + nonceEndPoint = authorizationServerConfiguration.nonceEndpoint!; + } + } + + return nonceEndPoint; + } + Future readAuthorizationEndPoint({ required OpenIdConfiguration openIdConfiguration, required String issuer, @@ -829,6 +886,7 @@ class OIDC4VC { } } case OIDC4VCIDraftType.draft13: + case OIDC4VCIDraftType.draft14: /// Extract the authorization endpoint from from first element of /// authorization_servers in opentIdConfiguration.authorizationServers @@ -1077,6 +1135,7 @@ class OIDC4VC { // } case OIDC4VCIDraftType.draft13: + case OIDC4VCIDraftType.draft14: credentialData['format'] = format; if (credentialDefinition != null) { diff --git a/packages/oidc4vc/lib/src/oidc4vci_draft_type.dart b/packages/oidc4vc/lib/src/oidc4vci_draft_type.dart index 02addee0e..9b6367f63 100644 --- a/packages/oidc4vc/lib/src/oidc4vci_draft_type.dart +++ b/packages/oidc4vc/lib/src/oidc4vci_draft_type.dart @@ -5,6 +5,8 @@ enum OIDC4VCIDraftType { draft11, @JsonValue('13') draft13, + @JsonValue('14') + draft14, } extension OIDC4VCIDraftTypeX on OIDC4VCIDraftType { @@ -14,6 +16,8 @@ extension OIDC4VCIDraftTypeX on OIDC4VCIDraftType { return 'Draft 11'; case OIDC4VCIDraftType.draft13: return 'Draft 13'; + case OIDC4VCIDraftType.draft14: + return 'Draft 14'; } } @@ -23,6 +27,20 @@ extension OIDC4VCIDraftTypeX on OIDC4VCIDraftType { return '11'; case OIDC4VCIDraftType.draft13: return '13'; + case OIDC4VCIDraftType.draft14: + return '14'; + } + } + + bool get getNonce { + /// For OIDC4VCI draft > =14, + /// the token endpoint does not return a c_nonce. + switch (this) { + case OIDC4VCIDraftType.draft11: + case OIDC4VCIDraftType.draft13: + return false; + case OIDC4VCIDraftType.draft14: + return true; } } } From c4cdbd906b1b4c52801975c0e7d7f8946c21df25 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 12 Dec 2024 15:03:29 +0545 Subject: [PATCH 2/6] feat: Remove app version #3186 --- .../about_altme/view/about_altme_menu.dart | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/dashboard/drawer/about_altme/about_altme/view/about_altme_menu.dart b/lib/dashboard/drawer/about_altme/about_altme/view/about_altme_menu.dart index 6b80446b3..ace874f74 100644 --- a/lib/dashboard/drawer/about_altme/about_altme/view/about_altme_menu.dart +++ b/lib/dashboard/drawer/about_altme/about_altme/view/about_altme_menu.dart @@ -86,19 +86,19 @@ class AboutAltmeView extends StatelessWidget { ), ], const SizedBox(height: Sizes.spaceXSmall), - FutureBuilder( - future: PackageInfo.fromPlatform(), - builder: (_, snapShot) { - var appVersion = '...'; - if (snapShot.connectionState == ConnectionState.done) { - appVersion = snapShot.data?.version ?? '0.1.0'; - } - return DrawerItem( - title: '${l10n.yourAppVersion} : $appVersion', - trailing: Container(), - ); - }, - ), + // FutureBuilder( + // future: PackageInfo.fromPlatform(), + // builder: (_, snapShot) { + // var appVersion = '...'; + // if (snapShot.connectionState == ConnectionState.done) { + // appVersion = snapShot.data?.version ?? '0.1.0'; + // } + // return DrawerItem( + // title: '${l10n.yourAppVersion} : $appVersion', + // trailing: Container(), + // ); + // }, + // ), DrawerItem( title: l10n.termsOfUse, onTap: () => From da7945da6c34c96ccbedeb2b6a850eeac9fc74b5 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 12 Dec 2024 15:41:05 +0545 Subject: [PATCH 3/6] feat: Update activity log and reset screen #3183 --- .../activity_log/view/activity_log_page.dart | 146 ++++++++++-------- .../reset_wallet/view/reset_wallet_menu.dart | 8 +- 2 files changed, 83 insertions(+), 71 deletions(-) diff --git a/lib/dashboard/drawer/activity_log/view/activity_log_page.dart b/lib/dashboard/drawer/activity_log/view/activity_log_page.dart index a0b3ef8e7..c309c2780 100644 --- a/lib/dashboard/drawer/activity_log/view/activity_log_page.dart +++ b/lib/dashboard/drawer/activity_log/view/activity_log_page.dart @@ -61,85 +61,95 @@ class _ActivityLogViewState extends State { builder: (context, state) { return BasePage( scrollView: false, - title: l10n.activityLog, titleAlignment: Alignment.topCenter, - titleLeading: const BackLeadingButton(), - body: ListView.builder( - itemCount: state.logDatas.length, - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const ScrollPhysics(), - itemBuilder: (context, index) { - final LogData logData = state.logDatas[index]; + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const BackLeadingButton(padding: EdgeInsets.zero), + const DrawerLogo(), + const AppVersionDrawer(), + const SizedBox(height: Sizes.spaceNormal), + Expanded( + child: ListView.builder( + itemCount: state.logDatas.length, + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const ScrollPhysics(), + itemBuilder: (context, index) { + final LogData logData = state.logDatas[index]; - var message = ''; + var message = ''; - var credentialName = ''; - var domainName = ''; + var credentialName = ''; + var domainName = ''; - if (logData.vcInfo != null) { - credentialName = logData.vcInfo!.name; - domainName = logData.vcInfo!.domain ?? ''; - } + if (logData.vcInfo != null) { + credentialName = logData.vcInfo!.name; + domainName = logData.vcInfo!.domain ?? ''; + } - switch (logData.type) { - case LogType.walletInit: - message = l10n.walletInitialized; - case LogType.backupData: - message = l10n.backupCredentials; - case LogType.restoreWallet: - message = l10n.restoredCredentials; - case LogType.addVC: - message = l10n.addedCredential(credentialName, domainName); - case LogType.deleteVC: - message = l10n.deletedCredential(credentialName); - case LogType.presentVC: - message = - l10n.presentedCredential(credentialName, domainName); - case LogType.importKey: - message = l10n.keysImported; - } + switch (logData.type) { + case LogType.walletInit: + message = l10n.walletInitialized; + case LogType.backupData: + message = l10n.backupCredentials; + case LogType.restoreWallet: + message = l10n.restoredCredentials; + case LogType.addVC: + message = + l10n.addedCredential(credentialName, domainName); + case LogType.deleteVC: + message = l10n.deletedCredential(credentialName); + case LogType.presentVC: + message = l10n.presentedCredential( + credentialName, domainName); + case LogType.importKey: + message = l10n.keysImported; + } - return Column( - children: [ - BackgroundCard( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + return Column( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - UiDate.formatDatetime(logData.timestamp), - style: TextStyle( - color: colorScheme.onSurface, - fontSize: 12, - fontWeight: FontWeight.w500, - height: 1.333, + BackgroundCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + UiDate.formatDatetime(logData.timestamp), + style: TextStyle( + color: colorScheme.onSurface, + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.333, + ), + ), + ], ), - ), - ], - ), - const SizedBox(height: 4), - Container( - alignment: Alignment.centerLeft, - child: Text( - message, - style: TextStyle( - color: colorScheme.onSurface, - fontSize: 16, - fontWeight: FontWeight.w500, - height: 1.5, - ), + const SizedBox(height: 4), + Container( + alignment: Alignment.centerLeft, + child: Text( + message, + style: TextStyle( + color: colorScheme.onSurface, + fontSize: 16, + fontWeight: FontWeight.w500, + height: 1.5, + ), + ), + ), + ], ), ), + const SizedBox(height: 10), ], - ), - ), - const SizedBox(height: 10), - ], - ); - }, + ); + }, + ), + ), + ], ), ); }, diff --git a/lib/dashboard/drawer/reset_wallet/view/reset_wallet_menu.dart b/lib/dashboard/drawer/reset_wallet/view/reset_wallet_menu.dart index 3531b0f7a..e2d692ab7 100644 --- a/lib/dashboard/drawer/reset_wallet/view/reset_wallet_menu.dart +++ b/lib/dashboard/drawer/reset_wallet/view/reset_wallet_menu.dart @@ -30,19 +30,21 @@ class ResetWalletView extends StatelessWidget { Widget build(BuildContext context) { final l10n = context.l10n; return BasePage( - title: l10n.resetWallet, useSafeArea: true, scrollView: false, titleAlignment: Alignment.topCenter, padding: const EdgeInsets.symmetric(horizontal: Sizes.spaceSmall), - titleLeading: const BackLeadingButton(), backgroundColor: Theme.of(context).colorScheme.surface, body: BlocBuilder( builder: (context, state) { return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [ + const BackLeadingButton(padding: EdgeInsets.zero), + const DrawerLogo(), + const AppVersionDrawer(), + const SizedBox(height: Sizes.spaceNormal), Text( l10n.resetWalletTitle, textAlign: TextAlign.center, From c5150c3426c64f87ce3bbdb431a8c648b53b483f Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 12 Dec 2024 17:27:00 +0545 Subject: [PATCH 4/6] Translation update #3182 --- .../profile/view/pick_profile_menu.dart | 4 +- .../widget/profile_selector_widget.dart | 2 +- lib/l10n/arb/app_en.arb | 59 ++++++++++--------- lib/l10n/arb/app_fr.arb | 17 +++--- lib/l10n/untranslated.json | 6 +- 5 files changed, 45 insertions(+), 43 deletions(-) diff --git a/lib/dashboard/drawer/profile/view/pick_profile_menu.dart b/lib/dashboard/drawer/profile/view/pick_profile_menu.dart index 3fa0e7900..146c36064 100644 --- a/lib/dashboard/drawer/profile/view/pick_profile_menu.dart +++ b/lib/dashboard/drawer/profile/view/pick_profile_menu.dart @@ -34,9 +34,7 @@ class PickProfileMenuView extends StatelessWidget { body: const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( - padding: EdgeInsets.zero, - ), + BackLeadingButton(padding: EdgeInsets.zero), DrawerLogo(), ProfileSelectorWidget(), ], diff --git a/lib/dashboard/drawer/profile/widget/profile_selector_widget.dart b/lib/dashboard/drawer/profile/widget/profile_selector_widget.dart index 25276670a..6d3d49275 100644 --- a/lib/dashboard/drawer/profile/widget/profile_selector_widget.dart +++ b/lib/dashboard/drawer/profile/widget/profile_selector_widget.dart @@ -42,7 +42,7 @@ class ProfileSelectorWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Choose your SSI profile or customize your own', + context.l10n.chooseYourSSIProfileOrCustomizeYourOwn, style: Theme.of(context).textTheme.titleMedium, ), ], diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index e4a390bbf..c4770694b 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -296,7 +296,7 @@ "save": "Save", "delete": "Delete", "enterNewPinCode": "Create a PIN Code\nto protect your wallet", - "confirmYourPinCode": "Confirm your PIN Code", + "confirmYourPinCode": "Confirm your PIN code", "walletAltme": "Wallet Altme", "createTitle": "Create or import a wallet", "createSubtitle": "Would you like to create a new wallet or import an existing one?", @@ -365,7 +365,7 @@ "onBoardingSecondTitle": "Our wallet is much more than a simple Digital Wallet.", "onBoardingSecondSubtitle": "Store & Manage your personal data and get access to any Web 3.0 Apps.", "onBoardingThirdTitle": "Manage your data with full autonomy, security and privacy.", - "onBoardingThirdSubtitle": "Our wallet use SSI cryptography to give you full control over your data. Nothing goes out of your phone.", + "onBoardingThirdSubtitle": "Our wallet use cryptography to give you full control over your data. Nothing goes out of your phone.", "onBoardingStart": "Start", "learnMoreAboutAltme": "Learn more about your wallet", "scroll": "Scroll", @@ -374,20 +374,20 @@ "createOrImportNewAccount": "Create or import a new account.", "selectAccount": "Select account", "onbordingSeedPhrase": "Seed Phrase", - "onboardingPleaseStoreMessage": "Please, write down your Recovery Phrase", - "onboardingVerifyPhraseMessage": "Confirm Recovery Words", - "onboardingVerifyPhraseMessageDetails": "To ensure your Recovery Phrase is written correctly, select the words in correct order.", - "onboardingAltmeMessage": "The wallet is non-custodial. Your Recovery Phrase is the only way to recover your account.", + "onboardingPleaseStoreMessage": "Please, write down your recovery phrase", + "onboardingVerifyPhraseMessage": "Confirm the recovery phrase", + "onboardingVerifyPhraseMessageDetails": "To ensure your recovery phrase is written correctly, select the words in correct order.", + "onboardingAltmeMessage": "The wallet is non-custodial. Your recovery phrase is the only way to recover your account.", "onboardingWroteDownMessage": "I wrote down my Recovery Phrase", "copyToClipboard": "Copy to clipboard", - "pinCodeMessage": "PIN Code prevent unauthorized access to your Wallet. You can change it at any time.", + "pinCodeMessage": "PIN code prevent unauthorized access to your wallet. You can change it at any time.", "enterNameForYourNewAccount": "Enter a name for your new account", "create": "Create", "import": "Import", "accountName": "Account name", "importWalletText": "Enter your recovery phrase or private key here.", "importWalletTextRecoveryPhraseOnly": "Enter your recovery phrase here.", - "recoveryPhraseDescriptions": "A recovery phrase (sometimes known as a seed phrase, private key or backup phrase) is a list of 12 words generated by your cryptocurrency wallet that gives you access to your funds", + "recoveryPhraseDescriptions": "A recovery phrase is a list of 12 words generated by your crypto wallet that gives you access to your funds", "importEasilyFrom": "Import your account from :", "templeWallet": "Temple wallet", "temple": "Temple", @@ -397,7 +397,7 @@ "kukaiWallet": "Kukai wallet", "other": "Other", "otherWalletApp": "Other wallet App", - "importWalletHintText": "Once you have entered your 12 words (recovery phrase) or {numberCharacters} characters private (private key), tap Import.", + "importWalletHintText": "Once you have entered your 12 words or all the characters of the private key, tap Import.", "@importWalletHintText": { "description": "hint text when importing additional account", "type": "text", @@ -405,7 +405,7 @@ "numberCharacters": {} } }, - "importWalletHintTextRecoveryPhraseOnly": "Once you have entered your 12 words (recovery phrase), tap Import.", + "importWalletHintTextRecoveryPhraseOnly": "Once you have entered your 12 words of the recovery phrase, tap Import.", "kycDialogTitle": "To get this card, and other identity cards, you need to verify your ID", "idVerificationProcess": "ID Verification Process", "idCheck": "ID Check", @@ -575,7 +575,7 @@ "website": "Website", "whyGetThisCard": "Why get this card", "howToGetIt": "How to get it", - "emailPassWhyGetThisCard": "This proof may be required by some Web 3 Apps / Websites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", + "emailPassWhyGetThisCard": "This proof may be required by some applications and web sites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", "emailPassExpirationDate": "This card will remain active and reusable for 1 YEAR.", "emailPassHowToGetIt": "It’s super easy. Altme will verify your email ownership by sending a code by email.", "tezotopiaMembershipWhyGetThisCard": "This Membership card will give you 25% cash backs on ALL Tezotopia Game transactions when you buy a Drops on the marketplace or mint an NFT on starbase.", @@ -590,23 +590,23 @@ "twitterExpirationDate": "This card will be active for 1 year.", "twitterDummyDesc": "Prove your twitter account ownership", "tezotopiaMembershipHowToGetIt": "You need to present a proof that you are over 13 YO and a proof of your email.", - "over18WhyGetThisCard": "This proof may be required by some Web 3 Apps / Websites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", + "over18WhyGetThisCard": "This proof may be required by some applications and web sites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", "over18ExpirationDate": "This card will remain active and reusable for 1 YEAR.", "over18HowToGetIt": "You can claim this card by following Altme’s KYC check.", - "over13WhyGetThisCard": "This proof may be required by some Web 3 Apps / Websites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", + "over13WhyGetThisCard": "This proof may be required by some applications and web sites to access their service or claim benefits : Membership card, Loyalty card, 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.", + "over15WhyGetThisCard": "This proof may be required by some applications and web sites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", "over15ExpirationDate": "This card will remain active and reusable for 1 YEAR.", "over15HowToGetIt": "You can claim this card by following Altme’s KYC check.", - "passportFootprintWhyGetThisCard": "This proof may be required by some Web 3 Apps / Websites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", + "passportFootprintWhyGetThisCard": "This proof may be required by some applications and web sites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", "passportFootprintExpirationDate": "This card will remain active and reusable for 1 YEAR.", "passportFootprintHowToGetIt": "You can claim this card by following Altme’s KYC check.", "verifiableIdCardWhyGetThisCard": "This digital identity card contains the same information as your physical ID card. You can use it in Web 3 for a KYC check for example.", "verifiableIdCardExpirationDate": "This card will remain active and reusable for 1 YEAR.", "verifiableIdCardHowToGetIt": "You can claim this card by following Altme’s KYC check.", "verifiableIdCardDummyDesc": "Get your Digital Identity Card.", - "phoneProofWhyGetThisCard": "This proof may be required by some Web 3 Apps / Websites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", + "phoneProofWhyGetThisCard": "This proof may be required by some applications and web sites to access their service or claim benefits : Membership card, Loyalty card, Rewards, etc.", "phoneProofExpirationDate": "This card will remain active and reusable for 1 YEAR.", "phoneProofHowToGetIt": "It’s super easy. Altme will verify your phone number ownership by sending a code by sms.", "tezVoucherWhyGetThisCard": "This Voucher card will give you 10% cash backs on ALL Tezotopia Game transactions when you buy a Drops on the marketplace or mint an NFT on starbase.", @@ -690,7 +690,7 @@ "officialWebsite": "Official website", "yourAppVersion": "Your app version", "resetWalletTitle": "Are you sure you want to reset your wallet ?", - "resetWalletSubtitle": "This action will erase your data. Please, make sure you have saved your Recovery Phrase and credentials backup file before deleting.", + "resetWalletSubtitle": "This action will erase your data. Please, make sure you have saved your recovery phrase and credentials backup file before deleting.", "resetWalletSubtitle2": "This wallet is self-custodial so we are not able to recover your funds or credentials for you.", "resetWalletCheckBox1": "I wrote down my Recovery Phrase", "resetWalletCheckBox2": "I saved my backup credentials file", @@ -726,8 +726,8 @@ "binanceAccountCreationCongratulations": "Your new BNB Chain account has been successfully created.", "accountImportCongratulations": "Your account has been successfully imported.", "saveBackupCredentialTitle": "Download the backup file.\nKeep it in a safe place.", - "saveBackupCredentialSubtitle": "To recover all your credentials you will need the Recovery Phrase AND this backup file.", - "saveBackupPolygonCredentialSubtitle": "To recover all your polygon id credentials you will need the Recovery Phrase AND this backup file.", + "saveBackupCredentialSubtitle": "To recover all your credentials you will need the recovery phrase and this backup file.", + "saveBackupPolygonCredentialSubtitle": "To recover all your polygon id credentials you will need the recovery phrase and this backup file.", "restoreCredentialStep1Title": "Step 1 : Enter your 12 Recovery Phrase words", "restorePhraseTextFieldHint": "Enter your Recovery Phrase (or mnemonic phrase) here...", "restoreCredentialStep2Title": "Step 2 : Upload your credentials backup file", @@ -893,13 +893,13 @@ "authenticationSuccess": "Authentication Success", "format": "Format", "verifyIssuerWebsiteIdentity": "Verify issuer identity", - "verifyIssuerWebsiteIdentitySubtitle": "Enable to verify issuer identity before access. Default: Off.", + "verifyIssuerWebsiteIdentitySubtitle": "Enable to verify issuer identity before access.", "developerMode": "Developer Mode", "developerModeSubtitle": "Enable developer mode to access advanced debugging tools", "confirmVerifierAccess": "Confirm verifier access", - "confirmVerifierAccessSubtitle": "Disable to skip confirmation when you share your verifiable credentials. Default: On.", + "confirmVerifierAccessSubtitle": "Disable to skip confirmation when you share your verifiable credentials.", "secureAuthenticationWithPINCode": "Secure authentication with PIN code", - "secureAuthenticationWithPINCodeSubtitle": "Turn off to skip PIN code for website authentication (not recommended). Default: On.", + "secureAuthenticationWithPINCodeSubtitle": "Disable to skip PIN code for website authentication (not recommended).", "youcanSelectOnlyXCredential": "You can select only {count} credential(s).", "@youcanSelectOnlyXCredential": { "description": "", @@ -952,14 +952,14 @@ "walletProfiles": "Wallet Profile", "walletProfilesDescription": "Choose your wallet profile or customize your own", "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.", + "protectYourWalletMessage": "Use your fingerprint, face, or PIN code to secure and unlock your wallet. Your data is securely encrypted on this device.", "pinUnlock": "PIN unlock", - "secureWithDevicePINOnly": "Secure with Device PIN only", + "secureWithDevicePINOnly": "Secure with PIN code only", "biometricUnlock": "Biometric unlock", "secureWithFingerprint": "Secure with fingerprint or facial recognition", "pinUnlockAndBiometric2FA": "PIN + biometric unlock (2FA)", "secureWithFingerprintAndPINBackup": "Secure with fingerprint or facial recognition + PIN code", - "secureYourWalletWithPINCodeAndBiometrics": "Secure your wallet with PIN code and Biometrics", + "secureYourWalletWithPINCodeAndBiometrics": "Secure your wallet with PIN code and biometrics", "twoFactorAuthenticationHasBeenEnabled": "Two factor authentication has been enabled.", "initialization": "Initialization", "login": "Login", @@ -982,7 +982,7 @@ "continueString": "Continue", "walletProvider": "Wallet Provider", "clientTypeSubtitle": "Switch to change the client type. Default: DID.", - "thisTypeProofCannotBeUsedWithThisVCFormat": "This type proof cannot be used with this VC Format.", + "thisTypeProofCannotBeUsedWithThisVCFormat": "This proof type cannot be used with this VC Format.", "blockchainCardsDiscoverTitle": "Get a proof of crypto account ownership", "blockchainCardsDiscoverSubtitle": "Get a proof of crypto account ownership.", "successfullyAddedEnterpriseAccount": "Successfully added enterprise account!", @@ -1006,9 +1006,9 @@ "theWalletIsSuspended": "The wallet is suspended.", "jwkThumbprintP256Key": "JWK Thumbprint P-256", "walletBlockedPopupTitle": "Blockerd 10 minutes", - "walletBlockedPopupDescription": "Too many failed attempts, your wallet is blocked for your security.\nYou can reset your wallet in order to use servives again.", + "walletBlockedPopupDescription": "Too many failed attempts, your wallet is blocked for your security.\nYou can reset your wallet in order to use it again.", "deleteMyWalletForWrontPincodeTitle": "Account blocked after 3 unsuccessful attempts", - "deleteMyWalletForWrontPincodeDescription": "For your security you must reset you wallet to use our services again.", + "deleteMyWalletForWrontPincodeDescription": "For your security you must reset you wallet to use it again.", "walletBloced": "Account blocked", "deleteMyWallet": "Delete my account", "pincodeRules": "Your secret code can't be a sequence or have 4 identical digit.", @@ -1171,5 +1171,6 @@ } }, "reject": "Reject", - "operation": "Operation" + "operation": "Operation", + "chooseYourSSIProfileOrCustomizeYourOwn": "Choose your SSI profile or customize your own" } diff --git a/lib/l10n/arb/app_fr.arb b/lib/l10n/arb/app_fr.arb index e4bd6fdbe..206d61f83 100644 --- a/lib/l10n/arb/app_fr.arb +++ b/lib/l10n/arb/app_fr.arb @@ -401,7 +401,7 @@ "accountName": "Nom du compte", "importWalletText": "Entrez ici votre phrase de récupération ou votre clé privée.", "importWalletTextRecoveryPhraseOnly": "Saisissez votre phrase de récupération ici.", - "recoveryPhraseDescriptions": "Une phrase de récupération est une liste de 12 mots générés par votre wallet crypto donnant accès à vos actifs", + "recoveryPhraseDescriptions": "Une phrase de récupération est une liste de 12 mots générés par votre crypto wallet donnant accès à vos actifs", "importEasilyFrom": "Importez votre compte depuis :", "templeWallet": "Temple", "temple": "Temple", @@ -686,16 +686,16 @@ "decline": "Refuser", "yotiCameraAppbarTitle": "Rapprochez votre visage au plus près du smartphone avant de prendre la photo", "cameraSubtitle": "Vous avez 5 secondes pour prendre votre photo. Rapprochez votre visage au plus près avant de commencer.", - "walletSecurityDescription": "Protégez votre wallet avec le code PIN et l'authentification biométrique", + "walletSecurityDescription": "Protégez votre wallet avec le code PIN ou l'authentification biométrique et faites une sauvegarde", "blockchainSettings": "Paramètres pour les blockchains", "blockchainSettingsDescription": "Gérez vos comptes, votre phrase de récupération et les dApps", "ssi": "Identité décentralisée (DID)", - "ssiDescription": "Gérez votre identité décentralisée et sauvegardez ou restaurez vos attestations digitales", + "ssiDescription": "Gérez votre identité décentralisée et recherchez des attestations digitales", "helpCenter": "Centre d'aide", "helpCenterDescription": "Contactez-nous, accédez à la documentation ou obtenez de l'aide", "about": "À propos", - "aboutDescription": "En savoir plus sur les conditions générales d'utilisation (CGU), la protection des données et les licences", - "resetWallet": "Réinitialiser le wallet", + "aboutDescription": "En savoir plus sur les conditions générales d'utilisation, la protection des données et les licences", + "resetWallet": "Réinitialisation", "resetWalletDescription": "Effacez les données stockées sur votre téléphone et réinitialisez le wallet", "showWalletRecoveryPhrase": "Afficher la phrase de récupération", "showWalletRecoveryPhraseSubtitle": "La phrase de récupération est nécessaire pour restaurer votre wallet.", @@ -1121,8 +1121,8 @@ "storageFee": "Storage Fee", "doYouWantToSetupTheProfile": "Souhaitez vous paramétrer ce profil", "thisFeatureIsNotSupportedYetForEtherlink": "Cette fonctionalité n'est pas supportée sur Etherlink.", - "walletSecurityAndBackup": "Sécurité et sauvegarde du wallet", - "addedCredential": "Added credential {credential} by {domain}", + "walletSecurityAndBackup": "Sécurité et sauvegarde", + "addedCredential": "Attestation {credential} de {domain} ajoutée", "@addedCredentialDescription": { "description": "name of the credential", "type": "text", @@ -1138,5 +1138,6 @@ } }, "reject": "Rejet", - "operation": "Opération" + "operation": "Opération", + "chooseYourSSIProfileOrCustomizeYourOwn": "Choisissez un écosystème pour votre wallet" } \ No newline at end of file diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index a796d1476..508325a69 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -5,7 +5,8 @@ "keyBindingPayload", "ebsiV4DecentralizedId", "reject", - "operation" + "operation", + "chooseYourSSIProfileOrCustomizeYourOwn" ], "es": [ @@ -14,6 +15,7 @@ "keyBindingPayload", "ebsiV4DecentralizedId", "reject", - "operation" + "operation", + "chooseYourSSIProfileOrCustomizeYourOwn" ] } From ecd300e42b64a2e524509f28cde2809afa5e0f22 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 12 Dec 2024 18:14:57 +0545 Subject: [PATCH 5/6] Pre-select verify later #3184 --- lib/onboarding/gen_phrase/view/onboarding_gen_phrase.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/onboarding/gen_phrase/view/onboarding_gen_phrase.dart b/lib/onboarding/gen_phrase/view/onboarding_gen_phrase.dart index 76b6147ae..5b36291f3 100644 --- a/lib/onboarding/gen_phrase/view/onboarding_gen_phrase.dart +++ b/lib/onboarding/gen_phrase/view/onboarding_gen_phrase.dart @@ -148,7 +148,7 @@ class _OnBoardingGenPhraseViewState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - MyOutlinedButton( + MyElevatedButton( text: l10n.verifyLater, verticalSpacing: 18, onPressed: () async { @@ -161,7 +161,7 @@ class _OnBoardingGenPhraseViewState extends State { }, ), const SizedBox(height: 10), - MyElevatedButton( + MyOutlinedButton( text: l10n.verifyNow, verticalSpacing: 18, onPressed: () { From 2d4bd64a89fd4bfc160caa80260f72d7583b3e32 Mon Sep 17 00:00:00 2001 From: Bibash Shrestha Date: Thu, 12 Dec 2024 19:17:57 +0545 Subject: [PATCH 6/6] version update: 2.18.9+5582 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index a77df902b..bce605568 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: altme description: AltMe Flutter App -version: 2.18.8+5581 +version: 2.18.9+5582 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: