Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • eclipse/xfsc/ocm/ocm-engine
  • zdravko61/ocm-engine
  • mjuergenscg/ocm-engine
  • tsabolov/ocm-engine
  • mikesell/ocm-engine
5 results
Show changes
Showing
with 411 additions and 29 deletions
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { EventTenantsCreate, EventTenantsCreateInput } from '@ocm/shared';
import { TenantsService } from './tenants.service.js';
@Controller('tenants')
export class TenantsController {
public constructor(private tenantsService: TenantsService) {}
@MessagePattern(EventTenantsCreate.token)
public async create({
label,
}: EventTenantsCreateInput): Promise<EventTenantsCreate> {
return new EventTenantsCreate(
await this.tenantsService.create(label),
undefined,
);
}
}
import { Module } from '@nestjs/common';
import { AgentModule } from '../agent.module.js';
import { TenantsController } from './tenants.controller.js';
import { TenantsService } from './tenants.service.js';
@Module({
imports: [AgentModule],
providers: [TenantsService],
controllers: [TenantsController],
})
export class TenantsModule {}
import type { AppAgent } from '../agent.service.js';
import { Injectable } from '@nestjs/common';
import { AgentService } from '../agent.service.js';
@Injectable()
export class TenantsService {
public agent: AppAgent;
public constructor(agentService: AgentService) {
this.agent = agentService.agent;
}
public async create(label: string) {
return await this.agent.modules.tenants.createTenant({ config: { label } });
}
}
import type { AppAgent } from './agent.service.js';
import { Injectable } from '@nestjs/common';
import { AgentService } from './agent.service.js';
@Injectable()
export class WithTenantService {
private agent: AppAgent;
public constructor(agentService: AgentService) {
this.agent = agentService.agent;
}
public invoke<T>(
tenantId: string,
cb: (tenant: AppAgent) => Promise<T>,
): Promise<T> {
// eslint-disable-next-line no-async-promise-executor
return new Promise<T>(async (resolve, reject) => {
await this.agent.modules.tenants.withTenantAgent(
{ tenantId },
async (tenant) => {
try {
const ret = await cb(tenant as unknown as AppAgent);
resolve(ret);
} catch (e) {
reject(e);
}
},
);
});
}
}
import { DidsModule } from '@aries-framework/core';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TerminusModule } from '@nestjs/terminus';
......@@ -5,6 +6,7 @@ import { HealthController } from '@ocm/shared';
import { AgentModule } from './agent/agent.module.js';
import { ConnectionsModule } from './agent/connections/connections.module.js';
import { TenantsModule } from './agent/tenants/tenants.module.js';
import { config } from './config/config.js';
import { validationSchema } from './config/validation.js';
......@@ -18,6 +20,8 @@ import { validationSchema } from './config/validation.js';
}),
AgentModule,
ConnectionsModule,
DidsModule,
TenantsModule,
],
controllers: [HealthController],
})
......
export enum NATSServices {
SERVICE_NAME = 'SSI_ABSTRACTION_SERVICE',
}
export enum MetadataTokens {
GAIA_X_CONNECTION_METADATA_KEY = 'gaia_x_connection_metadata_key',
}
import type { AppConfig } from '../config.js';
import { AutoAcceptCredential } from '@aries-framework/core';
import { AutoAcceptCredential, utils } from '@aries-framework/core';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { validationSchema } from '../validation.js';
const mockConfig = (port: number = 3001): AppConfig => ({
agentHost: '',
port:3000,
port: 3000,
jwtSecret: '',
nats: {
url: 'localhost',
},
agent: {
name: 'my-test-agent',
walletId: 'some-id',
walletId: utils.uuid(),
walletKey: 'some-key',
ledgerIds: [],
host: '3000',
host: 'http://localhost',
inboundPort: port,
path: '',
publicDidSeed: '',
autoAcceptConnection: false,
autoAcceptConnection: true,
autoAcceptCredential: AutoAcceptCredential.ContentApproved,
},
});
......@@ -50,7 +50,7 @@ describe('configuration', () => {
it('should be able to extract root value as object', () => {
const configuration = new ConfigService(mockConfig());
expect(configuration.get('agent')).toMatchObject(mockedConfig.agent);
expect(configuration.get('agent')).toHaveProperty('name');
});
it('should be able to extract nested values', () => {
......
......@@ -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 || '',
inboundPort: parseInt(process.env.AGENT_INBOUND_PORT || '3001'),
inboundPort: Number(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 {
EventDidcommConnectionsGetById,
EventDidcommConnectionsGetAll,
EventDidcommConnectionsGetAllInput,
EventDidcommConnectionsCreateWithSelfInput,
EventDidcommConnectionsGetByIdInput,
EventDidcommConnectionsBlockInput,
} from '@ocm/shared';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { Test } from '@nestjs/testing';
import { firstValueFrom, type Observable } from 'rxjs';
import {
EventDidcommConnectionsGetById,
EventDidcommConnectionsGetAll,
EventDidcommConnectionsCreateWithSelf,
EventDidcommConnectionsBlock,
} from '@ocm/shared';
import { firstValueFrom } from 'rxjs';
import { AgentModule } from '../src/agent/agent.module.js';
import { ConnectionsModule } from '../src/agent/connections/connections.module.js';
import { TenantsModule } from '../src/agent/tenants/tenants.module.js';
import { TenantsService } from '../src/agent/tenants/tenants.service.js';
import { MetadataTokens } from '../src/common/constants.js';
import { mockConfigModule } from '../src/config/__tests__/mockConfig.js';
describe('Connections', () => {
const TOKEN = 'CONNECTIONS_CLIENT_SERVICE';
let app: INestApplication;
let client: ClientProxy;
let tenantId: string;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
......@@ -24,6 +36,7 @@ describe('Connections', () => {
mockConfigModule(3004),
AgentModule,
ConnectionsModule,
TenantsModule,
ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
],
}).compile();
......@@ -37,28 +50,73 @@ describe('Connections', () => {
client = app.get(TOKEN);
await client.connect();
const ts = app.get(TenantsService);
const { id } = await ts.create(TOKEN);
tenantId = id;
});
it('didcomm.connections.getAll', async () => {
const response$: Observable<EventDidcommConnectionsGetAll> = client.send(
'didcomm.connections.getAll',
{},
);
afterAll(async () => {
await app.close();
client.close();
});
it(EventDidcommConnectionsGetAll.token, async () => {
const response$ = client.send<
EventDidcommConnectionsGetAll,
EventDidcommConnectionsGetAllInput
>(EventDidcommConnectionsGetAll.token, { tenantId });
const response = await firstValueFrom(response$);
expect(response.data).toMatchObject({ connections: [] });
const eventInstance = EventDidcommConnectionsGetAll.fromEvent(response);
expect(eventInstance.instance).toEqual(expect.arrayContaining([]));
});
it('didcomm.connections.getById', async () => {
const response$: Observable<EventDidcommConnectionsGetById> = client.send(
'didcomm.connections.getById',
{ id: 'some-id' },
);
it(EventDidcommConnectionsGetById.token, async () => {
const response$ = client.send<
EventDidcommConnectionsGetById,
EventDidcommConnectionsGetByIdInput
>(EventDidcommConnectionsGetById.token, {
id: 'some-id',
tenantId,
});
const response = await firstValueFrom(response$);
expect(response.data).toMatchObject({ connection: null });
const eventInstance = EventDidcommConnectionsGetById.fromEvent(response);
expect(eventInstance.instance).toBeNull();
});
afterAll(async () => {
await app.close();
client.close();
it(EventDidcommConnectionsCreateWithSelf.token, async () => {
const response$ = client.send<
EventDidcommConnectionsCreateWithSelf,
EventDidcommConnectionsCreateWithSelfInput
>(EventDidcommConnectionsCreateWithSelf.token, {
tenantId,
});
const response = await firstValueFrom(response$);
const eventInstance =
EventDidcommConnectionsCreateWithSelf.fromEvent(response);
expect(eventInstance.instance).toHaveProperty('id');
const metadata = eventInstance.instance.metadata.get(
MetadataTokens.GAIA_X_CONNECTION_METADATA_KEY,
);
expect(metadata).toMatchObject({ trusted: true });
});
it(EventDidcommConnectionsBlock.token, async () => {
const response$ = client.send<
EventDidcommConnectionsBlock,
EventDidcommConnectionsBlockInput
>(EventDidcommConnectionsBlock.token, {
idOrDid: 'some-id',
tenantId,
});
const response = await firstValueFrom(response$);
const eventInstance = EventDidcommConnectionsBlock.fromEvent(response);
expect(eventInstance.instance).toBeNull();
});
});
import type { INestApplication } from '@nestjs/common';
import type { ClientProxy } from '@nestjs/microservices';
import type {
EventDidsResolveInput,
EventDidsPublicDidInput,
} from '@ocm/shared';
import { DidDocument } from '@aries-framework/core';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { Test } from '@nestjs/testing';
import { EventDidsResolve, EventDidsPublicDid } from '@ocm/shared';
import { firstValueFrom } from 'rxjs';
import { AgentModule } from '../src/agent/agent.module.js';
import { DidsModule } from '../src/agent/dids/dids.module.js';
import { DidsService } from '../src/agent/dids/dids.service.js';
import { TenantsModule } from '../src/agent/tenants/tenants.module.js';
import { TenantsService } from '../src/agent/tenants/tenants.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('Dids', () => {
const TOKEN = 'DIDS_CLIENT_SERVICE';
let app: INestApplication;
let client: ClientProxy;
let tenantId: string;
beforeAll(async () => {
jest
.spyOn(DidsService.prototype, 'getPublicDid')
.mockResolvedValue(new DidDocument(mockDidDocument));
const moduleRef = await Test.createTestingModule({
imports: [
mockConfigModule(3005),
AgentModule,
DidsModule,
TenantsModule,
ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
],
}).compile();
app = moduleRef.createNestApplication();
app.connectMicroservice({ transport: Transport.NATS });
await app.startAllMicroservices();
await app.init();
client = app.get(TOKEN);
await client.connect();
const ts = app.get(TenantsService);
const { id } = await ts.create(TOKEN);
tenantId = id;
});
afterAll(async () => {
await app.close();
client.close();
});
it(EventDidsPublicDid.token, async () => {
const response$ = client.send<EventDidsPublicDid, EventDidsPublicDidInput>(
EventDidsPublicDid.token,
{ tenantId },
);
const response = await firstValueFrom(response$);
const eventInstance = EventDidsPublicDid.fromEvent(response);
expect(eventInstance.instance).toMatchObject(mockDidDocument);
});
it(EventDidsResolve.token, async () => {
const response$ = client.send<EventDidsResolve, EventDidsResolveInput>(
EventDidsResolve.token,
{
did: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH',
tenantId,
},
);
const response = await firstValueFrom(response$);
const eventInstance = EventDidsResolve.fromEvent(response);
expect(eventInstance.instance.toJSON()).toStrictEqual({
'@context': [
'https://w3id.org/did/v1',
'https://w3id.org/security/suites/ed25519-2018/v1',
'https://w3id.org/security/suites/x25519-2019/v1',
],
id: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH',
verificationMethod: [
{
id: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH',
type: 'Ed25519VerificationKey2018',
controller:
'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH',
publicKeyBase58: 'B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u',
},
],
authentication: [
'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH',
],
assertionMethod: [
'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH',
],
keyAgreement: [
{
id: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc',
type: 'X25519KeyAgreementKey2019',
controller:
'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH',
publicKeyBase58: 'JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr',
},
],
capabilityInvocation: [
'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH',
],
capabilityDelegation: [
'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH',
],
});
});
});
......@@ -3,7 +3,7 @@ import config from '../jest.config.js';
/** @type {import('jest').Config} */
export default {
...config,
testTimeout: 12000,
testTimeout: 24000,
rootDir: '.',
testRegex: '.*\\.e2e-spec\\.ts$',
};
......@@ -5,7 +5,7 @@ process.env.NATS_URL = 'nats://localhost:4222';
process.env.ECSURL = 'http://localhost:9200/';
process.env.AGENT_HOST = 'http://localhost';
process.env.AGENT_NAME = 'ssi-abstraction-agent';
process.env.AGENT_INBOUND_PORT = ':4000';
process.env.AGENT_INBOUND_PORT = 4000;
process.env.AGENT_URL_PATH = '/ocm/abstraction';
process.env.AGENT_PUBLIC_DID_SEED = '6b8b882e2618fa5d45ee7229ca880083';
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 type { EventTenantsCreateInput } 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';
import { EventTenantsCreate } from '@ocm/shared';
import { firstValueFrom } from 'rxjs';
import { AgentModule } from '../src/agent/agent.module.js';
import { AgentService } from '../src/agent/agent.service.js';
import { TenantsModule } from '../src/agent/tenants/tenants.module.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';
describe('Tenants', () => {
const TOKEN = 'TENANTS_CLIENT_SERVICE';
let app: INestApplication;
let client: ClientProxy;
beforeAll(async () => {
jest
.spyOn(AgentService.prototype, 'getPublicDid')
.mockImplementation(() =>
Promise.resolve(new DidDocument(mockDidDocument)),
);
const moduleRef = await Test.createTestingModule({
imports: [
mockConfigModule(3000),
mockConfigModule(3005),
AgentModule,
TenantsModule,
ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]),
],
}).compile();
......@@ -56,21 +37,29 @@ describe('Agent', () => {
await client.connect();
});
it('info.publicDid', async () => {
const response$: Observable<EventInfoPublicDid> = client.send(
'info.publicDid',
{},
afterAll(async () => {
await app.close();
client.close();
});
it(EventTenantsCreate.token, async () => {
const response$ = client.send<EventTenantsCreate, EventTenantsCreateInput>(
EventTenantsCreate.token,
{
label: 'my-new-tenant',
},
);
const response = await firstValueFrom(response$);
const eventInstance = EventTenantsCreate.fromEvent(response);
expect(response.data).toMatchObject({
didDocument: mockDidDocument,
expect(eventInstance.instance.toJSON()).toMatchObject({
config: {
label: 'my-new-tenant',
walletConfig: {
keyDerivationMethod: 'RAW',
},
},
});
});
afterAll(async () => {
await app.close();
client.close();
});
});
......@@ -603,6 +603,9 @@ importers:
'@nestjs/terminus':
specifier: ^10.1.1
version: 10.1.1(@nestjs/axios@3.0.1)(@nestjs/common@10.2.10)(@nestjs/core@10.2.10)(@nestjs/microservices@10.2.10)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@ocm/shared':
specifier: workspace:*
version: link:../shared
axios:
specifier: ^1.6.2
version: 1.6.2
......@@ -682,6 +685,9 @@ importers:
'@aries-framework/core':
specifier: 0.4.2
version: 0.4.2(expo@49.0.18)(react-native@0.72.7)
'@aries-framework/tenants':
specifier: ^0.4.2
version: 0.4.2(expo@49.0.18)(react-native@0.72.7)
'@elastic/ecs-winston-format':
specifier: ^1.5.0
version: 1.5.0
......@@ -758,6 +764,9 @@ importers:
'@aries-framework/node':
specifier: 0.4.2
version: 0.4.2(expo@49.0.18)(react-native@0.72.7)
'@aries-framework/tenants':
specifier: ^0.4.2
version: 0.4.2(expo@49.0.18)(react-native@0.72.7)
'@elastic/ecs-winston-format':
specifier: ^1.5.0
version: 1.5.0
......@@ -1062,6 +1071,19 @@ packages:
- web-streams-polyfill
dev: false
 
/@aries-framework/tenants@0.4.2(expo@49.0.18)(react-native@0.72.7):
resolution: {integrity: sha512-dRgneBY4z6YAn9ieNSeLEqhW+H03aFZwnxcnWhJfSGeHKUl0kMPmjCqvpP3NFhdB/rX92U9OOZDruIv2efM2ig==}
dependencies:
'@aries-framework/core': 0.4.2(expo@49.0.18)(react-native@0.72.7)
async-mutex: 0.4.0
transitivePeerDependencies:
- domexception
- encoding
- expo
- react-native
- web-streams-polyfill
dev: false
/@babel/code-frame@7.10.4:
resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==}
dependencies:
......@@ -6144,6 +6166,12 @@ packages:
dev: false
optional: true
 
/async-mutex@0.4.0:
resolution: {integrity: sha512-eJFZ1YhRR8UN8eBLoNzcDPcy/jqjsg6I1AP+KvWQX80BqOSW1oJPJXDylPUEeMr2ZQvHgnQ//Lp6f3RQ1zI7HA==}
dependencies:
tslib: 2.6.2
dev: false
/async-value-promise@1.1.1:
resolution: {integrity: sha512-c2RFDKjJle1rHa0YxN9Ysu97/QBu3Wa+NOejJxsX+1qVDJrkD3JL/GN1B3gaILAEXJXbu/4Z1lcoCHFESe/APA==}
requiresBuild: true
......@@ -8974,7 +9002,7 @@ packages:
semver: 7.5.4
tapable: 2.2.1
typescript: 5.2.2
webpack: 5.89.0(@swc/core@1.3.96)
webpack: 5.89.0
dev: true
 
/form-data@3.0.1:
......@@ -10313,7 +10341,7 @@ packages:
pretty-format: 29.7.0
slash: 3.0.0
strip-json-comments: 3.1.1
ts-node: 10.9.1(@swc/core@1.3.96)(@types/node@20.9.0)(typescript@5.2.2)
ts-node: 10.9.1(@types/node@20.9.4)(typescript@5.3.2)
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
......