@elisym/sdk 0.25.3 → 0.25.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +29 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +29 -5
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +47 -28
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +6 -0
- package/dist/node.d.ts +6 -0
- package/dist/node.js +47 -28
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1287,18 +1287,38 @@ var BlossomService = class {
|
|
|
1287
1287
|
}
|
|
1288
1288
|
}
|
|
1289
1289
|
/**
|
|
1290
|
-
* Download a
|
|
1291
|
-
* the declared Content-Length) and verifies the sha256 when
|
|
1290
|
+
* Download a content-addressed blob from THIS Blossom server (BUD-01 GET, no auth). Bounds memory
|
|
1291
|
+
* on the ACTUAL streamed bytes (never the declared Content-Length) and verifies the sha256 when
|
|
1292
|
+
* `expectedSha256` is given. Browser-safe.
|
|
1293
|
+
*
|
|
1294
|
+
* SSRF guard: `url` typically arrives inside a remote counterparty's encrypted job envelope, so it
|
|
1295
|
+
* is untrusted. elisym blobs are content-addressed on the single configured server (`seedBytes`
|
|
1296
|
+
* refuses non-content-addressed fallbacks), so a legitimate URL is always `<serverUrl>/<sha256>`.
|
|
1297
|
+
* The origin is pinned to `serverUrl` and redirects are refused, so a crafted url (or a 30x from
|
|
1298
|
+
* the host) can't coerce a fetch to loopback, cloud-metadata, or internal addresses. Federation
|
|
1299
|
+
* across Blossom servers would replace this single-origin pin with an explicit allowlist.
|
|
1292
1300
|
*/
|
|
1293
1301
|
async download(url, opts = {}) {
|
|
1302
|
+
if (new URL(url).origin !== new URL(this.serverUrl).origin) {
|
|
1303
|
+
throw new Error(`Refusing to download from a non-Blossom origin: ${url}`);
|
|
1304
|
+
}
|
|
1294
1305
|
const maxBytes = opts.maxBytes ?? LIMITS.MAX_FILE_SIZE;
|
|
1295
1306
|
const controller = new AbortController();
|
|
1296
1307
|
const timer = setTimeout(
|
|
1297
1308
|
() => controller.abort(),
|
|
1298
1309
|
opts.timeoutMs ?? DEFAULTS.BLOSSOM_FETCH_TIMEOUT_MS
|
|
1299
1310
|
);
|
|
1311
|
+
const externalSignal = opts.signal;
|
|
1312
|
+
const onExternalAbort = () => controller.abort();
|
|
1313
|
+
if (externalSignal !== void 0) {
|
|
1314
|
+
if (externalSignal.aborted) {
|
|
1315
|
+
controller.abort();
|
|
1316
|
+
} else {
|
|
1317
|
+
externalSignal.addEventListener("abort", onExternalAbort, { once: true });
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1300
1320
|
try {
|
|
1301
|
-
const res = await fetch(url, { signal: controller.signal });
|
|
1321
|
+
const res = await fetch(url, { signal: controller.signal, redirect: "error" });
|
|
1302
1322
|
if (!res.ok) {
|
|
1303
1323
|
throw new Error(`Download failed: ${res.status} ${res.statusText}`);
|
|
1304
1324
|
}
|
|
@@ -1340,6 +1360,9 @@ var BlossomService = class {
|
|
|
1340
1360
|
return bytes;
|
|
1341
1361
|
} finally {
|
|
1342
1362
|
clearTimeout(timer);
|
|
1363
|
+
if (externalSignal !== void 0) {
|
|
1364
|
+
externalSignal.removeEventListener("abort", onExternalAbort);
|
|
1365
|
+
}
|
|
1343
1366
|
}
|
|
1344
1367
|
}
|
|
1345
1368
|
async uploadToBlossom(identity, bytes, hashHex, mime) {
|
|
@@ -3737,11 +3760,12 @@ function createBlossomTransport(opts) {
|
|
|
3737
3760
|
enc: { alg: "AES-256-GCM", iv, key: wrappedKey }
|
|
3738
3761
|
};
|
|
3739
3762
|
},
|
|
3740
|
-
async fetchToBytes({ transport, senderPubkey, maxBytes }) {
|
|
3763
|
+
async fetchToBytes({ transport, senderPubkey, maxBytes, signal }) {
|
|
3741
3764
|
const plaintextCap = maxBytes ?? LIMITS.MAX_BLOSSOM_ENCRYPTED_BYTES;
|
|
3742
3765
|
const ciphertext = await blossom.download(transport.url, {
|
|
3743
3766
|
maxBytes: plaintextCap + AES_GCM_TAG_BYTES,
|
|
3744
|
-
expectedSha256: transport.sha256
|
|
3767
|
+
expectedSha256: transport.sha256,
|
|
3768
|
+
signal
|
|
3745
3769
|
});
|
|
3746
3770
|
return decryptBytesFromSender(
|
|
3747
3771
|
ciphertext,
|