@justin0713/opspilot 1.0.8 → 1.1.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.
- package/bin/opspilot.js +70 -5
- package/package.json +1 -1
package/bin/opspilot.js
CHANGED
|
@@ -214,17 +214,18 @@ function cmdStart(flags) {
|
|
|
214
214
|
// Detect first run: credentials file doesn't exist yet
|
|
215
215
|
const isFirstRun = !fs.existsSync(CREDENTIALS_FILE);
|
|
216
216
|
let setupMount = '';
|
|
217
|
+
let firstRunPassword = '';
|
|
217
218
|
|
|
218
219
|
if (isFirstRun) {
|
|
219
|
-
|
|
220
|
+
firstRunPassword = generatePassword();
|
|
220
221
|
|
|
221
222
|
// 1. Write to host temp file (chmod 600) — never passed as CLI arg or env var
|
|
222
223
|
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
223
|
-
fs.writeFileSync(SETUP_TOKEN_FILE,
|
|
224
|
+
fs.writeFileSync(SETUP_TOKEN_FILE, firstRunPassword);
|
|
224
225
|
try { fs.chmodSync(SETUP_TOKEN_FILE, 0o600); } catch (_) {}
|
|
225
226
|
|
|
226
227
|
// 2. Save to credentials file (chmod 600) for `opspilot password` command
|
|
227
|
-
writeCredentials(
|
|
228
|
+
writeCredentials(firstRunPassword);
|
|
228
229
|
|
|
229
230
|
// 3. Mount into container read-only — entrypoint reads & deletes it
|
|
230
231
|
setupMount = `-v "${SETUP_TOKEN_FILE}:/app/.setup_token:ro" `;
|
|
@@ -255,11 +256,16 @@ function cmdStart(flags) {
|
|
|
255
256
|
console.log(`${BOLD} URL :${RESET} http://localhost:${port}`);
|
|
256
257
|
console.log(`${BOLD} Username :${RESET} admin`);
|
|
257
258
|
if (isFirstRun) {
|
|
258
|
-
console.log(`${BOLD} Password :${RESET}
|
|
259
|
+
console.log(`${BOLD} Password :${RESET} ${BOLD}${firstRunPassword}${RESET}`);
|
|
259
260
|
}
|
|
260
261
|
console.log(`${BOLD} Data :${RESET} ${path.isAbsolute(data) ? data : `docker volume '${data}'`}`);
|
|
262
|
+
if (isFirstRun) {
|
|
263
|
+
console.log('');
|
|
264
|
+
console.log(`${YELLOW} Change your password in Settings after first login.${RESET}`);
|
|
265
|
+
console.log(` Password also saved at: ${CREDENTIALS_FILE}`);
|
|
266
|
+
console.log(` (run ${CYAN}opspilot password --clear${RESET} after you've changed it)`);
|
|
267
|
+
}
|
|
261
268
|
console.log('');
|
|
262
|
-
console.log(` ${CYAN}opspilot password${RESET} — show first-run admin password`);
|
|
263
269
|
console.log(` ${CYAN}opspilot logs -f${RESET} — tail live logs`);
|
|
264
270
|
console.log(` ${CYAN}opspilot stop${RESET} — stop the server`);
|
|
265
271
|
console.log(` ${CYAN}opspilot update${RESET} — upgrade to latest`);
|
|
@@ -398,6 +404,63 @@ function cmdUninstall(flags) {
|
|
|
398
404
|
console.log('');
|
|
399
405
|
}
|
|
400
406
|
|
|
407
|
+
function cmdResetAdmin() {
|
|
408
|
+
checkDocker();
|
|
409
|
+
|
|
410
|
+
const status = tryRun(`docker inspect -f "{{.State.Status}}" ${CONTAINER} 2>/dev/null`);
|
|
411
|
+
if (status !== 'running') {
|
|
412
|
+
die(
|
|
413
|
+
`Container '${CONTAINER}' is not running.\n\n` +
|
|
414
|
+
` Start it first: opspilot start --token <token>\n` +
|
|
415
|
+
` Then reset: opspilot reset-admin`
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const newPassword = generatePassword();
|
|
420
|
+
|
|
421
|
+
// Python runs INSIDE the container — reads password from stdin (never exposed in ps/docker inspect)
|
|
422
|
+
const script = [
|
|
423
|
+
'import sys, os',
|
|
424
|
+
'sys.path.insert(0, "/app")',
|
|
425
|
+
'from user_store import hash_password, load_users, save_users',
|
|
426
|
+
'data_dir = os.environ.get("OPSPILOT_DATA_DIR", "/app/data")',
|
|
427
|
+
'uf = data_dir + "/users.json"',
|
|
428
|
+
'pw = sys.stdin.readline().strip()',
|
|
429
|
+
'ud = load_users(uf)',
|
|
430
|
+
'ul = ud.get("users", [])',
|
|
431
|
+
'admin = next((u for u in ul if u.get("role") == "admin"), None)',
|
|
432
|
+
'assert admin, "ERROR: no admin user found"',
|
|
433
|
+
'salt, hashed = hash_password(pw)',
|
|
434
|
+
'admin["password_salt"] = salt',
|
|
435
|
+
'admin["password_hash"] = hashed',
|
|
436
|
+
'save_users(uf, ud)',
|
|
437
|
+
'print("OK:" + admin["username"])',
|
|
438
|
+
].join('\n');
|
|
439
|
+
|
|
440
|
+
log('Resetting admin password inside container...');
|
|
441
|
+
const result = spawnSync(
|
|
442
|
+
'docker', ['exec', '-i', CONTAINER, 'python3', '-c', script],
|
|
443
|
+
{ input: newPassword, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
if (result.status !== 0 || (result.stdout || '').startsWith('ERROR') || result.error) {
|
|
447
|
+
const detail = (result.stderr || result.stdout || String(result.error)).trim();
|
|
448
|
+
die(`Reset failed: ${detail}\n\nCheck logs: opspilot logs`);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Persist to credentials file (chmod 600) for `opspilot password`
|
|
452
|
+
writeCredentials(newPassword);
|
|
453
|
+
|
|
454
|
+
console.log('');
|
|
455
|
+
ok('Admin password reset successfully.');
|
|
456
|
+
console.log(`${BOLD} Username :${RESET} admin`);
|
|
457
|
+
console.log(`${BOLD} Password :${RESET} ${BOLD}${newPassword}${RESET}`);
|
|
458
|
+
console.log('');
|
|
459
|
+
console.log(`${YELLOW}Save this password — or retrieve it later with:${RESET}`);
|
|
460
|
+
console.log(` ${CYAN}opspilot password${RESET}`);
|
|
461
|
+
console.log('');
|
|
462
|
+
}
|
|
463
|
+
|
|
401
464
|
function cmdInstallGuide() {
|
|
402
465
|
const platform = os.platform();
|
|
403
466
|
console.log(`
|
|
@@ -457,6 +520,7 @@ ${BOLD}Commands:${RESET}
|
|
|
457
520
|
${CYAN}status${RESET} Show container status
|
|
458
521
|
${CYAN}config${RESET} Show saved local config
|
|
459
522
|
${CYAN}password${RESET} Show first-run admin password (--clear to delete after reading)
|
|
523
|
+
${CYAN}reset-admin${RESET} Reset admin password (official recovery if password is lost)
|
|
460
524
|
${CYAN}uninstall${RESET} Remove container, image, data volume and local config
|
|
461
525
|
${CYAN}install-guide${RESET} Show Docker installation instructions for your platform
|
|
462
526
|
|
|
@@ -499,6 +563,7 @@ switch (cmd) {
|
|
|
499
563
|
break;
|
|
500
564
|
case 'status': cmdStatus(); break;
|
|
501
565
|
case 'config': cmdConfig(); break;
|
|
566
|
+
case 'reset-admin': cmdResetAdmin(); break;
|
|
502
567
|
case 'uninstall': cmdUninstall(parsed.flags); break;
|
|
503
568
|
case 'install-guide': cmdInstallGuide(); break;
|
|
504
569
|
case 'password':
|
package/package.json
CHANGED