-
Notifications
You must be signed in to change notification settings - Fork 200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support w3c revocation #2024
base: main
Are you sure you want to change the base?
feat: support w3c revocation #2024
Conversation
Signed-off-by: KulkarniShashank <[email protected]>
|
Signed-off-by: KulkarniShashank <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this! Left some comments
@@ -265,6 +304,52 @@ export class W3cJsonLdCredentialService { | |||
challenge: options.challenge, | |||
domain: options.domain, | |||
documentLoader: this.w3cCredentialsModuleConfig.documentLoader(agentContext), | |||
checkStatus: async ({ credential }: { credential: W3cJsonCredential }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you extract this into a method and reuse that for both checkStatus methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@TimoGlastra I have developed a common function for this purpose. However, in the checkStatus method, there are specific conditions related to credential status that are dependent on the payload received from the verifyCredential and verifyPresentation functions. Therefore, the checkStatus method invokes the common function, as it contains the identical logic.
const encodedBitString = bitStringCredential.credential.credentialSubject.encodedList | ||
const compressedBuffer = Uint8Array.from(atob(encodedBitString), (c) => c.charCodeAt(0)) | ||
|
||
// Decompress using pako | ||
const decodedBitString = pako.ungzip(compressedBuffer, { to: 'string' }) | ||
const statusListIndex = Number(credential.credentialStatus.statusListIndex) | ||
|
||
if (statusListIndex < 0 || statusListIndex >= decodedBitString.length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should validate the bitstring status list credential as well
credentialStatus?: SingleOrArray<CredentialStatus> | ||
} | ||
|
||
type CredentialStatusType = 'BitstringStatusListEntry' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move all the status list logic related to bit string status list to a separate file?
throw new CredoError('Invalid credential status format') | ||
} | ||
|
||
const credentialStatusURL = credential.credentialStatus.statusListCredential |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should first check the type fiets to make sure this is a bit string status type. There could be others and those are not supported at the moment.
Signed-off-by: KulkarniShashank <[email protected]>
@TimoGlastra As per your suggestions, I have made the changes. Please review them and let me know your thoughts. |
Signed-off-by: KulkarniShashank <[email protected]>
Signed-off-by: KulkarniShashank <[email protected]>
Signed-off-by: KulkarniShashank <[email protected]>
…ction. Signed-off-by: KulkarniShashank <[email protected]>
Out of interest @KulkarniShashank will this work with cheqd DIDs and on-ledger Bitstring Status Lists? |
Its can work for all the DIDs that support JSON-LD credential format |
However @Tweeddalex this PR does not support cheqd yet. The current implementation only suppors https and uses |
if ('credentialStatus' in credential) { | ||
await verifyBitStringCredentialStatus(credential, agentContext) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
verifyPresentation also has options.verifyCredentialStatus, can you add that check here as well?
@IsEnum(['BitstringStatusListEntry']) | ||
@IsString() | ||
public type!: CredentialStatusType | ||
|
||
@IsEnum(CredentialStatusPurpose) | ||
@IsString() | ||
public statusPurpose!: CredentialStatusPurpose | ||
|
||
@IsString() | ||
public type!: string | ||
public statusListIndex!: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the VC Data model specification, these properties are not required fro the credentialStatus
property. Only id
and type
are.
We should have a generic base class and allow multiple extension points. You can look at e.g. how we solved this with the DidDocument service property, where there's a base service class and multiple possible extensions that are matched based on the type
property
// Function to validate the status using the updated method | ||
export const validateStatus = async (status: CredentialStatus, agentContext: AgentContext): Promise<boolean> => { | ||
const entry = plainToInstance(W3cCredentialStatus, status) | ||
|
||
try { | ||
await validateOrReject(entry) | ||
return true | ||
} catch (errors) { | ||
agentContext.config.logger.debug(`Credential status validation failed: ${errors}`, { | ||
stack: errors, | ||
}) | ||
throw new CredoError(`Invalid credential status type: ${errors}`) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This validation is automatically done when transforming into a specific class instance type, so I don't think it's needed if you follow the did document service approach
export type CredentialStatusType = 'BitstringStatusListEntry' | ||
// The purpose can be anything apart from this as well | ||
export enum CredentialStatusPurpose { | ||
'revocation' = 'revocation', | ||
'suspension' = 'suspension', | ||
'message' = 'message', | ||
} | ||
|
||
export interface StatusMessage { | ||
// a string representing the hexadecimal value of the status prefixed with 0x | ||
status: string | ||
// a string used by software developers to assist with debugging which SHOULD NOT be displayed to end users | ||
message?: string | ||
// We can have some key value pairs as well | ||
[key: string]: unknown | ||
} | ||
|
||
export interface CredentialStatus { | ||
id: string | ||
// Since currenlty we are only trying to support 'BitStringStatusListEntry' | ||
type: CredentialStatusType | ||
statusPurpose: CredentialStatusPurpose | ||
// Unique identifier for the specific credential | ||
statusListIndex: string | ||
// Must be url referencing to a VC of type 'BitstringStatusListCredential' | ||
statusListCredential: string | ||
// The statusSize indicates the size of the status entry in bits | ||
statusSize?: number | ||
// Must be preset if statusPurpose is message | ||
/** | ||
* the length of which MUST equal the number of possible status messages indicated by statusSize | ||
* (e.g., statusMessage array MUST have 2 elements if statusSize has 1 bit, | ||
* 4 elements if statusSize has 2 bits, 8 elements if statusSize has 3 bits, etc.). | ||
*/ | ||
statusMessage?: StatusMessage[] | ||
// An implementer MAY include the statusReference property. If present, its value MUST be a URL or an array of URLs [URL] which dereference to material related to the status | ||
statusReference?: SingleOrArray<string> | ||
} | ||
|
||
// Define an interface for `credentialSubject` | ||
export interface CredentialSubject { | ||
encodedList: string | ||
} | ||
|
||
// Define an interface for the `credential` object that uses `CredentialSubject` | ||
export interface Credential { | ||
credentialSubject: CredentialSubject | ||
} | ||
|
||
// Use the `Credential` interface within `BitStringStatusListCredential` | ||
export interface BitStringStatusListCredential { | ||
credential: Credential | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these interface names should be bitstring status list specific. It is important to make a distinction between bitstring status list, and possible other credentialStatus
methods that will be added in the future.
} | ||
} | ||
|
||
export const verifyBitStringCredentialStatus = async (credential: W3cJsonCredential, agentContext: AgentContext) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't validate the signature of the status list credential yet
* @returns Revoke credential notification message | ||
* | ||
*/ | ||
public async revokeJsonLdCredential(options: RevokeCredentialOption): Promise<{ message: string }> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is a lot of dupcliation in this file with the already present methods. Some suggestions:
- move all the credential status logic into a specific folder in the w3c module
- add the revocation related methods to the w3c credentails api, not the DIDcomm credentials api
- the only thing we should add it here is a
sendRevocationNotification
method (which we can extend to support non-anoncreds revocadion notification messages as well) - making a POST to the credential status list url to update the status list seems implementation specific and may not work for all implementations
What
This PR introduces support for W3C credential revocation. The following changes have been made:
Refactor functionality for Verify Credential and Verify Presentation.
Integrated with the Bit String Status List for checking and updating credential status.
How
Revocation Flow: Implemented the revocation flow by checking a credential status and updating the credential issuance process to handle revocable credentials.
Integration: Integrated the new revocation features with the existing system, ensuring compatibility and proper handling of revoked credentials.