Skip to content
Snippets Groups Projects
Commit a48e1cd4 authored by Berend Sliedrecht's avatar Berend Sliedrecht
Browse files

feat(ssi): untested credential revocation support


Signed-off-by: default avatarBerend Sliedrecht <berend@animo.id>
parent 00bc23b3
No related branches found
No related tags found
2 merge requests!37Draft: Modifications for manual testing,!25feat(ssi): revocation ssi-abstraction
...@@ -11,6 +11,13 @@ import { Injectable } from '@nestjs/common'; ...@@ -11,6 +11,13 @@ import { Injectable } from '@nestjs/common';
import { WithTenantService } from '../withTenantService.js'; import { WithTenantService } from '../withTenantService.js';
export interface AnonCredsCredentialMetadata {
schemaId?: string;
credentialDefinitionId?: string;
revocationRegistryId?: string;
credentialRevocationId?: string;
}
@Injectable() @Injectable()
export class RevocationService { export class RevocationService {
public constructor(private withTenantService: WithTenantService) {} public constructor(private withTenantService: WithTenantService) {}
...@@ -22,30 +29,156 @@ export class RevocationService { ...@@ -22,30 +29,156 @@ export class RevocationService {
// Update the status list with the revoked index set // Update the status list with the revoked index set
public async revoke({ public async revoke({
tenantId, tenantId,
credentialId,
}: EventAnonCredsRevocationRevokeInput): Promise< }: EventAnonCredsRevocationRevokeInput): Promise<
EventAnonCredsRevocationRevoke['data'] EventAnonCredsRevocationRevoke['data']
> { > {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
return this.withTenantService.invoke(tenantId, async (_) => ({})); return this.withTenantService.invoke(tenantId, async (t) => {
const credential = await t.credentials.getById(credentialId);
const metadata = credential.metadata.get<AnonCredsCredentialMetadata>(
'_anoncreds/credential',
);
if (
!metadata ||
!metadata.revocationRegistryId ||
!metadata.credentialRevocationId
) {
throw new Error(
`credential (${credentialId}) has no metadata, likley it was issued without support for revocation`,
);
}
const { revocationRegistryDefinition } =
await t.modules.anoncreds.getRevocationRegistryDefinition(
metadata.revocationRegistryId,
);
if (!revocationRegistryDefinition) {
throw new Error(
`Could not find the revocation registry definition for id: ${metadata.revocationRegistryId}`,
);
}
const timestamp = new Date().getTime() / 1000;
const { revocationStatusList } =
await t.modules.anoncreds.getRevocationStatusList(
metadata.revocationRegistryId,
timestamp,
);
if (!revocationStatusList) {
throw new Error(
`Could not find the revocation status list for revocation registry definition id: ${metadata.revocationRegistryId} and timestamp: ${timestamp}`,
);
}
if (
revocationStatusList.revocationList[
Number(metadata.credentialRevocationId)
] === 1
) {
throw new Error(
`credential (${credentialId}), with revocation id ${metadata.credentialRevocationId}, is already in a revoked state`,
);
}
const newRevokedIndices = revocationStatusList.revocationList
.filter(
(state, idx) =>
state === 1 || idx === Number(metadata.credentialRevocationId),
)
.map((_, idx) => idx);
const newIssuedIndices = revocationStatusList.revocationList
.filter(
(state, idx) =>
state === 0 && idx !== Number(metadata.credentialRevocationId),
)
.map((_, idx) => idx);
const result = await t.modules.anoncreds.updateRevocationStatusList({
revocationRegistryDefinitionId: metadata.revocationRegistryId,
revokedCredentialIndexes: newRevokedIndices,
issuedCredentialIndexes: newIssuedIndices,
});
if (result.revocationStatusListState.state !== 'finished') {
throw new Error(
`An error occurred while trying to update the revocation status list. Error: ${JSON.stringify(
result,
)}`,
);
}
return {};
});
} }
public async registerRevocationRegistryDefinition({ public async registerRevocationRegistryDefinition({
tenantId, tenantId,
tag,
issuerDid,
credentialDefinitionId,
maximumCredentialNumber,
}: EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput): Promise< }: EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput): Promise<
EventAnonCredsRevocationRegisterRevocationRegistryDefinition['data'] EventAnonCredsRevocationRegisterRevocationRegistryDefinition['data']
> { > {
// eslint-disable-next-line @typescript-eslint/no-unused-vars return this.withTenantService.invoke(tenantId, async (t) => {
return this.withTenantService.invoke(tenantId, async (_) => ({ const result =
revocationRegistryDefinitionId: 'TODO', await t.modules.anoncreds.registerRevocationRegistryDefinition({
})); options: {},
revocationRegistryDefinition: {
maximumCredentialNumber,
credentialDefinitionId,
tag,
issuerId: issuerDid,
},
});
if (result.revocationRegistryDefinitionState.state !== 'finished') {
throw new Error(
`Error registering the revocation registry definition. Error: ${JSON.stringify(
result,
)}`,
);
}
return {
revocationRegistryDefinitionId:
result.revocationRegistryDefinitionState
.revocationRegistryDefinitionId,
};
});
} }
public async registerRevocationStatusList({ public async registerRevocationStatusList({
tenantId, tenantId,
revocationRegistryDefinitionId,
issuerDid,
}: EventAnonCredsRevocationRegisterRevocationStatusListInput): Promise< }: EventAnonCredsRevocationRegisterRevocationStatusListInput): Promise<
EventAnonCredsRevocationRegisterRevocationStatusList['data'] EventAnonCredsRevocationRegisterRevocationStatusList['data']
> { > {
// eslint-disable-next-line @typescript-eslint/no-unused-vars return this.withTenantService.invoke(tenantId, async (t) => {
return this.withTenantService.invoke(tenantId, async (_) => ({})); const result = await t.modules.anoncreds.registerRevocationStatusList({
options: {},
revocationStatusList: {
revocationRegistryDefinitionId,
issuerId: issuerDid,
},
});
if (result.revocationStatusListState.state !== 'finished') {
throw new Error(
`Error registering the revocation status list. Error: ${JSON.stringify(
result,
)}`,
);
}
return {};
});
} }
} }
...@@ -4615,7 +4615,7 @@ packages: ...@@ -4615,7 +4615,7 @@ packages:
dependencies: dependencies:
'@nestjs/axios': 3.0.1(@nestjs/common@10.3.0)(axios@1.6.5)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/axios': 3.0.1(@nestjs/common@10.3.0)(axios@1.6.5)(reflect-metadata@0.1.14)(rxjs@7.8.1)
'@nestjs/common': 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/common': 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1)
'@nestjs/core': 10.3.0(@nestjs/common@10.3.0)(@nestjs/microservices@10.3.0)(@nestjs/platform-express@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/core': 10.3.0(@nestjs/common@10.3.0)(@nestjs/microservices@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1)
'@nestjs/microservices': 10.3.0(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(nats@2.19.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/microservices': 10.3.0(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(nats@2.19.0)(reflect-metadata@0.1.14)(rxjs@7.8.1)
boxen: 5.1.2 boxen: 5.1.2
check-disk-space: 3.4.0 check-disk-space: 3.4.0
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment