@calimero-network/mero-js 22.5.1 → 22.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities.d.ts +42 -0
- package/dist/capabilities.js +64 -0
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +403 -116
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -1
- package/dist/index.mjs +403 -116
- package/dist/index.mjs.map +4 -4
- package/dist/relay/index.d.ts +1 -1
- package/dist/relay/relay-client.d.ts +107 -2
- package/dist/relay/relay-client.js +121 -6
- package/dist/signer/index.d.ts +2 -0
- package/dist/signer/index.js +3 -0
- package/dist/signer/signer.d.ts +92 -0
- package/dist/signer/signer.js +147 -0
- package/dist/warrant/creation-warrant.d.ts +17 -3
- package/dist/warrant/creation-warrant.js +6 -5
- package/dist/warrant/governance-op.d.ts +47 -1
- package/dist/warrant/governance-op.js +62 -2
- package/dist/warrant/governance-warrant.d.ts +17 -3
- package/dist/warrant/governance-warrant.js +6 -5
- package/dist/warrant/index.d.ts +2 -2
- package/dist/warrant/index.js +1 -1
- package/dist/warrant/warrant.d.ts +20 -1
- package/dist/warrant/warrant.js +19 -4
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -745,6 +745,41 @@ var CAPABILITIES = {
|
|
|
745
745
|
*/
|
|
746
746
|
CAN_AUTHOR_ON_BEHALF: 1 << 9
|
|
747
747
|
};
|
|
748
|
+
var CAPABILITY_PRESETS = {
|
|
749
|
+
/** No capabilities. */
|
|
750
|
+
NONE: 0,
|
|
751
|
+
/** Join Open subgroups only: what a namespace starts with. */
|
|
752
|
+
JOIN_ONLY: CAPABILITIES.CAN_JOIN_OPEN_SUBGROUPS,
|
|
753
|
+
/**
|
|
754
|
+
* Create contexts, invite members, join Open subgroups (= 7). A member who
|
|
755
|
+
* can work in the namespace but not reshape it.
|
|
756
|
+
*/
|
|
757
|
+
CONTRIBUTOR: CAPABILITIES.CAN_CREATE_CONTEXT | CAPABILITIES.CAN_INVITE_MEMBERS | CAPABILITIES.CAN_JOIN_OPEN_SUBGROUPS,
|
|
758
|
+
/**
|
|
759
|
+
* `CONTRIBUTOR` plus create and delete subgroups and manage their visibility
|
|
760
|
+
* (= 231). What mero-chat gives members, so they can start and close their
|
|
761
|
+
* own channels.
|
|
762
|
+
*/
|
|
763
|
+
COLLABORATOR: CAPABILITIES.CAN_CREATE_CONTEXT | CAPABILITIES.CAN_INVITE_MEMBERS | CAPABILITIES.CAN_JOIN_OPEN_SUBGROUPS | CAPABILITIES.CAN_CREATE_SUBGROUP | CAPABILITIES.CAN_DELETE_SUBGROUP | CAPABILITIES.CAN_MANAGE_VISIBILITY
|
|
764
|
+
};
|
|
765
|
+
function capMask(...caps) {
|
|
766
|
+
let mask = 0;
|
|
767
|
+
for (const cap of caps) {
|
|
768
|
+
if (typeof cap === "number") {
|
|
769
|
+
mask |= cap;
|
|
770
|
+
} else if (Object.prototype.hasOwnProperty.call(CAPABILITIES, cap)) {
|
|
771
|
+
mask |= CAPABILITIES[cap];
|
|
772
|
+
} else {
|
|
773
|
+
throw new Error(`unknown capability: ${String(cap)}`);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return mask >>> 0;
|
|
777
|
+
}
|
|
778
|
+
function capNames(mask) {
|
|
779
|
+
return Object.keys(CAPABILITIES).filter(
|
|
780
|
+
(name) => hasCap(mask, CAPABILITIES[name])
|
|
781
|
+
);
|
|
782
|
+
}
|
|
748
783
|
function hasCap(mask, cap) {
|
|
749
784
|
const capU32 = cap >>> 0;
|
|
750
785
|
return (mask & capU32) >>> 0 === capU32;
|
|
@@ -6449,6 +6484,117 @@ var LocalStorageTokenStore = class {
|
|
|
6449
6484
|
}
|
|
6450
6485
|
};
|
|
6451
6486
|
|
|
6487
|
+
// src/signer/signer.ts
|
|
6488
|
+
var PKCS8_ED25519_PREFIX2 = new Uint8Array([
|
|
6489
|
+
48,
|
|
6490
|
+
46,
|
|
6491
|
+
2,
|
|
6492
|
+
1,
|
|
6493
|
+
0,
|
|
6494
|
+
48,
|
|
6495
|
+
5,
|
|
6496
|
+
6,
|
|
6497
|
+
3,
|
|
6498
|
+
43,
|
|
6499
|
+
101,
|
|
6500
|
+
112,
|
|
6501
|
+
4,
|
|
6502
|
+
34,
|
|
6503
|
+
4,
|
|
6504
|
+
32
|
|
6505
|
+
]);
|
|
6506
|
+
function unsupported(cause) {
|
|
6507
|
+
const detail = cause instanceof Error ? `: ${cause.message}` : "";
|
|
6508
|
+
return new Error(
|
|
6509
|
+
"this runtime has no WebCrypto Ed25519, so nothing can be signed here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it" + detail
|
|
6510
|
+
);
|
|
6511
|
+
}
|
|
6512
|
+
async function signerFromSecret(secret, label2 = "secret") {
|
|
6513
|
+
const seed = fromHex(secret, label2, 32);
|
|
6514
|
+
const pkcs8 = concat(PKCS8_ED25519_PREFIX2, seed);
|
|
6515
|
+
let privateKey;
|
|
6516
|
+
let publicKey;
|
|
6517
|
+
try {
|
|
6518
|
+
const exportable = await crypto.subtle.importKey(
|
|
6519
|
+
"pkcs8",
|
|
6520
|
+
pkcs8,
|
|
6521
|
+
{ name: "Ed25519" },
|
|
6522
|
+
true,
|
|
6523
|
+
["sign"]
|
|
6524
|
+
);
|
|
6525
|
+
const jwk = await crypto.subtle.exportKey("jwk", exportable);
|
|
6526
|
+
publicKey = hex(
|
|
6527
|
+
Uint8Array.from(
|
|
6528
|
+
atob(jwk.x.replace(/-/g, "+").replace(/_/g, "/")),
|
|
6529
|
+
(c) => c.charCodeAt(0)
|
|
6530
|
+
)
|
|
6531
|
+
);
|
|
6532
|
+
privateKey = await crypto.subtle.importKey(
|
|
6533
|
+
"pkcs8",
|
|
6534
|
+
pkcs8,
|
|
6535
|
+
{ name: "Ed25519" },
|
|
6536
|
+
false,
|
|
6537
|
+
["sign"]
|
|
6538
|
+
);
|
|
6539
|
+
} catch (cause) {
|
|
6540
|
+
throw unsupported(cause);
|
|
6541
|
+
}
|
|
6542
|
+
return fromKeyAndPublic(privateKey, publicKey);
|
|
6543
|
+
}
|
|
6544
|
+
async function signerFromCryptoKey(privateKey, publicKey) {
|
|
6545
|
+
if (privateKey.type !== "private") {
|
|
6546
|
+
throw new Error(
|
|
6547
|
+
`signerFromCryptoKey needs the private half of the pair, got a ${privateKey.type} key`
|
|
6548
|
+
);
|
|
6549
|
+
}
|
|
6550
|
+
if (!privateKey.usages.includes("sign")) {
|
|
6551
|
+
throw new Error(
|
|
6552
|
+
"this CryptoKey cannot sign: generate it with usages ['sign', 'verify']"
|
|
6553
|
+
);
|
|
6554
|
+
}
|
|
6555
|
+
let publicHex;
|
|
6556
|
+
if (typeof publicKey === "string") {
|
|
6557
|
+
fromHex(publicKey, "publicKey", 32);
|
|
6558
|
+
publicHex = publicKey.trim().toLowerCase();
|
|
6559
|
+
} else {
|
|
6560
|
+
try {
|
|
6561
|
+
publicHex = hex(
|
|
6562
|
+
new Uint8Array(await crypto.subtle.exportKey("raw", publicKey))
|
|
6563
|
+
);
|
|
6564
|
+
} catch (cause) {
|
|
6565
|
+
const detail = cause instanceof Error ? `: ${cause.message}` : "";
|
|
6566
|
+
throw new Error(
|
|
6567
|
+
"could not read the public half of this key pair; pass the public key as 64 hex instead" + detail
|
|
6568
|
+
);
|
|
6569
|
+
}
|
|
6570
|
+
}
|
|
6571
|
+
return fromKeyAndPublic(privateKey, publicHex);
|
|
6572
|
+
}
|
|
6573
|
+
function fromKeyAndPublic(privateKey, publicKey) {
|
|
6574
|
+
return {
|
|
6575
|
+
publicKey,
|
|
6576
|
+
async sign(payload) {
|
|
6577
|
+
try {
|
|
6578
|
+
return new Uint8Array(
|
|
6579
|
+
await crypto.subtle.sign({ name: "Ed25519" }, privateKey, payload)
|
|
6580
|
+
);
|
|
6581
|
+
} catch (cause) {
|
|
6582
|
+
throw unsupported(cause);
|
|
6583
|
+
}
|
|
6584
|
+
}
|
|
6585
|
+
};
|
|
6586
|
+
}
|
|
6587
|
+
async function resolveSigner(secret, signer, label2) {
|
|
6588
|
+
if (signer && secret !== void 0) {
|
|
6589
|
+
throw new Error(
|
|
6590
|
+
`pass either ${label2} or signer, not both \u2014 they may name different keys`
|
|
6591
|
+
);
|
|
6592
|
+
}
|
|
6593
|
+
if (signer) return signer;
|
|
6594
|
+
if (secret !== void 0) return signerFromSecret(secret, label2);
|
|
6595
|
+
throw new Error(`${label2} or signer is required`);
|
|
6596
|
+
}
|
|
6597
|
+
|
|
6452
6598
|
// src/warrant/warrant.ts
|
|
6453
6599
|
var SIGN_DOMAIN2 = new TextEncoder().encode("calimero.warrant.v2");
|
|
6454
6600
|
var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
|
|
@@ -6469,8 +6615,8 @@ async function signWarrant(input) {
|
|
|
6469
6615
|
);
|
|
6470
6616
|
const accountHeads = citedHeads(input.accountHeads, "accountHeads");
|
|
6471
6617
|
const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
|
|
6472
|
-
const
|
|
6473
|
-
const publicKey =
|
|
6618
|
+
const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
|
|
6619
|
+
const publicKey = fromHex(signer.publicKey, "signer.publicKey", 32);
|
|
6474
6620
|
const method = new TextEncoder().encode(input.method);
|
|
6475
6621
|
const commitment = await intentHash(input.method, input.argsJson);
|
|
6476
6622
|
const nonce2 = u64le(input.nonce);
|
|
@@ -6490,9 +6636,7 @@ async function signWarrant(input) {
|
|
|
6490
6636
|
nonce2,
|
|
6491
6637
|
notAfter
|
|
6492
6638
|
]);
|
|
6493
|
-
const signature =
|
|
6494
|
-
await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
|
|
6495
|
-
);
|
|
6639
|
+
const signature = checkedSignature(await signer.sign(preimage));
|
|
6496
6640
|
return hex(
|
|
6497
6641
|
concat(
|
|
6498
6642
|
context,
|
|
@@ -6513,6 +6657,13 @@ async function signWarrant(input) {
|
|
|
6513
6657
|
)
|
|
6514
6658
|
);
|
|
6515
6659
|
}
|
|
6660
|
+
function checkedSignature(signature) {
|
|
6661
|
+
if (!(signature instanceof Uint8Array) || signature.length !== 64) {
|
|
6662
|
+
const got = signature instanceof Uint8Array ? `${signature.length} bytes` : typeof signature;
|
|
6663
|
+
throw new Error(`signer returned ${got}, expected a 64-byte Ed25519 signature`);
|
|
6664
|
+
}
|
|
6665
|
+
return signature;
|
|
6666
|
+
}
|
|
6516
6667
|
function citedHeads(heads, label2) {
|
|
6517
6668
|
const list = heads ?? [];
|
|
6518
6669
|
if (list.length > MAX_CITED_HEADS) {
|
|
@@ -6562,8 +6713,8 @@ async function signCreationWarrant(input) {
|
|
|
6562
6713
|
const name = label(input.name, "name");
|
|
6563
6714
|
const accountHeads = citedHeads(input.accountHeads, "accountHeads");
|
|
6564
6715
|
const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
|
|
6565
|
-
const
|
|
6566
|
-
const deviceKey =
|
|
6716
|
+
const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
|
|
6717
|
+
const deviceKey = fromHex(signer.publicKey, "signer.publicKey", 32);
|
|
6567
6718
|
const initHash = await creationInitHash(input.initArgs);
|
|
6568
6719
|
const preimage = await creationWarrantPreimage({
|
|
6569
6720
|
group,
|
|
@@ -6580,9 +6731,7 @@ async function signCreationWarrant(input) {
|
|
|
6580
6731
|
nonce: input.nonce,
|
|
6581
6732
|
notAfter: input.notAfter
|
|
6582
6733
|
});
|
|
6583
|
-
const signature =
|
|
6584
|
-
await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
|
|
6585
|
-
);
|
|
6734
|
+
const signature = checkedSignature(await signer.sign(preimage));
|
|
6586
6735
|
const warrant = hex(
|
|
6587
6736
|
concat(
|
|
6588
6737
|
group,
|
|
@@ -6711,8 +6860,8 @@ async function signGovernanceWarrant(input) {
|
|
|
6711
6860
|
const accountHeads = citedHeads(input.accountHeads, "accountHeads");
|
|
6712
6861
|
const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
|
|
6713
6862
|
const kind = kindByte(input.op.kind);
|
|
6714
|
-
const
|
|
6715
|
-
const deviceKey =
|
|
6863
|
+
const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
|
|
6864
|
+
const deviceKey = fromHex(signer.publicKey, "signer.publicKey", 32);
|
|
6716
6865
|
const opHash = await governanceOpHash(input.op);
|
|
6717
6866
|
const preimage = await governanceWarrantPreimage({
|
|
6718
6867
|
scope,
|
|
@@ -6726,9 +6875,7 @@ async function signGovernanceWarrant(input) {
|
|
|
6726
6875
|
nonce: input.nonce,
|
|
6727
6876
|
notAfter: input.notAfter
|
|
6728
6877
|
});
|
|
6729
|
-
const signature =
|
|
6730
|
-
await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
|
|
6731
|
-
);
|
|
6878
|
+
const signature = checkedSignature(await signer.sign(preimage));
|
|
6732
6879
|
return hex(
|
|
6733
6880
|
concat(
|
|
6734
6881
|
scope,
|
|
@@ -6809,6 +6956,138 @@ function kindByte(kind) {
|
|
|
6809
6956
|
return byte;
|
|
6810
6957
|
}
|
|
6811
6958
|
|
|
6959
|
+
// src/warrant/governance-op.ts
|
|
6960
|
+
var ROLE = {
|
|
6961
|
+
Admin: 0,
|
|
6962
|
+
Member: 1,
|
|
6963
|
+
ReadOnly: 2
|
|
6964
|
+
};
|
|
6965
|
+
var GROUP_OP = {
|
|
6966
|
+
MemberAdded: 1,
|
|
6967
|
+
MemberRemoved: 2,
|
|
6968
|
+
MemberLeft: 3,
|
|
6969
|
+
MemberRoleSet: 4,
|
|
6970
|
+
DefaultCapabilitiesSet: 6
|
|
6971
|
+
};
|
|
6972
|
+
var ROOT_OP = {
|
|
6973
|
+
GroupCreated: 0,
|
|
6974
|
+
GroupReparented: 1,
|
|
6975
|
+
GroupDeleted: 2,
|
|
6976
|
+
NamespaceCreatedV2: 9
|
|
6977
|
+
};
|
|
6978
|
+
var NAMESPACE_ID_DOMAIN = new TextEncoder().encode("calimero.namespace.id.v1");
|
|
6979
|
+
var CLEARED_HASH = new Uint8Array(32);
|
|
6980
|
+
var EMPTY_VEC = u32le(0);
|
|
6981
|
+
function role(value) {
|
|
6982
|
+
const byte = ROLE[value];
|
|
6983
|
+
if (byte === void 0) {
|
|
6984
|
+
throw new Error(`role must be Admin, Member or ReadOnly, got ${String(value)}`);
|
|
6985
|
+
}
|
|
6986
|
+
return new Uint8Array([byte]);
|
|
6987
|
+
}
|
|
6988
|
+
function tag(byte) {
|
|
6989
|
+
return new Uint8Array([byte]);
|
|
6990
|
+
}
|
|
6991
|
+
function memberAddedOp(member, memberRole) {
|
|
6992
|
+
return {
|
|
6993
|
+
kind: "group",
|
|
6994
|
+
bytes: concat(tag(GROUP_OP.MemberAdded), fromHex(member, "member", 32), role(memberRole))
|
|
6995
|
+
};
|
|
6996
|
+
}
|
|
6997
|
+
function memberRemovedOp(member) {
|
|
6998
|
+
return {
|
|
6999
|
+
kind: "group",
|
|
7000
|
+
bytes: concat(
|
|
7001
|
+
tag(GROUP_OP.MemberRemoved),
|
|
7002
|
+
fromHex(member, "member", 32),
|
|
7003
|
+
CLEARED_HASH,
|
|
7004
|
+
EMPTY_VEC
|
|
7005
|
+
)
|
|
7006
|
+
};
|
|
7007
|
+
}
|
|
7008
|
+
function memberLeftOp(member) {
|
|
7009
|
+
return {
|
|
7010
|
+
kind: "group",
|
|
7011
|
+
bytes: concat(
|
|
7012
|
+
tag(GROUP_OP.MemberLeft),
|
|
7013
|
+
fromHex(member, "member", 32),
|
|
7014
|
+
CLEARED_HASH,
|
|
7015
|
+
EMPTY_VEC
|
|
7016
|
+
)
|
|
7017
|
+
};
|
|
7018
|
+
}
|
|
7019
|
+
function memberRoleSetOp(member, memberRole) {
|
|
7020
|
+
return {
|
|
7021
|
+
kind: "group",
|
|
7022
|
+
bytes: concat(tag(GROUP_OP.MemberRoleSet), fromHex(member, "member", 32), role(memberRole))
|
|
7023
|
+
};
|
|
7024
|
+
}
|
|
7025
|
+
function defaultCapabilitiesSetOp(capabilities) {
|
|
7026
|
+
if (!Number.isInteger(capabilities) || capabilities < 0 || capabilities > 4294967295) {
|
|
7027
|
+
throw new Error(`capabilities must be a u32 bit mask, got ${String(capabilities)}`);
|
|
7028
|
+
}
|
|
7029
|
+
if (hasCap(capabilities, CAPABILITIES.CAN_AUTHOR_ON_BEHALF)) {
|
|
7030
|
+
throw new Error(
|
|
7031
|
+
"capabilities may not include CAN_AUTHOR_ON_BEHALF (512): a relay never carries a change to it"
|
|
7032
|
+
);
|
|
7033
|
+
}
|
|
7034
|
+
return {
|
|
7035
|
+
kind: "group",
|
|
7036
|
+
bytes: concat(tag(GROUP_OP.DefaultCapabilitiesSet), u32le(capabilities))
|
|
7037
|
+
};
|
|
7038
|
+
}
|
|
7039
|
+
function groupCreatedOp(input) {
|
|
7040
|
+
return {
|
|
7041
|
+
kind: "root",
|
|
7042
|
+
bytes: concat(
|
|
7043
|
+
tag(ROOT_OP.GroupCreated),
|
|
7044
|
+
fromHex(input.groupId, "groupId", 32),
|
|
7045
|
+
fromHex(input.parentId, "parentId", 32),
|
|
7046
|
+
tag(input.restricted ? 1 : 0),
|
|
7047
|
+
fromHex(input.admin, "admin", 32)
|
|
7048
|
+
)
|
|
7049
|
+
};
|
|
7050
|
+
}
|
|
7051
|
+
function groupReparentedOp(childGroupId, newParentId) {
|
|
7052
|
+
return {
|
|
7053
|
+
kind: "root",
|
|
7054
|
+
bytes: concat(
|
|
7055
|
+
tag(ROOT_OP.GroupReparented),
|
|
7056
|
+
fromHex(childGroupId, "childGroupId", 32),
|
|
7057
|
+
fromHex(newParentId, "newParentId", 32)
|
|
7058
|
+
)
|
|
7059
|
+
};
|
|
7060
|
+
}
|
|
7061
|
+
function groupDeletedOp(rootGroupId) {
|
|
7062
|
+
return {
|
|
7063
|
+
kind: "root",
|
|
7064
|
+
bytes: concat(tag(ROOT_OP.GroupDeleted), fromHex(rootGroupId, "rootGroupId", 32), EMPTY_VEC, EMPTY_VEC)
|
|
7065
|
+
};
|
|
7066
|
+
}
|
|
7067
|
+
async function foundedNamespaceId(founder, salt) {
|
|
7068
|
+
return hex(
|
|
7069
|
+
await domainHash(NAMESPACE_ID_DOMAIN, [
|
|
7070
|
+
fromHex(founder, "founder", 32),
|
|
7071
|
+
fromHex(salt, "salt", 32)
|
|
7072
|
+
])
|
|
7073
|
+
);
|
|
7074
|
+
}
|
|
7075
|
+
function namespaceCreatedOp(input) {
|
|
7076
|
+
const credential = fromHexUnsized(input.credential, "credential");
|
|
7077
|
+
if (credential.length === 0) {
|
|
7078
|
+
throw new Error("credential must be the founder's AccountProof<DeviceCert>, got nothing");
|
|
7079
|
+
}
|
|
7080
|
+
return {
|
|
7081
|
+
kind: "root",
|
|
7082
|
+
bytes: concat(
|
|
7083
|
+
tag(ROOT_OP.NamespaceCreatedV2),
|
|
7084
|
+
fromHex(input.founder, "founder", 32),
|
|
7085
|
+
credential,
|
|
7086
|
+
fromHex(input.salt, "salt", 32)
|
|
7087
|
+
)
|
|
7088
|
+
};
|
|
7089
|
+
}
|
|
7090
|
+
|
|
6812
7091
|
// src/relay/relay-client.ts
|
|
6813
7092
|
var DEFAULT_TTL_SECONDS = 300;
|
|
6814
7093
|
var IntentRefusedError = class extends Error {
|
|
@@ -6829,6 +7108,14 @@ var RelayClient = class {
|
|
|
6829
7108
|
this.fetchImpl = injected ? (input, init) => injected(input, init) : (input, init) => globalThis.fetch(input, init);
|
|
6830
7109
|
this.timeoutMs = config.timeoutMs ?? 1e4;
|
|
6831
7110
|
}
|
|
7111
|
+
/**
|
|
7112
|
+
* The author device's signer, built from `deviceSecret` when that is what was
|
|
7113
|
+
* configured. A {@link Signer} and never the secret, so no caller of a
|
|
7114
|
+
* `RelayClient` gains the ability to read key material.
|
|
7115
|
+
*/
|
|
7116
|
+
async authorSigner() {
|
|
7117
|
+
return resolveSigner(this.config.deviceSecret, this.config.signer, "deviceSecret");
|
|
7118
|
+
}
|
|
6832
7119
|
/**
|
|
6833
7120
|
* Ask the relay what it can do in `contextId`.
|
|
6834
7121
|
*
|
|
@@ -6850,6 +7137,7 @@ var RelayClient = class {
|
|
|
6850
7137
|
*/
|
|
6851
7138
|
async execute(contextId, method, argsJson = {}) {
|
|
6852
7139
|
const executor = this.executorAccount ?? (await this.describe(contextId)).executorAccount;
|
|
7140
|
+
const signer = await this.authorSigner();
|
|
6853
7141
|
const nonce2 = await this.config.nonces.next();
|
|
6854
7142
|
const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
6855
7143
|
const warrant = await signWarrant({
|
|
@@ -6860,7 +7148,7 @@ var RelayClient = class {
|
|
|
6860
7148
|
argsJson,
|
|
6861
7149
|
nonce: nonce2,
|
|
6862
7150
|
notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
|
|
6863
|
-
|
|
7151
|
+
signer
|
|
6864
7152
|
});
|
|
6865
7153
|
const body = await this.json(
|
|
6866
7154
|
"POST",
|
|
@@ -6924,6 +7212,7 @@ var RelayClient = class {
|
|
|
6924
7212
|
}
|
|
6925
7213
|
const executor = this.checkedExecutor(described.executorAccount);
|
|
6926
7214
|
const initArgs = input.initArgs ?? {};
|
|
7215
|
+
const signer = await this.authorSigner();
|
|
6927
7216
|
const nonce2 = await this.config.nonces.next();
|
|
6928
7217
|
const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
6929
7218
|
const { warrant } = await signCreationWarrant({
|
|
@@ -6937,7 +7226,7 @@ var RelayClient = class {
|
|
|
6937
7226
|
initArgs,
|
|
6938
7227
|
nonce: nonce2,
|
|
6939
7228
|
notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
|
|
6940
|
-
|
|
7229
|
+
signer
|
|
6941
7230
|
});
|
|
6942
7231
|
const body = await this.json(
|
|
6943
7232
|
"POST",
|
|
@@ -6987,6 +7276,7 @@ var RelayClient = class {
|
|
|
6987
7276
|
);
|
|
6988
7277
|
}
|
|
6989
7278
|
const executor = this.checkedExecutor(described.executorAccount);
|
|
7279
|
+
const signer = await this.authorSigner();
|
|
6990
7280
|
const nonce2 = await this.config.nonces.next();
|
|
6991
7281
|
const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
6992
7282
|
const warrant = await signGovernanceWarrant({
|
|
@@ -6996,14 +7286,95 @@ var RelayClient = class {
|
|
|
6996
7286
|
executor,
|
|
6997
7287
|
nonce: nonce2,
|
|
6998
7288
|
notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
|
|
6999
|
-
|
|
7289
|
+
signer
|
|
7000
7290
|
});
|
|
7001
|
-
const
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7291
|
+
const data = await this.postGovernance(input.groupId, input.op, warrant);
|
|
7292
|
+
return { groupId: data.groupId };
|
|
7293
|
+
}
|
|
7294
|
+
/**
|
|
7295
|
+
* Found a namespace through the relay, with the author as its founder, owner
|
|
7296
|
+
* and admin. For an account with no node, this is how it gets a namespace at
|
|
7297
|
+
* all.
|
|
7298
|
+
*
|
|
7299
|
+
* The author signs the exact genesis (`NamespaceCreatedV2`, carrying the
|
|
7300
|
+
* author's own credential and the salt) under a root-plane governance
|
|
7301
|
+
* warrant scoped to the new namespace's id, which is derived from the
|
|
7302
|
+
* author's account and the salt, so the relay can neither choose another id
|
|
7303
|
+
* nor found it for anyone else. The relay takes an identity in the new
|
|
7304
|
+
* namespace, mints its key, publishes the genesis, and is seated as the
|
|
7305
|
+
* founding relay (a `Member` holding `CAN_AUTHOR_ON_BEHALF`), so later
|
|
7306
|
+
* `govern`, `createContext` and `execute` calls in the namespace work
|
|
7307
|
+
* through it straight away. A TEE relay then admits itself as the
|
|
7308
|
+
* namespace's first TEE; `teeEnabled` reports whether it did.
|
|
7309
|
+
*
|
|
7310
|
+
* The executor cannot be learned from the relay first: the namespace does not
|
|
7311
|
+
* exist, so `describeGovernance` has nothing to answer about. It comes from
|
|
7312
|
+
* `input.executorAccount`, the configured one, or one an earlier call learned
|
|
7313
|
+
* (`describe`, `createContext`, `govern`), and without any of them this
|
|
7314
|
+
* throws before taking a nonce.
|
|
7315
|
+
* The nonce is spent in the new namespace's ledger.
|
|
7316
|
+
*
|
|
7317
|
+
* With `defaultCapabilities`, the founder then sets the namespace's default
|
|
7318
|
+
* capability mask through the same relay (a second warrant, a second nonce)
|
|
7319
|
+
* and `defaultCapabilitiesSet` reports whether it landed. A failure there
|
|
7320
|
+
* does not throw, since the namespace is already founded.
|
|
7321
|
+
*
|
|
7322
|
+
* Refusals (`400`/`403`) come back as {@link IntentRefusedError}; a salt
|
|
7323
|
+
* that names an existing namespace is a `409`, an `HTTPError`.
|
|
7324
|
+
*/
|
|
7325
|
+
async foundNamespace(input = {}) {
|
|
7326
|
+
const executor = input.executorAccount ? this.checkedExecutor(input.executorAccount) : this.executorAccount;
|
|
7327
|
+
if (!executor) {
|
|
7328
|
+
throw new Error(
|
|
7329
|
+
"foundNamespace needs the relay's account: pass executorAccount or configure it (checked before signing, no nonce was spent)"
|
|
7330
|
+
);
|
|
7331
|
+
}
|
|
7332
|
+
const salt = input.salt ? hex(fromHex(input.salt, "salt", 32)) : hex(crypto.getRandomValues(new Uint8Array(32)));
|
|
7333
|
+
const namespaceId = await foundedNamespaceId(this.config.authorAccount, salt);
|
|
7334
|
+
const op = namespaceCreatedOp({
|
|
7335
|
+
founder: this.config.authorAccount,
|
|
7336
|
+
credential: this.config.authorProof,
|
|
7337
|
+
salt
|
|
7338
|
+
});
|
|
7339
|
+
const capabilitiesOp = input.defaultCapabilities === void 0 ? void 0 : defaultCapabilitiesSetOp(input.defaultCapabilities);
|
|
7340
|
+
const signer = await this.authorSigner();
|
|
7341
|
+
const nonce2 = await this.config.nonces.next();
|
|
7342
|
+
const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
7343
|
+
const warrant = await signGovernanceWarrant({
|
|
7344
|
+
scope: namespaceId,
|
|
7345
|
+
op,
|
|
7346
|
+
authorAccount: this.config.authorAccount,
|
|
7347
|
+
executor,
|
|
7348
|
+
nonce: nonce2,
|
|
7349
|
+
notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
|
|
7350
|
+
signer
|
|
7351
|
+
});
|
|
7352
|
+
const data = await this.postGovernance(namespaceId, op, warrant);
|
|
7353
|
+
const founded = {
|
|
7354
|
+
namespaceId: data.groupId,
|
|
7355
|
+
salt,
|
|
7356
|
+
teeEnabled: data.teeEnabled ?? false,
|
|
7357
|
+
...data.teeError ? { teeError: data.teeError } : {}
|
|
7358
|
+
};
|
|
7359
|
+
if (!capabilitiesOp) return founded;
|
|
7360
|
+
try {
|
|
7361
|
+
await this.govern({ groupId: founded.namespaceId, op: capabilitiesOp });
|
|
7362
|
+
return { ...founded, defaultCapabilitiesSet: true };
|
|
7363
|
+
} catch (err) {
|
|
7364
|
+
return {
|
|
7365
|
+
...founded,
|
|
7366
|
+
defaultCapabilitiesSet: false,
|
|
7367
|
+
defaultCapabilitiesError: err instanceof Error ? err.message : String(err)
|
|
7368
|
+
};
|
|
7369
|
+
}
|
|
7370
|
+
}
|
|
7371
|
+
async postGovernance(groupId, op, warrant) {
|
|
7372
|
+
const body = await this.json("POST", `/admin-api/groups/${encodeURIComponent(groupId)}/governance-intents`, {
|
|
7373
|
+
warrant,
|
|
7374
|
+
authorProof: this.config.authorProof,
|
|
7375
|
+
op: hex(op.bytes)
|
|
7376
|
+
});
|
|
7377
|
+
return body.data;
|
|
7007
7378
|
}
|
|
7008
7379
|
/**
|
|
7009
7380
|
* The executor a warrant must name: the one the relay answered with, which a
|
|
@@ -8397,98 +8768,6 @@ function splitVersion2(version) {
|
|
|
8397
8768
|
return [[Number(match[1]), Number(match[2]), Number(match[3])], match[4]];
|
|
8398
8769
|
}
|
|
8399
8770
|
|
|
8400
|
-
// src/warrant/governance-op.ts
|
|
8401
|
-
var ROLE = {
|
|
8402
|
-
Admin: 0,
|
|
8403
|
-
Member: 1,
|
|
8404
|
-
ReadOnly: 2
|
|
8405
|
-
};
|
|
8406
|
-
var GROUP_OP = {
|
|
8407
|
-
MemberAdded: 1,
|
|
8408
|
-
MemberRemoved: 2,
|
|
8409
|
-
MemberLeft: 3,
|
|
8410
|
-
MemberRoleSet: 4
|
|
8411
|
-
};
|
|
8412
|
-
var ROOT_OP = {
|
|
8413
|
-
GroupCreated: 0,
|
|
8414
|
-
GroupReparented: 1,
|
|
8415
|
-
GroupDeleted: 2
|
|
8416
|
-
};
|
|
8417
|
-
var CLEARED_HASH = new Uint8Array(32);
|
|
8418
|
-
var EMPTY_VEC = u32le(0);
|
|
8419
|
-
function role(value) {
|
|
8420
|
-
const byte = ROLE[value];
|
|
8421
|
-
if (byte === void 0) {
|
|
8422
|
-
throw new Error(`role must be Admin, Member or ReadOnly, got ${String(value)}`);
|
|
8423
|
-
}
|
|
8424
|
-
return new Uint8Array([byte]);
|
|
8425
|
-
}
|
|
8426
|
-
function tag(byte) {
|
|
8427
|
-
return new Uint8Array([byte]);
|
|
8428
|
-
}
|
|
8429
|
-
function memberAddedOp(member, memberRole) {
|
|
8430
|
-
return {
|
|
8431
|
-
kind: "group",
|
|
8432
|
-
bytes: concat(tag(GROUP_OP.MemberAdded), fromHex(member, "member", 32), role(memberRole))
|
|
8433
|
-
};
|
|
8434
|
-
}
|
|
8435
|
-
function memberRemovedOp(member) {
|
|
8436
|
-
return {
|
|
8437
|
-
kind: "group",
|
|
8438
|
-
bytes: concat(
|
|
8439
|
-
tag(GROUP_OP.MemberRemoved),
|
|
8440
|
-
fromHex(member, "member", 32),
|
|
8441
|
-
CLEARED_HASH,
|
|
8442
|
-
EMPTY_VEC
|
|
8443
|
-
)
|
|
8444
|
-
};
|
|
8445
|
-
}
|
|
8446
|
-
function memberLeftOp(member) {
|
|
8447
|
-
return {
|
|
8448
|
-
kind: "group",
|
|
8449
|
-
bytes: concat(
|
|
8450
|
-
tag(GROUP_OP.MemberLeft),
|
|
8451
|
-
fromHex(member, "member", 32),
|
|
8452
|
-
CLEARED_HASH,
|
|
8453
|
-
EMPTY_VEC
|
|
8454
|
-
)
|
|
8455
|
-
};
|
|
8456
|
-
}
|
|
8457
|
-
function memberRoleSetOp(member, memberRole) {
|
|
8458
|
-
return {
|
|
8459
|
-
kind: "group",
|
|
8460
|
-
bytes: concat(tag(GROUP_OP.MemberRoleSet), fromHex(member, "member", 32), role(memberRole))
|
|
8461
|
-
};
|
|
8462
|
-
}
|
|
8463
|
-
function groupCreatedOp(input) {
|
|
8464
|
-
return {
|
|
8465
|
-
kind: "root",
|
|
8466
|
-
bytes: concat(
|
|
8467
|
-
tag(ROOT_OP.GroupCreated),
|
|
8468
|
-
fromHex(input.groupId, "groupId", 32),
|
|
8469
|
-
fromHex(input.parentId, "parentId", 32),
|
|
8470
|
-
tag(input.restricted ? 1 : 0),
|
|
8471
|
-
fromHex(input.admin, "admin", 32)
|
|
8472
|
-
)
|
|
8473
|
-
};
|
|
8474
|
-
}
|
|
8475
|
-
function groupReparentedOp(childGroupId, newParentId) {
|
|
8476
|
-
return {
|
|
8477
|
-
kind: "root",
|
|
8478
|
-
bytes: concat(
|
|
8479
|
-
tag(ROOT_OP.GroupReparented),
|
|
8480
|
-
fromHex(childGroupId, "childGroupId", 32),
|
|
8481
|
-
fromHex(newParentId, "newParentId", 32)
|
|
8482
|
-
)
|
|
8483
|
-
};
|
|
8484
|
-
}
|
|
8485
|
-
function groupDeletedOp(rootGroupId) {
|
|
8486
|
-
return {
|
|
8487
|
-
kind: "root",
|
|
8488
|
-
bytes: concat(tag(ROOT_OP.GroupDeleted), fromHex(rootGroupId, "rootGroupId", 32), EMPTY_VEC, EMPTY_VEC)
|
|
8489
|
-
};
|
|
8490
|
-
}
|
|
8491
|
-
|
|
8492
8771
|
// src/namespace-op/namespace-op.ts
|
|
8493
8772
|
var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 16;
|
|
8494
8773
|
var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
|
|
@@ -8817,6 +9096,7 @@ export {
|
|
|
8817
9096
|
AuthApiClient,
|
|
8818
9097
|
AuthRevokedError,
|
|
8819
9098
|
CAPABILITIES,
|
|
9099
|
+
CAPABILITY_PRESETS,
|
|
8820
9100
|
CloudClient,
|
|
8821
9101
|
DEFAULT_LOCAL_NODE_PORTS,
|
|
8822
9102
|
DEFAULT_RELEASE_MIRROR,
|
|
@@ -8845,6 +9125,8 @@ export {
|
|
|
8845
9125
|
admitterAddrsFromNetworkStatus,
|
|
8846
9126
|
buildAuthLoginUrl,
|
|
8847
9127
|
callerProof,
|
|
9128
|
+
capMask,
|
|
9129
|
+
capNames,
|
|
8848
9130
|
classifyError,
|
|
8849
9131
|
cloudNodeReleaseUrl,
|
|
8850
9132
|
combineSignals,
|
|
@@ -8874,12 +9156,14 @@ export {
|
|
|
8874
9156
|
createTimeoutSignal,
|
|
8875
9157
|
createUniversalHttpClient,
|
|
8876
9158
|
creationInitHash,
|
|
9159
|
+
defaultCapabilitiesSetOp,
|
|
8877
9160
|
deviceCertPayload,
|
|
8878
9161
|
discoverLocalNodes,
|
|
8879
9162
|
encodeSignedInvitation,
|
|
8880
9163
|
fetchAttestedTransportKey,
|
|
8881
9164
|
fetchNodeRelease,
|
|
8882
9165
|
fetchNodeReleaseVersion,
|
|
9166
|
+
foundedNamespaceId,
|
|
8883
9167
|
generateAccountRoot,
|
|
8884
9168
|
generateSessionKey,
|
|
8885
9169
|
governanceOpHash,
|
|
@@ -8898,6 +9182,7 @@ export {
|
|
|
8898
9182
|
memberRemovedOp,
|
|
8899
9183
|
memberRoleSetOp,
|
|
8900
9184
|
mintDeviceId,
|
|
9185
|
+
namespaceCreatedOp,
|
|
8901
9186
|
nodeEndpoint,
|
|
8902
9187
|
nodeReleaseVersionFromImage,
|
|
8903
9188
|
parseAuthCallback,
|
|
@@ -8918,6 +9203,8 @@ export {
|
|
|
8918
9203
|
signRequest,
|
|
8919
9204
|
signRoutingChallenge,
|
|
8920
9205
|
signWarrant,
|
|
9206
|
+
signerFromCryptoKey,
|
|
9207
|
+
signerFromSecret,
|
|
8921
9208
|
transportKeyBinding,
|
|
8922
9209
|
trustSignedRelease,
|
|
8923
9210
|
trustedMeasurementsFromReleases,
|