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
Commits on Source (2)
Showing
with 552 additions and 35 deletions
import type { BaseEventInput } from './baseEvents.js';
import {
CredentialExchangeRecord,
JsonTransformer,
} from '@aries-framework/core';
import { BaseEvent } from './baseEvents.js';
export type EventDidcommAnonCredsCredentialsGetAllInput = BaseEventInput;
export class EventDidcommAnonCredsCredentialsGetAll extends BaseEvent<
Array<CredentialExchangeRecord>
> {
public static token = 'didcomm.anoncreds.credentials.getAll';
public get instance() {
return this.data.map((d) =>
JsonTransformer.fromJSON(d, CredentialExchangeRecord),
);
}
public static fromEvent(e: EventDidcommAnonCredsCredentialsGetAll) {
return new EventDidcommAnonCredsCredentialsGetAll(
e.data,
e.tenantId,
e.id,
e.type,
e.timestamp,
);
}
}
export type EventDidcommAnonCredsCredentialsGetByIdInput = BaseEventInput<{
credentialRecordId: string;
}>;
export class EventDidcommAnonCredsCredentialsGetById extends BaseEvent<CredentialExchangeRecord | null> {
public static token = 'didcomm.anoncreds.credentials.getById';
public get instance() {
return this.data
? JsonTransformer.fromJSON(this.data, CredentialExchangeRecord)
: null;
}
public static fromEvent(e: EventDidcommAnonCredsCredentialsGetById) {
return new EventDidcommAnonCredsCredentialsGetById(
e.data,
e.tenantId,
e.id,
e.type,
e.timestamp,
);
}
}
export type EventDidcommAnonCredsCredentialsOfferInput = BaseEventInput<{
connectionId: string;
credentialDefinitionId: string;
attributes: Array<{ name: string; value: string; mimeType?: string }>;
}>;
export class EventDidcommAnonCredsCredentialsOffer extends BaseEvent<CredentialExchangeRecord> {
public static token = 'didcomm.anoncreds.credentials.offer';
public get instance() {
return JsonTransformer.fromJSON(this.data, CredentialExchangeRecord);
}
public static fromEvent(e: EventDidcommAnonCredsCredentialsOffer) {
return new EventDidcommAnonCredsCredentialsOffer(
e.data,
e.tenantId,
e.id,
e.type,
e.timestamp,
);
}
}
export type EventDidcommAnonCredsCredentialsOfferToSelfInput = Omit<
EventDidcommAnonCredsCredentialsOfferInput,
'connectionId'
>;
export class EventDidcommAnonCredsCredentialsOfferToSelf extends BaseEvent<CredentialExchangeRecord> {
public static token = 'didcomm.anoncreds.credentials.offerToSelf';
public get instance() {
return JsonTransformer.fromJSON(this.data, CredentialExchangeRecord);
}
public static fromEvent(e: EventDidcommAnonCredsCredentialsOfferToSelf) {
return new EventDidcommAnonCredsCredentialsOfferToSelf(
e.data,
e.tenantId,
e.id,
e.type,
e.timestamp,
);
}
}
......@@ -9,3 +9,4 @@ export * from './events/didEvents.js';
export * from './events/tenantEvents.js';
export * from './events/schemaEvents.js';
export * from './events/credentialDefinitionEvents.js';
export * from './events/credentialEvents.js';
......@@ -3,7 +3,11 @@ import type { InitConfig } from '@aries-framework/core';
import type { IndyVdrPoolConfig } from '@aries-framework/indy-vdr';
import type { OnApplicationShutdown } from '@nestjs/common';
import { AnonCredsModule } from '@aries-framework/anoncreds';
import {
AnonCredsCredentialFormatService,
AnonCredsModule,
LegacyIndyCredentialFormatService,
} from '@aries-framework/anoncreds';
import { AnonCredsRsModule } from '@aries-framework/anoncreds-rs';
import { AskarModule } from '@aries-framework/askar';
import {
......@@ -19,6 +23,7 @@ import {
LogLevel,
PeerDidRegistrar,
PeerDidResolver,
V2CredentialProtocol,
WebDidResolver,
} from '@aries-framework/core';
import {
......@@ -94,6 +99,14 @@ export class AgentService implements OnApplicationShutdown {
}),
credentials: new CredentialsModule({
autoAcceptCredentials: autoAcceptCredential,
credentialProtocols: [
new V2CredentialProtocol({
credentialFormats: [
new AnonCredsCredentialFormatService(),
new LegacyIndyCredentialFormatService(),
],
}),
],
}),
anoncredsRs: new AnonCredsRsModule({ anoncreds }),
......
import {
CredentialExchangeRecord,
CredentialState,
} from '@aries-framework/core';
import { Test } from '@nestjs/testing';
import { mockConfigModule } from '../../../config/__tests__/mockConfig.js';
import { AgentModule } from '../../agent.module.js';
import { AnonCredsCredentialsController } from '../anoncredsCredentials.controller.js';
import { AnonCredsCredentialsService } from '../anoncredsCredentials.service.js';
describe('AnonCredsCredentialsController', () => {
let credentialsController: AnonCredsCredentialsController;
let credentialsService: AnonCredsCredentialsService;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
imports: [mockConfigModule(), AgentModule],
controllers: [AnonCredsCredentialsController],
providers: [AnonCredsCredentialsService],
}).compile();
credentialsService = moduleRef.get(AnonCredsCredentialsService);
credentialsController = moduleRef.get(AnonCredsCredentialsController);
});
describe('get all', () => {
it('should get all the credential records of the agent', async () => {
const result: Array<CredentialExchangeRecord> = [];
jest.spyOn(credentialsService, 'getAll').mockResolvedValue(result);
const event = await credentialsController.getAll({
tenantId: 'some-id',
});
expect(event.data).toStrictEqual(result);
});
});
describe('get by id', () => {
it('should get a credential record by id', async () => {
const result: CredentialExchangeRecord | null = null;
jest.spyOn(credentialsService, 'getById').mockResolvedValue(result);
const event = await credentialsController.getById({
tenantId: 'some-id',
credentialRecordId: 'some-id',
});
expect(event.data).toStrictEqual(result);
});
});
describe('offer', () => {
it('should offer a credential', async () => {
const result: CredentialExchangeRecord = new CredentialExchangeRecord({
state: CredentialState.Done,
threadId: 'some-id',
protocolVersion: 'v2',
});
jest.spyOn(credentialsService, 'offer').mockResolvedValue(result);
const event = await credentialsController.offer({
tenantId: 'some-id',
connectionId: 'some-id',
credentialDefinitionId: 'some-id',
attributes: [
{ name: 'Name', value: 'Berend', mimeType: 'application/text' },
{ name: 'Age', value: '25' },
],
});
expect(event.data).toStrictEqual(result);
});
});
describe('offer to self', () => {
it('should offer a credential to self', async () => {
const result: CredentialExchangeRecord = new CredentialExchangeRecord({
state: CredentialState.Done,
threadId: 'some-id',
protocolVersion: 'v2',
});
jest.spyOn(credentialsService, 'offerToSelf').mockResolvedValue(result);
const event = await credentialsController.offerToSelf({
tenantId: 'some-id',
credentialDefinitionId: 'some-id',
attributes: [
{ name: 'Name', value: 'Berend', mimeType: 'application/text' },
{ name: 'Age', value: '25' },
],
});
expect(event.data).toStrictEqual(result);
});
});
});
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import {
EventDidcommAnonCredsCredentialsGetAll,
EventDidcommAnonCredsCredentialsGetAllInput,
EventDidcommAnonCredsCredentialsGetById,
EventDidcommAnonCredsCredentialsGetByIdInput,
EventDidcommAnonCredsCredentialsOffer,
EventDidcommAnonCredsCredentialsOfferInput,
EventDidcommAnonCredsCredentialsOfferToSelfInput,
EventDidcommAnonCredsCredentialsOfferToSelf,
} from '@ocm/shared';
import { AnonCredsCredentialsService } from './anoncredsCredentials.service.js';
@Controller('anoncredsCredentials')
export class AnonCredsCredentialsController {
public constructor(private credentialsService: AnonCredsCredentialsService) {}
@MessagePattern(EventDidcommAnonCredsCredentialsGetAll.token)
public async getAll(
options: EventDidcommAnonCredsCredentialsGetAllInput,
): Promise<EventDidcommAnonCredsCredentialsGetAll> {
return new EventDidcommAnonCredsCredentialsGetAll(
await this.credentialsService.getAll(options),
options.tenantId,
);
}
@MessagePattern(EventDidcommAnonCredsCredentialsGetById.token)
public async getById(
options: EventDidcommAnonCredsCredentialsGetByIdInput,
): Promise<EventDidcommAnonCredsCredentialsGetById> {
return new EventDidcommAnonCredsCredentialsGetById(
await this.credentialsService.getById(options),
options.tenantId,
);
}
@MessagePattern(EventDidcommAnonCredsCredentialsOffer.token)
public async offer(
options: EventDidcommAnonCredsCredentialsOfferInput,
): Promise<EventDidcommAnonCredsCredentialsOffer> {
return new EventDidcommAnonCredsCredentialsOffer(
await this.credentialsService.offer(options),
options.tenantId,
);
}
@MessagePattern(EventDidcommAnonCredsCredentialsOfferToSelf.token)
public async offerToSelf(
options: EventDidcommAnonCredsCredentialsOfferToSelfInput,
): Promise<EventDidcommAnonCredsCredentialsOfferToSelf> {
return new EventDidcommAnonCredsCredentialsOfferToSelf(
await this.credentialsService.offerToSelf(options),
options.tenantId,
);
}
}
import { Module } from '@nestjs/common';
import { AgentModule } from '../agent.module.js';
import { AnonCredsCredentialsController } from './anoncredsCredentials.controller.js';
import { AnonCredsCredentialsService } from './anoncredsCredentials.service.js';
@Module({
imports: [AgentModule],
providers: [AnonCredsCredentialsService],
controllers: [AnonCredsCredentialsController],
})
export class AnonCredsCredentialsModule {}
import type {
EventDidcommAnonCredsCredentialsGetAllInput,
EventDidcommAnonCredsCredentialsGetByIdInput,
EventDidcommAnonCredsCredentialsOfferInput,
EventDidcommAnonCredsCredentialsOfferToSelfInput,
} from '@ocm/shared';
import {
AutoAcceptCredential,
type CredentialExchangeRecord,
} from '@aries-framework/core';
import { Injectable } from '@nestjs/common';
import { MetadataTokens } from '../../common/constants.js';
import { WithTenantService } from '../withTenantService.js';
@Injectable()
export class AnonCredsCredentialsService {
public constructor(private withTenantService: WithTenantService) {}
public async getAll({
tenantId,
}: EventDidcommAnonCredsCredentialsGetAllInput): Promise<
Array<CredentialExchangeRecord>
> {
return this.withTenantService.invoke(tenantId, (t) =>
t.credentials.getAll(),
);
}
public async getById({
tenantId,
credentialRecordId,
}: EventDidcommAnonCredsCredentialsGetByIdInput): Promise<CredentialExchangeRecord | null> {
return this.withTenantService.invoke(tenantId, (t) =>
t.credentials.findById(credentialRecordId),
);
}
public async offer({
tenantId,
connectionId,
credentialDefinitionId,
attributes,
}: EventDidcommAnonCredsCredentialsOfferInput): Promise<CredentialExchangeRecord> {
return this.withTenantService.invoke(tenantId, (t) =>
t.credentials.offerCredential({
protocolVersion: 'v2',
connectionId,
credentialFormats: {
anoncreds: { credentialDefinitionId, attributes },
},
}),
);
}
public async offerToSelf({
tenantId,
credentialDefinitionId,
attributes,
}: EventDidcommAnonCredsCredentialsOfferToSelfInput): Promise<CredentialExchangeRecord> {
return this.withTenantService.invoke(tenantId, async (t) => {
const connections = await t.connections.getAll();
const connection = connections.find((c) => {
const metadata = c.metadata.get<{ withSelf: boolean }>(
MetadataTokens.GAIA_X_CONNECTION_METADATA_KEY,
);
return metadata && metadata.withSelf === true;
});
if (!connection) {
throw new Error(
'Cannot offer a credential to yourself as there is no connection',
);
}
if (!connection.isReady) {
throw new Error('Connection with yourself is not ready, yet');
}
return t.credentials.offerCredential({
protocolVersion: 'v2',
autoAcceptCredential: AutoAcceptCredential.Always,
connectionId: connection.id,
credentialFormats: {
anoncreds: { credentialDefinitionId, attributes },
},
});
});
}
}
......@@ -30,11 +30,11 @@ describe('ConnectionsController', () => {
const result: Array<ConnectionRecord> = [];
jest.spyOn(connectionsService, 'getAll').mockResolvedValue(result);
const connectionsEvent = await connectionsController.getAll({
const event = await connectionsController.getAll({
tenantId: 'some-id',
});
expect(connectionsEvent.data).toStrictEqual(result);
expect(event.data).toStrictEqual(result);
});
});
......@@ -43,12 +43,12 @@ describe('ConnectionsController', () => {
const result: ConnectionRecord | null = null;
jest.spyOn(connectionsService, 'getById').mockResolvedValue(result);
const connectionsEvent = await connectionsController.getById({
const event = await connectionsController.getById({
id: 'id',
tenantId: 'some-id',
});
expect(connectionsEvent.data).toStrictEqual(result);
expect(event.data).toStrictEqual(result);
});
});
......@@ -63,12 +63,11 @@ describe('ConnectionsController', () => {
.spyOn(connectionsService, 'createConnectionWithSelf')
.mockResolvedValue(result);
const connectionsEvent =
await connectionsController.createConnectionWithSelf({
tenantId: 'some-id',
});
const event = await connectionsController.createConnectionWithSelf({
tenantId: 'some-id',
});
expect(connectionsEvent.data).toStrictEqual(result);
expect(event.data).toStrictEqual(result);
});
});
});
......@@ -24,15 +24,13 @@ import { WithTenantService } from '../withTenantService.js';
@Injectable()
export class ConnectionsService {
public agent: AppAgent;
public withTenantService: WithTenantService;
private agent: AppAgent;
public constructor(
agentService: AgentService,
withTenantService: WithTenantService,
private withTenantService: WithTenantService,
) {
this.agent = agentService.agent;
this.withTenantService = withTenantService;
}
public async getAll({
......@@ -104,6 +102,7 @@ export class ConnectionsService {
MetadataTokens.GAIA_X_CONNECTION_METADATA_KEY,
{
trusted: true,
withSelf: true,
},
);
......
......@@ -12,11 +12,7 @@ import { WithTenantService } from '../withTenantService.js';
@Injectable()
export class CredentialDefinitionsService {
public withTenantService: WithTenantService;
public constructor(withTenantService: WithTenantService) {
this.withTenantService = withTenantService;
}
public constructor(private withTenantService: WithTenantService) {}
public async getAll({
tenantId,
......
......@@ -9,16 +9,10 @@ import { WithTenantService } from '../withTenantService.js';
@Injectable()
export class DidsService {
private withTenantService: WithTenantService;
private configService: ConfigService;
public constructor(
withTenantService: WithTenantService,
configService: ConfigService,
) {
this.withTenantService = withTenantService;
this.configService = configService;
}
private withTenantService: WithTenantService,
private configService: ConfigService,
) {}
public async resolve({ did, tenantId }: EventDidsResolveInput) {
return this.withTenantService.invoke(tenantId, async (t) => {
......
......@@ -12,11 +12,7 @@ import { WithTenantService } from '../withTenantService.js';
@Injectable()
export class SchemasService {
public withTenantService: WithTenantService;
public constructor(withTenantService: WithTenantService) {
this.withTenantService = withTenantService;
}
public constructor(private withTenantService: WithTenantService) {}
public async getAll({
tenantId,
......
......@@ -6,7 +6,7 @@ import { AgentService } from '../agent.service.js';
@Injectable()
export class TenantsService {
public agent: AppAgent;
private agent: AppAgent;
public constructor(agentService: AgentService) {
this.agent = agentService.agent;
......
......@@ -5,6 +5,7 @@ import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from '@ocm/shared';
import { AgentModule } from './agent/agent.module.js';
import { AnonCredsCredentialsModule } from './agent/anoncredsCredentials/anoncredsCredentials.module.js';
import { ConnectionsModule } from './agent/connections/connections.module.js';
import { CredentialDefinitionsModule } from './agent/credentialDefinitions/credentialDefinitions.module.js';
import { SchemasModule } from './agent/schemas/schemas.module.js';
......@@ -26,6 +27,7 @@ import { validationSchema } from './config/validation.js';
CredentialDefinitionsModule,
DidsModule,
SchemasModule,
AnonCredsCredentialsModule,
TenantsModule,
],
controllers: [HealthController],
......
import type { INestApplication } from '@nestjs/common';
import type { ClientProxy } from '@nestjs/microservices';
import type {
EventDidcommAnonCredsCredentialsGetAllInput,
EventDidcommAnonCredsCredentialsGetByIdInput,
EventDidcommAnonCredsCredentialsOfferToSelfInput,
} from '@ocm/shared';
import { AutoAcceptCredential } from '@aries-framework/core';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { Test } from '@nestjs/testing';
import {
EventDidcommAnonCredsCredentialsGetAll,
EventDidcommAnonCredsCredentialsGetById,
EventDidcommAnonCredsCredentialsOfferToSelf,
} from '@ocm/shared';
import { firstValueFrom } from 'rxjs';
import { AgentModule } from '../src/agent/agent.module.js';
import { AnonCredsCredentialsModule } from '../src/agent/anoncredsCredentials/anoncredsCredentials.module.js';
import { ConnectionsModule } from '../src/agent/connections/connections.module.js';
import { ConnectionsService } from '../src/agent/connections/connections.service.js';
import { CredentialDefinitionsModule } from '../src/agent/credentialDefinitions/credentialDefinitions.module.js';
import { CredentialDefinitionsService } from '../src/agent/credentialDefinitions/credentialDefinitions.service.js';
import { DidsModule } from '../src/agent/dids/dids.module.js';
import { DidsService } from '../src/agent/dids/dids.service.js';
import { SchemasModule } from '../src/agent/schemas/schemas.module.js';
import { SchemasService } from '../src/agent/schemas/schemas.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';
describe('Credentials', () => {
const TOKEN = 'CREDENTIALS_CLIENT_SERVICE';
let app: INestApplication;
let client: ClientProxy;
let tenantId: string;
let issuerDid: string;
let credentialDefinitionId: string;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [
mockConfigModule(3004, true),
AgentModule,
ConnectionsModule,
SchemasModule,
CredentialDefinitionsModule,
AnonCredsCredentialsModule,
TenantsModule,
DidsModule,
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 tenantsService = app.get(TenantsService);
const { id } = await tenantsService.create(TOKEN);
tenantId = id;
const connectionsService = app.get(ConnectionsService);
await connectionsService.createConnectionWithSelf({ tenantId });
const didsService = app.get(DidsService);
const [did] = await didsService.registerDidIndyFromSeed({
tenantId,
seed: '12312367897123300000000000000000',
});
issuerDid = did;
const schemaService = app.get(SchemasService);
const { schemaId } = await schemaService.register({
issuerDid,
tenantId,
name: 'test-schema-name',
version: `1.${new Date().getTime()}`,
attributeNames: ['Name', 'Age'],
});
const credentialDefinitionService = app.get(CredentialDefinitionsService);
const { credentialDefinitionId: cdi } =
await credentialDefinitionService.register({
tenantId,
issuerDid,
schemaId,
tag: `default-${new Date().getTime()}`,
});
credentialDefinitionId = cdi;
});
afterAll(async () => {
await app.close();
client.close();
});
it(EventDidcommAnonCredsCredentialsGetAll.token, async () => {
const response$ = client.send<
EventDidcommAnonCredsCredentialsGetAll,
EventDidcommAnonCredsCredentialsGetAllInput
>(EventDidcommAnonCredsCredentialsGetAll.token, { tenantId });
const response = await firstValueFrom(response$);
const eventInstance =
EventDidcommAnonCredsCredentialsGetAll.fromEvent(response);
expect(eventInstance.instance).toEqual(expect.arrayContaining([]));
});
it(EventDidcommAnonCredsCredentialsGetById.token, async () => {
const response$ = client.send<
EventDidcommAnonCredsCredentialsGetById,
EventDidcommAnonCredsCredentialsGetByIdInput
>(EventDidcommAnonCredsCredentialsGetById.token, {
tenantId,
credentialRecordId: 'some-id',
});
const response = await firstValueFrom(response$);
const eventInstance =
EventDidcommAnonCredsCredentialsGetById.fromEvent(response);
expect(eventInstance.instance).toEqual(null);
});
it(EventDidcommAnonCredsCredentialsOfferToSelf.token, async () => {
const attributes = [
{ name: 'Name', value: 'Berend' },
{ name: 'Age', value: '25' },
];
const response$ = client.send<
EventDidcommAnonCredsCredentialsOfferToSelf,
EventDidcommAnonCredsCredentialsOfferToSelfInput
>(EventDidcommAnonCredsCredentialsOfferToSelf.token, {
tenantId,
credentialDefinitionId,
attributes,
});
const response = await firstValueFrom(response$);
const eventInstance =
EventDidcommAnonCredsCredentialsOfferToSelf.fromEvent(response);
expect(eventInstance.instance).toMatchObject({
autoAcceptCredential: AutoAcceptCredential.Always,
});
});
});
......@@ -3,7 +3,7 @@ import config from '../jest.config.js';
/** @type {import('jest').Config} */
export default {
...config,
testTimeout: 24000,
testTimeout: 36000,
rootDir: '.',
testRegex: '.*\\.e2e-spec\\.ts$',
};