home-hosted 0.7.5 → 0.7.7

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/dist/cli.js CHANGED
@@ -2437,6 +2437,11 @@ function createAuthRoute(deps) {
2437
2437
  statusCode: 400,
2438
2438
  code: "EXPOSED_WITHOUT_PASSWORD"
2439
2439
  });
2440
+ const proxyExposure = checkProxyExposure(deps.proxy.config, false, false, false);
2441
+ if (proxyExposure !== null) throw new DetailedError(proxyExposure, {
2442
+ statusCode: 400,
2443
+ code: "PROXY_EXPOSURE_BLOCKED"
2444
+ });
2440
2445
  deps.auth.clearPassword();
2441
2446
  deps.panel.settings.updateControl({ auth: { enabled: false } });
2442
2447
  return c.json({ ok: true });
@@ -9736,6 +9741,11 @@ function createSettingsRoute(deps) {
9736
9741
  statusCode: 400,
9737
9742
  code: "EXPOSURE_BLOCKED"
9738
9743
  });
9744
+ const proxyExposure = checkProxyExposure(deps.proxy.config, patch.control?.auth?.enabled ?? current.auth.enabled, deps.auth.passwordSet, deps.auth.usingDefaultPassword);
9745
+ if (proxyExposure !== null) throw new DetailedError(proxyExposure, {
9746
+ statusCode: 400,
9747
+ code: "PROXY_EXPOSURE_BLOCKED"
9748
+ });
9739
9749
  const previous = {
9740
9750
  trustProxy: current.auth.trustProxy,
9741
9751
  tlsEnabled: current.tls.enabled
@@ -10300,6 +10310,26 @@ function readJson(file) {
10300
10310
  return null;
10301
10311
  }
10302
10312
  }
10313
+ /**
10314
+ * A legacy file, with "absent" told apart from "present but unreadable".
10315
+ *
10316
+ * `readJson` collapses both into `null`, and a split that is skipped reads exactly like
10317
+ * one with nothing to do — so a corrupt legacy config used to be abandoned silently
10318
+ * while `workspaces.json` was still created, after which `hasLegacyLayout()` is false
10319
+ * and no later run ever looks at that file again. The definitions would sit unread
10320
+ * beside a panel supervising nothing.
10321
+ */
10322
+ function readLegacy(file) {
10323
+ if (!fs.existsSync(file)) return {
10324
+ parsed: null,
10325
+ unreadable: false
10326
+ };
10327
+ const parsed = readJson(file);
10328
+ return {
10329
+ parsed,
10330
+ unreadable: parsed === null
10331
+ };
10332
+ }
10303
10333
  function writeJson(file, value, mode) {
10304
10334
  fs.mkdirSync(path.dirname(file), { recursive: true });
10305
10335
  fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, mode === void 0 ? {} : { mode });
@@ -10397,10 +10427,11 @@ function migrateLayout() {
10397
10427
  const moved = [];
10398
10428
  const warnings = [];
10399
10429
  fs.mkdirSync(hhDir, { recursive: true });
10400
- const legacyConfig = readJson(legacy.configPath);
10430
+ const legacyConfig = readLegacy(legacy.configPath);
10401
10431
  let configSplit = false;
10402
- if (legacyConfig !== null) {
10403
- const split = splitConfig(legacyConfig);
10432
+ if (legacyConfig.unreadable) warnings.push(`${legacy.configPath} could not be read — it was NOT migrated and is still there; fix or remove it, then move the file in by hand`);
10433
+ if (legacyConfig.parsed !== null) {
10434
+ const split = splitConfig(legacyConfig.parsed);
10404
10435
  const destinations = [
10405
10436
  path.join(hhDir, "settings.json"),
10406
10437
  path.join(hhDir, "default", "settings.json"),
@@ -10417,10 +10448,11 @@ function migrateLayout() {
10417
10448
  configSplit = true;
10418
10449
  }
10419
10450
  }
10420
- const legacySecrets = readJson(legacy.secretsPath);
10451
+ const legacySecrets = readLegacy(legacy.secretsPath);
10421
10452
  let secretsSplit = false;
10422
- if (legacySecrets !== null) {
10423
- const split = splitSecrets(legacySecrets);
10453
+ if (legacySecrets.unreadable) warnings.push(`${legacy.secretsPath} could not be read — it was NOT migrated and is still there; a panel without it starts on the default password`);
10454
+ if (legacySecrets.parsed !== null) {
10455
+ const split = splitSecrets(legacySecrets.parsed);
10424
10456
  const destinations = [path.join(hhDir, ".control-secrets.json"), path.join(hhDir, "default", ".secrets.json")];
10425
10457
  const taken = destinations.filter((file) => fs.existsSync(file));
10426
10458
  if (taken.length > 0) warnings.push(`${legacy.secretsPath} could not be split — ${taken.map((file) => path.relative(hhDir, file)).join(", ")} already exist(s); left it in place`);
@@ -10600,6 +10632,8 @@ function localCall(runtime, path, method, token, timeoutMs) {
10600
10632
  status: response.statusCode ?? 0,
10601
10633
  body
10602
10634
  }));
10635
+ response.once("aborted", () => resolve(null));
10636
+ response.once("error", () => resolve(null));
10603
10637
  });
10604
10638
  request.once("error", () => resolve(null));
10605
10639
  request.once("timeout", () => {
@@ -17087,6 +17121,7 @@ state/.hh/*
17087
17121
  !state/.hh/settings.json
17088
17122
  !state/.hh/workspaces.json
17089
17123
  state/.hh/*/*
17124
+ !state/.hh/*/
17090
17125
  !state/.hh/*/settings.json
17091
17126
  !state/.hh/*/servers.config.json
17092
17127
  data/