libves 3.0.2 → 3.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/README.md CHANGED
@@ -1,424 +1,159 @@
1
- # libVES.subtle.js
1
+ ```
2
+ ___ ___
3
+ / \ / \ VESvault
4
+ \__ / \ __/ Encrypt Everything without fear of losing the Key
5
+ \\ // https://vesvault.com https://ves.host
6
+ \\ //
7
+ ___ \\_//
8
+ / \ / \ libVES: VESvault API library
9
+ \__ / \ __/
10
+ \\ //
11
+ \\ //
12
+ \\_// - Key Management and Exchange
13
+ / \ - Item Encryption and Sharing
14
+ \___/ - VESrecovery™
15
+ ```
16
+
17
+ # libVES.js
18
+
19
+ [![CI](https://github.com/vesvault/libVES/actions/workflows/ci.yml/badge.svg)](https://github.com/vesvault/libVES/actions/workflows/ci.yml)
20
+ [![npm](https://img.shields.io/npm/v/libves)](https://www.npmjs.com/package/libves)
21
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
22
+
23
+ **End-to-end encryption for the browser and Node — that you can actually recover from.**
24
+
25
+ The official VESvault JavaScript library. It does client-side end-to-end encryption
26
+ with three things most E2E stacks leave you to build (or skip) yourself:
27
+
28
+ - **End-to-end encryption at rest** — data is encrypted in the browser/Node; the server
29
+ only ever stores ciphertext.
30
+ - **Secure item sharing** — share an encrypted value with another user by reference;
31
+ they decrypt it with *their* key, no shared password.
32
+ - **VESrecovery™** — recover from a lost key without weakening the encryption.
33
+
34
+ Also on npm: [`libves`](https://www.npmjs.com/package/libves).
35
+
36
+ ## Why VES exists
37
+
38
+ True end-to-end encryption has a brutal failure mode: **lose the key and the data is
39
+ gone forever.** That single problem is why most products quietly fall back to
40
+ server-side encryption, where the provider can read everything.
2
41
 
3
- ### Browser PIN-based e2e encryption at-rest
4
- ## Simple * Safe * Secure
42
+ VES makes the encryption keys themselves recoverable — through other devices and people
43
+ you trust — **without the VESvault service ever seeing your keys or your plaintext.**
44
+ You get real end-to-end encryption *and* a way back in when a device is lost.
5
45
 
6
- https://ves.host/docs/libVES
46
+ > **Is VESrecovery a backdoor?** No. Recovery re-shares an encrypted key along a trust
47
+ > chain *you* define (your other devices, designated recovery contacts); the server only
48
+ > ever holds ciphertext it cannot decrypt. The mechanism — and its honest trade-offs —
49
+ > are written up in the [VESrecovery design doc](https://github.com/vesvault/libVES.c/blob/master/doc/VESrecovery.md)
50
+ > and at <https://ves.host>. We welcome scrutiny of it.
7
51
 
52
+ ## Quick start
8
53
 
54
+ ```js
55
+ // Open a vault in the shared `demo` domain (use your own identity in place of
56
+ // me@example.com). unlock() runs your app's auth: the VES authorization popup
57
+ // in the browser, or the local key store under Node — see the docs for options.
58
+ const vault = libVES.subtle('//demo/me@example.com');
59
+ await vault.unlock();
60
+
61
+ // Items are addressed by URI. Encrypt + store, then read it back:
62
+ await vault.item('//demo/note-1').put('hello');
63
+ console.log(await vault.item('//demo/note-1').get()); // -> "hello"
64
+
65
+ // Share with another VES user — they decrypt with their own key
66
+ // (their vault must already exist):
67
+ await vault.item('//demo/note-1').share(['//demo/friend@example.com']);
9
68
  ```
10
- /***************************************************************************
11
- * ___ ___
12
- * / \ / \ VESvault
13
- * \__ / \ __/ Encrypt Everything without fear of losing the Key
14
- * \\ // https://vesvault.com https://ves.host
15
- * \\ //
16
- * ___ \\_//
17
- * / \ / \ libVES.subtle.js
18
- * \__ / \ __/ Manage and share e2e encrypted items
19
- * \\ // Real time event tracking
20
- * \\ // VES PKI and e2e Key Exchange
21
- * \\_// VES Redundancies and Key Recovery
22
- * / \
23
- * \___/
24
- *
25
- *
26
- * (c) 2025 VESvault Corp
27
- * Jim Zubov <jz@vesvault.com>
28
- ***************************************************************************/
29
-
30
- /***************************************************************************
31
- * @type libVES.Vault
32
- * libVES.subtle Vault Factory
33
- * Use "demo" for the public shared VES demo domain
34
- * Use "x-*" to create your own experimental domain
35
- * @returns libVES.Vault
36
- ***************************************************************************/
37
- let vesDomain = 'demo'
38
- let vault = libVES.subtle(vesDomain)
39
-
40
- /***************************************************************************
41
- * Unlock the Vault
42
- ***************************************************************************/
43
- // Unlock a User App Vault using an interactive browser popup
44
- await vault.unlock()
45
-
46
- // OR, unlock a User App Vault using locally stored credentials. Make sure
47
- // the credentials are stored securely
48
- let credentialUri = 'ves://:demo@demo/demo/'
49
- await vault.unlock(credentialUri)
50
-
51
- // OR, unlock an Anonymous App Vault using a secret passPhrase. The Vault ID
52
- // is uniquely generated from the passphrase.
53
- let passPhrase = 'passphrase'
54
- await vault.anonymous(passPhrase)
55
-
56
- // Check if the Vault is unlocked
57
- let isUnlocked = await vault.unlocked()
58
-
59
- /***************************************************************************
60
- * Get an array of all items stored in the vault
61
- * @returns Promise(Array(libVES.Item))
62
- ***************************************************************************/
63
- let items = await vault.items()
64
-
65
- /***************************************************************************
66
- * Create an Item instance
67
- * @returns libVES.Item
68
- ***************************************************************************/
69
- // Create an instance of an item with a specified itemId
70
- let itemId = 'my-test-item'
71
- let item = vault.item(itemId)
72
-
73
- // Create an instance of an item with an automatically assigned itemId
74
- let item = vault.item()
75
-
76
- /***************************************************************************
77
- * Start real time event tracking.
78
- * Call vault.addEventListener() or define vault.on* event handlers prior to
79
- * the following call. The handlers are invoked with libVES.CustomEvent
80
- ***************************************************************************/
81
- // Start tracking future events without replaying the event history
82
- await vault.start()
83
-
84
- // Or, start tracking and replay the past events starting with nextId.
85
- // Use nextId = 0 to replay all history from the beginning.
86
- let nextId = 0
87
- await vault.start(nextId)
88
-
89
- // Or, start tracking and replay the short history that includes only
90
- // currently existing items
91
- await vault.start(false)
92
-
93
- /***************************************************************************
94
- * Stop real time event tracking
95
- ***************************************************************************/
96
- vault.stop()
97
-
98
- /***************************************************************************
99
- * Get the special Item that stores the VESkey (passphrase) to the Vault.
100
- * The VESkey can be retrieved using item.get() is it is decryptable by the
101
- * unlocked Vault.
102
- * @returns Promise(libVES.Item)
103
- ***************************************************************************/
104
- let item = await vault.password()
105
-
106
- /***************************************************************************
107
- * Get the list of dependent Vaults that are directly unlockable by the
108
- * current Vault.
109
- * @returns Promise(Array(libVES.Vault))
110
- ***************************************************************************/
111
- let subVaults = await vault.vaults()
112
-
113
- /***************************************************************************
114
- * Create an instance of the specific Vault. The vaultId can be a VES URI
115
- * or a short ID. Use the owner's email address to reference a Vault within
116
- * the current VES Domain owned by the specific user.
117
- * @returns libVES.Vault
118
- ***************************************************************************/
119
- let vaultId = 'user@acme.com'
120
- let subVault = vault.vault(vaultId)
121
-
122
- /***************************************************************************
123
- * Verify the status of the Vault. This call returns a Promise that resolves
124
- * to the current vault on success, or throws libVES.Error.
125
- * The call populates vault.current and vault.owned
126
- * @returns Promise(libVES.Vault)
127
- ***************************************************************************/
128
- let vault = await subVault.verify()
129
-
130
- /***************************************************************************
131
- * The following propertiest indicate the status of the Vault. The properies
132
- * are populated by vault.unlock(), vault.verify(), and in the Vaults
133
- * returned by item.share()
134
- ***************************************************************************/
135
- // The Vault currently exists, and is not in a Lost status
136
- // @type boolean
137
- vault.current
138
-
139
- // The Vault/Subvault is owned by the unlocked Vault.
140
- // @type boolean
141
- vault.owner
142
-
143
- // The Vault has an Admin permission on the Item. This property is populated
144
- // only in the Vaults returned by item.share()
145
- // @type boolean
146
- vault.admin
147
-
148
- /***************************************************************************
149
- * Get a VES URI that idenitfies the Vault.
150
- * @returns string
151
- ***************************************************************************/
152
- vault.uri()
153
-
154
- /***************************************************************************
155
- * Get a short identifier of the Vault. Note that the short identifier is
156
- * specific to the selected VES domain. Use vault.uri() to get a full
157
- * identifier that includes the VES domain.
158
- * @returns string
159
- ***************************************************************************/
160
- vault.short()
161
-
162
- /***************************************************************************
163
- * Lock the Vault
164
- ***************************************************************************/
165
- // Set the lock timeout in seconds. The Vault will be automatically locked
166
- // when the timeout expires. Register a handler for an "authexpire" event to
167
- // catch the expiration before the Vault is locked.
168
- // Any call to this function overrides the previously set timeout.
169
- let tmOut = 300
170
- vault.lock(tmOut)
171
-
172
- // Lock the Vault immediately
173
- vault.lock()
174
-
175
- /***************************************************************************
176
- * @type libVES.Item
177
- * Store a value in the item. The value is stored in the VES Repository an
178
- * e2e encrypted form.
179
- ***************************************************************************/
180
- let itemValue = 'secret'
181
- await item.put(itemValue)
182
-
183
- /***************************************************************************
184
- * Retrieve the value stored in the item
185
- * @returns Promise(string)
186
- ***************************************************************************/
187
- let itemValue = await item.get()
188
-
189
- /***************************************************************************
190
- * Manage the item sharing with other vaults in an e2e encrypted form
191
- ***************************************************************************/
192
- // Share the item with other vaults, keep any existing sharing
193
- let vaultIds = ['user@acme.com']
194
- await item.add(vaultIds)
195
-
196
- // Remove sharing with the specified Vaults.
197
- // Note: The current Vault can be removed if it doesn't own the Item.
198
- // Removing will make the Item unaccessible through the current Vault,
199
- // unless shared again by the Item owner.
200
- let vaultIds = ['user@acme.com']
201
- await item.remove(vaultIds)
202
-
203
- // Replace the list of vaults the Item is shared with. The current Vault is
204
- // added automatically if not included.
205
- let vaultIds = ['user@acme.com']
206
- await item.share(vaultIds)
207
-
208
- // Get the list of vaults the Item is currently shared with
209
- // @returns Promise(Array(libVES.Vault))
210
- let shares = await item.share()
211
-
212
- // Check whether the item is shared with a specific Vault. Returns null if
213
- // not shared.
214
- // @returns Promise(libVES.Vault)
215
- let vaultId = 'user@acme.com'
216
- let theShare = await item.shareFor(vaultId)
217
-
218
- /***************************************************************************
219
- * Check if the item currently exists and was not deleted.
220
- * @returns boolean
221
- ***************************************************************************/
222
- let exists = await item.exists()
223
-
224
- /***************************************************************************
225
- * Delete the item. The item ID can be reused for another item.
226
- ***************************************************************************/
227
- await item.delete()
228
-
229
- /***************************************************************************
230
- * Start real time event tracking.
231
- * Call item.addEventListener() or define item.on* event handlers prior to
232
- * the following call. The handlers are invoked with libVES.CustomEvent
233
- ***************************************************************************/
234
-
235
- // Start tracking future events without replaying the event history
236
- await item.start()
237
-
238
- // Or, start tracking and replay the past events starting with nextId.
239
- // Use nextId = 0 to replay all history from the beginning.
240
- let nextId = 0
241
- await item.start(nextId)
242
-
243
- // Or, start tracking and replay the short history that includes only
244
- // the Vaults the Item is currently shared with
245
- await item.start(false)
246
-
247
- /***************************************************************************
248
- * Stop real time event tracking
249
- ***************************************************************************/
250
- item.stop()
251
-
252
- /***************************************************************************
253
- * Get a VES URI that idenitfies the Item.
254
- * @returns string
255
- ***************************************************************************/
256
- item.uri()
257
-
258
- /***************************************************************************
259
- * Get a short identifier of the Item. Note that the short identifier is
260
- * specific to the selected VES domain. Use item.uri() to get a full
261
- * identifier that includes the VES domain.
262
- * @returns string
263
- ***************************************************************************/
264
- item.short()
265
-
266
- /***************************************************************************
267
- * Check if the Item value can be retrieved and decrypted by the currently
268
- * unlocked Vault.
269
- * @returns boolean
270
- ***************************************************************************/
271
- let isReadable = await item.readable()
272
-
273
- /***************************************************************************
274
- * Check if the Item value can be overwritten by the currently unlocked
275
- * Vault.
276
- * @returns boolean
277
- ***************************************************************************/
278
- let isWritable = await item.writable()
279
-
280
- /***************************************************************************
281
- * Use the Item as a stream cipher for encrypting and decrypting arbitrary
282
- * data. If the Item is used for a cipher, the cipher key is stored in the
283
- * VES repository in an e2e encrypted form, and the Item cannot store any
284
- * other value.
285
- * @returns Promise(libVES.ItemCipher)
286
- ***************************************************************************/
287
- let itemCipher = await item.cipher()
288
-
289
-
290
- /***************************************************************************
291
- * @type libVES.ItemCipher
292
- * A stream cipher for encrypting arbitrary data. The cipher key is stored
293
- * in the VES Repository in an e2e encrypted form. The data encrypted by
294
- * the cipher can be stored at any external storage. The default cipher
295
- * algorithm is AES256GCM1K, a VES implementation based on AES-256 GCM.
296
- * The plaintext and ciphertext data can be ArrayBuffer, Uint*Array,
297
- * Int*Array, Blob or string. The type of the return value of encrypt() and
298
- * decrypt() conforms to the type of the input value. If the type is string,
299
- * the ciphertext is Base64 encoded.
300
- ***************************************************************************/
301
- // Encrypt the data
302
- let plainText = 'The secret text'
303
- let cipherText = await itemCipher.encrypt(plainText)
304
-
305
- // Decrypt the data
306
- let plainText = await itemCipher.decrypt(cipherText)
307
-
308
- /***************************************************************************
309
- * An arbitrary metadata object associated with the cipher. The metadata is
310
- * stored in the VES Repository in an e2e encrypted form along with the
311
- * cipher key.
312
- ***************************************************************************/
313
- // Store metadata
314
- let cipherMeta = {myValue: 'Metadata String'}
315
- await itemCipher.meta(cipherMeta)
316
-
317
- // Retrieve metadata
318
- let cipherMeta = await itemCipher.meta()
319
-
320
-
321
- /***************************************************************************
322
- * @type libVES.CustomEvent
323
- * An event related to a Vault or an Item, current or hitorical. VES stores
324
- * a history of essential events for all objects.
325
- *
326
- * Event types:
327
- * "authexpire" : the Vault will be imminently locked unless an action
328
- * is taken. The event handler may call vault.lock(tmOut)
329
- * to extend the unlocked time by tmOut seconds. This
330
- * event is real time only, not stored in the history
331
- * "vaultcreate" : a Vault is created
332
- * "vaultadd" : the Item that stores the passphrase to a Vault is
333
- * shared with another Vault
334
- * "vaultremove" : the Item that stores the passphrase to a Vault is
335
- * unshared with another Vault
336
- * "itemcreate" : an Item is created
337
- * "itemadd" : an Item is shared with a Vault
338
- * "itemremove" : an Item is unshared with a Vault
339
- * "itemdelete" : an Item is deleted
340
- * "itemchange" : an Item has been changed. This event is delivered to
341
- * each Vault the Item is shared with that are currently
342
- * listening to real time events. The event does not
343
- * have historical value and is not guaranteed to be
344
- * permanently stored by VES.
345
- * "olditemadd" : a historical (deleted) version of the Item is shared
346
- * with a Vault. Historical versions are not guaranteed
347
- * to be permanently stored in the VES Repository.
348
- * "olditemremove" : a historical version of the Item is unshared with a
349
- * Vault
350
- * "sessioncreate" : the vault has been unlocked, a new session is created
351
- ***************************************************************************/
352
- vesEvent.type
353
-
354
- /***************************************************************************
355
- * Event details dictionary
356
- ***************************************************************************/
357
- vesEvent.detail
358
-
359
- // @type libVES.Item
360
- // The Item pertaining to the Event. Populated for "item*" and "olditem*"
361
- // event types.
362
- vesEvent.detail.item
363
-
364
- // @type libVES.Vault
365
- // The Vault pertaining to the event that the Item was shared or unshared
366
- // with. Populated for "*add" and "*remove" event types.
367
- vesEvent.detail.share
368
-
369
- // @type libVES.Vault
370
- // The Vault pertaining to the Event, the passphrase Item to which was
371
- // shared or unshared with another Vault, or an action was taken on.
372
- // Populated for "vault*" and "authexpire" event types.
373
- vesEvent.detail.vault
374
-
375
- // @type libVES.Author
376
- // The Session that authored the changes triggering the Event
377
- let vesSession = vesEvent.detail.author
378
-
379
- // @type libVES.Author
380
- // The Session subject to the Event. Populated only for "session*" event
381
- // types.
382
- let vesSession = vesEvent.detail.session
383
-
384
- // @type int
385
- // A unique numeric ID of the Event. Not populated on provisional Events
386
- // (when replay == true).
387
- vesEvent.detail.id
388
-
389
- // @type Date
390
- // The timestamp of the Event. Not populated on provisional Events (when
391
- // replay == true).
392
- vesEvent.detail.at
393
-
394
- // @type boolean
395
- // If set to true, the Event is provisional, and does not correspond to
396
- // any Event stored in VES. Provisional events are generated by
397
- // vault.start(false) or item.start(false) to replay the short history
398
- // that leads to the current state of the Vault / Item.
399
- vesEvent.detail.replay
400
-
401
- /***************************************************************************
402
- * @type libVES.Author
403
- * A VES session pertaining to an authenticated App Vault or to a VES User.
404
- * The details of the session can only be retrieved by a Session with the
405
- * same owner. Historical Session details are not guaranteed to be
406
- * permanently stored in VES.
407
- ***************************************************************************/
408
-
409
- // @type int
410
- // A unique numeric Session ID
411
- vesSession.sessid
412
-
413
- // @type libVES.Vault
414
- // The Vault that is authorized for the Session
415
- vesSession.vault
416
-
417
- // @type string
418
- // An IPv4 or IPv6 address of the creator of the Session
419
- vesSession.remote
420
-
421
- // @type string
422
- // A User Agent string passed to the API call that created the Session
423
- vesSession.userAgent
69
+
70
+ `put()` / `get()` / `share()` handle the encryption, key exchange, and API calls for
71
+ you. Full API reference: <https://ves.host/docs/libVES-subtle>.
72
+
73
+ > **Domains.** A VES *domain* (the `demo` above) namespaces vaults and items. It may
74
+ > mirror a DNS domain, but it must be registered in VES first. Two kinds work without
75
+ > registration: **`demo`** — a shared sandbox, used in the examples here — and **`x-…`**
76
+ > — experimental domains (any name beginning with `x-`) that are created automatically
77
+ > on first use, giving you a private namespace to build against. Any other (real DNS)
78
+ > domain returns an error until it is registered through VES Enterprise.
79
+
80
+ Runnable end-to-end examples live in [`tests/`](tests/) (`01-item.js`, `02-share.js`,
81
+ …) and can be run with `node tests/01-item.js` or opened in the browser via
82
+ `tests/index.html`.
83
+
84
+ ## Install
85
+
86
+ ```sh
87
+ npm install libves
88
+ ```
89
+
90
+ Or build from source (see below) and load `libVES-<version>.js` with a `<script>` tag.
91
+
92
+ ## Building
93
+
94
+ - `node build.js` — produces version-stamped `libVES-<version>.js` (browser) and
95
+ `libVES-<version>.node.js` (Node) for CDN/`<script>` delivery, plus stable `libVES.js`
96
+ and `libVES.node.js` (the npm `browser` / `main` entry points). Cross-platform;
97
+ `Makefile.bat` and `make all` both call it.
98
+ - `node build.js --minify` — also writes `libVES-<version>.min.js` and `libVES.min.js`
99
+ (requires `npm i -D terser`).
100
+ - Requires **Node 18+** (uses the built-in `fetch`).
101
+
102
+ ### Wasm builds
103
+
104
+ Post-quantum (ML-KEM via liboqs) and ECDH primitives are compiled to WebAssembly. See
105
+ the comments in [`WasmOQS/Makefile`](WasmOQS/Makefile) and
106
+ [`WasmECDH/Makefile`](WasmECDH/Makefile).
107
+
108
+ ## Post-quantum
109
+
110
+ The library supports post-quantum key exchange (ML-KEM / Kyber and other KEMs) via the
111
+ `libVES.Algo.OQS` module and the WasmOQS build. This matters today: "harvest now,
112
+ decrypt later" means data exchanged with classical-only keys can be captured now and
113
+ broken once quantum hardware arrives.
114
+
115
+ ## Real-time events
116
+
117
+ `libVES.Vault` and `libVES.Item` are event targets: call `.start()` and add listeners to
118
+ react to activity as it happens — an item shared with you, a key granted or revoked, a new
119
+ session opened.
120
+
121
+ ```js
122
+ vault.addEventListener('itemadd', (e) => {
123
+ console.log('shared with me:', e.detail.item.uri());
124
+ });
125
+ vault.start(); // begin watching; vault.stop() to end
424
126
  ```
127
+
128
+ Useful for live UI updates, notifications, and reacting to shares and revocations without
129
+ polling your own state. (`libVES.Watch` is the lower-level long-poll primitive underneath.)
130
+
131
+ ## Pricing & terms
132
+
133
+ VES has a **free tier**; paid usage is **priced by volume**. The library is free and
134
+ open source under the Apache License 2.0. See current terms and pricing at
135
+ <https://ves.host/terms_conditions> and <https://vesvault.com>.
136
+
137
+ ## Contributing
138
+
139
+ Bug reports and small, focused fixes are welcome via issues and pull requests. Because
140
+ this is security-critical software backed by a hosted service, larger changes — new
141
+ cryptography, API-surface or protocol changes — should **start with an issue** before you
142
+ write code; we can't always merge changes that affect the protocol or the service. See
143
+ [CONTRIBUTING.md](CONTRIBUTING.md) for build, syntax-check, and test details, and our
144
+ [Code of Conduct](CODE_OF_CONDUCT.md).
145
+
146
+ Security issues are different: **please don't open a public issue or PR** — follow
147
+ [SECURITY.md](SECURITY.md).
148
+
149
+ ## License
150
+
151
+ Apache License 2.0 — see [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE). Copyright © 2017–2026
152
+ VESvault Corp.
153
+
154
+ ## Links
155
+
156
+ - Documentation — <https://ves.host>
157
+ - JavaScript API reference — <https://ves.host/docs/libVES-subtle>
158
+ - npm — <https://www.npmjs.com/package/libves>
159
+ - C library & `ves` CLI — <https://ves.host/docs/libVES-c>