@dstorage-tech/dstorage-sdk 0.0.6 → 0.0.8
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/KeypairEncryptionAdapter-EOBRCIGP-5PFPNLLA.mjs +8 -0
- package/dist/{KeypairEncryptionAdapter-XUKCLRFU-AYDAZ2TZ.mjs → KeypairEncryptionAdapter-EOBRCIGP-FLPJIL26.mjs} +3 -3
- package/dist/{MnemonicEncryptionAdapter-RCHUETBP-M7NHGSHO.mjs → MnemonicEncryptionAdapter-S56YG63Q-B3F3TO3T.mjs} +3 -3
- package/dist/MnemonicEncryptionAdapter-S56YG63Q-POTD74UN.mjs +8 -0
- package/dist/{PasswordEncryptionAdapter-ECHND672-MUTHAMZY.mjs → PasswordEncryptionAdapter-B2UG7MWB-M4C3KJ4S.mjs} +3 -3
- package/dist/{PasswordEncryptionAdapter-ECHND672-3DEFO6FP.mjs → PasswordEncryptionAdapter-B2UG7MWB-QCSOIQJA.mjs} +3 -3
- package/dist/browser.d.mts +91 -8
- package/dist/browser.mjs +171 -67
- package/dist/{chunk-HDD6SUU4.mjs → chunk-42O7KEL4.mjs} +30 -11
- package/dist/{chunk-X4LEBNK6.mjs → chunk-5F3HZ2RJ.mjs} +30 -11
- package/dist/{chunk-6IAQVMSM.mjs → chunk-E73HFT6J.mjs} +5 -5
- package/dist/{chunk-UDYXMII2.mjs → chunk-EOPUNIUH.mjs} +5 -5
- package/dist/{chunk-O37NHERH.mjs → chunk-L6WCT64V.mjs} +4 -2
- package/dist/{chunk-4X5K43JF.mjs → chunk-M3F2LR3B.mjs} +3 -1
- package/dist/{chunk-JMPRZK5D.mjs → chunk-O6COTUD4.mjs} +3 -1
- package/dist/{chunk-BWLEAAFW.mjs → chunk-PCXBQRCO.mjs} +55 -2056
- package/dist/{chunk-OLGVVM5Y.mjs → chunk-QFJ2Y4XE.mjs} +5 -5
- package/dist/{chunk-Z6DUAI5B.mjs → chunk-XW4RZG2X.mjs} +5 -5
- package/dist/{contract-api-TJ7JPHZA-6FUBJ6DS.mjs → contract-api-NUY4UEKE-ZANT3ICG.mjs} +3 -3
- package/dist/{contract-api-AO4RGPLT-ENC72WCG.mjs → contract-api-P6YEDYQ6-2X6BMD64.mjs} +3 -3
- package/dist/{dist-INTAFXQ7.mjs → dist-AGNOIJI4.mjs} +3 -1
- package/dist/{dist-MOLWJ4Y7.mjs → dist-J4JUJ2J5.mjs} +3 -1
- package/dist/errors.d.mts +2 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +10 -2054
- package/dist/errors.mjs +10 -2054
- package/dist/index.d.mts +108 -8
- package/dist/index.d.ts +108 -8
- package/dist/index.js +306 -2187
- package/dist/index.mjs +174 -70
- package/package.json +3 -2
- package/dist/KeypairEncryptionAdapter-XUKCLRFU-ERPYK5S4.mjs +0 -8
- package/dist/MnemonicEncryptionAdapter-RCHUETBP-DZPBGQG6.mjs +0 -8
package/dist/browser.mjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ChainErrorCode
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-O6COTUD4.mjs";
|
|
4
4
|
import {
|
|
5
5
|
MnemonicEncryptionAdapter
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-E73HFT6J.mjs";
|
|
7
7
|
import {
|
|
8
8
|
KDF_PRESETS,
|
|
9
9
|
PasswordEncryptionAdapter,
|
|
10
10
|
generatePqsPassword
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-42O7KEL4.mjs";
|
|
12
12
|
import {
|
|
13
13
|
KeypairEncryptionAdapter
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XW4RZG2X.mjs";
|
|
15
15
|
import {
|
|
16
16
|
EncryptionErrorCode
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-L6WCT64V.mjs";
|
|
18
18
|
import {
|
|
19
19
|
CryptoErrorCode,
|
|
20
20
|
DStorageError,
|
|
@@ -42,11 +42,12 @@ import {
|
|
|
42
42
|
mlkemUnwrapDek,
|
|
43
43
|
mlkemWrapDek,
|
|
44
44
|
parseKeyEnvelope,
|
|
45
|
+
readResponseTextWithLimit,
|
|
45
46
|
serializeKeyEnvelope,
|
|
46
47
|
serializeXChaChaPayload,
|
|
47
48
|
unwrapKey,
|
|
48
49
|
wrapKey
|
|
49
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-PCXBQRCO.mjs";
|
|
50
51
|
import "./chunk-5QOKJEH3.mjs";
|
|
51
52
|
|
|
52
53
|
// src/types.ts
|
|
@@ -93,6 +94,7 @@ var CoreErrorCode = {
|
|
|
93
94
|
STORAGE_ADAPTER_MISMATCH: 10052,
|
|
94
95
|
RETRIEVE_BY_REF_ID_ENVELOPE_EMPTY: 10053,
|
|
95
96
|
CONTENT_HASH_MISMATCH: 10054,
|
|
97
|
+
METADATA_PARSE_FAILED: 10055,
|
|
96
98
|
// listReferences — 10060-10069
|
|
97
99
|
LIST_REFS_REQUIRES_CHAIN: 10060,
|
|
98
100
|
LIST_REFS_NOT_SUPPORTED: 10061,
|
|
@@ -106,6 +108,7 @@ var CoreErrorCode = {
|
|
|
106
108
|
DECRYPT_CHUNK_FAILED: 10093,
|
|
107
109
|
CHUNK_OVERFLOWS_TOTAL_SIZE: 10094,
|
|
108
110
|
REASSEMBLY_SIZE_MISMATCH: 10095,
|
|
111
|
+
MANIFEST_PARSE_FAILED: 10096,
|
|
109
112
|
// init state — 10100-10109
|
|
110
113
|
NOT_INITIALIZED: 10100,
|
|
111
114
|
// generic catch-all — 10999
|
|
@@ -128,7 +131,7 @@ function isStorePartialError(err) {
|
|
|
128
131
|
// package.json
|
|
129
132
|
var package_default = {
|
|
130
133
|
name: "@dstorage-tech/dstorage-sdk",
|
|
131
|
-
version: "0.0.
|
|
134
|
+
version: "0.0.8",
|
|
132
135
|
description: "Privacy-first decentralized storage SDK with pluggable adapters",
|
|
133
136
|
license: "MIT",
|
|
134
137
|
homepage: "https://dstorage.pro",
|
|
@@ -204,10 +207,11 @@ var package_default = {
|
|
|
204
207
|
"@midnight-ntwrk/midnight-js-protocol": "4.1.1",
|
|
205
208
|
"@midnight-ntwrk/midnight-js-types": "4.1.1",
|
|
206
209
|
"@midnight-ntwrk/midnight-js-utils": "4.1.1",
|
|
207
|
-
"@midnight-ntwrk/wallet-sdk": "1.
|
|
210
|
+
"@midnight-ntwrk/wallet-sdk": "1.2.0",
|
|
208
211
|
"@noble/ciphers": "^2.2.0",
|
|
209
212
|
"@noble/hashes": "^1.5.0",
|
|
210
213
|
"@noble/post-quantum": "^0.6.1",
|
|
214
|
+
"@scure/bip39": "^2.0.1",
|
|
211
215
|
arweave: "^1.15.7"
|
|
212
216
|
},
|
|
213
217
|
devDependencies: {
|
|
@@ -282,6 +286,9 @@ var DStorage = class {
|
|
|
282
286
|
}
|
|
283
287
|
/** Tear down active state and clear all in-memory key material. */
|
|
284
288
|
destroy() {
|
|
289
|
+
for (const provider of this._encryptionProviders) {
|
|
290
|
+
provider.destroy?.();
|
|
291
|
+
}
|
|
285
292
|
this.wallet = null;
|
|
286
293
|
this._encryptionProviders = [];
|
|
287
294
|
this._initialized = false;
|
|
@@ -381,20 +388,24 @@ var DStorage = class {
|
|
|
381
388
|
);
|
|
382
389
|
}
|
|
383
390
|
const ownerSeed = generateDek();
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
391
|
+
try {
|
|
392
|
+
const ownerSeedWrappers = await Promise.all(
|
|
393
|
+
this._encryptionProviders.map(async (provider) => ({
|
|
394
|
+
wrapKeyName: provider.name,
|
|
395
|
+
...await provider.wrapDek(ownerSeed)
|
|
396
|
+
}))
|
|
397
|
+
);
|
|
398
|
+
keyEnvelope = serializeKeyEnvelope(
|
|
399
|
+
buildKeyEnvelope(ownerSeedWrappers)
|
|
400
|
+
);
|
|
401
|
+
ownerSecret = await deriveOwnerSecret(
|
|
402
|
+
ownerSeed,
|
|
403
|
+
new TextEncoder().encode(storageResult.id),
|
|
404
|
+
"dstorage:owner-secret:public:v1"
|
|
405
|
+
);
|
|
406
|
+
} finally {
|
|
407
|
+
ownerSeed.fill(0);
|
|
408
|
+
}
|
|
398
409
|
}
|
|
399
410
|
onChainStorageId = storageResult.id;
|
|
400
411
|
} else {
|
|
@@ -467,6 +478,8 @@ var DStorage = class {
|
|
|
467
478
|
};
|
|
468
479
|
} catch {
|
|
469
480
|
throw new StorePartialError(storeRecovery);
|
|
481
|
+
} finally {
|
|
482
|
+
dek?.fill(0);
|
|
470
483
|
}
|
|
471
484
|
}
|
|
472
485
|
this.logger?.log(
|
|
@@ -827,7 +840,10 @@ var DStorage = class {
|
|
|
827
840
|
async retrieveByStorageId(storageId, dekScheme, contentHash) {
|
|
828
841
|
try {
|
|
829
842
|
this.assertConnected();
|
|
830
|
-
const { bytes: rawBytes, tags } = await this.config.storageAdapter.retrieve(
|
|
843
|
+
const { bytes: rawBytes, tags } = await this.config.storageAdapter.retrieve(
|
|
844
|
+
storageId,
|
|
845
|
+
contentHash !== void 0 ? { expectedContentHash: contentHash } : void 0
|
|
846
|
+
);
|
|
831
847
|
if (contentHash) {
|
|
832
848
|
const computed = await computeBlake3Hex(rawBytes);
|
|
833
849
|
if (computed !== contentHash) {
|
|
@@ -968,9 +984,16 @@ var DStorage = class {
|
|
|
968
984
|
} catch {
|
|
969
985
|
}
|
|
970
986
|
if (manifestBytes !== null) {
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
987
|
+
let parsed;
|
|
988
|
+
try {
|
|
989
|
+
parsed = JSON.parse(new TextDecoder().decode(manifestBytes));
|
|
990
|
+
} catch (err) {
|
|
991
|
+
throw new DStorageError(
|
|
992
|
+
CoreErrorCode.MANIFEST_PARSE_FAILED,
|
|
993
|
+
`[dStorage] Payload authenticated as manifest but is not valid JSON: ${err}`,
|
|
994
|
+
{ cause: err }
|
|
995
|
+
);
|
|
996
|
+
}
|
|
974
997
|
if (!isManifest(parsed)) {
|
|
975
998
|
throw new DStorageError(
|
|
976
999
|
CoreErrorCode.MANIFEST_INVALID_STRUCTURE,
|
|
@@ -1094,7 +1117,15 @@ var DStorage = class {
|
|
|
1094
1117
|
base64urlToBytes(ref.encryptedMetadata),
|
|
1095
1118
|
METADATA_AAD
|
|
1096
1119
|
);
|
|
1097
|
-
|
|
1120
|
+
try {
|
|
1121
|
+
metadata = JSON.parse(new TextDecoder().decode(raw));
|
|
1122
|
+
} catch (err) {
|
|
1123
|
+
throw new DStorageError(
|
|
1124
|
+
CoreErrorCode.METADATA_PARSE_FAILED,
|
|
1125
|
+
`[dStorage] Decrypted metadata is not valid JSON: ${err}`,
|
|
1126
|
+
{ cause: err }
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1098
1129
|
}
|
|
1099
1130
|
return { bytes: contentBytes, tags: contentTags, metadata };
|
|
1100
1131
|
} catch (err) {
|
|
@@ -1439,12 +1470,17 @@ var DStorage = class {
|
|
|
1439
1470
|
};
|
|
1440
1471
|
} catch {
|
|
1441
1472
|
throw new StorePartialError(storeRecovery);
|
|
1473
|
+
} finally {
|
|
1474
|
+
chunkDek?.fill(0);
|
|
1475
|
+
ownerSeed?.fill(0);
|
|
1442
1476
|
}
|
|
1443
1477
|
}
|
|
1444
1478
|
this.logger?.log(
|
|
1445
1479
|
"dStorage",
|
|
1446
1480
|
`Chunked upload complete (storage-only) \u2192 ${totalChunks} chunks + manifest, storageId: ${manifestResult.id}`
|
|
1447
1481
|
);
|
|
1482
|
+
chunkDek?.fill(0);
|
|
1483
|
+
ownerSeed?.fill(0);
|
|
1448
1484
|
return {
|
|
1449
1485
|
storageId: manifestResult.id,
|
|
1450
1486
|
storageProvider: manifestResult.provider,
|
|
@@ -2238,7 +2274,8 @@ var StorageErrorCode = {
|
|
|
2238
2274
|
ARWEAVE_BUNDLER_INVALID_AUTH_TOKEN_FORMAT: 15411,
|
|
2239
2275
|
ARWEAVE_BUNDLER_INVALID_AUTH_TOKEN_KEY: 15412,
|
|
2240
2276
|
ARWEAVE_BUNDLER_NO_TX_ID_RETURNED: 15413,
|
|
2241
|
-
ARWEAVE_BUNDLER_UPLOAD_FAILED: 15414
|
|
2277
|
+
ARWEAVE_BUNDLER_UPLOAD_FAILED: 15414,
|
|
2278
|
+
ARWEAVE_BUNDLER_METADATA_TOO_LARGE: 15415
|
|
2242
2279
|
};
|
|
2243
2280
|
var memoryStore = /* @__PURE__ */ new Map();
|
|
2244
2281
|
function bytesToBase64url2(bytes) {
|
|
@@ -2515,7 +2552,7 @@ var ArweaveStorageAdapter = class {
|
|
|
2515
2552
|
};
|
|
2516
2553
|
}
|
|
2517
2554
|
// ── retrieve ───────────────────────────────────────────────────────────────────
|
|
2518
|
-
async retrieve(id) {
|
|
2555
|
+
async retrieve(id, options) {
|
|
2519
2556
|
if (!/^[A-Za-z0-9_-]{43}$/.test(id)) {
|
|
2520
2557
|
throw new DStorageError(
|
|
2521
2558
|
StorageErrorCode.ARWEAVE_INVALID_TX_ID,
|
|
@@ -2579,14 +2616,15 @@ Check status at: https://viewblock.io/arweave/tx/${id}`
|
|
|
2579
2616
|
);
|
|
2580
2617
|
}
|
|
2581
2618
|
if (!this.skipIntegrityCheck) {
|
|
2582
|
-
|
|
2619
|
+
const anchorHash = options?.expectedContentHash;
|
|
2620
|
+
if (!anchorHash && !storedHash) {
|
|
2583
2621
|
throw new DStorageError(
|
|
2584
2622
|
StorageErrorCode.ARWEAVE_HASH_TAG_MISSING,
|
|
2585
|
-
`[dStorage/arweave]
|
|
2623
|
+
`[dStorage/arweave] Cannot verify content integrity for txId: ${id} \u2014 no expectedContentHash anchor was provided and the ${CONTENT_HASH_TAG2} tag was not found.
|
|
2586
2624
|
Set skipIntegrityCheck: true to bypass integrity checking for fully trusted gateways.`
|
|
2587
2625
|
);
|
|
2588
2626
|
}
|
|
2589
|
-
await assertContentHash(id, bytes, storedHash, "arweave");
|
|
2627
|
+
await assertContentHash(id, bytes, anchorHash ?? storedHash, "arweave");
|
|
2590
2628
|
}
|
|
2591
2629
|
this.logger?.log("dStorage/arweave", `Retrieved txId: ${id}`);
|
|
2592
2630
|
return { bytes, tags };
|
|
@@ -2710,14 +2748,19 @@ async function getTurboFactory() {
|
|
|
2710
2748
|
return TurboFactory;
|
|
2711
2749
|
}
|
|
2712
2750
|
var ARWEAVE_GATEWAY_URL = "https://turbo-gateway.com";
|
|
2751
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
2752
|
+
var DEFAULT_MAX_METADATA_RESPONSE_BYTES = 1024 * 1024;
|
|
2753
|
+
var DEFAULT_MAX_RETRIEVE_SIZE_BYTES = 256 * 1024 * 1024;
|
|
2713
2754
|
var ArweaveBundlerStorageAdapter = class _ArweaveBundlerStorageAdapter {
|
|
2714
2755
|
constructor(config = {}) {
|
|
2715
2756
|
this.name = "arweave_bundler";
|
|
2716
2757
|
this.providerName = "Arweave (Bundler)";
|
|
2717
2758
|
this.signingServerUrl = config.signingServerUrl ? config.signingServerUrl.replace(/\/$/, "") : null;
|
|
2718
2759
|
this.gateway = config.gateway ?? ARWEAVE_GATEWAY_URL;
|
|
2719
|
-
this.maxRetrieveSizeBytes = config.maxRetrieveSizeBytes ??
|
|
2760
|
+
this.maxRetrieveSizeBytes = config.maxRetrieveSizeBytes ?? DEFAULT_MAX_RETRIEVE_SIZE_BYTES;
|
|
2720
2761
|
this.skipIntegrityCheck = config.skipIntegrityCheck ?? false;
|
|
2762
|
+
this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
2763
|
+
this.maxMetadataResponseBytes = config.maxMetadataResponseBytes ?? DEFAULT_MAX_METADATA_RESPONSE_BYTES;
|
|
2721
2764
|
this.logger = config.logger;
|
|
2722
2765
|
if (config.signingServerUrl) {
|
|
2723
2766
|
if (!config.authToken?.trim()) {
|
|
@@ -2768,8 +2811,13 @@ var ArweaveBundlerStorageAdapter = class _ArweaveBundlerStorageAdapter {
|
|
|
2768
2811
|
);
|
|
2769
2812
|
return { id: txId, provider: this.name, url, uploadedAt: Date.now() };
|
|
2770
2813
|
}
|
|
2814
|
+
/** Adds an AbortSignal.timeout() to a fetch init object (when requestTimeoutMs > 0). */
|
|
2815
|
+
_withTimeout(init = {}) {
|
|
2816
|
+
const signal = this.requestTimeoutMs > 0 ? AbortSignal.timeout(this.requestTimeoutMs) : void 0;
|
|
2817
|
+
return { ...init, ...signal !== void 0 ? { signal } : {} };
|
|
2818
|
+
}
|
|
2771
2819
|
// ── retrieve ───────────────────────────────────────────────────────────────────
|
|
2772
|
-
async retrieve(id) {
|
|
2820
|
+
async retrieve(id, options) {
|
|
2773
2821
|
if (!/^[A-Za-z0-9_-]{43}$/.test(id)) {
|
|
2774
2822
|
throw new DStorageError(
|
|
2775
2823
|
StorageErrorCode.ARWEAVE_BUNDLER_INVALID_TX_ID,
|
|
@@ -2779,29 +2827,37 @@ var ArweaveBundlerStorageAdapter = class _ArweaveBundlerStorageAdapter {
|
|
|
2779
2827
|
let storedHash;
|
|
2780
2828
|
const tags = {};
|
|
2781
2829
|
if (!this.skipIntegrityCheck) {
|
|
2782
|
-
const metaResp = await fetch(
|
|
2830
|
+
const metaResp = await fetch(
|
|
2831
|
+
`${this.gateway}/tx/${id}`,
|
|
2832
|
+
this._withTimeout()
|
|
2833
|
+
);
|
|
2783
2834
|
if (!metaResp.ok) {
|
|
2784
2835
|
throw new DStorageError(
|
|
2785
2836
|
StorageErrorCode.ARWEAVE_BUNDLER_TX_METADATA_FAILED,
|
|
2786
2837
|
`[dStorage/arweave-bundler] Could not fetch transaction metadata for txId: ${id} \u2014 content hash cannot be verified. Set skipIntegrityCheck: true to bypass integrity checking for fully trusted gateways.`
|
|
2787
2838
|
);
|
|
2788
2839
|
}
|
|
2789
|
-
const
|
|
2840
|
+
const metaText = await readResponseTextWithLimit(metaResp, {
|
|
2841
|
+
maxBytes: this.maxMetadataResponseBytes,
|
|
2842
|
+
code: StorageErrorCode.ARWEAVE_BUNDLER_METADATA_TOO_LARGE,
|
|
2843
|
+
component: `[dStorage/arweave-bundler] retrieve(${id}) metadata`
|
|
2844
|
+
});
|
|
2845
|
+
const tx = JSON.parse(metaText);
|
|
2790
2846
|
for (const tag of tx.tags ?? []) {
|
|
2791
2847
|
const name = new TextDecoder().decode(_base64urlToBytes(tag.name));
|
|
2792
2848
|
const value = new TextDecoder().decode(_base64urlToBytes(tag.value));
|
|
2793
2849
|
tags[name] = value;
|
|
2794
2850
|
if (name === CONTENT_HASH_TAG2) storedHash = value;
|
|
2795
2851
|
}
|
|
2796
|
-
if (!storedHash) {
|
|
2852
|
+
if (!options?.expectedContentHash && !storedHash) {
|
|
2797
2853
|
throw new DStorageError(
|
|
2798
2854
|
StorageErrorCode.ARWEAVE_BUNDLER_HASH_TAG_MISSING,
|
|
2799
|
-
`[dStorage/arweave-bundler]
|
|
2855
|
+
`[dStorage/arweave-bundler] Cannot verify content integrity for txId: ${id} \u2014 no expectedContentHash anchor was provided and the ${CONTENT_HASH_TAG2} tag was not found.
|
|
2800
2856
|
Set skipIntegrityCheck: true to bypass integrity checking for fully trusted gateways.`
|
|
2801
2857
|
);
|
|
2802
2858
|
}
|
|
2803
2859
|
}
|
|
2804
|
-
const resp = await fetch(`${this.gateway}/${id}
|
|
2860
|
+
const resp = await fetch(`${this.gateway}/${id}`, this._withTimeout());
|
|
2805
2861
|
if (!resp.ok) {
|
|
2806
2862
|
throw new DStorageError(
|
|
2807
2863
|
StorageErrorCode.ARWEAVE_BUNDLER_RETRIEVE_HTTP_ERROR,
|
|
@@ -2826,8 +2882,14 @@ Check: https://viewblock.io/arweave/tx/${id}`
|
|
|
2826
2882
|
`[dStorage/arweave-bundler] Downloaded ${bytes.byteLength} bytes for txId: ${id}, which exceeds the configured limit of ${this.maxRetrieveSizeBytes} bytes.`
|
|
2827
2883
|
);
|
|
2828
2884
|
}
|
|
2829
|
-
|
|
2830
|
-
|
|
2885
|
+
const anchorHash = options?.expectedContentHash;
|
|
2886
|
+
if (!this.skipIntegrityCheck && (anchorHash || storedHash)) {
|
|
2887
|
+
await assertContentHash(
|
|
2888
|
+
id,
|
|
2889
|
+
bytes,
|
|
2890
|
+
anchorHash ?? storedHash,
|
|
2891
|
+
"arweave-bundler"
|
|
2892
|
+
);
|
|
2831
2893
|
}
|
|
2832
2894
|
this.logger?.log("dStorage/arweave-bundler", `Retrieved txId: ${id}`);
|
|
2833
2895
|
return { bytes, tags };
|
|
@@ -3638,6 +3700,8 @@ var MidnightSimulatorChainAdapter = class {
|
|
|
3638
3700
|
}
|
|
3639
3701
|
};
|
|
3640
3702
|
var COMPONENT = "[dStorage/http-gateway-chain]";
|
|
3703
|
+
var DEFAULT_REQUEST_TIMEOUT_MS2 = 3e4;
|
|
3704
|
+
var DEFAULT_MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
|
|
3641
3705
|
function generateRefId2() {
|
|
3642
3706
|
const id = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
3643
3707
|
return `ref_${id}`;
|
|
@@ -3653,6 +3717,13 @@ var HttpGatewayChainAdapter = class {
|
|
|
3653
3717
|
this.readUrl = `${config.baseUrl}${config.readPath}`;
|
|
3654
3718
|
this.listUrl = `${config.baseUrl}${config.listPath}`;
|
|
3655
3719
|
this.deleteUrl = `${config.baseUrl}${config.deletePath}`;
|
|
3720
|
+
this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS2;
|
|
3721
|
+
this.maxResponseBytes = config.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
|
|
3722
|
+
}
|
|
3723
|
+
/** Adds an AbortSignal.timeout() to a fetch init object (when requestTimeoutMs > 0). */
|
|
3724
|
+
_withTimeout(init) {
|
|
3725
|
+
const signal = this.requestTimeoutMs > 0 ? AbortSignal.timeout(this.requestTimeoutMs) : void 0;
|
|
3726
|
+
return { ...init, ...signal !== void 0 ? { signal } : {} };
|
|
3656
3727
|
}
|
|
3657
3728
|
async writeReference(ref) {
|
|
3658
3729
|
const { ownerSecret: _omit, ...payload } = ref;
|
|
@@ -3660,11 +3731,17 @@ var HttpGatewayChainAdapter = class {
|
|
|
3660
3731
|
const url = `${this.writeUrl}/${encodeURIComponent(refId)}`;
|
|
3661
3732
|
let res;
|
|
3662
3733
|
try {
|
|
3663
|
-
res = await this.fetchFn(
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3734
|
+
res = await this.fetchFn(
|
|
3735
|
+
url,
|
|
3736
|
+
this._withTimeout({
|
|
3737
|
+
method: "POST",
|
|
3738
|
+
headers: {
|
|
3739
|
+
"Content-Type": "application/json",
|
|
3740
|
+
...this.extraHeaders
|
|
3741
|
+
},
|
|
3742
|
+
body: JSON.stringify(payload)
|
|
3743
|
+
})
|
|
3744
|
+
);
|
|
3668
3745
|
} catch (err) {
|
|
3669
3746
|
throw new DStorageError(
|
|
3670
3747
|
ChainErrorCode.GATEWAY_WRITE_FAILED,
|
|
@@ -3690,11 +3767,17 @@ var HttpGatewayChainAdapter = class {
|
|
|
3690
3767
|
const url = `${this.writeUrl}/${encodeURIComponent(refId)}`;
|
|
3691
3768
|
let res;
|
|
3692
3769
|
try {
|
|
3693
|
-
res = await this.fetchFn(
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3770
|
+
res = await this.fetchFn(
|
|
3771
|
+
url,
|
|
3772
|
+
this._withTimeout({
|
|
3773
|
+
method: "POST",
|
|
3774
|
+
headers: {
|
|
3775
|
+
"Content-Type": "application/json",
|
|
3776
|
+
...this.extraHeaders
|
|
3777
|
+
},
|
|
3778
|
+
body: JSON.stringify(update)
|
|
3779
|
+
})
|
|
3780
|
+
);
|
|
3698
3781
|
} catch (err) {
|
|
3699
3782
|
throw new DStorageError(
|
|
3700
3783
|
ChainErrorCode.GATEWAY_UPDATE_FAILED,
|
|
@@ -3715,7 +3798,10 @@ var HttpGatewayChainAdapter = class {
|
|
|
3715
3798
|
const url = `${this.readUrl}/${encodeURIComponent(refId)}`;
|
|
3716
3799
|
let res;
|
|
3717
3800
|
try {
|
|
3718
|
-
res = await this.fetchFn(
|
|
3801
|
+
res = await this.fetchFn(
|
|
3802
|
+
url,
|
|
3803
|
+
this._withTimeout({ headers: { ...this.extraHeaders } })
|
|
3804
|
+
);
|
|
3719
3805
|
} catch (err) {
|
|
3720
3806
|
throw new DStorageError(
|
|
3721
3807
|
ChainErrorCode.GATEWAY_READ_FAILED,
|
|
@@ -3730,9 +3816,14 @@ var HttpGatewayChainAdapter = class {
|
|
|
3730
3816
|
{ httpStatus: res.status }
|
|
3731
3817
|
);
|
|
3732
3818
|
}
|
|
3819
|
+
const text = await readResponseTextWithLimit(res, {
|
|
3820
|
+
maxBytes: this.maxResponseBytes,
|
|
3821
|
+
code: ChainErrorCode.GATEWAY_READ_RESPONSE_TOO_LARGE,
|
|
3822
|
+
component: `${COMPONENT} readReference`
|
|
3823
|
+
});
|
|
3733
3824
|
let data;
|
|
3734
3825
|
try {
|
|
3735
|
-
data =
|
|
3826
|
+
data = JSON.parse(text);
|
|
3736
3827
|
} catch {
|
|
3737
3828
|
throw new DStorageError(
|
|
3738
3829
|
ChainErrorCode.GATEWAY_READ_INVALID_JSON,
|
|
@@ -3751,9 +3842,10 @@ var HttpGatewayChainAdapter = class {
|
|
|
3751
3842
|
async listReferences() {
|
|
3752
3843
|
let res;
|
|
3753
3844
|
try {
|
|
3754
|
-
res = await this.fetchFn(
|
|
3755
|
-
|
|
3756
|
-
|
|
3845
|
+
res = await this.fetchFn(
|
|
3846
|
+
this.listUrl,
|
|
3847
|
+
this._withTimeout({ headers: { ...this.extraHeaders } })
|
|
3848
|
+
);
|
|
3757
3849
|
} catch (err) {
|
|
3758
3850
|
throw new DStorageError(
|
|
3759
3851
|
ChainErrorCode.GATEWAY_LIST_FAILED,
|
|
@@ -3768,9 +3860,14 @@ var HttpGatewayChainAdapter = class {
|
|
|
3768
3860
|
{ httpStatus: res.status }
|
|
3769
3861
|
);
|
|
3770
3862
|
}
|
|
3863
|
+
const text = await readResponseTextWithLimit(res, {
|
|
3864
|
+
maxBytes: this.maxResponseBytes,
|
|
3865
|
+
code: ChainErrorCode.GATEWAY_LIST_RESPONSE_TOO_LARGE,
|
|
3866
|
+
component: `${COMPONENT} listReferences`
|
|
3867
|
+
});
|
|
3771
3868
|
let data;
|
|
3772
3869
|
try {
|
|
3773
|
-
data =
|
|
3870
|
+
data = JSON.parse(text);
|
|
3774
3871
|
} catch {
|
|
3775
3872
|
throw new DStorageError(
|
|
3776
3873
|
ChainErrorCode.GATEWAY_LIST_INVALID_JSON,
|
|
@@ -3803,11 +3900,17 @@ var HttpGatewayChainAdapter = class {
|
|
|
3803
3900
|
const body = ownerSecret !== void 0 ? { ownerSecret: bytesToBase64url(ownerSecret) } : {};
|
|
3804
3901
|
let res;
|
|
3805
3902
|
try {
|
|
3806
|
-
res = await this.fetchFn(
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3903
|
+
res = await this.fetchFn(
|
|
3904
|
+
url,
|
|
3905
|
+
this._withTimeout({
|
|
3906
|
+
method: "DELETE",
|
|
3907
|
+
headers: {
|
|
3908
|
+
"Content-Type": "application/json",
|
|
3909
|
+
...this.extraHeaders
|
|
3910
|
+
},
|
|
3911
|
+
body: JSON.stringify(body)
|
|
3912
|
+
})
|
|
3913
|
+
);
|
|
3811
3914
|
} catch (err) {
|
|
3812
3915
|
throw new DStorageError(
|
|
3813
3916
|
ChainErrorCode.GATEWAY_REMOVE_FAILED,
|
|
@@ -3854,16 +3957,16 @@ var NETWORKS = {
|
|
|
3854
3957
|
networkId: "preprod",
|
|
3855
3958
|
nodeHttp: "https://rpc.preprod.midnight.network",
|
|
3856
3959
|
nodeWs: "wss://rpc.preprod.midnight.network",
|
|
3857
|
-
indexerHttp: "https://indexer.preprod.midnight.network/api/
|
|
3858
|
-
indexerWs: "wss://indexer.preprod.midnight.network/api/
|
|
3960
|
+
indexerHttp: "https://indexer.preprod.midnight.network/api/v4/graphql",
|
|
3961
|
+
indexerWs: "wss://indexer.preprod.midnight.network/api/v4/graphql/ws",
|
|
3859
3962
|
proofServer: "http://127.0.0.1:6300"
|
|
3860
3963
|
},
|
|
3861
3964
|
undeployed: {
|
|
3862
3965
|
networkId: "undeployed",
|
|
3863
3966
|
nodeHttp: "http://127.0.0.1:9944",
|
|
3864
3967
|
nodeWs: "ws://127.0.0.1:9944",
|
|
3865
|
-
indexerHttp: "http://127.0.0.1:8088/api/
|
|
3866
|
-
indexerWs: "ws://127.0.0.1:8088/api/
|
|
3968
|
+
indexerHttp: "http://127.0.0.1:8088/api/v4/graphql",
|
|
3969
|
+
indexerWs: "ws://127.0.0.1:8088/api/v4/graphql/ws",
|
|
3867
3970
|
proofServer: "http://127.0.0.1:6300"
|
|
3868
3971
|
}
|
|
3869
3972
|
};
|
|
@@ -4273,7 +4376,7 @@ var MidnightChainAdapter = class _MidnightChainAdapter {
|
|
|
4273
4376
|
} else {
|
|
4274
4377
|
providers = await this._buildWalletProviderMode();
|
|
4275
4378
|
}
|
|
4276
|
-
const { DataRegistryAPI } = await import("./contract-api-
|
|
4379
|
+
const { DataRegistryAPI } = await import("./contract-api-P6YEDYQ6-2X6BMD64.mjs");
|
|
4277
4380
|
if (!this._contractAddress) {
|
|
4278
4381
|
this.logger?.log("dStorage/midnight", "Deploying DataRegistry contract\u2026");
|
|
4279
4382
|
this._api = await DataRegistryAPI.deploy(providers, this.logger);
|
|
@@ -4812,6 +4915,7 @@ export {
|
|
|
4812
4915
|
mlkemUnwrapDek,
|
|
4813
4916
|
mlkemWrapDek,
|
|
4814
4917
|
parseKeyEnvelope,
|
|
4918
|
+
readResponseTextWithLimit,
|
|
4815
4919
|
serializeKeyEnvelope,
|
|
4816
4920
|
serializeXChaChaPayload,
|
|
4817
4921
|
unwrapKey,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EncryptionErrorCode
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-L6WCT64V.mjs";
|
|
4
4
|
import {
|
|
5
5
|
DStorageError,
|
|
6
6
|
deriveKek,
|
|
7
7
|
unwrapKey,
|
|
8
8
|
wrapKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PCXBQRCO.mjs";
|
|
10
10
|
|
|
11
|
-
// ../encryption/dist/chunk-
|
|
11
|
+
// ../encryption/dist/chunk-ENX7VXEV.mjs
|
|
12
12
|
import { scrypt } from "@noble/hashes/scrypt.js";
|
|
13
13
|
var KDF_PRESETS = {
|
|
14
14
|
v1: { N: 131072, r: 8, p: 1 },
|
|
@@ -137,8 +137,8 @@ var PasswordEncryptionAdapter = class _PasswordEncryptionAdapter {
|
|
|
137
137
|
* @param variant ML-KEM variant. Default: "mlkem768".
|
|
138
138
|
*/
|
|
139
139
|
async intoKeypairEncryptionAdapter(context, variant) {
|
|
140
|
-
const { KeypairEncryptionAdapter } = await import("./KeypairEncryptionAdapter-
|
|
141
|
-
const { mlkemGenerateKeypairFromSeed } = await import("./dist-
|
|
140
|
+
const { KeypairEncryptionAdapter } = await import("./KeypairEncryptionAdapter-EOBRCIGP-5PFPNLLA.mjs");
|
|
141
|
+
const { mlkemGenerateKeypairFromSeed } = await import("./dist-J4JUJ2J5.mjs");
|
|
142
142
|
const kekMaterial = await this.kekMaterialPromise;
|
|
143
143
|
const mlkemBits = await globalThis.crypto.subtle.deriveBits(
|
|
144
144
|
{
|
|
@@ -170,7 +170,23 @@ function resolveSalt(salt) {
|
|
|
170
170
|
}
|
|
171
171
|
return bytes;
|
|
172
172
|
}
|
|
173
|
+
var MIN_SCRYPT_N = 32768;
|
|
174
|
+
function assertScryptCost(N) {
|
|
175
|
+
if (!Number.isInteger(N) || N < 2 || (N & N - 1) !== 0) {
|
|
176
|
+
throw new DStorageError(
|
|
177
|
+
EncryptionErrorCode.PASSWORD_SCRYPT_N_NOT_POWER_OF_TWO,
|
|
178
|
+
`[dStorage] PasswordEncryptionAdapter: scrypt N must be a power of two >= 2 (got ${N}).`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
if (N < MIN_SCRYPT_N) {
|
|
182
|
+
throw new DStorageError(
|
|
183
|
+
EncryptionErrorCode.PASSWORD_SCRYPT_N_TOO_LOW,
|
|
184
|
+
`[dStorage] PasswordEncryptionAdapter: scrypt N=${N} is below the minimum cost floor of ${MIN_SCRYPT_N} (OWASP 2024 minimum, 32 MB memory-hard). A lower N makes the KDF cheap enough to brute-force offline. Use a preset ("v1" or "v1-lite") or a custom N >= 32768.`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
173
188
|
function resolveParams(preset, params) {
|
|
189
|
+
let resolved;
|
|
174
190
|
if (preset !== void 0) {
|
|
175
191
|
if (!(preset in KDF_PRESETS)) {
|
|
176
192
|
throw new DStorageError(
|
|
@@ -178,13 +194,16 @@ function resolveParams(preset, params) {
|
|
|
178
194
|
`[dStorage] PasswordEncryptionAdapter: unknown preset "${preset}". Valid presets: ${Object.keys(KDF_PRESETS).join(", ")}.`
|
|
179
195
|
);
|
|
180
196
|
}
|
|
181
|
-
|
|
197
|
+
resolved = KDF_PRESETS[preset];
|
|
198
|
+
} else {
|
|
199
|
+
resolved = {
|
|
200
|
+
N: params?.N ?? KDF_PRESETS["v1"].N,
|
|
201
|
+
r: params?.r ?? KDF_PRESETS["v1"].r,
|
|
202
|
+
p: params?.p ?? KDF_PRESETS["v1"].p
|
|
203
|
+
};
|
|
182
204
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
r: params?.r ?? KDF_PRESETS["v1"].r,
|
|
186
|
-
p: params?.p ?? KDF_PRESETS["v1"].p
|
|
187
|
-
};
|
|
205
|
+
assertScryptCost(resolved.N);
|
|
206
|
+
return resolved;
|
|
188
207
|
}
|
|
189
208
|
function estimateEntropyBits(password) {
|
|
190
209
|
let pool = 0;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EncryptionErrorCode
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-L6WCT64V.mjs";
|
|
4
4
|
import {
|
|
5
5
|
DStorageError,
|
|
6
6
|
deriveKek,
|
|
7
7
|
unwrapKey,
|
|
8
8
|
wrapKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PCXBQRCO.mjs";
|
|
10
10
|
|
|
11
|
-
// ../encryption/dist/chunk-
|
|
11
|
+
// ../encryption/dist/chunk-ENX7VXEV.mjs
|
|
12
12
|
import { scrypt } from "@noble/hashes/scrypt.js";
|
|
13
13
|
var KDF_PRESETS = {
|
|
14
14
|
v1: { N: 131072, r: 8, p: 1 },
|
|
@@ -137,8 +137,8 @@ var PasswordEncryptionAdapter = class _PasswordEncryptionAdapter {
|
|
|
137
137
|
* @param variant ML-KEM variant. Default: "mlkem768".
|
|
138
138
|
*/
|
|
139
139
|
async intoKeypairEncryptionAdapter(context, variant) {
|
|
140
|
-
const { KeypairEncryptionAdapter } = await import("./KeypairEncryptionAdapter-
|
|
141
|
-
const { mlkemGenerateKeypairFromSeed } = await import("./dist-
|
|
140
|
+
const { KeypairEncryptionAdapter } = await import("./KeypairEncryptionAdapter-EOBRCIGP-FLPJIL26.mjs");
|
|
141
|
+
const { mlkemGenerateKeypairFromSeed } = await import("./dist-AGNOIJI4.mjs");
|
|
142
142
|
const kekMaterial = await this.kekMaterialPromise;
|
|
143
143
|
const mlkemBits = await globalThis.crypto.subtle.deriveBits(
|
|
144
144
|
{
|
|
@@ -170,7 +170,23 @@ function resolveSalt(salt) {
|
|
|
170
170
|
}
|
|
171
171
|
return bytes;
|
|
172
172
|
}
|
|
173
|
+
var MIN_SCRYPT_N = 32768;
|
|
174
|
+
function assertScryptCost(N) {
|
|
175
|
+
if (!Number.isInteger(N) || N < 2 || (N & N - 1) !== 0) {
|
|
176
|
+
throw new DStorageError(
|
|
177
|
+
EncryptionErrorCode.PASSWORD_SCRYPT_N_NOT_POWER_OF_TWO,
|
|
178
|
+
`[dStorage] PasswordEncryptionAdapter: scrypt N must be a power of two >= 2 (got ${N}).`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
if (N < MIN_SCRYPT_N) {
|
|
182
|
+
throw new DStorageError(
|
|
183
|
+
EncryptionErrorCode.PASSWORD_SCRYPT_N_TOO_LOW,
|
|
184
|
+
`[dStorage] PasswordEncryptionAdapter: scrypt N=${N} is below the minimum cost floor of ${MIN_SCRYPT_N} (OWASP 2024 minimum, 32 MB memory-hard). A lower N makes the KDF cheap enough to brute-force offline. Use a preset ("v1" or "v1-lite") or a custom N >= 32768.`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
173
188
|
function resolveParams(preset, params) {
|
|
189
|
+
let resolved;
|
|
174
190
|
if (preset !== void 0) {
|
|
175
191
|
if (!(preset in KDF_PRESETS)) {
|
|
176
192
|
throw new DStorageError(
|
|
@@ -178,13 +194,16 @@ function resolveParams(preset, params) {
|
|
|
178
194
|
`[dStorage] PasswordEncryptionAdapter: unknown preset "${preset}". Valid presets: ${Object.keys(KDF_PRESETS).join(", ")}.`
|
|
179
195
|
);
|
|
180
196
|
}
|
|
181
|
-
|
|
197
|
+
resolved = KDF_PRESETS[preset];
|
|
198
|
+
} else {
|
|
199
|
+
resolved = {
|
|
200
|
+
N: params?.N ?? KDF_PRESETS["v1"].N,
|
|
201
|
+
r: params?.r ?? KDF_PRESETS["v1"].r,
|
|
202
|
+
p: params?.p ?? KDF_PRESETS["v1"].p
|
|
203
|
+
};
|
|
182
204
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
r: params?.r ?? KDF_PRESETS["v1"].r,
|
|
186
|
-
p: params?.p ?? KDF_PRESETS["v1"].p
|
|
187
|
-
};
|
|
205
|
+
assertScryptCost(resolved.N);
|
|
206
|
+
return resolved;
|
|
188
207
|
}
|
|
189
208
|
function estimateEntropyBits(password) {
|
|
190
209
|
let pool = 0;
|