Skip to content

Commit

Permalink
Merge branch 'disclosure_list_issue' into october
Browse files Browse the repository at this point in the history
  • Loading branch information
hawkbee1 committed Aug 24, 2024
2 parents 722cc26 + b8c1b9d commit 5b4d4ae
Show file tree
Hide file tree
Showing 3 changed files with 619 additions and 436 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,356 @@
import 'package:altme/app/shared/extension/iterable_extension.dart';
import 'package:altme/dashboard/home/tab_bar/credentials/models/credential_model/credential_model.dart';
import 'package:altme/dashboard/home/tab_bar/credentials/present/pick/selective_disclosure/cubit/selective_disclosure_pick_cubit.dart';
import 'package:altme/selective_disclosure/selective_disclosure.dart';
import 'package:json_path/json_path.dart';
import 'package:oidc4vc/oidc4vc.dart';

class SelectiveDisclosureDisplayMap {
const SelectiveDisclosureDisplayMap({
required this.credentialModel,
required this.isPresentation,
required this.languageCode,
required this.limitDisclosure,
required this.filters,
required this.isDeveloperMode,
this.claims,
this.parentKeyId,
required this.selectedClaimsKeyIds,
this.onPressed,
});

final CredentialModel credentialModel;
final bool isPresentation;
final String languageCode;
final String limitDisclosure;
final bool isDeveloperMode;
final Map<String, dynamic>? claims;
final String? parentKeyId;
final Map<String, dynamic> filters;
final List<SelectedClaimsKeyIds> selectedClaimsKeyIds;
final void Function(String?, String, String?)? onPressed;

Map<String, dynamic> get buildMap {
final builtMap = <String, dynamic>{};
final selectiveDisclosure = SelectiveDisclosure(credentialModel);
final currentClaims = claims ?? selectiveDisclosure.claims;
currentClaims.forEach((key, value) {
String? title;

final mapKey = key;
final mapValue = value;

if (mapValue is! Map<String, dynamic>) return;

final display = getDisplay(mapKey, mapValue, languageCode);

if (display == null) return;
title = display['name'].toString();

final bool hasNestedData =
mapValue.values.any((element) => element is Map<String, dynamic>);

if (hasNestedData && parentKeyId == null) {
final nestedMap = SelectiveDisclosureDisplayMap(
credentialModel: credentialModel,
claims: mapValue,
isPresentation: isPresentation,
languageCode: languageCode,
limitDisclosure: limitDisclosure,
filters: filters,
parentKeyId: mapKey,
isDeveloperMode: isDeveloperMode,
selectedClaimsKeyIds: selectedClaimsKeyIds,
onPressed: onPressed,
).buildMap;
if (nestedMap.isNotEmpty) {
builtMap[title] = nestedMap;
}
} else {
builtMap.addAll(claimData(mapKey, title));
}
});
final Map<String, dynamic> mapFromJwtEntries = fileterdMapFromJwt(
selectiveDisclosure,
currentClaims,
parentKeyId,
);
builtMap.addAll(mapFromJwtEntries);
return builtMap;
}

Map<String, dynamic> fileterdMapFromJwt(
SelectiveDisclosure selectiveDisclosure,
Map<String, dynamic> currentClaims,
String? parentKeyId,
) {
final builtMap = <String, dynamic>{};
if (!isPresentation && !isDeveloperMode) return builtMap;
for (final disclosure in selectiveDisclosure.disclosureFromJWT) {
/// check if disclosure is in a nested value
/// if so, return empty container
final oidc4vc = OIDC4VC();
final content = selectiveDisclosure.disclosureToContent(disclosure);

final digest = oidc4vc.sh256HashOfContent(
content,
);
final disclosuresContent = Map<String, dynamic>.from(
selectiveDisclosure.disclosureListToContent,
);

if (parentKeyId == null) {
disclosuresContent.removeWhere((key, value) {
if (value is String) {
return !value.contains(digest);
}
return true;
});
if (disclosuresContent.isNotEmpty) continue;

/// Check if the disclosure is nested in a element from payload
/// If so, return empty container, else continue building of the widget
if (isNestedInpayload(selectiveDisclosure.contents, digest)) {
continue;
}
} else {
/// keep going only if element is in the nested value of the parentKeyId
/// either in the payload or the claims
print(parentKeyId);
final nestedValue =
selectiveDisclosure.extractedValuesFromJwt[parentKeyId] ??
SelectiveDisclosure(credentialModel).payload[parentKeyId];
if (nestedValue == null) continue;
bool displayElement = false;
if (nestedValue is String) {
if (nestedValue.contains(digest)) displayElement = true;
}
if (nestedValue is Map) {
final claimList = nestedValue['_sd'];
if (claimList is List) {
if (claimList.contains(digest)) displayElement = true;
}
}
if (!displayElement) continue;
}

/// Check if the disclosure is already displayed in the claims
/// from the display. If so, return empty container, else build the widget
final value = selectiveDisclosure
.contentOfSh256Hash(
content,
)
.entries
.first
.value;

final element = value.entries.first;
if (!currentClaims.containsKey(element.key)) {
if (element.value is Map) {
builtMap.addAll(MapForNestedClaimWithoutDisplay(element));
continue;
}

builtMap.addAll(
claimData(
element.key.toString(),
element.key.toString(),
),
);
}
}
return builtMap;
}

/// can be used in recursive way to get more nested levels
Map<String, dynamic> MapForNestedClaimWithoutDisplay(
dynamic element,
) {
final value = element.value as Map<String, dynamic>;
final builtMap = <String, dynamic>{};
value.remove('_sd');
if (value.isEmpty) {
final mapNestedSelectiveDisclosure = SelectiveDisclosureDisplayMap(
credentialModel: credentialModel,
claims: const {},
isPresentation: isPresentation,
languageCode: languageCode,
limitDisclosure: limitDisclosure,
filters: filters,
parentKeyId: element.key.toString(),
isDeveloperMode: isDeveloperMode,
selectedClaimsKeyIds: selectedClaimsKeyIds,
onPressed: onPressed,
).buildMap;
if (mapNestedSelectiveDisclosure.isNotEmpty) {
builtMap.addAll({
element.key.toString(): mapNestedSelectiveDisclosure,
});
}
} else {
final isCompulsary = limitDisclosure == 'required';

final bool isDisabled = isCompulsary;
if (!isDisabled && isPresentation && parentKeyId != null) {}
builtMap[element.key.toString()] = {
'mapKey': element.key.toString(),
'claimKey': element.key.toString(),
'threeDotValue': null,
'value': value,
'hasCheckbox': !isDisabled && isPresentation,
'isCompulsary': isCompulsary,
};
}

return builtMap;
}

Map<String, dynamic> claimData(String mapKey, String? title) {
final claimDataMap = <String, dynamic>{};
final List<ClaimsData> claimsData =
SelectiveDisclosure(credentialModel).getClaimsData(
key: mapKey,
);

if (claimsData.isEmpty) return claimDataMap;
int index = 0;
for (final element in claimsData) {
var keyToCheck = mapKey;
var claimKey = mapKey;
if (parentKeyId != null) {
keyToCheck = '$parentKeyId-$mapKey';
}
final isFirstElement = index == 0;

if (!isFirstElement) {
keyToCheck = '$keyToCheck-$index';
claimKey = '$claimKey-$index';
}

final isCompulsary = limitDisclosure == 'required';

bool isDisabled = isCompulsary;
final selectedKeyId = selectedClaimsKeyIds
.firstWhereOrNull((ele) => ele.keyId == keyToCheck);

if (isPresentation) {
if (filters.isNotEmpty) {
isDisabled = isCompulsary;

filters.forEach((key, value) {
if (element.threeDotValue != null) {
if (claimKey.contains(key) &&
element.data.replaceAll(' ', '') == value) {
if (isCompulsary) isDisabled = false;
if (selectedKeyId == null) {
onPressed?.call(
key,
claimKey,
element.threeDotValue,
);
}
}
} else {
if (claimKey == key && element.data == value) {
if (isCompulsary) isDisabled = false;
if (selectedKeyId == null) {
onPressed?.call(
key,
claimKey,
null,
);
}
}
}
});
}
}
if (!(isDisabled && isPresentation)) {
final listElement = {
'mapKey': mapKey,
'claimKey': claimKey,
'threeDotValue': element.threeDotValue,
'value': element.data,
'hasCheckbox': !isDisabled && isPresentation,
'isCompulsary': isCompulsary,
};
if (claimsData.length > 1) {
if (index == 0) {
claimDataMap[title ?? mapKey] = {
'value': [listElement],
};
} else {
claimDataMap[title ?? mapKey]['value'].add(listElement);
}
} else {
claimDataMap[title ?? mapKey] = listElement;
}
}
index++;
}
return claimDataMap;
}

dynamic getDisplay(String key, dynamic value, String languageCode) {
if (value is! Map<String, dynamic>) return null;

if (value.isEmpty) return null;

if (value.containsKey('display')) {
final displays = value['display'];
if (displays is! List<dynamic>) return null;
if (displays.isEmpty) return null;

final display = displays.firstWhere(
(element) =>
element is Map<String, dynamic> &&
element.containsKey('locale') &&
element['locale'].toString().contains(languageCode),
orElse: () => displays.firstWhere(
(element) =>
element is Map<String, dynamic> &&
element.containsKey('locale') &&
element['locale'].toString().contains('en'),
orElse: () => displays.firstWhere(
(element) =>
element is Map<String, dynamic> &&
element.containsKey('locale'),
orElse: () => null,
),
),
);

return display;
} else {
return null;
}
}

bool isNestedInpayload(List<String> contents, String digest) {
final payloadSd = SelectiveDisclosure(credentialModel).payload;
final JsonPath dataPathSd = JsonPath(
r'$..["_sd"]',
);
final List<dynamic> listSd = [];
payloadSd.remove('_sd');
dataPathSd.read(payloadSd).forEach((element) {
if (element.value is List) {
listSd.addAll(element.value! as List);
}
});
final payloadThreeDot = SelectiveDisclosure(credentialModel).payload;

final JsonPath dataPathThreeDot = JsonPath(
r'$..["..."]',
);
final List<dynamic> listThreeDot = [];
payloadThreeDot.remove('_sd');
dataPathThreeDot.read(payloadThreeDot).forEach((element) {
if (element.value is String) {
listThreeDot.add(element.value);
}
});

return listSd.contains(digest) || listThreeDot.contains(digest);
}
}
Loading

0 comments on commit 5b4d4ae

Please sign in to comment.