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

feat(ssi): added public did and event


Signed-off-by: default avatarBerend Sliedrecht <berend@animo.id>
parent 4ff432cb
No related branches found
No related tags found
1 merge request!6feat(ssi): added public did and event
Showing
with 105 additions and 59 deletions
import { utils, type ConnectionRecord } from '@aries-framework/core'; import type { DidDocument, ConnectionRecord } from '@aries-framework/core';
import { utils } from '@aries-framework/core';
export class BaseEvent< export class BaseEvent<
T extends Record<string, unknown> = Record<string, unknown>, T extends Record<string, unknown> = Record<string, unknown>,
...@@ -16,6 +18,10 @@ export class BaseEvent< ...@@ -16,6 +18,10 @@ export class BaseEvent<
} }
} }
export class EventInfoPublicDid extends BaseEvent<{
didDocument: DidDocument;
}> {}
export class EventDidcommConnectionsGetAll extends BaseEvent<{ export class EventDidcommConnectionsGetAll extends BaseEvent<{
connections: Array<ConnectionRecord>; connections: Array<ConnectionRecord>;
}> {} }> {}
import { DidDocument } from '@aries-framework/core';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { mockConfigModule } from '../../config/__tests__/mockConfig.js'; import { mockConfigModule } from '../../config/__tests__/mockConfig.js';
...@@ -10,7 +11,7 @@ describe('AgentController', () => { ...@@ -10,7 +11,7 @@ describe('AgentController', () => {
beforeEach(async () => { beforeEach(async () => {
const moduleRef = await Test.createTestingModule({ const moduleRef = await Test.createTestingModule({
imports: [mockConfigModule], imports: [mockConfigModule(3002)],
controllers: [AgentController], controllers: [AgentController],
providers: [AgentService], providers: [AgentService],
}).compile(); }).compile();
...@@ -21,12 +22,11 @@ describe('AgentController', () => { ...@@ -21,12 +22,11 @@ describe('AgentController', () => {
describe('public did', () => { describe('public did', () => {
it('should get the public did information of the agent', async () => { it('should get the public did information of the agent', async () => {
const result = { id: 'test' }; const result = new DidDocument({ id: 'did:key:123' });
jest jest.spyOn(agentService, 'getPublicDid').mockResolvedValue(result);
.spyOn(agentService, 'getPublicDid')
.mockResolvedValue(result)
expect(await agentController.publicDid()).toBe(result); const event = await agentController.publicDid();
expect(event.data).toMatchObject({ didDocument: result });
}); });
}); });
}); });
import { Controller } from '@nestjs/common'; import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices'; import { MessagePattern } from '@nestjs/microservices';
import { EventInfoPublicDid } from '@ocm/shared';
import { AgentService } from './agent.service.js'; import { AgentService } from './agent.service.js';
...@@ -9,6 +10,8 @@ export class AgentController { ...@@ -9,6 +10,8 @@ export class AgentController {
@MessagePattern('info.publicDid') @MessagePattern('info.publicDid')
public async publicDid() { public async publicDid() {
return await this.agent.getPublicDid() const didDocument = await this.agent.getPublicDid();
return new EventInfoPublicDid({ didDocument });
} }
} }
...@@ -58,7 +58,7 @@ export class AgentService { ...@@ -58,7 +58,7 @@ export class AgentService {
}); });
const httpInbound = new HttpInboundTransport({ const httpInbound = new HttpInboundTransport({
port: Number(peerPort.replace(':', '')), port: peerPort,
}); });
this.agent.registerInboundTransport(httpInbound); this.agent.registerInboundTransport(httpInbound);
...@@ -119,9 +119,7 @@ export class AgentService { ...@@ -119,9 +119,7 @@ export class AgentService {
const ledgerIds = this.configService.get('agent.ledgerIds'); const ledgerIds = this.configService.get('agent.ledgerIds');
if (!ledgerIds || ledgerIds.length < 1 || ledgerIds[0] === '') { if (!ledgerIds || ledgerIds.length < 1 || ledgerIds[0] === '') {
throw new Error( return [];
'Agent could not start, please provide a ledger environment variable.',
);
} }
return ledgerIds.map((id: LedgerIds) => { return ledgerIds.map((id: LedgerIds) => {
...@@ -148,12 +146,11 @@ export class AgentService { ...@@ -148,12 +146,11 @@ export class AgentService {
if (!publicDidSeed) { if (!publicDidSeed) {
logger.info('No public did seed provided, skipping registration'); logger.info('No public did seed provided, skipping registration');
return;
} }
if (!ledgerIds || ledgerIds.length < 1 || ledgerIds[0] === '') { if (!ledgerIds || ledgerIds.length < 1 || ledgerIds[0] === '') {
throw new Error( return;
'Agent could not start, please provide a ledger environment variable.',
);
} }
const registeredPublicDidResponses = await registerPublicDids({ const registeredPublicDidResponses = await registerPublicDids({
...@@ -177,9 +174,24 @@ export class AgentService { ...@@ -177,9 +174,24 @@ export class AgentService {
} }
public async getPublicDid() { public async getPublicDid() {
return { const dids = await this.agent.dids.getCreatedDids({ method: 'indy' });
id: 'test', if (dids.length === 0) {
}; throw new Error('No registered public DIDs');
}
if (dids.length > 1) {
throw new Error('Multiple public DIDs found');
}
const didRecord = dids[0];
if (!didRecord.didDocument) {
throw new Error(
'A public DID was found, but did not include a DID Document',
);
}
return didRecord.didDocument;
} }
public async onModuleInit() { public async onModuleInit() {
......
...@@ -13,7 +13,7 @@ describe('ConnectionsController', () => { ...@@ -13,7 +13,7 @@ describe('ConnectionsController', () => {
beforeEach(async () => { beforeEach(async () => {
const moduleRef = await Test.createTestingModule({ const moduleRef = await Test.createTestingModule({
imports: [mockConfigModule, AgentModule], imports: [mockConfigModule(3003), AgentModule],
controllers: [ConnectionsController], controllers: [ConnectionsController],
providers: [ConnectionsService], providers: [ConnectionsService],
}).compile(); }).compile();
......
...@@ -40,10 +40,11 @@ export const registerPublicDids = async ({ ...@@ -40,10 +40,11 @@ export const registerPublicDids = async ({
seed, seed,
}; };
const res = await new axios.Axios().post<RegisterPublicDidResponse>( const res = await axios({
ledgerRegisterUrl, method: 'post',
body, url: ledgerRegisterUrl,
); data: body,
});
if (res.data) { if (res.data) {
logger.info('Agent DID registered.'); logger.info('Agent DID registered.');
......
...@@ -5,9 +5,9 @@ import { ConfigModule, ConfigService } from '@nestjs/config'; ...@@ -5,9 +5,9 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
import { validationSchema } from '../validation.js'; import { validationSchema } from '../validation.js';
const mockConfig: AppConfig = { const mockConfig = (port: number = 3001): AppConfig => ({
agentHost: '', agentHost: '',
port: 3000, port:3000,
jwtSecret: '', jwtSecret: '',
nats: { nats: {
url: 'localhost', url: 'localhost',
...@@ -16,45 +16,48 @@ const mockConfig: AppConfig = { ...@@ -16,45 +16,48 @@ const mockConfig: AppConfig = {
name: 'my-test-agent', name: 'my-test-agent',
walletId: 'some-id', walletId: 'some-id',
walletKey: 'some-key', walletKey: 'some-key',
ledgerIds: ['BCOVRIN_TEST'], ledgerIds: [],
host: '3000', host: '3000',
peerPort: '3001', inboundPort: port,
path: '', path: '',
publicDidSeed: 'none', publicDidSeed: '',
autoAcceptConnection: false, autoAcceptConnection: false,
autoAcceptCredential: AutoAcceptCredential.ContentApproved, autoAcceptCredential: AutoAcceptCredential.ContentApproved,
}, },
};
export const mockConfigModule = ConfigModule.forRoot({
load: [() => mockConfig],
validationSchema,
}); });
export const mockConfigModule = (port: number = 3000) =>
ConfigModule.forRoot({
load: [() => mockConfig(port)],
validationSchema,
});
describe('configuration', () => { describe('configuration', () => {
const mockedConfig = mockConfig();
describe('service', () => { describe('service', () => {
it('should be able to instantiate a config service', () => { it('should be able to instantiate a config service', () => {
const configuration = new ConfigService(mockConfig); const configuration = new ConfigService(mockConfig());
expect(configuration).toBeInstanceOf(ConfigService); expect(configuration).toBeInstanceOf(ConfigService);
}); });
it('should be able to extract root value', () => { it('should be able to extract root value', () => {
const configuration = new ConfigService(mockConfig); const configuration = new ConfigService(mockConfig());
expect(configuration.get('port')).toStrictEqual(mockConfig.port); expect(configuration.get('port')).toStrictEqual(mockedConfig.port);
}); });
it('should be able to extract root value as object', () => { it('should be able to extract root value as object', () => {
const configuration = new ConfigService(mockConfig); const configuration = new ConfigService(mockConfig());
expect(configuration.get('agent')).toMatchObject(mockConfig.agent); expect(configuration.get('agent')).toMatchObject(mockedConfig.agent);
}); });
it('should be able to extract nested values', () => { it('should be able to extract nested values', () => {
const configuration = new ConfigService(mockConfig); const configuration = new ConfigService(mockConfig());
expect(configuration.get('agent.autoAcceptCredential')).toStrictEqual( expect(configuration.get('agent.autoAcceptCredential')).toStrictEqual(
mockConfig.agent.autoAcceptCredential, mockedConfig.agent.autoAcceptCredential,
); );
}); });
}); });
......
...@@ -15,7 +15,7 @@ export interface AppConfig { ...@@ -15,7 +15,7 @@ export interface AppConfig {
walletKey: string; walletKey: string;
ledgerIds?: string[]; ledgerIds?: string[];
host: string; host: string;
peerPort: string; inboundPort: number;
path: string; path: string;
publicDidSeed: string; publicDidSeed: string;
autoAcceptConnection: boolean; autoAcceptConnection: boolean;
...@@ -25,7 +25,7 @@ export interface AppConfig { ...@@ -25,7 +25,7 @@ export interface AppConfig {
export const config = (): AppConfig => ({ export const config = (): AppConfig => ({
agentHost: process.env.AGENT_HOST || '', agentHost: process.env.AGENT_HOST || '',
port: Number(process.env.PORT), port: parseInt(process.env.PORT || '3000'),
jwtSecret: process.env.JWT_SECRET || '', jwtSecret: process.env.JWT_SECRET || '',
nats: { nats: {
...@@ -38,7 +38,7 @@ export const config = (): AppConfig => ({ ...@@ -38,7 +38,7 @@ export const config = (): AppConfig => ({
walletKey: process.env.AGENT_WALLET_KEY || '', walletKey: process.env.AGENT_WALLET_KEY || '',
ledgerIds: process.env.AGENT_LEDGER_ID?.split(','), ledgerIds: process.env.AGENT_LEDGER_ID?.split(','),
host: process.env.AGENT_HOST || '', host: process.env.AGENT_HOST || '',
peerPort: process.env.AGENT_PEER_PORT || '', inboundPort: parseInt(process.env.AGENT_INBOUND_PORT || '3001'),
path: process.env.AGENT_URL_PATH || '', path: process.env.AGENT_URL_PATH || '',
publicDidSeed: process.env.AGENT_PUBLIC_DID_SEED || '', publicDidSeed: process.env.AGENT_PUBLIC_DID_SEED || '',
autoAcceptConnection: process.env.AGENT_AUTO_ACCEPT_CONNECTION === 'true', autoAcceptConnection: process.env.AGENT_AUTO_ACCEPT_CONNECTION === 'true',
......
import type { INestApplication } from '@nestjs/common'; import type { INestApplication } from '@nestjs/common';
import type { ClientProxy } from '@nestjs/microservices'; import type { ClientProxy } from '@nestjs/microservices';
import type { EventInfoPublicDid } from '@ocm/shared';
import { DidDocument } from '@aries-framework/core';
import { ClientsModule, Transport } from '@nestjs/microservices'; import { ClientsModule, Transport } from '@nestjs/microservices';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { firstValueFrom, type Observable } from 'rxjs'; import { firstValueFrom, type Observable } from 'rxjs';
...@@ -9,29 +11,39 @@ import { AgentModule } from '../src/agent/agent.module.js'; ...@@ -9,29 +11,39 @@ import { AgentModule } from '../src/agent/agent.module.js';
import { AgentService } from '../src/agent/agent.service.js'; import { AgentService } from '../src/agent/agent.service.js';
import { mockConfigModule } from '../src/config/__tests__/mockConfig.js'; import { mockConfigModule } from '../src/config/__tests__/mockConfig.js';
const mockDidDocument = {
'@context': ['https://w3id.org/did/v1'],
id: 'did:indy:bcovrin:test:7KuDTpQh3GJ7Gp6kErpWvM',
verificationMethod: [
{
id: 'did:indy:bcovrin:test:7KuDTpQh3GJ7Gp6kErpWvM#verkey',
type: 'Ed25519VerificationKey2018',
controller: 'did:indy:bcovrin:test:7KuDTpQh3GJ7Gp6kErpWvM',
publicKeyBase58: '4SySYXQUtuK26zfC7RpQpWYMThfbXphUf8LWyXXmxyTX',
},
],
authentication: ['did:indy:bcovrin:test:7KuDTpQh3GJ7Gp6kErpWvM#verkey'],
};
describe('Agent', () => { describe('Agent', () => {
const TOKEN = 'AGENT_CLIENT_SERVICE'; const TOKEN = 'AGENT_CLIENT_SERVICE';
let app: INestApplication; let app: INestApplication;
let client: ClientProxy; let client: ClientProxy;
const agentService = {
getPublicDid: () =>
Promise.resolve({
id: 'test',
}),
};
beforeAll(async () => { beforeAll(async () => {
jest
.spyOn(AgentService.prototype, 'getPublicDid')
.mockImplementation(() =>
Promise.resolve(new DidDocument(mockDidDocument)),
);
const moduleRef = await Test.createTestingModule({ const moduleRef = await Test.createTestingModule({
imports: [ imports: [
mockConfigModule, mockConfigModule(3000),
AgentModule, AgentModule,
ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]), ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
], ],
}) }).compile();
.overrideProvider(AgentService)
.useValue(agentService)
.compile();
app = moduleRef.createNestApplication(); app = moduleRef.createNestApplication();
...@@ -45,9 +57,16 @@ describe('Agent', () => { ...@@ -45,9 +57,16 @@ describe('Agent', () => {
}); });
it('info.publicDid', async () => { it('info.publicDid', async () => {
const response$: Observable<unknown> = client.send('info.publicDid', {}); const response$: Observable<EventInfoPublicDid> = client.send(
'info.publicDid',
{},
);
const response = await firstValueFrom(response$); const response = await firstValueFrom(response$);
expect(response).toMatchObject({ id: 'test' });
expect(response.data).toMatchObject({
didDocument: mockDidDocument,
});
}); });
afterAll(async () => { afterAll(async () => {
......
...@@ -18,7 +18,7 @@ describe('Connections', () => { ...@@ -18,7 +18,7 @@ describe('Connections', () => {
beforeAll(async () => { beforeAll(async () => {
const moduleRef = await Test.createTestingModule({ const moduleRef = await Test.createTestingModule({
imports: [ imports: [
mockConfigModule, mockConfigModule(3004),
AgentModule, AgentModule,
ConnectionsModule, ConnectionsModule,
ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]), ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
......
...@@ -17,6 +17,7 @@ describe('HealthController (e2e)', () => { ...@@ -17,6 +17,7 @@ describe('HealthController (e2e)', () => {
app = moduleFixture.createNestApplication(); app = moduleFixture.createNestApplication();
await app.init(); await app.init();
}); });
afterAll(async () => { afterAll(async () => {
await app.close(); await app.close();
}); });
......
/** @type {import('jest').Config} */
import config from '../jest.config.js'; import config from '../jest.config.js';
/** @type {import('jest').Config} */
export default { export default {
...config, ...config,
testTimeout: 12000,
rootDir: '.', rootDir: '.',
testRegex: '.*\\.e2e-spec\\.ts$', testRegex: '.*\\.e2e-spec\\.ts$',
}; };
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