Skip to content

Commit

Permalink
feat: Add statis list cache button and caching for status list #2577
Browse files Browse the repository at this point in the history
  • Loading branch information
bibash28 committed Apr 10, 2024
1 parent e517201 commit d6d09ac
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 35 deletions.
33 changes: 33 additions & 0 deletions lib/app/shared/helper_functions/helper_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1918,3 +1918,36 @@ String? getWalletAddress(CredentialSubjectModel credentialSubjectModel) {
}
return null;
}

Future<String> getCatchedGetData({
required SecureStorageProvider secureStorageProvider,
required String url,
required Map<String, dynamic> headers,
required DioClient client,
}) async {
final cachedData = await secureStorageProvider.get(url);

dynamic response;

if (cachedData == null) {
response = await client.get(url, headers: headers);
final expiry =
DateTime.now().add(const Duration(days: 2)).millisecondsSinceEpoch;

final value = {'expiry': expiry, 'data': response};
await secureStorageProvider.set(url, jsonEncode(value));
} else {
final cachedDataJson = jsonDecode(cachedData);
final expiry = int.parse(cachedDataJson['expiry'].toString());

final isExpired = DateTime.now().millisecondsSinceEpoch > expiry;

if (isExpired) {
response = await client.get(url, headers: headers);
} else {
response = await cachedDataJson['data'];
}
}

return response.toString();
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Oidc4vcSettingMenuView extends StatelessWidget {
const ProofTypeWidget(),
const ProofHeaderWidget(),
const PushAuthorizationRequesWidget(),
const StatusListCachingWidget(),
DrawerItem(
title: l10n.walletMetadataForIssuers,
onTap: () {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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 StatusListCachingWidget extends StatelessWidget {
const StatusListCachingWidget({super.key});

@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return BlocBuilder<ProfileCubit, ProfileState>(
builder: (context, state) {
return OptionContainer(
title: l10n.statusListCachingTitle,
subtitle: l10n.statusListCachingSubTitle,
body: Switch(
onChanged: (value) async {
await context.read<ProfileCubit>().updateProfileSetting(
statusListCaching: value,
);
},
value: state.model.profileSetting.selfSovereignIdentityOptions
.customOidc4vcProfile.statusListCache,
activeColor: Theme.of(context).colorScheme.primary,
),
);
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export 'proof_type_widget.dart';
export 'push_authorization_request.dart';
export 'scope_parameter.dart';
export 'security_level_widget.dart';
export 'status_list_caching_widget.dart';
export 'vc_format_widget.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -116,20 +116,25 @@ class CredentialDetailsCubit extends Cubit<CredentialDetailsState> {
final idx = statusList['idx'];

if (idx != null && idx is int && uri != null && uri is String) {
final dynamic response = await client.get(
uri,
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'accept': 'application/statuslist+jwt',
},
final headers = {
'Content-Type': 'application/json; charset=UTF-8',
'accept': 'application/statuslist+jwt',
};

final String response = await getCatchedGetData(
secureStorageProvider: secureStorageProvider,
url: uri,
headers: headers,
client: client,
);
final payload = jwtDecode.parseJwt(response.toString());

final payload = jwtDecode.parseJwt(response);

/// verify the signature of the VC with the kid of the JWT
final VerificationType isVerified = await verifyEncodedData(
issuer: payload['iss']?.toString() ?? item.issuer,
jwtDecode: jwtDecode,
jwt: response.toString(),
jwt: response,
);

if (isVerified != VerificationType.verified) {
Expand Down Expand Up @@ -187,21 +192,26 @@ class CredentialDetailsCubit extends Cubit<CredentialDetailsState> {
if (iteratedData is Map<String, dynamic>) {
final data = CredentialStatusField.fromJson(iteratedData);

final dynamic response = await client.get(
data.statusListCredential,
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'accept': 'application/statuslist+jwt',
},
final url = data.statusListCredential;
final headers = {
'Content-Type': 'application/json; charset=UTF-8',
'accept': 'application/statuslist+jwt',
};

final String response = await getCatchedGetData(
secureStorageProvider: secureStorageProvider,
url: url,
headers: headers,
client: client,
);

final payload = jwtDecode.parseJwt(response.toString());
final payload = jwtDecode.parseJwt(response);

// verify the signature of the VC with the kid of the JWT
final VerificationType isVerified = await verifyEncodedData(
issuer: payload['iss']?.toString() ?? item.issuer,
jwtDecode: jwtDecode,
jwt: response.toString(),
jwt: response,
);

if (isVerified != VerificationType.verified) {
Expand Down
2 changes: 2 additions & 0 deletions lib/dashboard/profile/cubit/profile_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ class ProfileCubit extends Cubit<ProfileState> {
ProofHeaderType? proofHeaderType,
ProofType? proofType,
bool? pushAuthorizationRequest,
bool? statusListCaching,
}) async {
final profileModel = state.model.copyWith(
profileSetting: state.model.profileSetting.copyWith(
Expand Down Expand Up @@ -429,6 +430,7 @@ class ProfileCubit extends Cubit<ProfileState> {
vcFormatType: vcFormatType,
proofType: proofType,
pushAuthorizationRequest: pushAuthorizationRequest,
statusListCache: statusListCaching,
),
),
),
Expand Down
20 changes: 5 additions & 15 deletions lib/dashboard/profile/models/profile_setting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ class CustomOidc4VcProfile extends Equatable {
this.proofHeader = ProofHeaderType.kid,
this.proofType = ProofType.jwt,
this.pushAuthorizationRequest = false,
this.statusListCache = true,
});

factory CustomOidc4VcProfile.initial() => CustomOidc4VcProfile(
Expand Down Expand Up @@ -570,16 +571,12 @@ 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;
final ProofHeaderType proofHeader;
final bool securityLevel;
final bool statusListCache;
final bool pushAuthorizationRequest;
final SIOPV2DraftType siopv2Draft;
@JsonKey(name: 'subjectSyntaxeType')
Expand All @@ -590,16 +587,6 @@ class CustomOidc4VcProfile extends Equatable {

Map<String, dynamic> 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 Exception();
}
}

CustomOidc4VcProfile copyWith({
ClientAuthentication? clientAuthentication,
bool? credentialManifestSupport,
Expand All @@ -612,6 +599,7 @@ class CustomOidc4VcProfile extends Equatable {
bool? scope,
ProofHeaderType? proofHeader,
bool? securityLevel,
bool? statusListCache,
bool? pushAuthorizationRequest,
SIOPV2DraftType? siopv2Draft,
ClientType? clientType,
Expand All @@ -629,6 +617,7 @@ class CustomOidc4VcProfile extends Equatable {
scope: scope ?? this.scope,
proofHeader: proofHeader ?? this.proofHeader,
securityLevel: securityLevel ?? this.securityLevel,
statusListCache: statusListCache ?? this.statusListCache,
pushAuthorizationRequest:
pushAuthorizationRequest ?? this.pushAuthorizationRequest,
siopv2Draft: siopv2Draft ?? this.siopv2Draft,
Expand All @@ -652,6 +641,7 @@ class CustomOidc4VcProfile extends Equatable {
scope,
proofHeader,
securityLevel,
statusListCache,
pushAuthorizationRequest,
siopv2Draft,
clientType,
Expand Down
4 changes: 3 additions & 1 deletion lib/l10n/arb/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1051,5 +1051,7 @@
"statusIsInvalid": "Status is invalid",
"statuslListSignatureFailed": "Status list signature failed",
"walletMetadataForIssuers": "Wallet metadata for issuers",
"walletMetadataForVerifiers": "Wallet metadata for verifiers"
"walletMetadataForVerifiers": "Wallet metadata for verifiers",
"statusListCachingTitle": "StatusList caching",
"statusListCachingSubTitle": "Default: On\nSwitch off to reload StatusList when needed"
}
12 changes: 9 additions & 3 deletions lib/l10n/untranslated.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
"statusIsInvalid",
"statuslListSignatureFailed",
"walletMetadataForIssuers",
"walletMetadataForVerifiers"
"walletMetadataForVerifiers",
"statusListCachingTitle",
"statusListCachingSubTitle"
],

"es": [
Expand All @@ -40,7 +42,9 @@
"statusIsInvalid",
"statuslListSignatureFailed",
"walletMetadataForIssuers",
"walletMetadataForVerifiers"
"walletMetadataForVerifiers",
"statusListCachingTitle",
"statusListCachingSubTitle"
],

"fr": [
Expand All @@ -52,6 +56,8 @@
"statusIsInvalid",
"statuslListSignatureFailed",
"walletMetadataForIssuers",
"walletMetadataForVerifiers"
"walletMetadataForVerifiers",
"statusListCachingTitle",
"statusListCachingSubTitle"
]
}

0 comments on commit d6d09ac

Please sign in to comment.