@tinycloud/cli 1.5.0-beta.3 → 1.5.0-beta.30
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 +315 -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 +1893 -101
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +5213 -2230
- 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 +21 -27
- package/skills/tinycloud-cli/INSTALL.md +36 -0
- package/skills/{tc-cli → tinycloud-cli}/REFERENCE.md +113 -97
- package/skills/{tc-cli → tinycloud-cli}/SDK.md +1 -1
- package/skills/{tc-cli → tinycloud-cli}/SKILL.md +32 -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 ──────────────────────────────────────────────────
|
|
@@ -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);
|
|
@@ -13419,7 +14738,7 @@ async function refusal(response) {
|
|
|
13419
14738
|
async function prepareLinkRecord(input) {
|
|
13420
14739
|
const apiOrigin = checkApiOrigin(input.apiOrigin);
|
|
13421
14740
|
const nowMs = toEpochMs(input.now);
|
|
13422
|
-
const expiresMs = input.expiresAt.getTime();
|
|
14741
|
+
const expiresMs = Math.floor(input.expiresAt.getTime() / 1e3) * 1e3;
|
|
13423
14742
|
if (!Number.isFinite(nowMs) || !Number.isFinite(expiresMs)) throw new LinkError("invalid_argument", "now and expiresAt must be valid dates");
|
|
13424
14743
|
let blob;
|
|
13425
14744
|
let key;
|
|
@@ -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})?$/;
|
|
@@ -13798,6 +15199,7 @@ init_profiles();
|
|
|
13798
15199
|
|
|
13799
15200
|
// src/commands/share.ts
|
|
13800
15201
|
import { Option } from "commander";
|
|
15202
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
13801
15203
|
import { CLI_NAME as CLI_NAME12 } from "@tinycloud/operations/cli-name";
|
|
13802
15204
|
|
|
13803
15205
|
// ../share-sdk/dist/artifact.js
|
|
@@ -18984,6 +20386,23 @@ var unifiedEncryptionNetworkSchema = external_exports.string().refine((value) =>
|
|
|
18984
20386
|
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
18985
20387
|
return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
|
|
18986
20388
|
}, { message: "expected canonical TinyCloud encryption network" });
|
|
20389
|
+
var unifiedEncryptionResourceSchema = external_exports.string().refine((value) => {
|
|
20390
|
+
const prefix = "urn:tinycloud:encryption:";
|
|
20391
|
+
if (!value.startsWith(prefix)) return false;
|
|
20392
|
+
const match = /^(did:.+):([^/:?#\s]+)(?:\/(.+))?$/.exec(value.slice(prefix.length));
|
|
20393
|
+
if (match === null) return false;
|
|
20394
|
+
const path = match[3];
|
|
20395
|
+
return path === void 0 || path.split("/").every(
|
|
20396
|
+
(segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment)
|
|
20397
|
+
);
|
|
20398
|
+
}, { message: "expected a canonical TinyCloud encryption resource" });
|
|
20399
|
+
var unifiedEncryptionKeyPathSchema = external_exports.string().regex(/^share\/[^/]+$/).refine(
|
|
20400
|
+
(value) => {
|
|
20401
|
+
const segment = value.slice("share/".length);
|
|
20402
|
+
return segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment);
|
|
20403
|
+
},
|
|
20404
|
+
{ message: "expected an exact share key path" }
|
|
20405
|
+
);
|
|
18987
20406
|
var unifiedKvCapabilitySchema = external_exports.object({
|
|
18988
20407
|
kind: external_exports.literal("kv"),
|
|
18989
20408
|
resource: unifiedResourceSchema,
|
|
@@ -18997,7 +20416,7 @@ var unifiedKvCapabilitySchema = external_exports.object({
|
|
|
18997
20416
|
}).strict();
|
|
18998
20417
|
var unifiedEncryptionCapabilitySchema = external_exports.object({
|
|
18999
20418
|
kind: external_exports.literal("encryption"),
|
|
19000
|
-
resource:
|
|
20419
|
+
resource: unifiedEncryptionResourceSchema,
|
|
19001
20420
|
action: external_exports.literal("tinycloud.encryption/decrypt")
|
|
19002
20421
|
}).strict();
|
|
19003
20422
|
var unifiedCapabilitySchema = external_exports.union([unifiedKvCapabilitySchema, unifiedEncryptionCapabilitySchema]);
|
|
@@ -19006,6 +20425,7 @@ var unifiedContentSourceSchema = external_exports.object({
|
|
|
19006
20425
|
kvResource: unifiedResourceSchema,
|
|
19007
20426
|
selector: external_exports.union([external_exports.literal("exact"), external_exports.literal("prefix")]),
|
|
19008
20427
|
encryptionNetwork: unifiedEncryptionNetworkSchema,
|
|
20428
|
+
encryptionKeyPath: unifiedEncryptionKeyPathSchema.optional(),
|
|
19009
20429
|
encryptedSymmetricKeyDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/),
|
|
19010
20430
|
keyVersion: external_exports.number().int().positive(),
|
|
19011
20431
|
mode: external_exports.union([external_exports.literal("mutable"), external_exports.literal("immutable")]),
|
|
@@ -19123,16 +20543,21 @@ function validateV3Invariants(value, ctx) {
|
|
|
19123
20543
|
if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
|
|
19124
20544
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
|
|
19125
20545
|
}
|
|
19126
|
-
|
|
20546
|
+
const encryptionKeyPath = value.contentSource.encryptionKeyPath;
|
|
20547
|
+
if (encryptionKeyPath !== void 0 && encryptionKeyPath !== `share/${value.contentSource.shareId}`) {
|
|
20548
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource", "encryptionKeyPath"], message: "share key path must name this share" });
|
|
20549
|
+
}
|
|
20550
|
+
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
20551
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
|
|
19128
20552
|
}
|
|
19129
20553
|
if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
|
|
19130
20554
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
|
|
19131
20555
|
}
|
|
19132
20556
|
const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
|
|
19133
|
-
const
|
|
20557
|
+
const expectedEncryptionResource = encryptionKeyPath === void 0 ? value.encryptionNetwork : `${value.encryptionNetwork}/${encryptionKeyPath}`;
|
|
20558
|
+
const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === expectedEncryptionResource && capability.action === "tinycloud.encryption/decrypt");
|
|
19134
20559
|
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
|
|
20560
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain the exact decrypt resource" });
|
|
19136
20561
|
}
|
|
19137
20562
|
}
|
|
19138
20563
|
var unsignedShareEnvelopeV3Schema = unsignedShareEnvelopeV3BaseSchema.superRefine(validateV3Invariants);
|
|
@@ -24635,6 +26060,23 @@ var unifiedEncryptionNetworkSchema2 = external_exports3.string().refine((value)
|
|
|
24635
26060
|
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
24636
26061
|
return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
|
|
24637
26062
|
}, { message: "expected canonical TinyCloud encryption network" });
|
|
26063
|
+
var unifiedEncryptionResourceSchema2 = external_exports3.string().refine((value) => {
|
|
26064
|
+
const prefix = "urn:tinycloud:encryption:";
|
|
26065
|
+
if (!value.startsWith(prefix)) return false;
|
|
26066
|
+
const match = /^(did:.+):([^/:?#\s]+)(?:\/(.+))?$/.exec(value.slice(prefix.length));
|
|
26067
|
+
if (match === null) return false;
|
|
26068
|
+
const path = match[3];
|
|
26069
|
+
return path === void 0 || path.split("/").every(
|
|
26070
|
+
(segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment)
|
|
26071
|
+
);
|
|
26072
|
+
}, { message: "expected a canonical TinyCloud encryption resource" });
|
|
26073
|
+
var unifiedEncryptionKeyPathSchema2 = external_exports3.string().regex(/^share\/[^/]+$/).refine(
|
|
26074
|
+
(value) => {
|
|
26075
|
+
const segment = value.slice("share/".length);
|
|
26076
|
+
return segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment);
|
|
26077
|
+
},
|
|
26078
|
+
{ message: "expected an exact share key path" }
|
|
26079
|
+
);
|
|
24638
26080
|
var unifiedKvCapabilitySchema2 = external_exports3.object({
|
|
24639
26081
|
kind: external_exports3.literal("kv"),
|
|
24640
26082
|
resource: unifiedResourceSchema2,
|
|
@@ -24648,7 +26090,7 @@ var unifiedKvCapabilitySchema2 = external_exports3.object({
|
|
|
24648
26090
|
}).strict();
|
|
24649
26091
|
var unifiedEncryptionCapabilitySchema2 = external_exports3.object({
|
|
24650
26092
|
kind: external_exports3.literal("encryption"),
|
|
24651
|
-
resource:
|
|
26093
|
+
resource: unifiedEncryptionResourceSchema2,
|
|
24652
26094
|
action: external_exports3.literal("tinycloud.encryption/decrypt")
|
|
24653
26095
|
}).strict();
|
|
24654
26096
|
var unifiedCapabilitySchema2 = external_exports3.union([unifiedKvCapabilitySchema2, unifiedEncryptionCapabilitySchema2]);
|
|
@@ -24657,6 +26099,7 @@ var unifiedContentSourceSchema2 = external_exports3.object({
|
|
|
24657
26099
|
kvResource: unifiedResourceSchema2,
|
|
24658
26100
|
selector: external_exports3.union([external_exports3.literal("exact"), external_exports3.literal("prefix")]),
|
|
24659
26101
|
encryptionNetwork: unifiedEncryptionNetworkSchema2,
|
|
26102
|
+
encryptionKeyPath: unifiedEncryptionKeyPathSchema2.optional(),
|
|
24660
26103
|
encryptedSymmetricKeyDigestHex: external_exports3.string().regex(/^[0-9a-f]{64}$/),
|
|
24661
26104
|
keyVersion: external_exports3.number().int().positive(),
|
|
24662
26105
|
mode: external_exports3.union([external_exports3.literal("mutable"), external_exports3.literal("immutable")]),
|
|
@@ -24774,16 +26217,21 @@ function validateV3Invariants2(value, ctx) {
|
|
|
24774
26217
|
if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
|
|
24775
26218
|
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
|
|
24776
26219
|
}
|
|
24777
|
-
|
|
26220
|
+
const encryptionKeyPath = value.contentSource.encryptionKeyPath;
|
|
26221
|
+
if (encryptionKeyPath !== void 0 && encryptionKeyPath !== `share/${value.contentSource.shareId}`) {
|
|
26222
|
+
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["contentSource", "encryptionKeyPath"], message: "share key path must name this share" });
|
|
26223
|
+
}
|
|
26224
|
+
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
26225
|
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
|
|
24779
26226
|
}
|
|
24780
26227
|
if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
|
|
24781
26228
|
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
|
|
24782
26229
|
}
|
|
24783
26230
|
const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
|
|
24784
|
-
const
|
|
26231
|
+
const expectedEncryptionResource = encryptionKeyPath === void 0 ? value.encryptionNetwork : `${value.encryptionNetwork}/${encryptionKeyPath}`;
|
|
26232
|
+
const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === expectedEncryptionResource && capability.action === "tinycloud.encryption/decrypt");
|
|
24785
26233
|
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
|
|
26234
|
+
ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain the exact decrypt resource" });
|
|
24787
26235
|
}
|
|
24788
26236
|
}
|
|
24789
26237
|
var unsignedShareEnvelopeV3Schema2 = unsignedShareEnvelopeV3BaseSchema2.superRefine(validateV3Invariants2);
|
|
@@ -24793,6 +26241,7 @@ var SEALED_BLOB_VERSION2 = 1;
|
|
|
24793
26241
|
var AAD3 = utf8Bytes3(ENVELOPE_AAD_LABEL3);
|
|
24794
26242
|
var KEY_LENGTH2 = 32;
|
|
24795
26243
|
var NONCE_LENGTH2 = 12;
|
|
26244
|
+
var TAG_LENGTH2 = 16;
|
|
24796
26245
|
var HEADER_LENGTH2 = 1;
|
|
24797
26246
|
function assertKey3(key32) {
|
|
24798
26247
|
if (key32.length !== KEY_LENGTH2) {
|
|
@@ -24820,6 +26269,17 @@ async function seal2(plaintextBytes, key32) {
|
|
|
24820
26269
|
blob.set(ciphertext, HEADER_LENGTH2 + nonce.length);
|
|
24821
26270
|
return { blob, cid: await computeCid2(blob) };
|
|
24822
26271
|
}
|
|
26272
|
+
async function open7(blob, key32) {
|
|
26273
|
+
if (blob.length < HEADER_LENGTH2 + NONCE_LENGTH2 + TAG_LENGTH2) {
|
|
26274
|
+
throw new TypeError(`sealed blob too short: ${blob.length} bytes`);
|
|
26275
|
+
}
|
|
26276
|
+
if (blob[0] !== SEALED_BLOB_VERSION2) {
|
|
26277
|
+
throw new TypeError(`unknown sealed blob version: ${blob[0]}`);
|
|
26278
|
+
}
|
|
26279
|
+
const nonce = blob.subarray(HEADER_LENGTH2, HEADER_LENGTH2 + NONCE_LENGTH2);
|
|
26280
|
+
const ciphertext = blob.subarray(HEADER_LENGTH2 + NONCE_LENGTH2);
|
|
26281
|
+
return decryptEnvelope2(nonce, ciphertext, key32);
|
|
26282
|
+
}
|
|
24823
26283
|
async function encryptEnvelope2(plaintextBytes, key32) {
|
|
24824
26284
|
const key = await importAesKey2(key32, "encrypt");
|
|
24825
26285
|
const nonce = globalThis.crypto.getRandomValues(new Uint8Array(NONCE_LENGTH2));
|
|
@@ -24832,6 +26292,19 @@ async function encryptEnvelope2(plaintextBytes, key32) {
|
|
|
24832
26292
|
);
|
|
24833
26293
|
return { nonce, ciphertext };
|
|
24834
26294
|
}
|
|
26295
|
+
async function decryptEnvelope2(nonce, ciphertext, key32) {
|
|
26296
|
+
if (nonce.length !== NONCE_LENGTH2) {
|
|
26297
|
+
throw new TypeError(`nonce must be ${NONCE_LENGTH2} bytes, got ${nonce.length}`);
|
|
26298
|
+
}
|
|
26299
|
+
const key = await importAesKey2(key32, "decrypt");
|
|
26300
|
+
return new Uint8Array(
|
|
26301
|
+
await globalThis.crypto.subtle.decrypt(
|
|
26302
|
+
{ name: "AES-GCM", iv: nonce, additionalData: AAD3 },
|
|
26303
|
+
key,
|
|
26304
|
+
ciphertext
|
|
26305
|
+
)
|
|
26306
|
+
);
|
|
26307
|
+
}
|
|
24835
26308
|
function isPlainRecord3(value) {
|
|
24836
26309
|
const proto = Object.getPrototypeOf(value);
|
|
24837
26310
|
return proto === Object.prototype || proto === null;
|
|
@@ -24946,6 +26419,7 @@ function equal(left, right) {
|
|
|
24946
26419
|
return left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
24947
26420
|
}
|
|
24948
26421
|
var ED25519_VERIFY_OPTS2 = { zip215: false };
|
|
26422
|
+
var ENVELOPE_V2_SIGNATURE_DOMAIN = "xyz.tinycloud.share/envelope/v2\0";
|
|
24949
26423
|
var ENVELOPE_V3_SIGNATURE_DOMAIN = "xyz.tinycloud.share/envelope/v3\0";
|
|
24950
26424
|
var POLICY_V1_SIGNATURE_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
|
|
24951
26425
|
var POLICY_V2_SIGNATURE_DOMAIN = "xyz.tinycloud.policy/policy/v2\0";
|
|
@@ -24953,6 +26427,14 @@ var CONTENT_SOURCE_V1_DOMAIN = "xyz.tinycloud.policy/ContentSource/v1\0";
|
|
|
24953
26427
|
var POLICY_CAPABILITY_V1_DOMAIN = "xyz.tinycloud.policy/PolicyCapability/v1\0";
|
|
24954
26428
|
var NATIVE_PROJECTION_V1_DOMAIN = "xyz.tinycloud.policy/NativeProjection/v1\0";
|
|
24955
26429
|
var ATTESTED_ENFORCER_V2_DOMAIN = "xyz.tinycloud.policy/AttestedEnforcerBinding/v2\0";
|
|
26430
|
+
function signingBytesV2(unsigned) {
|
|
26431
|
+
const domain = utf8Bytes3(ENVELOPE_V2_SIGNATURE_DOMAIN);
|
|
26432
|
+
const body = utf8Bytes3(canonicalize3(unsigned));
|
|
26433
|
+
const bytes3 = new Uint8Array(domain.length + body.length);
|
|
26434
|
+
bytes3.set(domain);
|
|
26435
|
+
bytes3.set(body, domain.length);
|
|
26436
|
+
return bytes3;
|
|
26437
|
+
}
|
|
24956
26438
|
function signingBytesV3(unsigned) {
|
|
24957
26439
|
const domain = utf8Bytes3(ENVELOPE_V3_SIGNATURE_DOMAIN);
|
|
24958
26440
|
const body = utf8Bytes3(canonicalize3(unsigned));
|
|
@@ -24961,6 +26443,17 @@ function signingBytesV3(unsigned) {
|
|
|
24961
26443
|
bytes3.set(body, domain.length);
|
|
24962
26444
|
return bytes3;
|
|
24963
26445
|
}
|
|
26446
|
+
function verifyEnvelopeV2SignatureOnly(envelope) {
|
|
26447
|
+
const parsed = shareEnvelopeV2Schema2.parse(envelope);
|
|
26448
|
+
const { signature, ...unsigned } = parsed;
|
|
26449
|
+
return ed25519.verify(fromBase64Url3(signature.value), signingBytesV2(unsigned), ed25519PublicKeyFromDidKey2(signature.signerDid), ED25519_VERIFY_OPTS2);
|
|
26450
|
+
}
|
|
26451
|
+
async function verifyEnvelopeV2(envelope, options) {
|
|
26452
|
+
const parsed = shareEnvelopeV2Schema2.parse(envelope);
|
|
26453
|
+
if (parsed.signature.signerDid !== options.expectedSignerDid || !verifyEnvelopeV2SignatureOnly(parsed)) return false;
|
|
26454
|
+
if (parsed.authorizationTarget.kind === "policy") return await computeCid2(fromBase64Url3(parsed.authorizationTarget.policyBytes)) === parsed.authorizationTarget.policyCid;
|
|
26455
|
+
return true;
|
|
26456
|
+
}
|
|
24964
26457
|
function verifyEnvelopeV3SignatureOnly(envelope) {
|
|
24965
26458
|
const parsed = shareEnvelopeV3Schema2.parse(envelope);
|
|
24966
26459
|
const { signature, ...unsigned } = parsed;
|
|
@@ -25047,6 +26540,52 @@ function base32Lower(bytes3) {
|
|
|
25047
26540
|
if (bits > 0) output += alphabet[buffer << 5 - bits & 31];
|
|
25048
26541
|
return output;
|
|
25049
26542
|
}
|
|
26543
|
+
var KEY_LENGTH22 = 32;
|
|
26544
|
+
function assertCanonicalCid(cidString) {
|
|
26545
|
+
const cid2 = CID3.parse(cidString);
|
|
26546
|
+
if (cid2.version !== 1 || cid2.code !== code3 || cid2.multihash.code !== 18 || // sha2-256 (0x12) only, at the link layer too
|
|
26547
|
+
cid2.toString() !== cidString) {
|
|
26548
|
+
throw new TypeError(`not a canonical CIDv1 raw sha2-256 base32 CID: ${cidString}`);
|
|
26549
|
+
}
|
|
26550
|
+
}
|
|
26551
|
+
function parseShareUrl(url, options = {}) {
|
|
26552
|
+
const parsed = new URL(url);
|
|
26553
|
+
if (parsed.protocol !== "https:") {
|
|
26554
|
+
throw new TypeError(`share URL must be https, got ${parsed.protocol}`);
|
|
26555
|
+
}
|
|
26556
|
+
if (parsed.username !== "" || parsed.password !== "") {
|
|
26557
|
+
throw new TypeError("share URL must not carry userinfo");
|
|
26558
|
+
}
|
|
26559
|
+
if (parsed.search !== "") {
|
|
26560
|
+
throw new TypeError("share URL must not have a query string");
|
|
26561
|
+
}
|
|
26562
|
+
if (options.expectedOrigin !== void 0) {
|
|
26563
|
+
if (!isCanonicalHttpsOrigin2(options.expectedOrigin)) {
|
|
26564
|
+
throw new TypeError(
|
|
26565
|
+
`expectedOrigin must be a canonical https origin, got ${options.expectedOrigin}`
|
|
26566
|
+
);
|
|
26567
|
+
}
|
|
26568
|
+
if (parsed.origin !== options.expectedOrigin) {
|
|
26569
|
+
throw new TypeError(
|
|
26570
|
+
`share URL origin ${parsed.origin} does not match expected ${options.expectedOrigin}`
|
|
26571
|
+
);
|
|
26572
|
+
}
|
|
26573
|
+
}
|
|
26574
|
+
const match = /^\/s\/([a-z2-7]+)$/.exec(parsed.pathname);
|
|
26575
|
+
if (!match || match[1] === void 0) {
|
|
26576
|
+
throw new TypeError(`not a share URL path: ${parsed.pathname}`);
|
|
26577
|
+
}
|
|
26578
|
+
const ciphertextCid = match[1];
|
|
26579
|
+
assertCanonicalCid(ciphertextCid);
|
|
26580
|
+
if (!parsed.hash.startsWith("#k=")) {
|
|
26581
|
+
throw new TypeError("share URL is missing the #k= key fragment");
|
|
26582
|
+
}
|
|
26583
|
+
const key32 = fromBase64Url3(parsed.hash.slice("#k=".length));
|
|
26584
|
+
if (key32.length !== KEY_LENGTH22) {
|
|
26585
|
+
throw new TypeError(`fragment key must be ${KEY_LENGTH22} bytes, got ${key32.length}`);
|
|
26586
|
+
}
|
|
26587
|
+
return { ciphertextCid, key32 };
|
|
26588
|
+
}
|
|
25050
26589
|
var ARTIFACT_ROOT2 = "artifacts";
|
|
25051
26590
|
function parseArtifactVersionPath2(path) {
|
|
25052
26591
|
const match = /^artifacts\/([a-z0-9][a-z0-9_-]{2,62})\/versions\/([1-9][0-9]{0,14})\/([^/]+)$/.exec(path);
|
|
@@ -25123,6 +26662,7 @@ function verifyArtifactShare(envelope, options) {
|
|
|
25123
26662
|
}
|
|
25124
26663
|
var SHARE_RESULT_VERSION = 1;
|
|
25125
26664
|
var DEFAULT_MAX_SEALED_BLOB_BYTES = 100 * 1024 * 1024 + 29;
|
|
26665
|
+
var DEFAULT_MAX_CONTENT_BLOB_BYTES = DEFAULT_MAX_SEALED_BLOB_BYTES;
|
|
25126
26666
|
var ShareReceiveError = class extends Error {
|
|
25127
26667
|
code;
|
|
25128
26668
|
details;
|
|
@@ -25136,13 +26676,13 @@ var ShareReceiveError = class extends Error {
|
|
|
25136
26676
|
return { protocol: "tinycloud-share", version: SHARE_RESULT_VERSION, error: { code: this.code } };
|
|
25137
26677
|
}
|
|
25138
26678
|
};
|
|
25139
|
-
function metadataFor(envelope,
|
|
25140
|
-
const kind = envelope.recipientMatcher.kind === "recipientDid" ? "recipientDid" : envelope.recipientMatcher.kind === "exactEmail" ? "email" : "emailDomain";
|
|
26679
|
+
function metadataFor(envelope, origin2) {
|
|
26680
|
+
const kind = envelope.recipientMatcher.kind === "recipientDid" ? "recipientDid" : envelope.recipientMatcher.kind === "exactEmail" ? "email" : envelope.recipientMatcher.kind === "emailDomain" ? "emailDomain" : "bearer";
|
|
25141
26681
|
return {
|
|
25142
26682
|
protocol: "tinycloud-share",
|
|
25143
26683
|
version: 1,
|
|
25144
26684
|
shareId: envelope.shareId,
|
|
25145
|
-
origin,
|
|
26685
|
+
origin: origin2,
|
|
25146
26686
|
target: { ...envelope.target, kind },
|
|
25147
26687
|
resource: { ...envelope.resource },
|
|
25148
26688
|
actions: [...envelope.actions],
|
|
@@ -25152,7 +26692,7 @@ function metadataFor(envelope, origin) {
|
|
|
25152
26692
|
...envelope.display.filename === void 0 ? {} : { filename: envelope.display.filename },
|
|
25153
26693
|
...envelope.display.mode === void 0 ? {} : { mode: envelope.display.mode }
|
|
25154
26694
|
},
|
|
25155
|
-
...envelope.
|
|
26695
|
+
...envelope.version === 3 && envelope.artifactPin !== void 0 ? { artifact: { id: envelope.artifactPin.artifactId, version: envelope.artifactPin.version } } : {}
|
|
25156
26696
|
};
|
|
25157
26697
|
}
|
|
25158
26698
|
function receiveErrorFor(error) {
|
|
@@ -25250,14 +26790,165 @@ async function resolvePolicyShare(link4, options) {
|
|
|
25250
26790
|
options.onResolvedAddressedEnvelope?.(envelope, cid2);
|
|
25251
26791
|
return { envelope, origin: url.origin, cid: cid2 };
|
|
25252
26792
|
}
|
|
26793
|
+
async function resolveLegacyV2(link4, options) {
|
|
26794
|
+
let parsed;
|
|
26795
|
+
try {
|
|
26796
|
+
parsed = parseShareUrl(link4, { ...options.expectedOrigin === void 0 ? {} : { expectedOrigin: options.expectedOrigin } });
|
|
26797
|
+
} catch {
|
|
26798
|
+
throw new ShareReceiveError("invalid-link", "legacy share link format is invalid");
|
|
26799
|
+
}
|
|
26800
|
+
try {
|
|
26801
|
+
options.signal?.throwIfAborted();
|
|
26802
|
+
const origin2 = new URL(link4).origin;
|
|
26803
|
+
const limit = options.maxSealedBlobBytes ?? DEFAULT_MAX_SEALED_BLOB_BYTES;
|
|
26804
|
+
if (!Number.isSafeInteger(limit) || limit <= 0) throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope limit is invalid");
|
|
26805
|
+
let sealed;
|
|
26806
|
+
if (options.fetchBlob !== void 0) {
|
|
26807
|
+
try {
|
|
26808
|
+
sealed = await options.fetchBlob({ origin: origin2, cid: parsed.ciphertextCid, ...options.signal === void 0 ? {} : { signal: options.signal } });
|
|
26809
|
+
} catch {
|
|
26810
|
+
throw new ShareReceiveError("fetch-failed", "legacy registry unavailable");
|
|
26811
|
+
}
|
|
26812
|
+
} else {
|
|
26813
|
+
if (options.registryBaseUrl === void 0) throw new ShareReceiveError("fetch-failed", "legacy registry is required");
|
|
26814
|
+
const response = await (options.fetch ?? globalThis.fetch)(`${options.registryBaseUrl.replace(/\/+$/, "")}/ipfs/${parsed.ciphertextCid}?format=raw`, {
|
|
26815
|
+
headers: { accept: "application/vnd.ipld.raw" },
|
|
26816
|
+
redirect: "error",
|
|
26817
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
26818
|
+
});
|
|
26819
|
+
if (!response.ok) throw new ShareReceiveError("fetch-failed", "legacy registry unavailable");
|
|
26820
|
+
if (Number(response.headers.get("content-length")) > limit) throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope exceeds the size limit");
|
|
26821
|
+
const reader = response.body?.getReader();
|
|
26822
|
+
if (reader === void 0) throw new ShareReceiveError("fetch-failed", "legacy registry returned no body");
|
|
26823
|
+
const chunks = [];
|
|
26824
|
+
let length32 = 0;
|
|
26825
|
+
for (; ; ) {
|
|
26826
|
+
const part = await reader.read();
|
|
26827
|
+
if (part.done) break;
|
|
26828
|
+
length32 += part.value.length;
|
|
26829
|
+
if (length32 > limit) {
|
|
26830
|
+
await reader.cancel();
|
|
26831
|
+
throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope exceeds the size limit");
|
|
26832
|
+
}
|
|
26833
|
+
chunks.push(part.value);
|
|
26834
|
+
}
|
|
26835
|
+
sealed = new Uint8Array(length32);
|
|
26836
|
+
let offset = 0;
|
|
26837
|
+
for (const chunk of chunks) {
|
|
26838
|
+
sealed.set(chunk, offset);
|
|
26839
|
+
offset += chunk.length;
|
|
26840
|
+
}
|
|
26841
|
+
}
|
|
26842
|
+
options.signal?.throwIfAborted();
|
|
26843
|
+
if (!(sealed instanceof Uint8Array) || sealed.length > limit) throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope exceeds the size limit");
|
|
26844
|
+
if (await computeCid2(sealed) !== parsed.ciphertextCid) throw new ShareReceiveError("cid-mismatch", "legacy envelope CID does not match");
|
|
26845
|
+
let plaintext;
|
|
26846
|
+
try {
|
|
26847
|
+
plaintext = await open7(sealed, parsed.key32);
|
|
26848
|
+
} catch {
|
|
26849
|
+
throw new ShareReceiveError("decrypt-failed", "legacy envelope could not be opened");
|
|
26850
|
+
}
|
|
26851
|
+
let envelope;
|
|
26852
|
+
try {
|
|
26853
|
+
const encoded = new TextDecoder("utf-8", { fatal: true }).decode(plaintext);
|
|
26854
|
+
const value = JSON.parse(encoded);
|
|
26855
|
+
if (canonicalize3(value) !== encoded) throw new Error("non-canonical envelope");
|
|
26856
|
+
envelope = shareEnvelopeV2Schema2.parse(value);
|
|
26857
|
+
} catch {
|
|
26858
|
+
throw new ShareReceiveError("envelope-invalid", "legacy envelope is invalid");
|
|
26859
|
+
}
|
|
26860
|
+
return { envelope, origin: origin2, cid: parsed.ciphertextCid };
|
|
26861
|
+
} finally {
|
|
26862
|
+
parsed.key32.fill(0);
|
|
26863
|
+
}
|
|
26864
|
+
}
|
|
26865
|
+
function evidenceMatchesV2(envelope, evidence) {
|
|
26866
|
+
const actions = new Set(evidence.actions.map((action) => action === "read" ? "tinycloud.kv/get" : action === "list" ? "tinycloud.kv/list" : action === "edit" ? "tinycloud.kv/put" : action));
|
|
26867
|
+
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}/`);
|
|
26868
|
+
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);
|
|
26869
|
+
}
|
|
26870
|
+
async function verifyLegacyV2(envelope, options) {
|
|
26871
|
+
try {
|
|
26872
|
+
if (!await verifyEnvelopeV2(envelope, { expectedSignerDid: envelope.signature.signerDid })) throw new Error("signature");
|
|
26873
|
+
} catch {
|
|
26874
|
+
throw new ShareReceiveError("signature-invalid", "legacy envelope signature is invalid");
|
|
26875
|
+
}
|
|
26876
|
+
const expiry = Date.parse(envelope.expiry);
|
|
26877
|
+
if (!Number.isFinite(expiry)) throw new ShareReceiveError("envelope-invalid", "legacy share expiry is invalid");
|
|
26878
|
+
if (expiry <= (options.now?.() ?? Date.now())) throw new ShareReceiveError("expired", "legacy share has expired", { expiresAt: envelope.expiry });
|
|
26879
|
+
if (envelope.authorizationTarget.kind === "policy") {
|
|
26880
|
+
if (options.trustedPolicyAuthority === void 0) throw new ShareReceiveError("envelope-invalid", "a legacy policy authority is required");
|
|
26881
|
+
let evidence;
|
|
26882
|
+
try {
|
|
26883
|
+
evidence = await options.trustedPolicyAuthority.resolve({ policyCid: envelope.authorizationTarget.policyCid, envelope });
|
|
26884
|
+
} catch {
|
|
26885
|
+
}
|
|
26886
|
+
if (evidence === void 0 || !evidenceMatchesV2(envelope, evidence)) throw new ShareReceiveError("capability-invalid", "legacy policy evidence does not match");
|
|
26887
|
+
if (options.trustedSignerDid !== void 0 && options.trustedSignerDid !== evidence.signerDid) throw new ShareReceiveError("signature-invalid", "legacy signer is not trusted");
|
|
26888
|
+
} 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) {
|
|
26889
|
+
throw new ShareReceiveError("capability-invalid", "legacy recipient authority does not match");
|
|
26890
|
+
}
|
|
26891
|
+
}
|
|
25253
26892
|
async function inspectShare(link4, options = {}) {
|
|
26893
|
+
if (isLegacyV2Link(link4)) {
|
|
26894
|
+
const legacy = await resolveLegacyV2(link4, options);
|
|
26895
|
+
await verifyLegacyV2(legacy.envelope, options);
|
|
26896
|
+
options.onResolvedAddressedEnvelope?.(legacy.envelope, legacy.cid);
|
|
26897
|
+
return { metadata: metadataFor(legacy.envelope, legacy.origin), link: { origin: legacy.origin, cid: legacy.cid, kind: "compact" } };
|
|
26898
|
+
}
|
|
25254
26899
|
const resolved = await resolvePolicyShare(link4, options);
|
|
25255
26900
|
return { metadata: metadataFor(resolved.envelope, resolved.origin), link: { origin: resolved.origin, cid: resolved.cid, kind: "policy" } };
|
|
25256
26901
|
}
|
|
25257
26902
|
async function receiveShare(link4, options = {}) {
|
|
26903
|
+
if (isLegacyV2Link(link4)) return receiveLegacyV2(link4, options);
|
|
25258
26904
|
const resolved = await resolvePolicyShare(link4, options);
|
|
25259
26905
|
return { state: "authorization-required", method: resolved.envelope.recipientMatcher.kind === "recipientDid" ? "openkey-device" : "email-claim" };
|
|
25260
26906
|
}
|
|
26907
|
+
function isLegacyV2Link(link4) {
|
|
26908
|
+
try {
|
|
26909
|
+
const url = new URL(link4);
|
|
26910
|
+
return /^\/s\/bafkrei[a-z2-7]{52}$/.test(url.pathname) && url.hash.startsWith("#k=");
|
|
26911
|
+
} catch {
|
|
26912
|
+
return false;
|
|
26913
|
+
}
|
|
26914
|
+
}
|
|
26915
|
+
async function receiveLegacyV2(link4, options) {
|
|
26916
|
+
const resolved = await resolveLegacyV2(link4, options);
|
|
26917
|
+
const { envelope } = resolved;
|
|
26918
|
+
await verifyLegacyV2(envelope, options);
|
|
26919
|
+
options.onResolvedAddressedEnvelope?.(envelope, resolved.cid);
|
|
26920
|
+
const method = envelope.recipientMatcher.kind === "recipientDid" ? "openkey-device" : "email-claim";
|
|
26921
|
+
if (options.authorization === void 0) return { state: "authorization-required", method };
|
|
26922
|
+
const result = options.authorizationResumeToken === void 0 ? await options.authorization.begin({ envelope, method }) : await options.authorization.resume({
|
|
26923
|
+
envelope,
|
|
26924
|
+
method,
|
|
26925
|
+
resumeToken: options.authorizationResumeToken,
|
|
26926
|
+
...options.authorizationProof === void 0 ? {} : { proof: options.authorizationProof }
|
|
26927
|
+
});
|
|
26928
|
+
if (result.state === "authorization-required") return result;
|
|
26929
|
+
if (result.state === "denied") throw new ShareReceiveError("authorization-denied", "legacy share authorization was denied");
|
|
26930
|
+
if (result.value === null || typeof result.value !== "object" || !(result.value.bytes instanceof Uint8Array) || result.value.proof === void 0 || options.authorization.verifyResult === void 0) {
|
|
26931
|
+
throw new ShareReceiveError("content-integrity-failed", "legacy content lacks a verifiable proof");
|
|
26932
|
+
}
|
|
26933
|
+
const authorized = result.value;
|
|
26934
|
+
try {
|
|
26935
|
+
if (!await options.authorization.verifyResult({ envelope, value: authorized, proof: authorized.proof })) throw new Error("proof");
|
|
26936
|
+
} catch {
|
|
26937
|
+
throw new ShareReceiveError("content-integrity-failed", "legacy content proof is invalid");
|
|
26938
|
+
}
|
|
26939
|
+
const bytes3 = authorized.bytes.slice();
|
|
26940
|
+
if (bytes3.length > (options.maxContentBlobBytes ?? DEFAULT_MAX_CONTENT_BLOB_BYTES)) throw new ShareReceiveError("max-bytes-exceeded", "legacy content exceeds the size limit");
|
|
26941
|
+
const bodyDigest = toBase64Url2(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes3)));
|
|
26942
|
+
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) {
|
|
26943
|
+
throw new ShareReceiveError("content-integrity-failed", "legacy content binding does not match");
|
|
26944
|
+
}
|
|
26945
|
+
let text;
|
|
26946
|
+
try {
|
|
26947
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes3);
|
|
26948
|
+
} catch {
|
|
26949
|
+
}
|
|
26950
|
+
return { metadata: metadataFor(envelope, resolved.origin), link: { origin: resolved.origin, cid: resolved.cid, kind: "compact" }, bytes: bytes3, ...text === void 0 ? {} : { text } };
|
|
26951
|
+
}
|
|
25261
26952
|
var SHARE_CONTENT_LIMIT = 100 * 1024 * 1024;
|
|
25262
26953
|
var SHARE_PUBLISH_RESULT_VERSION = 1;
|
|
25263
26954
|
var DEFAULT_SHARE_LIFETIME_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -25745,7 +27436,10 @@ async function publishTargetShare(input) {
|
|
|
25745
27436
|
expiresAt,
|
|
25746
27437
|
expiryWasExplicit: input.expiryWasExplicit ?? input.expiresAt !== void 0,
|
|
25747
27438
|
origin: input.origin,
|
|
25748
|
-
...input.notify === void 0 ? {} : { notify: input.notify }
|
|
27439
|
+
...input.notify === void 0 ? {} : { notify: input.notify },
|
|
27440
|
+
...input.credentialDescriptor === void 0 ? {} : { credentialDescriptor: input.credentialDescriptor },
|
|
27441
|
+
...input.issuerDid === void 0 ? {} : { issuerDid: input.issuerDid },
|
|
27442
|
+
...input.issuerKid === void 0 ? {} : { issuerKid: input.issuerKid }
|
|
25749
27443
|
});
|
|
25750
27444
|
}
|
|
25751
27445
|
var POLICY_V1_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
|
|
@@ -25831,7 +27525,7 @@ async function createPolicy(options, capabilities) {
|
|
|
25831
27525
|
function addressedPlan(options) {
|
|
25832
27526
|
const capabilities = sortCanonical([
|
|
25833
27527
|
{ kind: "kv", resource: options.contentSource.kvResource, selector: options.resource.kind, actions: [...options.policyActions] },
|
|
25834
|
-
{ kind: "encryption", resource: options.contentSource.encryptionNetwork
|
|
27528
|
+
{ kind: "encryption", resource: options.contentSource.encryptionKeyPath === void 0 ? options.contentSource.encryptionNetwork : `${options.contentSource.encryptionNetwork}/${options.contentSource.encryptionKeyPath}`, action: "tinycloud.encryption/decrypt" }
|
|
25835
27529
|
]);
|
|
25836
27530
|
return {
|
|
25837
27531
|
expiry: rfc3339Seconds(options.expiresAt),
|
|
@@ -26156,6 +27850,7 @@ async function addressedShareBodyUpperBound(input) {
|
|
|
26156
27850
|
kvResource: `${input.spaceId}/kv/${path}`,
|
|
26157
27851
|
selector: input.resource.kind,
|
|
26158
27852
|
encryptionNetwork: input.encryptionNetwork,
|
|
27853
|
+
...input.encryptionKeyPath === void 0 ? {} : { encryptionKeyPath: input.encryptionKeyPath },
|
|
26159
27854
|
encryptedSymmetricKeyDigestHex: "f".repeat(64),
|
|
26160
27855
|
keyVersion: Number.MAX_SAFE_INTEGER,
|
|
26161
27856
|
mode: "immutable",
|
|
@@ -26875,9 +28570,9 @@ async function validateReceipt(receipt, shareUrl) {
|
|
|
26875
28570
|
}
|
|
26876
28571
|
const links = await Promise.resolve().then(() => (init_links(), links_exports));
|
|
26877
28572
|
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 })) {
|
|
28573
|
+
const origin2 = new URL(shareUrl).origin;
|
|
28574
|
+
const parsed = links.parseLink(shareUrl, { trustedOrigins: [origin2] });
|
|
28575
|
+
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
28576
|
throw new Error("not a short share link");
|
|
26882
28577
|
}
|
|
26883
28578
|
} catch {
|
|
@@ -28200,6 +29895,23 @@ var unifiedEncryptionNetworkSchema3 = external_exports2.string().refine((value)
|
|
|
28200
29895
|
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
28201
29896
|
return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
|
|
28202
29897
|
}, { message: "expected canonical TinyCloud encryption network" });
|
|
29898
|
+
var unifiedEncryptionResourceSchema3 = external_exports2.string().refine((value) => {
|
|
29899
|
+
const prefix = "urn:tinycloud:encryption:";
|
|
29900
|
+
if (!value.startsWith(prefix)) return false;
|
|
29901
|
+
const match = /^(did:.+):([^/:?#\s]+)(?:\/(.+))?$/.exec(value.slice(prefix.length));
|
|
29902
|
+
if (match === null) return false;
|
|
29903
|
+
const path = match[3];
|
|
29904
|
+
return path === void 0 || path.split("/").every(
|
|
29905
|
+
(segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment)
|
|
29906
|
+
);
|
|
29907
|
+
}, { message: "expected a canonical TinyCloud encryption resource" });
|
|
29908
|
+
var unifiedEncryptionKeyPathSchema3 = external_exports2.string().regex(/^share\/[^/]+$/).refine(
|
|
29909
|
+
(value) => {
|
|
29910
|
+
const segment = value.slice("share/".length);
|
|
29911
|
+
return segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment);
|
|
29912
|
+
},
|
|
29913
|
+
{ message: "expected an exact share key path" }
|
|
29914
|
+
);
|
|
28203
29915
|
var unifiedKvCapabilitySchema3 = external_exports2.object({
|
|
28204
29916
|
kind: external_exports2.literal("kv"),
|
|
28205
29917
|
resource: unifiedResourceSchema3,
|
|
@@ -28213,7 +29925,7 @@ var unifiedKvCapabilitySchema3 = external_exports2.object({
|
|
|
28213
29925
|
}).strict();
|
|
28214
29926
|
var unifiedEncryptionCapabilitySchema3 = external_exports2.object({
|
|
28215
29927
|
kind: external_exports2.literal("encryption"),
|
|
28216
|
-
resource:
|
|
29928
|
+
resource: unifiedEncryptionResourceSchema3,
|
|
28217
29929
|
action: external_exports2.literal("tinycloud.encryption/decrypt")
|
|
28218
29930
|
}).strict();
|
|
28219
29931
|
var unifiedCapabilitySchema3 = external_exports2.union([unifiedKvCapabilitySchema3, unifiedEncryptionCapabilitySchema3]);
|
|
@@ -28222,6 +29934,7 @@ var unifiedContentSourceSchema3 = external_exports2.object({
|
|
|
28222
29934
|
kvResource: unifiedResourceSchema3,
|
|
28223
29935
|
selector: external_exports2.union([external_exports2.literal("exact"), external_exports2.literal("prefix")]),
|
|
28224
29936
|
encryptionNetwork: unifiedEncryptionNetworkSchema3,
|
|
29937
|
+
encryptionKeyPath: unifiedEncryptionKeyPathSchema3.optional(),
|
|
28225
29938
|
encryptedSymmetricKeyDigestHex: external_exports2.string().regex(/^[0-9a-f]{64}$/),
|
|
28226
29939
|
keyVersion: external_exports2.number().int().positive(),
|
|
28227
29940
|
mode: external_exports2.union([external_exports2.literal("mutable"), external_exports2.literal("immutable")]),
|
|
@@ -28339,16 +30052,21 @@ function validateV3Invariants3(value, ctx) {
|
|
|
28339
30052
|
if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
|
|
28340
30053
|
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
|
|
28341
30054
|
}
|
|
28342
|
-
|
|
30055
|
+
const encryptionKeyPath = value.contentSource.encryptionKeyPath;
|
|
30056
|
+
if (encryptionKeyPath !== void 0 && encryptionKeyPath !== `share/${value.contentSource.shareId}`) {
|
|
30057
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource", "encryptionKeyPath"], message: "share key path must name this share" });
|
|
30058
|
+
}
|
|
30059
|
+
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
30060
|
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
|
|
28344
30061
|
}
|
|
28345
30062
|
if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
|
|
28346
30063
|
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
|
|
28347
30064
|
}
|
|
28348
30065
|
const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
|
|
28349
|
-
const
|
|
30066
|
+
const expectedEncryptionResource = encryptionKeyPath === void 0 ? value.encryptionNetwork : `${value.encryptionNetwork}/${encryptionKeyPath}`;
|
|
30067
|
+
const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === expectedEncryptionResource && capability.action === "tinycloud.encryption/decrypt");
|
|
28350
30068
|
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
|
|
30069
|
+
ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain the exact decrypt resource" });
|
|
28352
30070
|
}
|
|
28353
30071
|
}
|
|
28354
30072
|
var unsignedShareEnvelopeV3Schema3 = unsignedShareEnvelopeV3BaseSchema3.superRefine(validateV3Invariants3);
|
|
@@ -28555,7 +30273,7 @@ function receiveJson(result, path) {
|
|
|
28555
30273
|
|
|
28556
30274
|
// src/share/io.ts
|
|
28557
30275
|
import { constants } from "fs";
|
|
28558
|
-
import { lstat as lstat6, mkdir as mkdir4, mkdtemp, open as
|
|
30276
|
+
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
30277
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
28560
30278
|
import { basename as basename2, join as join11, resolve as resolve4, sep as sep3 } from "path";
|
|
28561
30279
|
init_errors();
|
|
@@ -28631,7 +30349,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
|
|
|
28631
30349
|
const outputDirectory = resolve4(directory);
|
|
28632
30350
|
await assertDirectory(outputDirectory);
|
|
28633
30351
|
const safeName = safeFilename(filename);
|
|
28634
|
-
const directoryHandle = await
|
|
30352
|
+
const directoryHandle = await open8(outputDirectory, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0));
|
|
28635
30353
|
const stableDirectory = await realpath2(outputDirectory);
|
|
28636
30354
|
const outputPath = join11(stableDirectory, safeName);
|
|
28637
30355
|
const directoryIdentity = await directoryHandle.stat();
|
|
@@ -28655,7 +30373,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
|
|
|
28655
30373
|
if (error.code !== "ENOENT") throw error;
|
|
28656
30374
|
}
|
|
28657
30375
|
temporaryPath = stagingPath;
|
|
28658
|
-
handle = await
|
|
30376
|
+
handle = await open8(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 384);
|
|
28659
30377
|
await handle.writeFile(bytes);
|
|
28660
30378
|
await handle.close();
|
|
28661
30379
|
handle = void 0;
|
|
@@ -28677,7 +30395,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
|
|
|
28677
30395
|
if (temporaryPath !== void 0) await unlink4(temporaryPath);
|
|
28678
30396
|
} catch {
|
|
28679
30397
|
}
|
|
28680
|
-
await
|
|
30398
|
+
await rm6(stagingDirectory, { recursive: true, force: true });
|
|
28681
30399
|
await directoryHandle.close();
|
|
28682
30400
|
}
|
|
28683
30401
|
return join11(outputDirectory, safeName);
|
|
@@ -28764,17 +30482,30 @@ function createShareLinks(input) {
|
|
|
28764
30482
|
return {
|
|
28765
30483
|
async show(published, options) {
|
|
28766
30484
|
const material = published.deliveryMaterial;
|
|
28767
|
-
if (published.link.kind !== "policy"
|
|
30485
|
+
if (published.link.kind !== "policy") return { url: published.url, short: false };
|
|
28768
30486
|
if (options.fullLink) return { url: published.url, short: false };
|
|
28769
30487
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
28770
30488
|
const expiresAt = new Date(published.metadata.expiresAt);
|
|
28771
30489
|
const choice = linkFormForLifetime((expiresAt.getTime() - now.getTime()) / 1e3);
|
|
28772
30490
|
if (choice.form === "full") return { url: published.url, short: false, ...choice.warning ? { notice: LINK_EXPIRY_WARNING } : {} };
|
|
28773
30491
|
try {
|
|
30492
|
+
const issuerKey = await input.signer();
|
|
30493
|
+
let sealed;
|
|
30494
|
+
if (material !== void 0) {
|
|
30495
|
+
sealed = { blob: fromBase64Url4(material.sealedEnvelope), key: fromBase64Url4(material.envelopeKey) };
|
|
30496
|
+
} else {
|
|
30497
|
+
const parsed = parseLink(published.url, { trustedOrigins: [published.metadata.origin] });
|
|
30498
|
+
if (parsed.form !== "full") throw new LinkError("invalid_argument");
|
|
30499
|
+
const opened = await openLinkRecord(parsed.record, parsed.key, { now });
|
|
30500
|
+
if (opened.type !== "share" || opened.header.issuer !== issuerKey.did || opened.header.bodyCid !== published.link.cid || opened.header.expiresAt !== published.metadata.expiresAt) {
|
|
30501
|
+
throw new LinkError("invalid_argument");
|
|
30502
|
+
}
|
|
30503
|
+
sealed = { blob: opened.body, key: parsed.key };
|
|
30504
|
+
}
|
|
28774
30505
|
const created = await createLink({
|
|
28775
30506
|
type: "share",
|
|
28776
|
-
sealed
|
|
28777
|
-
issuerKey
|
|
30507
|
+
sealed,
|
|
30508
|
+
issuerKey,
|
|
28778
30509
|
apiOrigin,
|
|
28779
30510
|
linkOrigin: new URL(published.url).origin,
|
|
28780
30511
|
expiresAt,
|
|
@@ -28792,6 +30523,38 @@ function createShareLinks(input) {
|
|
|
28792
30523
|
};
|
|
28793
30524
|
}
|
|
28794
30525
|
|
|
30526
|
+
// src/share/email-publish-v3.ts
|
|
30527
|
+
import {
|
|
30528
|
+
canonicalDigest,
|
|
30529
|
+
createEmailCredentialRequirement,
|
|
30530
|
+
credentialRequirementDigest,
|
|
30531
|
+
validateCredentialFlowDescriptor
|
|
30532
|
+
} from "@tinycloud/sdk-core";
|
|
30533
|
+
async function publishEmailShareV3(input) {
|
|
30534
|
+
const { contentSource } = input;
|
|
30535
|
+
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)) {
|
|
30536
|
+
throw new TypeError("email share binding is invalid");
|
|
30537
|
+
}
|
|
30538
|
+
const descriptor = validateCredentialFlowDescriptor(input.credentialDescriptor);
|
|
30539
|
+
if (descriptor.issuer.did !== input.issuerDid || descriptor.issuer.kid !== input.issuerKid || !descriptor.claims.some((claim) => claim.name === "email" && claim.matching === "normalized_exact")) {
|
|
30540
|
+
throw new TypeError("email credential issuer or claim is invalid");
|
|
30541
|
+
}
|
|
30542
|
+
const profile = { id: descriptor.profile, version: 1 };
|
|
30543
|
+
const credentialType = { id: descriptor.format.vct, version: 1 };
|
|
30544
|
+
const requirement = createEmailCredentialRequirement({ email: input.target.address, profile, credentialType });
|
|
30545
|
+
const credentialRequirement = {
|
|
30546
|
+
type: "TinyCloudPolicyCredentialRequirement",
|
|
30547
|
+
version: 1,
|
|
30548
|
+
requirementDigest: await credentialRequirementDigest(requirement),
|
|
30549
|
+
descriptorDigest: await canonicalDigest(descriptor),
|
|
30550
|
+
issuerDid: input.issuerDid,
|
|
30551
|
+
issuerKid: input.issuerKid,
|
|
30552
|
+
profile,
|
|
30553
|
+
credentialType
|
|
30554
|
+
};
|
|
30555
|
+
return publishAddressedShare({ ...input, credentialRequirement });
|
|
30556
|
+
}
|
|
30557
|
+
|
|
28795
30558
|
// src/share/errors.ts
|
|
28796
30559
|
var SharePublishAuthorityError = class extends Error {
|
|
28797
30560
|
constructor(failure, options) {
|
|
@@ -28853,7 +30616,7 @@ init_profiles();
|
|
|
28853
30616
|
init_constants();
|
|
28854
30617
|
init_errors();
|
|
28855
30618
|
init_session_expired();
|
|
28856
|
-
import { chmod as chmod4, link as link3, open as
|
|
30619
|
+
import { chmod as chmod4, link as link3, open as open9, readFile as readFile7, stat as stat5, unlink as unlink5 } from "fs/promises";
|
|
28857
30620
|
import { dirname as dirname5, join as join12 } from "path";
|
|
28858
30621
|
import { createHash } from "crypto";
|
|
28859
30622
|
import { writeJsonAtomic as writeJsonAtomic2 } from "@tinycloud/operations/state";
|
|
@@ -29210,7 +30973,7 @@ function createEncryptedProfileHistory(profileName, sessionSigner) {
|
|
|
29210
30973
|
await link3(found.file, target);
|
|
29211
30974
|
await chmod4(target, PRIVATE_HISTORY_MODE);
|
|
29212
30975
|
await unlink5(found.file);
|
|
29213
|
-
const directory = await
|
|
30976
|
+
const directory = await open9(dirname5(found.file), "r");
|
|
29214
30977
|
try {
|
|
29215
30978
|
await directory.sync();
|
|
29216
30979
|
} finally {
|
|
@@ -29258,7 +31021,7 @@ function quarantineUnreadableProfileHistory(profileName) {
|
|
|
29258
31021
|
return createEncryptedProfileHistory(async () => profileName, signShareHistoryBytes).quarantineUnreadable();
|
|
29259
31022
|
}
|
|
29260
31023
|
function createShareAuthorityAdapters(input = {}) {
|
|
29261
|
-
const
|
|
31024
|
+
const origin2 = input.origin ?? DEFAULT_SHARE_ORIGIN;
|
|
29262
31025
|
const fetchFn = input.fetchFn ?? globalThis.fetch;
|
|
29263
31026
|
let selectedProfile;
|
|
29264
31027
|
const profileName = () => selectedProfile ??= input.profileName?.() ?? selectedProfileName();
|
|
@@ -29273,7 +31036,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29273
31036
|
const publicConfig = async () => configPromise ??= (async () => {
|
|
29274
31037
|
let response;
|
|
29275
31038
|
try {
|
|
29276
|
-
response = await fetchFn(`${
|
|
31039
|
+
response = await fetchFn(`${origin2}/.well-known/tinycloud-share/config.json`, {
|
|
29277
31040
|
headers: { accept: "application/json" },
|
|
29278
31041
|
credentials: "omit",
|
|
29279
31042
|
redirect: "error",
|
|
@@ -29281,9 +31044,9 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29281
31044
|
signal: AbortSignal.timeout(1e4)
|
|
29282
31045
|
});
|
|
29283
31046
|
} catch (error) {
|
|
29284
|
-
throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin }, { cause: error });
|
|
31047
|
+
throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin: origin2 }, { cause: error });
|
|
29285
31048
|
}
|
|
29286
|
-
if (!response.ok) throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin });
|
|
31049
|
+
if (!response.ok) throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin: origin2 });
|
|
29287
31050
|
const value = await response.json();
|
|
29288
31051
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("share public config is invalid");
|
|
29289
31052
|
const object3 = value;
|
|
@@ -29413,8 +31176,15 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29413
31176
|
profileName: activeProfileName2
|
|
29414
31177
|
});
|
|
29415
31178
|
}
|
|
29416
|
-
|
|
29417
|
-
|
|
31179
|
+
if (targetInput.target.kind === "email" && (targetInput.credentialDescriptor === void 0 || targetInput.issuerDid === void 0 || targetInput.issuerKid === void 0)) {
|
|
31180
|
+
throw new TypeError("email credential descriptor and issuer are required");
|
|
31181
|
+
}
|
|
31182
|
+
const addressedEncryptionNetwork = targetInput.target.kind === "bearer" ? void 0 : targetInput.target.kind === "email" ? node.getDefaultEncryptionNetworkId() : node.getEncryptionNetworkIdForSpace(ownerSpaceId);
|
|
31183
|
+
const emailKeyPath = targetInput.target.kind === "email" ? `share/${crypto.randomUUID().replaceAll("-", "")}` : void 0;
|
|
31184
|
+
if (addressedEncryptionNetwork !== void 0 && node.isSessionOnly && !sessionHoldsEncryptionDecrypt(
|
|
31185
|
+
node,
|
|
31186
|
+
emailKeyPath === void 0 ? addressedEncryptionNetwork : `${addressedEncryptionNetwork}/${emailKeyPath}`
|
|
31187
|
+
)) {
|
|
29418
31188
|
throw new SharePublishAuthorityError({ kind: "decrypt-not-held" });
|
|
29419
31189
|
}
|
|
29420
31190
|
const config = await publicConfig();
|
|
@@ -29423,7 +31193,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29423
31193
|
if (targetInput.notify === true && targetInput.target.kind === "emailDomain") {
|
|
29424
31194
|
await assertDomainDeliveryForOrigin(activeNode.origin, "publish");
|
|
29425
31195
|
}
|
|
29426
|
-
const shareId = crypto.randomUUID().replaceAll("-", "");
|
|
31196
|
+
const shareId = emailKeyPath?.slice("share/".length) ?? crypto.randomUUID().replaceAll("-", "");
|
|
29427
31197
|
const files = targetInput.files === void 0 || targetInput.files.length === 0 ? [{ bytes: targetInput.source, filename: targetInput.filename, mediaType: targetInput.mediaType }] : targetInput.files;
|
|
29428
31198
|
const resourceKind = targetInput.resourceKind ?? "exact";
|
|
29429
31199
|
if (targetInput.target.kind === "bearer") {
|
|
@@ -29545,6 +31315,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29545
31315
|
resource: { kind: resourceKind },
|
|
29546
31316
|
storage: artifact === void 0 ? { path: resourcePath } : { artifactId: artifact.id, storageName },
|
|
29547
31317
|
encryptionNetwork: addressedEncryptionNetwork,
|
|
31318
|
+
...emailKeyPath === void 0 ? {} : { encryptionKeyPath: emailKeyPath },
|
|
29548
31319
|
actions,
|
|
29549
31320
|
policyActions,
|
|
29550
31321
|
...deliveryEmail === void 0 ? {} : { deliveryEmail },
|
|
@@ -29560,8 +31331,14 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29560
31331
|
throw new SharePublishAuthorityError({ kind: rejected ? "registry-rejected" : "registry-unavailable" });
|
|
29561
31332
|
}
|
|
29562
31333
|
const encryptionNetwork = addressedEncryptionNetwork;
|
|
29563
|
-
const encrypted = await node.encryption.encryptToNetwork(encryptionNetwork, file.bytes, {
|
|
31334
|
+
const encrypted = await node.encryption.encryptToNetwork(encryptionNetwork, file.bytes, {
|
|
31335
|
+
...emailKeyPath === void 0 ? {} : { keyPath: emailKeyPath },
|
|
31336
|
+
metadata: { contentType: mediaType }
|
|
31337
|
+
});
|
|
29564
31338
|
if (!encrypted.ok) throw new Error("addressed source encryption was rejected");
|
|
31339
|
+
if (emailKeyPath !== void 0 && (encrypted.data.networkId !== encryptionNetwork || encrypted.data.keyPath !== emailKeyPath)) {
|
|
31340
|
+
throw new Error("email share encryption was rejected");
|
|
31341
|
+
}
|
|
29565
31342
|
const storedBytes = new TextEncoder().encode(canonicalize4(encrypted.data));
|
|
29566
31343
|
let artifactVersion;
|
|
29567
31344
|
if (artifact !== void 0) {
|
|
@@ -29594,6 +31371,7 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29594
31371
|
kvResource: `${ownerSpaceId}/kv/${resourcePath}`,
|
|
29595
31372
|
selector: resourceKind,
|
|
29596
31373
|
encryptionNetwork: encrypted.data.networkId,
|
|
31374
|
+
...emailKeyPath === void 0 ? {} : { encryptionKeyPath: emailKeyPath },
|
|
29597
31375
|
encryptedSymmetricKeyDigestHex: encrypted.data.encryptedSymmetricKeyHash,
|
|
29598
31376
|
keyVersion: encrypted.data.keyVersion,
|
|
29599
31377
|
mode: "immutable",
|
|
@@ -29635,7 +31413,13 @@ function createShareAuthorityAdapters(input = {}) {
|
|
|
29635
31413
|
};
|
|
29636
31414
|
let published;
|
|
29637
31415
|
try {
|
|
29638
|
-
published = await
|
|
31416
|
+
published = prepared.target.kind === "email" ? await publishEmailShareV3({
|
|
31417
|
+
...addressedOptions,
|
|
31418
|
+
target: prepared.target,
|
|
31419
|
+
credentialDescriptor: targetInput.credentialDescriptor,
|
|
31420
|
+
issuerDid: targetInput.issuerDid,
|
|
31421
|
+
issuerKid: targetInput.issuerKid
|
|
31422
|
+
}) : await publishAddressedShare(addressedOptions);
|
|
29639
31423
|
} catch (error) {
|
|
29640
31424
|
if (!(error instanceof AddressedShareOverLimitError)) throw error;
|
|
29641
31425
|
const remaining = await removeOverLimitShare({
|
|
@@ -29828,7 +31612,7 @@ init_profiles();
|
|
|
29828
31612
|
|
|
29829
31613
|
// src/share/html-folder.ts
|
|
29830
31614
|
import { constants as constants2, existsSync } from "fs";
|
|
29831
|
-
import { lstat as lstat7, open as
|
|
31615
|
+
import { lstat as lstat7, open as open10, readdir as readdir6, realpath as realpath3, stat as stat6 } from "fs/promises";
|
|
29832
31616
|
import { basename as basename3, dirname as dirname6, isAbsolute, join as join13, relative as relativePath, resolve as resolve5, sep as sep4 } from "path";
|
|
29833
31617
|
|
|
29834
31618
|
// ../share-sdk/dist/html-bundle.js
|
|
@@ -30183,9 +31967,9 @@ function scanMarkup(html, options) {
|
|
|
30183
31967
|
if (comments > MAX_ARTIFACT_COMMENTS) fail("limit", "artifact page has too many comments");
|
|
30184
31968
|
};
|
|
30185
31969
|
while (index < length5) {
|
|
30186
|
-
const
|
|
30187
|
-
if (
|
|
30188
|
-
index =
|
|
31970
|
+
const open11 = html.indexOf("<", index);
|
|
31971
|
+
if (open11 === -1) return;
|
|
31972
|
+
index = open11 + 1;
|
|
30189
31973
|
const next = html[index] ?? "";
|
|
30190
31974
|
if (html.startsWith("!--", index)) {
|
|
30191
31975
|
countComment();
|
|
@@ -30786,7 +32570,7 @@ async function readRegularFile(root, path, relative, remaining, limit, hooks = {
|
|
|
30786
32570
|
await hooks.beforeOpen?.();
|
|
30787
32571
|
before = await lstat7(path);
|
|
30788
32572
|
await hooks.afterLstat?.();
|
|
30789
|
-
handle = await
|
|
32573
|
+
handle = await open10(path, constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0) | (constants2.O_NONBLOCK ?? 0));
|
|
30790
32574
|
} catch (error) {
|
|
30791
32575
|
if (error.code === "ELOOP") return problem("symbolic link");
|
|
30792
32576
|
if (isRaceError(error)) return problem(CHANGED);
|
|
@@ -30845,7 +32629,7 @@ async function listFolderDirectory(root, absolute, relative, hooks = {}) {
|
|
|
30845
32629
|
if (before.isSymbolicLink()) return problem("symbolic link");
|
|
30846
32630
|
if (!before.isDirectory()) return problem(CHANGED);
|
|
30847
32631
|
await hooks.afterLstat?.();
|
|
30848
|
-
const handle = await
|
|
32632
|
+
const handle = await open10(absolute, constants2.O_RDONLY | (constants2.O_DIRECTORY ?? 0) | (constants2.O_NOFOLLOW ?? 0));
|
|
30849
32633
|
try {
|
|
30850
32634
|
await hooks.afterOpen?.();
|
|
30851
32635
|
const info = await handle.stat();
|
|
@@ -31137,12 +32921,7 @@ function shareCliError(error, operation = "publish") {
|
|
|
31137
32921
|
return new CLIError("UPLOAD_FAILED", "share source upload failed; nothing was shared", 4);
|
|
31138
32922
|
}
|
|
31139
32923
|
if (failure.kind === "decrypt-not-held") {
|
|
31140
|
-
return new CLIError(
|
|
31141
|
-
"PERMISSION_DENIED",
|
|
31142
|
-
"this sign-in can't create email-addressed shares: it has no permission to decrypt with the account's key. Nothing was shared.",
|
|
31143
|
-
5,
|
|
31144
|
-
{ 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." }
|
|
31145
|
-
);
|
|
32924
|
+
return new CLIError("PERMISSION_DENIED", `Email shares need a paste sign-in: run ${CLI_NAME12} auth login --paste --manifest builtin:share-publishing`, 5);
|
|
31146
32925
|
}
|
|
31147
32926
|
if (failure.kind === "over-limit") {
|
|
31148
32927
|
return new CLIError("MAX_BYTES_EXCEEDED", ADDRESSED_SHARE_TOO_LARGE_MESSAGE, 7, { hint: `What stays behind: ${failure.remaining.join("; ")}.` });
|
|
@@ -31277,7 +33056,7 @@ function assertAggregateInputLimit(inputs, maxBytes) {
|
|
|
31277
33056
|
}
|
|
31278
33057
|
function registerShareCommand(program2) {
|
|
31279
33058
|
const share = program2.command("share").description("Publish and consume TinyCloud Share links");
|
|
31280
|
-
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) => {
|
|
33059
|
+
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) => {
|
|
31281
33060
|
try {
|
|
31282
33061
|
const json = jsonOutput(options, command);
|
|
31283
33062
|
if (options.ongoing === true) throw new CLIError("UNSUPPORTED_TARGET", ONGOING_UNAVAILABLE, 2);
|
|
@@ -31285,6 +33064,15 @@ function registerShareCommand(program2) {
|
|
|
31285
33064
|
if (files.length === 0 || files.includes("-") && files.length > 1) throw new CLIError("INVALID_ARGUMENT", "stdin must be the only publish input", 2);
|
|
31286
33065
|
const name = files.length === 1 ? options.name : void 0;
|
|
31287
33066
|
const target = parseShareTarget(options.to);
|
|
33067
|
+
const actions = requestedActions(options.action);
|
|
33068
|
+
if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
|
|
33069
|
+
if (target.kind === "email" && (!options.credentialDescriptor || !options.issuerDid || !options.issuerKid)) {
|
|
33070
|
+
throw new CLIError("INVALID_ARGUMENT", "email publication requires --credential-descriptor, --issuer-did, and --issuer-kid", 2);
|
|
33071
|
+
}
|
|
33072
|
+
if (target.kind !== "email" && (options.credentialDescriptor || options.issuerDid || options.issuerKid)) {
|
|
33073
|
+
throw new CLIError("INVALID_ARGUMENT", "credential options require an exact email target", 2);
|
|
33074
|
+
}
|
|
33075
|
+
const credentialDescriptor = target.kind === "email" ? JSON.parse(await readFile8(options.credentialDescriptor, "utf8")) : void 0;
|
|
31288
33076
|
const folder = files.length === 1 && target.kind === "bearer" && options.prefix !== true && await isDirectoryInput(files[0]);
|
|
31289
33077
|
let inputs;
|
|
31290
33078
|
if (folder) {
|
|
@@ -31301,13 +33089,11 @@ function registerShareCommand(program2) {
|
|
|
31301
33089
|
inputs = await Promise.all(files.map((file) => readShareInput(file, name, maxBytes)));
|
|
31302
33090
|
}
|
|
31303
33091
|
assertAggregateInputLimit(inputs, maxBytes);
|
|
31304
|
-
const actions = requestedActions(options.action);
|
|
31305
33092
|
if (options.prefix && target.kind === "bearer") throw new CLIError("INVALID_ARGUMENT", "--prefix requires an addressed target", 2);
|
|
31306
33093
|
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);
|
|
31307
33094
|
if (inputs.length > 1 && target.kind === "bearer") throw new CLIError("UNSUPPORTED_LINK", "multiple files require an addressed target", 2);
|
|
31308
33095
|
const artifact = artifactRequest(options, actions, inputs.length);
|
|
31309
33096
|
if (inputs.length > 1 && !options.prefix) throw new CLIError("INVALID_ARGUMENT", "multiple files require --prefix", 2);
|
|
31310
|
-
if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
|
|
31311
33097
|
if (options.notifyTo !== void 0 && (options.notify !== true || target.kind !== "emailDomain")) {
|
|
31312
33098
|
throw new CLIError("INVALID_ARGUMENT", "--notify-to requires --to domain:<name> --notify", 2);
|
|
31313
33099
|
}
|
|
@@ -31337,6 +33123,7 @@ function registerShareCommand(program2) {
|
|
|
31337
33123
|
origin: options.viewerOrigin,
|
|
31338
33124
|
...maxBytes === void 0 ? {} : { maxBytes },
|
|
31339
33125
|
notify: options.notify === true,
|
|
33126
|
+
...credentialDescriptor === void 0 ? {} : { credentialDescriptor, issuerDid: options.issuerDid, issuerKid: options.issuerKid },
|
|
31340
33127
|
// The artifact request rides on the adapter call rather than through `publishTargetShare`, whose code is part of
|
|
31341
33128
|
// the browser bundles (the web-sdk size ceiling counts every byte it carries).
|
|
31342
33129
|
targetAdapter: artifact === void 0 || shareServices.targetAdapter === void 0 ? shareServices.targetAdapter : { publish: (request) => shareServices.targetAdapter.publish({ ...request, artifact }) }
|
|
@@ -31646,7 +33433,8 @@ configureShareCommandServices({
|
|
|
31646
33433
|
revocation: shareAuthority.revocation,
|
|
31647
33434
|
nativeReader: shareAuthority.nativeReader,
|
|
31648
33435
|
artifactStore: shareAuthority.artifactStore,
|
|
31649
|
-
links: shareAuthority.links
|
|
33436
|
+
links: shareAuthority.links,
|
|
33437
|
+
shortLinkInvitations: true
|
|
31650
33438
|
});
|
|
31651
33439
|
var argv = process.argv.slice(2);
|
|
31652
33440
|
var globalLongOptionsWithValues = { "--profile": true, "--host": true };
|
|
@@ -31733,6 +33521,10 @@ if (argv[0] === "courier") {
|
|
|
31733
33521
|
@noble/curves/esm/abstract/curve.js:
|
|
31734
33522
|
@noble/curves/esm/abstract/edwards.js:
|
|
31735
33523
|
@noble/curves/esm/ed25519.js:
|
|
33524
|
+
@noble/curves/esm/abstract/weierstrass.js:
|
|
33525
|
+
@noble/curves/esm/_shortw_utils.js:
|
|
33526
|
+
@noble/curves/esm/nist.js:
|
|
33527
|
+
@noble/curves/esm/p256.js:
|
|
31736
33528
|
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
31737
33529
|
*/
|
|
31738
33530
|
//# sourceMappingURL=index.js.map
|