@ravi-hq/ravi 0.6.3 → 0.7.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 +14 -9
- package/dist/auth.d.ts +31 -28
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +28 -51
- package/dist/auth.js.map +1 -1
- package/dist/bin/ravi-secrets.d.ts +1 -2
- package/dist/bin/ravi-secrets.d.ts.map +1 -1
- package/dist/bin/ravi-secrets.js +7 -34
- package/dist/bin/ravi-secrets.js.map +1 -1
- package/dist/channels/email-trusted.d.ts +2 -0
- package/dist/channels/email-trusted.d.ts.map +1 -1
- package/dist/channels/email-trusted.js +18 -51
- package/dist/channels/email-trusted.js.map +1 -1
- package/dist/channels/email.d.ts +2 -0
- package/dist/channels/email.d.ts.map +1 -1
- package/dist/channels/email.js +18 -60
- package/dist/channels/email.js.map +1 -1
- package/dist/cli.d.ts +13 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +65 -382
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +13 -28
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +22 -63
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/index.d.ts +17 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +156 -45
- package/dist/index.js.map +1 -1
- package/dist/polling.d.ts +2 -12
- package/dist/polling.d.ts.map +1 -1
- package/dist/polling.js +2 -36
- package/dist/polling.js.map +1 -1
- package/dist/tools/identity.d.ts +0 -7
- package/dist/tools/identity.d.ts.map +1 -1
- package/dist/tools/identity.js.map +1 -1
- package/dist/tools/passwords.d.ts +1 -7
- package/dist/tools/passwords.d.ts.map +1 -1
- package/dist/tools/passwords.js +18 -58
- package/dist/tools/passwords.js.map +1 -1
- package/dist/tools/secrets.d.ts +1 -3
- package/dist/tools/secrets.d.ts.map +1 -1
- package/dist/tools/secrets.js +11 -37
- package/dist/tools/secrets.js.map +1 -1
- package/dist/types.d.ts +85 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -2
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +0 -6
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +0 -18
- package/dist/utils.js.map +1 -1
- package/openclaw.plugin.json +1 -0
- package/package.json +1 -5
- package/dist/crypto.d.ts +0 -156
- package/dist/crypto.d.ts.map +0 -1
- package/dist/crypto.js +0 -350
- package/dist/crypto.js.map +0 -1
package/dist/utils.d.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module utils
|
|
5
5
|
*/
|
|
6
|
-
import type { CryptoManager } from "./crypto.js";
|
|
7
6
|
/**
|
|
8
7
|
* Prepare text for email sending as HTML.
|
|
9
8
|
*
|
|
@@ -12,9 +11,4 @@ import type { CryptoManager } from "./crypto.js";
|
|
|
12
11
|
* and the result is wrapped in a `<div>` element.
|
|
13
12
|
*/
|
|
14
13
|
export declare function wrapInHtml(text: string): string;
|
|
15
|
-
/**
|
|
16
|
-
* Try to decrypt a value, returning a fallback on failure.
|
|
17
|
-
* Logs the first decryption failure to help diagnose wrong-PIN issues.
|
|
18
|
-
*/
|
|
19
|
-
export declare function tryDecrypt(crypto: CryptoManager, value: string, context: string): Promise<string>;
|
|
20
14
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAU/C"}
|
package/dist/utils.js
CHANGED
|
@@ -21,22 +21,4 @@ export function wrapInHtml(text) {
|
|
|
21
21
|
.replace(/\n/g, "<br>");
|
|
22
22
|
return `<div>${escaped}</div>`;
|
|
23
23
|
}
|
|
24
|
-
let decryptionWarningLogged = false;
|
|
25
|
-
/**
|
|
26
|
-
* Try to decrypt a value, returning a fallback on failure.
|
|
27
|
-
* Logs the first decryption failure to help diagnose wrong-PIN issues.
|
|
28
|
-
*/
|
|
29
|
-
export async function tryDecrypt(crypto, value, context) {
|
|
30
|
-
try {
|
|
31
|
-
return await crypto.decrypt(value);
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
if (!decryptionWarningLogged) {
|
|
35
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
36
|
-
console.error(`[ravi] Decryption failed (${context}): ${detail}. Wrong PIN?`);
|
|
37
|
-
decryptionWarningLogged = true;
|
|
38
|
-
}
|
|
39
|
-
return "[decryption failed]";
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
24
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAG,IAAI;SACjB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC1B,OAAO,QAAQ,OAAO,QAAQ,CAAC;AACjC,CAAC"}
|
package/openclaw.plugin.json
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"type": "object",
|
|
7
7
|
"properties": {
|
|
8
8
|
"identityUuid": { "type": "string" },
|
|
9
|
+
"identityKey": { "type": "string", "description": "Identity API key (ravi_id_...). Set per-agent for multi-agent setups." },
|
|
9
10
|
"externalEmail": {
|
|
10
11
|
"type": "boolean",
|
|
11
12
|
"default": true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ravi-hq/ravi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "OpenClaw plugin for Ravi — identity provider for AI agents. Email channels + full agent toolbox.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -32,10 +32,6 @@
|
|
|
32
32
|
}
|
|
33
33
|
]
|
|
34
34
|
},
|
|
35
|
-
"dependencies": {
|
|
36
|
-
"hash-wasm": "^4.11.0",
|
|
37
|
-
"tweetnacl": "^1.0.3"
|
|
38
|
-
},
|
|
39
35
|
"devDependencies": {
|
|
40
36
|
"@types/node": "^22.0.0",
|
|
41
37
|
"tsx": "^4.21.0",
|
package/dist/crypto.d.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E2E encryption/decryption module for the OpenClaw plugin.
|
|
3
|
-
*
|
|
4
|
-
* Implements the same key derivation and NaCl SealedBox operations as the Go CLI,
|
|
5
|
-
* ensuring cross-platform compatibility. Ciphertext format: `"e2e::<base64>"`.
|
|
6
|
-
*
|
|
7
|
-
* Key derivation flow:
|
|
8
|
-
* PIN + salt -> Argon2id -> 32-byte seed -> SHA-512 -> clamp first 32 bytes
|
|
9
|
-
* -> X25519 scalar base mult -> public key
|
|
10
|
-
*
|
|
11
|
-
* @module crypto
|
|
12
|
-
*/
|
|
13
|
-
/** Prefix prepended to every E2E-encrypted field value. */
|
|
14
|
-
export declare const ENCRYPTED_PREFIX = "e2e::";
|
|
15
|
-
/** A NaCl box keypair derived from a PIN and salt. */
|
|
16
|
-
export interface KeyPair {
|
|
17
|
-
/** 32-byte X25519 public key. */
|
|
18
|
-
publicKey: Uint8Array;
|
|
19
|
-
/** 32-byte clamped private key (Curve25519 scalar). */
|
|
20
|
-
secretKey: Uint8Array;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* High-level manager that caches a derived keypair and exposes
|
|
24
|
-
* encrypt/decrypt operations for tool use.
|
|
25
|
-
*/
|
|
26
|
-
export interface CryptoManager {
|
|
27
|
-
/** Decrypt an `"e2e::<base64>"` string. Non-encrypted values pass through unchanged. */
|
|
28
|
-
decrypt(ciphertext: string): Promise<string>;
|
|
29
|
-
/** Encrypt plaintext into `"e2e::<base64>"` format. Empty input returns `""`. */
|
|
30
|
-
encrypt(plaintext: string): Promise<string>;
|
|
31
|
-
/** Return the public key as a lowercase hex string. */
|
|
32
|
-
getPublicKeyHex(): string;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Encrypt a message using NaCl SealedBox (anonymous sender).
|
|
36
|
-
*
|
|
37
|
-
* Layout: `ephemeralPK (32) || crypto_box(message, nonce, recipientPK, ephemeralSK)`.
|
|
38
|
-
*
|
|
39
|
-
* @param message - Plaintext bytes to encrypt.
|
|
40
|
-
* @param recipientPK - Recipient's 32-byte X25519 public key.
|
|
41
|
-
* @returns Sealed ciphertext (32 + message.length + 16 bytes).
|
|
42
|
-
*/
|
|
43
|
-
export declare function sealedBoxSeal(message: Uint8Array, recipientPK: Uint8Array): Promise<Uint8Array>;
|
|
44
|
-
/**
|
|
45
|
-
* Decrypt a NaCl SealedBox ciphertext.
|
|
46
|
-
*
|
|
47
|
-
* @param sealed - The full sealed ciphertext (ephemeralPK || box output).
|
|
48
|
-
* @param recipientPK - Recipient's 32-byte X25519 public key.
|
|
49
|
-
* @param recipientSK - Recipient's 32-byte private key (clamped scalar).
|
|
50
|
-
* @returns Decrypted plaintext bytes, or `null` if decryption fails.
|
|
51
|
-
*/
|
|
52
|
-
export declare function sealedBoxOpen(sealed: Uint8Array, recipientPK: Uint8Array, recipientSK: Uint8Array): Promise<Uint8Array | null>;
|
|
53
|
-
/**
|
|
54
|
-
* Derive a NaCl keypair from a PIN and salt, matching the Go CLI exactly.
|
|
55
|
-
*
|
|
56
|
-
* Steps:
|
|
57
|
-
* 1. Argon2id(PIN, salt, time=3, mem=64MB, threads=1, keyLen=32) -> 32-byte seed
|
|
58
|
-
* 2. SHA-512(seed) -> 64-byte hash
|
|
59
|
-
* 3. First 32 bytes of hash with Curve25519 clamping applied
|
|
60
|
-
* 4. X25519 scalar base multiplication -> public key
|
|
61
|
-
*
|
|
62
|
-
* @param pin - User's encryption PIN (arbitrary string).
|
|
63
|
-
* @param saltBase64 - Base64-encoded 16-byte salt from the server.
|
|
64
|
-
* @returns The derived keypair.
|
|
65
|
-
*/
|
|
66
|
-
export declare function deriveKeyPair(pin: string, saltBase64: string): Promise<KeyPair>;
|
|
67
|
-
/**
|
|
68
|
-
* Check whether a field value carries the `"e2e::"` encrypted prefix.
|
|
69
|
-
*/
|
|
70
|
-
export declare function isEncrypted(value: string): boolean;
|
|
71
|
-
/**
|
|
72
|
-
* Decrypt an `"e2e::<base64>"` field value.
|
|
73
|
-
*
|
|
74
|
-
* If the value does not carry the encrypted prefix it is returned unchanged.
|
|
75
|
-
* Uses standard base64 (with padding) to match Go's `base64.StdEncoding`.
|
|
76
|
-
*
|
|
77
|
-
* @param value - The field value, possibly prefixed with `"e2e::"`.
|
|
78
|
-
* @param kp - The recipient keypair.
|
|
79
|
-
* @returns The plaintext string.
|
|
80
|
-
* @throws If base64 decoding or SealedBox decryption fails.
|
|
81
|
-
*/
|
|
82
|
-
export declare function decryptField(value: string, kp: KeyPair): Promise<string>;
|
|
83
|
-
/**
|
|
84
|
-
* Encrypt plaintext into `"e2e::<base64>"` format using a SealedBox.
|
|
85
|
-
*
|
|
86
|
-
* Empty plaintext returns an empty string (matching Go CLI behavior).
|
|
87
|
-
*
|
|
88
|
-
* @param plaintext - The string to encrypt.
|
|
89
|
-
* @param publicKey - Recipient's 32-byte X25519 public key.
|
|
90
|
-
* @returns The encrypted field value with `"e2e::"` prefix.
|
|
91
|
-
*/
|
|
92
|
-
export declare function encryptField(plaintext: string, publicKey: Uint8Array): Promise<string>;
|
|
93
|
-
/**
|
|
94
|
-
* Verify that a keypair can decrypt the server-stored verifier.
|
|
95
|
-
*
|
|
96
|
-
* The verifier is a base64-encoded SealedBox ciphertext of the literal
|
|
97
|
-
* string `"ravi-e2e-verify"`.
|
|
98
|
-
*
|
|
99
|
-
* @param kp - The derived keypair to verify.
|
|
100
|
-
* @param verifierB64 - Base64-encoded SealedBox ciphertext from the server.
|
|
101
|
-
* @returns `true` if decryption succeeds and produces the expected plaintext.
|
|
102
|
-
*/
|
|
103
|
-
export declare function verify(kp: KeyPair, verifierB64: string): Promise<boolean>;
|
|
104
|
-
/**
|
|
105
|
-
* Create a verifier by encrypting `"ravi-e2e-verify"` with the public key.
|
|
106
|
-
*
|
|
107
|
-
* @param kp - The keypair whose public key will be used to seal the verifier.
|
|
108
|
-
* @returns Base64-encoded SealedBox ciphertext.
|
|
109
|
-
*/
|
|
110
|
-
export declare function createVerifier(kp: KeyPair): Promise<string>;
|
|
111
|
-
/**
|
|
112
|
-
* Perform first-time E2E encryption setup.
|
|
113
|
-
*
|
|
114
|
-
* Generates a random 16-byte salt, derives a keypair from the PIN,
|
|
115
|
-
* creates a verifier, and returns all values needed to register
|
|
116
|
-
* with the server. Matches the Go CLI's `initialEncryptionSetup`.
|
|
117
|
-
*
|
|
118
|
-
* @param pin - The user's 6-digit PIN.
|
|
119
|
-
* @returns Object with base64-encoded salt, publicKey, verifier, and recoveryKey.
|
|
120
|
-
*/
|
|
121
|
-
export declare function setupEncryption(pin: string): Promise<{
|
|
122
|
-
salt: string;
|
|
123
|
-
publicKey: string;
|
|
124
|
-
verifier: string;
|
|
125
|
-
recoveryKey: string;
|
|
126
|
-
keyPair: KeyPair;
|
|
127
|
-
}>;
|
|
128
|
-
/**
|
|
129
|
-
* Create a {@link CryptoManager} that caches a derived keypair.
|
|
130
|
-
*
|
|
131
|
-
* On creation the manager:
|
|
132
|
-
* 1. Derives a keypair from PIN + salt.
|
|
133
|
-
* 2. Verifies the derived public key matches the server's stored public key.
|
|
134
|
-
* 3. Decrypts the server-stored verifier to confirm the PIN is correct.
|
|
135
|
-
*
|
|
136
|
-
* @param pin - User's encryption PIN.
|
|
137
|
-
* @param saltBase64 - Base64-encoded 16-byte salt from the server.
|
|
138
|
-
* @param verifierBase64 - Base64-encoded SealedBox ciphertext of `"ravi-e2e-verify"`.
|
|
139
|
-
* @param serverPublicKeyBase64 - Base64-encoded 32-byte public key stored on the server.
|
|
140
|
-
* @returns A ready-to-use CryptoManager.
|
|
141
|
-
* @throws If the derived public key does not match or the verifier decryption fails.
|
|
142
|
-
*/
|
|
143
|
-
export declare function createCryptoManager(pin: string, saltBase64: string, verifierBase64: string, serverPublicKeyBase64: string): Promise<CryptoManager>;
|
|
144
|
-
/**
|
|
145
|
-
* Create a {@link CryptoManager} from an already-derived keypair.
|
|
146
|
-
*
|
|
147
|
-
* Used when the keypair is loaded from ~/.ravi/auth.json (stored after
|
|
148
|
-
* initial PIN-based derivation). Skips Argon2id derivation and verification.
|
|
149
|
-
*
|
|
150
|
-
* @param publicKeyBase64 - Base64-encoded 32-byte public key.
|
|
151
|
-
* @param privateKeyBase64 - Base64-encoded 32-byte private key.
|
|
152
|
-
*/
|
|
153
|
-
export declare function createCryptoManagerFromKeyPair(publicKeyBase64: string, privateKeyBase64: string): CryptoManager;
|
|
154
|
-
/** Encode bytes to standard base64 with padding. Matches Go's `base64.StdEncoding`. */
|
|
155
|
-
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
156
|
-
//# sourceMappingURL=crypto.d.ts.map
|
package/dist/crypto.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,2DAA2D;AAC3D,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAkBxC,sDAAsD;AACtD,MAAM,WAAW,OAAO;IACtB,iCAAiC;IACjC,SAAS,EAAE,UAAU,CAAC;IACtB,uDAAuD;IACvD,SAAS,EAAE,UAAU,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,wFAAwF;IACxF,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,iFAAiF;IACjF,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,uDAAuD;IACvD,eAAe,IAAI,MAAM,CAAC;CAC3B;AAwBD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,UAAU,EACnB,WAAW,EAAE,UAAU,GACtB,OAAO,CAAC,UAAU,CAAC,CAcrB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,UAAU,EACvB,WAAW,EAAE,UAAU,GACtB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAY5B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CA+BlB;AAMD;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,OAAO,GACV,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAMD;;;;;;;;;GASG;AACH,wBAAsB,MAAM,CAC1B,EAAE,EAAE,OAAO,EACX,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CASlB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAIjE;AAMD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC,CAwBD;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,qBAAqB,EAAE,MAAM,GAC5B,OAAO,CAAC,aAAa,CAAC,CA4BxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC5C,eAAe,EAAE,MAAM,EACvB,gBAAgB,EAAE,MAAM,GACvB,aAAa,CAsBf;AAkBD,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEvD"}
|
package/dist/crypto.js
DELETED
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E2E encryption/decryption module for the OpenClaw plugin.
|
|
3
|
-
*
|
|
4
|
-
* Implements the same key derivation and NaCl SealedBox operations as the Go CLI,
|
|
5
|
-
* ensuring cross-platform compatibility. Ciphertext format: `"e2e::<base64>"`.
|
|
6
|
-
*
|
|
7
|
-
* Key derivation flow:
|
|
8
|
-
* PIN + salt -> Argon2id -> 32-byte seed -> SHA-512 -> clamp first 32 bytes
|
|
9
|
-
* -> X25519 scalar base mult -> public key
|
|
10
|
-
*
|
|
11
|
-
* @module crypto
|
|
12
|
-
*/
|
|
13
|
-
import { argon2id, blake2b } from "hash-wasm";
|
|
14
|
-
import nacl from "tweetnacl";
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
// Constants
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
/** Prefix prepended to every E2E-encrypted field value. */
|
|
19
|
-
export const ENCRYPTED_PREFIX = "e2e::";
|
|
20
|
-
/** Literal string encrypted inside the verifier ciphertext. */
|
|
21
|
-
const VERIFY_PLAINTEXT = "ravi-e2e-verify";
|
|
22
|
-
/** SealedBox overhead: 32-byte ephemeral public key + 16-byte Poly1305 MAC. */
|
|
23
|
-
const SEALED_BOX_OVERHEAD = 48;
|
|
24
|
-
// Argon2id parameters -- must match the Go CLI and libsodium exactly.
|
|
25
|
-
const ARGON2_TIME = 3;
|
|
26
|
-
const ARGON2_MEMORY = 65536; // 64 MB in KiB
|
|
27
|
-
const ARGON2_THREADS = 1;
|
|
28
|
-
const ARGON2_KEY_LEN = 32;
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
// SealedBox primitives (NaCl anonymous box using tweetnacl + hash-wasm)
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
/**
|
|
33
|
-
* Compute the 24-byte nonce for a NaCl SealedBox.
|
|
34
|
-
*
|
|
35
|
-
* The nonce is `BLAKE2b(ephemeralPK || recipientPK)` with a 24-byte digest,
|
|
36
|
-
* matching libsodium's `crypto_box_seal` implementation.
|
|
37
|
-
*/
|
|
38
|
-
async function sealedBoxNonce(ephemeralPK, recipientPK) {
|
|
39
|
-
const input = new Uint8Array(64);
|
|
40
|
-
input.set(ephemeralPK, 0);
|
|
41
|
-
input.set(recipientPK, 32);
|
|
42
|
-
const nonceHex = await blake2b(input, 192); // 192 bits = 24 bytes
|
|
43
|
-
return hexToBytes(nonceHex);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Encrypt a message using NaCl SealedBox (anonymous sender).
|
|
47
|
-
*
|
|
48
|
-
* Layout: `ephemeralPK (32) || crypto_box(message, nonce, recipientPK, ephemeralSK)`.
|
|
49
|
-
*
|
|
50
|
-
* @param message - Plaintext bytes to encrypt.
|
|
51
|
-
* @param recipientPK - Recipient's 32-byte X25519 public key.
|
|
52
|
-
* @returns Sealed ciphertext (32 + message.length + 16 bytes).
|
|
53
|
-
*/
|
|
54
|
-
export async function sealedBoxSeal(message, recipientPK) {
|
|
55
|
-
const ephemeral = nacl.box.keyPair();
|
|
56
|
-
const nonce = await sealedBoxNonce(ephemeral.publicKey, recipientPK);
|
|
57
|
-
const encrypted = nacl.box(message, nonce, recipientPK, ephemeral.secretKey);
|
|
58
|
-
if (!encrypted) {
|
|
59
|
-
throw new Error("nacl.box encryption failed");
|
|
60
|
-
}
|
|
61
|
-
// sealed = ephemeralPK || encrypted
|
|
62
|
-
const sealed = new Uint8Array(32 + encrypted.length);
|
|
63
|
-
sealed.set(ephemeral.publicKey, 0);
|
|
64
|
-
sealed.set(encrypted, 32);
|
|
65
|
-
return sealed;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Decrypt a NaCl SealedBox ciphertext.
|
|
69
|
-
*
|
|
70
|
-
* @param sealed - The full sealed ciphertext (ephemeralPK || box output).
|
|
71
|
-
* @param recipientPK - Recipient's 32-byte X25519 public key.
|
|
72
|
-
* @param recipientSK - Recipient's 32-byte private key (clamped scalar).
|
|
73
|
-
* @returns Decrypted plaintext bytes, or `null` if decryption fails.
|
|
74
|
-
*/
|
|
75
|
-
export async function sealedBoxOpen(sealed, recipientPK, recipientSK) {
|
|
76
|
-
if (sealed.length < SEALED_BOX_OVERHEAD) {
|
|
77
|
-
throw new Error(`Ciphertext too short (${sealed.length} bytes, minimum ${SEALED_BOX_OVERHEAD}). Data may be corrupted.`);
|
|
78
|
-
}
|
|
79
|
-
const ephemeralPK = sealed.subarray(0, 32);
|
|
80
|
-
const ciphertext = sealed.subarray(32);
|
|
81
|
-
const nonce = await sealedBoxNonce(ephemeralPK, recipientPK);
|
|
82
|
-
return nacl.box.open(ciphertext, nonce, ephemeralPK, recipientSK);
|
|
83
|
-
}
|
|
84
|
-
// ---------------------------------------------------------------------------
|
|
85
|
-
// Key derivation
|
|
86
|
-
// ---------------------------------------------------------------------------
|
|
87
|
-
/**
|
|
88
|
-
* Derive a NaCl keypair from a PIN and salt, matching the Go CLI exactly.
|
|
89
|
-
*
|
|
90
|
-
* Steps:
|
|
91
|
-
* 1. Argon2id(PIN, salt, time=3, mem=64MB, threads=1, keyLen=32) -> 32-byte seed
|
|
92
|
-
* 2. SHA-512(seed) -> 64-byte hash
|
|
93
|
-
* 3. First 32 bytes of hash with Curve25519 clamping applied
|
|
94
|
-
* 4. X25519 scalar base multiplication -> public key
|
|
95
|
-
*
|
|
96
|
-
* @param pin - User's encryption PIN (arbitrary string).
|
|
97
|
-
* @param saltBase64 - Base64-encoded 16-byte salt from the server.
|
|
98
|
-
* @returns The derived keypair.
|
|
99
|
-
*/
|
|
100
|
-
export async function deriveKeyPair(pin, saltBase64) {
|
|
101
|
-
// 1. Decode salt from base64
|
|
102
|
-
const salt = base64ToBytes(saltBase64);
|
|
103
|
-
// 2. Argon2id -> 32-byte seed
|
|
104
|
-
const seedHex = await argon2id({
|
|
105
|
-
password: pin,
|
|
106
|
-
salt,
|
|
107
|
-
parallelism: ARGON2_THREADS,
|
|
108
|
-
iterations: ARGON2_TIME,
|
|
109
|
-
memorySize: ARGON2_MEMORY,
|
|
110
|
-
hashLength: ARGON2_KEY_LEN,
|
|
111
|
-
outputType: "hex",
|
|
112
|
-
});
|
|
113
|
-
const seed = hexToBytes(seedHex);
|
|
114
|
-
// 3. SHA-512 of the seed
|
|
115
|
-
const { createHash } = await import("node:crypto");
|
|
116
|
-
const hashBuf = createHash("sha512").update(seed).digest();
|
|
117
|
-
const hash = new Uint8Array(hashBuf.buffer, hashBuf.byteOffset, hashBuf.byteLength);
|
|
118
|
-
// 4. Curve25519 clamping on the first 32 bytes
|
|
119
|
-
const privateKey = new Uint8Array(hash.subarray(0, 32));
|
|
120
|
-
privateKey[0] &= 248;
|
|
121
|
-
privateKey[31] &= 127;
|
|
122
|
-
privateKey[31] |= 64;
|
|
123
|
-
// 5. Scalar base multiplication -> public key
|
|
124
|
-
const publicKey = nacl.scalarMult.base(privateKey);
|
|
125
|
-
return { publicKey, secretKey: privateKey };
|
|
126
|
-
}
|
|
127
|
-
// ---------------------------------------------------------------------------
|
|
128
|
-
// Field-level encrypt / decrypt
|
|
129
|
-
// ---------------------------------------------------------------------------
|
|
130
|
-
/**
|
|
131
|
-
* Check whether a field value carries the `"e2e::"` encrypted prefix.
|
|
132
|
-
*/
|
|
133
|
-
export function isEncrypted(value) {
|
|
134
|
-
return value.startsWith(ENCRYPTED_PREFIX);
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Decrypt an `"e2e::<base64>"` field value.
|
|
138
|
-
*
|
|
139
|
-
* If the value does not carry the encrypted prefix it is returned unchanged.
|
|
140
|
-
* Uses standard base64 (with padding) to match Go's `base64.StdEncoding`.
|
|
141
|
-
*
|
|
142
|
-
* @param value - The field value, possibly prefixed with `"e2e::"`.
|
|
143
|
-
* @param kp - The recipient keypair.
|
|
144
|
-
* @returns The plaintext string.
|
|
145
|
-
* @throws If base64 decoding or SealedBox decryption fails.
|
|
146
|
-
*/
|
|
147
|
-
export async function decryptField(value, kp) {
|
|
148
|
-
if (!isEncrypted(value)) {
|
|
149
|
-
return value;
|
|
150
|
-
}
|
|
151
|
-
const b64 = value.slice(ENCRYPTED_PREFIX.length);
|
|
152
|
-
const sealed = base64ToBytes(b64);
|
|
153
|
-
const plaintext = await sealedBoxOpen(sealed, kp.publicKey, kp.secretKey);
|
|
154
|
-
if (!plaintext) {
|
|
155
|
-
throw new Error("Decryption failed: invalid ciphertext or wrong key");
|
|
156
|
-
}
|
|
157
|
-
return new TextDecoder().decode(plaintext);
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Encrypt plaintext into `"e2e::<base64>"` format using a SealedBox.
|
|
161
|
-
*
|
|
162
|
-
* Empty plaintext returns an empty string (matching Go CLI behavior).
|
|
163
|
-
*
|
|
164
|
-
* @param plaintext - The string to encrypt.
|
|
165
|
-
* @param publicKey - Recipient's 32-byte X25519 public key.
|
|
166
|
-
* @returns The encrypted field value with `"e2e::"` prefix.
|
|
167
|
-
*/
|
|
168
|
-
export async function encryptField(plaintext, publicKey) {
|
|
169
|
-
if (plaintext === "") {
|
|
170
|
-
return "";
|
|
171
|
-
}
|
|
172
|
-
const message = new TextEncoder().encode(plaintext);
|
|
173
|
-
const sealed = await sealedBoxSeal(message, publicKey);
|
|
174
|
-
return ENCRYPTED_PREFIX + bytesToBase64(sealed);
|
|
175
|
-
}
|
|
176
|
-
// ---------------------------------------------------------------------------
|
|
177
|
-
// Verifier
|
|
178
|
-
// ---------------------------------------------------------------------------
|
|
179
|
-
/**
|
|
180
|
-
* Verify that a keypair can decrypt the server-stored verifier.
|
|
181
|
-
*
|
|
182
|
-
* The verifier is a base64-encoded SealedBox ciphertext of the literal
|
|
183
|
-
* string `"ravi-e2e-verify"`.
|
|
184
|
-
*
|
|
185
|
-
* @param kp - The derived keypair to verify.
|
|
186
|
-
* @param verifierB64 - Base64-encoded SealedBox ciphertext from the server.
|
|
187
|
-
* @returns `true` if decryption succeeds and produces the expected plaintext.
|
|
188
|
-
*/
|
|
189
|
-
export async function verify(kp, verifierB64) {
|
|
190
|
-
try {
|
|
191
|
-
const ciphertext = base64ToBytes(verifierB64);
|
|
192
|
-
const plaintext = await sealedBoxOpen(ciphertext, kp.publicKey, kp.secretKey);
|
|
193
|
-
if (!plaintext)
|
|
194
|
-
return false;
|
|
195
|
-
return new TextDecoder().decode(plaintext) === VERIFY_PLAINTEXT;
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Create a verifier by encrypting `"ravi-e2e-verify"` with the public key.
|
|
203
|
-
*
|
|
204
|
-
* @param kp - The keypair whose public key will be used to seal the verifier.
|
|
205
|
-
* @returns Base64-encoded SealedBox ciphertext.
|
|
206
|
-
*/
|
|
207
|
-
export async function createVerifier(kp) {
|
|
208
|
-
const message = new TextEncoder().encode(VERIFY_PLAINTEXT);
|
|
209
|
-
const sealed = await sealedBoxSeal(message, kp.publicKey);
|
|
210
|
-
return bytesToBase64(sealed);
|
|
211
|
-
}
|
|
212
|
-
// ---------------------------------------------------------------------------
|
|
213
|
-
// First-time encryption setup
|
|
214
|
-
// ---------------------------------------------------------------------------
|
|
215
|
-
/**
|
|
216
|
-
* Perform first-time E2E encryption setup.
|
|
217
|
-
*
|
|
218
|
-
* Generates a random 16-byte salt, derives a keypair from the PIN,
|
|
219
|
-
* creates a verifier, and returns all values needed to register
|
|
220
|
-
* with the server. Matches the Go CLI's `initialEncryptionSetup`.
|
|
221
|
-
*
|
|
222
|
-
* @param pin - The user's 6-digit PIN.
|
|
223
|
-
* @returns Object with base64-encoded salt, publicKey, verifier, and recoveryKey.
|
|
224
|
-
*/
|
|
225
|
-
export async function setupEncryption(pin) {
|
|
226
|
-
// Generate random 16-byte salt (same as Go CLI's rand.Read(salt))
|
|
227
|
-
const salt = new Uint8Array(16);
|
|
228
|
-
globalThis.crypto.getRandomValues(salt);
|
|
229
|
-
// Base64-encode the salt (deriveKeyPair expects base64)
|
|
230
|
-
const saltB64 = bytesToBase64(salt);
|
|
231
|
-
// Derive keypair from PIN + salt
|
|
232
|
-
const kp = await deriveKeyPair(pin, saltB64);
|
|
233
|
-
// Create verifier (encrypted "ravi-e2e-verify")
|
|
234
|
-
const verifierB64 = await createVerifier(kp);
|
|
235
|
-
// Base64-encode the public key
|
|
236
|
-
const publicKeyB64 = bytesToBase64(kp.publicKey);
|
|
237
|
-
return {
|
|
238
|
-
salt: saltB64,
|
|
239
|
-
publicKey: publicKeyB64,
|
|
240
|
-
verifier: verifierB64,
|
|
241
|
-
recoveryKey: saltB64, // Same as CLI — recovery key IS the salt
|
|
242
|
-
keyPair: kp,
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
// ---------------------------------------------------------------------------
|
|
246
|
-
// CryptoManager factory
|
|
247
|
-
// ---------------------------------------------------------------------------
|
|
248
|
-
/**
|
|
249
|
-
* Create a {@link CryptoManager} that caches a derived keypair.
|
|
250
|
-
*
|
|
251
|
-
* On creation the manager:
|
|
252
|
-
* 1. Derives a keypair from PIN + salt.
|
|
253
|
-
* 2. Verifies the derived public key matches the server's stored public key.
|
|
254
|
-
* 3. Decrypts the server-stored verifier to confirm the PIN is correct.
|
|
255
|
-
*
|
|
256
|
-
* @param pin - User's encryption PIN.
|
|
257
|
-
* @param saltBase64 - Base64-encoded 16-byte salt from the server.
|
|
258
|
-
* @param verifierBase64 - Base64-encoded SealedBox ciphertext of `"ravi-e2e-verify"`.
|
|
259
|
-
* @param serverPublicKeyBase64 - Base64-encoded 32-byte public key stored on the server.
|
|
260
|
-
* @returns A ready-to-use CryptoManager.
|
|
261
|
-
* @throws If the derived public key does not match or the verifier decryption fails.
|
|
262
|
-
*/
|
|
263
|
-
export async function createCryptoManager(pin, saltBase64, verifierBase64, serverPublicKeyBase64) {
|
|
264
|
-
const keyPair = await deriveKeyPair(pin, saltBase64);
|
|
265
|
-
// Verify: derived public key must match the server's stored public key
|
|
266
|
-
const serverPubKey = base64ToBytes(serverPublicKeyBase64);
|
|
267
|
-
if (!nacl.verify(keyPair.publicKey, serverPubKey)) {
|
|
268
|
-
throw new Error("Derived public key does not match server record. Wrong PIN?");
|
|
269
|
-
}
|
|
270
|
-
// Verify: decrypting the verifier must produce "ravi-e2e-verify"
|
|
271
|
-
const isValid = await verify(keyPair, verifierBase64);
|
|
272
|
-
if (!isValid) {
|
|
273
|
-
throw new Error("Verifier decryption failed. Wrong PIN?");
|
|
274
|
-
}
|
|
275
|
-
return {
|
|
276
|
-
async decrypt(ciphertext) {
|
|
277
|
-
return decryptField(ciphertext, keyPair);
|
|
278
|
-
},
|
|
279
|
-
async encrypt(plaintext) {
|
|
280
|
-
return encryptField(plaintext, keyPair.publicKey);
|
|
281
|
-
},
|
|
282
|
-
getPublicKeyHex() {
|
|
283
|
-
return bytesToHex(keyPair.publicKey);
|
|
284
|
-
},
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Create a {@link CryptoManager} from an already-derived keypair.
|
|
289
|
-
*
|
|
290
|
-
* Used when the keypair is loaded from ~/.ravi/auth.json (stored after
|
|
291
|
-
* initial PIN-based derivation). Skips Argon2id derivation and verification.
|
|
292
|
-
*
|
|
293
|
-
* @param publicKeyBase64 - Base64-encoded 32-byte public key.
|
|
294
|
-
* @param privateKeyBase64 - Base64-encoded 32-byte private key.
|
|
295
|
-
*/
|
|
296
|
-
export function createCryptoManagerFromKeyPair(publicKeyBase64, privateKeyBase64) {
|
|
297
|
-
const publicKey = base64ToBytes(publicKeyBase64);
|
|
298
|
-
const secretKey = base64ToBytes(privateKeyBase64);
|
|
299
|
-
if (publicKey.length !== 32) {
|
|
300
|
-
throw new Error(`Invalid public key length: expected 32 bytes, got ${publicKey.length}`);
|
|
301
|
-
}
|
|
302
|
-
if (secretKey.length !== 32) {
|
|
303
|
-
throw new Error(`Invalid private key length: expected 32 bytes, got ${secretKey.length}`);
|
|
304
|
-
}
|
|
305
|
-
const keyPair = { publicKey, secretKey };
|
|
306
|
-
return {
|
|
307
|
-
async decrypt(ciphertext) {
|
|
308
|
-
return decryptField(ciphertext, keyPair);
|
|
309
|
-
},
|
|
310
|
-
async encrypt(plaintext) {
|
|
311
|
-
return encryptField(plaintext, keyPair.publicKey);
|
|
312
|
-
},
|
|
313
|
-
getPublicKeyHex() {
|
|
314
|
-
return bytesToHex(keyPair.publicKey);
|
|
315
|
-
},
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
// ---------------------------------------------------------------------------
|
|
319
|
-
// Encoding helpers
|
|
320
|
-
// ---------------------------------------------------------------------------
|
|
321
|
-
/**
|
|
322
|
-
* Decode a standard base64 string (with padding) to bytes.
|
|
323
|
-
* Matches Go's `base64.StdEncoding`.
|
|
324
|
-
*/
|
|
325
|
-
function base64ToBytes(b64) {
|
|
326
|
-
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(b64)) {
|
|
327
|
-
throw new Error("Invalid base64 string");
|
|
328
|
-
}
|
|
329
|
-
const buf = Buffer.from(b64, "base64");
|
|
330
|
-
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
331
|
-
}
|
|
332
|
-
/** Encode bytes to standard base64 with padding. Matches Go's `base64.StdEncoding`. */
|
|
333
|
-
export function bytesToBase64(bytes) {
|
|
334
|
-
return Buffer.from(bytes).toString("base64");
|
|
335
|
-
}
|
|
336
|
-
/** Convert a hex string to a Uint8Array. */
|
|
337
|
-
function hexToBytes(hex) {
|
|
338
|
-
const bytes = new Uint8Array(hex.length / 2);
|
|
339
|
-
for (let i = 0; i < hex.length; i += 2) {
|
|
340
|
-
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
|
341
|
-
}
|
|
342
|
-
return bytes;
|
|
343
|
-
}
|
|
344
|
-
/** Convert bytes to a lowercase hex string. */
|
|
345
|
-
function bytesToHex(bytes) {
|
|
346
|
-
return Array.from(bytes)
|
|
347
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
348
|
-
.join("");
|
|
349
|
-
}
|
|
350
|
-
//# sourceMappingURL=crypto.js.map
|
package/dist/crypto.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
|