Skip to content

Commit

Permalink
feat: Manage statuslist 2021 for different formats #2255 #2570
Browse files Browse the repository at this point in the history
  • Loading branch information
bibash28 committed Apr 8, 2024
1 parent 8cc5ec5 commit b917ab3
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,11 @@ class CredentialDetailsCubit extends Cubit<CredentialDetailsState> {
'accept': 'application/statuslist+jwt',
},
);
final payload = jwtDecode.parseJwt(response.toString());

/// verify the signature of the VC with the kid of the JWT
final VerificationType isVerified = await verifyEncodedData(
issuer: item.issuer,
issuer: payload['iss']?.toString() ?? item.issuer,
jwtDecode: jwtDecode,
jwt: response.toString(),
);
Expand All @@ -142,7 +143,6 @@ class CredentialDetailsCubit extends Cubit<CredentialDetailsState> {
return;
}

final payload = jwtDecode.parseJwt(response.toString());
final newStatusList = payload['status_list'];
if (newStatusList != null &&
newStatusList is Map<String, dynamic>) {
Expand All @@ -155,7 +155,7 @@ class CredentialDetailsCubit extends Cubit<CredentialDetailsState> {
profileCubit.oidc4vc.decodeAndZlibDecompress(lst);
final byteToCheck = decompressedBytes[bytes];

final posOfBit = profileCubit.oidc4vc.getPositionOfBit(idx);
final posOfBit = profileCubit.oidc4vc.getPositionOfZlibBit(idx);
final bit = profileCubit.oidc4vc
.getBit(byte: byteToCheck, bitPosition: posOfBit);

Expand All @@ -177,6 +177,84 @@ class CredentialDetailsCubit extends Cubit<CredentialDetailsState> {
}
}

if (item.format == VCFormatType.jwtVc.value ||
item.format == VCFormatType.jwtVcJson.value ||
item.format == VCFormatType.ldpVc.value) {
final credentialStatus = item.credentialPreview.credentialStatus;
if (credentialStatus != null) {
if (credentialStatus is List<dynamic>) {
for (final iteratedData in credentialStatus) {
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 payload = jwtDecode.parseJwt(response.toString());

// 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(),
);

if (isVerified != VerificationType.verified) {
emit(
state.copyWith(
credentialStatus:
CredentialStatus.statusListInvalidSignature,
status: AppStatus.idle,
),
);
return;
}

final vc = payload['vc'];
if (vc != null && vc is Map<String, dynamic>) {
final credentialSubject = vc['credentialSubject'];
if (credentialSubject != null &&
credentialSubject is Map<String, dynamic>) {
final encodedList = credentialSubject['encodedList'];

if (encodedList != null && encodedList is String) {
final decompressedBytes = profileCubit.oidc4vc
.decodeAndGzibDecompress(encodedList);

final idx = int.parse(data.statusListIndex);
final bytes = profileCubit.oidc4vc.getByte(idx);
final byteToCheck = decompressedBytes[bytes];
final posOfBit =
profileCubit.oidc4vc.getPositionOfGZipBit(idx);
final bit = profileCubit.oidc4vc
.getBit(byte: byteToCheck, bitPosition: posOfBit);

if (bit == 0) {
// active
} else {
// revoked
emit(
state.copyWith(
credentialStatus: CredentialStatus.invalidStatus,
status: AppStatus.idle,
),
);
return;
}
}
}
}
}
}
}
}
}

if (item.jwt != null) {
final jwt = item.jwt!;
final Map<String, dynamic> payload = jwtDecode.parseJwt(jwt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Credential {
CredentialSubjectModel? credentialSubjectModel,
List<Translation>? description,
List<Translation>? name,
CredentialStatusField? credentialStatus,
dynamic credentialStatus,
List<Evidence>? evidence,
}) {
return Credential(
Expand Down
4 changes: 2 additions & 2 deletions lib/dashboard/profile/models/profile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class ProfileModel extends Equatable {
oidc4vciDraft: OIDC4VCIDraftType.draft11,
oidc4vpDraft: OIDC4VPDraftType.draft10,
scope: false,
securityLevel: false,
securityLevel: true,
proofHeader: ProofHeaderType.kid,
siopv2Draft: SIOPV2DraftType.draft12,
clientType: ClientType.did,
Expand Down Expand Up @@ -177,7 +177,7 @@ class ProfileModel extends Equatable {
oidc4vciDraft: OIDC4VCIDraftType.draft13,
oidc4vpDraft: OIDC4VPDraftType.draft10,
scope: false,
securityLevel: false,
securityLevel: true,
proofHeader: ProofHeaderType.kid,
siopv2Draft: SIOPV2DraftType.draft12,
clientType: ClientType.did,
Expand Down
15 changes: 14 additions & 1 deletion packages/oidc4vc/lib/src/oidc4vc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,7 @@ class OIDC4VC {
}

late final bool isVerified;

if (kty == 'OKP') {
isVerified = verifyTokenEdDSA(
publicKey: publicKeyJwk,
Expand Down Expand Up @@ -1621,7 +1622,9 @@ class OIDC4VC {
return hash;
}

int getPositionOfBit(int index) => index % 8;
int getPositionOfZlibBit(int index) => index % 8;

int getPositionOfGZipBit(int index) => 7 - (index % 8);

int getByte(int index) => index ~/ 8;

Expand All @@ -1645,4 +1648,14 @@ class OIDC4VC {

return decompressedBytes;
}

List<int> decodeAndGzibDecompress(String lst) {
final paddedBase64 = lst.padRight((lst.length + 3) & ~3, '=');
final compressedBytes = base64Url.decode(paddedBase64);

final gzib = GZipCodec();
final decompressedBytes = gzib.decode(compressedBytes);

return decompressedBytes;
}
}

0 comments on commit b917ab3

Please sign in to comment.