lsh-framework 3.1.7 → 3.1.8
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.
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Stores encrypted secrets on IPFS using Storacha (formerly web3.storage)
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from 'fs';
|
|
6
|
+
import * as fsPromises from 'fs/promises';
|
|
6
7
|
import * as path from 'path';
|
|
7
8
|
import * as os from 'os';
|
|
8
9
|
import * as crypto from 'crypto';
|
|
@@ -30,12 +31,19 @@ export class IPFSSecretsStorage {
|
|
|
30
31
|
const lshDir = path.join(homeDir, '.lsh');
|
|
31
32
|
this.cacheDir = path.join(lshDir, 'secrets-cache');
|
|
32
33
|
this.metadataPath = path.join(lshDir, 'secrets-metadata.json');
|
|
34
|
+
// Initialize metadata - will be loaded on first use
|
|
35
|
+
this.metadata = {};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Initialize async parts
|
|
39
|
+
*/
|
|
40
|
+
async initialize() {
|
|
33
41
|
// Ensure directories exist
|
|
34
42
|
if (!fs.existsSync(this.cacheDir)) {
|
|
35
43
|
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
36
44
|
}
|
|
37
45
|
// Load metadata
|
|
38
|
-
this.metadata = this.
|
|
46
|
+
this.metadata = await this.loadMetadataAsync();
|
|
39
47
|
}
|
|
40
48
|
/**
|
|
41
49
|
* Store secrets on IPFS
|
|
@@ -59,7 +67,7 @@ export class IPFSSecretsStorage {
|
|
|
59
67
|
encrypted: true,
|
|
60
68
|
};
|
|
61
69
|
this.metadata[this.getMetadataKey(gitRepo, environment)] = metadata;
|
|
62
|
-
this.saveMetadata();
|
|
70
|
+
await this.saveMetadata();
|
|
63
71
|
logger.info(`📦 Stored ${secrets.length} secrets on IPFS: ${cid}`);
|
|
64
72
|
logger.info(` Environment: ${environment}`);
|
|
65
73
|
if (gitRepo) {
|
|
@@ -132,7 +140,7 @@ export class IPFSSecretsStorage {
|
|
|
132
140
|
encrypted: true,
|
|
133
141
|
};
|
|
134
142
|
this.metadata[metadataKey] = metadata;
|
|
135
|
-
this.saveMetadata();
|
|
143
|
+
await this.saveMetadata();
|
|
136
144
|
}
|
|
137
145
|
}
|
|
138
146
|
}
|
|
@@ -162,7 +170,7 @@ export class IPFSSecretsStorage {
|
|
|
162
170
|
timestamp: new Date().toISOString(),
|
|
163
171
|
};
|
|
164
172
|
this.metadata[metadataKey] = metadata;
|
|
165
|
-
this.saveMetadata();
|
|
173
|
+
await this.saveMetadata();
|
|
166
174
|
}
|
|
167
175
|
}
|
|
168
176
|
}
|
|
@@ -236,20 +244,24 @@ export class IPFSSecretsStorage {
|
|
|
236
244
|
return Object.values(this.metadata);
|
|
237
245
|
}
|
|
238
246
|
/**
|
|
239
|
-
* Delete secrets for environment
|
|
247
|
+
* Delete local cached secrets for an environment
|
|
240
248
|
*/
|
|
241
|
-
async
|
|
249
|
+
async deleteLocal(environment, gitRepo) {
|
|
242
250
|
const metadataKey = this.getMetadataKey(gitRepo, environment);
|
|
243
251
|
const metadata = this.metadata[metadataKey];
|
|
244
252
|
if (metadata) {
|
|
245
253
|
// Delete local cache
|
|
246
254
|
const cachePath = path.join(this.cacheDir, `${metadata.cid}.encrypted`);
|
|
247
|
-
|
|
248
|
-
|
|
255
|
+
try {
|
|
256
|
+
await fsPromises.access(cachePath);
|
|
257
|
+
await fsPromises.unlink(cachePath);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// File doesn't exist, which is fine
|
|
249
261
|
}
|
|
250
262
|
// Remove metadata
|
|
251
263
|
delete this.metadata[metadataKey];
|
|
252
|
-
this.saveMetadata();
|
|
264
|
+
await this.saveMetadata();
|
|
253
265
|
logger.info(`🗑️ Deleted secrets for ${environment}`);
|
|
254
266
|
}
|
|
255
267
|
}
|
|
@@ -310,7 +322,10 @@ export class IPFSSecretsStorage {
|
|
|
310
322
|
*/
|
|
311
323
|
async storeLocally(cid, encryptedData, _environment) {
|
|
312
324
|
const cachePath = path.join(this.cacheDir, `${cid}.encrypted`);
|
|
313
|
-
|
|
325
|
+
// Ensure parent directory exists
|
|
326
|
+
await fsPromises.mkdir(this.cacheDir, { recursive: true });
|
|
327
|
+
// Write file without locking (simpler approach)
|
|
328
|
+
await fsPromises.writeFile(cachePath, encryptedData, 'utf8');
|
|
314
329
|
logger.debug(`Cached secrets locally: ${cachePath}`);
|
|
315
330
|
}
|
|
316
331
|
/**
|
|
@@ -318,10 +333,14 @@ export class IPFSSecretsStorage {
|
|
|
318
333
|
*/
|
|
319
334
|
async loadLocally(cid) {
|
|
320
335
|
const cachePath = path.join(this.cacheDir, `${cid}.encrypted`);
|
|
321
|
-
|
|
336
|
+
try {
|
|
337
|
+
await fsPromises.access(cachePath);
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
322
340
|
return null;
|
|
323
341
|
}
|
|
324
|
-
|
|
342
|
+
// Simple read without locking for now
|
|
343
|
+
return await fsPromises.readFile(cachePath, 'utf8');
|
|
325
344
|
}
|
|
326
345
|
/**
|
|
327
346
|
* Get metadata key for environment
|
|
@@ -344,10 +363,31 @@ export class IPFSSecretsStorage {
|
|
|
344
363
|
return {};
|
|
345
364
|
}
|
|
346
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* Load metadata from disk asynchronously
|
|
368
|
+
*/
|
|
369
|
+
async loadMetadataAsync() {
|
|
370
|
+
try {
|
|
371
|
+
await fsPromises.access(this.metadataPath);
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
return {};
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
const content = await fsPromises.readFile(this.metadataPath, 'utf8');
|
|
378
|
+
return JSON.parse(content);
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
return {};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
347
384
|
/**
|
|
348
385
|
* Save metadata to disk
|
|
349
386
|
*/
|
|
350
|
-
saveMetadata() {
|
|
351
|
-
|
|
387
|
+
async saveMetadata() {
|
|
388
|
+
// Ensure parent directory exists
|
|
389
|
+
const parentDir = path.dirname(this.metadataPath);
|
|
390
|
+
await fsPromises.mkdir(parentDir, { recursive: true });
|
|
391
|
+
await fsPromises.writeFile(this.metadataPath, JSON.stringify(this.metadata, null, 2), 'utf8');
|
|
352
392
|
}
|
|
353
393
|
}
|
|
@@ -458,6 +458,7 @@ API_KEY=
|
|
|
458
458
|
.option('--export', 'Output in export format for shell evaluation (alias for --format export)')
|
|
459
459
|
.option('--format <type>', 'Output format: env, json, yaml, toml, export', 'env')
|
|
460
460
|
.option('--exact', 'Require exact key match (disable fuzzy matching)')
|
|
461
|
+
.option('--no-mask', 'Show full values in fuzzy match results')
|
|
461
462
|
.action(async (key, options) => {
|
|
462
463
|
try {
|
|
463
464
|
const manager = new SecretsManager({ globalMode: options.global });
|
|
@@ -546,11 +547,13 @@ API_KEY=
|
|
|
546
547
|
// Multiple matches - show all matches for user to choose
|
|
547
548
|
console.error(`🔍 Found ${matches.length} matches for '${key}':\n`);
|
|
548
549
|
for (const match of matches) {
|
|
549
|
-
// Mask value for display
|
|
550
|
-
const
|
|
551
|
-
? match.value
|
|
552
|
-
:
|
|
553
|
-
|
|
550
|
+
// Mask value for display unless --no-mask is set
|
|
551
|
+
const displayValue = options.mask === false
|
|
552
|
+
? match.value
|
|
553
|
+
: (match.value.length > 4
|
|
554
|
+
? match.value.substring(0, 4) + '*'.repeat(Math.min(match.value.length - 4, 10))
|
|
555
|
+
: '****');
|
|
556
|
+
console.error(` ${match.key}=${displayValue}`);
|
|
554
557
|
}
|
|
555
558
|
console.error('');
|
|
556
559
|
console.error('💡 Please specify the exact key name or use one of:');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lsh-framework",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.8",
|
|
4
4
|
"description": "Simple, cross-platform encrypted secrets manager with automatic sync, IPFS audit logs, and multi-environment support. Just run lsh sync and start managing your secrets.",
|
|
5
5
|
"main": "dist/app.js",
|
|
6
6
|
"bin": {
|
|
@@ -65,7 +65,8 @@
|
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@storacha/client": "^1.8.18",
|
|
67
67
|
"@supabase/supabase-js": "^2.57.4",
|
|
68
|
-
"
|
|
68
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
69
|
+
"bcrypt": "^6.0.0",
|
|
69
70
|
"chalk": "^5.3.0",
|
|
70
71
|
"chokidar": "^5.0.0",
|
|
71
72
|
"commander": "^14.0.2",
|
|
@@ -80,6 +81,7 @@
|
|
|
80
81
|
"node-cron": "^4.2.1",
|
|
81
82
|
"ora": "^9.0.0",
|
|
82
83
|
"pg": "^8.16.3",
|
|
84
|
+
"proper-lockfile": "^4.1.2",
|
|
83
85
|
"smol-toml": "^1.3.1",
|
|
84
86
|
"uuid": "^13.0.0"
|
|
85
87
|
},
|