Skip to content

Commit

Permalink
Merge branch 'feat/create-multi-sig-oobi' of github.com:cardano-found…
Browse files Browse the repository at this point in the history
…ation/cf-identity-wallet into feat/multisig-receive-acdc
  • Loading branch information
Sotatek-HocNguyena committed Jul 15, 2024
2 parents 9fe136a + 71d24dd commit 0c8ea8a
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 105 deletions.
20 changes: 20 additions & 0 deletions src/core/agent/agent.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,24 @@ interface KeriaStatusChangedEvent extends BaseEventEmitter {
};
}

interface NotificationRpy {
a: {
cid: string;
eid: string;
role: string;
};
d: string;
dt: string;
r: string;
t: string;
v: string;
}

interface AuthorizationRequestExn {
a: { gid: string };
e: { rpy: NotificationRpy; d: string };
}

interface KeriaNotification {
id: string;
createdAt: string;
Expand Down Expand Up @@ -193,4 +211,6 @@ export type {
KeriaStatusChangedEvent,
AgentUrls,
BranAndMnemonic,
NotificationRpy,
AuthorizationRequestExn,
};
13 changes: 0 additions & 13 deletions src/core/agent/records/identifierStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,6 @@ class IdentifierStorage {
}
return null;
}

async getMultisigMembersMetadata(
id: string
): Promise<IdentifierMetadataRecord[]> {
const records = await this.storageService.findAllByQuery(
{
id,
groupCreated: true,
},
IdentifierMetadataRecord
);
return records;
}
}

export { IdentifierStorage };
56 changes: 22 additions & 34 deletions src/core/agent/services/multiSigService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,7 @@ describe("Multisig sig service of agent", () => {
theme: 0,
displayName: "Multisig",
})
).rejects.toThrowError(MultiSigService.CANNOT_JOIN_MULTISIG_ICP);
).rejects.toThrowError(MultiSigService.MEMBER_AID_NOT_FOUND);
});

test("Can get multisig icp details of 2 persons multi-sig", async () => {
Expand Down Expand Up @@ -1239,7 +1239,7 @@ describe("Multisig sig service of agent", () => {
multiSigService.getMultisigIcpDetails(
"EHe8OnqWhR--r7zPJy97PS2B5rY7Zp4vnYQICs4gXodW"
)
).rejects.toThrowError(MultiSigService.CANNOT_JOIN_MULTISIG_ICP);
).rejects.toThrowError(MultiSigService.MEMBER_AID_NOT_FOUND);
});

test("cannot get multi-sig details from an unknown sender (missing metadata)", async () => {
Expand Down Expand Up @@ -1563,7 +1563,26 @@ describe("Multisig sig service of agent", () => {
serder: { size: 1 },
sigs: [],
});
await multiSigService.joinAuthorization("notification-said");
await multiSigService.joinAuthorization({
a: {
gid: "EFPEKHhywRg2Naa-Gx0jiAAXYnQ5y92vDniHAk8beEA_",
},
e: {
rpy: {
v: "KERI10JSON000111_",
t: "rpy",
d: "EE8Ze_pwiMHMMDz_giL0ezN7y_4PJSUPKTe3q2Km_WpY",
dt: "2024-07-12T09:37:48.801000+00:00",
r: "/end/role/add",
a: {
cid: "EFPEKHhywRg2Naa-Gx0jiAAXYnQ5y92vDniHAk8beEA_",
role: "agent",
eid: "EDr4kddR_keAzTUs_PNW-qSsUdLDrKD0YbZxiU-y4B3K",
},
},
d: "EFme1_S0eHc-C6HpcaWpFZnKJGX4f91IBCDmiM6vBQOR",
},
});
expect(sendExchangesMock).toBeCalled();
});

Expand Down Expand Up @@ -1609,35 +1628,4 @@ describe("Multisig sig service of agent", () => {
sigs: [],
});
});
test("Should throw error if there is no joining authorization message", async () => {
const notificationSaid = "notification-said";
getExchangesMock.mockResolvedValueOnce(undefined);
await expect(
multiSigService.joinAuthorization(notificationSaid)
).rejects.toThrowError(
new Error(`${MultiSigService.EXN_MESSAGE_NOT_FOUND} ${notificationSaid}`)
);

getExchangesMock.mockResolvedValueOnce({
exn: {
a: {
gid: "gid",
},
},
});
groupGetRequestMock.mockRejectedValue(
new Error("request - 404 - SignifyClient message")
);
identifiersMemberMock.mockResolvedValue(multisigMockMembers);
identifierStorage.getIdentifierMetadata = jest
.fn()
.mockResolvedValue(multisigMockMemberMetadata);
await expect(
multiSigService.joinAuthorization(notificationSaid)
).rejects.toThrowError(
new Error(
`${MultiSigService.GROUP_REQUEST_NOT_FOUND} ${notificationSaid}`
)
);
});
});
58 changes: 14 additions & 44 deletions src/core/agent/services/multiSigService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import {
CreateIdentifierResult,
AgentServicesProps,
} from "../agent.types";
import type { KeriaNotification, ConnectionShortDetails } from "../agent.types";
import type {
KeriaNotification,
ConnectionShortDetails,
AuthorizationRequestExn,
} from "../agent.types";
import {
IdentifierMetadataRecord,
IdentifierMetadataRecordProps,
Expand Down Expand Up @@ -39,8 +43,6 @@ class MultiSigService extends AgentService {
"This AID is not a multi sig identifier";
static readonly NOT_FOUND_ALL_MEMBER_OF_MULTISIG =
"Cannot find all members of multisig or one of the members does not rotate its AID";
static readonly CANNOT_JOIN_MULTISIG_ICP =
"Cannot join multi-sig inception as we do not control any member AID of the multi-sig";
static readonly UNKNOWN_AIDS_IN_MULTISIG_ICP =
"Multi-sig join request contains unknown AIDs (not connected)";
static readonly MISSING_GROUP_METADATA =
Expand All @@ -52,8 +54,6 @@ class MultiSigService extends AgentService {
static readonly GROUP_ALREADY_EXISTs = "Group already exists";
static readonly MEMBER_AID_NOT_FOUND =
"We do not control any member AID of the multi-sig";
static readonly GROUP_REQUEST_NOT_FOUND =
"Group request with given SAID not found";

protected readonly identifierStorage: IdentifierStorage;
protected readonly notificationStorage!: NotificationStorage;
Expand Down Expand Up @@ -391,7 +391,7 @@ class MultiSigService extends AgentService {
smids.includes(identifier.id)
);
if (!ourIdentifier || !ourIdentifier.groupMetadata?.groupId) {
throw new Error(MultiSigService.CANNOT_JOIN_MULTISIG_ICP);
throw new Error(MultiSigService.MEMBER_AID_NOT_FOUND);
}

const otherConnections = (
Expand Down Expand Up @@ -451,7 +451,7 @@ class MultiSigService extends AgentService {
});

if (!identifier) {
throw new Error(MultiSigService.CANNOT_JOIN_MULTISIG_ICP);
throw new Error(MultiSigService.MEMBER_AID_NOT_FOUND);
}

if (!identifier.groupMetadata) {
Expand Down Expand Up @@ -786,14 +786,13 @@ class MultiSigService extends AgentService {
};
}

async endRoleAuthorization(multisigSignifyName: string) {
async endRoleAuthorization(multisigSignifyName: string): Promise<void> {
const { ourIdentifier, multisigMembers } =
await this.getMultisigParticipants(multisigSignifyName);
const hab = await this.props.signifyClient
.identifiers()
.get(multisigSignifyName);
const aid = hab["prefix"];
const results = [];
const recp = multisigMembers
.filter((signing: any) => signing.aid !== ourIdentifier.id)
.map((member: any) => member.aid);
Expand Down Expand Up @@ -832,50 +831,22 @@ class MultiSigService extends AgentService {
recp,
{ gid: aid }
);
results.push(op);
}
return results;
}

async joinAuthorization(notificationSaid: string) {
const exchangeMessage = await this.props.signifyClient
.exchanges()
.get(notificationSaid);
if (!exchangeMessage) {
throw new Error(
`${MultiSigService.EXN_MESSAGE_NOT_FOUND} ${notificationSaid}`
);
}
const multisigAid = exchangeMessage.exn.a.gid;
async joinAuthorization(requestExn: AuthorizationRequestExn): Promise<void> {
const multisigAid = requestExn.a.gid;
const multisigMetadataRecord =
await this.identifierStorage.getIdentifierMetadata(multisigAid);
const multisigSignifyName = multisigMetadataRecord.signifyName;
const request = await this.props.signifyClient
.groups()
.getRequest(notificationSaid)
.catch((error) => {
const errorStack = (error as Error).stack as string;
const status = errorStack.split("-")[1];
if (/404/gi.test(status) && /SignifyClient/gi.test(errorStack)) {
return [];
} else {
throw error;
}
});
if (!request.length) {
throw new Error(
`${MultiSigService.GROUP_REQUEST_NOT_FOUND} ${notificationSaid}`
);
}
const exn = request[0].exn;
// stamp, eid and role are provided in the exn message
const rpystamp = exn.e.rpy.dt;
const rpyrole = exn.e.rpy.a.role;
const rpyeid = exn.e.rpy.a.eid;
const rpystamp = requestExn.e.rpy.dt;
const rpyrole = requestExn.e.rpy.a.role;
const rpyeid = requestExn.e.rpy.a.eid;
const endRoleRes = await this.props.signifyClient
.identifiers()
.addEndRole(multisigSignifyName, rpyrole, rpyeid, rpystamp);
const op = await endRoleRes.op();
await endRoleRes.op();
const rpy = endRoleRes.serder;
const sigs = endRoleRes.sigs;

Expand Down Expand Up @@ -912,7 +883,6 @@ class MultiSigService extends AgentService {
recp,
{ gid: hab["prefix"] }
);
return op;
}

async multisigAdmit(multisigSignifyName: string, notificationSaid: string) {
Expand Down
46 changes: 32 additions & 14 deletions src/core/agent/services/signifyNotificationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,13 @@ class SignifyNotificationService extends AgentService {
await this.markNotification(notif.i);
return;
}
await this.markNotification(notif.i);
return await Agent.agent.multiSigs.joinAuthorization(notif.a.d);
if (multisigNotification[0].exn.e.rpy.r == "/end/role/add") {
await this.markNotification(notif.i);
await Agent.agent.multiSigs.joinAuthorization(
multisigNotification[0].exn
);
return;
}
}
if (notif.a.r === NotificationRoute.MultiSigIcp) {
const multisigNotification = await this.props.signifyClient
Expand Down Expand Up @@ -247,7 +252,10 @@ class SignifyNotificationService extends AgentService {
route: event.a.r,
connectionId: exchange.exn.i,
};
if (event.a.r === NotificationRoute.MultiSigIcp) {
if (
event.a.r === NotificationRoute.MultiSigIcp ||
event.a.r === NotificationRoute.MultiSigRpy
) {
const multisigNotification = await this.props.signifyClient
.groups()
.getRequest(event.a.d)
Expand Down Expand Up @@ -364,23 +372,21 @@ class SignifyNotificationService extends AgentService {
""
);
switch (pendingOperation.recordType) {
case OperationPendingRecordType.Group:
case OperationPendingRecordType.Witness: {
case OperationPendingRecordType.Group: {
await this.identifierStorage.updateIdentifierMetadata(
recordId,
{
isPending: false,
}
);
// Trigger add end role authorization for multi-sigs
if (
pendingOperation.recordType ==
OperationPendingRecordType.Group
) {
const multisigIdentifier =
await this.identifierStorage.getIdentifierMetadata(
recordId
);
const multisigIdentifier =
await this.identifierStorage.getIdentifierMetadata(recordId);
const { ourIdentifier } =
await Agent.agent.multiSigs.getMultisigParticipants(
multisigIdentifier.signifyName
);
if (ourIdentifier.groupMetadata?.groupInitiator) {
await Agent.agent.multiSigs.endRoleAuthorization(
multisigIdentifier.signifyName
);
Expand All @@ -389,7 +395,19 @@ class SignifyNotificationService extends AgentService {
opType: pendingOperation.recordType,
oid: recordId,
});

break;
}
case OperationPendingRecordType.Witness: {
await this.identifierStorage.updateIdentifierMetadata(
recordId,
{
isPending: false,
}
);
callback({
opType: pendingOperation.recordType,
oid: recordId,
});
break;
}

Expand Down

0 comments on commit 0c8ea8a

Please sign in to comment.