diff --git a/lib/app/shared/helper_functions/helper_functions.dart b/lib/app/shared/helper_functions/helper_functions.dart index fafe47548..024e4f382 100644 --- a/lib/app/shared/helper_functions/helper_functions.dart +++ b/lib/app/shared/helper_functions/helper_functions.dart @@ -5,14 +5,13 @@ import 'package:altme/app/app.dart'; import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/oidc4vc/oidc4vc.dart'; import 'package:altme/selective_disclosure/selective_disclosure.dart'; +import 'package:asn1lib/asn1lib.dart' as asn1lib; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:convert/convert.dart'; import 'package:credential_manifest/credential_manifest.dart'; - import 'package:dartez/dartez.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:dio/dio.dart'; - import 'package:fast_base58/fast_base58.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:intl/intl.dart'; @@ -23,8 +22,6 @@ import 'package:key_generator/key_generator.dart'; import 'package:oidc4vc/oidc4vc.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:secure_storage/secure_storage.dart'; -import 'package:pointycastle/pointycastle.dart' as pc; -import 'package:asn1lib/asn1lib.dart' as asn1lib; import 'package:x509/x509.dart' as x509; String generateDefaultAccountName( @@ -1661,7 +1658,6 @@ List getStringCredentialsForToken({ /// jwt_vc presentJwtVc = format?.jwtVc != null || format?.jwtVp != null; - ; /// jwt_vc_json presentJwtVcJson = format?.jwtVcJson != null || format?.jwtVpJson != null; 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 25610d33c..5a1618ee3 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 @@ -145,9 +145,6 @@ class _CredentialsDetailsViewState extends State { .customOidc4vcProfile .credentialManifestSupport; - final isSecure = profileData.profileSetting.selfSovereignIdentityOptions - .customOidc4vcProfile.securityLevel; - final credentialSupported = widget.credentialModel.credentialSupported; final claims = credentialSupported?['claims']; diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart index 3bc160cb8..133b371cb 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/credential_manifest/view/credential_manifest_credential_offer_pick_page.dart @@ -214,10 +214,13 @@ class CredentialManifestOfferPickView extends StatelessWidget { .filteredCredentialList[ credentialManifestState .selected.first], + presentationDefinition: + presentationDefinition, ), ), - /// next button because we will now choose the claims we will present + /// next button because we will now choose + /// the claims we will present /// from the selected credential text: l10n.next, ) diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/cubit/selective_disclosure_pick_cubit.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/cubit/selective_disclosure_pick_cubit.dart index d7e2ec025..fc9551688 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/cubit/selective_disclosure_pick_cubit.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/cubit/selective_disclosure_pick_cubit.dart @@ -1,6 +1,7 @@ import 'package:altme/app/shared/shared.dart'; import 'package:altme/dashboard/home/home.dart'; import 'package:altme/selective_disclosure/selective_disclosure.dart'; +import 'package:credential_manifest/credential_manifest.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:json_annotation/json_annotation.dart'; @@ -16,6 +17,41 @@ class SelectiveDisclosureCubit extends Cubit { final OIDC4VC oidc4vc; + void dataFromPresentation({ + required CredentialModel credentialModel, + required PresentationDefinition? presentationDefinition, + }) { + String? limitDisclosure; + final json = {}; + + if (presentationDefinition != null) { + final selectiveDisclosure = SelectiveDisclosure(credentialModel); + + final credentialData = createJsonByDecryptingSDValues( + encryptedJson: credentialModel.data, + selectiveDisclosure: selectiveDisclosure, + ); + + for (final inputDescriptor in presentationDefinition.inputDescriptors) { + final filterList = inputDescriptor.constraints?.fields ?? []; + + limitDisclosure = inputDescriptor.constraints?.limitDisclosure; + + for (final field in filterList) { + for (final path in field.path) { + final searchList = getTextsFromCredential(path, credentialData); + for (final element in searchList) { + final key = path.split('.').toList().last; + json[key] = element; + } + } + } + } + + emit(state.copyWith(limitDisclosure: limitDisclosure, filters: json)); + } + } + void toggle(String claimKeyId) { final List selectedClaimsKeys = List.of(state.selectedClaimsKeyIds); @@ -82,4 +118,18 @@ class SelectiveDisclosureCubit extends Cubit { } emit(state.copyWith(selectedSDIndexInJWT: selected)); } + + void disclosureAction({ + required String claimKeyId, + required CredentialModel credentialModel, + String? threeDotValue, + String? claimsKey, + }) { + toggle(claimKeyId); + saveIndexOfSDJWT( + claimsKey: claimsKey, + credentialModel: credentialModel, + threeDotValue: threeDotValue, + ); + } } diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/cubit/selective_disclosure_pick_state.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/cubit/selective_disclosure_pick_state.dart index f8f7c5c6f..fdc94693a 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/cubit/selective_disclosure_pick_state.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/cubit/selective_disclosure_pick_state.dart @@ -6,6 +6,8 @@ class SelectiveDisclosureState extends Equatable { this.message, this.selectedClaimsKeyIds = const [], this.selectedSDIndexInJWT = const [], + this.limitDisclosure, + this.filters, }); factory SelectiveDisclosureState.fromJson(Map json) => @@ -14,15 +16,21 @@ class SelectiveDisclosureState extends Equatable { final StateMessage? message; final List selectedClaimsKeyIds; final List selectedSDIndexInJWT; + final String? limitDisclosure; + final Map? filters; SelectiveDisclosureState copyWith({ List? selectedClaimsKeyIds, List? selectedSDIndexInJWT, StateMessage? message, + String? limitDisclosure, + Map? filters, }) { return SelectiveDisclosureState( selectedClaimsKeyIds: selectedClaimsKeyIds ?? this.selectedClaimsKeyIds, selectedSDIndexInJWT: selectedSDIndexInJWT ?? this.selectedSDIndexInJWT, + limitDisclosure: limitDisclosure ?? this.limitDisclosure, + filters: filters ?? this.filters, message: message, ); } @@ -34,5 +42,7 @@ class SelectiveDisclosureState extends Equatable { selectedClaimsKeyIds, selectedSDIndexInJWT, message, + limitDisclosure, + filters, ]; } diff --git a/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/view/selective_disclosure_pick_page.dart b/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/view/selective_disclosure_pick_page.dart index dc3e0ec13..e04e17a05 100644 --- a/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/view/selective_disclosure_pick_page.dart +++ b/lib/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/view/selective_disclosure_pick_page.dart @@ -6,6 +6,7 @@ import 'package:altme/l10n/l10n.dart'; import 'package:altme/scan/cubit/scan_cubit.dart'; import 'package:altme/selective_disclosure/selective_disclosure.dart'; import 'package:altme/selective_disclosure/widget/display_selective_disclosure.dart'; +import 'package:credential_manifest/credential_manifest.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:oidc4vc/oidc4vc.dart'; @@ -17,18 +18,21 @@ class SelectiveDisclosurePickPage extends StatelessWidget { required this.credential, required this.issuer, required this.credentialToBePresented, + required this.presentationDefinition, }); final Uri uri; final CredentialModel credential; final Issuer issuer; final CredentialModel credentialToBePresented; + final PresentationDefinition? presentationDefinition; static Route route({ required Uri uri, required CredentialModel credential, required Issuer issuer, required CredentialModel credentialToBePresented, + required PresentationDefinition? presentationDefinition, }) { return MaterialPageRoute( builder: (context) => SelectiveDisclosurePickPage( @@ -36,6 +40,7 @@ class SelectiveDisclosurePickPage extends StatelessWidget { credential: credential, issuer: issuer, credentialToBePresented: credentialToBePresented, + presentationDefinition: presentationDefinition, ), settings: const RouteSettings(name: '/SelectiveDisclosurePickPage'), ); @@ -52,24 +57,45 @@ class SelectiveDisclosurePickPage extends StatelessWidget { credential: credential, issuer: issuer, credentialToBePresented: credentialToBePresented, + presentationDefinition: presentationDefinition, ), ); } } -class SelectiveDisclosurePickView extends StatelessWidget { +class SelectiveDisclosurePickView extends StatefulWidget { const SelectiveDisclosurePickView({ super.key, required this.uri, required this.credential, required this.issuer, required this.credentialToBePresented, + required this.presentationDefinition, }); final Uri uri; final CredentialModel credential; final Issuer issuer; final CredentialModel credentialToBePresented; + final PresentationDefinition? presentationDefinition; + + @override + State createState() => + _SelectiveDisclosurePickViewState(); +} + +class _SelectiveDisclosurePickViewState + extends State { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + context.read().dataFromPresentation( + credentialModel: widget.credentialToBePresented, + presentationDefinition: widget.presentationDefinition, + ); + }); + } @override Widget build(BuildContext context) { @@ -95,7 +121,7 @@ class SelectiveDisclosurePickView extends StatelessWidget { context.read().state.model.profileSetting; final credentialImage = - SelectiveDisclosure(credentialToBePresented).getPicture; + SelectiveDisclosure(widget.credentialToBePresented).getPicture; return BasePage( title: l10n.thisOrganisationRequestsThisInformation, @@ -111,22 +137,22 @@ class SelectiveDisclosurePickView extends StatelessWidget { PictureDisplay(credentialImage: credentialImage) else CredentialDisplay( - credentialModel: credentialToBePresented, + credentialModel: widget.credentialToBePresented, credDisplayType: CredDisplayType.List, profileSetting: profileSetting, isDiscover: false, ), const SizedBox(height: 20), DisplaySelectiveDisclosure( - credentialModel: credentialToBePresented, + credentialModel: widget.credentialToBePresented, claims: null, - selectedClaimsKeyIds: state.selectedClaimsKeyIds, + selectiveDisclosureState: state, onPressed: (claimKey, claimKeyId, threeDotValue) { - context.read().toggle(claimKeyId); - context.read().saveIndexOfSDJWT( + context.read().disclosureAction( claimsKey: claimKey, - credentialModel: credentialToBePresented, + credentialModel: widget.credentialToBePresented, threeDotValue: threeDotValue, + claimKeyId: claimKeyId, ); }, showVertically: true, @@ -142,7 +168,7 @@ class SelectiveDisclosurePickView extends StatelessWidget { onPressed: () => present( context: context, selectedSDIndexInJWT: state.selectedSDIndexInJWT, - uri: uri, + uri: widget.uri, ), text: l10n.credentialPickPresent, ), @@ -184,7 +210,7 @@ class SelectiveDisclosurePickView extends StatelessWidget { } } - final encryptedValues = credentialToBePresented.jwt + final encryptedValues = widget.credentialToBePresented.jwt ?.split('~') .where((element) => element.isNotEmpty) .toList(); @@ -244,17 +270,17 @@ class SelectiveDisclosurePickView extends StatelessWidget { newJwt = '$newJwt$jwtToken'; - final CredentialModel newModel = - credentialToBePresented.copyWith(selectiveDisclosureJwt: newJwt); + final CredentialModel newModel = widget.credentialToBePresented + .copyWith(selectiveDisclosureJwt: newJwt); final credToBePresented = [newModel]; await context.read().credentialOfferOrPresent( uri: uri, - credentialModel: credential, + credentialModel: widget.credential, keyId: SecureStorageKeys.ssiKey, credentialsToBePresented: credToBePresented, - issuer: issuer, + issuer: widget.issuer, qrCodeScanCubit: context.read(), ); } else { diff --git a/lib/selective_disclosure/selective_disclosure.dart b/lib/selective_disclosure/selective_disclosure.dart index d274f21d7..a731505ea 100644 --- a/lib/selective_disclosure/selective_disclosure.dart +++ b/lib/selective_disclosure/selective_disclosure.dart @@ -168,9 +168,7 @@ class SelectiveDisclosure { } } - List getClaimsData({ - required String key, - }) { + List getClaimsData({required String key}) { dynamic data; final value = []; final JsonPath dataPath = JsonPath( diff --git a/lib/selective_disclosure/widget/display_selective_disclosure.dart b/lib/selective_disclosure/widget/display_selective_disclosure.dart index 0314a1a6f..eed3b9ee0 100644 --- a/lib/selective_disclosure/widget/display_selective_disclosure.dart +++ b/lib/selective_disclosure/widget/display_selective_disclosure.dart @@ -1,5 +1,5 @@ import 'package:altme/app/app.dart'; -import 'package:altme/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart'; +import 'package:altme/dashboard/dashboard.dart'; import 'package:altme/lang/cubit/lang_cubit.dart'; import 'package:altme/selective_disclosure/selective_disclosure.dart'; import 'package:altme/theme/theme.dart'; @@ -13,7 +13,7 @@ class DisplaySelectiveDisclosure extends StatelessWidget { required this.showVertically, this.claims, this.onPressed, - this.selectedClaimsKeyIds, + this.selectiveDisclosureState, this.parentKeyId, }); @@ -21,7 +21,8 @@ class DisplaySelectiveDisclosure extends StatelessWidget { final bool showVertically; final Map? claims; final void Function(String?, String, String?)? onPressed; - final List? selectedClaimsKeyIds; + final SelectiveDisclosureState? selectiveDisclosureState; + final String? parentKeyId; @override @@ -87,7 +88,7 @@ class DisplaySelectiveDisclosure extends StatelessWidget { credentialModel: credentialModel, claims: value, showVertically: showVertically, - selectedClaimsKeyIds: selectedClaimsKeyIds, + selectiveDisclosureState: selectiveDisclosureState, parentKeyId: key, onPressed: (nestedKey, _, threeDotValue) { onPressed?.call( @@ -127,9 +128,41 @@ class DisplaySelectiveDisclosure extends StatelessWidget { claimKey = '$claimKey-$index'; } + bool? disable; + + if (selectiveDisclosureState != null) { + final limitDisclosure = + selectiveDisclosureState!.limitDisclosure; + + if (limitDisclosure != null) { + final filters = selectiveDisclosureState!.filters; + if (filters != null) { + if (limitDisclosure == 'required') { + disable = true; + + filters.forEach((key, value) { + if (claims.threeDotValue != null) { + if (claimKey.contains(key) && + claims.data.replaceAll(' ', '') == value) { + disable = false; + } + } else { + if (claimKey == key && claims.data == value) { + disable = false; + } + } + }); + } + } + } + } + return TransparentInkWell( - onTap: () => - onPressed?.call(key, claimKey, claims.threeDotValue), + onTap: () { + if (disable != null && disable!) return; + + onPressed?.call(key, claimKey, claims.threeDotValue); + }, child: Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ @@ -141,17 +174,23 @@ class DisplaySelectiveDisclosure extends StatelessWidget { valueColor: Theme.of(context).colorScheme.valueColor, showVertically: showVertically, ), - if (selectedClaimsKeyIds != null && + if (selectiveDisclosureState != null && claims.isfromDisclosureOfJWT) ...[ const Spacer(), Padding( padding: const EdgeInsets.only(top: 0, right: 10), child: Icon( - selectedClaimsKeyIds!.contains(keyToCheck) + selectiveDisclosureState!.selectedClaimsKeyIds + .contains(keyToCheck) ? Icons.check_box : Icons.check_box_outline_blank, size: 25, - color: Theme.of(context).colorScheme.onPrimary, + color: disable != null && disable! + ? Theme.of(context) + .colorScheme + .lightGrey + .withOpacity(0.2) + : Theme.of(context).colorScheme.onPrimary, ), ), ],