Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): linking of ipex flows to contacts #422

Merged
merged 21 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6ef8a97
feat: rework some API in cred server
Sotatek-BaoHoanga Mar 4, 2024
ce55883
feat: add apply schema API
Sotatek-BaoHoanga Mar 5, 2024
e9e38eb
refactor: function and var name and dependency link
Sotatek-BaoHoanga Mar 5, 2024
814e78b
feat: add full ipex flow for idw and cred server
Sotatek-BaoHoanga Mar 11, 2024
c8ce453
refactor: testing and some missing logic
Sotatek-BaoHoanga Mar 11, 2024
4f0156e
feature: save linked IPEX messages for connections
Sotatek-HocNguyena Apr 16, 2024
6f29933
Merge branch 'develop' of github.com:cardano-foundation/cf-identity-w…
Sotatek-HocNguyena May 31, 2024
c035d41
refactor: change the file contruction
Sotatek-HocNguyena Jun 3, 2024
f66f763
Merge branch 'develop' of github.com:cardano-foundation/cf-identity-w…
Sotatek-HocNguyena Jun 20, 2024
5cd3036
Merge branch 'develop' of github.com:cardano-foundation/cf-identity-w…
Sotatek-TungNguyen2a Jul 26, 2024
44c7d0f
Merge branch 'develop' of github.com:cardano-foundation/cf-identity-w…
Sotatek-TungNguyen2a Jul 26, 2024
cc73acd
Merge branch 'develop' of github.com:cardano-foundation/cf-identity-w…
Sotatek-TungNguyen2a Jul 27, 2024
0caf0a4
feat: linking of IPEX flows to contacts
Sotatek-TungNguyen2a Jul 29, 2024
9bc6440
fix: update unit tests
Sotatek-TungNguyen2a Jul 29, 2024
5f71099
update: add isUpdate to linkedIpexMessage record
Sotatek-TungNguyen2a Jul 29, 2024
092ba49
update: add credentialType to linkedIpexMessageRecord
Sotatek-TungNguyen2a Jul 29, 2024
a6750ea
update: get linkedIpexRecord from exchange message
Sotatek-TungNguyen2a Jul 30, 2024
29115e5
update: get linkedIpexRecord id from exchange message SAID
Sotatek-TungNguyen2a Jul 30, 2024
78b490e
feat: resolve schema if we fail to get the schema
Sotatek-TungNguyen2a Jul 31, 2024
39739e0
Merge branch 'develop' of github.com:cardano-foundation/cf-identity-w…
Sotatek-TungNguyen2a Jul 31, 2024
ba8ddbc
feat: handle for apply and agree routes
Sotatek-TungNguyen2a Jul 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 102 additions & 125 deletions services/credential-issuance-server/package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ async function requestDisclosure(req: Request, res: Response): Promise<void> {
httpResponse(res, response);
}


export { issueAcdcCredential, requestDisclosure };
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum NotificationRoute {
ExnIpexOffer = "/exn/ipex/offer",
}
8 changes: 6 additions & 2 deletions src/core/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { IonicSession } from "../storage/ionicStorage/ionicSession";
import { IonicStorage } from "../storage/ionicStorage";
import { SqliteStorage } from "../storage/sqliteStorage";
import { BaseRecord } from "../storage/storage.types";
import { IpexMessageStorage } from "./records/ipexMessageStorage";
import { OperationPendingStorage } from "./records/operationPendingStorage";
import { OperationPendingRecord } from "./records/operationPendingRecord";

Expand Down Expand Up @@ -74,6 +75,7 @@ class Agent {
private connectionNoteStorage!: ConnectionNoteStorage;
private notificationStorage!: NotificationStorage;
private peerConnectionStorage!: PeerConnectionStorage;
private ipexMessageStorage!: IpexMessageStorage;
private operationPendingStorage!: OperationPendingStorage;

private signifyClient!: SignifyClient;
Expand Down Expand Up @@ -117,7 +119,8 @@ class Agent {
this.agentServicesProps,
this.identifierStorage,
this.credentialStorage,
this.notificationStorage
this.notificationStorage,
this.ipexMessageStorage
);
}
return this.ipexCommunicationService;
Expand All @@ -129,7 +132,8 @@ class Agent {
this.agentServicesProps,
this.connectionStorage,
this.connectionNoteStorage,
this.credentialStorage
this.credentialStorage,
this.ipexMessageStorage
);
}
return this.connectionService;
Expand Down
28 changes: 28 additions & 0 deletions src/core/agent/agent.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,37 @@ type ConnectionNoteDetails = {
message: string;
};

type IpexMessages = {
iFergal marked this conversation as resolved.
Show resolved Hide resolved
exn: {
v: string;
t: string;
d: string;
i: string;
p: string;
dt: string;
r: string;
q: any;
iFergal marked this conversation as resolved.
Show resolved Hide resolved
a: any;
e: any;
};
pathed: {
acdc: string;
iss: string;
anc: string;
};
};

type IpexMessageDetails = {
id: string;
content: IpexMessages;
};

type ConnectionNoteProps = Pick<ConnectionNoteDetails, "title" | "message">;

interface ConnectionDetails extends ConnectionShortDetails {
serviceEndpoints?: string[];
notes?: ConnectionNoteDetails[];
linkedIpexMessages?: IpexMessageDetails[];
iFergal marked this conversation as resolved.
Show resolved Hide resolved
}

enum ConnectionEventTypes {
Expand Down Expand Up @@ -185,4 +211,6 @@ export type {
KeriaStatusChangedEvent,
AgentUrls,
BranAndMnemonic,
IpexMessages,
IpexMessageDetails,
};
41 changes: 41 additions & 0 deletions src/core/agent/records/ipexMessageRecord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { BaseRecord } from "../../storage/storage.types";
import { IpexMessages } from "../agent.types";

interface IpexMessageProps {
id: string;
content: IpexMessages;
connectionId: string;
}

class IpexMessageRecord extends BaseRecord {
content!: IpexMessages;
connectionId!: string;

static readonly type = "IpexMessagMetadataRecord";
iFergal marked this conversation as resolved.
Show resolved Hide resolved
readonly type = IpexMessageRecord.type;

constructor(props: {
id: string;
content: IpexMessages;
connectionId: string;
}) {
super();

if (props) {
this.id = props.id;
this.content = props.content;
this.connectionId = props.connectionId;
}
}

getTags() {
return {
...this._tags,
connectionId: this.connectionId,
id: this.id,
iFergal marked this conversation as resolved.
Show resolved Hide resolved
};
}
}

export { IpexMessageRecord };
export type { IpexMessageProps };
39 changes: 39 additions & 0 deletions src/core/agent/records/ipexMessageStorage.ts
iFergal marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { StorageService } from "../../storage/storage.types";
import { IpexMessageProps, IpexMessageRecord } from "./ipexMessageRecord";

class IpexMessageStorage {
static readonly IPEX_MESSAGE_METADATA_RECORD_MISSING =
iFergal marked this conversation as resolved.
Show resolved Hide resolved
"Ipex message metadata record does not exist";
private storageService: StorageService<IpexMessageRecord>;

constructor(storageService: StorageService<IpexMessageRecord>) {
this.storageService = storageService;
}

async getIpexMessageMetadata(id: string): Promise<IpexMessageRecord> {
const metadata = await this.storageService.findById(id, IpexMessageRecord);
if (!metadata) {
throw new Error(IpexMessageStorage.IPEX_MESSAGE_METADATA_RECORD_MISSING);
}
return metadata;
}

async createIpexMessageRecord(data: IpexMessageProps): Promise<void> {
const record = new IpexMessageRecord(data);
await this.storageService.save(record);
}

async getIpexMessageMetadataByConnectionId(
connectionId: string
): Promise<IpexMessageRecord[]> {
const records = await this.storageService.findAllByQuery(
{
connectionId,
},
IpexMessageRecord
);
return records;
}
}

export { IpexMessageStorage };
4 changes: 3 additions & 1 deletion src/core/agent/services/connectionService.test.ts
iFergal marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { EventService } from "./eventService";
import { CredentialStorage, IdentifierStorage } from "../records";
import { ConfigurationService } from "../../configuration";
import { Agent } from "../agent";
import { IpexMessageStorage } from "../records/ipexMessageStorage";

const contactListMock = jest.fn();
const deleteContactMock = jest.fn();
Expand Down Expand Up @@ -127,7 +128,8 @@ const connectionService = new ConnectionService(
agentServicesProps,
connectionStorage as any,
connectionNoteStorage as any,
new CredentialStorage(session as any)
new CredentialStorage(session as any),
new IpexMessageStorage(session as any)
);

jest.mock("../../../core/agent/agent", () => ({
Expand Down
21 changes: 19 additions & 2 deletions src/core/agent/services/connectionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
AgentServicesProps,
OobiScan,
KeriConnectionType,
IpexMessageDetails,
} from "../agent.types";
import { AgentService } from "./agentService";
import { Agent } from "../agent";
Expand All @@ -22,23 +23,26 @@ import {
} from "../records";
import { OnlineOnly, waitAndGetDoneOp } from "./utils";
import { ConnectionHistoryType, KeriaContact } from "./connection.types";
import { ConfigurationService } from "../../configuration";
import { IpexMessageStorage } from "../records/ipexMessageStorage";

class ConnectionService extends AgentService {
protected readonly connectionStorage!: ConnectionStorage;
protected readonly connectionNoteStorage!: ConnectionNoteStorage;
protected readonly credentialStorage: CredentialStorage;
protected readonly ipexMessageStorage: IpexMessageStorage;

constructor(
agentServiceProps: AgentServicesProps,
connectionStorage: ConnectionStorage,
connectionNoteStorage: ConnectionNoteStorage,
credentialStorage: CredentialStorage
credentialStorage: CredentialStorage,
ipexMessageStorage: IpexMessageStorage
) {
super(agentServiceProps);
this.connectionStorage = connectionStorage;
this.connectionNoteStorage = connectionNoteStorage;
this.credentialStorage = credentialStorage;
this.ipexMessageStorage = ipexMessageStorage;
}

static readonly CONNECTION_NOTE_RECORD_NOT_FOUND =
Expand Down Expand Up @@ -161,6 +165,9 @@ class ConnectionService extends AgentService {
).createdAt.toISOString(),
serviceEndpoints: [connection.oobi],
notes: await this.getConnectNotesByConnectionId(connection.id),
linkedIpexMessages: await this.getLinkedIPEXMessageByConnectionId(
iFergal marked this conversation as resolved.
Show resolved Hide resolved
connection.id
),
};
}

Expand Down Expand Up @@ -321,6 +328,16 @@ class ConnectionService extends AgentService {
};
});
}

private async getLinkedIPEXMessageByConnectionId(
connectionId: string
): Promise<IpexMessageDetails[]> {
const messages =
await this.ipexMessageStorage.getIpexMessageMetadataByConnectionId(
connectionId
);
return messages;
}
iFergal marked this conversation as resolved.
Show resolved Hide resolved
}

export { ConnectionService };
10 changes: 9 additions & 1 deletion src/core/agent/services/ipexCommunicationService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ const credentialStorage = jest.mocked({
getCredentialMetadatasById: jest.fn(),
});

const ipexMessageRecordStorage = jest.mocked({
getIpexMessageMetadata: jest.fn(),
getIpexMessageMetadataByConnectionId: jest.fn(),
createIpexMessageRecord: jest.fn(),
});

let credentialListMock = jest.fn();
let credentialGetMock = jest.fn();
const identifierListMock = jest.fn();
Expand Down Expand Up @@ -177,7 +183,8 @@ const ipexCommunicationService = new IpexCommunicationService(
agentServicesProps,
identifierStorage as any,
credentialStorage as any,
notificationStorage as any
notificationStorage as any,
ipexMessageRecordStorage as any
);

describe("Ipex communication service of agent", () => {
Expand Down Expand Up @@ -206,6 +213,7 @@ describe("Ipex communication service of agent", () => {
connectionId: "i",
})
);
expect(ipexMessageRecordStorage.createIpexMessageRecord).toBeCalledTimes(1);
expect(credentialStorage.updateCredentialMetadata).toBeCalledWith("id", {
id: "id",
status: CredentialStatus.CONFIRMED,
Expand Down
21 changes: 20 additions & 1 deletion src/core/agent/services/ipexCommunicationService.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { v4 as uuidv4 } from "uuid";
import { Serder } from "signify-ts";
import { ConfigurationService } from "../../configuration";
import { Agent } from "../agent";
import {
AcdcEventTypes,
IpexMessages,
type AcdcStateChangedEvent,
type AgentServicesProps,
type KeriaNotification,
Expand All @@ -23,6 +25,7 @@ import {
} from "./credentialService.types";
import { OnlineOnly, getCredentialShortDetails } from "./utils";
import { CredentialsMatchingApply } from "./ipexCommunicationService.types";
import { IpexMessageStorage } from "../records/ipexMessageStorage";

class IpexCommunicationService extends AgentService {
static readonly ISSUEE_NOT_FOUND_LOCALLY =
Expand All @@ -47,17 +50,20 @@ class IpexCommunicationService extends AgentService {
protected readonly identifierStorage: IdentifierStorage;
protected readonly credentialStorage: CredentialStorage;
protected readonly notificationStorage: NotificationStorage;
protected readonly ipexMessageStorage: IpexMessageStorage;

constructor(
agentServiceProps: AgentServicesProps,
identifierStorage: IdentifierStorage,
credentialStorage: CredentialStorage,
notificationStorage: NotificationStorage
notificationStorage: NotificationStorage,
ipexMessageStorage: IpexMessageStorage
) {
super(agentServiceProps);
this.identifierStorage = identifierStorage;
this.credentialStorage = credentialStorage;
this.notificationStorage = notificationStorage;
this.ipexMessageStorage = ipexMessageStorage;
}

@OnlineOnly
Expand All @@ -69,13 +75,15 @@ class IpexCommunicationService extends AgentService {
const exn = await this.props.signifyClient
.exchanges()
.get(notifRecord.a.d as string);

const credentialId = exn.exn.e.acdc.d;
const connectionId = exn.exn.i;
await this.saveAcdcMetadataRecord(
exn.exn.e.acdc.d,
exn.exn.e.acdc.a.dt,
connectionId
);
await this.createLinkedIpexMessageRecord(exn.exn.i, exn);
iFergal marked this conversation as resolved.
Show resolved Hide resolved

this.props.eventService.emit<AcdcStateChangedEvent>({
type: AcdcEventTypes.AcdcStateChanged,
Expand Down Expand Up @@ -331,6 +339,17 @@ class IpexCommunicationService extends AgentService {
};
}
}

private async createLinkedIpexMessageRecord(
connectionId: string,
message: IpexMessages
): Promise<void> {
await this.ipexMessageStorage.createIpexMessageRecord({
iFergal marked this conversation as resolved.
Show resolved Hide resolved
id: uuidv4(),
iFergal marked this conversation as resolved.
Show resolved Hide resolved
content: message,
connectionId,
});
}
}

export { IpexCommunicationService };
Loading