asherah 4.0.25 → 4.0.27
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 +241 -17
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -2,16 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Node.js bindings for the Asherah envelope encryption and key rotation library.
|
|
4
4
|
|
|
5
|
-
Prebuilt native binaries are published to npm for Linux (x64/
|
|
6
|
-
musl), macOS (x64/
|
|
7
|
-
selected automatically at install time.
|
|
8
|
-
|
|
9
|
-
## Features
|
|
10
|
-
|
|
11
|
-
- Synchronous and asynchronous encrypt/decrypt APIs
|
|
12
|
-
- Compatible with Go, Python, Ruby, Java, and .NET Asherah implementations
|
|
13
|
-
- SQLite, MySQL, PostgreSQL, and DynamoDB metastore support
|
|
14
|
-
- AWS KMS and static key management
|
|
5
|
+
Prebuilt native binaries are published to npm for Linux (x64/ARM64, glibc and
|
|
6
|
+
musl), macOS (x64/ARM64), and Windows (x64/ARM64). The correct binary is
|
|
7
|
+
selected automatically at install time. No compilation needed.
|
|
15
8
|
|
|
16
9
|
## Installation
|
|
17
10
|
|
|
@@ -19,24 +12,255 @@ selected automatically at install time.
|
|
|
19
12
|
npm install asherah
|
|
20
13
|
```
|
|
21
14
|
|
|
22
|
-
|
|
15
|
+
Requires Node.js >= 18.
|
|
16
|
+
|
|
17
|
+
## Quick Start (Static API)
|
|
18
|
+
|
|
19
|
+
The static API uses a global singleton. Call `setup()` once, then `encrypt`/`decrypt` from anywhere.
|
|
23
20
|
|
|
24
21
|
```js
|
|
25
22
|
const asherah = require('asherah');
|
|
26
23
|
|
|
24
|
+
// Static master key for local development only.
|
|
25
|
+
// In production, use kms: 'aws' with a region map.
|
|
26
|
+
process.env.STATIC_MASTER_KEY_HEX = '22'.repeat(32);
|
|
27
|
+
|
|
27
28
|
asherah.setup({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
serviceName: 'my-service',
|
|
30
|
+
productId: 'my-product',
|
|
31
|
+
metastore: 'memory', // testing only
|
|
32
|
+
kms: 'static', // testing only
|
|
33
|
+
enableSessionCaching: true,
|
|
32
34
|
});
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
+
// Encrypt raw bytes
|
|
37
|
+
const ciphertext = asherah.encrypt('my-partition', Buffer.from('secret data'));
|
|
38
|
+
const plaintext = asherah.decrypt('my-partition', ciphertext);
|
|
39
|
+
console.log(plaintext.toString()); // 'secret data'
|
|
40
|
+
|
|
41
|
+
// Or use the string convenience methods
|
|
42
|
+
const ct = asherah.encryptString('my-partition', 'hello world');
|
|
43
|
+
const pt = asherah.decryptString('my-partition', ct);
|
|
44
|
+
console.log(pt); // 'hello world'
|
|
36
45
|
|
|
37
46
|
asherah.shutdown();
|
|
38
47
|
```
|
|
39
48
|
|
|
49
|
+
## Session-Based API
|
|
50
|
+
|
|
51
|
+
The `SessionFactory` / `AsherahSession` pattern is preferred for production. It
|
|
52
|
+
avoids the global singleton and gives you explicit control over session
|
|
53
|
+
lifetimes.
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
const { SessionFactory } = require('asherah');
|
|
57
|
+
|
|
58
|
+
process.env.STATIC_MASTER_KEY_HEX = '22'.repeat(32);
|
|
59
|
+
|
|
60
|
+
const factory = new SessionFactory({
|
|
61
|
+
serviceName: 'my-service',
|
|
62
|
+
productId: 'my-product',
|
|
63
|
+
metastore: 'memory', // testing only
|
|
64
|
+
kms: 'static', // testing only
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const session = factory.getSession('my-partition');
|
|
68
|
+
|
|
69
|
+
const ct = session.encrypt(Buffer.from('secret'));
|
|
70
|
+
const pt = session.decrypt(ct);
|
|
71
|
+
console.log(pt.toString()); // 'secret'
|
|
72
|
+
|
|
73
|
+
// String variants
|
|
74
|
+
const ct2 = session.encryptString('hello');
|
|
75
|
+
const pt2 = session.decryptString(ct2);
|
|
76
|
+
console.log(pt2); // 'hello'
|
|
77
|
+
|
|
78
|
+
session.close();
|
|
79
|
+
factory.close();
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
You can also create a factory from environment variables:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
const factory = SessionFactory.fromEnv();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Async API
|
|
89
|
+
|
|
90
|
+
Every sync function has an async counterpart that returns a Promise and never
|
|
91
|
+
blocks the Node.js event loop.
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
const asherah = require('asherah');
|
|
95
|
+
|
|
96
|
+
process.env.STATIC_MASTER_KEY_HEX = '22'.repeat(32);
|
|
97
|
+
|
|
98
|
+
await asherah.setupAsync({
|
|
99
|
+
serviceName: 'my-service',
|
|
100
|
+
productId: 'my-product',
|
|
101
|
+
metastore: 'memory', // testing only
|
|
102
|
+
kms: 'static', // testing only
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const ct = await asherah.encryptStringAsync('my-partition', 'secret');
|
|
106
|
+
const pt = await asherah.decryptStringAsync('my-partition', ct);
|
|
107
|
+
console.log(pt); // 'secret'
|
|
108
|
+
|
|
109
|
+
await asherah.shutdownAsync();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Async Behavior
|
|
113
|
+
|
|
114
|
+
Async operations run on a Rust tokio runtime, separate from the Node.js event
|
|
115
|
+
loop. The exact execution strategy depends on the metastore:
|
|
116
|
+
|
|
117
|
+
| Metastore | Async Encrypt/Decrypt | Blocks Event Loop? |
|
|
118
|
+
|-----------|----------------------|-------------------|
|
|
119
|
+
| In-Memory | Runs on tokio worker thread | No |
|
|
120
|
+
| DynamoDB | True async AWS SDK calls on tokio | No |
|
|
121
|
+
| MySQL | `spawn_blocking` (sync driver on tokio thread pool) | No |
|
|
122
|
+
| Postgres | `spawn_blocking` (sync driver on tokio thread pool) | No |
|
|
123
|
+
|
|
124
|
+
**Async never blocks the Node.js event loop.** The tradeoff is ~12us overhead
|
|
125
|
+
per async call vs ~1us for sync (hot cache, 64B payload). Use sync in tight
|
|
126
|
+
loops where latency matters; use async when you need to keep the event loop
|
|
127
|
+
responsive.
|
|
128
|
+
|
|
129
|
+
## Configuration
|
|
130
|
+
|
|
131
|
+
Pass a config object to `setup()`, `setupAsync()`, or the `SessionFactory`
|
|
132
|
+
constructor. Both camelCase and PascalCase field names are accepted (PascalCase
|
|
133
|
+
is auto-mapped for backward compatibility with the canonical Go-based package).
|
|
134
|
+
|
|
135
|
+
| Field | Type | Default | Description |
|
|
136
|
+
|-------|------|---------|-------------|
|
|
137
|
+
| `serviceName` | `string` | **(required)** | Service identifier for key hierarchy |
|
|
138
|
+
| `productId` | `string` | **(required)** | Product identifier for key hierarchy |
|
|
139
|
+
| `metastore` | `string` | **(required)** | `"rdbms"`, `"dynamodb"`, `"memory"` (testing) |
|
|
140
|
+
| `kms` | `string` | `"static"` | `"static"` or `"aws"` |
|
|
141
|
+
| `connectionString` | `string` | | Connection string for sqlite or rdbms metastore |
|
|
142
|
+
| `sqlMetastoreDBType` | `string` | | `"mysql"` or `"postgres"` (for rdbms metastore) |
|
|
143
|
+
| `enableSessionCaching` | `boolean` | `true` | Cache sessions by partition ID |
|
|
144
|
+
| `sessionCacheMaxSize` | `number` | `1000` | Max cached sessions |
|
|
145
|
+
| `sessionCacheDuration` | `number` | | Session cache TTL in milliseconds |
|
|
146
|
+
| `regionMap` | `object` | | `{ "us-west-2": "arn:aws:kms:..." }` for AWS KMS multi-region |
|
|
147
|
+
| `preferredRegion` | `string` | | Preferred AWS region for KMS |
|
|
148
|
+
| `enableRegionSuffix` | `boolean` | | Append region suffix to system key IDs |
|
|
149
|
+
| `expireAfter` | `number` | | Key expiration in milliseconds |
|
|
150
|
+
| `checkInterval` | `number` | | Key rotation check interval in milliseconds |
|
|
151
|
+
| `dynamoDBEndpoint` | `string` | | Custom DynamoDB endpoint URL |
|
|
152
|
+
| `dynamoDBRegion` | `string` | | DynamoDB region |
|
|
153
|
+
| `dynamoDBTableName` | `string` | | DynamoDB table name |
|
|
154
|
+
| `replicaReadConsistency` | `string` | | DynamoDB read consistency |
|
|
155
|
+
| `verbose` | `boolean` | `false` | Enable debug logging |
|
|
156
|
+
| `enableCanaries` | `boolean` | | Enable canary key verification |
|
|
157
|
+
| `disableZeroCopy` | `boolean` | | Disable zero-copy optimizations |
|
|
158
|
+
| `nullDataCheck` | `boolean` | | Verify data is not null before decrypt |
|
|
159
|
+
|
|
160
|
+
### Environment Variables
|
|
161
|
+
|
|
162
|
+
- `STATIC_MASTER_KEY_HEX` -- 64 hex chars (32 bytes) for static KMS. **Testing only.**
|
|
163
|
+
- `ASHERAH_NODE_DEBUG=1` -- Enable native debug logging.
|
|
164
|
+
|
|
165
|
+
## Performance
|
|
166
|
+
|
|
167
|
+
This is a native Rust implementation compiled via napi-rs. Typical latencies on
|
|
168
|
+
Apple M4 Max (in-memory metastore, session caching enabled, 64-byte payload):
|
|
169
|
+
|
|
170
|
+
| Operation | Sync | Async |
|
|
171
|
+
|-----------|------|-------|
|
|
172
|
+
| Encrypt | ~970 ns | ~12 us |
|
|
173
|
+
| Decrypt | ~1,200 ns | ~12 us |
|
|
174
|
+
|
|
175
|
+
See `scripts/benchmark.sh` for head-to-head comparisons with the canonical
|
|
176
|
+
Go-based implementation.
|
|
177
|
+
|
|
178
|
+
## Migration from Canonical (v3.x)
|
|
179
|
+
|
|
180
|
+
This package is a drop-in replacement for the Go-based `asherah` npm package
|
|
181
|
+
(v3.x). The JavaScript wrapper provides full backward compatibility:
|
|
182
|
+
|
|
183
|
+
- **PascalCase config** -- `ServiceName`, `ProductID`, `Metastore`, etc. are
|
|
184
|
+
auto-mapped to camelCase equivalents.
|
|
185
|
+
- **snake_case function aliases** -- `set_log_hook`, `get_setup_status`,
|
|
186
|
+
`encrypt_string`, `decrypt_string_async`, etc. all work.
|
|
187
|
+
- **Metastore/KMS aliases** -- `"test-debug-memory"`, `"test-debug-static"`,
|
|
188
|
+
etc. are normalized to their short forms.
|
|
189
|
+
- **`set_log_hook` callback signature** -- Both the canonical
|
|
190
|
+
`(level: number, message: string)` and the native
|
|
191
|
+
`(event: { level, message, target })` signatures are supported.
|
|
192
|
+
|
|
193
|
+
To migrate, update your package version. No code changes required.
|
|
194
|
+
|
|
195
|
+
## Supported Platforms
|
|
196
|
+
|
|
197
|
+
| Platform | Architecture | Notes |
|
|
198
|
+
|----------|-------------|-------|
|
|
199
|
+
| Linux | x64 | glibc (most distros) |
|
|
200
|
+
| Linux | x64 | musl (Alpine) |
|
|
201
|
+
| Linux | ARM64 | glibc |
|
|
202
|
+
| Linux | ARM64 | musl (Alpine) |
|
|
203
|
+
| macOS | x64 | Intel Macs |
|
|
204
|
+
| macOS | ARM64 | Apple Silicon |
|
|
205
|
+
| Windows | x64 | MSVC |
|
|
206
|
+
| Windows | ARM64 | MSVC |
|
|
207
|
+
|
|
208
|
+
## API Reference
|
|
209
|
+
|
|
210
|
+
### Setup / Teardown
|
|
211
|
+
|
|
212
|
+
- `setup(config)` -- Initialize the global Asherah instance.
|
|
213
|
+
- `setupAsync(config)` -- Async variant of `setup`.
|
|
214
|
+
- `shutdown()` -- Shut down and release all resources.
|
|
215
|
+
- `shutdownAsync()` -- Async variant of `shutdown`.
|
|
216
|
+
- `getSetupStatus()` -- Returns `true` if `setup` has been called.
|
|
217
|
+
|
|
218
|
+
### Encrypt / Decrypt (Static API)
|
|
219
|
+
|
|
220
|
+
- `encrypt(partitionId, data: Buffer)` -- Returns JSON string (DataRowRecord).
|
|
221
|
+
- `encryptAsync(partitionId, data: Buffer)` -- Async variant.
|
|
222
|
+
- `encryptString(partitionId, data: string)` -- String-in, string-out convenience.
|
|
223
|
+
- `encryptStringAsync(partitionId, data: string)` -- Async variant.
|
|
224
|
+
- `decrypt(partitionId, dataRowRecord: string | Buffer)` -- Returns `Buffer`.
|
|
225
|
+
- `decryptAsync(partitionId, dataRowRecord: string | Buffer)` -- Async variant.
|
|
226
|
+
- `decryptString(partitionId, dataRowRecord: string)` -- Returns `string`.
|
|
227
|
+
- `decryptStringAsync(partitionId, dataRowRecord: string)` -- Async variant.
|
|
228
|
+
|
|
229
|
+
### Session-Based API
|
|
230
|
+
|
|
231
|
+
- `new SessionFactory(config)` -- Create a factory with explicit config.
|
|
232
|
+
- `SessionFactory.fromEnv()` -- Create a factory from environment variables.
|
|
233
|
+
- `factory.getSession(partitionId)` -- Get a session for a partition.
|
|
234
|
+
- `factory.close()` -- Close the factory and release resources.
|
|
235
|
+
- `session.encrypt(data: Buffer)` -- Returns JSON string.
|
|
236
|
+
- `session.encryptString(data: string)` -- String convenience.
|
|
237
|
+
- `session.decrypt(dataRowRecord: string)` -- Returns `Buffer`.
|
|
238
|
+
- `session.decryptString(dataRowRecord: string)` -- Returns `string`.
|
|
239
|
+
- `session.close()` -- Close the session.
|
|
240
|
+
|
|
241
|
+
### Hooks
|
|
242
|
+
|
|
243
|
+
- `setLogHook(callback)` / `set_log_hook(callback)` -- Receive log events.
|
|
244
|
+
Pass `null` to disable.
|
|
245
|
+
- `setMetricsHook(callback)` -- Receive metrics events
|
|
246
|
+
(`{ type, durationNs?, name? }`). Pass `null` to disable.
|
|
247
|
+
|
|
248
|
+
### Utility
|
|
249
|
+
|
|
250
|
+
- `setenv(lines: string)` -- Set environment variables from `KEY=VALUE` lines.
|
|
251
|
+
- `setMaxStackAllocItemSize(n)` -- No-op (compatibility stub).
|
|
252
|
+
- `setSafetyPaddingOverhead(n)` -- No-op (compatibility stub).
|
|
253
|
+
|
|
254
|
+
## Features
|
|
255
|
+
|
|
256
|
+
- Synchronous and asynchronous encrypt/decrypt APIs
|
|
257
|
+
- Session-based API with factory pattern
|
|
258
|
+
- Compatible with Go, Python, Ruby, Java, and .NET Asherah implementations
|
|
259
|
+
- SQLite, MySQL, PostgreSQL, and DynamoDB metastore support
|
|
260
|
+
- AWS KMS and static key management
|
|
261
|
+
- Log and metrics hooks
|
|
262
|
+
- Automatic key rotation with configurable intervals
|
|
263
|
+
|
|
40
264
|
## License
|
|
41
265
|
|
|
42
266
|
Licensed under the Apache License, Version 2.0.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "asherah",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.27",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Asherah envelope encryption and key rotation library",
|
|
6
6
|
"main": "npm/index.js",
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
"node": ">= 18"
|
|
41
41
|
},
|
|
42
42
|
"optionalDependencies": {
|
|
43
|
-
"asherah-darwin-arm64": "4.0.
|
|
44
|
-
"asherah-darwin-x64": "4.0.
|
|
45
|
-
"asherah-linux-x64-gnu": "4.0.
|
|
46
|
-
"asherah-linux-arm64-gnu": "4.0.
|
|
47
|
-
"asherah-linux-x64-musl": "4.0.
|
|
48
|
-
"asherah-linux-arm64-musl": "4.0.
|
|
49
|
-
"asherah-windows-x64": "4.0.
|
|
50
|
-
"asherah-windows-arm64": "4.0.
|
|
43
|
+
"asherah-darwin-arm64": "4.0.27",
|
|
44
|
+
"asherah-darwin-x64": "4.0.27",
|
|
45
|
+
"asherah-linux-x64-gnu": "4.0.27",
|
|
46
|
+
"asherah-linux-arm64-gnu": "4.0.27",
|
|
47
|
+
"asherah-linux-x64-musl": "4.0.27",
|
|
48
|
+
"asherah-linux-arm64-musl": "4.0.27",
|
|
49
|
+
"asherah-windows-x64": "4.0.27",
|
|
50
|
+
"asherah-windows-arm64": "4.0.27"
|
|
51
51
|
}
|
|
52
52
|
}
|