lockform 3.0.0 → 3.0.1
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 +18 -18
- package/derive-key.js +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,21 +14,21 @@ npm install lockform
|
|
|
14
14
|
- **Signature verification**: Verify webhook authenticity using HMAC-SHA256 signatures
|
|
15
15
|
- **Field mapping**: Automatically map field IDs to human-readable CSV names
|
|
16
16
|
- **X25519 encryption**: Modern, fast elliptic curve cryptography
|
|
17
|
-
- **BIP39 support**: Works with 15-word
|
|
17
|
+
- **BIP39 support**: Works with 15-word passphrases or base64 private keys
|
|
18
18
|
- **TypeScript support**: Full type definitions included
|
|
19
19
|
|
|
20
20
|
## Quick Start
|
|
21
21
|
|
|
22
22
|
### Decrypting Webhook Data
|
|
23
23
|
|
|
24
|
-
You can decrypt webhooks using either your 15-word
|
|
24
|
+
You can decrypt webhooks using either your 15-word passphrase or a base64-encoded private key:
|
|
25
25
|
|
|
26
|
-
**Using
|
|
26
|
+
**Using passphrase:**
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
29
|
import { decryptWebhookData } from 'lockform'
|
|
30
30
|
|
|
31
|
-
const mnemonic = 'your fifteen word
|
|
31
|
+
const mnemonic = 'your fifteen word passphrase goes here and must be exactly fifteen words'
|
|
32
32
|
|
|
33
33
|
app.post('/webhook', async (req, res) => {
|
|
34
34
|
const payload = req.body
|
|
@@ -96,10 +96,10 @@ app.post('/webhook', async (req, res) => {
|
|
|
96
96
|
|
|
97
97
|
### `derivePrivateKey(mnemonic)`
|
|
98
98
|
|
|
99
|
-
Derives a base64-encoded X25519 private key from a 15-word BIP39
|
|
99
|
+
Derives a base64-encoded X25519 private key from a 15-word BIP39 passphrase. Useful for generating keys to use in edge functions.
|
|
100
100
|
|
|
101
101
|
**Parameters:**
|
|
102
|
-
- `mnemonic` (string): Your 15-word BIP39
|
|
102
|
+
- `mnemonic` (string): Your 15-word BIP39 passphrase
|
|
103
103
|
|
|
104
104
|
**Returns:** `string` - Base64-encoded X25519 private key
|
|
105
105
|
|
|
@@ -108,7 +108,7 @@ Derives a base64-encoded X25519 private key from a 15-word BIP39 recovery phrase
|
|
|
108
108
|
```typescript
|
|
109
109
|
import { derivePrivateKey } from 'lockform'
|
|
110
110
|
|
|
111
|
-
const mnemonic = 'your fifteen word
|
|
111
|
+
const mnemonic = 'your fifteen word passphrase goes here exactly fifteen words'
|
|
112
112
|
const privateKeyBase64 = derivePrivateKey(mnemonic)
|
|
113
113
|
|
|
114
114
|
console.log(privateKeyBase64)
|
|
@@ -125,7 +125,7 @@ Decrypts an encrypted webhook payload from Lockform using X25519 + AES-256-GCM.
|
|
|
125
125
|
|
|
126
126
|
**Parameters:**
|
|
127
127
|
- `options.payload` (WebhookPayload): The webhook payload received from Lockform
|
|
128
|
-
- `options.passphrase` (string): Your 15-word BIP39
|
|
128
|
+
- `options.passphrase` (string): Your 15-word BIP39 passphrase (or optionally, base64-encoded X25519 private key)
|
|
129
129
|
|
|
130
130
|
**Returns:** `Promise<DecryptedSubmission>`
|
|
131
131
|
|
|
@@ -272,7 +272,7 @@ app.listen(3000, () => {
|
|
|
272
272
|
|
|
273
273
|
### Deno Edge Function
|
|
274
274
|
|
|
275
|
-
**Important:** Edge functions have strict CPU time limits. Use a base64-encoded private key instead of the 15-word
|
|
275
|
+
**Important:** Edge functions have strict CPU time limits. Use a base64-encoded private key instead of the 15-word passphrase to avoid CPU timeout errors. See the performance note below.
|
|
276
276
|
|
|
277
277
|
```typescript
|
|
278
278
|
import { decryptWebhookData, verifyWebhookSignature, type WebhookPayload } from 'lockform'
|
|
@@ -290,7 +290,7 @@ Deno.serve(async (req) => {
|
|
|
290
290
|
|
|
291
291
|
if (!recoveryPhrase) {
|
|
292
292
|
return new Response(
|
|
293
|
-
JSON.stringify({ error: '
|
|
293
|
+
JSON.stringify({ error: 'Passphrase not configured' }),
|
|
294
294
|
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
|
295
295
|
)
|
|
296
296
|
}
|
|
@@ -347,8 +347,8 @@ Lockform uses modern, audited cryptography for maximum security:
|
|
|
347
347
|
## Security Best Practices
|
|
348
348
|
|
|
349
349
|
1. **Always verify signatures**: Use `verifyWebhookSignature` to ensure webhooks are genuinely from Lockform
|
|
350
|
-
2. **Protect your
|
|
351
|
-
3. **Never share your
|
|
350
|
+
2. **Protect your passphrase**: Store your 15-word passphrase in environment variables, never commit it to version control
|
|
351
|
+
3. **Never share your passphrase**: Anyone with your 15-word passphrase can decrypt all submissions
|
|
352
352
|
4. **Use HTTPS**: Always use HTTPS endpoints for webhooks in production
|
|
353
353
|
5. **Validate data**: Always validate the decrypted data before processing it
|
|
354
354
|
6. **Implement idempotency**: Use the `submission_id` to prevent duplicate processing
|
|
@@ -359,8 +359,8 @@ Lockform uses modern, audited cryptography for maximum security:
|
|
|
359
359
|
If you're migrating from the RSA-based v1.x version:
|
|
360
360
|
|
|
361
361
|
1. **Update your package**: `npm install lockform@latest`
|
|
362
|
-
2. **Update your credentials**: Use your 15-word
|
|
363
|
-
3. **Update your code**: Pass your
|
|
362
|
+
2. **Update your credentials**: Use your 15-word passphrase instead of PEM-formatted RSA keys
|
|
363
|
+
3. **Update your code**: Pass your passphrase as the `passphrase` parameter (renamed from `privateKey`)
|
|
364
364
|
|
|
365
365
|
The webhook payload structure has changed:
|
|
366
366
|
- `wrapped_key` → `ephemeral_public_key`
|
|
@@ -373,7 +373,7 @@ The webhook payload structure has changed:
|
|
|
373
373
|
|
|
374
374
|
Edge functions have strict CPU time limits (typically 50-100ms). The PBKDF2 key derivation with 600,000 iterations can take several seconds and will cause timeout errors.
|
|
375
375
|
|
|
376
|
-
**Solution:** Use a base64-encoded private key instead of the
|
|
376
|
+
**Solution:** Use a base64-encoded private key instead of the passphrase.
|
|
377
377
|
|
|
378
378
|
**Option 1: Use the CLI tool (easiest)**
|
|
379
379
|
|
|
@@ -382,14 +382,14 @@ npx lockform-derive-key
|
|
|
382
382
|
# Or if installed: npm run derive-key
|
|
383
383
|
```
|
|
384
384
|
|
|
385
|
-
This will prompt you for your
|
|
385
|
+
This will prompt you for your passphrase and output the base64 private key.
|
|
386
386
|
|
|
387
387
|
**Option 2: Use the API programmatically**
|
|
388
388
|
|
|
389
389
|
```javascript
|
|
390
390
|
import { derivePrivateKey } from 'lockform'
|
|
391
391
|
|
|
392
|
-
const mnemonic = 'your fifteen word
|
|
392
|
+
const mnemonic = 'your fifteen word passphrase here exactly fifteen words'
|
|
393
393
|
const privateKeyBase64 = derivePrivateKey(mnemonic)
|
|
394
394
|
console.log(privateKeyBase64) // Store this in your edge function environment
|
|
395
395
|
```
|
|
@@ -411,7 +411,7 @@ The library automatically detects the format:
|
|
|
411
411
|
|
|
412
412
|
### Node.js / Long-running servers
|
|
413
413
|
|
|
414
|
-
You can use either format. The 15-word
|
|
414
|
+
You can use either format. The 15-word passphrase works fine in environments without strict CPU time limits.
|
|
415
415
|
|
|
416
416
|
## Requirements
|
|
417
417
|
|
package/derive-key.js
CHANGED
|
@@ -8,35 +8,35 @@ const rl = createInterface({
|
|
|
8
8
|
})
|
|
9
9
|
|
|
10
10
|
console.log('='.repeat(70))
|
|
11
|
-
console.log('Lockform
|
|
11
|
+
console.log('Lockform Passphrase Key Derivation Tool')
|
|
12
12
|
console.log('='.repeat(70))
|
|
13
13
|
console.log()
|
|
14
|
-
console.log('This tool derives a base64-encoded X25519
|
|
15
|
-
console.log('15-word BIP39
|
|
14
|
+
console.log('This tool derives a base64-encoded X25519 key from your')
|
|
15
|
+
console.log('15-word BIP39 passphrase for use in edge functions.')
|
|
16
16
|
console.log()
|
|
17
17
|
|
|
18
|
-
rl.question('Enter your 15-word
|
|
18
|
+
rl.question('Enter your 15-word passphrase: ', (mnemonic) => {
|
|
19
19
|
try {
|
|
20
20
|
const words = mnemonic.trim().split(/\s+/)
|
|
21
21
|
|
|
22
22
|
if (words.length !== 15) {
|
|
23
|
-
console.error('\n❌ Error:
|
|
23
|
+
console.error('\n❌ Error: Passphrase must be exactly 15 words')
|
|
24
24
|
console.error(` You entered ${words.length} words`)
|
|
25
25
|
process.exit(1)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
console.log('\n⏳ Deriving
|
|
28
|
+
console.log('\n⏳ Deriving encryption key (this may take a few seconds)...\n')
|
|
29
29
|
|
|
30
30
|
const privateKeyBase64 = derivePrivateKey(mnemonic.trim())
|
|
31
31
|
|
|
32
|
-
console.log('✅ Success! Your base64-encoded
|
|
32
|
+
console.log('✅ Success! Your base64-encoded encryption key:\n')
|
|
33
33
|
console.log('─'.repeat(70))
|
|
34
34
|
console.log(privateKeyBase64)
|
|
35
35
|
console.log('─'.repeat(70))
|
|
36
36
|
console.log()
|
|
37
37
|
console.log('Add this to your edge function environment variables:')
|
|
38
38
|
console.log()
|
|
39
|
-
console.log(`
|
|
39
|
+
console.log(`LOCKFORM_DERIVED_KEY="${privateKeyBase64}"`)
|
|
40
40
|
console.log()
|
|
41
41
|
console.log('⚠️ Keep this secret! Anyone with this key can decrypt all submissions.')
|
|
42
42
|
console.log()
|
package/package.json
CHANGED