@swal/vault 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +128 -0
- package/README.md +232 -2
- package/dist/bytes.d.ts +20 -0
- package/dist/bytes.d.ts.map +1 -0
- package/dist/bytes.js +135 -0
- package/dist/bytes.js.map +1 -0
- package/dist/cloudShare.d.ts +20 -0
- package/dist/cloudShare.d.ts.map +1 -0
- package/dist/cloudShare.js +21 -0
- package/dist/cloudShare.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/r2Client.d.ts +37 -0
- package/dist/r2Client.d.ts.map +1 -0
- package/dist/r2Client.js +109 -0
- package/dist/r2Client.js.map +1 -0
- package/dist/sealedPack.d.ts +90 -0
- package/dist/sealedPack.d.ts.map +1 -0
- package/dist/sealedPack.js +233 -0
- package/dist/sealedPack.js.map +1 -0
- package/dist/web/vault-client.d.ts +64 -0
- package/dist/web/vault-client.d.ts.map +1 -0
- package/dist/web/vault-client.js +249 -0
- package/dist/web/vault-client.js.map +1 -0
- package/package.json +79 -4
- package/src/bytes.ts +126 -0
- package/src/cloudShare.ts +27 -0
- package/src/index.ts +4 -0
- package/src/r2Client.ts +123 -0
- package/src/sealedPack.ts +306 -0
- package/src/web/vault-client.ts +348 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work.
|
|
38
|
+
|
|
39
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
40
|
+
form, that is based on (or derived from) the Work and for which the
|
|
41
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
42
|
+
represent, as a whole, an original work of authorship.
|
|
43
|
+
|
|
44
|
+
"Contribution" shall mean any work of authorship, including
|
|
45
|
+
the original version of the Work and any modifications or additions
|
|
46
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
47
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
48
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
49
|
+
the copyright owner.
|
|
50
|
+
|
|
51
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
52
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
53
|
+
subsequently incorporated within the Work.
|
|
54
|
+
|
|
55
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
56
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
57
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
58
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
59
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
60
|
+
Work and such Derivative Works in Source or Object form.
|
|
61
|
+
|
|
62
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
63
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
64
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
65
|
+
(except as stated in this section) patent license to make, have made,
|
|
66
|
+
use, offer to sell, sell, import, and otherwise transfer the Work.
|
|
67
|
+
|
|
68
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
69
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
70
|
+
modifications, and in Source or Object form, provided that You
|
|
71
|
+
meet the following conditions:
|
|
72
|
+
|
|
73
|
+
(a) You must give any other recipients of the Work or
|
|
74
|
+
Derivative Works a copy of this License; and
|
|
75
|
+
|
|
76
|
+
(b) You must cause any modified files to carry prominent notices
|
|
77
|
+
stating that You changed the files; and
|
|
78
|
+
|
|
79
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
80
|
+
that You distribute, all copyright, patent, trademark, and
|
|
81
|
+
attribution notices from the Source form of the Work; and
|
|
82
|
+
|
|
83
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
84
|
+
distribution, then any Derivative Works that You distribute must
|
|
85
|
+
include a readable copy of the attribution notices contained
|
|
86
|
+
within such NOTICE file.
|
|
87
|
+
|
|
88
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
89
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
90
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
91
|
+
this License, without any additional terms or conditions.
|
|
92
|
+
|
|
93
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
94
|
+
names, trademarks, service marks, or product names of the Licensor.
|
|
95
|
+
|
|
96
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
97
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
98
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
99
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
100
|
+
implied.
|
|
101
|
+
|
|
102
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
103
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
104
|
+
unless required by applicable law (such as deliberate and grossly
|
|
105
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
106
|
+
liable to You for damages.
|
|
107
|
+
|
|
108
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
109
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
110
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
111
|
+
or other liability obligations and/or rights consistent with this
|
|
112
|
+
License.
|
|
113
|
+
|
|
114
|
+
END OF TERMS AND CONDITIONS
|
|
115
|
+
|
|
116
|
+
Copyright 2026 SouthWest AI Labs (SWAL)
|
|
117
|
+
|
|
118
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
119
|
+
you may not use this file except in compliance with the License.
|
|
120
|
+
You may obtain a copy of the License at
|
|
121
|
+
|
|
122
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
123
|
+
|
|
124
|
+
Unless required by applicable law or agreed to in writing, software
|
|
125
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
126
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
127
|
+
See the License for the specific language governing permissions and
|
|
128
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,3 +1,233 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @swal/vault
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Pure WebCrypto end-to-end encrypted (E2EE) storage core with Shamir's Secret Sharing (2-of-3 threshold), AES-256-GCM authenticated encryption with associated data (AEAD), and zero-knowledge cloud synchronization.
|
|
4
|
+
|
|
5
|
+
Built for privacy-first, local-first web applications and edge runtimes.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
`@swal/vault` provides cryptographic building blocks and local key custody for modern web applications and cloud edge services. It is designed so that backend storage providers (such as Cloudflare R2, D1, or S3-compatible stores) only ever see ciphertext, authentication tags, and public metadata—never plaintext data or sufficient key material to decrypt it.
|
|
12
|
+
|
|
13
|
+
### Core Properties
|
|
14
|
+
|
|
15
|
+
- **100% End-to-End Encrypted (E2EE):** Data is encrypted on the client device using an ephemeral Data Encryption Key (DEK).
|
|
16
|
+
- **2-of-3 Shamir Secret Sharing:** The DEK is split into three shares over $\text{GF}(257)$. Reconstructing the DEK requires any two shares.
|
|
17
|
+
- **Share 1 ($x=1$):** Kept strictly on the local device.
|
|
18
|
+
- **Share 2 ($x=2$):** Recovery share provided to the user upon onboarding.
|
|
19
|
+
- **Share 3 ($x=3$):** Cloud custody share stored in a database (such as Cloudflare D1).
|
|
20
|
+
- **Zero Cloud Compromise:** Because the cloud backend never holds more than one share ($x=3$), the operator or a compromised cloud infrastructure cannot decrypt user records.
|
|
21
|
+
- **Pure WebCrypto Runtime:** Relies exclusively on standard `globalThis.crypto.subtle` and `Uint8Array`. Zero dependencies on Node.js-specific modules (`node:crypto`, `Buffer`). Runs seamlessly in browsers (PWAs), Cloudflare Workers, Node.js (>= 19), Bun, and Deno.
|
|
22
|
+
- **Tamper-Proof Metadata (AEAD):** In Pack format v2, metadata is authenticated as Additional Authenticated Data (AAD) in AES-GCM. Modifying metadata, ciphertext, IV, or tag causes decryption to fail.
|
|
23
|
+
- **Hardware-Backed Identity & Key Wrapping:** Client module (`@swal/vault/web`) provides non-extractable IndexedDB key custody, passkey PRF support, and PBKDF2-SHA256 key derivation with up to 600,000 iterations.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @swal/vault
|
|
31
|
+
# or
|
|
32
|
+
pnpm add @swal/vault
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Usage Guide
|
|
38
|
+
|
|
39
|
+
### 1. Sealing and Unpacking Data
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import {
|
|
43
|
+
createSealedPack,
|
|
44
|
+
unpackSealedPack,
|
|
45
|
+
packWithoutShares,
|
|
46
|
+
packMetadataForEntity,
|
|
47
|
+
} from '@swal/vault';
|
|
48
|
+
|
|
49
|
+
// 1. Prepare plaintext payload and metadata
|
|
50
|
+
const payload = new TextEncoder().encode(JSON.stringify({ secretNote: 'Confidential message' }));
|
|
51
|
+
const metadata = packMetadataForEntity('document', 'doc-123', 'my-app', 'instance-1');
|
|
52
|
+
|
|
53
|
+
// 2. Create sealed pack (AES-256-GCM + Shamir 2/3 + Ed25519 signature)
|
|
54
|
+
const pack = await createSealedPack(payload, metadata);
|
|
55
|
+
|
|
56
|
+
// pack.shares contains 3 shares:
|
|
57
|
+
// - Share 1 (index: 1): store in device IndexedDB
|
|
58
|
+
// - Share 2 (index: 2): backup/recovery key for user
|
|
59
|
+
// - Share 3 (index: 3): cloud custody share
|
|
60
|
+
|
|
61
|
+
// 3. Prepare pack for cloud storage (strips shares)
|
|
62
|
+
const cloudSafePack = packWithoutShares(pack);
|
|
63
|
+
|
|
64
|
+
// 4. Decrypt payload using any 2 shares
|
|
65
|
+
const deviceShare = pack.shares[0]; // x=1
|
|
66
|
+
const recoveryShare = pack.shares[1]; // x=2
|
|
67
|
+
|
|
68
|
+
const decryptedBytes = await unpackSealedPack(cloudSafePack, [deviceShare, recoveryShare]);
|
|
69
|
+
const decryptedText = new TextDecoder().decode(decryptedBytes);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Cloud Storage Boundary (R2 & CloudShareStore)
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { R2StorageClient, storeCloudShare, MemoryCloudShareStore } from '@swal/vault';
|
|
76
|
+
|
|
77
|
+
// Initialize R2 storage client (supports real Cloudflare Worker R2 bucket bindings or in-memory fallback)
|
|
78
|
+
const r2 = new R2StorageClient({
|
|
79
|
+
appId: 'my-app',
|
|
80
|
+
instanceId: 'inst-01',
|
|
81
|
+
r2Binding: env.SWAL_R2, // Cloudflare R2 bucket binding (optional)
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Upload pack: enforce that no more than 1 share is uploaded.
|
|
85
|
+
// uploadSealedPack automatically strips shares and throws an error if >= 2 shares are present.
|
|
86
|
+
await r2.uploadSealedPack(pack);
|
|
87
|
+
|
|
88
|
+
// Store the single permitted cloud share (x=3) in CloudShareStore (D1 / KV / Memory)
|
|
89
|
+
const shareStore = new MemoryCloudShareStore();
|
|
90
|
+
await storeCloudShare(shareStore, pack);
|
|
91
|
+
|
|
92
|
+
// Retrieve and decrypt
|
|
93
|
+
const storedPack = await r2.getSealedPack(pack.content_hash);
|
|
94
|
+
const cloudShare = await shareStore.get(pack.id);
|
|
95
|
+
|
|
96
|
+
if (storedPack && cloudShare) {
|
|
97
|
+
const plain = await unpackSealedPack(storedPack, [deviceShare, cloudShare]);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 3. Browser Client (`@swal/vault/web`)
|
|
102
|
+
|
|
103
|
+
The browser client provides zero-network, local-first key lifecycle management in IndexedDB.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { createVaultClient } from '@swal/vault/web';
|
|
107
|
+
|
|
108
|
+
// 1. Initialize client with IndexedDB backing
|
|
109
|
+
const vault = createVaultClient({
|
|
110
|
+
storage: 'idb',
|
|
111
|
+
dbName: 'app-vault-storage',
|
|
112
|
+
pbkdf2Iterations: 600_000, // minimum allowed is 310,000
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// 2. Hardware / device identity (non-extractable ECDSA P-256)
|
|
116
|
+
const identity = await vault.getDeviceIdentity();
|
|
117
|
+
|
|
118
|
+
// 3. Unlock KEK via Passkey PRF (WebAuthn) or passphrase
|
|
119
|
+
await vault.unlockPreferPasskey('user-strong-passphrase');
|
|
120
|
+
|
|
121
|
+
// 4. Retrieve or generate the mesh encryption key (wrapped at rest in IndexedDB)
|
|
122
|
+
const { raw, key } = await vault.getOrCreateMeshKey();
|
|
123
|
+
|
|
124
|
+
// 5. Export recovery shares (allowed only ONCE; subsequent calls throw SHARE_ALREADY_SHOWN)
|
|
125
|
+
const { recoveryShare, cloudShare } = await vault.exportRecoveryShare();
|
|
126
|
+
|
|
127
|
+
// 6. Emergency recovery / passphrase reset using recovery share
|
|
128
|
+
await vault.resetPassphrase(recoveryShare, 'new-strong-passphrase');
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## API Reference
|
|
134
|
+
|
|
135
|
+
### Core (`@swal/vault`)
|
|
136
|
+
|
|
137
|
+
#### `createSealedPack(payload, metadata, keyPair?, options?)`
|
|
138
|
+
Encrypts `payload` with a freshly generated 32-byte AES-GCM DEK, splits the DEK into 3 Shamir shares, computes a SHA-256 content hash over ciphertext and metadata, signs the hash using Ed25519, and binds metadata into the AES-GCM tag via AAD.
|
|
139
|
+
- `payload`: `Uint8Array` of data to encrypt.
|
|
140
|
+
- `metadata`: `SealedPackMetadata` object. Keys must be whitelisted unless specified in `options.extraClearKeys`.
|
|
141
|
+
- `keyPair`: Optional Ed25519 `CryptoKeyPair` (or Node-compatible `KeyObject` pair). A key pair is generated if omitted.
|
|
142
|
+
- `options.extraClearKeys`: Optional array of string keys permitted in plaintext metadata.
|
|
143
|
+
- Returns: `Promise<SealedPack>`.
|
|
144
|
+
|
|
145
|
+
#### `unpackSealedPack(pack, shares)`
|
|
146
|
+
Reconstructs the 32-byte DEK from any two valid `DEKShare` objects, verifies the AAD and authentication tag, and decrypts the ciphertext.
|
|
147
|
+
- `pack`: `SealedPack`.
|
|
148
|
+
- `shares`: `DEKShare[]` containing at least 2 distinct shares.
|
|
149
|
+
- Returns: `Promise<Uint8Array>`.
|
|
150
|
+
|
|
151
|
+
#### `packWithoutShares(pack)`
|
|
152
|
+
Returns a shallow copy of `pack` with `shares: []`. Safe for transmitting to cloud backends.
|
|
153
|
+
|
|
154
|
+
#### `splitDEK(dek)` / `reconstructDEK(shares)`
|
|
155
|
+
Low-level Shamir Secret Sharing implementation over $\text{GF}(257)$.
|
|
156
|
+
- `splitDEK(dek: Uint8Array)`: Returns an array of 3 `DEKShare` objects ($x \in \{1, 2, 3\}$).
|
|
157
|
+
- `reconstructDEK(shares: DEKShare[])`: Takes 2 distinct shares and returns the original 32-byte DEK.
|
|
158
|
+
|
|
159
|
+
#### `verifySealedPackHash(pack)`
|
|
160
|
+
Asynchronously validates that the pack's `content_hash` matches `SHA-256(ciphertext || sorted(metadata))`. Returns `Promise<boolean>`.
|
|
161
|
+
|
|
162
|
+
#### `verifySealedPackSignature(pack)`
|
|
163
|
+
Verifies the Ed25519 signature over `content_hash` using the embedded `publicKey`. Returns `Promise<boolean>`.
|
|
164
|
+
|
|
165
|
+
#### `R2StorageClient`
|
|
166
|
+
Storage client adapter for Cloudflare R2 / S3 storage:
|
|
167
|
+
- `uploadSealedPack(pack)`: Verifies integrity, strips shares, and stores pack under `packs/{appId}/{instanceId}/{entity}/{content_hash}.json`. Throws if pack contains $\ge 2$ shares.
|
|
168
|
+
- `getSealedPack(keyOrHash)`: Fetches pack from R2 or fallback memory store.
|
|
169
|
+
- `deleteSealedPack(keyOrHash)`: Deletes pack from storage.
|
|
170
|
+
- `listSealedPacks(prefix?)`: Lists stored pack keys.
|
|
171
|
+
|
|
172
|
+
#### `CloudShareStore` & `storeCloudShare(store, pack)`
|
|
173
|
+
- `CloudShareStore`: Abstract storage interface (`put`, `get`, `delete`) for cloud-persisted shares ($x=3$).
|
|
174
|
+
- `storeCloudShare(store, pack)`: Extracts share $x=3$ and persists it. Rejects any operation that would store shares with index $\ne 3$.
|
|
175
|
+
- `MemoryCloudShareStore`: In-memory reference implementation for testing and mesh node synchronization.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### Web (`@swal/vault/web`)
|
|
180
|
+
|
|
181
|
+
#### `createVaultClient(options)`
|
|
182
|
+
Creates a browser vault manager backed by IndexedDB.
|
|
183
|
+
- `options.storage`: Currently `'idb'` is supported.
|
|
184
|
+
- `options.dbName`: IndexedDB database name (default: `'swal-vault'`).
|
|
185
|
+
- `options.pbkdf2Iterations`: PBKDF2 iterations for passphrase derivation (default: `600_000`, minimum: `310_000`).
|
|
186
|
+
- `options.passkey`: Optional WebAuthn PRF provider implementation.
|
|
187
|
+
|
|
188
|
+
#### `VaultClient` Methods
|
|
189
|
+
- `getDeviceIdentity(): Promise<DeviceIdentity>`: Returns device ID and SPKI/JWK public keys.
|
|
190
|
+
- `sign(data: Uint8Array): Promise<Uint8Array>`: Signs data with device private key.
|
|
191
|
+
- `verify(publicKeyJwk, data, signature): Promise<boolean>`: Verifies device signature.
|
|
192
|
+
- `unlock(options): Promise<void>`: Unlocks memory KEK using `{ passphrase: string }` or `{ passkey: true }`.
|
|
193
|
+
- `unlockPreferPasskey(passphrase): Promise<'passkey' | 'passphrase'>`: Attempts passkey unlock with automatic passphrase fallback.
|
|
194
|
+
- `lock(): void`: Wipes in-memory KEK.
|
|
195
|
+
- `isUnlocked(): boolean`: Returns current unlock state.
|
|
196
|
+
- `getOrCreateMeshKey(): Promise<MeshKey>`: Returns the active wrapped 32-byte mesh key.
|
|
197
|
+
- `exportRecoveryShare(): Promise<{ recoveryShare: DEKShare, cloudShare: DEKShare }>`: Exports recovery and cloud shares. Allowed only once.
|
|
198
|
+
- `recoverMeshKey(recoveryShare: DEKShare): Promise<Uint8Array>`: Reconstructs mesh key using device share and recovery share.
|
|
199
|
+
- `resetPassphrase(recoveryShare: DEKShare, newPassphrase: string): Promise<void>`: Re-wraps mesh key under a new passphrase.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Security Notes
|
|
204
|
+
|
|
205
|
+
1. **Threshold Secrecy:** Shamir secret sharing over $\text{GF}(257)$ provides information-theoretic security for the threshold: any single share ($k=1$) reveals zero information about the underlying encryption key.
|
|
206
|
+
2. **Cloud Boundary Invariant:** At no point should any single backend service accumulate 2 or more shares. Cloud storage (R2/S3) must only receive packs stripped of shares (`packWithoutShares`). Cloud databases (such as Cloudflare D1) must only ever store share $x=3$. Both `uploadSealedPack` and `storeCloudShare` enforce this programmatically (`assertCloudSharesSafe`).
|
|
207
|
+
3. **AEAD Authentication:** Pack format v2 binds metadata directly into AES-GCM via AAD (`swal-vault/v2|...`). Any alteration to ciphertext, initialization vector, authentication tag, or metadata properties will fail decryption.
|
|
208
|
+
4. **Clear Metadata Whitelist:** To prevent accidental data leaks in plaintext metadata fields, `createSealedPack` enforces a strict whitelist (`CLEAR_METADATA_KEYS`: `vehicleId`, `entityId`, `entity`, `appId`, `instanceId`, `timestamp`, `recordCount`, `deviceId`). Custom fields require explicit opt-in via `extraClearKeys`.
|
|
209
|
+
5. **Key Derivation Standards:** PBKDF2-SHA256 derivation requires a minimum of 310,000 iterations (OWASP recommendation) and defaults to 600,000 iterations. Initializing `VaultClient` with fewer than 310,000 iterations throws a `VaultError`.
|
|
210
|
+
6. **Zero Client Network Leakage:** `createVaultClient` performs zero network requests. All private and secret keys remain securely confined to memory and encrypted IndexedDB storage.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Development & Gate
|
|
215
|
+
|
|
216
|
+
Run tests and typecheck verification:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# Run test suite
|
|
220
|
+
npx vitest run
|
|
221
|
+
|
|
222
|
+
# Run TypeScript check
|
|
223
|
+
npx tsc --noEmit
|
|
224
|
+
|
|
225
|
+
# Verify package tarball contents
|
|
226
|
+
npm pack --dry-run
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
[Apache-2.0](LICENSE) © 2026 SouthWest AI Labs (SWAL)
|
package/dist/bytes.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare function utf8(s: string): Uint8Array;
|
|
2
|
+
export declare function fromUtf8(b: Uint8Array): string;
|
|
3
|
+
export declare function concatBytes(...parts: Uint8Array[]): Uint8Array;
|
|
4
|
+
export declare function toBase64(b: Uint8Array): string;
|
|
5
|
+
export declare function fromBase64(s: string): Uint8Array;
|
|
6
|
+
export declare function toBase64Url(b: Uint8Array): string;
|
|
7
|
+
export declare function fromBase64Url(s: string): Uint8Array;
|
|
8
|
+
export declare function toHex(b: Uint8Array): string;
|
|
9
|
+
export declare function fromHex(h: string): Uint8Array;
|
|
10
|
+
/** Bytes aleatorios criptograficos (WebCrypto). */
|
|
11
|
+
export declare function randomBytes(n: number): Uint8Array;
|
|
12
|
+
/** Entero uniforme en [min, max) sin sesgo (rejection sampling). */
|
|
13
|
+
export declare function randomInt(min: number, max: number): number;
|
|
14
|
+
/** Cast para TS >=5.7 (Uint8Array<ArrayBufferLike> -> BufferSource). */
|
|
15
|
+
export declare function bs(b: Uint8Array): BufferSource;
|
|
16
|
+
/** SHA-256 con WebCrypto. */
|
|
17
|
+
export declare function sha256(b: Uint8Array): Promise<Uint8Array>;
|
|
18
|
+
/** SHA-256 sincrono en JS puro (solo para el API legacy computeContentHash sincrono). */
|
|
19
|
+
export declare function sha256Sync(msg: Uint8Array): Uint8Array;
|
|
20
|
+
//# sourceMappingURL=bytes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"AAEA,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAE1C;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAE9C;AAED,wBAAgB,WAAW,CAAC,GAAG,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,CAQ9D;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAI9C;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAKhD;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAEjD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAGnD;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAI3C;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAK7C;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAIjD;AAED,oEAAoE;AACpE,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,wEAAwE;AACxE,wBAAgB,EAAE,CAAC,CAAC,EAAE,UAAU,GAAG,YAAY,CAE9C;AAED,6BAA6B;AAC7B,wBAAsB,MAAM,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAE/D;AAED,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CA0CtD"}
|
package/dist/bytes.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// bytes.ts — helpers Uint8Array <-> base64 / base64url / hex (sin Buffer, aptos para navegador)
|
|
2
|
+
export function utf8(s) {
|
|
3
|
+
return new TextEncoder().encode(s);
|
|
4
|
+
}
|
|
5
|
+
export function fromUtf8(b) {
|
|
6
|
+
return new TextDecoder().decode(b);
|
|
7
|
+
}
|
|
8
|
+
export function concatBytes(...parts) {
|
|
9
|
+
const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
|
|
10
|
+
let o = 0;
|
|
11
|
+
for (const p of parts) {
|
|
12
|
+
out.set(p, o);
|
|
13
|
+
o += p.length;
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
export function toBase64(b) {
|
|
18
|
+
let s = '';
|
|
19
|
+
for (let i = 0; i < b.length; i += 0x8000)
|
|
20
|
+
s += String.fromCharCode(...b.subarray(i, i + 0x8000));
|
|
21
|
+
return btoa(s);
|
|
22
|
+
}
|
|
23
|
+
export function fromBase64(s) {
|
|
24
|
+
const bin = atob(s);
|
|
25
|
+
const out = new Uint8Array(bin.length);
|
|
26
|
+
for (let i = 0; i < bin.length; i++)
|
|
27
|
+
out[i] = bin.charCodeAt(i);
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
export function toBase64Url(b) {
|
|
31
|
+
return toBase64(b).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
32
|
+
}
|
|
33
|
+
export function fromBase64Url(s) {
|
|
34
|
+
const t = s.replace(/-/g, '+').replace(/_/g, '/');
|
|
35
|
+
return fromBase64(t + '='.repeat((4 - (t.length % 4)) % 4));
|
|
36
|
+
}
|
|
37
|
+
export function toHex(b) {
|
|
38
|
+
let s = '';
|
|
39
|
+
for (const x of b)
|
|
40
|
+
s += x.toString(16).padStart(2, '0');
|
|
41
|
+
return s;
|
|
42
|
+
}
|
|
43
|
+
export function fromHex(h) {
|
|
44
|
+
if (h.length % 2)
|
|
45
|
+
throw new Error('hex invalido');
|
|
46
|
+
const out = new Uint8Array(h.length / 2);
|
|
47
|
+
for (let i = 0; i < out.length; i++)
|
|
48
|
+
out[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16);
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
/** Bytes aleatorios criptograficos (WebCrypto). */
|
|
52
|
+
export function randomBytes(n) {
|
|
53
|
+
const out = new Uint8Array(n);
|
|
54
|
+
globalThis.crypto.getRandomValues(out);
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
/** Entero uniforme en [min, max) sin sesgo (rejection sampling). */
|
|
58
|
+
export function randomInt(min, max) {
|
|
59
|
+
const range = max - min;
|
|
60
|
+
const limit = Math.floor(0x100000000 / range) * range;
|
|
61
|
+
const buf = new Uint32Array(1);
|
|
62
|
+
do
|
|
63
|
+
globalThis.crypto.getRandomValues(buf);
|
|
64
|
+
while (buf[0] >= limit);
|
|
65
|
+
return min + (buf[0] % range);
|
|
66
|
+
}
|
|
67
|
+
/** Cast para TS >=5.7 (Uint8Array<ArrayBufferLike> -> BufferSource). */
|
|
68
|
+
export function bs(b) {
|
|
69
|
+
return b;
|
|
70
|
+
}
|
|
71
|
+
/** SHA-256 con WebCrypto. */
|
|
72
|
+
export async function sha256(b) {
|
|
73
|
+
return new Uint8Array(await globalThis.crypto.subtle.digest('SHA-256', bs(b)));
|
|
74
|
+
}
|
|
75
|
+
/** SHA-256 sincrono en JS puro (solo para el API legacy computeContentHash sincrono). */
|
|
76
|
+
export function sha256Sync(msg) {
|
|
77
|
+
const K = new Uint32Array([
|
|
78
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
79
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
80
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
81
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
82
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
83
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
84
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
85
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
86
|
+
]);
|
|
87
|
+
const H = new Uint32Array([
|
|
88
|
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
89
|
+
]);
|
|
90
|
+
const len = msg.length;
|
|
91
|
+
const padded = new Uint8Array(((len + 9 + 63) >> 6) << 6);
|
|
92
|
+
padded.set(msg);
|
|
93
|
+
padded[len] = 0x80;
|
|
94
|
+
const dv = new DataView(padded.buffer);
|
|
95
|
+
dv.setUint32(padded.length - 8, Math.floor((len * 8) / 0x100000000));
|
|
96
|
+
dv.setUint32(padded.length - 4, (len * 8) >>> 0);
|
|
97
|
+
const w = new Uint32Array(64);
|
|
98
|
+
const rotr = (x, n) => (x >>> n) | (x << (32 - n));
|
|
99
|
+
for (let off = 0; off < padded.length; off += 64) {
|
|
100
|
+
for (let i = 0; i < 16; i++)
|
|
101
|
+
w[i] = dv.getUint32(off + i * 4);
|
|
102
|
+
for (let i = 16; i < 64; i++) {
|
|
103
|
+
const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >>> 3);
|
|
104
|
+
const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >>> 10);
|
|
105
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
|
|
106
|
+
}
|
|
107
|
+
let [a, b, c, d, e, f, g, h] = H;
|
|
108
|
+
for (let i = 0; i < 64; i++) {
|
|
109
|
+
const t1 = (h + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + ((e & f) ^ (~e & g)) + K[i] + w[i]) >>> 0;
|
|
110
|
+
const t2 = ((rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) >>> 0;
|
|
111
|
+
h = g;
|
|
112
|
+
g = f;
|
|
113
|
+
f = e;
|
|
114
|
+
e = (d + t1) >>> 0;
|
|
115
|
+
d = c;
|
|
116
|
+
c = b;
|
|
117
|
+
b = a;
|
|
118
|
+
a = (t1 + t2) >>> 0;
|
|
119
|
+
}
|
|
120
|
+
H[0] += a;
|
|
121
|
+
H[1] += b;
|
|
122
|
+
H[2] += c;
|
|
123
|
+
H[3] += d;
|
|
124
|
+
H[4] += e;
|
|
125
|
+
H[5] += f;
|
|
126
|
+
H[6] += g;
|
|
127
|
+
H[7] += h;
|
|
128
|
+
}
|
|
129
|
+
const out = new Uint8Array(32);
|
|
130
|
+
const odv = new DataView(out.buffer);
|
|
131
|
+
for (let i = 0; i < 8; i++)
|
|
132
|
+
odv.setUint32(i * 4, H[i]);
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=bytes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bytes.js","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type DEKShare, type SealedPack } from './sealedPack.js';
|
|
2
|
+
export interface CloudShareStore {
|
|
3
|
+
/** Guarda el share x=3 del pack `packId`. */
|
|
4
|
+
put(packId: string, share: DEKShare): Promise<void>;
|
|
5
|
+
get(packId: string): Promise<DEKShare | null>;
|
|
6
|
+
delete(packId: string): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
/** Guarda en `store` el unico share permitido (x=3) de un pack recien sellado. Lanza si no existe. */
|
|
9
|
+
export declare function storeCloudShare(store: CloudShareStore, pack: SealedPack): Promise<void>;
|
|
10
|
+
/** Implementacion en memoria (tests / mesh-only). */
|
|
11
|
+
export declare class MemoryCloudShareStore implements CloudShareStore {
|
|
12
|
+
private m;
|
|
13
|
+
put(id: string, s: DEKShare): Promise<void>;
|
|
14
|
+
get(id: string): Promise<{
|
|
15
|
+
index: number;
|
|
16
|
+
value: string;
|
|
17
|
+
} | null>;
|
|
18
|
+
delete(id: string): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=cloudShare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudShare.d.ts","sourceRoot":"","sources":["../src/cloudShare.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6D,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE5H,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC9C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,sGAAsG;AACtG,wBAAsB,eAAe,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAK7F;AAED,qDAAqD;AACrD,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,CAAC,CAA+B;IAClC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,iBAAkH;IAC7I,GAAG,CAAC,EAAE,EAAE,MAAM;;;cAA2D;IACzE,MAAM,CAAC,EAAE,EAAE,MAAM,iBAAwB;CAChD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// cloudShare.ts — interfaz agnostica de almacenamiento para el unico share que la nube puede tener (x=3).
|
|
2
|
+
// Implementala con D1 (recomendado: 100.000 filas/dia), KV (1 escritura por registro; cupo de 1.000
|
|
3
|
+
// escrituras/dia por cuenta de Cloudflare) o memoria en tests. El vault no depende de ninguna.
|
|
4
|
+
import { assertCloudSharesSafe, CLOUD_SHARE_INDEX, cloudBoundShare } from './sealedPack.js';
|
|
5
|
+
/** Guarda en `store` el unico share permitido (x=3) de un pack recien sellado. Lanza si no existe. */
|
|
6
|
+
export async function storeCloudShare(store, pack) {
|
|
7
|
+
const share = cloudBoundShare(pack.shares);
|
|
8
|
+
if (!share)
|
|
9
|
+
throw new Error(`El pack no tiene el share x=${CLOUD_SHARE_INDEX}`);
|
|
10
|
+
assertCloudSharesSafe(1);
|
|
11
|
+
await store.put(pack.id, share);
|
|
12
|
+
}
|
|
13
|
+
/** Implementacion en memoria (tests / mesh-only). */
|
|
14
|
+
export class MemoryCloudShareStore {
|
|
15
|
+
m = new Map();
|
|
16
|
+
async put(id, s) { if (s.index !== CLOUD_SHARE_INDEX)
|
|
17
|
+
throw new Error('solo se admite el share x=3'); this.m.set(id, { ...s }); }
|
|
18
|
+
async get(id) { const s = this.m.get(id); return s ? { ...s } : null; }
|
|
19
|
+
async delete(id) { this.m.delete(id); }
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=cloudShare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudShare.js","sourceRoot":"","sources":["../src/cloudShare.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,oGAAoG;AACpG,+FAA+F;AAC/F,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,eAAe,EAAkC,MAAM,iBAAiB,CAAC;AAS5H,sGAAsG;AACtG,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAsB,EAAE,IAAgB;IAC5E,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,iBAAiB,EAAE,CAAC,CAAC;IAChF,qBAAqB,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;AAClC,CAAC;AAED,qDAAqD;AACrD,MAAM,OAAO,qBAAqB;IACxB,CAAC,GAAG,IAAI,GAAG,EAAoB,CAAC;IACxC,KAAK,CAAC,GAAG,CAAC,EAAU,EAAE,CAAW,IAAI,IAAI,CAAC,CAAC,KAAK,KAAK,iBAAiB;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnJ,KAAK,CAAC,GAAG,CAAC,EAAU,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/E,KAAK,CAAC,MAAM,CAAC,EAAU,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;CAChD"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { SealedPack } from './sealedPack.js';
|
|
2
|
+
export interface R2ClientConfig {
|
|
3
|
+
bucketName?: string;
|
|
4
|
+
endpointUrl?: string;
|
|
5
|
+
accessKeyId?: string;
|
|
6
|
+
secretAccessKey?: string;
|
|
7
|
+
r2Binding?: any;
|
|
8
|
+
appId?: string;
|
|
9
|
+
instanceId?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class R2StorageClient {
|
|
12
|
+
private bucketName;
|
|
13
|
+
private endpointUrl;
|
|
14
|
+
private r2Binding;
|
|
15
|
+
private appId;
|
|
16
|
+
private instanceId;
|
|
17
|
+
private memoryStore;
|
|
18
|
+
constructor(config?: R2ClientConfig);
|
|
19
|
+
getBucketName(): string;
|
|
20
|
+
isCloudEnabled(): boolean;
|
|
21
|
+
private r2KeyForPack;
|
|
22
|
+
/**
|
|
23
|
+
* Sube el pack SIN shares (frontera E2EE). Lanza si el pack trae >=2 shares: el llamador debe
|
|
24
|
+
* quitar los shares 1 y 2 y guardar el 3 aparte (ver `CloudShareStore`).
|
|
25
|
+
*/
|
|
26
|
+
uploadSealedPack(input: SealedPack): Promise<{
|
|
27
|
+
url: string;
|
|
28
|
+
contentHash: string;
|
|
29
|
+
key: string;
|
|
30
|
+
}>;
|
|
31
|
+
getSealedPack(keyOrHash: string): Promise<SealedPack | null>;
|
|
32
|
+
deleteSealedPack(keyOrHash: string): Promise<boolean>;
|
|
33
|
+
verifyR2PackIntegrity(keyOrHash: string): Promise<boolean>;
|
|
34
|
+
listSealedPacks(prefix?: string): Promise<string[]>;
|
|
35
|
+
estimateStoredBytes(): Promise<number>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=r2Client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"r2Client.d.ts","sourceRoot":"","sources":["../src/r2Client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAsB,MAAM,iBAAiB,CAAC;AAGtE,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAsC;IAEzD,YAAY,MAAM,GAAE,cAAmB,EAMtC;IAED,aAAa,IAAI,MAAM,CAA4B;IACnD,cAAc,IAAI,OAAO,CAA6B;IAEtD,OAAO,CAAC,YAAY;IAQpB;;;OAGG;IACG,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAmBpG;IAEK,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAWjE;IAEK,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ1D;IAEK,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAI/D;IAEK,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAWxD;IAGK,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAQ3C;CACF"}
|