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<
T extends Record<string, unknown> = Record<string, unknown>,
......@@ -16,6 +18,10 @@ export class BaseEvent<
}
}
export class EventInfoPublicDid extends BaseEvent<{
didDocument: DidDocument;
}> {}
export class EventDidcommConnectionsGetAll extends BaseEvent<{
connections: Array<ConnectionRecord>;
}> {}
import { DidDocument } from '@aries-framework/core';
import { Test } from '@nestjs/testing';
import { mockConfigModule } from '../../config/__tests__/mockConfig.js';
......@@ -10,7 +11,7 @@ describe('AgentController', () => {
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
imports: [mockConfigModule],
imports: [mockConfigModule(3002)],
controllers: [AgentController],
providers: [AgentService],
}).compile();
......@@ -21,12 +22,11 @@ describe('AgentController', () => {
describe('public did', () => {
it('should get the public did information of the agent', async () => {
const result = { id: 'test' };
jest
.spyOn(agentService, 'getPublicDid')
.mockResolvedValue(result)
const result = new DidDocument({ id: 'did:key:123' });
jest.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 { MessagePattern } from '@nestjs/microservices';
import { EventInfoPublicDid } from '@ocm/shared';
import { AgentService } from './agent.service.js';
......@@ -9,6 +10,8 @@ export class AgentController {
@MessagePattern('info.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 {
});
const httpInbound = new HttpInboundTransport({
port: Number(peerPort.replace(':', '')),
port: peerPort,
});
this.agent.registerInboundTransport(httpInbound);
......@@ -119,9 +119,7 @@ export class AgentService {
const ledgerIds = this.configService.get('agent.ledgerIds');
if (!ledgerIds || ledgerIds.length < 1 || ledgerIds[0] === '') {
throw new Error(
'Agent could not start, please provide a ledger environment variable.',
);
return [];
}
return ledgerIds.map((id: LedgerIds) => {
......@@ -148,12 +146,11 @@ export class AgentService {
if (!publicDidSeed) {
logger.info('No public did seed provided, skipping registration');
return;
}
if (!ledgerIds || ledgerIds.length < 1 || ledgerIds[0] === '') {
throw new Error(
'Agent could not start, please provide a ledger environment variable.',
);
return;
}
const registeredPublicDidResponses = await registerPublicDids({
......@@ -177,9 +174,24 @@ export class AgentService {
}
public async getPublicDid() {
return {
id: 'test',
};
const dids = await this.agent.dids.getCreatedDids({ method: 'indy' });
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() {
......
......@@ -13,7 +13,7 @@ describe('ConnectionsController', () => {
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
imports: [mockConfigModule, AgentModule],
imports: [mockConfigModule(3003), AgentModule],
controllers: [ConnectionsController],
providers: [ConnectionsService],
}).compile();
......
......@@ -40,10 +40,11 @@ export const registerPublicDids = async ({
seed,
};
const res = await new axios.Axios().post<RegisterPublicDidResponse>(
ledgerRegisterUrl,
body,
);
const res = await axios({
method: 'post',
url: ledgerRegisterUrl,
data: body,
});
if (res.data) {
logger.info('Agent DID registered.');
......
......@@ -5,9 +5,9 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
import { validationSchema } from '../validation.js';
const mockConfig: AppConfig = {
const mockConfig = (port: number = 3001): AppConfig => ({
agentHost: '',
port: 3000,
port:3000,
jwtSecret: '',
nats: {
url: 'localhost',
......@@ -16,45 +16,48 @@ const mockConfig: AppConfig = {
name: 'my-test-agent',
walletId: 'some-id',
walletKey: 'some-key',
ledgerIds: ['BCOVRIN_TEST'],
ledgerIds: [],
host: '3000',
peerPort: '3001',
inboundPort: port,
path: '',
publicDidSeed: 'none',
publicDidSeed: '',
autoAcceptConnection: false,
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', () => {
const mockedConfig = mockConfig();
describe('service', () => {
it('should be able to instantiate a config service', () => {
const configuration = new ConfigService(mockConfig);
const configuration = new ConfigService(mockConfig());
expect(configuration).toBeInstanceOf(ConfigService);
});
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', () => {
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', () => {
const configuration = new ConfigService(mockConfig);
const configuration = new ConfigService(mockConfig());
expect(configuration.get('agent.autoAcceptCredential')).toStrictEqual(
mockConfig.agent.autoAcceptCredential,
mockedConfig.agent.autoAcceptCredential,
);
});
});
......
......@@ -15,7 +15,7 @@ export interface AppConfig {
walletKey: string;
ledgerIds?: string[];
host: string;
peerPort: string;
inboundPort: number;
path: string;
publicDidSeed: string;
autoAcceptConnection: boolean;
......@@ -25,7 +25,7 @@ export interface AppConfig {
export const config = (): AppConfig => ({
agentHost: process.env.AGENT_HOST || '',
port: Number(process.env.PORT),
port: parseInt(process.env.PORT || '3000'),
jwtSecret: process.env.JWT_SECRET || '',
nats: {
......@@ -38,7 +38,7 @@ export const config = (): AppConfig => ({
walletKey: process.env.AGENT_WALLET_KEY || '',
ledgerIds: process.env.AGENT_LEDGER_ID?.split(','),
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 || '',
publicDidSeed: process.env.AGENT_PUBLIC_DID_SEED || '',
autoAcceptConnection: process.env.AGENT_AUTO_ACCEPT_CONNECTION === 'true',
......
import type { INestApplication } from '@nestjs/common';
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 { Test } from '@nestjs/testing';
import { firstValueFrom, type Observable } from 'rxjs';
......@@ -9,29 +11,39 @@ import { AgentModule } from '../src/agent/agent.module.js';
import { AgentService } from '../src/agent/agent.service.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', () => {
const TOKEN = 'AGENT_CLIENT_SERVICE';
let app: INestApplication;
let client: ClientProxy;
const agentService = {
getPublicDid: () =>
Promise.resolve({
id: 'test',
}),
};
beforeAll(async () => {
jest
.spyOn(AgentService.prototype, 'getPublicDid')
.mockImplementation(() =>
Promise.resolve(new DidDocument(mockDidDocument)),
);
const moduleRef = await Test.createTestingModule({
imports: [
mockConfigModule,
mockConfigModule(3000),
AgentModule,
ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
],
})
.overrideProvider(AgentService)
.useValue(agentService)
.compile();
}).compile();
app = moduleRef.createNestApplication();
......@@ -45,9 +57,16 @@ describe('Agent', () => {
});
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$);
expect(response).toMatchObject({ id: 'test' });
expect(response.data).toMatchObject({
didDocument: mockDidDocument,
});
});
afterAll(async () => {
......
......@@ -18,7 +18,7 @@ describe('Connections', () => {
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [
mockConfigModule,
mockConfigModule(3004),
AgentModule,
ConnectionsModule,
ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
......
......@@ -17,6 +17,7 @@ describe('HealthController (e2e)', () => {
app = moduleFixture.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
});
......
/** @type {import('jest').Config} */
import config from '../jest.config.js';
/** @type {import('jest').Config} */
export default {
...config,
testTimeout: 12000,
rootDir: '.',
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