Skip to content

Commit

Permalink
refactor(core): delegation service
Browse files Browse the repository at this point in the history
  • Loading branch information
iFergal committed Apr 29, 2024
1 parent 627b56e commit da7c957
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 144 deletions.
1 change: 0 additions & 1 deletion src/core/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
ready as signifyReady,
Tier,
} from "signify-ts";
import { Storage } from "@ionic/storage";
import { DataType } from "@aparajita/capacitor-secure-storage";
import {
ConnectionService,
Expand Down
129 changes: 129 additions & 0 deletions src/core/agent/services/delegationService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { truncate } from "fs";
import { IdentifierMetadataRecord } from "../records/identifierMetadataRecord";
import { EventService } from "./eventService";
import { DelegationService } from "./delegationService";

const identifiersGetMock = jest.fn();
let identifiersCreateMock = jest.fn();
const identifiersInteractMock = jest.fn();

const queryKeyStateMock = jest.fn();

const signifyClient = jest.mocked({
identifiers: () => ({
get: identifiersGetMock,
create: identifiersCreateMock,
interact: identifiersInteractMock,
}),
keyStates: () => ({
query: queryKeyStateMock,
}),
});

const identifierStorage = jest.mocked({
getIdentifierMetadata: jest.fn(),
getAllIdentifierMetadata: jest.fn(),
getKeriIdentifiersMetadata: jest.fn(),
updateIdentifierMetadata: jest.fn(),
createIdentifierMetadataRecord: jest.fn(),
});

const agentServicesProps = {
basicStorage: {} as any,
signifyClient: signifyClient as any,
eventService: new EventService(),
identifierStorage: identifierStorage as any,
credentialStorage: {} as any,
};

const delegationService = new DelegationService(agentServicesProps);

describe("Delegation sig service of agent", () => {
beforeEach(() => {
jest.resetAllMocks();
});

test("should call signify.createDelegationIdentifier with the correct parameters and return the result", async () => {
const aid = "newIdentifierAid";
const displayName = "newDisplayName";
const signifyName = "newUuidHere";
identifiersCreateMock = jest.fn().mockResolvedValue({
identifier: aid,
signifyName,
serder: {
ked: {
i: "i",
},
},
});
expect(
await delegationService.createDelegatedIdentifier(
{
displayName,
theme: 0,
},
"delegationPrefix"
)
).toEqual({
identifier: "i",
signifyName: expect.any(String),
});
expect(identifiersCreateMock).toBeCalled();
expect(identifierStorage.createIdentifierMetadataRecord).toBeCalledTimes(1);
});

test("should call the interactDelegation method of the signify module with the given arguments", async () => {
const signifyName = "exampleSignifyName";
const delegatePrefix = "exampleDelegatePrefix";
identifiersInteractMock.mockResolvedValue({
op: jest.fn().mockResolvedValue({
done: truncate,
}),
});
await delegationService.approveDelegation(signifyName, delegatePrefix);
expect(identifiersInteractMock).toHaveBeenCalledWith(signifyName, {
d: delegatePrefix,
i: delegatePrefix,
s: "0",
});
});
test("should call signify.checkDelegationSuccess and update metadata isPending property to false", async () => {
const metadata = {
id: "123456",
displayName: "John Doe",
isPending: true,
signifyOpName: "op123",
signifyName: "john_doe",
theme: 4,
} as IdentifierMetadataRecord;
identifiersGetMock.mockResolvedValue({
state: {
id: metadata.id,
},
});
queryKeyStateMock.mockResolvedValue({
done: true,
});
expect(await delegationService.checkDelegationSuccess(metadata)).toEqual(
true
);
expect(identifierStorage.updateIdentifierMetadata).toHaveBeenCalledWith(
metadata.id,
{ isPending: false }
);
});
test("should call signify.checkDelegationSuccess with isPending is false and return true", async () => {
const metadata = {
id: "123456",
displayName: "John Doe",

isPending: false,
signifyOpName: "op123",
signifyName: "john_doe",
theme: 4,
} as IdentifierMetadataRecord;
expect(await delegationService.checkDelegationSuccess(metadata)).toEqual(
true
);
});
});
72 changes: 72 additions & 0 deletions src/core/agent/services/delegationService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { v4 as uuidv4 } from "uuid";
import { CreateIdentifierResult } from "../agent.types";
import {
IdentifierMetadataRecord,
IdentifierMetadataRecordProps,
} from "../records";
import { AgentService } from "./agentService";
import { waitAndGetDoneOp } from "./utils";

class DelegationService extends AgentService {
async createDelegatedIdentifier(
metadata: Omit<
IdentifierMetadataRecordProps,
"id" | "createdAt" | "isArchived" | "signifyName"
>,
delegatorPrefix: string
): Promise<CreateIdentifierResult> {
const signifyName = uuidv4();
const operation = await this.signifyClient
.identifiers()
.create(signifyName, { delpre: delegatorPrefix });
const identifier = operation.serder.ked.i;
await this.identifierStorage.createIdentifierMetadataRecord({
id: identifier,
...metadata,
signifyName: signifyName,
isPending: true,
});
return { identifier, signifyName };
}

async approveDelegation(
signifyName: string,
delegatePrefix: string
): Promise<void> {
const anchor = {
i: delegatePrefix,
s: "0",
d: delegatePrefix,
};
const ixnResult = await this.signifyClient
.identifiers()
.interact(signifyName, anchor);
const operation = await ixnResult.op();
await waitAndGetDoneOp(this.signifyClient, operation);
return operation.done;
}

async checkDelegationSuccess(
metadata: IdentifierMetadataRecord
): Promise<boolean> {
if (!metadata.isPending) {
return true;
}
const identifier = await this.signifyClient
.identifiers()
.get(metadata.signifyName);
const operation = await this.signifyClient
.keyStates()
.query(identifier.state.di, "1");
await waitAndGetDoneOp(this.signifyClient, operation);
const isDone = operation.done;
if (isDone) {
await this.identifierStorage.updateIdentifierMetadata(metadata.id, {
isPending: false,
});
}
return isDone;
}
}

export { DelegationService };
85 changes: 2 additions & 83 deletions src/core/agent/services/multiSigService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ describe("Multisig sig service of agent", () => {
{ state: {} }
);
});

test("can join the multisig inception", async () => {
const multisigIdentifier = "newMultisigIdentifierAid";
basicStorage.findById = jest.fn().mockResolvedValue({
Expand Down Expand Up @@ -391,6 +392,7 @@ describe("Multisig sig service of agent", () => {
signifyName: expect.any(String),
});
});

test("cannot join multisig by notification if exn messages are missing", async () => {
await expect(
multiSigService.joinMultisig(
Expand All @@ -402,89 +404,6 @@ describe("Multisig sig service of agent", () => {
)
).rejects.toThrowError();
});
test("should call signify.createDelegationIdentifier with the correct parameters and return the result", async () => {
const aid = "newIdentifierAid";
const displayName = "newDisplayName";
const signifyName = "newUuidHere";
identifiersCreateMock = jest.fn().mockResolvedValue({
identifier: aid,
signifyName,
serder: {
ked: {
i: "i",
},
},
});
expect(
await multiSigService.createDelegatedIdentifier(
{
displayName,
theme: 0,
},
"delegationPrefix"
)
).toEqual({
identifier: "i",
signifyName: expect.any(String),
});
expect(identifiersCreateMock).toBeCalled();
expect(identifierStorage.createIdentifierMetadataRecord).toBeCalledTimes(1);
});

test("should call the interactDelegation method of the signify module with the given arguments", async () => {
const signifyName = "exampleSignifyName";
const delegatePrefix = "exampleDelegatePrefix";
identifiersInteractMock.mockResolvedValue({
op: jest.fn().mockResolvedValue({
done: truncate,
}),
});
await multiSigService.approveDelegation(signifyName, delegatePrefix);
expect(identifiersInteractMock).toHaveBeenCalledWith(signifyName, {
d: delegatePrefix,
i: delegatePrefix,
s: "0",
});
});
test("should call signify.checkDelegationSuccess and update metadata isPending property to false", async () => {
const metadata = {
id: "123456",
displayName: "John Doe",
isPending: true,
signifyOpName: "op123",
signifyName: "john_doe",
theme: 4,
} as IdentifierMetadataRecord;
identifiersGetMock.mockResolvedValue({
state: {
id: metadata.id,
},
});
queryKeyStateMock.mockResolvedValue({
done: true,
});
expect(await multiSigService.checkDelegationSuccess(metadata)).toEqual(
true
);
expect(identifierStorage.updateIdentifierMetadata).toHaveBeenCalledWith(
metadata.id,
{ isPending: false }
);
});
test("should call signify.checkDelegationSuccess with isPending is false and return true", async () => {
const metadata = {
id: "123456",
displayName: "John Doe",

isPending: false,
signifyOpName: "op123",
signifyName: "john_doe",
theme: 4,
} as IdentifierMetadataRecord;
expect(await multiSigService.checkDelegationSuccess(metadata)).toEqual(
true
);
});

test("should can rorate multisig with KERI multisig do not have manageAid and throw error", async () => {
const metadata = {
Expand Down
60 changes: 0 additions & 60 deletions src/core/agent/services/multiSigService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,66 +424,6 @@ class MultiSigService extends AgentService {
});
}

async createDelegatedIdentifier(
metadata: Omit<
IdentifierMetadataRecordProps,
"id" | "createdAt" | "isArchived" | "signifyName"
>,
delegatorPrefix: string
): Promise<CreateIdentifierResult> {
const signifyName = uuidv4();
const operation = await this.signifyClient
.identifiers()
.create(signifyName, { delpre: delegatorPrefix });
const identifier = operation.serder.ked.i;
await this.identifierStorage.createIdentifierMetadataRecord({
id: identifier,
...metadata,
signifyName: signifyName,
isPending: true,
});
return { identifier, signifyName };
}

async approveDelegation(
signifyName: string,
delegatePrefix: string
): Promise<void> {
const anchor = {
i: delegatePrefix,
s: "0",
d: delegatePrefix,
};
const ixnResult = await this.signifyClient
.identifiers()
.interact(signifyName, anchor);
const operation = await ixnResult.op();
await waitAndGetDoneOp(this.signifyClient, operation);
return operation.done;
}

async checkDelegationSuccess(
metadata: IdentifierMetadataRecord
): Promise<boolean> {
if (!metadata.isPending) {
return true;
}
const identifier = await this.signifyClient
.identifiers()
.get(metadata.signifyName);
const operation = await this.signifyClient
.keyStates()
.query(identifier.state.di, "1");
await waitAndGetDoneOp(this.signifyClient, operation);
const isDone = operation.done;
if (isDone) {
await this.identifierStorage.updateIdentifierMetadata(metadata.id, {
isPending: false,
});
}
return isDone;
}

async rotateMultisigAid(
aid: Aid,
multisigAidMembers: Pick<Aid, "state">[],
Expand Down

0 comments on commit da7c957

Please sign in to comment.