Skip to content

Commit

Permalink
fix: implementing JWT Revocation.
Browse files Browse the repository at this point in the history
Signed-off-by: Francisco Javier Ribó Labrador <elribonazo@gmail.com>
  • Loading branch information
elribonazo committed May 6, 2024
1 parent 28d2358 commit 78b6100
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 7 deletions.
15 changes: 12 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"@types/google-protobuf": "^3.15.6",
"@types/jest": "^29.5.5",
"@types/node": "^18.14.2",
"@types/pako": "^2.0.3",
"@types/sinon": "^10.0.13",
"@types/sinon-chai": "^3.2.9",
"@types/uuid": "^9.0.1",
Expand Down Expand Up @@ -202,6 +203,7 @@
"jose": "^4.15.5",
"jsonwebtoken": "^9.0.0",
"multiformats": "^9.9.0",
"pako": "^2.1.0",
"rxdb": "^14.17.1",
"text-encoding": "^0.7.0",
"util": "^0.12.5",
Expand Down
58 changes: 54 additions & 4 deletions src/domain/models/VerifiableCredential.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ export enum DescriptorItemFormat {
}

export enum W3CVerifiableCredentialContext {
credential = "https://www.w3.org/2018/credentials/v1"
credential = "https://www.w3.org/2018/credentials/v1",
revocation = "https://w3id.org/vc/status-list/2021/v1"
}

export enum W3CVerifiableCredentialType {
presentation = "VerifiablePresentation",
credential = "VerifiableCredential"
credential = "VerifiableCredential",
revocation = "StatusList2021Credential"
}


Expand Down Expand Up @@ -171,9 +173,57 @@ export type W3CVerifiableCredential = {
id: string,
type: string
},
credentialStatus?: {
credentialStatus?: JWTRevocationStatus | unknown
}

export interface W3CVerifiableCredentialData {
id: string,
type: string
}


export enum JWTRevocationStatusPurpose {
Revocation = "Revocation",
Suspension = 'Suspension'
}

export enum RevocationType {
StatusList2021Entry = 'StatusList2021Entry'
}

export interface JWTRevocationStatus extends W3CVerifiableCredentialData {
statusPurpose: JWTRevocationStatusPurpose,
statusListIndex: number,
id: string,
type: RevocationType,
statusListCredential: string
}

export interface JWTStatusListResponse {
"@context": [
W3CVerifiableCredentialContext.credential,
W3CVerifiableCredentialContext.revocation
],
type: [
W3CVerifiableCredentialType.credential,
W3CVerifiableCredentialType.revocation
],
issuer: string,
id: string,
issuanceDate: string,
credentialSubject: {
id: string,
type: string
type: string,
statusPurpose: string,
encodedList: string
},
proof: {
type: string,
proofPurpose: string,
verificationMethod: string,
created: string,
proofValue: string,
cryptoSuite: string
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/domain/models/errors/Pollux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ export class InvalidPresentationProofArgs extends Error {
}
}

export class CredentialRevocationTypeInvalid extends Error {
constructor(message?: string) {
super(message || "CredentialStatus revocation type not supported");
}
}

export class CredentialTypeNotSupported extends Error {
constructor(message?: string) {
super(message || "Credential type not supported");
Expand Down
43 changes: 43 additions & 0 deletions src/pollux/Pollux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Castor } from "../domain/buildingBlocks/Castor";
import { Pollux as IPollux } from "../domain/buildingBlocks/Pollux";
import { base64 } from "multiformats/bases/base64";
import { AnoncredsLoader } from "./AnoncredsLoader";
import pako from 'pako';

import {
AttachmentDescriptor,
Expand Down Expand Up @@ -31,6 +32,9 @@ import {
JWTPresentationPayload,
AttachmentFormats,
PresentationOptions,
JWTRevocationStatus,
RevocationType,
JWTStatusListResponse,
} from "../domain";

import { AnonCredsCredential } from "./models/AnonCredsVerifiableCredential";
Expand All @@ -42,6 +46,7 @@ import { Secp256k1PrivateKey } from "../apollo/utils/Secp256k1PrivateKey";
import { DescriptorPath } from "./utils/DescriptorPath";
import { JWT } from "./utils/JWT";
import { InvalidVerifyCredentialError, InvalidVerifyFormatError } from "../domain/models/errors/Pollux";
import { HttpStatusCode } from "axios";

/**
* Implementation of Pollux
Expand All @@ -59,6 +64,44 @@ export default class Pollux implements IPollux {
private jwt = new JWT(castor)
) { }

extractVerificationStatus(credentialStatus: any): credentialStatus is JWTRevocationStatus {
const type = credentialStatus.type;
if (typeof type === "string" && credentialStatus.type === RevocationType.StatusList2021Entry) {
return true;
}
return false;
}

extractEncodedList(body: JWTStatusListResponse): Uint8Array {
const encodedList = Buffer.from(body.credentialSubject.encodedList, 'base64');
return pako.ungzip(encodedList);
}

async isCredentialRevoked(credential: Credential): Promise<boolean> {
if (credential instanceof JWTCredential) {
if (!this.extractVerificationStatus(credential.credentialStatus)) {
throw new PolluxError.CredentialRevocationTypeInvalid()
}
const revocationStatus = credential.credentialStatus;
const response = await this.api.request<JWTStatusListResponse>(
"GET",
revocationStatus.statusListCredential,
new Map(),
new Map(),
null
)
if (response.httpStatus !== HttpStatusCode.Ok) {
throw new PolluxError.CredentialRevocationTypeInvalid()
}
const list = this.extractEncodedList(response.body);
if (list[revocationStatus.statusListIndex] === 1) {
return true;
}
return false
}
throw new PolluxError.CredentialTypeNotSupported()
}

async createPresentationSubmission(
presentationDefinitionRequest: PresentationDefinitionRequest,
credential: Credential,
Expand Down

0 comments on commit 78b6100

Please sign in to comment.