asherah 4.0.40 → 4.0.42
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/index.d.ts +40 -4
- package/npm/index.js +25 -4
- package/package.json +13 -12
package/index.d.ts
CHANGED
|
@@ -169,7 +169,7 @@ export type AsherahConfigCompat = {
|
|
|
169
169
|
* serviceName: 'my-svc',
|
|
170
170
|
* productId: 'my-prod',
|
|
171
171
|
* metastore: 'memory', // production: 'rdbms' or 'dynamodb'
|
|
172
|
-
* kms: 'static', // production: 'aws'
|
|
172
|
+
* kms: 'test-debug-static', // production: 'aws'
|
|
173
173
|
* });
|
|
174
174
|
* ```
|
|
175
175
|
*
|
|
@@ -230,11 +230,20 @@ export declare function setenv(env: string): void;
|
|
|
230
230
|
* const drr = asherah.encrypt('user-42', Buffer.from('secret'));
|
|
231
231
|
* // store drr in your database
|
|
232
232
|
* ```
|
|
233
|
+
*
|
|
234
|
+
* **Blocking the Node.js event loop**: this function runs on the JS
|
|
235
|
+
* thread and synchronously waits for the metastore (MySQL/Postgres/
|
|
236
|
+
* DynamoDB) and KMS round-trips. While it executes no other JavaScript
|
|
237
|
+
* — timers, network callbacks, GC scheduling — can run. For any
|
|
238
|
+
* production workload that touches the network on a cache miss, prefer
|
|
239
|
+
* {@link encryptAsync}, which offloads to the Rust tokio runtime and
|
|
240
|
+
* keeps the event loop responsive.
|
|
233
241
|
*/
|
|
234
242
|
export declare function encrypt(partitionId: string, data: Buffer): string;
|
|
235
243
|
|
|
236
244
|
/** Async variant of {@link encrypt}. The work runs on the Rust tokio
|
|
237
|
-
* runtime; the Node event loop is NOT blocked.
|
|
245
|
+
* runtime; the Node event loop is NOT blocked. Prefer this in any
|
|
246
|
+
* service that handles concurrent requests. */
|
|
238
247
|
export declare function encryptAsync(partitionId: string, data: Buffer): Promise<string>;
|
|
239
248
|
|
|
240
249
|
/**
|
|
@@ -248,10 +257,16 @@ export declare function encryptAsync(partitionId: string, data: Buffer): Promise
|
|
|
248
257
|
* @throws TypeError if either argument is null/undefined.
|
|
249
258
|
* @throws Error if the JSON is malformed, the partition doesn't match,
|
|
250
259
|
* the parent key has been revoked, or the AEAD tag fails.
|
|
260
|
+
*
|
|
261
|
+
* **Blocking the Node.js event loop**: like {@link encrypt}, this runs
|
|
262
|
+
* synchronously on the JS thread and waits for any metastore/KMS calls.
|
|
263
|
+
* Use {@link decryptAsync} in services that handle concurrent traffic.
|
|
251
264
|
*/
|
|
252
265
|
export declare function decrypt(partitionId: string, dataRowRecordJson: string): Buffer;
|
|
253
266
|
|
|
254
|
-
/** Async variant of {@link decrypt}.
|
|
267
|
+
/** Async variant of {@link decrypt}. The work runs on the Rust tokio
|
|
268
|
+
* runtime; the Node event loop stays responsive. Prefer this in any
|
|
269
|
+
* service that handles concurrent requests. */
|
|
255
270
|
export declare function decryptAsync(partitionId: string, dataRowRecordJson: string): Promise<Buffer>;
|
|
256
271
|
|
|
257
272
|
/** UTF-8 string-typed wrapper around {@link encrypt}. Empty `string`
|
|
@@ -267,6 +282,27 @@ export declare function decryptString(partitionId: string, dataRowRecordJson: st
|
|
|
267
282
|
/** Async variant of {@link decryptString}. */
|
|
268
283
|
export declare function decryptStringAsync(partitionId: string, dataRowRecordJson: string): Promise<string>;
|
|
269
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Best-effort wipe of a plaintext `Buffer` returned by {@link decrypt}
|
|
287
|
+
* or {@link decryptAsync}.
|
|
288
|
+
*
|
|
289
|
+
* The native (Rust) buffer is volatile-wiped before the Buffer reaches
|
|
290
|
+
* JavaScript, but the V8 `Buffer` lives on the JS heap where the GC may
|
|
291
|
+
* have already copied the bytes during compaction. Pass the Buffer here
|
|
292
|
+
* to overwrite its current backing store with zeros via
|
|
293
|
+
* `buffer.fill(0)`. Mirrors `Zeroize([]byte)` in the Go binding,
|
|
294
|
+
* `AsherahSession.ZeroizePlaintext(byte[])` in .NET, and
|
|
295
|
+
* `Asherah.clearPlaintext(byte[])` in Java.
|
|
296
|
+
*
|
|
297
|
+
* **Caveat:** treat the plaintext as opaque within a tight scope and
|
|
298
|
+
* never copy or substring it before clearing — V8 may have aliased
|
|
299
|
+
* portions of the underlying ArrayBuffer that this call doesn't reach.
|
|
300
|
+
*
|
|
301
|
+
* T-finding "Node has no parallel `clearPlaintext`" in
|
|
302
|
+
* `docs/review-2026-05-05-findings.md`.
|
|
303
|
+
*/
|
|
304
|
+
export declare function clearPlaintext(plaintext: Buffer | null | undefined): void;
|
|
305
|
+
|
|
270
306
|
// ─── Factory / Session API (recommended) ────────────────────────────────────
|
|
271
307
|
|
|
272
308
|
/**
|
|
@@ -280,7 +316,7 @@ export declare function decryptStringAsync(partitionId: string, dataRowRecordJso
|
|
|
280
316
|
* serviceName: 'my-svc',
|
|
281
317
|
* productId: 'my-prod',
|
|
282
318
|
* metastore: 'memory',
|
|
283
|
-
* kms: 'static',
|
|
319
|
+
* kms: 'test-debug-static',
|
|
284
320
|
* });
|
|
285
321
|
* const session = factory.getSession('user-42');
|
|
286
322
|
* try {
|
package/npm/index.js
CHANGED
|
@@ -152,10 +152,13 @@ const METASTORE_ALIASES = {
|
|
|
152
152
|
'test-debug-static': 'static',
|
|
153
153
|
};
|
|
154
154
|
|
|
155
|
-
// Legacy/debug KMS aliases
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
// Legacy/debug KMS aliases.
|
|
156
|
+
//
|
|
157
|
+
// The Rust core treats `static` and `test-debug-static` as synonyms
|
|
158
|
+
// — both fall back to the publicly known test key when no hex is
|
|
159
|
+
// supplied — so no JS-side normalization is needed. The map is kept
|
|
160
|
+
// as a hook for future aliases.
|
|
161
|
+
const KMS_ALIASES = {};
|
|
159
162
|
|
|
160
163
|
function normalizeConfig(config) {
|
|
161
164
|
if (!config || typeof config !== 'object') {
|
|
@@ -264,6 +267,23 @@ function decryptAsync(partitionId, dataRowRecord) {
|
|
|
264
267
|
return native.decryptAsync(partitionId, toBuffer(dataRowRecord));
|
|
265
268
|
}
|
|
266
269
|
|
|
270
|
+
// Best-effort wipe of a plaintext Buffer. The native (Rust) buffer is
|
|
271
|
+
// volatile-wiped before reaching JS; this clears the JS-side copy.
|
|
272
|
+
// V8 may have aliased portions of the ArrayBuffer that this call
|
|
273
|
+
// doesn't reach, so the wipe is best-effort. Mirrors Go's `Zeroize`,
|
|
274
|
+
// .NET's `ZeroizePlaintext`, and Java's `clearPlaintext`. T-finding
|
|
275
|
+
// "Node has no parallel clearPlaintext" in
|
|
276
|
+
// docs/review-2026-05-05-findings.md.
|
|
277
|
+
function clearPlaintext(plaintext) {
|
|
278
|
+
if (plaintext == null) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (typeof plaintext.fill !== 'function') {
|
|
282
|
+
throw new TypeError('clearPlaintext: argument must be a Buffer or Uint8Array');
|
|
283
|
+
}
|
|
284
|
+
plaintext.fill(0);
|
|
285
|
+
}
|
|
286
|
+
|
|
267
287
|
// Export everything from native addon
|
|
268
288
|
Object.assign(module.exports, native);
|
|
269
289
|
|
|
@@ -272,6 +292,7 @@ module.exports.setup = setup;
|
|
|
272
292
|
module.exports.setupAsync = setupAsync;
|
|
273
293
|
module.exports.decrypt = decrypt;
|
|
274
294
|
module.exports.decryptAsync = decryptAsync;
|
|
295
|
+
module.exports.clearPlaintext = clearPlaintext;
|
|
275
296
|
|
|
276
297
|
// snake_case aliases for canonical API compatibility
|
|
277
298
|
module.exports.setup_async = setupAsync;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "asherah",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.42",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Asherah application-layer encryption for Node.js with automatic key rotation, powered by the native Rust implementation.",
|
|
6
6
|
"author": "Jay Gowdy",
|
|
@@ -57,11 +57,12 @@
|
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "napi build",
|
|
59
59
|
"build:release": "napi build --release",
|
|
60
|
-
"test": "node test/roundtrip.js && node test/e2e-consumer.js",
|
|
61
|
-
"test:unit": "node test/roundtrip.js",
|
|
60
|
+
"test": "node test/roundtrip.js && node test/rotation.js && node test/e2e-consumer.js",
|
|
61
|
+
"test:unit": "node test/roundtrip.js && node test/rotation.js",
|
|
62
|
+
"test:rotation": "node test/rotation.js",
|
|
62
63
|
"test:e2e": "node test/e2e-consumer.js",
|
|
63
64
|
"test:e2e-aws": "node test/e2e-aws.js",
|
|
64
|
-
"test:bun": "bun test/roundtrip.js && bun test/e2e-consumer.js && bun test/bun-compat.js"
|
|
65
|
+
"test:bun": "bun test/roundtrip.js && bun test/rotation.js && bun test/e2e-consumer.js && bun test/bun-compat.js"
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
67
68
|
"@napi-rs/cli": "^2.18.0"
|
|
@@ -70,13 +71,13 @@
|
|
|
70
71
|
"node": ">= 18"
|
|
71
72
|
},
|
|
72
73
|
"optionalDependencies": {
|
|
73
|
-
"asherah-darwin-arm64": "4.0.
|
|
74
|
-
"asherah-darwin-x64": "4.0.
|
|
75
|
-
"asherah-linux-x64-gnu": "4.0.
|
|
76
|
-
"asherah-linux-arm64-gnu": "4.0.
|
|
77
|
-
"asherah-linux-x64-musl": "4.0.
|
|
78
|
-
"asherah-linux-arm64-musl": "4.0.
|
|
79
|
-
"asherah-windows-x64": "4.0.
|
|
80
|
-
"asherah-windows-arm64": "4.0.
|
|
74
|
+
"asherah-darwin-arm64": "4.0.42",
|
|
75
|
+
"asherah-darwin-x64": "4.0.42",
|
|
76
|
+
"asherah-linux-x64-gnu": "4.0.42",
|
|
77
|
+
"asherah-linux-arm64-gnu": "4.0.42",
|
|
78
|
+
"asherah-linux-x64-musl": "4.0.42",
|
|
79
|
+
"asherah-linux-arm64-musl": "4.0.42",
|
|
80
|
+
"asherah-windows-x64": "4.0.42",
|
|
81
|
+
"asherah-windows-arm64": "4.0.42"
|
|
81
82
|
}
|
|
82
83
|
}
|