@iterable/mcp 1.0.3 → 1.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.
@@ -1,25 +1,20 @@
1
1
  /**
2
- * Secure API Key Management using macOS Keychain
2
+ * Secure API Key Management with cross-platform support
3
3
  *
4
- * This module provides secure storage and management of multiple Iterable API keys
5
- * using macOS Keychain via the native `security` command-line tool.
4
+ * This module provides secure storage and management of multiple Iterable API keys.
6
5
  *
7
- * Platform Support:
8
- * - macOS: Full support with Keychain integration
9
- * - Windows/Linux: Not supported - use ITERABLE_API_KEY environment variable
10
- *
11
- * Storage:
12
- * - API keys: Stored securely in macOS Keychain (never on disk)
13
- * - Metadata: Stored in ~/.iterable-mcp/keys.json (names, IDs, endpoints, timestamps)
14
- * - Lock file: ~/.iterable-mcp/keys.lock (prevents concurrent modifications)
6
+ * Storage Strategy:
7
+ * - macOS: API keys in Keychain, metadata in ~/.iterable-mcp/keys.json
8
+ * - Windows: API keys encrypted with DPAPI in ~/.iterable-mcp/keys.json
9
+ * - Linux: API keys and metadata in ~/.iterable-mcp/keys.json (mode 0o600)
10
+ * - Lock file: ~/.iterable-mcp/keys.lock prevents concurrent modifications
15
11
  *
16
12
  * Security Features:
17
- * - Uses spawn() with argument arrays to prevent shell injection
18
- * - File-based locking for concurrent access protection
19
- * - Test-specific service name to isolate test keychain entries
20
13
  * - API key format validation (32-char lowercase hex)
21
- * - HTTPS-only URL validation
14
+ * - HTTPS-only URL validation (except localhost)
22
15
  * - Duplicate key detection (both names and values)
16
+ * - File-based locking for concurrent access protection
17
+ * - Restrictive file permissions where supported (Linux/macOS)
23
18
  */
24
19
  export type SecurityExecutor = (args: string[]) => Promise<string>;
25
20
  export interface ApiKeyMetadata {
@@ -35,6 +30,10 @@ export interface ApiKeyMetadata {
35
30
  isActive: boolean;
36
31
  /** Optional per-key environment overrides (extensible for future vars) */
37
32
  env?: Record<string, string>;
33
+ /** API key value (only present when not using Keychain storage) */
34
+ apiKey?: string;
35
+ /** Encrypted API key (Windows DPAPI) */
36
+ encryptedApiKey?: string;
38
37
  }
39
38
  export declare class KeyManager {
40
39
  private readonly configDir;
@@ -43,16 +42,16 @@ export declare class KeyManager {
43
42
  private store;
44
43
  private saveLock;
45
44
  private readonly execSecurity;
45
+ private readonly storageMethod;
46
46
  /**
47
47
  * Create a new KeyManager instance
48
48
  *
49
49
  * @param configDir - Optional custom config directory (defaults to ~/.iterable-mcp)
50
50
  * @param execSecurity - Optional security command executor (for dependency injection in tests)
51
- * @throws {Error} If not running on macOS and no mock executor is provided
52
51
  */
53
52
  constructor(configDir?: string, execSecurity?: SecurityExecutor);
54
53
  /**
55
- * Validate metadata against keychain and clean up orphaned entries
54
+ * Validate metadata against keychain and clean up orphaned entries (macOS only)
56
55
  *
57
56
  * Checks if each key in metadata still exists in the keychain.
58
57
  * Removes any metadata entries that no longer have corresponding keychain entries.
@@ -111,18 +110,43 @@ export declare class KeyManager {
111
110
  * Validate and normalize base URL
112
111
  */
113
112
  private validateBaseUrl;
113
+ /**
114
+ * Encrypt data using Windows DPAPI
115
+ *
116
+ * Security: Uses native C++ bindings to Windows DPAPI (Data Protection API).
117
+ * - No shell execution or code evaluation
118
+ * - Encrypted data can only be decrypted by the same user on the same machine
119
+ * - Uses CurrentUser scope for user-level protection
120
+ * - No optional entropy parameter (null) for simplicity
121
+ *
122
+ * @param text - Plain text to encrypt (validated as 32-char hex by caller)
123
+ * @returns Base64-encoded encrypted blob
124
+ * @throws {Error} If DPAPI encryption fails or platform is not Windows
125
+ */
126
+ private encryptWindows;
127
+ /**
128
+ * Decrypt data using Windows DPAPI
129
+ *
130
+ * Security: Uses native C++ bindings to Windows DPAPI.
131
+ * - No shell execution or code evaluation
132
+ * - Only the user who encrypted the data can decrypt it
133
+ * - Validates base64 input before decryption
134
+ *
135
+ * @param encryptedBase64 - Base64-encoded encrypted blob
136
+ * @returns Decrypted plain text
137
+ * @throws {Error} If DPAPI decryption fails, data is corrupt, or platform is not Windows
138
+ */
139
+ private decryptWindows;
114
140
  /**
115
141
  * Add a new API key
116
142
  *
117
- * Securely stores an API key in macOS Keychain and saves its metadata
118
- * (name, base URL, timestamps) to disk. Each key is tightly coupled to
119
- * its API endpoint.
143
+ * Stores an API key securely (Keychain on macOS, file on other platforms).
120
144
  *
121
145
  * @param name - User-friendly name for the key (must be unique)
122
146
  * @param apiKey - 32-character lowercase hexadecimal Iterable API key
123
147
  * @param baseUrl - Iterable API base URL (must be HTTPS)
124
148
  * @returns The unique ID generated for this key
125
- * @throws {Error} If the key name already exists, validation fails, or keychain storage fails
149
+ * @throws {Error} If the key name already exists, validation fails, or storage fails
126
150
  */
127
151
  addKey(name: string, apiKey: string, baseUrl: string, envOverrides?: Record<string, string>): Promise<string>;
128
152
  /**
@@ -142,11 +166,11 @@ export declare class KeyManager {
142
166
  /**
143
167
  * Get a key by ID or name
144
168
  *
145
- * Retrieves the actual API key value from macOS Keychain.
169
+ * Retrieves the actual API key value from storage.
146
170
  *
147
171
  * @param idOrName - The unique ID or user-friendly name of the key
148
172
  * @returns The API key value, or null if not found
149
- * @throws {Error} If keychain access fails
173
+ * @throws {Error} If storage access fails
150
174
  */
151
175
  getKey(idOrName: string): Promise<string | null>;
152
176
  /**
@@ -156,14 +180,14 @@ export declare class KeyManager {
156
180
  * Only one key can be active at a time.
157
181
  *
158
182
  * @returns The active API key value, or null if no key is active
159
- * @throws {Error} If keychain access fails
183
+ * @throws {Error} If storage access fails
160
184
  */
161
185
  getActiveKey(): Promise<string | null>;
162
186
  /**
163
187
  * Get the active key metadata
164
188
  *
165
189
  * Returns metadata for the currently active key without retrieving the
166
- * actual API key value from Keychain.
190
+ * actual API key value.
167
191
  *
168
192
  * @returns The active key metadata, or null if no key is active
169
193
  * @throws {Error} If the key store is not initialized
@@ -183,10 +207,9 @@ export declare class KeyManager {
183
207
  /**
184
208
  * Delete a key by ID
185
209
  *
186
- * Removes a key from both the macOS Keychain and the metadata store.
210
+ * Removes a key from storage and the metadata store.
187
211
  * The currently active key cannot be deleted - you must activate a different
188
- * key first. If keychain deletion fails, the metadata will still be removed
189
- * and a warning will be displayed.
212
+ * key first.
190
213
  *
191
214
  * Note: Only accepts key ID (not name) since IDs are guaranteed unique.
192
215
  *
@@ -206,12 +229,12 @@ export declare class KeyManager {
206
229
  /**
207
230
  * Find a key by its actual API key value
208
231
  *
209
- * Checks all stored keys in the keychain to see if the given API key value
210
- * already exists. Useful for preventing duplicate key values.
232
+ * Checks all stored keys to see if the given API key value already exists.
233
+ * Useful for preventing duplicate key values.
211
234
  *
212
235
  * @param apiKeyValue - The API key value to search for
213
236
  * @returns The metadata of the matching key, or null if not found
214
- * @throws {Error} If keychain access fails
237
+ * @throws {Error} If storage access fails
215
238
  */
216
239
  findKeyByValue(apiKeyValue: string): Promise<ApiKeyMetadata | null>;
217
240
  /**
@@ -219,13 +242,13 @@ export declare class KeyManager {
219
242
  *
220
243
  * Adds an API key to the key manager with a default name if it doesn't
221
244
  * already exist. This is used during the migration path from environment
222
- * variable-based configuration to secure keychain storage.
245
+ * variable-based configuration to key manager storage.
223
246
  *
224
247
  * @param apiKey - The 32-character lowercase hexadecimal API key to migrate
225
248
  * @param baseUrl - The Iterable API base URL for this key
226
249
  * @param name - The name to assign (defaults to "default")
227
250
  * @returns The unique ID of the migrated key (existing or newly created)
228
- * @throws {Error} If validation fails or keychain storage fails
251
+ * @throws {Error} If validation fails or storage fails
229
252
  */
230
253
  migrateLegacyKey(apiKey: string, baseUrl: string, name?: string): Promise<string>;
231
254
  }
@@ -1 +1 @@
1
- {"version":3,"file":"key-manager.d.ts","sourceRoot":"","sources":["../src/key-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAwDH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEnE,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AASD,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmB;IAEhD;;;;;;OAMG;gBACS,SAAS,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,gBAAgB;IAc/D;;;;;;;;OAQG;YACW,kBAAkB;IAmEhC;;;;;;;;;;;;OAYG;YACW,WAAW;IAsFzB;;;;;;;;;OASG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BjC;;OAEG;YACW,YAAY;IAU1B;;OAEG;YACW,cAAc;IAa5B;;OAEG;YACW,YAAY;IA6C1B;;;OAGG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAoCvB;;;;;;;;;;;;OAYG;IACG,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,OAAO,CAAC,MAAM,CAAC;IAmElB;;OAEG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC;IAiBhB;;;;;;;;OAQG;IACG,QAAQ,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAY3C;;;;;;;;OAQG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAgDtD;;;;;;;;OAQG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAiB5C;;;;;;;;OAQG;IACG,oBAAoB,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAY5D;;;;;;;;;OASG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BnD;;;;;;;;;;;;OAYG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkE1C;;;;;;;OAOG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAYjC;;;;;;;;;OASG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAiCzE;;;;;;;;;;;;OAYG;IACG,gBAAgB,CACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,SAAY,GACf,OAAO,CAAC,MAAM,CAAC;CAoBnB;AAKD;;GAEG;AACH,wBAAgB,aAAa,IAAI,UAAU,CAK1C"}
1
+ {"version":3,"file":"key-manager.d.ts","sourceRoot":"","sources":["../src/key-manager.ts"],"names":[],"mappings":"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"}