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 16 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-server/package-lock.json
iFergal marked this conversation as resolved.
Show resolved Hide resolved

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions src/core/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import {
PeerConnectionStorage,
NotificationRecord,
NotificationStorage,
IpexMessageStorage,
IpexMessageRecord,
} from "./records";
import { KeyStoreKeys, SecureStorage } from "../storage";
import { MultiSigService } from "./services/multiSigService";
Expand Down Expand Up @@ -75,6 +77,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 @@ -120,6 +123,7 @@ class Agent {
this.identifierStorage,
this.credentialStorage,
this.notificationStorage,
this.ipexMessageStorage,
this.operationPendingStorage
);
}
Expand All @@ -133,6 +137,7 @@ class Agent {
this.connectionStorage,
this.connectionNoteStorage,
this.credentialStorage,
this.ipexMessageStorage,
this.operationPendingStorage
);
}
Expand Down Expand Up @@ -339,6 +344,9 @@ class Agent {
this.operationPendingStorage = new OperationPendingStorage(
this.getStorageService<OperationPendingRecord>(this.storageSession)
);
this.ipexMessageStorage = new IpexMessageStorage(
this.getStorageService<IpexMessageRecord>(this.storageSession)
);
this.agentServicesProps = {
signifyClient: this.signifyClient,
eventService: new EventService(),
Expand Down
39 changes: 39 additions & 0 deletions src/core/agent/agent.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,41 @@ type ConnectionNoteDetails = {
message: string;
};

interface JSONObject {
[x: string]: JSONValue;
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface JSONArray extends Array<JSONValue> {}

type JSONValue = string | number | boolean | JSONObject | JSONArray;

type IpexMessage = {
exn: {
v: string;
t: string;
d: string;
i: string;
p: string;
dt: string;
r: string;
q: JSONValue;
a: any;
e: any;
};
pathed: {
acdc: string;
iss: string;
anc: string;
};
};

type IpexMessageDetails = {
id: string;
content: IpexMessage;
createdAt: Date;
};

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

interface ConnectionDetails extends ConnectionShortDetails {
Expand Down Expand Up @@ -185,6 +220,8 @@ enum NotificationRoute {

enum ExchangeRoute {
IpexAdmit = "/ipex/admit",
IpexGrant = "/ipex/grant",
IpexApply = "/ipex/apply",
}

interface BranAndMnemonic {
Expand Down Expand Up @@ -221,6 +258,8 @@ export type {
KeriaStatusChangedEvent,
AgentUrls,
BranAndMnemonic,
IpexMessage,
IpexMessageDetails,
NotificationRpy,
AuthorizationRequestExn,
};
10 changes: 0 additions & 10 deletions src/core/agent/records/credentialStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,6 @@ class CredentialStorage {
return record;
}

async getCredentialMetadataByConnectionId(connectionId: string) {
const record = await this.storageService.findAllByQuery(
{
connectionId,
},
CredentialMetadataRecord
);
return record;
}

async saveCredentialMetadataRecord(data: CredentialMetadataRecordProps) {
const record = new CredentialMetadataRecord(data);
return this.storageService.save(record);
Expand Down
2 changes: 2 additions & 0 deletions src/core/agent/records/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ export * from "./connectionStorage";
export * from "./connectionNoteStorage";
export * from "./notificationStorage";
export * from "./operationPendingStorage";
export * from "./ipexMessageRecord";
export * from "./ipexMessageStorage";
45 changes: 45 additions & 0 deletions src/core/agent/records/ipexMessageRecord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BaseRecord } from "../../storage/storage.types";
import { IpexMessage } from "../agent.types";
import { ConnectionHistoryType } from "../services/connection.types";

interface IpexMessageProps {
id: string;
credentialType: string;
content: IpexMessage;
historyType: ConnectionHistoryType;
createdAt?: Date;
connectionId: string;
}

class IpexMessageRecord extends BaseRecord {
credentialType!: string;
content!: IpexMessage;
connectionId!: string;
historyType!: ConnectionHistoryType;

static readonly type = "IpexMessageRecord";
readonly type = IpexMessageRecord.type;

constructor(props: IpexMessageProps) {
super();

if (props) {
this.id = props.id;
this.credentialType = props.credentialType;
this.content = props.content;
this.connectionId = props.connectionId;
this.historyType = props.historyType;
this.createdAt = props.createdAt ?? new Date();
}
}

getTags() {
return {
...this._tags,
connectionId: this.connectionId,
};
}
}

export { IpexMessageRecord };
export type { IpexMessageProps };
80 changes: 80 additions & 0 deletions src/core/agent/records/ipexMessageStorage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { StorageService } from "../../storage/storage.types";
import { ConnectionHistoryType } from "../services/connection.types";
import { IpexMessageRecord, IpexMessageProps } from "./ipexMessageRecord";
import { IpexMessageStorage } from "./ipexMessageStorage";

const storageService = jest.mocked<StorageService<IpexMessageRecord>>({
save: jest.fn(),
delete: jest.fn(),
deleteById: jest.fn(),
update: jest.fn(),
findById: jest.fn(),
findAllByQuery: jest.fn(),
getAll: jest.fn(),
});

const ipexMessageStorage = new IpexMessageStorage(storageService);

const id1 = "id1";
const id2 = "id2";

const now = new Date();
const ipexMessage = {
exn: {
v: "string",
d: "string",
t: "string",
i: "string",
p: "string",
dt: "string",
r: "string",
q: {},
a: {},
e: {},
},
pathed: {
acdc: "string",
iss: "string",
anc: "string",
},
};
const ipexMessageRecordProps: IpexMessageProps = {
id: id1,
credentialType: "IIW 2024 Demo Day Attendee",
createdAt: now,
connectionId: "connectionId",
content: ipexMessage,
historyType: ConnectionHistoryType.CREDENTIAL_ISSUANCE,
};

const ipexMessageRecordA = new IpexMessageRecord(ipexMessageRecordProps);

const ipexMessageRecordB = new IpexMessageRecord({
...ipexMessageRecordProps,
id: id2,
historyType: ConnectionHistoryType.CREDENTIAL_UPDATE,
});

describe("ipexMessage Storage", () => {
beforeEach(() => {
jest.resetAllMocks();
});

test("Should save ipexMessage record", async () => {
storageService.save.mockResolvedValue(ipexMessageRecordA);
await ipexMessageStorage.createIpexMessageRecord(ipexMessageRecordProps);
expect(storageService.save).toBeCalledWith(ipexMessageRecordA);
});

test("Should find ipexMessage record by connectionId", async () => {
storageService.findAllByQuery.mockResolvedValue([
ipexMessageRecordA,
ipexMessageRecordB,
]);
const result =
await ipexMessageStorage.getIpexMessageMetadataByConnectionId(
ipexMessageRecordA.connectionId
);
expect(result).toEqual([ipexMessageRecordA, ipexMessageRecordB]);
});
});
31 changes: 31 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,31 @@
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 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/connection.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ interface KeriaContact {
}

enum ConnectionHistoryType {
CREDENTIAL_ACCEPTED,
CREDENTIAL_ISSUANCE,
CREDENTIAL_REQUEST_PRESENT,
CREDENTIAL_UPDATE,
}

export { ConnectionHistoryType };
Expand Down
Loading
Loading