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

Multisig end role authorization #120

Merged
merged 3 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 5 additions & 7 deletions examples/integration-scripts/externalModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ async function run() {
state1.agent.i
);
let words = new BIP39Shim(0, {}).generateMnemonic(256);
let icpResult = await client1
.identifiers()
.create('aid1', {
algo: signify.Algos.extern,
extern_type: 'bip39_shim',
extern: { mnemonics: words },
});
let icpResult = await client1.identifiers().create('aid1', {
algo: signify.Algos.extern,
extern_type: 'bip39_shim',
extern: { mnemonics: words },
});
let op = await icpResult.op();
assert.equal(op['done'], true);
}
192 changes: 189 additions & 3 deletions examples/integration-scripts/multisig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,6 @@ async function run() {
await new Promise((resolve) => setTimeout(resolve, 1000));
}
console.log('Multisig created!');

const identifiers1 = await client1.identifiers().list();
assert.equal(identifiers1.aids.length, 2);
assert.equal(identifiers1.aids[0].name, 'member1');
Expand Down Expand Up @@ -406,6 +405,191 @@ async function run() {

let multisig = identifiers3.aids[1].prefix;

// Multisig end role
// for brevity, this script authorize only the agent of member 1
// a full implementation should repeat the process to authorize all agents

let members = await client1.identifiers().members('multisig');
let hab = await client1.identifiers().get('multisig');
let aid = hab['prefix'];
let signing = members['signing'];
let eid1 = Object.keys(signing[0].ends.agent)[0]; //agent of member 1
// other agent eids can be obtained with
// let eid2 = Object.keys(signing[1].ends.agent)[0];
// let eid3 = Object.keys(signing[2].ends.agent)[0];
console.log(`Starting multisig end role authorization for agent ${eid1}`);

// initial stamp for the event that will be passed in the exn message
// to the other members
let stamp = new Date().toISOString().replace('Z', '000+00:00');

let endRoleRes = await client1
.identifiers()
.addEndRole('multisig', 'agent', eid1, stamp);
op1 = await endRoleRes.op();
let rpy = endRoleRes.serder;
sigs = endRoleRes.sigs;
let mstate = hab['state'];
let seal = [
'SealEvent',
{ i: hab['prefix'], s: mstate['ee']['s'], d: mstate['ee']['d'] },
];
sigers = sigs.map((sig: any) => new signify.Siger({ qb64: sig }));
let roleims = signify.d(
signify.messagize(rpy, sigers, seal, undefined, undefined, false)
);
atc = roleims.substring(rpy.size);
let roleembeds: any = {
rpy: [rpy, atc],
};
recp = [aid2['state'], aid3['state']].map((state) => state['i']);
res = await client1
.exchanges()
.send(
'member1',
'multisig',
aid1,
'/multisig/rpy',
{ gid: aid },
roleembeds,
recp
);
console.log(
`Member1 authorized agent role to ${eid1}, waiting for others to authorize...`
);

//Member2 check for notifications and join the authorization
msgSaid = '';
while (msgSaid == '') {
let notifications = await client2.notifications().list(1);
for (let notif of notifications.notes) {
if (notif.a.r == '/multisig/rpy') {
msgSaid = notif.a.d;
await client2.notifications().mark(notif.i);
console.log(
'Member2 received exchange message to join the end role authorization'
);
}
}
await new Promise((resolve) => setTimeout(resolve, 1000));
}
res = await client2.groups().getRequest(msgSaid);
exn = res[0].exn;
// stamp, eid and role are provided in the exn message
let rpystamp = exn.e.rpy.dt;
let rpyrole = exn.e.rpy.a.role;
let rpyeid = exn.e.rpy.a.eid;
endRoleRes = await client2
.identifiers()
.addEndRole('multisig', rpyrole, rpyeid, rpystamp);
op2 = await endRoleRes.op();
rpy = endRoleRes.serder;
sigs = endRoleRes.sigs;

hab = await client2.identifiers().get('multisig');
mstate = hab['state'];
seal = [
'SealEvent',
{ i: hab['prefix'], s: mstate['ee']['s'], d: mstate['ee']['d'] },
];
sigers = sigs.map((sig: any) => new signify.Siger({ qb64: sig }));
roleims = signify.d(
signify.messagize(rpy, sigers, seal, undefined, undefined, false)
);
atc = roleims.substring(rpy.size);
roleembeds = {
rpy: [rpy, atc],
};
recp = [aid1['state'], aid3['state']].map((state) => state['i']);
res = await client2
.exchanges()
.send(
'member2',
'multisig',
aid2,
'/multisig/rpy',
{ gid: aid },
roleembeds,
recp
);
console.log(
`Member2 authorized agent role to ${eid1}, waiting for others to authorize...`
);

//Member3 check for notifications and join the authorization
msgSaid = '';
while (msgSaid == '') {
let notifications = await client3.notifications().list(1);
for (let notif of notifications.notes) {
if (notif.a.r == '/multisig/rpy') {
msgSaid = notif.a.d;
await client3.notifications().mark(notif.i);
console.log(
'Member3 received exchange message to join the end role authorization'
);
}
}
await new Promise((resolve) => setTimeout(resolve, 1000));
}
res = await client3.groups().getRequest(msgSaid);
exn = res[0].exn;
rpystamp = exn.e.rpy.dt;
rpyrole = exn.e.rpy.a.role;
rpyeid = exn.e.rpy.a.eid;
endRoleRes = await client3
.identifiers()
.addEndRole('multisig', rpyrole, rpyeid, rpystamp);

op3 = await endRoleRes.op();
rpy = endRoleRes.serder;
sigs = endRoleRes.sigs;
hab = await client3.identifiers().get('multisig');
mstate = hab['state'];
seal = [
'SealEvent',
{ i: hab['prefix'], s: mstate['ee']['s'], d: mstate['ee']['d'] },
];
sigers = sigs.map((sig: any) => new signify.Siger({ qb64: sig }));
roleims = signify.d(
signify.messagize(rpy, sigers, seal, undefined, undefined, false)
);
atc = roleims.substring(rpy.size);
roleembeds = {
rpy: [rpy, atc],
};
recp = [aid1['state'], aid2['state']].map((state) => state['i']);
res = await client3
.exchanges()
.send(
'member3',
'multisig',
aid3,
'/multisig/rpy',
{ gid: aid },
roleembeds,
recp
);
console.log(
`Member3 authorized agent role to ${eid1}, waiting for others to authorize...`
);

// Check for completion
while (!op1['done']) {
op1 = await client1.operations().get(op1.name);
await new Promise((resolve) => setTimeout(resolve, 1000));
}

while (!op2['done']) {
op2 = await client2.operations().get(op2.name);
await new Promise((resolve) => setTimeout(resolve, 1000));
}

while (!op3['done']) {
op3 = await client3.operations().get(op3.name);
await new Promise((resolve) => setTimeout(resolve, 1000));
}
console.log(`End role authorization for agent ${eid1}completed!`);

// MultiSig Interaction

// Member1 initiates an interaction event
Expand Down Expand Up @@ -767,6 +951,8 @@ async function run() {
}
console.log('Multisig rotation completed!');

// Multisig Registry creation

console.log('Starting multisig registry creation');

let vcpRes1 = await client1.registries().create({
Expand Down Expand Up @@ -854,7 +1040,7 @@ async function run() {
regbeds,
recp
);
console.log('Member2 joins rotation event, waiting for others...');
console.log('Member2 joins registry event, waiting for others...');

// Member3 check for notifications and join the create registry event
msgSaid = '';
Expand Down Expand Up @@ -923,5 +1109,5 @@ async function run() {
op3 = await client3.operations().get(op3.name);
await new Promise((resolve) => setTimeout(resolve, 1000));
}
// console.log("Multisig create registry completed!")
console.log('Multisig create registry completed!');
}
2 changes: 2 additions & 0 deletions examples/integration-scripts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 7 additions & 9 deletions examples/integration-scripts/salty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,13 @@ async function run() {
assert.equal(salt.stem, 'signify:aid');
assert.equal(aid.prefix, icp.pre);

icpResult = await client1
.identifiers()
.create('aid2', {
count: 3,
ncount: 3,
isith: '2',
nsith: '2',
bran: '0123456789lmnopqrstuv',
});
icpResult = await client1.identifiers().create('aid2', {
count: 3,
ncount: 3,
isith: '2',
nsith: '2',
bran: '0123456789lmnopqrstuv',
});
op = await icpResult.op();
assert.equal(op['done'], true);
const aid2 = op['response'];
Expand Down
6 changes: 3 additions & 3 deletions src/keri/app/aiding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ export class Identifier {
* @param {string} role Authorized role for eid
* @param {string} [eid] Optional qb64 of endpoint provider to be authorized
* @param {string} [stamp=now] Optional date-time-stamp RFC-3339 profile of iso8601 datetime. Now is the default if not provided
* @returns {Promise<any>} A promise to the result of the authorization
* @returns {Promise<EventResult>} A promise to the result of the authorization
*/
async addEndRole(
name: string,
Expand All @@ -390,12 +390,12 @@ export class Identifier {
sigs: sigs,
};

let res = await this.client.fetch(
let res = this.client.fetch(
'/identifiers/' + name + '/endroles',
'POST',
jsondata
);
return await res.json();
return new EventResult(rpy, sigs, res);
}

/**
Expand Down
5 changes: 4 additions & 1 deletion src/keri/app/exchanging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ export function exchange(
): [Serder, Uint8Array] {
const vs = versify(Ident.KERI, undefined, Serials.JSON, 0);
const ilk = Ilks.exn;
const dt = date !== undefined ? date : nowUTC().toISOString();
const dt =
date !== undefined
? date
: nowUTC().toISOString().replace('Z', '000+00:00');
const p = dig !== undefined ? dig : '';
const q = modifiers !== undefined ? modifiers : {};
const ems = embeds != undefined ? embeds : {};
Expand Down
4 changes: 2 additions & 2 deletions src/keri/core/eventing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,9 +432,9 @@ export function messagize(
new Counter({ code: CtrDex.TransIdxSigGroups, count: 1 })
.qb64b
);
atc = concat(atc, seal.i.encode('utf-8'));
atc = concat(atc, new TextEncoder().encode(seal[1].i));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just made this change too, lol

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I saw it :)

atc = concat(atc, new Seqner(seal[1].s).qb64b);
atc = concat(atc, seal.d.encode('utf-8'));
atc = concat(atc, new TextEncoder().encode(seal[1].d));
} else if (seal[0] == 'SealLast') {
atc = concat(
atc,
Expand Down
13 changes: 13 additions & 0 deletions test/core/eventing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,18 @@ describe('key event function', () => {
'"nt":1,"n":["EIf-ENw7PrM52w4H-S7NGU2qVIfraXVIlV9hEAaMHg7W"],"bt":0,"b":[],"c":[],"a":[]}' +
'-AABAABB3MJGmBXxSEryNHw3YwZZLRl_6Ws4Me2WFq8PrQ6WlluSOpPqbwXuiG9RvNWZkqeW8A_0VRjokGMVRZ3m-c0I'
);
let seal = [
'SealEvent',
{ i: 'EIflL4H4134zYoRM6ls6Q086RLC_BhfNFh5uk-WxvhsL', s: '0', d: 'EIflL4H4134zYoRM6ls6Q086RLC_BhfNFh5uk-WxvhsL' },
];
let msgseal = messagize(serder0, [siger], seal);
assert.equal(
d(msgseal),
'{"v":"KERI10JSON000125_","t":"icp","d":"EIflL4H4134zYoRM6ls6Q086RLC_BhfNFh5uk-WxvhsL","i"'+
':"EIflL4H4134zYoRM6ls6Q086RLC_BhfNFh5uk-WxvhsL","s":"0","kt":1,"k":["DFs8BBx86uytIM0D2BhsE5rrqVIT8ef8mflpNceHo4XH"]'+
',"nt":1,"n":["EIf-ENw7PrM52w4H-S7NGU2qVIfraXVIlV9hEAaMHg7W"],"bt":0,"b":[],"c":[],"a"'+
':[]}-FABEIflL4H4134zYoRM6ls6Q086RLC_BhfNFh5uk-WxvhsL0AAAAAAAAAAAAAAAAAAAAAAAEIflL4H4134zYoRM6ls6Q086RLC_'+
'BhfNFh5uk-WxvhsL-AABAABB3MJGmBXxSEryNHw3YwZZLRl_6Ws4Me2WFq8PrQ6WlluSOpPqbwXuiG9RvNWZkqeW8A_0VRjokGMVRZ3m-c0I'
);
});
});
Loading