@tinycloud/cli 1.5.0-beta.9 → 1.5.1-beta.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/README.md +479 -103
- package/bin/tinycloud +9 -0
- package/dist/courier-entry.js +10179 -503
- package/dist/courier-entry.js.map +1 -1
- package/dist/index.js +1877 -101
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +6279 -2752
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +10 -10
- package/skills/courier/SKILL.md +21 -0
- package/skills/courier/start.md +17 -0
- package/skills/{tc-cli → tinycloud-cli}/AUTH.md +23 -27
- package/skills/tinycloud-cli/INSTALL.md +36 -0
- package/skills/{tc-cli → tinycloud-cli}/REFERENCE.md +117 -97
- package/skills/{tc-cli → tinycloud-cli}/SDK.md +1 -1
- package/skills/{tc-cli → tinycloud-cli}/SKILL.md +34 -48
- package/skills/{tc-cli → tinycloud-cli}/release.json +1 -1
- package/skills/tc-cli/INSTALL.md +0 -35
package/dist/index.js
CHANGED
|
@@ -932,6 +932,12 @@ function abytes(b, ...lengths) {
|
|
|
932
932
|
if (lengths.length > 0 && !lengths.includes(b.length))
|
|
933
933
|
throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
934
934
|
}
|
|
935
|
+
function ahash(h) {
|
|
936
|
+
if (typeof h !== "function" || typeof h.create !== "function")
|
|
937
|
+
throw new Error("Hash should be wrapped by utils.createHasher");
|
|
938
|
+
anumber(h.outputLen);
|
|
939
|
+
anumber(h.blockLen);
|
|
940
|
+
}
|
|
935
941
|
function aexists(instance, checkFinished = true) {
|
|
936
942
|
if (instance.destroyed)
|
|
937
943
|
throw new Error("Hash instance has been destroyed");
|
|
@@ -1100,7 +1106,7 @@ function Chi(a, b, c) {
|
|
|
1100
1106
|
function Maj(a, b, c) {
|
|
1101
1107
|
return a & b ^ a & c ^ b & c;
|
|
1102
1108
|
}
|
|
1103
|
-
var HashMD, SHA256_IV, SHA512_IV;
|
|
1109
|
+
var HashMD, SHA256_IV, SHA384_IV, SHA512_IV;
|
|
1104
1110
|
var init_md = __esm({
|
|
1105
1111
|
"../../node_modules/@noble/hashes/esm/_md.js"() {
|
|
1106
1112
|
"use strict";
|
|
@@ -1205,6 +1211,24 @@ var init_md = __esm({
|
|
|
1205
1211
|
528734635,
|
|
1206
1212
|
1541459225
|
|
1207
1213
|
]);
|
|
1214
|
+
SHA384_IV = /* @__PURE__ */ Uint32Array.from([
|
|
1215
|
+
3418070365,
|
|
1216
|
+
3238371032,
|
|
1217
|
+
1654270250,
|
|
1218
|
+
914150663,
|
|
1219
|
+
2438529370,
|
|
1220
|
+
812702999,
|
|
1221
|
+
355462360,
|
|
1222
|
+
4144912697,
|
|
1223
|
+
1731405415,
|
|
1224
|
+
4290775857,
|
|
1225
|
+
2394180231,
|
|
1226
|
+
1750603025,
|
|
1227
|
+
3675008525,
|
|
1228
|
+
1694076839,
|
|
1229
|
+
1203062813,
|
|
1230
|
+
3204075428
|
|
1231
|
+
]);
|
|
1208
1232
|
SHA512_IV = /* @__PURE__ */ Uint32Array.from([
|
|
1209
1233
|
1779033703,
|
|
1210
1234
|
4089235720,
|
|
@@ -1227,7 +1251,7 @@ var init_md = __esm({
|
|
|
1227
1251
|
});
|
|
1228
1252
|
|
|
1229
1253
|
// ../../node_modules/@noble/hashes/esm/sha2.js
|
|
1230
|
-
var SHA256_K, SHA256_W, SHA256, K512, SHA512_Kh, SHA512_Kl, SHA512_W_H, SHA512_W_L, SHA512, sha256, sha512;
|
|
1254
|
+
var SHA256_K, SHA256_W, SHA256, K512, SHA512_Kh, SHA512_Kl, SHA512_W_H, SHA512_W_L, SHA512, SHA384, sha256, sha512, sha384;
|
|
1231
1255
|
var init_sha2 = __esm({
|
|
1232
1256
|
"../../node_modules/@noble/hashes/esm/sha2.js"() {
|
|
1233
1257
|
"use strict";
|
|
@@ -1568,8 +1592,30 @@ var init_sha2 = __esm({
|
|
|
1568
1592
|
this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
1569
1593
|
}
|
|
1570
1594
|
};
|
|
1595
|
+
SHA384 = class extends SHA512 {
|
|
1596
|
+
constructor() {
|
|
1597
|
+
super(48);
|
|
1598
|
+
this.Ah = SHA384_IV[0] | 0;
|
|
1599
|
+
this.Al = SHA384_IV[1] | 0;
|
|
1600
|
+
this.Bh = SHA384_IV[2] | 0;
|
|
1601
|
+
this.Bl = SHA384_IV[3] | 0;
|
|
1602
|
+
this.Ch = SHA384_IV[4] | 0;
|
|
1603
|
+
this.Cl = SHA384_IV[5] | 0;
|
|
1604
|
+
this.Dh = SHA384_IV[6] | 0;
|
|
1605
|
+
this.Dl = SHA384_IV[7] | 0;
|
|
1606
|
+
this.Eh = SHA384_IV[8] | 0;
|
|
1607
|
+
this.El = SHA384_IV[9] | 0;
|
|
1608
|
+
this.Fh = SHA384_IV[10] | 0;
|
|
1609
|
+
this.Fl = SHA384_IV[11] | 0;
|
|
1610
|
+
this.Gh = SHA384_IV[12] | 0;
|
|
1611
|
+
this.Gl = SHA384_IV[13] | 0;
|
|
1612
|
+
this.Hh = SHA384_IV[14] | 0;
|
|
1613
|
+
this.Hl = SHA384_IV[15] | 0;
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1571
1616
|
sha256 = /* @__PURE__ */ createHasher(() => new SHA256());
|
|
1572
1617
|
sha512 = /* @__PURE__ */ createHasher(() => new SHA512());
|
|
1618
|
+
sha384 = /* @__PURE__ */ createHasher(() => new SHA384());
|
|
1573
1619
|
}
|
|
1574
1620
|
});
|
|
1575
1621
|
|
|
@@ -1583,6 +1629,81 @@ var init_sha256 = __esm({
|
|
|
1583
1629
|
}
|
|
1584
1630
|
});
|
|
1585
1631
|
|
|
1632
|
+
// ../../node_modules/@noble/hashes/esm/hmac.js
|
|
1633
|
+
var HMAC, hmac;
|
|
1634
|
+
var init_hmac = __esm({
|
|
1635
|
+
"../../node_modules/@noble/hashes/esm/hmac.js"() {
|
|
1636
|
+
"use strict";
|
|
1637
|
+
init_utils();
|
|
1638
|
+
HMAC = class extends Hash {
|
|
1639
|
+
constructor(hash, _key) {
|
|
1640
|
+
super();
|
|
1641
|
+
this.finished = false;
|
|
1642
|
+
this.destroyed = false;
|
|
1643
|
+
ahash(hash);
|
|
1644
|
+
const key = toBytes(_key);
|
|
1645
|
+
this.iHash = hash.create();
|
|
1646
|
+
if (typeof this.iHash.update !== "function")
|
|
1647
|
+
throw new Error("Expected instance of class which extends utils.Hash");
|
|
1648
|
+
this.blockLen = this.iHash.blockLen;
|
|
1649
|
+
this.outputLen = this.iHash.outputLen;
|
|
1650
|
+
const blockLen = this.blockLen;
|
|
1651
|
+
const pad = new Uint8Array(blockLen);
|
|
1652
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
1653
|
+
for (let i = 0; i < pad.length; i++)
|
|
1654
|
+
pad[i] ^= 54;
|
|
1655
|
+
this.iHash.update(pad);
|
|
1656
|
+
this.oHash = hash.create();
|
|
1657
|
+
for (let i = 0; i < pad.length; i++)
|
|
1658
|
+
pad[i] ^= 54 ^ 92;
|
|
1659
|
+
this.oHash.update(pad);
|
|
1660
|
+
clean(pad);
|
|
1661
|
+
}
|
|
1662
|
+
update(buf) {
|
|
1663
|
+
aexists(this);
|
|
1664
|
+
this.iHash.update(buf);
|
|
1665
|
+
return this;
|
|
1666
|
+
}
|
|
1667
|
+
digestInto(out) {
|
|
1668
|
+
aexists(this);
|
|
1669
|
+
abytes(out, this.outputLen);
|
|
1670
|
+
this.finished = true;
|
|
1671
|
+
this.iHash.digestInto(out);
|
|
1672
|
+
this.oHash.update(out);
|
|
1673
|
+
this.oHash.digestInto(out);
|
|
1674
|
+
this.destroy();
|
|
1675
|
+
}
|
|
1676
|
+
digest() {
|
|
1677
|
+
const out = new Uint8Array(this.oHash.outputLen);
|
|
1678
|
+
this.digestInto(out);
|
|
1679
|
+
return out;
|
|
1680
|
+
}
|
|
1681
|
+
_cloneInto(to) {
|
|
1682
|
+
to || (to = Object.create(Object.getPrototypeOf(this), {}));
|
|
1683
|
+
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
1684
|
+
to = to;
|
|
1685
|
+
to.finished = finished;
|
|
1686
|
+
to.destroyed = destroyed;
|
|
1687
|
+
to.blockLen = blockLen;
|
|
1688
|
+
to.outputLen = outputLen;
|
|
1689
|
+
to.oHash = oHash._cloneInto(to.oHash);
|
|
1690
|
+
to.iHash = iHash._cloneInto(to.iHash);
|
|
1691
|
+
return to;
|
|
1692
|
+
}
|
|
1693
|
+
clone() {
|
|
1694
|
+
return this._cloneInto();
|
|
1695
|
+
}
|
|
1696
|
+
destroy() {
|
|
1697
|
+
this.destroyed = true;
|
|
1698
|
+
this.oHash.destroy();
|
|
1699
|
+
this.iHash.destroy();
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
|
|
1703
|
+
hmac.create = (hash, key) => new HMAC(hash, key);
|
|
1704
|
+
}
|
|
1705
|
+
});
|
|
1706
|
+
|
|
1586
1707
|
// src/lib/raw-encryption.ts
|
|
1587
1708
|
var init_raw_encryption = __esm({
|
|
1588
1709
|
"src/lib/raw-encryption.ts"() {
|
|
@@ -1782,8 +1903,8 @@ function createReplicationEventSink(profileRoot, options) {
|
|
|
1782
1903
|
`);
|
|
1783
1904
|
} else if (event.type === "replication.sync") {
|
|
1784
1905
|
const pending = event.pendingCleared === void 0 ? "" : ` pendingCleared:${event.pendingCleared}`;
|
|
1785
|
-
const
|
|
1786
|
-
process.stderr.write(`[replication] sync ${event.replica} ${event.outcome}${event.code ? ` ${event.code}` : ""}${pending}${
|
|
1906
|
+
const origin2 = event.origin === void 0 ? "" : ` origin:${event.origin}`;
|
|
1907
|
+
process.stderr.write(`[replication] sync ${event.replica} ${event.outcome}${event.code ? ` ${event.code}` : ""}${pending}${origin2}
|
|
1787
1908
|
`);
|
|
1788
1909
|
} else if (event.type === "replication.grant") {
|
|
1789
1910
|
process.stderr.write(`[replication] grant ${event.replicaId} ${event.action}${event.code ? ` ${event.code}` : ""}${event.effectiveExpiresAt ? ` effectiveExpiresAt:${event.effectiveExpiresAt}` : ""}
|
|
@@ -2188,6 +2309,10 @@ function _abytes2(value, length5, title = "") {
|
|
|
2188
2309
|
}
|
|
2189
2310
|
return value;
|
|
2190
2311
|
}
|
|
2312
|
+
function numberToHexUnpadded(num) {
|
|
2313
|
+
const hex3 = num.toString(16);
|
|
2314
|
+
return hex3.length & 1 ? "0" + hex3 : hex3;
|
|
2315
|
+
}
|
|
2191
2316
|
function hexToNumber(hex3) {
|
|
2192
2317
|
if (typeof hex3 !== "string")
|
|
2193
2318
|
throw new Error("hex string expected, got " + typeof hex3);
|
|
@@ -2248,6 +2373,56 @@ function bitLen(n) {
|
|
|
2248
2373
|
;
|
|
2249
2374
|
return len;
|
|
2250
2375
|
}
|
|
2376
|
+
function createHmacDrbg(hashLen, qByteLen, hmacFn) {
|
|
2377
|
+
if (typeof hashLen !== "number" || hashLen < 2)
|
|
2378
|
+
throw new Error("hashLen must be a number");
|
|
2379
|
+
if (typeof qByteLen !== "number" || qByteLen < 2)
|
|
2380
|
+
throw new Error("qByteLen must be a number");
|
|
2381
|
+
if (typeof hmacFn !== "function")
|
|
2382
|
+
throw new Error("hmacFn must be a function");
|
|
2383
|
+
const u8n = (len) => new Uint8Array(len);
|
|
2384
|
+
const u8of = (byte) => Uint8Array.of(byte);
|
|
2385
|
+
let v = u8n(hashLen);
|
|
2386
|
+
let k = u8n(hashLen);
|
|
2387
|
+
let i = 0;
|
|
2388
|
+
const reset = () => {
|
|
2389
|
+
v.fill(1);
|
|
2390
|
+
k.fill(0);
|
|
2391
|
+
i = 0;
|
|
2392
|
+
};
|
|
2393
|
+
const h = (...b) => hmacFn(k, v, ...b);
|
|
2394
|
+
const reseed = (seed = u8n(0)) => {
|
|
2395
|
+
k = h(u8of(0), seed);
|
|
2396
|
+
v = h();
|
|
2397
|
+
if (seed.length === 0)
|
|
2398
|
+
return;
|
|
2399
|
+
k = h(u8of(1), seed);
|
|
2400
|
+
v = h();
|
|
2401
|
+
};
|
|
2402
|
+
const gen = () => {
|
|
2403
|
+
if (i++ >= 1e3)
|
|
2404
|
+
throw new Error("drbg: tried 1000 values");
|
|
2405
|
+
let len = 0;
|
|
2406
|
+
const out = [];
|
|
2407
|
+
while (len < qByteLen) {
|
|
2408
|
+
v = h();
|
|
2409
|
+
const sl = v.slice();
|
|
2410
|
+
out.push(sl);
|
|
2411
|
+
len += v.length;
|
|
2412
|
+
}
|
|
2413
|
+
return concatBytes(...out);
|
|
2414
|
+
};
|
|
2415
|
+
const genUntil = (seed, pred) => {
|
|
2416
|
+
reset();
|
|
2417
|
+
reseed(seed);
|
|
2418
|
+
let res = void 0;
|
|
2419
|
+
while (!(res = pred(gen())))
|
|
2420
|
+
reseed();
|
|
2421
|
+
reset();
|
|
2422
|
+
return res;
|
|
2423
|
+
};
|
|
2424
|
+
return genUntil;
|
|
2425
|
+
}
|
|
2251
2426
|
function _validateObject(object3, fields, optFields = {}) {
|
|
2252
2427
|
if (!object3 || typeof object3 !== "object")
|
|
2253
2428
|
throw new Error("expected valid options object");
|
|
@@ -2584,6 +2759,26 @@ function Field(ORDER, bitLenOrOpts, isLE2 = false, opts = {}) {
|
|
|
2584
2759
|
});
|
|
2585
2760
|
return Object.freeze(f);
|
|
2586
2761
|
}
|
|
2762
|
+
function getFieldBytesLength(fieldOrder) {
|
|
2763
|
+
if (typeof fieldOrder !== "bigint")
|
|
2764
|
+
throw new Error("field order must be bigint");
|
|
2765
|
+
const bitLength = fieldOrder.toString(2).length;
|
|
2766
|
+
return Math.ceil(bitLength / 8);
|
|
2767
|
+
}
|
|
2768
|
+
function getMinHashLength(fieldOrder) {
|
|
2769
|
+
const length5 = getFieldBytesLength(fieldOrder);
|
|
2770
|
+
return length5 + Math.ceil(length5 / 2);
|
|
2771
|
+
}
|
|
2772
|
+
function mapHashToField(key, fieldOrder, isLE2 = false) {
|
|
2773
|
+
const len = key.length;
|
|
2774
|
+
const fieldLen = getFieldBytesLength(fieldOrder);
|
|
2775
|
+
const minLen = getMinHashLength(fieldOrder);
|
|
2776
|
+
if (len < 16 || len < minLen || len > 1024)
|
|
2777
|
+
throw new Error("expected " + minLen + "-1024 bytes of input, got " + len);
|
|
2778
|
+
const num = isLE2 ? bytesToNumberLE(key) : bytesToNumberBE(key);
|
|
2779
|
+
const reduced = mod(num, fieldOrder - _1n2) + _1n2;
|
|
2780
|
+
return isLE2 ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
|
|
2781
|
+
}
|
|
2587
2782
|
var _0n2, _1n2, _2n, _3n, _4n, _5n, _7n, _8n, _9n, _16n, isNegativeLE, FIELD_FIELDS;
|
|
2588
2783
|
var init_modular = __esm({
|
|
2589
2784
|
"../../node_modules/@noble/curves/esm/abstract/modular.js"() {
|
|
@@ -2683,6 +2878,21 @@ function assert0(n) {
|
|
|
2683
2878
|
if (n !== _0n3)
|
|
2684
2879
|
throw new Error("invalid wNAF");
|
|
2685
2880
|
}
|
|
2881
|
+
function mulEndoUnsafe(Point, point, k1, k2) {
|
|
2882
|
+
let acc = point;
|
|
2883
|
+
let p1 = Point.ZERO;
|
|
2884
|
+
let p2 = Point.ZERO;
|
|
2885
|
+
while (k1 > _0n3 || k2 > _0n3) {
|
|
2886
|
+
if (k1 & _1n3)
|
|
2887
|
+
p1 = p1.add(acc);
|
|
2888
|
+
if (k2 & _1n3)
|
|
2889
|
+
p2 = p2.add(acc);
|
|
2890
|
+
acc = acc.double();
|
|
2891
|
+
k1 >>= _1n3;
|
|
2892
|
+
k2 >>= _1n3;
|
|
2893
|
+
}
|
|
2894
|
+
return { p1, p2 };
|
|
2895
|
+
}
|
|
2686
2896
|
function pippenger(c, fieldN, points, scalars) {
|
|
2687
2897
|
validateMSMPoints(points, c);
|
|
2688
2898
|
validateMSMScalars(scalars, fieldN);
|
|
@@ -6592,7 +6802,7 @@ var init_profile_replicas = __esm({
|
|
|
6592
6802
|
});
|
|
6593
6803
|
|
|
6594
6804
|
// src/lib/logout-pending.ts
|
|
6595
|
-
import { lstat as lstat4, open as open5, readFile as readFile5 } from "fs/promises";
|
|
6805
|
+
import { lstat as lstat4, open as open5, readFile as readFile5, rm as rm4 } from "fs/promises";
|
|
6596
6806
|
import { join as join9 } from "path";
|
|
6597
6807
|
import { createProfileReplicaPurge, logoutPrincipalDigest, REPLICA_LOGOUT_PENDING_FILE as REPLICA_LOGOUT_PENDING_FILE2, RESTORED_GATE_MESSAGE } from "@tinycloud/node-sdk";
|
|
6598
6808
|
import { namedProfilePath, profilePath as profilePath4 } from "@tinycloud/operations/state";
|
|
@@ -6673,32 +6883,35 @@ async function assertPendingRemoteLogoutSession(name, expected) {
|
|
|
6673
6883
|
}, { requireProfile: true });
|
|
6674
6884
|
}
|
|
6675
6885
|
async function clearProfileCredentials(name, syncDirectory = false, legacyCleanup = false) {
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
} catch (cause) {
|
|
6684
|
-
failed = true;
|
|
6685
|
-
error = cause;
|
|
6686
|
-
}
|
|
6687
|
-
try {
|
|
6688
|
-
await ProfileManager.clearSession(name);
|
|
6689
|
-
} catch (cause) {
|
|
6690
|
-
if (!failed) error = cause;
|
|
6691
|
-
failed = true;
|
|
6692
|
-
}
|
|
6693
|
-
if (failed) throw error;
|
|
6694
|
-
if (syncDirectory) {
|
|
6695
|
-
const directory = await open5(profilePath4(name), "r");
|
|
6886
|
+
await ProfileManager.withLock(name, async () => {
|
|
6887
|
+
const profile = await ProfileManager.getProfile(name);
|
|
6888
|
+
const { namedKeys: _namedKeys, ...signedOutProfile } = profile;
|
|
6889
|
+
await rm4(join9(profilePath4(name), "approval-pending.json"), { force: true });
|
|
6890
|
+
await ProfileManager.setProfileDurable(name, { ...signedOutProfile, authSignedOut: true, ...legacyCleanup ? { legacyReplicaCleanup: true } : {} });
|
|
6891
|
+
let failed = false;
|
|
6892
|
+
let error;
|
|
6696
6893
|
try {
|
|
6697
|
-
await
|
|
6698
|
-
}
|
|
6699
|
-
|
|
6894
|
+
await ProfileManager.removeKey(name);
|
|
6895
|
+
} catch (cause) {
|
|
6896
|
+
failed = true;
|
|
6897
|
+
error = cause;
|
|
6700
6898
|
}
|
|
6701
|
-
|
|
6899
|
+
try {
|
|
6900
|
+
await ProfileManager.clearSession(name);
|
|
6901
|
+
} catch (cause) {
|
|
6902
|
+
if (!failed) error = cause;
|
|
6903
|
+
failed = true;
|
|
6904
|
+
}
|
|
6905
|
+
if (failed) throw error;
|
|
6906
|
+
if (syncDirectory) {
|
|
6907
|
+
const directory = await open5(profilePath4(name), "r");
|
|
6908
|
+
try {
|
|
6909
|
+
await directory.sync();
|
|
6910
|
+
} finally {
|
|
6911
|
+
await directory.close();
|
|
6912
|
+
}
|
|
6913
|
+
}
|
|
6914
|
+
}, { requireProfile: true });
|
|
6702
6915
|
}
|
|
6703
6916
|
async function finishSignedOutCredentialRemoval(name) {
|
|
6704
6917
|
const profile = await ProfileManager.getProfile(name).catch((error) => {
|
|
@@ -7363,7 +7576,7 @@ var init_host = __esm({
|
|
|
7363
7576
|
});
|
|
7364
7577
|
|
|
7365
7578
|
// src/config/profiles.ts
|
|
7366
|
-
import { chmod as chmod3, lstat as lstat5, readdir as readdir5, rm as
|
|
7579
|
+
import { chmod as chmod3, lstat as lstat5, readdir as readdir5, rm as rm5 } from "fs/promises";
|
|
7367
7580
|
import { CLI_NAME as CLI_NAME11 } from "@tinycloud/operations/cli-name";
|
|
7368
7581
|
import { join as join10 } from "path";
|
|
7369
7582
|
import {
|
|
@@ -7385,6 +7598,7 @@ var init_profiles = __esm({
|
|
|
7385
7598
|
"use strict";
|
|
7386
7599
|
init_constants();
|
|
7387
7600
|
init_storage2();
|
|
7601
|
+
init_types();
|
|
7388
7602
|
init_errors();
|
|
7389
7603
|
ProfileManager = class _ProfileManager {
|
|
7390
7604
|
// ── Initialization ──────────────────────────────────────────────────
|
|
@@ -7458,7 +7672,7 @@ var init_profiles = __esm({
|
|
|
7458
7672
|
if (!profile) {
|
|
7459
7673
|
throw new CLIError(
|
|
7460
7674
|
"PROFILE_NOT_FOUND",
|
|
7461
|
-
`Profile "${name}" does not exist. Create it with \`${CLI_NAME11} init --name ${name}\`.`
|
|
7675
|
+
`Profile "${name}" does not exist. Create it with \`${CLI_NAME11} init --key-only --name ${name}\`.`
|
|
7462
7676
|
);
|
|
7463
7677
|
}
|
|
7464
7678
|
return profile;
|
|
@@ -7481,7 +7695,7 @@ var init_profiles = __esm({
|
|
|
7481
7695
|
}
|
|
7482
7696
|
/** Removes profile.json under the profile lock (rollback of a profile a failed login created). */
|
|
7483
7697
|
static async removeProfileConfig(name) {
|
|
7484
|
-
await _ProfileManager.withLock(name, () =>
|
|
7698
|
+
await _ProfileManager.withLock(name, () => rm5(join10(profilePath5(name), "profile.json"), { force: true }));
|
|
7485
7699
|
}
|
|
7486
7700
|
/**
|
|
7487
7701
|
* Returns true if a profile directory exists.
|
|
@@ -7532,16 +7746,16 @@ var init_profiles = __esm({
|
|
|
7532
7746
|
});
|
|
7533
7747
|
if (kind === "missing") return;
|
|
7534
7748
|
if (kind === "link") {
|
|
7535
|
-
await
|
|
7749
|
+
await rm5(profileDir, { force: true });
|
|
7536
7750
|
return;
|
|
7537
7751
|
}
|
|
7538
7752
|
await _ProfileManager.withLock(name, async () => {
|
|
7539
7753
|
const directory = profilePath5(name);
|
|
7540
|
-
for (const file of ["session.json", "key.json"]) await
|
|
7754
|
+
for (const file of ["session.json", "key.json"]) await rm5(join10(directory, file), { force: true });
|
|
7541
7755
|
for (const entry of await readdir5(directory)) {
|
|
7542
|
-
if (entry !== ".lock" && entry !== "profile.json") await
|
|
7756
|
+
if (entry !== ".lock" && entry !== "profile.json") await rm5(join10(directory, entry), { recursive: true, force: true });
|
|
7543
7757
|
}
|
|
7544
|
-
await
|
|
7758
|
+
await rm5(join10(directory, "profile.json"), { force: true });
|
|
7545
7759
|
await recordProfileDeletion(name);
|
|
7546
7760
|
});
|
|
7547
7761
|
}
|
|
@@ -7571,7 +7785,7 @@ var init_profiles = __esm({
|
|
|
7571
7785
|
}
|
|
7572
7786
|
/** Removes key.json under the profile lock (rollback of a key a failed login created). */
|
|
7573
7787
|
static async removeKey(name) {
|
|
7574
|
-
await _ProfileManager.withLock(name, () =>
|
|
7788
|
+
await _ProfileManager.withLock(name, () => rm5(join10(profilePath5(name), "key.json"), { force: true }));
|
|
7575
7789
|
}
|
|
7576
7790
|
// ── Session management ──────────────────────────────────────────────
|
|
7577
7791
|
/**
|
|
@@ -7666,6 +7880,7 @@ var init_profiles = __esm({
|
|
|
7666
7880
|
quiet: options.quiet ?? false,
|
|
7667
7881
|
replication,
|
|
7668
7882
|
replicationDebug: options.replicationDebug === true || process.env.TC_REPLICATION_DEBUG === "1",
|
|
7883
|
+
...profileConfig === void 0 ? {} : { posture: resolveProfilePosture(profileConfig) },
|
|
7669
7884
|
...localDiscovery === void 0 ? {} : { localDiscovery }
|
|
7670
7885
|
};
|
|
7671
7886
|
}
|
|
@@ -12787,6 +13002,1097 @@ var init_raw = __esm({
|
|
|
12787
13002
|
}
|
|
12788
13003
|
});
|
|
12789
13004
|
|
|
13005
|
+
// ../../node_modules/@noble/curves/esm/abstract/weierstrass.js
|
|
13006
|
+
function _splitEndoScalar(k, basis, n) {
|
|
13007
|
+
const [[a1, b1], [a2, b2]] = basis;
|
|
13008
|
+
const c1 = divNearest(b2 * k, n);
|
|
13009
|
+
const c2 = divNearest(-b1 * k, n);
|
|
13010
|
+
let k1 = k - c1 * a1 - c2 * a2;
|
|
13011
|
+
let k2 = -c1 * b1 - c2 * b2;
|
|
13012
|
+
const k1neg = k1 < _0n6;
|
|
13013
|
+
const k2neg = k2 < _0n6;
|
|
13014
|
+
if (k1neg)
|
|
13015
|
+
k1 = -k1;
|
|
13016
|
+
if (k2neg)
|
|
13017
|
+
k2 = -k2;
|
|
13018
|
+
const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n6;
|
|
13019
|
+
if (k1 < _0n6 || k1 >= MAX_NUM || k2 < _0n6 || k2 >= MAX_NUM) {
|
|
13020
|
+
throw new Error("splitScalar (endomorphism): failed, k=" + k);
|
|
13021
|
+
}
|
|
13022
|
+
return { k1neg, k1, k2neg, k2 };
|
|
13023
|
+
}
|
|
13024
|
+
function validateSigFormat(format5) {
|
|
13025
|
+
if (!["compact", "recovered", "der"].includes(format5))
|
|
13026
|
+
throw new Error('Signature format must be "compact", "recovered", or "der"');
|
|
13027
|
+
return format5;
|
|
13028
|
+
}
|
|
13029
|
+
function validateSigOpts(opts, def) {
|
|
13030
|
+
const optsn = {};
|
|
13031
|
+
for (let optName of Object.keys(def)) {
|
|
13032
|
+
optsn[optName] = opts[optName] === void 0 ? def[optName] : opts[optName];
|
|
13033
|
+
}
|
|
13034
|
+
_abool2(optsn.lowS, "lowS");
|
|
13035
|
+
_abool2(optsn.prehash, "prehash");
|
|
13036
|
+
if (optsn.format !== void 0)
|
|
13037
|
+
validateSigFormat(optsn.format);
|
|
13038
|
+
return optsn;
|
|
13039
|
+
}
|
|
13040
|
+
function _normFnElement(Fn2, key) {
|
|
13041
|
+
const { BYTES: expected } = Fn2;
|
|
13042
|
+
let num;
|
|
13043
|
+
if (typeof key === "bigint") {
|
|
13044
|
+
num = key;
|
|
13045
|
+
} else {
|
|
13046
|
+
let bytes = ensureBytes("private key", key);
|
|
13047
|
+
try {
|
|
13048
|
+
num = Fn2.fromBytes(bytes);
|
|
13049
|
+
} catch (error) {
|
|
13050
|
+
throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
|
|
13051
|
+
}
|
|
13052
|
+
}
|
|
13053
|
+
if (!Fn2.isValidNot0(num))
|
|
13054
|
+
throw new Error("invalid private key: out of range [1..N-1]");
|
|
13055
|
+
return num;
|
|
13056
|
+
}
|
|
13057
|
+
function weierstrassN(params, extraOpts = {}) {
|
|
13058
|
+
const validated = _createCurveFields("weierstrass", params, extraOpts);
|
|
13059
|
+
const { Fp: Fp2, Fn: Fn2 } = validated;
|
|
13060
|
+
let CURVE = validated.CURVE;
|
|
13061
|
+
const { h: cofactor, n: CURVE_ORDER } = CURVE;
|
|
13062
|
+
_validateObject(extraOpts, {}, {
|
|
13063
|
+
allowInfinityPoint: "boolean",
|
|
13064
|
+
clearCofactor: "function",
|
|
13065
|
+
isTorsionFree: "function",
|
|
13066
|
+
fromBytes: "function",
|
|
13067
|
+
toBytes: "function",
|
|
13068
|
+
endo: "object",
|
|
13069
|
+
wrapPrivateKey: "boolean"
|
|
13070
|
+
});
|
|
13071
|
+
const { endo } = extraOpts;
|
|
13072
|
+
if (endo) {
|
|
13073
|
+
if (!Fp2.is0(CURVE.a) || typeof endo.beta !== "bigint" || !Array.isArray(endo.basises)) {
|
|
13074
|
+
throw new Error('invalid endo: expected "beta": bigint and "basises": array');
|
|
13075
|
+
}
|
|
13076
|
+
}
|
|
13077
|
+
const lengths = getWLengths(Fp2, Fn2);
|
|
13078
|
+
function assertCompressionIsSupported() {
|
|
13079
|
+
if (!Fp2.isOdd)
|
|
13080
|
+
throw new Error("compression is not supported: Field does not have .isOdd()");
|
|
13081
|
+
}
|
|
13082
|
+
function pointToBytes(_c, point, isCompressed) {
|
|
13083
|
+
const { x, y } = point.toAffine();
|
|
13084
|
+
const bx = Fp2.toBytes(x);
|
|
13085
|
+
_abool2(isCompressed, "isCompressed");
|
|
13086
|
+
if (isCompressed) {
|
|
13087
|
+
assertCompressionIsSupported();
|
|
13088
|
+
const hasEvenY = !Fp2.isOdd(y);
|
|
13089
|
+
return concatBytes(pprefix(hasEvenY), bx);
|
|
13090
|
+
} else {
|
|
13091
|
+
return concatBytes(Uint8Array.of(4), bx, Fp2.toBytes(y));
|
|
13092
|
+
}
|
|
13093
|
+
}
|
|
13094
|
+
function pointFromBytes(bytes) {
|
|
13095
|
+
_abytes2(bytes, void 0, "Point");
|
|
13096
|
+
const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths;
|
|
13097
|
+
const length5 = bytes.length;
|
|
13098
|
+
const head = bytes[0];
|
|
13099
|
+
const tail = bytes.subarray(1);
|
|
13100
|
+
if (length5 === comp && (head === 2 || head === 3)) {
|
|
13101
|
+
const x = Fp2.fromBytes(tail);
|
|
13102
|
+
if (!Fp2.isValid(x))
|
|
13103
|
+
throw new Error("bad point: is not on curve, wrong x");
|
|
13104
|
+
const y2 = weierstrassEquation(x);
|
|
13105
|
+
let y;
|
|
13106
|
+
try {
|
|
13107
|
+
y = Fp2.sqrt(y2);
|
|
13108
|
+
} catch (sqrtError) {
|
|
13109
|
+
const err = sqrtError instanceof Error ? ": " + sqrtError.message : "";
|
|
13110
|
+
throw new Error("bad point: is not on curve, sqrt error" + err);
|
|
13111
|
+
}
|
|
13112
|
+
assertCompressionIsSupported();
|
|
13113
|
+
const isYOdd = Fp2.isOdd(y);
|
|
13114
|
+
const isHeadOdd = (head & 1) === 1;
|
|
13115
|
+
if (isHeadOdd !== isYOdd)
|
|
13116
|
+
y = Fp2.neg(y);
|
|
13117
|
+
return { x, y };
|
|
13118
|
+
} else if (length5 === uncomp && head === 4) {
|
|
13119
|
+
const L = Fp2.BYTES;
|
|
13120
|
+
const x = Fp2.fromBytes(tail.subarray(0, L));
|
|
13121
|
+
const y = Fp2.fromBytes(tail.subarray(L, L * 2));
|
|
13122
|
+
if (!isValidXY(x, y))
|
|
13123
|
+
throw new Error("bad point: is not on curve");
|
|
13124
|
+
return { x, y };
|
|
13125
|
+
} else {
|
|
13126
|
+
throw new Error(`bad point: got length ${length5}, expected compressed=${comp} or uncompressed=${uncomp}`);
|
|
13127
|
+
}
|
|
13128
|
+
}
|
|
13129
|
+
const encodePoint = extraOpts.toBytes || pointToBytes;
|
|
13130
|
+
const decodePoint2 = extraOpts.fromBytes || pointFromBytes;
|
|
13131
|
+
function weierstrassEquation(x) {
|
|
13132
|
+
const x2 = Fp2.sqr(x);
|
|
13133
|
+
const x3 = Fp2.mul(x2, x);
|
|
13134
|
+
return Fp2.add(Fp2.add(x3, Fp2.mul(x, CURVE.a)), CURVE.b);
|
|
13135
|
+
}
|
|
13136
|
+
function isValidXY(x, y) {
|
|
13137
|
+
const left = Fp2.sqr(y);
|
|
13138
|
+
const right = weierstrassEquation(x);
|
|
13139
|
+
return Fp2.eql(left, right);
|
|
13140
|
+
}
|
|
13141
|
+
if (!isValidXY(CURVE.Gx, CURVE.Gy))
|
|
13142
|
+
throw new Error("bad curve params: generator point");
|
|
13143
|
+
const _4a3 = Fp2.mul(Fp2.pow(CURVE.a, _3n3), _4n2);
|
|
13144
|
+
const _27b2 = Fp2.mul(Fp2.sqr(CURVE.b), BigInt(27));
|
|
13145
|
+
if (Fp2.is0(Fp2.add(_4a3, _27b2)))
|
|
13146
|
+
throw new Error("bad curve params: a or b");
|
|
13147
|
+
function acoord(title, n, banZero = false) {
|
|
13148
|
+
if (!Fp2.isValid(n) || banZero && Fp2.is0(n))
|
|
13149
|
+
throw new Error(`bad point coordinate ${title}`);
|
|
13150
|
+
return n;
|
|
13151
|
+
}
|
|
13152
|
+
function aprjpoint(other) {
|
|
13153
|
+
if (!(other instanceof Point))
|
|
13154
|
+
throw new Error("ProjectivePoint expected");
|
|
13155
|
+
}
|
|
13156
|
+
function splitEndoScalarN(k) {
|
|
13157
|
+
if (!endo || !endo.basises)
|
|
13158
|
+
throw new Error("no endo");
|
|
13159
|
+
return _splitEndoScalar(k, endo.basises, Fn2.ORDER);
|
|
13160
|
+
}
|
|
13161
|
+
const toAffineMemo = memoized((p, iz) => {
|
|
13162
|
+
const { X, Y, Z } = p;
|
|
13163
|
+
if (Fp2.eql(Z, Fp2.ONE))
|
|
13164
|
+
return { x: X, y: Y };
|
|
13165
|
+
const is0 = p.is0();
|
|
13166
|
+
if (iz == null)
|
|
13167
|
+
iz = is0 ? Fp2.ONE : Fp2.inv(Z);
|
|
13168
|
+
const x = Fp2.mul(X, iz);
|
|
13169
|
+
const y = Fp2.mul(Y, iz);
|
|
13170
|
+
const zz = Fp2.mul(Z, iz);
|
|
13171
|
+
if (is0)
|
|
13172
|
+
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
|
13173
|
+
if (!Fp2.eql(zz, Fp2.ONE))
|
|
13174
|
+
throw new Error("invZ was invalid");
|
|
13175
|
+
return { x, y };
|
|
13176
|
+
});
|
|
13177
|
+
const assertValidMemo = memoized((p) => {
|
|
13178
|
+
if (p.is0()) {
|
|
13179
|
+
if (extraOpts.allowInfinityPoint && !Fp2.is0(p.Y))
|
|
13180
|
+
return;
|
|
13181
|
+
throw new Error("bad point: ZERO");
|
|
13182
|
+
}
|
|
13183
|
+
const { x, y } = p.toAffine();
|
|
13184
|
+
if (!Fp2.isValid(x) || !Fp2.isValid(y))
|
|
13185
|
+
throw new Error("bad point: x or y not field elements");
|
|
13186
|
+
if (!isValidXY(x, y))
|
|
13187
|
+
throw new Error("bad point: equation left != right");
|
|
13188
|
+
if (!p.isTorsionFree())
|
|
13189
|
+
throw new Error("bad point: not in prime-order subgroup");
|
|
13190
|
+
return true;
|
|
13191
|
+
});
|
|
13192
|
+
function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
|
|
13193
|
+
k2p = new Point(Fp2.mul(k2p.X, endoBeta), k2p.Y, k2p.Z);
|
|
13194
|
+
k1p = negateCt(k1neg, k1p);
|
|
13195
|
+
k2p = negateCt(k2neg, k2p);
|
|
13196
|
+
return k1p.add(k2p);
|
|
13197
|
+
}
|
|
13198
|
+
class Point {
|
|
13199
|
+
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
13200
|
+
constructor(X, Y, Z) {
|
|
13201
|
+
this.X = acoord("x", X);
|
|
13202
|
+
this.Y = acoord("y", Y, true);
|
|
13203
|
+
this.Z = acoord("z", Z);
|
|
13204
|
+
Object.freeze(this);
|
|
13205
|
+
}
|
|
13206
|
+
static CURVE() {
|
|
13207
|
+
return CURVE;
|
|
13208
|
+
}
|
|
13209
|
+
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
13210
|
+
static fromAffine(p) {
|
|
13211
|
+
const { x, y } = p || {};
|
|
13212
|
+
if (!p || !Fp2.isValid(x) || !Fp2.isValid(y))
|
|
13213
|
+
throw new Error("invalid affine point");
|
|
13214
|
+
if (p instanceof Point)
|
|
13215
|
+
throw new Error("projective point not allowed");
|
|
13216
|
+
if (Fp2.is0(x) && Fp2.is0(y))
|
|
13217
|
+
return Point.ZERO;
|
|
13218
|
+
return new Point(x, y, Fp2.ONE);
|
|
13219
|
+
}
|
|
13220
|
+
static fromBytes(bytes) {
|
|
13221
|
+
const P = Point.fromAffine(decodePoint2(_abytes2(bytes, void 0, "point")));
|
|
13222
|
+
P.assertValidity();
|
|
13223
|
+
return P;
|
|
13224
|
+
}
|
|
13225
|
+
static fromHex(hex3) {
|
|
13226
|
+
return Point.fromBytes(ensureBytes("pointHex", hex3));
|
|
13227
|
+
}
|
|
13228
|
+
get x() {
|
|
13229
|
+
return this.toAffine().x;
|
|
13230
|
+
}
|
|
13231
|
+
get y() {
|
|
13232
|
+
return this.toAffine().y;
|
|
13233
|
+
}
|
|
13234
|
+
/**
|
|
13235
|
+
*
|
|
13236
|
+
* @param windowSize
|
|
13237
|
+
* @param isLazy true will defer table computation until the first multiplication
|
|
13238
|
+
* @returns
|
|
13239
|
+
*/
|
|
13240
|
+
precompute(windowSize = 8, isLazy = true) {
|
|
13241
|
+
wnaf.createCache(this, windowSize);
|
|
13242
|
+
if (!isLazy)
|
|
13243
|
+
this.multiply(_3n3);
|
|
13244
|
+
return this;
|
|
13245
|
+
}
|
|
13246
|
+
// TODO: return `this`
|
|
13247
|
+
/** A point on curve is valid if it conforms to equation. */
|
|
13248
|
+
assertValidity() {
|
|
13249
|
+
assertValidMemo(this);
|
|
13250
|
+
}
|
|
13251
|
+
hasEvenY() {
|
|
13252
|
+
const { y } = this.toAffine();
|
|
13253
|
+
if (!Fp2.isOdd)
|
|
13254
|
+
throw new Error("Field doesn't support isOdd");
|
|
13255
|
+
return !Fp2.isOdd(y);
|
|
13256
|
+
}
|
|
13257
|
+
/** Compare one point to another. */
|
|
13258
|
+
equals(other) {
|
|
13259
|
+
aprjpoint(other);
|
|
13260
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
13261
|
+
const { X: X2, Y: Y2, Z: Z2 } = other;
|
|
13262
|
+
const U1 = Fp2.eql(Fp2.mul(X1, Z2), Fp2.mul(X2, Z1));
|
|
13263
|
+
const U2 = Fp2.eql(Fp2.mul(Y1, Z2), Fp2.mul(Y2, Z1));
|
|
13264
|
+
return U1 && U2;
|
|
13265
|
+
}
|
|
13266
|
+
/** Flips point to one corresponding to (x, -y) in Affine coordinates. */
|
|
13267
|
+
negate() {
|
|
13268
|
+
return new Point(this.X, Fp2.neg(this.Y), this.Z);
|
|
13269
|
+
}
|
|
13270
|
+
// Renes-Costello-Batina exception-free doubling formula.
|
|
13271
|
+
// There is 30% faster Jacobian formula, but it is not complete.
|
|
13272
|
+
// https://eprint.iacr.org/2015/1060, algorithm 3
|
|
13273
|
+
// Cost: 8M + 3S + 3*a + 2*b3 + 15add.
|
|
13274
|
+
double() {
|
|
13275
|
+
const { a, b } = CURVE;
|
|
13276
|
+
const b3 = Fp2.mul(b, _3n3);
|
|
13277
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
13278
|
+
let X3 = Fp2.ZERO, Y3 = Fp2.ZERO, Z3 = Fp2.ZERO;
|
|
13279
|
+
let t0 = Fp2.mul(X1, X1);
|
|
13280
|
+
let t1 = Fp2.mul(Y1, Y1);
|
|
13281
|
+
let t2 = Fp2.mul(Z1, Z1);
|
|
13282
|
+
let t3 = Fp2.mul(X1, Y1);
|
|
13283
|
+
t3 = Fp2.add(t3, t3);
|
|
13284
|
+
Z3 = Fp2.mul(X1, Z1);
|
|
13285
|
+
Z3 = Fp2.add(Z3, Z3);
|
|
13286
|
+
X3 = Fp2.mul(a, Z3);
|
|
13287
|
+
Y3 = Fp2.mul(b3, t2);
|
|
13288
|
+
Y3 = Fp2.add(X3, Y3);
|
|
13289
|
+
X3 = Fp2.sub(t1, Y3);
|
|
13290
|
+
Y3 = Fp2.add(t1, Y3);
|
|
13291
|
+
Y3 = Fp2.mul(X3, Y3);
|
|
13292
|
+
X3 = Fp2.mul(t3, X3);
|
|
13293
|
+
Z3 = Fp2.mul(b3, Z3);
|
|
13294
|
+
t2 = Fp2.mul(a, t2);
|
|
13295
|
+
t3 = Fp2.sub(t0, t2);
|
|
13296
|
+
t3 = Fp2.mul(a, t3);
|
|
13297
|
+
t3 = Fp2.add(t3, Z3);
|
|
13298
|
+
Z3 = Fp2.add(t0, t0);
|
|
13299
|
+
t0 = Fp2.add(Z3, t0);
|
|
13300
|
+
t0 = Fp2.add(t0, t2);
|
|
13301
|
+
t0 = Fp2.mul(t0, t3);
|
|
13302
|
+
Y3 = Fp2.add(Y3, t0);
|
|
13303
|
+
t2 = Fp2.mul(Y1, Z1);
|
|
13304
|
+
t2 = Fp2.add(t2, t2);
|
|
13305
|
+
t0 = Fp2.mul(t2, t3);
|
|
13306
|
+
X3 = Fp2.sub(X3, t0);
|
|
13307
|
+
Z3 = Fp2.mul(t2, t1);
|
|
13308
|
+
Z3 = Fp2.add(Z3, Z3);
|
|
13309
|
+
Z3 = Fp2.add(Z3, Z3);
|
|
13310
|
+
return new Point(X3, Y3, Z3);
|
|
13311
|
+
}
|
|
13312
|
+
// Renes-Costello-Batina exception-free addition formula.
|
|
13313
|
+
// There is 30% faster Jacobian formula, but it is not complete.
|
|
13314
|
+
// https://eprint.iacr.org/2015/1060, algorithm 1
|
|
13315
|
+
// Cost: 12M + 0S + 3*a + 3*b3 + 23add.
|
|
13316
|
+
add(other) {
|
|
13317
|
+
aprjpoint(other);
|
|
13318
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
13319
|
+
const { X: X2, Y: Y2, Z: Z2 } = other;
|
|
13320
|
+
let X3 = Fp2.ZERO, Y3 = Fp2.ZERO, Z3 = Fp2.ZERO;
|
|
13321
|
+
const a = CURVE.a;
|
|
13322
|
+
const b3 = Fp2.mul(CURVE.b, _3n3);
|
|
13323
|
+
let t0 = Fp2.mul(X1, X2);
|
|
13324
|
+
let t1 = Fp2.mul(Y1, Y2);
|
|
13325
|
+
let t2 = Fp2.mul(Z1, Z2);
|
|
13326
|
+
let t3 = Fp2.add(X1, Y1);
|
|
13327
|
+
let t4 = Fp2.add(X2, Y2);
|
|
13328
|
+
t3 = Fp2.mul(t3, t4);
|
|
13329
|
+
t4 = Fp2.add(t0, t1);
|
|
13330
|
+
t3 = Fp2.sub(t3, t4);
|
|
13331
|
+
t4 = Fp2.add(X1, Z1);
|
|
13332
|
+
let t5 = Fp2.add(X2, Z2);
|
|
13333
|
+
t4 = Fp2.mul(t4, t5);
|
|
13334
|
+
t5 = Fp2.add(t0, t2);
|
|
13335
|
+
t4 = Fp2.sub(t4, t5);
|
|
13336
|
+
t5 = Fp2.add(Y1, Z1);
|
|
13337
|
+
X3 = Fp2.add(Y2, Z2);
|
|
13338
|
+
t5 = Fp2.mul(t5, X3);
|
|
13339
|
+
X3 = Fp2.add(t1, t2);
|
|
13340
|
+
t5 = Fp2.sub(t5, X3);
|
|
13341
|
+
Z3 = Fp2.mul(a, t4);
|
|
13342
|
+
X3 = Fp2.mul(b3, t2);
|
|
13343
|
+
Z3 = Fp2.add(X3, Z3);
|
|
13344
|
+
X3 = Fp2.sub(t1, Z3);
|
|
13345
|
+
Z3 = Fp2.add(t1, Z3);
|
|
13346
|
+
Y3 = Fp2.mul(X3, Z3);
|
|
13347
|
+
t1 = Fp2.add(t0, t0);
|
|
13348
|
+
t1 = Fp2.add(t1, t0);
|
|
13349
|
+
t2 = Fp2.mul(a, t2);
|
|
13350
|
+
t4 = Fp2.mul(b3, t4);
|
|
13351
|
+
t1 = Fp2.add(t1, t2);
|
|
13352
|
+
t2 = Fp2.sub(t0, t2);
|
|
13353
|
+
t2 = Fp2.mul(a, t2);
|
|
13354
|
+
t4 = Fp2.add(t4, t2);
|
|
13355
|
+
t0 = Fp2.mul(t1, t4);
|
|
13356
|
+
Y3 = Fp2.add(Y3, t0);
|
|
13357
|
+
t0 = Fp2.mul(t5, t4);
|
|
13358
|
+
X3 = Fp2.mul(t3, X3);
|
|
13359
|
+
X3 = Fp2.sub(X3, t0);
|
|
13360
|
+
t0 = Fp2.mul(t3, t1);
|
|
13361
|
+
Z3 = Fp2.mul(t5, Z3);
|
|
13362
|
+
Z3 = Fp2.add(Z3, t0);
|
|
13363
|
+
return new Point(X3, Y3, Z3);
|
|
13364
|
+
}
|
|
13365
|
+
subtract(other) {
|
|
13366
|
+
return this.add(other.negate());
|
|
13367
|
+
}
|
|
13368
|
+
is0() {
|
|
13369
|
+
return this.equals(Point.ZERO);
|
|
13370
|
+
}
|
|
13371
|
+
/**
|
|
13372
|
+
* Constant time multiplication.
|
|
13373
|
+
* Uses wNAF method. Windowed method may be 10% faster,
|
|
13374
|
+
* but takes 2x longer to generate and consumes 2x memory.
|
|
13375
|
+
* Uses precomputes when available.
|
|
13376
|
+
* Uses endomorphism for Koblitz curves.
|
|
13377
|
+
* @param scalar by which the point would be multiplied
|
|
13378
|
+
* @returns New point
|
|
13379
|
+
*/
|
|
13380
|
+
multiply(scalar) {
|
|
13381
|
+
const { endo: endo2 } = extraOpts;
|
|
13382
|
+
if (!Fn2.isValidNot0(scalar))
|
|
13383
|
+
throw new Error("invalid scalar: out of range");
|
|
13384
|
+
let point, fake;
|
|
13385
|
+
const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p));
|
|
13386
|
+
if (endo2) {
|
|
13387
|
+
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar);
|
|
13388
|
+
const { p: k1p, f: k1f } = mul(k1);
|
|
13389
|
+
const { p: k2p, f: k2f } = mul(k2);
|
|
13390
|
+
fake = k1f.add(k2f);
|
|
13391
|
+
point = finishEndo(endo2.beta, k1p, k2p, k1neg, k2neg);
|
|
13392
|
+
} else {
|
|
13393
|
+
const { p, f } = mul(scalar);
|
|
13394
|
+
point = p;
|
|
13395
|
+
fake = f;
|
|
13396
|
+
}
|
|
13397
|
+
return normalizeZ(Point, [point, fake])[0];
|
|
13398
|
+
}
|
|
13399
|
+
/**
|
|
13400
|
+
* Non-constant-time multiplication. Uses double-and-add algorithm.
|
|
13401
|
+
* It's faster, but should only be used when you don't care about
|
|
13402
|
+
* an exposed secret key e.g. sig verification, which works over *public* keys.
|
|
13403
|
+
*/
|
|
13404
|
+
multiplyUnsafe(sc) {
|
|
13405
|
+
const { endo: endo2 } = extraOpts;
|
|
13406
|
+
const p = this;
|
|
13407
|
+
if (!Fn2.isValid(sc))
|
|
13408
|
+
throw new Error("invalid scalar: out of range");
|
|
13409
|
+
if (sc === _0n6 || p.is0())
|
|
13410
|
+
return Point.ZERO;
|
|
13411
|
+
if (sc === _1n6)
|
|
13412
|
+
return p;
|
|
13413
|
+
if (wnaf.hasCache(this))
|
|
13414
|
+
return this.multiply(sc);
|
|
13415
|
+
if (endo2) {
|
|
13416
|
+
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc);
|
|
13417
|
+
const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2);
|
|
13418
|
+
return finishEndo(endo2.beta, p1, p2, k1neg, k2neg);
|
|
13419
|
+
} else {
|
|
13420
|
+
return wnaf.unsafe(p, sc);
|
|
13421
|
+
}
|
|
13422
|
+
}
|
|
13423
|
+
multiplyAndAddUnsafe(Q, a, b) {
|
|
13424
|
+
const sum = this.multiplyUnsafe(a).add(Q.multiplyUnsafe(b));
|
|
13425
|
+
return sum.is0() ? void 0 : sum;
|
|
13426
|
+
}
|
|
13427
|
+
/**
|
|
13428
|
+
* Converts Projective point to affine (x, y) coordinates.
|
|
13429
|
+
* @param invertedZ Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch
|
|
13430
|
+
*/
|
|
13431
|
+
toAffine(invertedZ) {
|
|
13432
|
+
return toAffineMemo(this, invertedZ);
|
|
13433
|
+
}
|
|
13434
|
+
/**
|
|
13435
|
+
* Checks whether Point is free of torsion elements (is in prime subgroup).
|
|
13436
|
+
* Always torsion-free for cofactor=1 curves.
|
|
13437
|
+
*/
|
|
13438
|
+
isTorsionFree() {
|
|
13439
|
+
const { isTorsionFree } = extraOpts;
|
|
13440
|
+
if (cofactor === _1n6)
|
|
13441
|
+
return true;
|
|
13442
|
+
if (isTorsionFree)
|
|
13443
|
+
return isTorsionFree(Point, this);
|
|
13444
|
+
return wnaf.unsafe(this, CURVE_ORDER).is0();
|
|
13445
|
+
}
|
|
13446
|
+
clearCofactor() {
|
|
13447
|
+
const { clearCofactor } = extraOpts;
|
|
13448
|
+
if (cofactor === _1n6)
|
|
13449
|
+
return this;
|
|
13450
|
+
if (clearCofactor)
|
|
13451
|
+
return clearCofactor(Point, this);
|
|
13452
|
+
return this.multiplyUnsafe(cofactor);
|
|
13453
|
+
}
|
|
13454
|
+
isSmallOrder() {
|
|
13455
|
+
return this.multiplyUnsafe(cofactor).is0();
|
|
13456
|
+
}
|
|
13457
|
+
toBytes(isCompressed = true) {
|
|
13458
|
+
_abool2(isCompressed, "isCompressed");
|
|
13459
|
+
this.assertValidity();
|
|
13460
|
+
return encodePoint(Point, this, isCompressed);
|
|
13461
|
+
}
|
|
13462
|
+
toHex(isCompressed = true) {
|
|
13463
|
+
return bytesToHex(this.toBytes(isCompressed));
|
|
13464
|
+
}
|
|
13465
|
+
toString() {
|
|
13466
|
+
return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`;
|
|
13467
|
+
}
|
|
13468
|
+
// TODO: remove
|
|
13469
|
+
get px() {
|
|
13470
|
+
return this.X;
|
|
13471
|
+
}
|
|
13472
|
+
get py() {
|
|
13473
|
+
return this.X;
|
|
13474
|
+
}
|
|
13475
|
+
get pz() {
|
|
13476
|
+
return this.Z;
|
|
13477
|
+
}
|
|
13478
|
+
toRawBytes(isCompressed = true) {
|
|
13479
|
+
return this.toBytes(isCompressed);
|
|
13480
|
+
}
|
|
13481
|
+
_setWindowSize(windowSize) {
|
|
13482
|
+
this.precompute(windowSize);
|
|
13483
|
+
}
|
|
13484
|
+
static normalizeZ(points) {
|
|
13485
|
+
return normalizeZ(Point, points);
|
|
13486
|
+
}
|
|
13487
|
+
static msm(points, scalars) {
|
|
13488
|
+
return pippenger(Point, Fn2, points, scalars);
|
|
13489
|
+
}
|
|
13490
|
+
static fromPrivateKey(privateKey) {
|
|
13491
|
+
return Point.BASE.multiply(_normFnElement(Fn2, privateKey));
|
|
13492
|
+
}
|
|
13493
|
+
}
|
|
13494
|
+
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp2.ONE);
|
|
13495
|
+
Point.ZERO = new Point(Fp2.ZERO, Fp2.ONE, Fp2.ZERO);
|
|
13496
|
+
Point.Fp = Fp2;
|
|
13497
|
+
Point.Fn = Fn2;
|
|
13498
|
+
const bits = Fn2.BITS;
|
|
13499
|
+
const wnaf = new wNAF(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits);
|
|
13500
|
+
Point.BASE.precompute(8);
|
|
13501
|
+
return Point;
|
|
13502
|
+
}
|
|
13503
|
+
function pprefix(hasEvenY) {
|
|
13504
|
+
return Uint8Array.of(hasEvenY ? 2 : 3);
|
|
13505
|
+
}
|
|
13506
|
+
function getWLengths(Fp2, Fn2) {
|
|
13507
|
+
return {
|
|
13508
|
+
secretKey: Fn2.BYTES,
|
|
13509
|
+
publicKey: 1 + Fp2.BYTES,
|
|
13510
|
+
publicKeyUncompressed: 1 + 2 * Fp2.BYTES,
|
|
13511
|
+
publicKeyHasPrefix: true,
|
|
13512
|
+
signature: 2 * Fn2.BYTES
|
|
13513
|
+
};
|
|
13514
|
+
}
|
|
13515
|
+
function ecdh(Point, ecdhOpts = {}) {
|
|
13516
|
+
const { Fn: Fn2 } = Point;
|
|
13517
|
+
const randomBytes_ = ecdhOpts.randomBytes || randomBytes;
|
|
13518
|
+
const lengths = Object.assign(getWLengths(Point.Fp, Fn2), { seed: getMinHashLength(Fn2.ORDER) });
|
|
13519
|
+
function isValidSecretKey(secretKey) {
|
|
13520
|
+
try {
|
|
13521
|
+
return !!_normFnElement(Fn2, secretKey);
|
|
13522
|
+
} catch (error) {
|
|
13523
|
+
return false;
|
|
13524
|
+
}
|
|
13525
|
+
}
|
|
13526
|
+
function isValidPublicKey(publicKey, isCompressed) {
|
|
13527
|
+
const { publicKey: comp, publicKeyUncompressed } = lengths;
|
|
13528
|
+
try {
|
|
13529
|
+
const l = publicKey.length;
|
|
13530
|
+
if (isCompressed === true && l !== comp)
|
|
13531
|
+
return false;
|
|
13532
|
+
if (isCompressed === false && l !== publicKeyUncompressed)
|
|
13533
|
+
return false;
|
|
13534
|
+
return !!Point.fromBytes(publicKey);
|
|
13535
|
+
} catch (error) {
|
|
13536
|
+
return false;
|
|
13537
|
+
}
|
|
13538
|
+
}
|
|
13539
|
+
function randomSecretKey(seed = randomBytes_(lengths.seed)) {
|
|
13540
|
+
return mapHashToField(_abytes2(seed, lengths.seed, "seed"), Fn2.ORDER);
|
|
13541
|
+
}
|
|
13542
|
+
function getPublicKey(secretKey, isCompressed = true) {
|
|
13543
|
+
return Point.BASE.multiply(_normFnElement(Fn2, secretKey)).toBytes(isCompressed);
|
|
13544
|
+
}
|
|
13545
|
+
function keygen(seed) {
|
|
13546
|
+
const secretKey = randomSecretKey(seed);
|
|
13547
|
+
return { secretKey, publicKey: getPublicKey(secretKey) };
|
|
13548
|
+
}
|
|
13549
|
+
function isProbPub(item) {
|
|
13550
|
+
if (typeof item === "bigint")
|
|
13551
|
+
return false;
|
|
13552
|
+
if (item instanceof Point)
|
|
13553
|
+
return true;
|
|
13554
|
+
const { secretKey, publicKey, publicKeyUncompressed } = lengths;
|
|
13555
|
+
if (Fn2.allowedLengths || secretKey === publicKey)
|
|
13556
|
+
return void 0;
|
|
13557
|
+
const l = ensureBytes("key", item).length;
|
|
13558
|
+
return l === publicKey || l === publicKeyUncompressed;
|
|
13559
|
+
}
|
|
13560
|
+
function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
|
|
13561
|
+
if (isProbPub(secretKeyA) === true)
|
|
13562
|
+
throw new Error("first arg must be private key");
|
|
13563
|
+
if (isProbPub(publicKeyB) === false)
|
|
13564
|
+
throw new Error("second arg must be public key");
|
|
13565
|
+
const s = _normFnElement(Fn2, secretKeyA);
|
|
13566
|
+
const b = Point.fromHex(publicKeyB);
|
|
13567
|
+
return b.multiply(s).toBytes(isCompressed);
|
|
13568
|
+
}
|
|
13569
|
+
const utils = {
|
|
13570
|
+
isValidSecretKey,
|
|
13571
|
+
isValidPublicKey,
|
|
13572
|
+
randomSecretKey,
|
|
13573
|
+
// TODO: remove
|
|
13574
|
+
isValidPrivateKey: isValidSecretKey,
|
|
13575
|
+
randomPrivateKey: randomSecretKey,
|
|
13576
|
+
normPrivateKeyToScalar: (key) => _normFnElement(Fn2, key),
|
|
13577
|
+
precompute(windowSize = 8, point = Point.BASE) {
|
|
13578
|
+
return point.precompute(windowSize, false);
|
|
13579
|
+
}
|
|
13580
|
+
};
|
|
13581
|
+
return Object.freeze({ getPublicKey, getSharedSecret, keygen, Point, utils, lengths });
|
|
13582
|
+
}
|
|
13583
|
+
function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
13584
|
+
ahash(hash);
|
|
13585
|
+
_validateObject(ecdsaOpts, {}, {
|
|
13586
|
+
hmac: "function",
|
|
13587
|
+
lowS: "boolean",
|
|
13588
|
+
randomBytes: "function",
|
|
13589
|
+
bits2int: "function",
|
|
13590
|
+
bits2int_modN: "function"
|
|
13591
|
+
});
|
|
13592
|
+
const randomBytes4 = ecdsaOpts.randomBytes || randomBytes;
|
|
13593
|
+
const hmac2 = ecdsaOpts.hmac || ((key, ...msgs) => hmac(hash, key, concatBytes(...msgs)));
|
|
13594
|
+
const { Fp: Fp2, Fn: Fn2 } = Point;
|
|
13595
|
+
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn2;
|
|
13596
|
+
const { keygen, getPublicKey, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
|
|
13597
|
+
const defaultSigOpts = {
|
|
13598
|
+
prehash: false,
|
|
13599
|
+
lowS: typeof ecdsaOpts.lowS === "boolean" ? ecdsaOpts.lowS : false,
|
|
13600
|
+
format: void 0,
|
|
13601
|
+
//'compact' as ECDSASigFormat,
|
|
13602
|
+
extraEntropy: false
|
|
13603
|
+
};
|
|
13604
|
+
const defaultSigOpts_format = "compact";
|
|
13605
|
+
function isBiggerThanHalfOrder(number) {
|
|
13606
|
+
const HALF = CURVE_ORDER >> _1n6;
|
|
13607
|
+
return number > HALF;
|
|
13608
|
+
}
|
|
13609
|
+
function validateRS(title, num) {
|
|
13610
|
+
if (!Fn2.isValidNot0(num))
|
|
13611
|
+
throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`);
|
|
13612
|
+
return num;
|
|
13613
|
+
}
|
|
13614
|
+
function validateSigLength(bytes, format5) {
|
|
13615
|
+
validateSigFormat(format5);
|
|
13616
|
+
const size = lengths.signature;
|
|
13617
|
+
const sizer = format5 === "compact" ? size : format5 === "recovered" ? size + 1 : void 0;
|
|
13618
|
+
return _abytes2(bytes, sizer, `${format5} signature`);
|
|
13619
|
+
}
|
|
13620
|
+
class Signature {
|
|
13621
|
+
constructor(r, s, recovery) {
|
|
13622
|
+
this.r = validateRS("r", r);
|
|
13623
|
+
this.s = validateRS("s", s);
|
|
13624
|
+
if (recovery != null)
|
|
13625
|
+
this.recovery = recovery;
|
|
13626
|
+
Object.freeze(this);
|
|
13627
|
+
}
|
|
13628
|
+
static fromBytes(bytes, format5 = defaultSigOpts_format) {
|
|
13629
|
+
validateSigLength(bytes, format5);
|
|
13630
|
+
let recid;
|
|
13631
|
+
if (format5 === "der") {
|
|
13632
|
+
const { r: r2, s: s2 } = DER.toSig(_abytes2(bytes));
|
|
13633
|
+
return new Signature(r2, s2);
|
|
13634
|
+
}
|
|
13635
|
+
if (format5 === "recovered") {
|
|
13636
|
+
recid = bytes[0];
|
|
13637
|
+
format5 = "compact";
|
|
13638
|
+
bytes = bytes.subarray(1);
|
|
13639
|
+
}
|
|
13640
|
+
const L = Fn2.BYTES;
|
|
13641
|
+
const r = bytes.subarray(0, L);
|
|
13642
|
+
const s = bytes.subarray(L, L * 2);
|
|
13643
|
+
return new Signature(Fn2.fromBytes(r), Fn2.fromBytes(s), recid);
|
|
13644
|
+
}
|
|
13645
|
+
static fromHex(hex3, format5) {
|
|
13646
|
+
return this.fromBytes(hexToBytes(hex3), format5);
|
|
13647
|
+
}
|
|
13648
|
+
addRecoveryBit(recovery) {
|
|
13649
|
+
return new Signature(this.r, this.s, recovery);
|
|
13650
|
+
}
|
|
13651
|
+
recoverPublicKey(messageHash) {
|
|
13652
|
+
const FIELD_ORDER = Fp2.ORDER;
|
|
13653
|
+
const { r, s, recovery: rec } = this;
|
|
13654
|
+
if (rec == null || ![0, 1, 2, 3].includes(rec))
|
|
13655
|
+
throw new Error("recovery id invalid");
|
|
13656
|
+
const hasCofactor = CURVE_ORDER * _2n4 < FIELD_ORDER;
|
|
13657
|
+
if (hasCofactor && rec > 1)
|
|
13658
|
+
throw new Error("recovery id is ambiguous for h>1 curve");
|
|
13659
|
+
const radj = rec === 2 || rec === 3 ? r + CURVE_ORDER : r;
|
|
13660
|
+
if (!Fp2.isValid(radj))
|
|
13661
|
+
throw new Error("recovery id 2 or 3 invalid");
|
|
13662
|
+
const x = Fp2.toBytes(radj);
|
|
13663
|
+
const R = Point.fromBytes(concatBytes(pprefix((rec & 1) === 0), x));
|
|
13664
|
+
const ir = Fn2.inv(radj);
|
|
13665
|
+
const h = bits2int_modN(ensureBytes("msgHash", messageHash));
|
|
13666
|
+
const u1 = Fn2.create(-h * ir);
|
|
13667
|
+
const u2 = Fn2.create(s * ir);
|
|
13668
|
+
const Q = Point.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2));
|
|
13669
|
+
if (Q.is0())
|
|
13670
|
+
throw new Error("point at infinify");
|
|
13671
|
+
Q.assertValidity();
|
|
13672
|
+
return Q;
|
|
13673
|
+
}
|
|
13674
|
+
// Signatures should be low-s, to prevent malleability.
|
|
13675
|
+
hasHighS() {
|
|
13676
|
+
return isBiggerThanHalfOrder(this.s);
|
|
13677
|
+
}
|
|
13678
|
+
toBytes(format5 = defaultSigOpts_format) {
|
|
13679
|
+
validateSigFormat(format5);
|
|
13680
|
+
if (format5 === "der")
|
|
13681
|
+
return hexToBytes(DER.hexFromSig(this));
|
|
13682
|
+
const r = Fn2.toBytes(this.r);
|
|
13683
|
+
const s = Fn2.toBytes(this.s);
|
|
13684
|
+
if (format5 === "recovered") {
|
|
13685
|
+
if (this.recovery == null)
|
|
13686
|
+
throw new Error("recovery bit must be present");
|
|
13687
|
+
return concatBytes(Uint8Array.of(this.recovery), r, s);
|
|
13688
|
+
}
|
|
13689
|
+
return concatBytes(r, s);
|
|
13690
|
+
}
|
|
13691
|
+
toHex(format5) {
|
|
13692
|
+
return bytesToHex(this.toBytes(format5));
|
|
13693
|
+
}
|
|
13694
|
+
// TODO: remove
|
|
13695
|
+
assertValidity() {
|
|
13696
|
+
}
|
|
13697
|
+
static fromCompact(hex3) {
|
|
13698
|
+
return Signature.fromBytes(ensureBytes("sig", hex3), "compact");
|
|
13699
|
+
}
|
|
13700
|
+
static fromDER(hex3) {
|
|
13701
|
+
return Signature.fromBytes(ensureBytes("sig", hex3), "der");
|
|
13702
|
+
}
|
|
13703
|
+
normalizeS() {
|
|
13704
|
+
return this.hasHighS() ? new Signature(this.r, Fn2.neg(this.s), this.recovery) : this;
|
|
13705
|
+
}
|
|
13706
|
+
toDERRawBytes() {
|
|
13707
|
+
return this.toBytes("der");
|
|
13708
|
+
}
|
|
13709
|
+
toDERHex() {
|
|
13710
|
+
return bytesToHex(this.toBytes("der"));
|
|
13711
|
+
}
|
|
13712
|
+
toCompactRawBytes() {
|
|
13713
|
+
return this.toBytes("compact");
|
|
13714
|
+
}
|
|
13715
|
+
toCompactHex() {
|
|
13716
|
+
return bytesToHex(this.toBytes("compact"));
|
|
13717
|
+
}
|
|
13718
|
+
}
|
|
13719
|
+
const bits2int = ecdsaOpts.bits2int || function bits2int_def(bytes) {
|
|
13720
|
+
if (bytes.length > 8192)
|
|
13721
|
+
throw new Error("input is too large");
|
|
13722
|
+
const num = bytesToNumberBE(bytes);
|
|
13723
|
+
const delta = bytes.length * 8 - fnBits;
|
|
13724
|
+
return delta > 0 ? num >> BigInt(delta) : num;
|
|
13725
|
+
};
|
|
13726
|
+
const bits2int_modN = ecdsaOpts.bits2int_modN || function bits2int_modN_def(bytes) {
|
|
13727
|
+
return Fn2.create(bits2int(bytes));
|
|
13728
|
+
};
|
|
13729
|
+
const ORDER_MASK = bitMask(fnBits);
|
|
13730
|
+
function int2octets(num) {
|
|
13731
|
+
aInRange("num < 2^" + fnBits, num, _0n6, ORDER_MASK);
|
|
13732
|
+
return Fn2.toBytes(num);
|
|
13733
|
+
}
|
|
13734
|
+
function validateMsgAndHash(message, prehash) {
|
|
13735
|
+
_abytes2(message, void 0, "message");
|
|
13736
|
+
return prehash ? _abytes2(hash(message), void 0, "prehashed message") : message;
|
|
13737
|
+
}
|
|
13738
|
+
function prepSig(message, privateKey, opts) {
|
|
13739
|
+
if (["recovered", "canonical"].some((k) => k in opts))
|
|
13740
|
+
throw new Error("sign() legacy options not supported");
|
|
13741
|
+
const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts);
|
|
13742
|
+
message = validateMsgAndHash(message, prehash);
|
|
13743
|
+
const h1int = bits2int_modN(message);
|
|
13744
|
+
const d = _normFnElement(Fn2, privateKey);
|
|
13745
|
+
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
13746
|
+
if (extraEntropy != null && extraEntropy !== false) {
|
|
13747
|
+
const e = extraEntropy === true ? randomBytes4(lengths.secretKey) : extraEntropy;
|
|
13748
|
+
seedArgs.push(ensureBytes("extraEntropy", e));
|
|
13749
|
+
}
|
|
13750
|
+
const seed = concatBytes(...seedArgs);
|
|
13751
|
+
const m = h1int;
|
|
13752
|
+
function k2sig(kBytes) {
|
|
13753
|
+
const k = bits2int(kBytes);
|
|
13754
|
+
if (!Fn2.isValidNot0(k))
|
|
13755
|
+
return;
|
|
13756
|
+
const ik = Fn2.inv(k);
|
|
13757
|
+
const q = Point.BASE.multiply(k).toAffine();
|
|
13758
|
+
const r = Fn2.create(q.x);
|
|
13759
|
+
if (r === _0n6)
|
|
13760
|
+
return;
|
|
13761
|
+
const s = Fn2.create(ik * Fn2.create(m + r * d));
|
|
13762
|
+
if (s === _0n6)
|
|
13763
|
+
return;
|
|
13764
|
+
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n6);
|
|
13765
|
+
let normS = s;
|
|
13766
|
+
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
13767
|
+
normS = Fn2.neg(s);
|
|
13768
|
+
recovery ^= 1;
|
|
13769
|
+
}
|
|
13770
|
+
return new Signature(r, normS, recovery);
|
|
13771
|
+
}
|
|
13772
|
+
return { seed, k2sig };
|
|
13773
|
+
}
|
|
13774
|
+
function sign(message, secretKey, opts = {}) {
|
|
13775
|
+
message = ensureBytes("message", message);
|
|
13776
|
+
const { seed, k2sig } = prepSig(message, secretKey, opts);
|
|
13777
|
+
const drbg = createHmacDrbg(hash.outputLen, Fn2.BYTES, hmac2);
|
|
13778
|
+
const sig = drbg(seed, k2sig);
|
|
13779
|
+
return sig;
|
|
13780
|
+
}
|
|
13781
|
+
function tryParsingSig(sg) {
|
|
13782
|
+
let sig = void 0;
|
|
13783
|
+
const isHex = typeof sg === "string" || isBytes(sg);
|
|
13784
|
+
const isObj = !isHex && sg !== null && typeof sg === "object" && typeof sg.r === "bigint" && typeof sg.s === "bigint";
|
|
13785
|
+
if (!isHex && !isObj)
|
|
13786
|
+
throw new Error("invalid signature, expected Uint8Array, hex string or Signature instance");
|
|
13787
|
+
if (isObj) {
|
|
13788
|
+
sig = new Signature(sg.r, sg.s);
|
|
13789
|
+
} else if (isHex) {
|
|
13790
|
+
try {
|
|
13791
|
+
sig = Signature.fromBytes(ensureBytes("sig", sg), "der");
|
|
13792
|
+
} catch (derError) {
|
|
13793
|
+
if (!(derError instanceof DER.Err))
|
|
13794
|
+
throw derError;
|
|
13795
|
+
}
|
|
13796
|
+
if (!sig) {
|
|
13797
|
+
try {
|
|
13798
|
+
sig = Signature.fromBytes(ensureBytes("sig", sg), "compact");
|
|
13799
|
+
} catch (error) {
|
|
13800
|
+
return false;
|
|
13801
|
+
}
|
|
13802
|
+
}
|
|
13803
|
+
}
|
|
13804
|
+
if (!sig)
|
|
13805
|
+
return false;
|
|
13806
|
+
return sig;
|
|
13807
|
+
}
|
|
13808
|
+
function verify(signature, message, publicKey, opts = {}) {
|
|
13809
|
+
const { lowS, prehash, format: format5 } = validateSigOpts(opts, defaultSigOpts);
|
|
13810
|
+
publicKey = ensureBytes("publicKey", publicKey);
|
|
13811
|
+
message = validateMsgAndHash(ensureBytes("message", message), prehash);
|
|
13812
|
+
if ("strict" in opts)
|
|
13813
|
+
throw new Error("options.strict was renamed to lowS");
|
|
13814
|
+
const sig = format5 === void 0 ? tryParsingSig(signature) : Signature.fromBytes(ensureBytes("sig", signature), format5);
|
|
13815
|
+
if (sig === false)
|
|
13816
|
+
return false;
|
|
13817
|
+
try {
|
|
13818
|
+
const P = Point.fromBytes(publicKey);
|
|
13819
|
+
if (lowS && sig.hasHighS())
|
|
13820
|
+
return false;
|
|
13821
|
+
const { r, s } = sig;
|
|
13822
|
+
const h = bits2int_modN(message);
|
|
13823
|
+
const is = Fn2.inv(s);
|
|
13824
|
+
const u1 = Fn2.create(h * is);
|
|
13825
|
+
const u2 = Fn2.create(r * is);
|
|
13826
|
+
const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
|
|
13827
|
+
if (R.is0())
|
|
13828
|
+
return false;
|
|
13829
|
+
const v = Fn2.create(R.x);
|
|
13830
|
+
return v === r;
|
|
13831
|
+
} catch (e) {
|
|
13832
|
+
return false;
|
|
13833
|
+
}
|
|
13834
|
+
}
|
|
13835
|
+
function recoverPublicKey(signature, message, opts = {}) {
|
|
13836
|
+
const { prehash } = validateSigOpts(opts, defaultSigOpts);
|
|
13837
|
+
message = validateMsgAndHash(message, prehash);
|
|
13838
|
+
return Signature.fromBytes(signature, "recovered").recoverPublicKey(message).toBytes();
|
|
13839
|
+
}
|
|
13840
|
+
return Object.freeze({
|
|
13841
|
+
keygen,
|
|
13842
|
+
getPublicKey,
|
|
13843
|
+
getSharedSecret,
|
|
13844
|
+
utils,
|
|
13845
|
+
lengths,
|
|
13846
|
+
Point,
|
|
13847
|
+
sign,
|
|
13848
|
+
verify,
|
|
13849
|
+
recoverPublicKey,
|
|
13850
|
+
Signature,
|
|
13851
|
+
hash
|
|
13852
|
+
});
|
|
13853
|
+
}
|
|
13854
|
+
function _weierstrass_legacy_opts_to_new(c) {
|
|
13855
|
+
const CURVE = {
|
|
13856
|
+
a: c.a,
|
|
13857
|
+
b: c.b,
|
|
13858
|
+
p: c.Fp.ORDER,
|
|
13859
|
+
n: c.n,
|
|
13860
|
+
h: c.h,
|
|
13861
|
+
Gx: c.Gx,
|
|
13862
|
+
Gy: c.Gy
|
|
13863
|
+
};
|
|
13864
|
+
const Fp2 = c.Fp;
|
|
13865
|
+
let allowedLengths = c.allowedPrivateKeyLengths ? Array.from(new Set(c.allowedPrivateKeyLengths.map((l) => Math.ceil(l / 2)))) : void 0;
|
|
13866
|
+
const Fn2 = Field(CURVE.n, {
|
|
13867
|
+
BITS: c.nBitLength,
|
|
13868
|
+
allowedLengths,
|
|
13869
|
+
modFromBytes: c.wrapPrivateKey
|
|
13870
|
+
});
|
|
13871
|
+
const curveOpts = {
|
|
13872
|
+
Fp: Fp2,
|
|
13873
|
+
Fn: Fn2,
|
|
13874
|
+
allowInfinityPoint: c.allowInfinityPoint,
|
|
13875
|
+
endo: c.endo,
|
|
13876
|
+
isTorsionFree: c.isTorsionFree,
|
|
13877
|
+
clearCofactor: c.clearCofactor,
|
|
13878
|
+
fromBytes: c.fromBytes,
|
|
13879
|
+
toBytes: c.toBytes
|
|
13880
|
+
};
|
|
13881
|
+
return { CURVE, curveOpts };
|
|
13882
|
+
}
|
|
13883
|
+
function _ecdsa_legacy_opts_to_new(c) {
|
|
13884
|
+
const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
|
|
13885
|
+
const ecdsaOpts = {
|
|
13886
|
+
hmac: c.hmac,
|
|
13887
|
+
randomBytes: c.randomBytes,
|
|
13888
|
+
lowS: c.lowS,
|
|
13889
|
+
bits2int: c.bits2int,
|
|
13890
|
+
bits2int_modN: c.bits2int_modN
|
|
13891
|
+
};
|
|
13892
|
+
return { CURVE, curveOpts, hash: c.hash, ecdsaOpts };
|
|
13893
|
+
}
|
|
13894
|
+
function _ecdsa_new_output_to_legacy(c, _ecdsa) {
|
|
13895
|
+
const Point = _ecdsa.Point;
|
|
13896
|
+
return Object.assign({}, _ecdsa, {
|
|
13897
|
+
ProjectivePoint: Point,
|
|
13898
|
+
CURVE: Object.assign({}, c, nLength(Point.Fn.ORDER, Point.Fn.BITS))
|
|
13899
|
+
});
|
|
13900
|
+
}
|
|
13901
|
+
function weierstrass(c) {
|
|
13902
|
+
const { CURVE, curveOpts, hash, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
|
|
13903
|
+
const Point = weierstrassN(CURVE, curveOpts);
|
|
13904
|
+
const signs = ecdsa(Point, hash, ecdsaOpts);
|
|
13905
|
+
return _ecdsa_new_output_to_legacy(c, signs);
|
|
13906
|
+
}
|
|
13907
|
+
var divNearest, DERErr, DER, _0n6, _1n6, _2n4, _3n3, _4n2;
|
|
13908
|
+
var init_weierstrass = __esm({
|
|
13909
|
+
"../../node_modules/@noble/curves/esm/abstract/weierstrass.js"() {
|
|
13910
|
+
"use strict";
|
|
13911
|
+
init_hmac();
|
|
13912
|
+
init_utils();
|
|
13913
|
+
init_utils2();
|
|
13914
|
+
init_curve();
|
|
13915
|
+
init_modular();
|
|
13916
|
+
divNearest = (num, den) => (num + (num >= 0 ? den : -den) / _2n4) / den;
|
|
13917
|
+
DERErr = class extends Error {
|
|
13918
|
+
constructor(m = "") {
|
|
13919
|
+
super(m);
|
|
13920
|
+
}
|
|
13921
|
+
};
|
|
13922
|
+
DER = {
|
|
13923
|
+
// asn.1 DER encoding utils
|
|
13924
|
+
Err: DERErr,
|
|
13925
|
+
// Basic building block is TLV (Tag-Length-Value)
|
|
13926
|
+
_tlv: {
|
|
13927
|
+
encode: (tag, data) => {
|
|
13928
|
+
const { Err: E } = DER;
|
|
13929
|
+
if (tag < 0 || tag > 256)
|
|
13930
|
+
throw new E("tlv.encode: wrong tag");
|
|
13931
|
+
if (data.length & 1)
|
|
13932
|
+
throw new E("tlv.encode: unpadded data");
|
|
13933
|
+
const dataLen = data.length / 2;
|
|
13934
|
+
const len = numberToHexUnpadded(dataLen);
|
|
13935
|
+
if (len.length / 2 & 128)
|
|
13936
|
+
throw new E("tlv.encode: long form length too big");
|
|
13937
|
+
const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : "";
|
|
13938
|
+
const t = numberToHexUnpadded(tag);
|
|
13939
|
+
return t + lenLen + len + data;
|
|
13940
|
+
},
|
|
13941
|
+
// v - value, l - left bytes (unparsed)
|
|
13942
|
+
decode(tag, data) {
|
|
13943
|
+
const { Err: E } = DER;
|
|
13944
|
+
let pos = 0;
|
|
13945
|
+
if (tag < 0 || tag > 256)
|
|
13946
|
+
throw new E("tlv.encode: wrong tag");
|
|
13947
|
+
if (data.length < 2 || data[pos++] !== tag)
|
|
13948
|
+
throw new E("tlv.decode: wrong tlv");
|
|
13949
|
+
const first = data[pos++];
|
|
13950
|
+
const isLong = !!(first & 128);
|
|
13951
|
+
let length5 = 0;
|
|
13952
|
+
if (!isLong)
|
|
13953
|
+
length5 = first;
|
|
13954
|
+
else {
|
|
13955
|
+
const lenLen = first & 127;
|
|
13956
|
+
if (!lenLen)
|
|
13957
|
+
throw new E("tlv.decode(long): indefinite length not supported");
|
|
13958
|
+
if (lenLen > 4)
|
|
13959
|
+
throw new E("tlv.decode(long): byte length is too big");
|
|
13960
|
+
const lengthBytes = data.subarray(pos, pos + lenLen);
|
|
13961
|
+
if (lengthBytes.length !== lenLen)
|
|
13962
|
+
throw new E("tlv.decode: length bytes not complete");
|
|
13963
|
+
if (lengthBytes[0] === 0)
|
|
13964
|
+
throw new E("tlv.decode(long): zero leftmost byte");
|
|
13965
|
+
for (const b of lengthBytes)
|
|
13966
|
+
length5 = length5 << 8 | b;
|
|
13967
|
+
pos += lenLen;
|
|
13968
|
+
if (length5 < 128)
|
|
13969
|
+
throw new E("tlv.decode(long): not minimal encoding");
|
|
13970
|
+
}
|
|
13971
|
+
const v = data.subarray(pos, pos + length5);
|
|
13972
|
+
if (v.length !== length5)
|
|
13973
|
+
throw new E("tlv.decode: wrong value length");
|
|
13974
|
+
return { v, l: data.subarray(pos + length5) };
|
|
13975
|
+
}
|
|
13976
|
+
},
|
|
13977
|
+
// https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
|
|
13978
|
+
// since we always use positive integers here. It must always be empty:
|
|
13979
|
+
// - add zero byte if exists
|
|
13980
|
+
// - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
|
|
13981
|
+
_int: {
|
|
13982
|
+
encode(num) {
|
|
13983
|
+
const { Err: E } = DER;
|
|
13984
|
+
if (num < _0n6)
|
|
13985
|
+
throw new E("integer: negative integers are not allowed");
|
|
13986
|
+
let hex3 = numberToHexUnpadded(num);
|
|
13987
|
+
if (Number.parseInt(hex3[0], 16) & 8)
|
|
13988
|
+
hex3 = "00" + hex3;
|
|
13989
|
+
if (hex3.length & 1)
|
|
13990
|
+
throw new E("unexpected DER parsing assertion: unpadded hex");
|
|
13991
|
+
return hex3;
|
|
13992
|
+
},
|
|
13993
|
+
decode(data) {
|
|
13994
|
+
const { Err: E } = DER;
|
|
13995
|
+
if (data[0] & 128)
|
|
13996
|
+
throw new E("invalid signature integer: negative");
|
|
13997
|
+
if (data[0] === 0 && !(data[1] & 128))
|
|
13998
|
+
throw new E("invalid signature integer: unnecessary leading zero");
|
|
13999
|
+
return bytesToNumberBE(data);
|
|
14000
|
+
}
|
|
14001
|
+
},
|
|
14002
|
+
toSig(hex3) {
|
|
14003
|
+
const { Err: E, _int: int, _tlv: tlv } = DER;
|
|
14004
|
+
const data = ensureBytes("signature", hex3);
|
|
14005
|
+
const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data);
|
|
14006
|
+
if (seqLeftBytes.length)
|
|
14007
|
+
throw new E("invalid signature: left bytes after parsing");
|
|
14008
|
+
const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes);
|
|
14009
|
+
const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes);
|
|
14010
|
+
if (sLeftBytes.length)
|
|
14011
|
+
throw new E("invalid signature: left bytes after parsing");
|
|
14012
|
+
return { r: int.decode(rBytes), s: int.decode(sBytes) };
|
|
14013
|
+
},
|
|
14014
|
+
hexFromSig(sig) {
|
|
14015
|
+
const { _tlv: tlv, _int: int } = DER;
|
|
14016
|
+
const rs = tlv.encode(2, int.encode(sig.r));
|
|
14017
|
+
const ss = tlv.encode(2, int.encode(sig.s));
|
|
14018
|
+
const seq = rs + ss;
|
|
14019
|
+
return tlv.encode(48, seq);
|
|
14020
|
+
}
|
|
14021
|
+
};
|
|
14022
|
+
_0n6 = BigInt(0);
|
|
14023
|
+
_1n6 = BigInt(1);
|
|
14024
|
+
_2n4 = BigInt(2);
|
|
14025
|
+
_3n3 = BigInt(3);
|
|
14026
|
+
_4n2 = BigInt(4);
|
|
14027
|
+
}
|
|
14028
|
+
});
|
|
14029
|
+
|
|
14030
|
+
// ../../node_modules/@noble/curves/esm/_shortw_utils.js
|
|
14031
|
+
function createCurve(curveDef, defHash) {
|
|
14032
|
+
const create5 = (hash) => weierstrass({ ...curveDef, hash });
|
|
14033
|
+
return { ...create5(defHash), create: create5 };
|
|
14034
|
+
}
|
|
14035
|
+
var init_shortw_utils = __esm({
|
|
14036
|
+
"../../node_modules/@noble/curves/esm/_shortw_utils.js"() {
|
|
14037
|
+
"use strict";
|
|
14038
|
+
init_weierstrass();
|
|
14039
|
+
}
|
|
14040
|
+
});
|
|
14041
|
+
|
|
14042
|
+
// ../../node_modules/@noble/curves/esm/nist.js
|
|
14043
|
+
var p256_CURVE, p384_CURVE, p521_CURVE, Fp256, Fp384, Fp521, p256, p384, p521;
|
|
14044
|
+
var init_nist = __esm({
|
|
14045
|
+
"../../node_modules/@noble/curves/esm/nist.js"() {
|
|
14046
|
+
"use strict";
|
|
14047
|
+
init_sha2();
|
|
14048
|
+
init_shortw_utils();
|
|
14049
|
+
init_modular();
|
|
14050
|
+
p256_CURVE = {
|
|
14051
|
+
p: BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"),
|
|
14052
|
+
n: BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"),
|
|
14053
|
+
h: BigInt(1),
|
|
14054
|
+
a: BigInt("0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc"),
|
|
14055
|
+
b: BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"),
|
|
14056
|
+
Gx: BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"),
|
|
14057
|
+
Gy: BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")
|
|
14058
|
+
};
|
|
14059
|
+
p384_CURVE = {
|
|
14060
|
+
p: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"),
|
|
14061
|
+
n: BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973"),
|
|
14062
|
+
h: BigInt(1),
|
|
14063
|
+
a: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc"),
|
|
14064
|
+
b: BigInt("0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"),
|
|
14065
|
+
Gx: BigInt("0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"),
|
|
14066
|
+
Gy: BigInt("0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")
|
|
14067
|
+
};
|
|
14068
|
+
p521_CURVE = {
|
|
14069
|
+
p: BigInt("0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
|
|
14070
|
+
n: BigInt("0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409"),
|
|
14071
|
+
h: BigInt(1),
|
|
14072
|
+
a: BigInt("0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc"),
|
|
14073
|
+
b: BigInt("0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00"),
|
|
14074
|
+
Gx: BigInt("0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66"),
|
|
14075
|
+
Gy: BigInt("0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650")
|
|
14076
|
+
};
|
|
14077
|
+
Fp256 = Field(p256_CURVE.p);
|
|
14078
|
+
Fp384 = Field(p384_CURVE.p);
|
|
14079
|
+
Fp521 = Field(p521_CURVE.p);
|
|
14080
|
+
p256 = createCurve({ ...p256_CURVE, Fp: Fp256, lowS: false }, sha256);
|
|
14081
|
+
p384 = createCurve({ ...p384_CURVE, Fp: Fp384, lowS: false }, sha384);
|
|
14082
|
+
p521 = createCurve({ ...p521_CURVE, Fp: Fp521, lowS: false, allowedPrivateKeyLengths: [130, 131, 132] }, sha512);
|
|
14083
|
+
}
|
|
14084
|
+
});
|
|
14085
|
+
|
|
14086
|
+
// ../../node_modules/@noble/curves/esm/p256.js
|
|
14087
|
+
var p2562;
|
|
14088
|
+
var init_p256 = __esm({
|
|
14089
|
+
"../../node_modules/@noble/curves/esm/p256.js"() {
|
|
14090
|
+
"use strict";
|
|
14091
|
+
init_nist();
|
|
14092
|
+
p2562 = p256;
|
|
14093
|
+
}
|
|
14094
|
+
});
|
|
14095
|
+
|
|
12790
14096
|
// ../share-envelope/dist/links.js
|
|
12791
14097
|
var links_exports = {};
|
|
12792
14098
|
__export(links_exports, {
|
|
@@ -12813,6 +14119,7 @@ __export(links_exports, {
|
|
|
12813
14119
|
checkLinkBody: () => checkLinkBody,
|
|
12814
14120
|
checkLinkHeaderLife: () => checkLinkHeaderLife,
|
|
12815
14121
|
checkLinkRecord: () => checkLinkRecord,
|
|
14122
|
+
createApprovalRequest: () => createApprovalRequest,
|
|
12816
14123
|
createLink: () => createLink,
|
|
12817
14124
|
deleteLink: () => deleteLink,
|
|
12818
14125
|
ed25519KeyProblem: () => ed25519KeyProblem,
|
|
@@ -12826,11 +14133,13 @@ __export(links_exports, {
|
|
|
12826
14133
|
linkTypeSchema: () => linkTypeSchema,
|
|
12827
14134
|
normalizeLinkId: () => normalizeLinkId,
|
|
12828
14135
|
openLinkRecord: () => openLinkRecord,
|
|
14136
|
+
parseApprovalRequest: () => parseApprovalRequest,
|
|
12829
14137
|
parseLink: () => parseLink,
|
|
12830
14138
|
parseLinkTimestamp: () => parseLinkTimestamp,
|
|
12831
14139
|
prepareLinkRecord: () => prepareLinkRecord,
|
|
12832
14140
|
randomLinkNonce: () => randomLinkNonce,
|
|
12833
14141
|
redactLink: () => redactLink,
|
|
14142
|
+
resolveApprovalRequest: () => resolveApprovalRequest,
|
|
12834
14143
|
resolveLink: () => resolveLink,
|
|
12835
14144
|
shortShareLinkCid: () => shortShareLinkCid,
|
|
12836
14145
|
signDelete: () => signDelete,
|
|
@@ -13205,14 +14514,14 @@ function linkTypeForPathLetter(letter) {
|
|
|
13205
14514
|
function normalizeLinkId(id) {
|
|
13206
14515
|
return /^[A-Za-z2-7]{26}$/.test(id) ? id.toLowerCase() : null;
|
|
13207
14516
|
}
|
|
13208
|
-
function canonicalHttpsOrigin(
|
|
14517
|
+
function canonicalHttpsOrigin(origin2) {
|
|
13209
14518
|
let url;
|
|
13210
14519
|
try {
|
|
13211
|
-
url = new URL(
|
|
14520
|
+
url = new URL(origin2);
|
|
13212
14521
|
} catch {
|
|
13213
14522
|
return false;
|
|
13214
14523
|
}
|
|
13215
|
-
return url.protocol === "https:" && url.username === "" && url.password === "" && url.origin ===
|
|
14524
|
+
return url.protocol === "https:" && url.username === "" && url.password === "" && url.origin === origin2;
|
|
13216
14525
|
}
|
|
13217
14526
|
function assertKey2(key) {
|
|
13218
14527
|
if (key.length !== 32) throw new LinkError("invalid_argument", "a link key is 32 bytes");
|
|
@@ -13345,9 +14654,19 @@ async function openLinkRecord(record2, key, options = {}) {
|
|
|
13345
14654
|
await runBodyValidator(opened, options.validateBody);
|
|
13346
14655
|
return opened;
|
|
13347
14656
|
}
|
|
13348
|
-
function
|
|
13349
|
-
|
|
13350
|
-
|
|
14657
|
+
function parseApprovalRequest(value, options = {}) {
|
|
14658
|
+
const parsed = requestSchema.safeParse(value);
|
|
14659
|
+
if (!parsed.success) throw new LinkError("body_validation_failed", "invalid approval request");
|
|
14660
|
+
const request = parsed.data;
|
|
14661
|
+
const publicKey = decodeStrictBase64Url(request.targetPublicJwk.x);
|
|
14662
|
+
if (ed25519KeyProblem(publicKey) !== null || didKeyFromEd25519PublicKey(publicKey) !== request.targetDid || request.issuer !== request.targetDid || options.issuer !== void 0 && request.issuer !== options.issuer) {
|
|
14663
|
+
throw new LinkError("issuer_binding_mismatch");
|
|
14664
|
+
}
|
|
14665
|
+
return request;
|
|
14666
|
+
}
|
|
14667
|
+
function checkApiOrigin(origin2) {
|
|
14668
|
+
if (!AUDIENCE_ORIGIN.test(origin2)) throw new LinkError("invalid_argument", "the API origin is not a canonical https origin");
|
|
14669
|
+
return origin2;
|
|
13351
14670
|
}
|
|
13352
14671
|
function requestSignal(options) {
|
|
13353
14672
|
const timeout = AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
@@ -13460,6 +14779,34 @@ async function createLink(input) {
|
|
|
13460
14779
|
const { id } = created.data;
|
|
13461
14780
|
return { link: buildShortLink({ origin: input.linkOrigin, type: input.type, id, key, bodyCid }), id, expiresAt: record2.header.expiresAt, bodyCid };
|
|
13462
14781
|
}
|
|
14782
|
+
async function createApprovalRequest(input) {
|
|
14783
|
+
const request = parseApprovalRequest(input.request, { issuer: input.issuerKey.did });
|
|
14784
|
+
const now = toEpochMs(input.now);
|
|
14785
|
+
const prepared = await prepareLinkRecord({
|
|
14786
|
+
type: "openkey-approval-request",
|
|
14787
|
+
issuerKey: input.issuerKey,
|
|
14788
|
+
apiOrigin: input.apiOrigin,
|
|
14789
|
+
now,
|
|
14790
|
+
expiresAt: input.expiresAt ?? new Date(now + LINK_TYPE_SPECS["openkey-approval-request"].defaultLifeSeconds * 1e3),
|
|
14791
|
+
plaintext: new TextEncoder().encode(canonicalize2(request))
|
|
14792
|
+
});
|
|
14793
|
+
const response = await send(
|
|
14794
|
+
`${checkApiOrigin(input.apiOrigin)}/v1/links`,
|
|
14795
|
+
{ method: "POST", body: JSON.stringify(prepared.record) },
|
|
14796
|
+
input,
|
|
14797
|
+
"application/json"
|
|
14798
|
+
);
|
|
14799
|
+
if (response.status !== 201) throw await refusal(response);
|
|
14800
|
+
const created = createdSchema.safeParse(await readJson2(response));
|
|
14801
|
+
if (!created.success || !LINK_ID_PATTERN.test(created.data.id) || created.data.expiresAt !== prepared.record.header.expiresAt) throw new LinkError("invalid_response");
|
|
14802
|
+
return {
|
|
14803
|
+
id: created.data.id,
|
|
14804
|
+
expiresAt: prepared.record.header.expiresAt,
|
|
14805
|
+
bodyCid: prepared.bodyCid,
|
|
14806
|
+
record: prepared.record,
|
|
14807
|
+
link: buildShortLink({ origin: input.openkeyOrigin, type: "openkey-approval-request", id: created.data.id, key: prepared.key, bodyCid: prepared.bodyCid })
|
|
14808
|
+
};
|
|
14809
|
+
}
|
|
13463
14810
|
async function deleteLink(input) {
|
|
13464
14811
|
const apiOrigin = checkApiOrigin(input.apiOrigin);
|
|
13465
14812
|
const id = normalizeLinkId(input.id);
|
|
@@ -13524,9 +14871,20 @@ async function resolveLink(link4, input) {
|
|
|
13524
14871
|
} else if (opened.type !== "share") {
|
|
13525
14872
|
throw new LinkError("full_non_share");
|
|
13526
14873
|
}
|
|
14874
|
+
if (opened.type === "openkey-approval-request") {
|
|
14875
|
+
if (opened.header.audience !== input.apiOrigin) throw new LinkError("audience_mismatch");
|
|
14876
|
+
parseApprovalRequest(opened.value, { issuer: opened.header.issuer });
|
|
14877
|
+
}
|
|
13527
14878
|
await runBodyValidator(opened, input.validateBody);
|
|
13528
14879
|
return { ...opened, form: parsed.form, id: parsed.form === "short" ? parsed.id : void 0 };
|
|
13529
14880
|
}
|
|
14881
|
+
async function resolveApprovalRequest(link4, input) {
|
|
14882
|
+
const opened = await resolveLink(link4, input);
|
|
14883
|
+
if (opened.type !== "openkey-approval-request") throw new LinkError("type_path_mismatch");
|
|
14884
|
+
if (opened.header.audience !== input.apiOrigin) throw new LinkError("audience_mismatch");
|
|
14885
|
+
const request = parseApprovalRequest(opened.value, { issuer: opened.header.issuer });
|
|
14886
|
+
return { ...opened, request };
|
|
14887
|
+
}
|
|
13530
14888
|
function shortShareLinkCid(href, options) {
|
|
13531
14889
|
try {
|
|
13532
14890
|
const parsed = parseLink(href, { trustedOrigins: options.trustedOrigins });
|
|
@@ -13569,7 +14927,7 @@ function signerFromJwk(jwk) {
|
|
|
13569
14927
|
if (signer.did !== didKeyFromEd25519PublicKey(publicKey)) throw new LinkError("invalid_argument", "the JWK public key does not match its private key");
|
|
13570
14928
|
return signer;
|
|
13571
14929
|
}
|
|
13572
|
-
var SHA256_CODE2, ENVELOPE_AAD_LABEL2, SEALED_BLOB_VERSION, AAD2, KEY_LENGTH, NONCE_LENGTH, TAG_LENGTH, HEADER_LENGTH, LINK_TYPES, MAX_LINK_BODY_BYTES, MAX_LINK_REQUEST_BYTES, LINK_TYPE_SPECS, LINK_HEADER_DOMAIN, LINK_DELETE_DOMAIN, LINK_WINDOW_SECONDS, LINK_MIN_LIFE_SECONDS, LINK_MIN_BODY_BYTES, LINK_SEAL_OVERHEAD_BYTES, LINK_MAX_RECORD_HEADER_BYTES, DEFAULT_LINKS_API_ORIGIN, FULL_LINK_PATH, LINK_ID_PATTERN, LinkError, ED25519_MULTICODEC_PREFIX2, PUBLIC_KEY_LENGTH, ExtendedPoint, GROUP_ORDER, FIELD_PRIME, DID_KEY_PATTERN, SERVICE_ISSUER_PATTERN, AUDIENCE_PATTERN, TIMESTAMP_PATTERN, NONCE_PATTERN, CID_PATTERN, HEADER_KEYS, DELETE_KEYS, ed25519DidKey, linkTypeSchema, linkHeaderV1Schema, linkSignatureV1Schema, linkDeleteRequestV1Schema, LINK_FRAGMENT_VERSION, SHORT_PATH, SHORT_FRAGMENT, FULL_FRAGMENT, REMOVED_FRAGMENT, MAX_FULL_RECORD_JSON_BYTES, jsonObject, DEFAULT_TIMEOUT_MS, MAX_JSON_RESPONSE_BYTES, AUDIENCE_ORIGIN, createdSchema, errorBodySchema, KEY_PARAMETER, DEFAULT_SHARE_ORIGINS;
|
|
14930
|
+
var SHA256_CODE2, ENVELOPE_AAD_LABEL2, SEALED_BLOB_VERSION, AAD2, KEY_LENGTH, NONCE_LENGTH, TAG_LENGTH, HEADER_LENGTH, LINK_TYPES, MAX_LINK_BODY_BYTES, MAX_LINK_REQUEST_BYTES, LINK_TYPE_SPECS, LINK_HEADER_DOMAIN, LINK_DELETE_DOMAIN, LINK_WINDOW_SECONDS, LINK_MIN_LIFE_SECONDS, LINK_MIN_BODY_BYTES, LINK_SEAL_OVERHEAD_BYTES, LINK_MAX_RECORD_HEADER_BYTES, DEFAULT_LINKS_API_ORIGIN, FULL_LINK_PATH, LINK_ID_PATTERN, LinkError, ED25519_MULTICODEC_PREFIX2, PUBLIC_KEY_LENGTH, ExtendedPoint, GROUP_ORDER, FIELD_PRIME, DID_KEY_PATTERN, SERVICE_ISSUER_PATTERN, AUDIENCE_PATTERN, TIMESTAMP_PATTERN, NONCE_PATTERN, CID_PATTERN, HEADER_KEYS, DELETE_KEYS, ed25519DidKey, linkTypeSchema, linkHeaderV1Schema, linkSignatureV1Schema, linkDeleteRequestV1Schema, LINK_FRAGMENT_VERSION, SHORT_PATH, SHORT_FRAGMENT, FULL_FRAGMENT, REMOVED_FRAGMENT, MAX_FULL_RECORD_JSON_BYTES, jsonObject, bytes32, ed25519Jwk, p256Jwk, origin, permission, requestSchema, DEFAULT_TIMEOUT_MS, MAX_JSON_RESPONSE_BYTES, AUDIENCE_ORIGIN, createdSchema, errorBodySchema, KEY_PARAMETER, DEFAULT_SHARE_ORIGINS;
|
|
13573
14931
|
var init_links = __esm({
|
|
13574
14932
|
"../share-envelope/dist/links.js"() {
|
|
13575
14933
|
"use strict";
|
|
@@ -13584,6 +14942,8 @@ var init_links = __esm({
|
|
|
13584
14942
|
init_base58();
|
|
13585
14943
|
init_ed25519();
|
|
13586
14944
|
init_zod();
|
|
14945
|
+
init_p256();
|
|
14946
|
+
init_zod();
|
|
13587
14947
|
init_ed25519();
|
|
13588
14948
|
SHA256_CODE2 = 18;
|
|
13589
14949
|
ENVELOPE_AAD_LABEL2 = "tinycloud-share-envelope-v1";
|
|
@@ -13593,11 +14953,12 @@ var init_links = __esm({
|
|
|
13593
14953
|
NONCE_LENGTH = 12;
|
|
13594
14954
|
TAG_LENGTH = 16;
|
|
13595
14955
|
HEADER_LENGTH = 1;
|
|
13596
|
-
LINK_TYPES = ["openkey-login", "courier", "share"];
|
|
14956
|
+
LINK_TYPES = ["openkey-login", "openkey-approval-request", "courier", "share"];
|
|
13597
14957
|
MAX_LINK_BODY_BYTES = 65536;
|
|
13598
14958
|
MAX_LINK_REQUEST_BYTES = Math.ceil(MAX_LINK_BODY_BYTES * 4 / 3) + 3072;
|
|
13599
14959
|
LINK_TYPE_SPECS = {
|
|
13600
14960
|
"openkey-login": { maxLifeSeconds: 600, defaultLifeSeconds: 600, pathLetter: "l", readOnce: true },
|
|
14961
|
+
"openkey-approval-request": { maxLifeSeconds: 86400, defaultLifeSeconds: 3600, pathLetter: "a", readOnce: false },
|
|
13601
14962
|
courier: { maxLifeSeconds: 604800, defaultLifeSeconds: 86400, pathLetter: "c", readOnce: false },
|
|
13602
14963
|
share: { maxLifeSeconds: 2592e3, defaultLifeSeconds: 2592e3, pathLetter: "s", readOnce: false }
|
|
13603
14964
|
};
|
|
@@ -13668,12 +15029,52 @@ var init_links = __esm({
|
|
|
13668
15029
|
nonce: external_exports2.string()
|
|
13669
15030
|
}).strict();
|
|
13670
15031
|
LINK_FRAGMENT_VERSION = 4;
|
|
13671
|
-
SHORT_PATH = /^\/(s|c|l)\/([A-Za-z2-7]{26})$/;
|
|
15032
|
+
SHORT_PATH = /^\/(s|c|l|a)\/([A-Za-z2-7]{26})$/;
|
|
13672
15033
|
SHORT_FRAGMENT = /^#v=4&k=([A-Za-z0-9_-]{43})&c=(bafkrei[a-z2-7]{52})$/;
|
|
13673
15034
|
FULL_FRAGMENT = /^#v=4&k=([A-Za-z0-9_-]{43})&r=([A-Za-z0-9_-]+)$/;
|
|
13674
15035
|
REMOVED_FRAGMENT = /^#v=[23](&|$)/;
|
|
13675
15036
|
MAX_FULL_RECORD_JSON_BYTES = MAX_LINK_REQUEST_BYTES;
|
|
13676
15037
|
jsonObject = external_exports2.record(external_exports2.unknown());
|
|
15038
|
+
bytes32 = external_exports2.string().refine((value) => decodeStrictBase64Url(value)?.length === 32);
|
|
15039
|
+
ed25519Jwk = external_exports2.object({ kty: external_exports2.literal("OKP"), crv: external_exports2.literal("Ed25519"), x: bytes32 }).strict();
|
|
15040
|
+
p256Jwk = external_exports2.object({ kty: external_exports2.literal("EC"), crv: external_exports2.literal("P-256"), x: bytes32, y: bytes32 }).strict().refine((key) => {
|
|
15041
|
+
try {
|
|
15042
|
+
const point = new Uint8Array(65);
|
|
15043
|
+
point[0] = 4;
|
|
15044
|
+
point.set(decodeStrictBase64Url(key.x), 1);
|
|
15045
|
+
point.set(decodeStrictBase64Url(key.y), 33);
|
|
15046
|
+
p2562.ProjectivePoint.fromHex(point).assertValidity();
|
|
15047
|
+
return true;
|
|
15048
|
+
} catch {
|
|
15049
|
+
return false;
|
|
15050
|
+
}
|
|
15051
|
+
});
|
|
15052
|
+
origin = external_exports2.string().refine((value) => {
|
|
15053
|
+
try {
|
|
15054
|
+
const url = new URL(value);
|
|
15055
|
+
return url.origin === value && (url.protocol === "https:" || url.protocol === "http:" && ["127.0.0.1", "localhost", "[::1]"].includes(url.hostname));
|
|
15056
|
+
} catch {
|
|
15057
|
+
return false;
|
|
15058
|
+
}
|
|
15059
|
+
});
|
|
15060
|
+
permission = external_exports2.object({
|
|
15061
|
+
service: external_exports2.string().min(1),
|
|
15062
|
+
space: external_exports2.string().min(1),
|
|
15063
|
+
path: external_exports2.string(),
|
|
15064
|
+
actions: external_exports2.array(external_exports2.string().min(1)).min(1),
|
|
15065
|
+
caveats: external_exports2.array(external_exports2.unknown()).optional()
|
|
15066
|
+
}).strict();
|
|
15067
|
+
requestSchema = external_exports2.object({
|
|
15068
|
+
issuer: external_exports2.string(),
|
|
15069
|
+
requestVersion: external_exports2.literal(1),
|
|
15070
|
+
targetDid: external_exports2.string(),
|
|
15071
|
+
targetPublicJwk: ed25519Jwk,
|
|
15072
|
+
nodeOrigin: origin,
|
|
15073
|
+
permissions: external_exports2.array(permission).min(1),
|
|
15074
|
+
reason: external_exports2.string().optional(),
|
|
15075
|
+
grantLifetimeSeconds: external_exports2.number().int().positive(),
|
|
15076
|
+
resultEncryptionPublicJwk: p256Jwk
|
|
15077
|
+
}).strict();
|
|
13677
15078
|
DEFAULT_TIMEOUT_MS = 1e4;
|
|
13678
15079
|
MAX_JSON_RESPONSE_BYTES = 4096;
|
|
13679
15080
|
AUDIENCE_ORIGIN = /^https:\/\/[a-z0-9]([a-z0-9.-]*[a-z0-9])?(:[0-9]{1,5})?$/;
|
|
@@ -18984,6 +20385,23 @@ var unifiedEncryptionNetworkSchema = external_exports.string().refine((value) =>
|
|
|
18984
20385
|
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
18985
20386
|
return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
|
|
18986
20387
|
}, { message: "expected canonical TinyCloud encryption network" });
|
|
20388
|
+
var unifiedEncryptionResourceSchema = external_exports.string().refine((value) => {
|
|
20389
|
+
const prefix = "urn:tinycloud:encryption:";
|
|
20390
|
+
if (!value.startsWith(prefix)) return false;
|
|
20391
|
+
const match = /^(did:.+):([^/:?#\s]+)(?:\/(.+))?$/.exec(value.slice(prefix.length));
|
|
20392
|
+
if (match === null) return false;
|
|
20393
|
+
const path = match[3];
|
|
20394
|
+
return path === void 0 || path.split("/").every(
|
|
20395
|
+
(segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment)
|
|
20396
|
+
);
|
|
20397
|
+
}, { message: "expected a canonical TinyCloud encryption resource" });
|
|
20398
|
+
var unifiedEncryptionKeyPathSchema = external_exports.string().regex(/^share\/[^/]+$/).refine(
|
|
20399
|
+
(value) => {
|
|
20400
|
+
const segment = value.slice("share/".length);
|
|
20401
|
+
return segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment);
|
|
20402
|
+
},
|
|
20403
|
+
{ message: "expected an exact share key path" }
|
|
20404
|
+
);
|
|
18987
20405
|
var unifiedKvCapabilitySchema = external_exports.object({
|
|
18988
20406
|
kind: external_exports.literal("kv"),
|
|
18989
20407
|
resource: unifiedResourceSchema,
|
|
@@ -18997,7 +20415,7 @@ var unifiedKvCapabilitySchema = external_exports.object({
|
|
|
18997
20415
|
}).strict();
|
|
18998
20416
|
var unifiedEncryptionCapabilitySchema = external_exports.object({
|
|
18999
20417
|
kind: external_exports.literal("encryption"),
|
|
19000
|
-
resource:
|
|
20418
|
+
resource: unifiedEncryptionResourceSchema,
|
|
19001
20419
|
action: external_exports.literal("tinycloud.encryption/decrypt")
|
|
19002
20420
|
}).strict();
|
|
19003
20421
|
var unifiedCapabilitySchema = external_exports.union([unifiedKvCapabilitySchema, unifiedEncryptionCapabilitySchema]);
|
|
@@ -19006,6 +20424,7 @@ var unifiedContentSourceSchema = external_exports.object({
|
|
|
19006
20424
|
kvResource: unifiedResourceSchema,
|
|
19007
20425
|
selector: external_exports.union([external_exports.literal("exact"), external_exports.literal("prefix")]),
|
|
19008
20426
|
encryptionNetwork: unifiedEncryptionNetworkSchema,
|
|
20427
|
+
encryptionKeyPath: unifiedEncryptionKeyPathSchema.optional(),
|
|
19009
20428
|
encryptedSymmetricKeyDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
19010
20429
|
keyVersion: external_exports.number().int().positive(),
|
|
19011
20430
|
mode: external_exports.union([external_exports.literal("mutable"), external_exports.literal("immutable")]),
|
|
@@ -19123,16 +20542,21 @@ function validateV3Invariants(value, ctx) {
|
|
|
19123
20542
|
if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
|
|
19124
20543
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
|
|
19125
20544
|
}
|
|
19126
|
-
|
|
20545
|
+
const encryptionKeyPath = value.contentSource.encryptionKeyPath;
|
|
20546
|
+
if (encryptionKeyPath !== void 0 && encryptionKeyPath !== `share/${value.contentSource.shareId}`) {
|
|
20547
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource", "encryptionKeyPath"], message: "share key path must name this share" });
|
|
20548
|
+
}
|
|
20549
|
+
if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptionKeyPath !== encryptionKeyPath || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
|
|
19127
20550
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
|
|
19128
20551
|
}
|
|
19129
20552
|
if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
|
|
19130
20553
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
|
|
19131
20554
|
}
|
|
19132
20555
|
const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
|
|
19133
|
-
const
|
|
20556
|
+
const expectedEncryptionResource = encryptionKeyPath === void 0 ? value.encryptionNetwork : `${value.encryptionNetwork}/${encryptionKeyPath}`;
|
|
20557
|
+
const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === expectedEncryptionResource && capability.action === "tinycloud.encryption/decrypt");
|
|
19134
20558
|
if (value.policy.capabilityCeiling.length !== 2 || kvCapabilities.length !== 1 || decryptCapabilities.length !== 1 || kvCapabilities[0]?.resource !== value.contentSource.kvResource || kvCapabilities[0]?.selector !== value.contentSource.selector) {
|
|
19135
|
-
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain exact decrypt
|
|
20559
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain the exact decrypt resource" });
|
|
19136
20560
|
}
|
|
19137
20561
|
}
|
|
19138
20562
|
var unsignedShareEnvelopeV3Schema = unsignedShareEnvelopeV3BaseSchema.superRefine(validateV3Invariants);
|
|
@@ -24635,6 +26059,23 @@ var unifiedEncryptionNetworkSchema2 = external_exports3.string().refine((value)
|
|
|
24635
26059
|
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
24636
26060
|
return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
|
|
24637
26061
|
}, { message: "expected canonical TinyCloud encryption network" });
|
|
26062
|
+
var unifiedEncryptionResourceSchema2 = external_exports3.string().refine((value) => {
|
|
26063
|
+
const prefix = "urn:tinycloud:encryption:";
|
|
26064
|
+
if (!value.startsWith(prefix)) return false;
|
|
26065
|
+
const match = /^(did:.+):([^/:?#\s]+)(?:\/(.+))?$/.exec(value.slice(prefix.length));
|
|
26066
|
+
if (match === null) return false;
|
|
26067
|
+
const path = match[3];
|
|
26068
|
+
return path === void 0 || path.split("/").every(
|
|
26069
|
+
(segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment)
|
|
26070
|
+
);
|
|
26071
|
+
}, { message: "expected a canonical TinyCloud encryption resource" });
|
|
26072
|
+
var unifiedEncryptionKeyPathSchema2 = external_exports3.string().regex(/^share\/[^/]+$/).refine(
|
|
26073
|
+
(value) => {
|
|
26074
|
+
const segment = value.slice("share/".length);
|
|
26075
|
+
return segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment);
|
|
26076
|
+
},
|
|
26077
|
+
{ message: "expected an exact share key path" }
|
|
26078
|
+
);
|
|
24638
26079
|
var unifiedKvCapabilitySchema2 = external_exports3.object({
|
|
24639
26080
|
kind: external_exports3.literal("kv"),
|
|
24640
26081
|
resource: unifiedResourceSchema2,
|
|
@@ -24648,7 +26089,7 @@ var unifiedKvCapabilitySchema2 = external_exports3.object({
|
|
|
24648
26089
|
}).strict();
|
|
24649
26090
|
var unifiedEncryptionCapabilitySchema2 = external_exports3.object({
|
|
24650
26091
|
kind: external_exports3.literal("encryption"),
|
|
24651
|
-
resource:
|
|
26092
|
+
resource: unifiedEncryptionResourceSchema2,
|
|
24652
26093
|
action: external_exports3.literal("tinycloud.encryption/decrypt")
|
|
24653
26094
|
}).strict();
|
|
24654
26095
|
var unifiedCapabilitySchema2 = external_exports3.union([unifiedKvCapabilitySchema2, unifiedEncryptionCapabilitySchema2]);
|
|
@@ -24657,6 +26098,7 @@ var unifiedContentSourceSchema2 = external_exports3.object({
|
|
|
24657
26098
|
kvResource: unifiedResourceSchema2,
|
|
24658
26099
|
selector: external_exports3.union([external_exports3.literal("exact"), external_exports3.literal("prefix")]),
|
|
24659
26100
|
encryptionNetwork: unifiedEncryptionNetworkSchema2,
|
|
26101
|
+
encryptionKeyPath: unifiedEncryptionKeyPathSchema2.optional(),
|
|
24660
26102
|
encryptedSymmetricKeyDigestHex: external_exports3.string().regex(/^[0-9a-f]{64}$/),
|
|
24661
26103
|
keyVersion: external_exports3.number().int().positive(),
|
|
24662
26104
|
mode: external_exports3.union([external_exports3.literal("mutable"), external_exports3.literal("immutable")]),
|
|
@@ -24774,16 +26216,21 @@ function validateV3Invariants2(value, ctx) {
|
|
|
24774
26216
|
if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
|
|
24775
26217
|
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
|
|
24776
26218
|
}
|
|
24777
|
-
|
|
26219
|
+
const encryptionKeyPath = value.contentSource.encryptionKeyPath;
|
|
26220
|
+
if (encryptionKeyPath !== void 0 && encryptionKeyPath !== `share/${value.contentSource.shareId}`) {
|
|
26221
|
+
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["contentSource", "encryptionKeyPath"], message: "share key path must name this share" });
|
|
26222
|
+
}
|
|
26223
|
+
if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptionKeyPath !== encryptionKeyPath || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
|
|
24778
26224
|
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
|
|
24779
26225
|
}
|
|
24780
26226
|
if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
|
|
24781
26227
|
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
|
|
24782
26228
|
}
|
|
24783
26229
|
const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
|
|
24784
|
-
const
|
|
26230
|
+
const expectedEncryptionResource = encryptionKeyPath === void 0 ? value.encryptionNetwork : `${value.encryptionNetwork}/${encryptionKeyPath}`;
|
|
26231
|
+
const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === expectedEncryptionResource && capability.action === "tinycloud.encryption/decrypt");
|
|
24785
26232
|
if (value.policy.capabilityCeiling.length !== 2 || kvCapabilities.length !== 1 || decryptCapabilities.length !== 1 || kvCapabilities[0]?.resource !== value.contentSource.kvResource || kvCapabilities[0]?.selector !== value.contentSource.selector) {
|
|
24786
|
-
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain exact decrypt
|
|
26233
|
+
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain the exact decrypt resource" });
|
|
24787
26234
|
}
|
|
24788
26235
|
}
|
|
24789
26236
|
var unsignedShareEnvelopeV3Schema2 = unsignedShareEnvelopeV3BaseSchema2.superRefine(validateV3Invariants2);
|
|
@@ -24793,6 +26240,7 @@ var SEALED_BLOB_VERSION2 = 1;
|
|
|
24793
26240
|
var AAD3 = utf8Bytes3(ENVELOPE_AAD_LABEL3);
|
|
24794
26241
|
var KEY_LENGTH2 = 32;
|
|
24795
26242
|
var NONCE_LENGTH2 = 12;
|
|
26243
|
+
var TAG_LENGTH2 = 16;
|
|
24796
26244
|
var HEADER_LENGTH2 = 1;
|
|
24797
26245
|
function assertKey3(key32) {
|
|
24798
26246
|
if (key32.length !== KEY_LENGTH2) {
|
|
@@ -24820,6 +26268,17 @@ async function seal2(plaintextBytes, key32) {
|
|
|
24820
26268
|
blob.set(ciphertext, HEADER_LENGTH2 + nonce.length);
|
|
24821
26269
|
return { blob, cid: await computeCid2(blob) };
|
|
24822
26270
|
}
|
|
26271
|
+
async function open7(blob, key32) {
|
|
26272
|
+
if (blob.length < HEADER_LENGTH2 + NONCE_LENGTH2 + TAG_LENGTH2) {
|
|
26273
|
+
throw new TypeError(`sealed blob too short: ${blob.length} bytes`);
|
|
26274
|
+
}
|
|
26275
|
+
if (blob[0] !== SEALED_BLOB_VERSION2) {
|
|
26276
|
+
throw new TypeError(`unknown sealed blob version: ${blob[0]}`);
|
|
26277
|
+
}
|
|
26278
|
+
const nonce = blob.subarray(HEADER_LENGTH2, HEADER_LENGTH2 + NONCE_LENGTH2);
|
|
26279
|
+
const ciphertext = blob.subarray(HEADER_LENGTH2 + NONCE_LENGTH2);
|
|
26280
|
+
return decryptEnvelope2(nonce, ciphertext, key32);
|
|
26281
|
+
}
|
|
24823
26282
|
async function encryptEnvelope2(plaintextBytes, key32) {
|
|
24824
26283
|
const key = await importAesKey2(key32, "encrypt");
|
|
24825
26284
|
const nonce = globalThis.crypto.getRandomValues(new Uint8Array(NONCE_LENGTH2));
|
|
@@ -24832,6 +26291,19 @@ async function encryptEnvelope2(plaintextBytes, key32) {
|
|
|
24832
26291
|
);
|
|
24833
26292
|
return { nonce, ciphertext };
|
|
24834
26293
|
}
|
|
26294
|
+
async function decryptEnvelope2(nonce, ciphertext, key32) {
|
|
26295
|
+
if (nonce.length !== NONCE_LENGTH2) {
|
|
26296
|
+
throw new TypeError(`nonce must be ${NONCE_LENGTH2} bytes, got ${nonce.length}`);
|
|
26297
|
+
}
|
|
26298
|
+
const key = await importAesKey2(key32, "decrypt");
|
|
26299
|
+
return new Uint8Array(
|
|
26300
|
+
await globalThis.crypto.subtle.decrypt(
|
|
26301
|
+
{ name: "AES-GCM", iv: nonce, additionalData: AAD3 },
|
|
26302
|
+
key,
|
|
26303
|
+
ciphertext
|
|
26304
|
+
)
|
|
26305
|
+
);
|
|
26306
|
+
}
|
|
24835
26307
|
function isPlainRecord3(value) {
|
|
24836
26308
|
const proto = Object.getPrototypeOf(value);
|
|
24837
26309
|
return proto === Object.prototype || proto === null;
|
|
@@ -24946,6 +26418,7 @@ function equal(left, right) {
|
|
|
24946
26418
|
return left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
24947
26419
|
}
|
|
24948
26420
|
var ED25519_VERIFY_OPTS2 = { zip215: false };
|
|
26421
|
+
var ENVELOPE_V2_SIGNATURE_DOMAIN = "xyz.tinycloud.share/envelope/v2\0";
|
|
24949
26422
|
var ENVELOPE_V3_SIGNATURE_DOMAIN = "xyz.tinycloud.share/envelope/v3\0";
|
|
24950
26423
|
var POLICY_V1_SIGNATURE_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
|
|
24951
26424
|
var POLICY_V2_SIGNATURE_DOMAIN = "xyz.tinycloud.policy/policy/v2\0";
|
|
@@ -24953,6 +26426,14 @@ var CONTENT_SOURCE_V1_DOMAIN = "xyz.tinycloud.policy/ContentSource/v1\0";
|
|
|
24953
26426
|
var POLICY_CAPABILITY_V1_DOMAIN = "xyz.tinycloud.policy/PolicyCapability/v1\0";
|
|
24954
26427
|
var NATIVE_PROJECTION_V1_DOMAIN = "xyz.tinycloud.policy/NativeProjection/v1\0";
|
|
24955
26428
|
var ATTESTED_ENFORCER_V2_DOMAIN = "xyz.tinycloud.policy/AttestedEnforcerBinding/v2\0";
|
|
26429
|
+
function signingBytesV2(unsigned) {
|
|
26430
|
+
const domain = utf8Bytes3(ENVELOPE_V2_SIGNATURE_DOMAIN);
|
|
26431
|
+
const body = utf8Bytes3(canonicalize3(unsigned));
|
|
26432
|
+
const bytes3 = new Uint8Array(domain.length + body.length);
|
|
26433
|
+
bytes3.set(domain);
|
|
26434
|
+
bytes3.set(body, domain.length);
|
|
26435
|
+
return bytes3;
|
|
26436
|
+
}
|
|
24956
26437
|
function signingBytesV3(unsigned) {
|
|
24957
26438
|
const domain = utf8Bytes3(ENVELOPE_V3_SIGNATURE_DOMAIN);
|
|
24958
26439
|
const body = utf8Bytes3(canonicalize3(unsigned));
|
|
@@ -24961,6 +26442,17 @@ function signingBytesV3(unsigned) {
|
|
|
24961
26442
|
bytes3.set(body, domain.length);
|
|
24962
26443
|
return bytes3;
|
|
24963
26444
|
}
|
|
26445
|
+
function verifyEnvelopeV2SignatureOnly(envelope) {
|
|
26446
|
+
const parsed = shareEnvelopeV2Schema2.parse(envelope);
|
|
26447
|
+
const { signature, ...unsigned } = parsed;
|
|
26448
|
+
return ed25519.verify(fromBase64Url3(signature.value), signingBytesV2(unsigned), ed25519PublicKeyFromDidKey2(signature.signerDid), ED25519_VERIFY_OPTS2);
|
|
26449
|
+
}
|
|
26450
|
+
async function verifyEnvelopeV2(envelope, options) {
|
|
26451
|
+
const parsed = shareEnvelopeV2Schema2.parse(envelope);
|
|
26452
|
+
if (parsed.signature.signerDid !== options.expectedSignerDid || !verifyEnvelopeV2SignatureOnly(parsed)) return false;
|
|
26453
|
+
if (parsed.authorizationTarget.kind === "policy") return await computeCid2(fromBase64Url3(parsed.authorizationTarget.policyBytes)) === parsed.authorizationTarget.policyCid;
|
|
26454
|
+
return true;
|
|
26455
|
+
}
|
|
24964
26456
|
function verifyEnvelopeV3SignatureOnly(envelope) {
|
|
24965
26457
|
const parsed = shareEnvelopeV3Schema2.parse(envelope);
|
|
24966
26458
|
const { signature, ...unsigned } = parsed;
|
|
@@ -25047,6 +26539,52 @@ function base32Lower(bytes3) {
|
|
|
25047
26539
|
if (bits > 0) output += alphabet[buffer << 5 - bits & 31];
|
|
25048
26540
|
return output;
|
|
25049
26541
|
}
|
|
26542
|
+
var KEY_LENGTH22 = 32;
|
|
26543
|
+
function assertCanonicalCid(cidString) {
|
|
26544
|
+
const cid2 = CID3.parse(cidString);
|
|
26545
|
+
if (cid2.version !== 1 || cid2.code !== code3 || cid2.multihash.code !== 18 || // sha2-256 (0x12) only, at the link layer too
|
|
26546
|
+
cid2.toString() !== cidString) {
|
|
26547
|
+
throw new TypeError(`not a canonical CIDv1 raw sha2-256 base32 CID: ${cidString}`);
|
|
26548
|
+
}
|
|
26549
|
+
}
|
|
26550
|
+
function parseShareUrl(url, options = {}) {
|
|
26551
|
+
const parsed = new URL(url);
|
|
26552
|
+
if (parsed.protocol !== "https:") {
|
|
26553
|
+
throw new TypeError(`share URL must be https, got ${parsed.protocol}`);
|
|
26554
|
+
}
|
|
26555
|
+
if (parsed.username !== "" || parsed.password !== "") {
|
|
26556
|
+
throw new TypeError("share URL must not carry userinfo");
|
|
26557
|
+
}
|
|
26558
|
+
if (parsed.search !== "") {
|
|
26559
|
+
throw new TypeError("share URL must not have a query string");
|
|
26560
|
+
}
|
|
26561
|
+
if (options.expectedOrigin !== void 0) {
|
|
26562
|
+
if (!isCanonicalHttpsOrigin2(options.expectedOrigin)) {
|
|
26563
|
+
throw new TypeError(
|
|
26564
|
+
`expectedOrigin must be a canonical https origin, got ${options.expectedOrigin}`
|
|
26565
|
+
);
|
|
26566
|
+
}
|
|
26567
|
+
if (parsed.origin !== options.expectedOrigin) {
|
|
26568
|
+
throw new TypeError(
|
|
26569
|
+
`share URL origin ${parsed.origin} does not match expected ${options.expectedOrigin}`
|
|
26570
|
+
);
|
|
26571
|
+
}
|
|
26572
|
+
}
|
|
26573
|
+
const match = /^\/s\/([a-z2-7]+)$/.exec(parsed.pathname);
|
|
26574
|
+
if (!match || match[1] === void 0) {
|
|
26575
|
+
throw new TypeError(`not a share URL path: ${parsed.pathname}`);
|
|
26576
|
+
}
|
|
26577
|
+
const ciphertextCid = match[1];
|
|
26578
|
+
assertCanonicalCid(ciphertextCid);
|
|
26579
|
+
if (!parsed.hash.startsWith("#k=")) {
|
|
26580
|
+
throw new TypeError("share URL is missing the #k= key fragment");
|
|
26581
|
+
}
|
|
26582
|
+
const key32 = fromBase64Url3(parsed.hash.slice("#k=".length));
|
|
26583
|
+
if (key32.length !== KEY_LENGTH22) {
|
|
26584
|
+
throw new TypeError(`fragment key must be ${KEY_LENGTH22} bytes, got ${key32.length}`);
|
|
26585
|
+
}
|
|
26586
|
+
return { ciphertextCid, key32 };
|
|
26587
|
+
}
|
|
25050
26588
|
var ARTIFACT_ROOT2 = "artifacts";
|
|
25051
26589
|
function parseArtifactVersionPath2(path) {
|
|
25052
26590
|
const match = /^artifacts\/([a-z0-9][a-z0-9_-]{2,62})\/versions\/([1-9][0-9]{0,14})\/([^/]+)$/.exec(path);
|
|
@@ -25123,6 +26661,7 @@ function verifyArtifactShare(envelope, options) {
|
|
|
25123
26661
|
}
|
|
25124
26662
|
var SHARE_RESULT_VERSION = 1;
|
|
25125
26663
|
var DEFAULT_MAX_SEALED_BLOB_BYTES = 100 * 1024 * 1024 + 29;
|
|
26664
|
+
var DEFAULT_MAX_CONTENT_BLOB_BYTES = DEFAULT_MAX_SEALED_BLOB_BYTES;
|
|
25126
26665
|
var ShareReceiveError = class extends Error {
|
|
25127
26666
|
code;
|
|
25128
26667
|
details;
|
|
@@ -25136,13 +26675,13 @@ var ShareReceiveError = class extends Error {
|
|
|
25136
26675
|
return { protocol: "tinycloud-share", version: SHARE_RESULT_VERSION, error: { code: this.code } };
|
|
25137
26676
|
}
|
|
25138
26677
|
};
|
|
25139
|
-
function metadataFor(envelope,
|
|
25140
|
-
const kind = envelope.recipientMatcher.kind === "recipientDid" ? "recipientDid" : envelope.recipientMatcher.kind === "exactEmail" ? "email" : "emailDomain";
|
|
26678
|
+
function metadataFor(envelope, origin2) {
|
|
26679
|
+
const kind = envelope.recipientMatcher.kind === "recipientDid" ? "recipientDid" : envelope.recipientMatcher.kind === "exactEmail" ? "email" : envelope.recipientMatcher.kind === "emailDomain" ? "emailDomain" : "bearer";
|
|
25141
26680
|
return {
|
|
25142
26681
|
protocol: "tinycloud-share",
|
|
25143
26682
|
version: 1,
|
|
25144
26683
|
shareId: envelope.shareId,
|
|
25145
|
-
origin,
|
|
26684
|
+
origin: origin2,
|
|
25146
26685
|
target: { ...envelope.target, kind },
|
|
25147
26686
|
resource: { ...envelope.resource },
|
|
25148
26687
|
actions: [...envelope.actions],
|
|
@@ -25152,7 +26691,7 @@ function metadataFor(envelope, origin) {
|
|
|
25152
26691
|
...envelope.display.filename === void 0 ? {} : { filename: envelope.display.filename },
|
|
25153
26692
|
...envelope.display.mode === void 0 ? {} : { mode: envelope.display.mode }
|
|
25154
26693
|
},
|
|
25155
|
-
...envelope.
|
|
26694
|
+
...envelope.version === 3 && envelope.artifactPin !== void 0 ? { artifact: { id: envelope.artifactPin.artifactId, version: envelope.artifactPin.version } } : {}
|
|
25156
26695
|
};
|
|
25157
26696
|
}
|
|
25158
26697
|
function receiveErrorFor(error) {
|
|
@@ -25250,14 +26789,165 @@ async function resolvePolicyShare(link4, options) {
|
|
|
25250
26789
|
options.onResolvedAddressedEnvelope?.(envelope, cid2);
|
|
25251
26790
|
return { envelope, origin: url.origin, cid: cid2 };
|
|
25252
26791
|
}
|
|
26792
|
+
async function resolveLegacyV2(link4, options) {
|
|
26793
|
+
let parsed;
|
|
26794
|
+
try {
|
|
26795
|
+
parsed = parseShareUrl(link4, { ...options.expectedOrigin === void 0 ? {} : { expectedOrigin: options.expectedOrigin } });
|
|
26796
|
+
} catch {
|
|
26797
|
+
throw new ShareReceiveError("invalid-link", "legacy share link format is invalid");
|
|
26798
|
+
}
|
|
26799
|
+
try {
|
|
26800
|
+
options.signal?.throwIfAborted();
|
|
26801
|
+
const origin2 = new URL(link4).origin;
|
|
26802
|
+
const limit = options.maxSealedBlobBytes ?? DEFAULT_MAX_SEALED_BLOB_BYTES;
|
|
26803
|
+
if (!Number.isSafeInteger(limit) || limit <= 0) throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope limit is invalid");
|
|
26804
|
+
let sealed;
|
|
26805
|
+
if (options.fetchBlob !== void 0) {
|
|
26806
|
+
try {
|
|
26807
|
+
sealed = await options.fetchBlob({ origin: origin2, cid: parsed.ciphertextCid, ...options.signal === void 0 ? {} : { signal: options.signal } });
|
|
26808
|
+
} catch {
|
|
26809
|
+
throw new ShareReceiveError("fetch-failed", "legacy registry unavailable");
|
|
26810
|
+
}
|
|
26811
|
+
} else {
|
|
26812
|
+
if (options.registryBaseUrl === void 0) throw new ShareReceiveError("fetch-failed", "legacy registry is required");
|
|
26813
|
+
const response = await (options.fetch ?? globalThis.fetch)(`${options.registryBaseUrl.replace(/\/+$/, "")}/ipfs/${parsed.ciphertextCid}?format=raw`, {
|
|
26814
|
+
headers: { accept: "application/vnd.ipld.raw" },
|
|
26815
|
+
redirect: "error",
|
|
26816
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
26817
|
+
});
|
|
26818
|
+
if (!response.ok) throw new ShareReceiveError("fetch-failed", "legacy registry unavailable");
|
|
26819
|
+
if (Number(response.headers.get("content-length")) > limit) throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope exceeds the size limit");
|
|
26820
|
+
const reader = response.body?.getReader();
|
|
26821
|
+
if (reader === void 0) throw new ShareReceiveError("fetch-failed", "legacy registry returned no body");
|
|
26822
|
+
const chunks = [];
|
|
26823
|
+
let length32 = 0;
|
|
26824
|
+
for (; ; ) {
|
|
26825
|
+
const part = await reader.read();
|
|
26826
|
+
if (part.done) break;
|
|
26827
|
+
length32 += part.value.length;
|
|
26828
|
+
if (length32 > limit) {
|
|
26829
|
+
await reader.cancel();
|
|
26830
|
+
throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope exceeds the size limit");
|
|
26831
|
+
}
|
|
26832
|
+
chunks.push(part.value);
|
|
26833
|
+
}
|
|
26834
|
+
sealed = new Uint8Array(length32);
|
|
26835
|
+
let offset = 0;
|
|
26836
|
+
for (const chunk of chunks) {
|
|
26837
|
+
sealed.set(chunk, offset);
|
|
26838
|
+
offset += chunk.length;
|
|
26839
|
+
}
|
|
26840
|
+
}
|
|
26841
|
+
options.signal?.throwIfAborted();
|
|
26842
|
+
if (!(sealed instanceof Uint8Array) || sealed.length > limit) throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope exceeds the size limit");
|
|
26843
|
+
if (await computeCid2(sealed) !== parsed.ciphertextCid) throw new ShareReceiveError("cid-mismatch", "legacy envelope CID does not match");
|
|
26844
|
+
let plaintext;
|
|
26845
|
+
try {
|
|
26846
|
+
plaintext = await open7(sealed, parsed.key32);
|
|
26847
|
+
} catch {
|
|
26848
|
+
throw new ShareReceiveError("decrypt-failed", "legacy envelope could not be opened");
|
|
26849
|
+
}
|
|
26850
|
+
let envelope;
|
|
26851
|
+
try {
|
|
26852
|
+
const encoded = new TextDecoder("utf-8", { fatal: true }).decode(plaintext);
|
|
26853
|
+
const value = JSON.parse(encoded);
|
|
26854
|
+
if (canonicalize3(value) !== encoded) throw new Error("non-canonical envelope");
|
|
26855
|
+
envelope = shareEnvelopeV2Schema2.parse(value);
|
|
26856
|
+
} catch {
|
|
26857
|
+
throw new ShareReceiveError("envelope-invalid", "legacy envelope is invalid");
|
|
26858
|
+
}
|
|
26859
|
+
return { envelope, origin: origin2, cid: parsed.ciphertextCid };
|
|
26860
|
+
} finally {
|
|
26861
|
+
parsed.key32.fill(0);
|
|
26862
|
+
}
|
|
26863
|
+
}
|
|
26864
|
+
function evidenceMatchesV2(envelope, evidence) {
|
|
26865
|
+
const actions = new Set(evidence.actions.map((action) => action === "read" ? "tinycloud.kv/get" : action === "list" ? "tinycloud.kv/list" : action === "edit" ? "tinycloud.kv/put" : action));
|
|
26866
|
+
const resourceCovers = evidence.resource.kind === "exact" ? envelope.resource.kind === "exact" && evidence.resource.path === envelope.resource.path : envelope.resource.path === evidence.resource.path || envelope.resource.path.startsWith(evidence.resource.path.endsWith("/") ? evidence.resource.path : `${evidence.resource.path}/`);
|
|
26867
|
+
return envelope.authorizationTarget.kind === "policy" && evidence.policyCid === envelope.authorizationTarget.policyCid && evidence.signerDid === envelope.signature.signerDid && evidence.registrationCid.length > 0 && evidence.shareId === envelope.shareId && canonicalize3(evidence.recipientMatcher) === canonicalize3(envelope.recipientMatcher) && canonicalize3(evidence.target) === canonicalize3(envelope.target) && resourceCovers && envelope.actions.every((action) => actions.has(action === "read" ? "tinycloud.kv/get" : action === "list" ? "tinycloud.kv/list" : "tinycloud.kv/put")) && canonicalize3(evidence.contentSource) === canonicalize3(envelope.contentSource) && evidence.contentSourceDigest === envelope.contentSourceDigest && evidence.delegationCid === envelope.delegationCid && evidence.authorityMaterialHandle === envelope.authorityMaterialHandle && evidence.authorityMaterialDigest === envelope.authorityMaterialDigest && evidence.expiresAt === envelope.expiry && Number.isFinite(Date.parse(evidence.expiresAt)) && Date.parse(evidence.expiresAt) === Date.parse(envelope.expiry);
|
|
26868
|
+
}
|
|
26869
|
+
async function verifyLegacyV2(envelope, options) {
|
|
26870
|
+
try {
|
|
26871
|
+
if (!await verifyEnvelopeV2(envelope, { expectedSignerDid: envelope.signature.signerDid })) throw new Error("signature");
|
|
26872
|
+
} catch {
|
|
26873
|
+
throw new ShareReceiveError("signature-invalid", "legacy envelope signature is invalid");
|
|
26874
|
+
}
|
|
26875
|
+
const expiry = Date.parse(envelope.expiry);
|
|
26876
|
+
if (!Number.isFinite(expiry)) throw new ShareReceiveError("envelope-invalid", "legacy share expiry is invalid");
|
|
26877
|
+
if (expiry <= (options.now?.() ?? Date.now())) throw new ShareReceiveError("expired", "legacy share has expired", { expiresAt: envelope.expiry });
|
|
26878
|
+
if (envelope.authorizationTarget.kind === "policy") {
|
|
26879
|
+
if (options.trustedPolicyAuthority === void 0) throw new ShareReceiveError("envelope-invalid", "a legacy policy authority is required");
|
|
26880
|
+
let evidence;
|
|
26881
|
+
try {
|
|
26882
|
+
evidence = await options.trustedPolicyAuthority.resolve({ policyCid: envelope.authorizationTarget.policyCid, envelope });
|
|
26883
|
+
} catch {
|
|
26884
|
+
}
|
|
26885
|
+
if (evidence === void 0 || !evidenceMatchesV2(envelope, evidence)) throw new ShareReceiveError("capability-invalid", "legacy policy evidence does not match");
|
|
26886
|
+
if (options.trustedSignerDid !== void 0 && options.trustedSignerDid !== evidence.signerDid) throw new ShareReceiveError("signature-invalid", "legacy signer is not trusted");
|
|
26887
|
+
} else if (options.trustedSignerDid === void 0 || options.trustedSignerDid !== envelope.signature.signerDid || envelope.authorizationTarget.kind === "recipientDid" && envelope.recipientMatcher.kind === "recipientDid" && envelope.authorizationTarget.did !== envelope.recipientMatcher.value) {
|
|
26888
|
+
throw new ShareReceiveError("capability-invalid", "legacy recipient authority does not match");
|
|
26889
|
+
}
|
|
26890
|
+
}
|
|
25253
26891
|
async function inspectShare(link4, options = {}) {
|
|
26892
|
+
if (isLegacyV2Link(link4)) {
|
|
26893
|
+
const legacy = await resolveLegacyV2(link4, options);
|
|
26894
|
+
await verifyLegacyV2(legacy.envelope, options);
|
|
26895
|
+
options.onResolvedAddressedEnvelope?.(legacy.envelope, legacy.cid);
|
|
26896
|
+
return { metadata: metadataFor(legacy.envelope, legacy.origin), link: { origin: legacy.origin, cid: legacy.cid, kind: "compact" } };
|
|
26897
|
+
}
|
|
25254
26898
|
const resolved = await resolvePolicyShare(link4, options);
|
|
25255
26899
|
return { metadata: metadataFor(resolved.envelope, resolved.origin), link: { origin: resolved.origin, cid: resolved.cid, kind: "policy" } };
|
|
25256
26900
|
}
|
|
25257
26901
|
async function receiveShare(link4, options = {}) {
|
|
26902
|
+
if (isLegacyV2Link(link4)) return receiveLegacyV2(link4, options);
|
|
25258
26903
|
const resolved = await resolvePolicyShare(link4, options);
|
|
25259
26904
|
return { state: "authorization-required", method: resolved.envelope.recipientMatcher.kind === "recipientDid" ? "openkey-device" : "email-claim" };
|
|
25260
26905
|
}
|
|
26906
|
+
function isLegacyV2Link(link4) {
|
|
26907
|
+
try {
|
|
26908
|
+
const url = new URL(link4);
|
|
26909
|
+
return /^\/s\/bafkrei[a-z2-7]{52}$/.test(url.pathname) && url.hash.startsWith("#k=");
|
|
26910
|
+
} catch {
|
|
26911
|
+
return false;
|
|
26912
|
+
}
|
|
26913
|
+
}
|
|
26914
|
+
async function receiveLegacyV2(link4, options) {
|
|
26915
|
+
const resolved = await resolveLegacyV2(link4, options);
|
|
26916
|
+
const { envelope } = resolved;
|
|
26917
|
+
await verifyLegacyV2(envelope, options);
|
|
26918
|
+
options.onResolvedAddressedEnvelope?.(envelope, resolved.cid);
|
|
26919
|
+
const method = envelope.recipientMatcher.kind === "recipientDid" ? "openkey-device" : "email-claim";
|
|
26920
|
+
if (options.authorization === void 0) return { state: "authorization-required", method };
|
|
26921
|
+
const result = options.authorizationResumeToken === void 0 ? await options.authorization.begin({ envelope, method }) : await options.authorization.resume({
|
|
26922
|
+
envelope,
|
|
26923
|
+
method,
|
|
26924
|
+
resumeToken: options.authorizationResumeToken,
|
|
26925
|
+
...options.authorizationProof === void 0 ? {} : { proof: options.authorizationProof }
|
|
26926
|
+
});
|
|
26927
|
+
if (result.state === "authorization-required") return result;
|
|
26928
|
+
if (result.state === "denied") throw new ShareReceiveError("authorization-denied", "legacy share authorization was denied");
|
|
26929
|
+
if (result.value === null || typeof result.value !== "object" || !(result.value.bytes instanceof Uint8Array) || result.value.proof === void 0 || options.authorization.verifyResult === void 0) {
|
|
26930
|
+
throw new ShareReceiveError("content-integrity-failed", "legacy content lacks a verifiable proof");
|
|
26931
|
+
}
|
|
26932
|
+
const authorized = result.value;
|
|
26933
|
+
try {
|
|
26934
|
+
if (!await options.authorization.verifyResult({ envelope, value: authorized, proof: authorized.proof })) throw new Error("proof");
|
|
26935
|
+
} catch {
|
|
26936
|
+
throw new ShareReceiveError("content-integrity-failed", "legacy content proof is invalid");
|
|
26937
|
+
}
|
|
26938
|
+
const bytes3 = authorized.bytes.slice();
|
|
26939
|
+
if (bytes3.length > (options.maxContentBlobBytes ?? DEFAULT_MAX_CONTENT_BLOB_BYTES)) throw new ShareReceiveError("max-bytes-exceeded", "legacy content exceeds the size limit");
|
|
26940
|
+
const bodyDigest = toBase64Url2(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes3)));
|
|
26941
|
+
if (authorized.bodyDigest !== bodyDigest || authorized.contentSourceDigest !== envelope.contentSourceDigest || authorized.binding.shareId !== envelope.shareId || authorized.binding.delegationCid !== envelope.delegationCid || authorized.binding.authorityMaterialHandle !== envelope.authorityMaterialHandle || authorized.binding.authorityMaterialDigest !== envelope.authorityMaterialDigest || authorized.binding.resource.kind !== envelope.resource.kind || authorized.binding.resource.path !== envelope.resource.path || authorized.binding.action !== void 0 && !envelope.actions.some((action) => action === authorized.binding.action || `tinycloud.kv/${action}` === authorized.binding.action) || envelope.metadata.byteLength !== void 0 && envelope.metadata.byteLength !== bytes3.length) {
|
|
26942
|
+
throw new ShareReceiveError("content-integrity-failed", "legacy content binding does not match");
|
|
26943
|
+
}
|
|
26944
|
+
let text;
|
|
26945
|
+
try {
|
|
26946
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes3);
|
|
26947
|
+
} catch {
|
|
26948
|
+
}
|
|
26949
|
+
return { metadata: metadataFor(envelope, resolved.origin), link: { origin: resolved.origin, cid: resolved.cid, kind: "compact" }, bytes: bytes3, ...text === void 0 ? {} : { text } };
|
|
26950
|
+
}
|
|
25261
26951
|
var SHARE_CONTENT_LIMIT = 100 * 1024 * 1024;
|
|
25262
26952
|
var SHARE_PUBLISH_RESULT_VERSION = 1;
|
|
25263
26953
|
var DEFAULT_SHARE_LIFETIME_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -25745,7 +27435,10 @@ async function publishTargetShare(input) {
|
|
|
25745
27435
|
expiresAt,
|
|
25746
27436
|
expiryWasExplicit: input.expiryWasExplicit ?? input.expiresAt !== void 0,
|
|
25747
27437
|
origin: input.origin,
|
|
25748
|
-
...input.notify === void 0 ? {} : { notify: input.notify }
|
|
27438
|
+
...input.notify === void 0 ? {} : { notify: input.notify },
|
|
27439
|
+
...input.credentialDescriptor === void 0 ? {} : { credentialDescriptor: input.credentialDescriptor },
|
|
27440
|
+
...input.issuerDid === void 0 ? {} : { issuerDid: input.issuerDid },
|
|
27441
|
+
...input.issuerKid === void 0 ? {} : { issuerKid: input.issuerKid }
|
|
25749
27442
|
});
|
|
25750
27443
|
}
|
|
25751
27444
|
var POLICY_V1_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
|
|
@@ -25831,7 +27524,7 @@ async function createPolicy(options, capabilities) {
|
|
|
25831
27524
|
function addressedPlan(options) {
|
|
25832
27525
|
const capabilities = sortCanonical([
|
|
25833
27526
|
{ kind: "kv", resource: options.contentSource.kvResource, selector: options.resource.kind, actions: [...options.policyActions] },
|
|
25834
|
-
{ kind: "encryption", resource: options.contentSource.encryptionNetwork
|
|
27527
|
+
{ kind: "encryption", resource: options.contentSource.encryptionKeyPath === void 0 ? options.contentSource.encryptionNetwork : `${options.contentSource.encryptionNetwork}/${options.contentSource.encryptionKeyPath}`, action: "tinycloud.encryption/decrypt" }
|
|
25835
27528
|
]);
|
|
25836
27529
|
return {
|
|
25837
27530
|
expiry: rfc3339Seconds(options.expiresAt),
|
|
@@ -26156,6 +27849,7 @@ async function addressedShareBodyUpperBound(input) {
|
|
|
26156
27849
|
kvResource: `${input.spaceId}/kv/${path}`,
|
|
26157
27850
|
selector: input.resource.kind,
|
|
26158
27851
|
encryptionNetwork: input.encryptionNetwork,
|
|
27852
|
+
...input.encryptionKeyPath === void 0 ? {} : { encryptionKeyPath: input.encryptionKeyPath },
|
|
26159
27853
|
encryptedSymmetricKeyDigestHex: "f".repeat(64),
|
|
26160
27854
|
keyVersion: Number.MAX_SAFE_INTEGER,
|
|
26161
27855
|
mode: "immutable",
|
|
@@ -26875,9 +28569,9 @@ async function validateReceipt(receipt, shareUrl) {
|
|
|
26875
28569
|
}
|
|
26876
28570
|
const links = await Promise.resolve().then(() => (init_links(), links_exports));
|
|
26877
28571
|
try {
|
|
26878
|
-
const
|
|
26879
|
-
const parsed = links.parseLink(shareUrl, { trustedOrigins: [
|
|
26880
|
-
if (parsed.form !== "short" || parsed.pathType !== "share" || shareUrl.length > MAX_INVITATION_LINK_BYTES || shareUrl !== links.buildShortLink({ origin, type: "share", id: parsed.id, key: parsed.key, bodyCid: parsed.c })) {
|
|
28572
|
+
const origin2 = new URL(shareUrl).origin;
|
|
28573
|
+
const parsed = links.parseLink(shareUrl, { trustedOrigins: [origin2] });
|
|
28574
|
+
if (parsed.form !== "short" || parsed.pathType !== "share" || shareUrl.length > MAX_INVITATION_LINK_BYTES || shareUrl !== links.buildShortLink({ origin: origin2, type: "share", id: parsed.id, key: parsed.key, bodyCid: parsed.c })) {
|
|
26881
28575
|
throw new Error("not a short share link");
|
|
26882
28576
|
}
|
|
26883
28577
|
} catch {
|
|
@@ -28200,6 +29894,23 @@ var unifiedEncryptionNetworkSchema3 = external_exports2.string().refine((value)
|
|
|
28200
29894
|
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
28201
29895
|
return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
|
|
28202
29896
|
}, { message: "expected canonical TinyCloud encryption network" });
|
|
29897
|
+
var unifiedEncryptionResourceSchema3 = external_exports2.string().refine((value) => {
|
|
29898
|
+
const prefix = "urn:tinycloud:encryption:";
|
|
29899
|
+
if (!value.startsWith(prefix)) return false;
|
|
29900
|
+
const match = /^(did:.+):([^/:?#\s]+)(?:\/(.+))?$/.exec(value.slice(prefix.length));
|
|
29901
|
+
if (match === null) return false;
|
|
29902
|
+
const path = match[3];
|
|
29903
|
+
return path === void 0 || path.split("/").every(
|
|
29904
|
+
(segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment)
|
|
29905
|
+
);
|
|
29906
|
+
}, { message: "expected a canonical TinyCloud encryption resource" });
|
|
29907
|
+
var unifiedEncryptionKeyPathSchema3 = external_exports2.string().regex(/^share\/[^/]+$/).refine(
|
|
29908
|
+
(value) => {
|
|
29909
|
+
const segment = value.slice("share/".length);
|
|
29910
|
+
return segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment);
|
|
29911
|
+
},
|
|
29912
|
+
{ message: "expected an exact share key path" }
|
|
29913
|
+
);
|
|
28203
29914
|
var unifiedKvCapabilitySchema3 = external_exports2.object({
|
|
28204
29915
|
kind: external_exports2.literal("kv"),
|
|
28205
29916
|
resource: unifiedResourceSchema3,
|
|
@@ -28213,7 +29924,7 @@ var unifiedKvCapabilitySchema3 = external_exports2.object({
|
|
|
28213
29924
|
}).strict();
|
|
28214
29925
|
var unifiedEncryptionCapabilitySchema3 = external_exports2.object({
|
|
28215
29926
|
kind: external_exports2.literal("encryption"),
|
|
28216
|
-
resource:
|
|
29927
|
+
resource: unifiedEncryptionResourceSchema3,
|
|
28217
29928
|
action: external_exports2.literal("tinycloud.encryption/decrypt")
|
|
28218
29929
|
}).strict();
|
|
28219
29930
|
var unifiedCapabilitySchema3 = external_exports2.union([unifiedKvCapabilitySchema3, unifiedEncryptionCapabilitySchema3]);
|
|
@@ -28222,6 +29933,7 @@ var unifiedContentSourceSchema3 = external_exports2.object({
|
|
|
28222
29933
|
kvResource: unifiedResourceSchema3,
|
|
28223
29934
|
selector: external_exports2.union([external_exports2.literal("exact"), external_exports2.literal("prefix")]),
|
|
28224
29935
|
encryptionNetwork: unifiedEncryptionNetworkSchema3,
|
|
29936
|
+
encryptionKeyPath: unifiedEncryptionKeyPathSchema3.optional(),
|
|
28225
29937
|
encryptedSymmetricKeyDigestHex: external_exports2.string().regex(/^[0-9a-f]{64}$/),
|
|
28226
29938
|
keyVersion: external_exports2.number().int().positive(),
|
|
28227
29939
|
mode: external_exports2.union([external_exports2.literal("mutable"), external_exports2.literal("immutable")]),
|
|
@@ -28339,16 +30051,21 @@ function validateV3Invariants3(value, ctx) {
|
|
|
28339
30051
|
if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
|
|
28340
30052
|
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
|
|
28341
30053
|
}
|
|
28342
|
-
|
|
30054
|
+
const encryptionKeyPath = value.contentSource.encryptionKeyPath;
|
|
30055
|
+
if (encryptionKeyPath !== void 0 && encryptionKeyPath !== `share/${value.contentSource.shareId}`) {
|
|
30056
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource", "encryptionKeyPath"], message: "share key path must name this share" });
|
|
30057
|
+
}
|
|
30058
|
+
if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptionKeyPath !== encryptionKeyPath || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
|
|
28343
30059
|
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
|
|
28344
30060
|
}
|
|
28345
30061
|
if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
|
|
28346
30062
|
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
|
|
28347
30063
|
}
|
|
28348
30064
|
const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
|
|
28349
|
-
const
|
|
30065
|
+
const expectedEncryptionResource = encryptionKeyPath === void 0 ? value.encryptionNetwork : `${value.encryptionNetwork}/${encryptionKeyPath}`;
|
|
30066
|
+
const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === expectedEncryptionResource && capability.action === "tinycloud.encryption/decrypt");
|
|
28350
30067
|
if (value.policy.capabilityCeiling.length !== 2 || kvCapabilities.length !== 1 || decryptCapabilities.length !== 1 || kvCapabilities[0]?.resource !== value.contentSource.kvResource || kvCapabilities[0]?.selector !== value.contentSource.selector) {
|
|
28351
|
-
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain exact decrypt
|
|
30068
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain the exact decrypt resource" });
|
|
28352
30069
|
}
|
|
28353
30070
|
}
|
|
28354
30071
|
var unsignedShareEnvelopeV3Schema3 = unsignedShareEnvelopeV3BaseSchema3.superRefine(validateV3Invariants3);
|
|
@@ -28555,7 +30272,7 @@ function receiveJson(result, path) {
|
|
|
28555
30272
|
|
|
28556
30273
|
// src/share/io.ts
|
|
28557
30274
|
import { constants } from "fs";
|
|
28558
|
-
import { lstat as lstat6, mkdir as mkdir4, mkdtemp, open as
|
|
30275
|
+
import { lstat as lstat6, mkdir as mkdir4, mkdtemp, open as open8, readFile as readFile6, realpath as realpath2, stat as stat4, link as link2, rename as rename3, rm as rm6, unlink as unlink4 } from "fs/promises";
|
|
28559
30276
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
28560
30277
|
import { basename as basename2, join as join11, resolve as resolve4, sep as sep3 } from "path";
|
|
28561
30278
|
init_errors();
|
|
@@ -28631,7 +30348,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
|
|
|
28631
30348
|
const outputDirectory = resolve4(directory);
|
|
28632
30349
|
await assertDirectory(outputDirectory);
|
|
28633
30350
|
const safeName = safeFilename(filename);
|
|
28634
|
-
const directoryHandle = await
|
|
30351
|
+
const directoryHandle = await open8(outputDirectory, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0));
|
|
28635
30352
|
const stableDirectory = await realpath2(outputDirectory);
|
|
28636
30353
|
const outputPath = join11(stableDirectory, safeName);
|
|
28637
30354
|
const directoryIdentity = await directoryHandle.stat();
|
|
@@ -28655,7 +30372,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
|
|
|
28655
30372
|
if (error.code !== "ENOENT") throw error;
|
|
28656
30373
|
}
|
|
28657
30374
|
temporaryPath = stagingPath;
|
|
28658
|
-
handle = await
|
|
30375
|
+
handle = await open8(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 384);
|
|
28659
30376
|
await handle.writeFile(bytes);
|
|
28660
30377
|
await handle.close();
|
|
28661
30378
|
handle = void 0;
|
|
@@ -28677,7 +30394,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
|
|
|
28677
30394
|
if (temporaryPath !== void 0) await unlink4(temporaryPath);
|
|
28678
30395
|
} catch {
|
|
28679
30396
|
}
|
|
28680
|
-
await
|
|
30397
|
+
await rm6(stagingDirectory, { recursive: true, force: true });
|
|
28681
30398
|
await directoryHandle.close();
|
|
28682
30399
|
}
|
|
28683
30400
|
return join11(outputDirectory, safeName);
|
|
@@ -28805,6 +30522,38 @@ function createShareLinks(input) {
|
|
|
28805
30522
|
};
|
|
28806
30523
|
}
|
|
28807
30524
|
|
|
30525
|
+
// src/share/email-publish-v3.ts
|
|
30526
|
+
import {
|
|
30527
|
+
canonicalDigest,
|
|
30528
|
+
createEmailCredentialRequirement,
|
|
30529
|
+
credentialRequirementDigest,
|
|
30530
|
+
validateCredentialFlowDescriptor
|
|
30531
|
+
} from "@tinycloud/sdk-core";
|
|
30532
|
+
async function publishEmailShareV3(input) {
|
|
30533
|
+
const { contentSource } = input;
|
|
30534
|
+
if (input.resource.kind !== "exact" || contentSource.encryptionKeyPath !== `share/${input.shareId}` || !/^urn:tinycloud:encryption:did:pkh:eip155:\d+:0x[0-9a-fA-F]{40}:default$/.test(contentSource.encryptionNetwork)) {
|
|
30535
|
+
throw new TypeError("email share binding is invalid");
|
|
30536
|
+
}
|
|
30537
|
+
const descriptor = validateCredentialFlowDescriptor(input.credentialDescriptor);
|
|
30538
|
+
if (descriptor.issuer.did !== input.issuerDid || descriptor.issuer.kid !== input.issuerKid || !descriptor.claims.some((claim) => claim.name === "email" && claim.matching === "normalized_exact")) {
|
|
30539
|
+
throw new TypeError("email credential issuer or claim is invalid");
|
|
30540
|
+
}
|
|
30541
|
+
const profile = { id: descriptor.profile, version: 1 };
|
|
30542
|
+
const credentialType = { id: descriptor.format.vct, version: 1 };
|
|
30543
|
+
const requirement = createEmailCredentialRequirement({ email: input.target.address, profile, credentialType });
|
|
30544
|
+
const credentialRequirement = {
|
|
30545
|
+
type: "TinyCloudPolicyCredentialRequirement",
|
|
30546
|
+
version: 1,
|
|
30547
|
+
requirementDigest: await credentialRequirementDigest(requirement),
|
|
30548
|
+
descriptorDigest: await canonicalDigest(descriptor),
|
|
30549
|
+
issuerDid: input.issuerDid,
|
|
30550
|
+
issuerKid: input.issuerKid,
|
|
30551
|
+
profile,
|
|
30552
|
+
credentialType
|
|
30553
|
+
};
|
|
30554
|
+
return publishAddressedShare({ ...input, credentialRequirement });
|
|
30555
|
+
}
|
|
30556
|
+
|
|
28808
30557
|
// src/share/errors.ts
|
|
28809
30558
|
var SharePublishAuthorityError = class extends Error {
|
|
28810
30559
|
constructor(failure, options) {
|
|
@@ -28866,7 +30615,7 @@ init_profiles();
|
|
|
28866
30615
|
init_constants();
|
|
28867
30616
|
init_errors();
|
|
28868
30617
|
init_session_expired();
|
|
28869
|
-
import { chmod as chmod4, link as link3, open as
|
|
30618
|
+
import { chmod as chmod4, link as link3, open as open9, readFile as readFile7, stat as stat5, unlink as unlink5 } from "fs/promises";
|
|
28870
30619
|
import { dirname as dirname5, join as join12 } from "path";
|
|
28871
30620
|
import { createHash } from "crypto";
|
|
28872
30621
|
import { writeJsonAtomic as writeJsonAtomic2 } from "@tinycloud/operations/state";
|
|
@@ -29223,7 +30972,7 @@ function createEncryptedProfileHistory(profileName, sessionSigner) {
|
|
|
29223
30972
|
await link3(found.file, target);
|
|
29224
30973
|
await chmod4(target, PRIVATE_HISTORY_MODE);
|
|
29225
30974
|
await unlink5(found.file);
|
|
29226
|
-
const directory = await
|
|
30975
|
+
const directory = await open9(dirname5(found.file), "r");
|
|
29227
30976
|
try {
|
|
29228
30977
|
await directory.sync();
|
|
29229
30978
|
} finally {
|
|
@@ -29271,7 +31020,7 @@ function quarantineUnreadableProfileHistory(profileName) {
|
|
|
29271
31020
|
return createEncryptedProfileHistory(async () => profileName, signShareHistoryBytes).quarantineUnreadable();
|
|
29272
31021
|
}
|
|
29273
31022
|
function createShareAuthorityAdapters(input = {}) {
|
|
29274
|
-
const
|
|
31023
|
+
const origin2 = input.origin ?? DEFAULT_SHARE_ORIGIN;
|
|
29275
31024
|
const fetchFn = input.fetchFn ?? globalThis.fetch;
|
|
29276
31025
|
let selectedProfile;
|
|
29277
31026
|
const profileName = () => selectedProfile ??= input.profileName?.() ?? selectedProfileName();
|
|
@@ -29286,7 +31035,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29286
31035
|
const publicConfig = async () => configPromise ??= (async () => {
|
|
29287
31036
|
let response;
|
|
29288
31037
|
try {
|
|
29289
|
-
response = await fetchFn(`${
|
|
31038
|
+
response = await fetchFn(`${origin2}/.well-known/tinycloud-share/config.json`, {
|
|
29290
31039
|
headers: { accept: "application/json" },
|
|
29291
31040
|
credentials: "omit",
|
|
29292
31041
|
redirect: "error",
|
|
@@ -29294,9 +31043,9 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29294
31043
|
signal: AbortSignal.timeout(1e4)
|
|
29295
31044
|
});
|
|
29296
31045
|
} catch (error) {
|
|
29297
|
-
throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin }, { cause: error });
|
|
31046
|
+
throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin: origin2 }, { cause: error });
|
|
29298
31047
|
}
|
|
29299
|
-
if (!response.ok) throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin });
|
|
31048
|
+
if (!response.ok) throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin: origin2 });
|
|
29300
31049
|
const value = await response.json();
|
|
29301
31050
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("share public config is invalid");
|
|
29302
31051
|
const object3 = value;
|
|
@@ -29380,6 +31129,8 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29380
31129
|
});
|
|
29381
31130
|
const targetAdapter = { async publish(targetInput) {
|
|
29382
31131
|
if (input.publishTarget !== void 0) return input.publishTarget(targetInput);
|
|
31132
|
+
const refusedKind = { emailDomain: "domain", recipientDid: "did" }[targetInput.target.kind];
|
|
31133
|
+
if (refusedKind !== void 0) throw new CLIError("UNAVAILABLE", `${refusedKind}-addressed shares are not available in this release; nothing was shared`, 4);
|
|
29383
31134
|
const node = await authenticatedNode();
|
|
29384
31135
|
const session = node.restorableSession;
|
|
29385
31136
|
const ownerSpaceId = session?.spaceId;
|
|
@@ -29426,8 +31177,15 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29426
31177
|
profileName: activeProfileName2
|
|
29427
31178
|
});
|
|
29428
31179
|
}
|
|
29429
|
-
|
|
29430
|
-
|
|
31180
|
+
if (targetInput.target.kind === "email" && (targetInput.credentialDescriptor === void 0 || targetInput.issuerDid === void 0 || targetInput.issuerKid === void 0)) {
|
|
31181
|
+
throw new TypeError("email credential descriptor and issuer are required");
|
|
31182
|
+
}
|
|
31183
|
+
const addressedEncryptionNetwork = targetInput.target.kind === "bearer" ? void 0 : targetInput.target.kind === "email" ? node.getDefaultEncryptionNetworkId() : node.getEncryptionNetworkIdForSpace(ownerSpaceId);
|
|
31184
|
+
const emailKeyPath = targetInput.target.kind === "email" ? `share/${crypto.randomUUID().replaceAll("-", "")}` : void 0;
|
|
31185
|
+
if (addressedEncryptionNetwork !== void 0 && node.isSessionOnly && !sessionHoldsEncryptionDecrypt(
|
|
31186
|
+
node,
|
|
31187
|
+
emailKeyPath === void 0 ? addressedEncryptionNetwork : `${addressedEncryptionNetwork}/${emailKeyPath}`
|
|
31188
|
+
)) {
|
|
29431
31189
|
throw new SharePublishAuthorityError({ kind: "decrypt-not-held" });
|
|
29432
31190
|
}
|
|
29433
31191
|
const config = await publicConfig();
|
|
@@ -29436,7 +31194,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29436
31194
|
if (targetInput.notify === true && targetInput.target.kind === "emailDomain") {
|
|
29437
31195
|
await assertDomainDeliveryForOrigin(activeNode.origin, "publish");
|
|
29438
31196
|
}
|
|
29439
|
-
const shareId = crypto.randomUUID().replaceAll("-", "");
|
|
31197
|
+
const shareId = emailKeyPath?.slice("share/".length) ?? crypto.randomUUID().replaceAll("-", "");
|
|
29440
31198
|
const files = targetInput.files === void 0 || targetInput.files.length === 0 ? [{ bytes: targetInput.source, filename: targetInput.filename, mediaType: targetInput.mediaType }] : targetInput.files;
|
|
29441
31199
|
const resourceKind = targetInput.resourceKind ?? "exact";
|
|
29442
31200
|
if (targetInput.target.kind === "bearer") {
|
|
@@ -29558,6 +31316,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29558
31316
|
resource: { kind: resourceKind },
|
|
29559
31317
|
storage: artifact === void 0 ? { path: resourcePath } : { artifactId: artifact.id, storageName },
|
|
29560
31318
|
encryptionNetwork: addressedEncryptionNetwork,
|
|
31319
|
+
...emailKeyPath === void 0 ? {} : { encryptionKeyPath: emailKeyPath },
|
|
29561
31320
|
actions,
|
|
29562
31321
|
policyActions,
|
|
29563
31322
|
...deliveryEmail === void 0 ? {} : { deliveryEmail },
|
|
@@ -29573,8 +31332,14 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29573
31332
|
throw new SharePublishAuthorityError({ kind: rejected ? "registry-rejected" : "registry-unavailable" });
|
|
29574
31333
|
}
|
|
29575
31334
|
const encryptionNetwork = addressedEncryptionNetwork;
|
|
29576
|
-
const encrypted = await node.encryption.encryptToNetwork(encryptionNetwork, file.bytes, {
|
|
31335
|
+
const encrypted = await node.encryption.encryptToNetwork(encryptionNetwork, file.bytes, {
|
|
31336
|
+
...emailKeyPath === void 0 ? {} : { keyPath: emailKeyPath },
|
|
31337
|
+
metadata: { contentType: mediaType }
|
|
31338
|
+
});
|
|
29577
31339
|
if (!encrypted.ok) throw new Error("addressed source encryption was rejected");
|
|
31340
|
+
if (emailKeyPath !== void 0 && (encrypted.data.networkId !== encryptionNetwork || encrypted.data.keyPath !== emailKeyPath)) {
|
|
31341
|
+
throw new Error("email share encryption was rejected");
|
|
31342
|
+
}
|
|
29578
31343
|
const storedBytes = new TextEncoder().encode(canonicalize4(encrypted.data));
|
|
29579
31344
|
let artifactVersion;
|
|
29580
31345
|
if (artifact !== void 0) {
|
|
@@ -29607,6 +31372,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29607
31372
|
kvResource: `${ownerSpaceId}/kv/${resourcePath}`,
|
|
29608
31373
|
selector: resourceKind,
|
|
29609
31374
|
encryptionNetwork: encrypted.data.networkId,
|
|
31375
|
+
...emailKeyPath === void 0 ? {} : { encryptionKeyPath: emailKeyPath },
|
|
29610
31376
|
encryptedSymmetricKeyDigestHex: encrypted.data.encryptedSymmetricKeyHash,
|
|
29611
31377
|
keyVersion: encrypted.data.keyVersion,
|
|
29612
31378
|
mode: "immutable",
|
|
@@ -29648,7 +31414,13 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29648
31414
|
};
|
|
29649
31415
|
let published;
|
|
29650
31416
|
try {
|
|
29651
|
-
published = await
|
|
31417
|
+
published = prepared.target.kind === "email" ? await publishEmailShareV3({
|
|
31418
|
+
...addressedOptions,
|
|
31419
|
+
target: prepared.target,
|
|
31420
|
+
credentialDescriptor: targetInput.credentialDescriptor,
|
|
31421
|
+
issuerDid: targetInput.issuerDid,
|
|
31422
|
+
issuerKid: targetInput.issuerKid
|
|
31423
|
+
}) : await publishAddressedShare(addressedOptions);
|
|
29652
31424
|
} catch (error) {
|
|
29653
31425
|
if (!(error instanceof AddressedShareOverLimitError)) throw error;
|
|
29654
31426
|
const remaining = await removeOverLimitShare({
|
|
@@ -29841,7 +31613,7 @@ init_profiles();
|
|
|
29841
31613
|
|
|
29842
31614
|
// src/share/html-folder.ts
|
|
29843
31615
|
import { constants as constants2, existsSync } from "fs";
|
|
29844
|
-
import { lstat as lstat7, open as
|
|
31616
|
+
import { lstat as lstat7, open as open10, readdir as readdir6, realpath as realpath3, stat as stat6 } from "fs/promises";
|
|
29845
31617
|
import { basename as basename3, dirname as dirname6, isAbsolute, join as join13, relative as relativePath, resolve as resolve5, sep as sep4 } from "path";
|
|
29846
31618
|
|
|
29847
31619
|
// ../share-sdk/dist/html-bundle.js
|
|
@@ -30196,9 +31968,9 @@ function scanMarkup(html, options) {
|
|
|
30196
31968
|
if (comments > MAX_ARTIFACT_COMMENTS) fail("limit", "artifact page has too many comments");
|
|
30197
31969
|
};
|
|
30198
31970
|
while (index < length5) {
|
|
30199
|
-
const
|
|
30200
|
-
if (
|
|
30201
|
-
index =
|
|
31971
|
+
const open11 = html.indexOf("<", index);
|
|
31972
|
+
if (open11 === -1) return;
|
|
31973
|
+
index = open11 + 1;
|
|
30202
31974
|
const next = html[index] ?? "";
|
|
30203
31975
|
if (html.startsWith("!--", index)) {
|
|
30204
31976
|
countComment();
|
|
@@ -30799,7 +32571,7 @@ async function readRegularFile(root, path, relative, remaining, limit, hooks = {
|
|
|
30799
32571
|
await hooks.beforeOpen?.();
|
|
30800
32572
|
before = await lstat7(path);
|
|
30801
32573
|
await hooks.afterLstat?.();
|
|
30802
|
-
handle = await
|
|
32574
|
+
handle = await open10(path, constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0) | (constants2.O_NONBLOCK ?? 0));
|
|
30803
32575
|
} catch (error) {
|
|
30804
32576
|
if (error.code === "ELOOP") return problem("symbolic link");
|
|
30805
32577
|
if (isRaceError(error)) return problem(CHANGED);
|
|
@@ -30858,7 +32630,7 @@ async function listFolderDirectory(root, absolute, relative, hooks = {}) {
|
|
|
30858
32630
|
if (before.isSymbolicLink()) return problem("symbolic link");
|
|
30859
32631
|
if (!before.isDirectory()) return problem(CHANGED);
|
|
30860
32632
|
await hooks.afterLstat?.();
|
|
30861
|
-
const handle = await
|
|
32633
|
+
const handle = await open10(absolute, constants2.O_RDONLY | (constants2.O_DIRECTORY ?? 0) | (constants2.O_NOFOLLOW ?? 0));
|
|
30862
32634
|
try {
|
|
30863
32635
|
await hooks.afterOpen?.();
|
|
30864
32636
|
const info = await handle.stat();
|
|
@@ -31150,12 +32922,7 @@ function shareCliError(error, operation = "publish") {
|
|
|
31150
32922
|
return new CLIError("UPLOAD_FAILED", "share source upload failed; nothing was shared", 4);
|
|
31151
32923
|
}
|
|
31152
32924
|
if (failure.kind === "decrypt-not-held") {
|
|
31153
|
-
return new CLIError(
|
|
31154
|
-
"PERMISSION_DENIED",
|
|
31155
|
-
"this sign-in can't create email-addressed shares: it has no permission to decrypt with the account's key. Nothing was shared.",
|
|
31156
|
-
5,
|
|
31157
|
-
{ hint: "Share it from https://share.tinycloud.xyz while signed in as the account owner, or ask the owner to share it. A link anyone can open works from this sign-in: --to anyone." }
|
|
31158
|
-
);
|
|
32925
|
+
return new CLIError("PERMISSION_DENIED", `Email shares need a paste sign-in: run ${CLI_NAME12} auth login --paste --manifest builtin:share-publishing`, 5);
|
|
31159
32926
|
}
|
|
31160
32927
|
if (failure.kind === "over-limit") {
|
|
31161
32928
|
return new CLIError("MAX_BYTES_EXCEEDED", ADDRESSED_SHARE_TOO_LARGE_MESSAGE, 7, { hint: `What stays behind: ${failure.remaining.join("; ")}.` });
|
|
@@ -31290,14 +33057,20 @@ function assertAggregateInputLimit(inputs, maxBytes) {
|
|
|
31290
33057
|
}
|
|
31291
33058
|
function registerShareCommand(program2) {
|
|
31292
33059
|
const share = program2.command("share").description("Publish and consume TinyCloud Share links");
|
|
31293
|
-
share.command("publish <files...>").description("Publish one or more bounded files as a Share, or a folder with an index.html as one self-contained page (anyone links only)").option("--name <filename>", "Filename for stdin input, or the published .html name of a folder").option("--to <target>", "Share target", "anyone").option("--notify", "Email an exact-email recipient, or a domain mailbox on node 1.17.3+").option("--notify-to <address>", "Mailbox to invite for --to domain:<name> --notify (node 1.17.3+)").option("--expires <duration>", "Share lifetime").option("--max-bytes <bytes>", "Bound input bytes").option("--media-type <type>", "Media type for a single input").option("--action <actions...>", "Addressed permission: read, list, or edit").option("--prefix", "Publish multiple inputs beneath one addressed prefix").option("--binary", "Allow non-UTF-8 bearer content").option("--artifact <id>", 'Publish as the next write-once version of an artifact ("new" starts one); the share is pinned to that version').addOption(new Option("--ongoing").hideHelp()).option("--note <text>", "Note stored with the artifact version").option("--json", "Print versioned redacted JSON").option("--full-link", "Print the full self-contained link instead of a short link (addressed shares)").option("--viewer-origin <origin>", "Canonical HTTPS viewer origin", SHARE_ORIGIN).action(async (files, options, command) => {
|
|
33060
|
+
share.command("publish <files...>").description("Publish one or more bounded files as a Share, or a folder with an index.html as one self-contained page (anyone links only)").option("--name <filename>", "Filename for stdin input, or the published .html name of a folder").option("--to <target>", "Share target", "anyone").option("--credential-descriptor <path>", "Email credential flow descriptor JSON").option("--issuer-did <did>", "Trusted email credential issuer DID").option("--issuer-kid <kid>", "Trusted email credential issuer key ID").option("--notify", "Email an exact-email recipient, or a domain mailbox on node 1.17.3+").option("--notify-to <address>", "Mailbox to invite for --to domain:<name> --notify (node 1.17.3+)").option("--expires <duration>", "Share lifetime").option("--max-bytes <bytes>", "Bound input bytes").option("--media-type <type>", "Media type for a single input").option("--action <actions...>", "Addressed permission: read, list, or edit").option("--prefix", "Publish multiple inputs beneath one addressed prefix").option("--binary", "Allow non-UTF-8 bearer content").option("--artifact <id>", 'Publish as the next write-once version of an artifact ("new" starts one); the share is pinned to that version').addOption(new Option("--ongoing").hideHelp()).option("--note <text>", "Note stored with the artifact version").option("--json", "Print versioned redacted JSON").option("--full-link", "Print the full self-contained link instead of a short link (addressed shares)").option("--viewer-origin <origin>", "Canonical HTTPS viewer origin", SHARE_ORIGIN).action(async (files, options, command) => {
|
|
31294
33061
|
try {
|
|
31295
33062
|
const json = jsonOutput(options, command);
|
|
31296
33063
|
if (options.ongoing === true) throw new CLIError("UNSUPPORTED_TARGET", ONGOING_UNAVAILABLE, 2);
|
|
33064
|
+
const target = parseShareTarget(options.to);
|
|
33065
|
+
if (target.kind === "email") throw new CLIError("UNAVAILABLE", "email-addressed shares are not available in this release; nothing was shared", 4);
|
|
31297
33066
|
const maxBytes = byteLimit(options.maxBytes);
|
|
31298
33067
|
if (files.length === 0 || files.includes("-") && files.length > 1) throw new CLIError("INVALID_ARGUMENT", "stdin must be the only publish input", 2);
|
|
31299
33068
|
const name = files.length === 1 ? options.name : void 0;
|
|
31300
|
-
const
|
|
33069
|
+
const actions = requestedActions(options.action);
|
|
33070
|
+
if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
|
|
33071
|
+
if (options.credentialDescriptor || options.issuerDid || options.issuerKid) {
|
|
33072
|
+
throw new CLIError("INVALID_ARGUMENT", "credential options require an exact email target", 2);
|
|
33073
|
+
}
|
|
31301
33074
|
const folder = files.length === 1 && target.kind === "bearer" && options.prefix !== true && await isDirectoryInput(files[0]);
|
|
31302
33075
|
let inputs;
|
|
31303
33076
|
if (folder) {
|
|
@@ -31314,19 +33087,16 @@ function registerShareCommand(program2) {
|
|
|
31314
33087
|
inputs = await Promise.all(files.map((file) => readShareInput(file, name, maxBytes)));
|
|
31315
33088
|
}
|
|
31316
33089
|
assertAggregateInputLimit(inputs, maxBytes);
|
|
31317
|
-
const actions = requestedActions(options.action);
|
|
31318
33090
|
if (options.prefix && target.kind === "bearer") throw new CLIError("INVALID_ARGUMENT", "--prefix requires an addressed target", 2);
|
|
31319
33091
|
if (target.kind === "bearer" && actions.includes("edit")) throw new CLIError("INVALID_ARGUMENT", `--action edit is not available with --to ${options.to}: a link can only be read; address a recipient to allow edits`, 2);
|
|
31320
33092
|
if (inputs.length > 1 && target.kind === "bearer") throw new CLIError("UNSUPPORTED_LINK", "multiple files require an addressed target", 2);
|
|
31321
33093
|
const artifact = artifactRequest(options, actions, inputs.length);
|
|
31322
33094
|
if (inputs.length > 1 && !options.prefix) throw new CLIError("INVALID_ARGUMENT", "multiple files require --prefix", 2);
|
|
31323
|
-
if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
|
|
31324
33095
|
if (options.notifyTo !== void 0 && (options.notify !== true || target.kind !== "emailDomain")) {
|
|
31325
33096
|
throw new CLIError("INVALID_ARGUMENT", "--notify-to requires --to domain:<name> --notify", 2);
|
|
31326
33097
|
}
|
|
31327
33098
|
let notifyRecipient;
|
|
31328
|
-
if (options.notify === true && target.kind === "
|
|
31329
|
-
else if (options.notify === true && target.kind === "emailDomain") {
|
|
33099
|
+
if (options.notify === true && target.kind === "emailDomain") {
|
|
31330
33100
|
const mailbox = options.notifyTo === void 0 ? void 0 : canonicalMailbox2(options.notifyTo);
|
|
31331
33101
|
if (mailbox === void 0 || mailbox.domain !== target.domain) {
|
|
31332
33102
|
throw new CLIError("INVALID_ARGUMENT", "--to domain:<name> --notify requires --notify-to <email> at that exact domain (node 1.17.3+)", 2);
|
|
@@ -31473,6 +33243,7 @@ function registerShareCommand(program2) {
|
|
|
31473
33243
|
process.exitCode = 6;
|
|
31474
33244
|
return;
|
|
31475
33245
|
}
|
|
33246
|
+
if (result.method === "email-claim") throw new CLIError("CLAIM_REQUIRED", "email-addressed shares cannot be opened with this version of the CLI yet; open the link in a web browser", 6);
|
|
31476
33247
|
throw new CLIError(result.method === "openkey-device" ? "DEVICE_AUTH_REQUIRED" : "CLAIM_REQUIRED", "recipient authorization is required; resume through the configured authority adapter", 6);
|
|
31477
33248
|
}
|
|
31478
33249
|
if (options.stdout) {
|
|
@@ -31659,7 +33430,8 @@ configureShareCommandServices({
|
|
|
31659
33430
|
revocation: shareAuthority.revocation,
|
|
31660
33431
|
nativeReader: shareAuthority.nativeReader,
|
|
31661
33432
|
artifactStore: shareAuthority.artifactStore,
|
|
31662
|
-
links: shareAuthority.links
|
|
33433
|
+
links: shareAuthority.links,
|
|
33434
|
+
shortLinkInvitations: true
|
|
31663
33435
|
});
|
|
31664
33436
|
var argv = process.argv.slice(2);
|
|
31665
33437
|
var globalLongOptionsWithValues = { "--profile": true, "--host": true };
|
|
@@ -31746,6 +33518,10 @@ if (argv[0] === "courier") {
|
|
|
31746
33518
|
@noble/curves/esm/abstract/curve.js:
|
|
31747
33519
|
@noble/curves/esm/abstract/edwards.js:
|
|
31748
33520
|
@noble/curves/esm/ed25519.js:
|
|
33521
|
+
@noble/curves/esm/abstract/weierstrass.js:
|
|
33522
|
+
@noble/curves/esm/_shortw_utils.js:
|
|
33523
|
+
@noble/curves/esm/nist.js:
|
|
33524
|
+
@noble/curves/esm/p256.js:
|
|
31749
33525
|
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
31750
33526
|
*/
|
|
31751
33527
|
//# sourceMappingURL=index.js.map
|