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

feat(ssi): revocation typings and interface


Signed-off-by: default avatarBerend Sliedrecht <berend@animo.id>
parent ede9cb95
No related branches found
No related tags found
2 merge requests!37Draft: Modifications for manual testing,!25feat(ssi): revocation ssi-abstraction
Showing
with 330 additions and 31 deletions
......@@ -3,13 +3,14 @@ import type { AnonCredsCredentialDefinition } from '@credo-ts/anoncreds';
import { BaseEvent } from './baseEvents.js';
export type CredentialDefinitionWithId = AnonCredsCredentialDefinition & {
credentialDefinitionId: string;
};
export type AnonCredsCredentialDefinitionWithId =
AnonCredsCredentialDefinition & {
credentialDefinitionId: string;
};
export type EventAnonCredsCredentialDefinitionsGetAllInput = BaseEventInput;
export class EventAnonCredsCredentialDefinitionsGetAll extends BaseEvent<
Array<CredentialDefinitionWithId>
Array<AnonCredsCredentialDefinition>
> {
public static token = 'anoncreds.credentialDefinitions.getAll';
......@@ -31,7 +32,7 @@ export class EventAnonCredsCredentialDefinitionsGetAll extends BaseEvent<
export type EventAnonCredsCredentialDefinitionsGetByIdInput = BaseEventInput<{
credentialDefinitionId: string;
}>;
export class EventAnonCredsCredentialDefinitionsGetById extends BaseEvent<CredentialDefinitionWithId | null> {
export class EventAnonCredsCredentialDefinitionsGetById extends BaseEvent<AnonCredsCredentialDefinitionWithId | null> {
public static token = 'anoncreds.credentialDefinitions.getById';
public get instance() {
......@@ -55,7 +56,7 @@ export type EventAnonCredsCredentialDefinitionsRegisterInput = BaseEventInput<{
issuerDid: string;
}>;
export class EventAnonCredsCredentialDefinitionsRegister extends BaseEvent<CredentialDefinitionWithId> {
export class EventAnonCredsCredentialDefinitionsRegister extends BaseEvent<AnonCredsCredentialDefinitionWithId> {
public static token = 'anoncreds.credentialDefinitions.register';
public get instance() {
......
import type { BaseEventInput } from './baseEvents.js';
import { BaseEvent } from './baseEvents.js';
export type EventAnonCredsRevocationRevokeInput = BaseEventInput<{
credentialId: string;
}>;
export class EventAnonCredsRevocationRevoke extends BaseEvent {
public static token = 'anoncreds.revocation.revoke';
public get instance() {
return null;
}
public static fromEvent(e: EventAnonCredsRevocationRevoke) {
return new EventAnonCredsRevocationRevoke(
e.data,
e.tenantId,
e.id,
e.type,
e.timestamp,
);
}
}
// TODO: input type available in the new AFJ
export type EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput =
BaseEventInput;
export class EventAnonCredsRevocationRegisterRevocationRegistryDefinition extends BaseEvent<{
revocationRegistryDefinitionId: string;
}> {
public static token =
'anoncreds.revocation.registerRevocationRegistryDefinition';
public get instance() {
return this.data;
}
public static fromEvent(
e: EventAnonCredsRevocationRegisterRevocationRegistryDefinition,
) {
return new EventAnonCredsRevocationRegisterRevocationRegistryDefinition(
e.data,
e.tenantId,
e.id,
e.type,
e.timestamp,
);
}
}
// TODO: input type available in the new AFJ
export type EventAnonCredsRevocationRegisterRevocationStatusListInput =
BaseEventInput<{ revocationRegistryDefinitionId: string }>;
export class EventAnonCredsRevocationRegisterRevocationStatusList extends BaseEvent {
public static token = 'anoncreds.revocation.registerRevocationStatusList';
public get instance() {
return this.data;
}
public static fromEvent(
e: EventAnonCredsRevocationRegisterRevocationStatusList,
) {
return new EventAnonCredsRevocationRegisterRevocationStatusList(
e.data,
e.tenantId,
e.id,
e.type,
e.timestamp,
);
}
}
......@@ -3,6 +3,10 @@ import type { AnonCredsSchema } from '@credo-ts/anoncreds';
import { BaseEvent } from './baseEvents.js';
export type AnonCredsSchemaWithId = AnonCredsSchema & {
schemaId: string;
};
export type EventAnonCredsSchemasGetAllInput = BaseEventInput;
export class EventAnonCredsSchemasGetAll extends BaseEvent<
Array<AnonCredsSchema>
......@@ -51,7 +55,7 @@ export type EventAnonCredsSchemasRegisterInput = BaseEventInput<{
version: string;
attributeNames: Array<string>;
}>;
export class EventAnonCredsSchemasRegister extends BaseEvent<AnonCredsSchema> {
export class EventAnonCredsSchemasRegister extends BaseEvent<AnonCredsSchemaWithId> {
public static token = 'anoncreds.schemas.register';
public get instance() {
......
......@@ -13,6 +13,7 @@ export * from './events/credentialEvents.js';
export * from './events/credentialOfferEvents.js';
export * from './events/credentialRequestEvents.js';
export * from './events/proofEvents.js';
export * from './events/revocationEvents.js';
export * from './dto/pagination-params.dto.js';
export * from './dto/multitenancy-params.dto.js';
......
......@@ -4,6 +4,7 @@ const swcConfig = JSON.parse(readFileSync('../../.swcrc', 'utf8'));
/** @type {import('jest').Config} */
export default {
testPathIgnorePatterns: ['dist'],
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
transform: {
......
......@@ -194,6 +194,8 @@ export class AgentService implements OnApplicationShutdown {
try {
await this.agent.shutdown();
// eslint-disable-next-line no-empty
} catch {}
} catch (e) {
logger.warn(`Agent shutdown issue occurred. Cause: ${e}`);
}
}
}
......@@ -4,10 +4,13 @@ import type {
ConnectionStateChangedEvent,
} from '@credo-ts/core';
import type {
EventDidcommConnectionsBlock,
EventDidcommConnectionsBlockInput,
EventDidcommConnectionsCreateInvitationInput,
EventDidcommConnectionsCreateWithSelf,
EventDidcommConnectionsCreateWithSelfInput,
EventDidcommConnectionsGetAllInput,
EventDidcommConnectionsGetById,
EventDidcommConnectionsGetByIdInput,
EventDidcommConnectionsReceiveInvitationFromUrlInput,
} from '@ocm/shared';
......@@ -48,7 +51,9 @@ export class ConnectionsService {
public async getById({
tenantId,
id,
}: EventDidcommConnectionsGetByIdInput): Promise<ConnectionRecord | null> {
}: EventDidcommConnectionsGetByIdInput): Promise<
EventDidcommConnectionsGetById['data']
> {
return this.withTenantService.invoke(tenantId, (t) =>
t.connections.findById(id),
);
......@@ -57,7 +62,9 @@ export class ConnectionsService {
public async blockByIdOrDid({
tenantId,
idOrDid,
}: EventDidcommConnectionsBlockInput): Promise<ConnectionRecord | null> {
}: EventDidcommConnectionsBlockInput): Promise<
EventDidcommConnectionsBlock['data']
> {
return this.withTenantService.invoke(tenantId, async (t) => {
if (isDid(idOrDid)) {
const records = await t.connections.findAllByQuery({
......@@ -131,7 +138,9 @@ export class ConnectionsService {
public async createConnectionWithSelf({
tenantId,
}: EventDidcommConnectionsCreateWithSelfInput): Promise<ConnectionRecord> {
}: EventDidcommConnectionsCreateWithSelfInput): Promise<
EventDidcommConnectionsCreateWithSelf['data']
> {
return this.withTenantService.invoke(tenantId, async (t) => {
const outOfBandRecord = await t.oob.createInvitation();
const invitation = outOfBandRecord.outOfBandInvitation;
......
......@@ -57,7 +57,9 @@ describe('CredentialDefinitionsController', () => {
describe('register credentialDefinition', () => {
it('should register a credentialDefinition on a ledger', async () => {
const result: AnonCredsCredentialDefinition = {
const result: AnonCredsCredentialDefinition & {
credentialDefinitionId: string;
} = {
tag: 'some-tag',
type: 'CL',
issuerId: 'did:indy:issuer',
......@@ -65,6 +67,7 @@ describe('CredentialDefinitionsController', () => {
value: {
primary: {},
},
credentialDefinitionId: 'some-id',
};
jest
......
import type { IndyVdrRegisterCredentialDefinitionOptions } from '@credo-ts/indy-vdr';
import type {
CredentialDefinitionWithId,
EventAnonCredsCredentialDefinitionsGetAll,
EventAnonCredsCredentialDefinitionsGetAllInput,
EventAnonCredsCredentialDefinitionsGetById,
EventAnonCredsCredentialDefinitionsGetByIdInput,
EventAnonCredsCredentialDefinitionsRegister,
EventAnonCredsCredentialDefinitionsRegisterInput,
} from '@ocm/shared';
......@@ -17,7 +19,7 @@ export class CredentialDefinitionsService {
public async getAll({
tenantId,
}: EventAnonCredsCredentialDefinitionsGetAllInput): Promise<
Array<CredentialDefinitionWithId>
EventAnonCredsCredentialDefinitionsGetAll['data']
> {
return this.withTenantService.invoke(tenantId, async (t) =>
(await t.modules.anoncreds.getCreatedCredentialDefinitions({})).map(
......@@ -32,7 +34,9 @@ export class CredentialDefinitionsService {
public async getById({
tenantId,
credentialDefinitionId,
}: EventAnonCredsCredentialDefinitionsGetByIdInput): Promise<CredentialDefinitionWithId | null> {
}: EventAnonCredsCredentialDefinitionsGetByIdInput): Promise<
EventAnonCredsCredentialDefinitionsGetById['data']
> {
return this.withTenantService.invoke(tenantId, async (t) => {
const { credentialDefinition } =
await t.modules.anoncreds.getCredentialDefinition(
......@@ -49,7 +53,9 @@ export class CredentialDefinitionsService {
schemaId,
issuerDid,
tag,
}: EventAnonCredsCredentialDefinitionsRegisterInput): Promise<CredentialDefinitionWithId> {
}: EventAnonCredsCredentialDefinitionsRegisterInput): Promise<
EventAnonCredsCredentialDefinitionsRegister['data']
> {
return this.withTenantService.invoke(tenantId, async (t) => {
const { credentialDefinitionState } =
await t.modules.anoncreds.registerCredentialDefinition<IndyVdrRegisterCredentialDefinitionOptions>(
......
......@@ -4,12 +4,12 @@ import type {
IndyVdrDidCreateResult,
} from '@credo-ts/indy-vdr';
import type {
EventDidsRegisterIndyFromSeed,
EventDidsRegisterIndyFromSeedInput,
EventDidsResolve,
DidConfiguration,
EventDidsDidConfiguration,
EventDidsDidConfigurationInput,
EventDidsRegisterIndyFromSeed,
EventDidsResolve,
EventDidsResolveInput,
} from '@ocm/shared';
......
import { Test } from '@nestjs/testing';
import { mockConfigModule } from '../../../config/__tests__/mockConfig.js';
import { AgentModule } from '../../agent.module.js';
import { RevocationController } from '../revocation.controller.js';
import { RevocationService } from '../revocation.service.js';
describe('RevocationController', () => {
let revocationController: RevocationController;
let revocationService: RevocationService;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
imports: [mockConfigModule(), AgentModule],
controllers: [RevocationController],
providers: [RevocationService],
}).compile();
revocationService = moduleRef.get(RevocationService);
revocationController = moduleRef.get(RevocationController);
});
describe('revoke', () => {
it('should revoke a credential by id', async () => {
const result = {};
jest.spyOn(revocationService, 'revoke').mockResolvedValue(result);
const event = await revocationController.revoke({
tenantId: 'some-id',
credentialId: 'some-fake-id',
});
expect(event.data).toStrictEqual(result);
});
});
describe('register revocation registry definition', () => {
it('should register a revocation registry definition', async () => {
const result = { revocationRegistryDefinitionId: 'some-id' };
jest
.spyOn(revocationService, 'registerRevocationRegistryDefinition')
.mockResolvedValue(result);
const event =
await revocationController.registerRevocationRegistryDefinition({
tenantId: 'some-id',
});
expect(event.data).toStrictEqual(result);
});
});
describe('register revocation status list', () => {
it('should register a revocation status list', async () => {
const result = {};
jest
.spyOn(revocationService, 'registerRevocationStatusList')
.mockResolvedValue(result);
const event = await revocationController.registerRevocationStatusList({
tenantId: 'some-id',
revocationRegistryDefinitionId: 'some-fake-id',
});
expect(event.data).toStrictEqual(result);
});
});
});
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import {
EventAnonCredsRevocationRegisterRevocationRegistryDefinition,
EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput,
EventAnonCredsRevocationRegisterRevocationStatusList,
EventAnonCredsRevocationRegisterRevocationStatusListInput,
EventAnonCredsRevocationRevoke,
EventAnonCredsRevocationRevokeInput,
} from '@ocm/shared';
import { RevocationService } from './revocation.service.js';
@Controller('revocation')
export class RevocationController {
public constructor(private revocationService: RevocationService) {}
@MessagePattern(EventAnonCredsRevocationRevoke.token)
public async revoke(
options: EventAnonCredsRevocationRevokeInput,
): Promise<EventAnonCredsRevocationRevoke> {
return new EventAnonCredsRevocationRevoke(
await this.revocationService.revoke(options),
options.tenantId,
);
}
@MessagePattern(
EventAnonCredsRevocationRegisterRevocationRegistryDefinition.token,
)
public async registerRevocationRegistryDefinition(
options: EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput,
): Promise<EventAnonCredsRevocationRegisterRevocationRegistryDefinition> {
return new EventAnonCredsRevocationRegisterRevocationRegistryDefinition(
await this.revocationService.registerRevocationRegistryDefinition(
options,
),
options.tenantId,
);
}
@MessagePattern(
EventAnonCredsRevocationRegisterRevocationRegistryDefinition.token,
)
public async registerRevocationStatusList(
options: EventAnonCredsRevocationRegisterRevocationStatusListInput,
): Promise<EventAnonCredsRevocationRegisterRevocationStatusList> {
return new EventAnonCredsRevocationRegisterRevocationStatusList(
await this.revocationService.registerRevocationStatusList(options),
options.tenantId,
);
}
}
import { Module } from '@nestjs/common';
import { AgentModule } from '../agent.module.js';
import { RevocationController } from './revocation.controller.js';
import { RevocationService } from './revocation.service.js';
@Module({
imports: [AgentModule],
providers: [RevocationService],
controllers: [RevocationController],
})
export class RevocationModule {}
import type {
EventAnonCredsRevocationRegisterRevocationRegistryDefinition,
EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput,
EventAnonCredsRevocationRegisterRevocationStatusList,
EventAnonCredsRevocationRegisterRevocationStatusListInput,
EventAnonCredsRevocationRevoke,
EventAnonCredsRevocationRevokeInput,
} from '@ocm/shared';
import { Injectable } from '@nestjs/common';
import { WithTenantService } from '../withTenantService.js';
@Injectable()
export class RevocationService {
public constructor(private withTenantService: WithTenantService) {}
// Get the credential from storage
// Get the revocation registry definition id
// Get the revocation index
// Get the status list
// Update the status list with the revoked index set
public async revoke({
tenantId,
}: EventAnonCredsRevocationRevokeInput): Promise<
EventAnonCredsRevocationRevoke['data']
> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return this.withTenantService.invoke(tenantId, async (_) => ({}));
}
public async registerRevocationRegistryDefinition({
tenantId,
}: EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput): Promise<
EventAnonCredsRevocationRegisterRevocationRegistryDefinition['data']
> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return this.withTenantService.invoke(tenantId, async (_) => ({
revocationRegistryDefinitionId: 'TODO',
}));
}
public async registerRevocationStatusList({
tenantId,
}: EventAnonCredsRevocationRegisterRevocationStatusListInput): Promise<
EventAnonCredsRevocationRegisterRevocationStatusList['data']
> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return this.withTenantService.invoke(tenantId, async (_) => ({}));
}
}
......@@ -7,7 +7,7 @@ import { AgentModule } from '../../agent.module.js';
import { SchemasController } from '../schemas.controller.js';
import { SchemasService } from '../schemas.service.js';
describe('SchemassController', () => {
describe('SchemasController', () => {
let schemasController: SchemasController;
let schemasService: SchemasService;
......@@ -51,11 +51,12 @@ describe('SchemassController', () => {
describe('register schema', () => {
it('should register a schema on a ledger', async () => {
const result: AnonCredsSchema = {
const result: AnonCredsSchema & { schemaId: string } = {
name: 'schema-name',
version: '1.0',
issuerId: 'did:indy:123',
attrNames: ['name', 'age'],
schemaId: 'some-id',
};
jest.spyOn(schemasService, 'register').mockResolvedValue(result);
......
import type { AnonCredsSchema } from '@credo-ts/anoncreds';
import type { IndyVdrRegisterSchemaOptions } from '@credo-ts/indy-vdr';
import type {
EventAnonCredsSchemasGetAll,
EventAnonCredsSchemasGetAllInput,
EventAnonCredsSchemasGetById,
EventAnonCredsSchemasGetByIdInput,
EventAnonCredsSchemasRegister,
EventAnonCredsSchemasRegisterInput,
} from '@ocm/shared';
......@@ -16,7 +19,9 @@ export class SchemasService {
public async getAll({
tenantId,
}: EventAnonCredsSchemasGetAllInput): Promise<Array<AnonCredsSchema>> {
}: EventAnonCredsSchemasGetAllInput): Promise<
EventAnonCredsSchemasGetAll['data']
> {
return this.withTenantService.invoke(tenantId, async (t) =>
(await t.modules.anoncreds.getCreatedSchemas({})).map((r) => r.schema),
);
......@@ -25,7 +30,9 @@ export class SchemasService {
public async getById({
tenantId,
schemaId,
}: EventAnonCredsSchemasGetByIdInput): Promise<AnonCredsSchema | null> {
}: EventAnonCredsSchemasGetByIdInput): Promise<
EventAnonCredsSchemasGetById['data']
> {
return this.withTenantService.invoke(tenantId, async (t) => {
const { schema } = await t.modules.anoncreds.getSchema(schemaId);
return schema ?? null;
......@@ -39,7 +46,7 @@ export class SchemasService {
issuerDid,
attributeNames,
}: EventAnonCredsSchemasRegisterInput): Promise<
AnonCredsSchema & { schemaId: string }
EventAnonCredsSchemasRegister['data']
> {
return this.withTenantService.invoke(tenantId, async (t) => {
const { schemaState } =
......
......@@ -9,11 +9,11 @@ export class TenantsController {
public constructor(private tenantsService: TenantsService) {}
@MessagePattern(EventTenantsCreate.token)
public async create({
label,
}: EventTenantsCreateInput): Promise<EventTenantsCreate> {
public async create(
options: EventTenantsCreateInput,
): Promise<EventTenantsCreate> {
return new EventTenantsCreate(
await this.tenantsService.create(label),
await this.tenantsService.create(options),
undefined,
);
}
......
import type { AppAgent } from '../agent.service.js';
import type { EventTenantsCreate, EventTenantsCreateInput } from '@ocm/shared';
import { Injectable } from '@nestjs/common';
......@@ -12,7 +13,11 @@ export class TenantsService {
this.agent = agentService.agent;
}
public async create(label: string) {
return await this.agent.modules.tenants.createTenant({ config: { label } });
public async create(
options: EventTenantsCreateInput,
): Promise<EventTenantsCreate['data']> {
return await this.agent.modules.tenants.createTenant({
config: { label: options.label },
});
}
}
......@@ -76,7 +76,7 @@ describe('Credentials', () => {
await client.connect();
const tenantsService = app.get(TenantsService);
const { id } = await tenantsService.create(TOKEN);
const { id } = await tenantsService.create({ label: TOKEN });
tenantId = id;
const connectionsService = app.get(ConnectionsService);
......
......@@ -57,7 +57,7 @@ describe('Connections', () => {
await client.connect();
const ts = app.get(TenantsService);
const { id } = await ts.create(TOKEN);
const { id } = await ts.create({ label: TOKEN });
tenantId = id;
});
......
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