@camstack/system 1.2.357 → 1.2.359
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/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/auth/user-manager.d.ts +43 -2
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +2 -2
- package/dist/builtins/autotrack/index.mjs +2 -2
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/calendars/calendars.addon.js +1 -1
- package/dist/builtins/calendars/calendars.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +8 -8
- package/dist/builtins/composer/composer.addon.mjs +8 -8
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
- package/dist/builtins/device-manager/device-manager.addon.js +9 -9
- package/dist/builtins/device-manager/device-manager.addon.mjs +9 -9
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/admin-account-boot.d.ts +27 -0
- package/dist/builtins/local-auth/auth-schema.d.ts +3 -2
- package/dist/builtins/local-auth/local-auth.addon.js +281 -8
- package/dist/builtins/local-auth/local-auth.addon.mjs +291 -22
- package/dist/builtins/local-network/address-book.d.ts +69 -0
- package/dist/builtins/local-network/local-network.addon.d.ts +44 -32
- package/dist/builtins/local-network/local-network.addon.js +368 -55
- package/dist/builtins/local-network/local-network.addon.mjs +369 -54
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{child-cap-dispatch-BcRHQBKW.mjs → child-cap-dispatch-Dm1TRDCr.mjs} +2 -2
- package/dist/{child-cap-dispatch-wbIQJctP.js → child-cap-dispatch-t61ohDpb.js} +2 -2
- package/dist/{composition-sources-CeO0K2cl.js → composition-sources-CCU_KizO.js} +1 -1
- package/dist/{composition-sources-BBfqepyT.mjs → composition-sources-CHlfWHl6.mjs} +1 -1
- package/dist/{dist-CFVOy8VT.js → dist-W_X44h-s.js} +669 -121
- package/dist/{dist-B7WRgEZY.mjs → dist-pTfD_M-U.mjs} +628 -122
- package/dist/index.js +6 -141
- package/dist/index.mjs +4 -139
- package/dist/kernel/config-manager.d.ts +1 -1
- package/dist/kernel/config-schema.d.ts +6 -1
- package/dist/{retired-settings-keys-DKRjfz0U.mjs → retired-settings-keys-CK_ifret.mjs} +1 -1
- package/dist/{retired-settings-keys-CRlTzxaS.js → retired-settings-keys-jglEzgWR.js} +1 -1
- package/package.json +3 -3
|
@@ -3,11 +3,16 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-W_X44h-s.js");
|
|
7
|
+
let zod = require("zod");
|
|
7
8
|
let node_crypto = require("node:crypto");
|
|
8
9
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
9
10
|
let crypto$1 = require("crypto");
|
|
10
11
|
crypto$1 = require_chunk.__toESM(crypto$1, 1);
|
|
12
|
+
let node_path = require("node:path");
|
|
13
|
+
node_path = require_chunk.__toESM(node_path);
|
|
14
|
+
let node_fs = require("node:fs");
|
|
15
|
+
node_fs = require_chunk.__toESM(node_fs);
|
|
11
16
|
//#region src/auth/parse-record.ts
|
|
12
17
|
function parseRecord(kind, schema, data) {
|
|
13
18
|
try {
|
|
@@ -6708,15 +6713,44 @@ var UserManager = class {
|
|
|
6708
6713
|
}
|
|
6709
6714
|
});
|
|
6710
6715
|
}
|
|
6711
|
-
|
|
6716
|
+
/**
|
|
6717
|
+
* Seed the configured admin (`auth.adminUsername` / `auth.adminPassword`,
|
|
6718
|
+
* i.e. `CAMSTACK_ADMIN_USER` / `CAMSTACK_ADMIN_PASS`) — on FIRST boot only.
|
|
6719
|
+
*
|
|
6720
|
+
* The configured password is a seed, never an authority. Once any admin
|
|
6721
|
+
* exists, this never writes a password: the operator's own change in the
|
|
6722
|
+
* admin UI is the truth from then on. This method used to compare the stored
|
|
6723
|
+
* hash with the configured password on every boot and rewrite it when they
|
|
6724
|
+
* differed, so a password changed in the UI went back to the configured one
|
|
6725
|
+
* (`changeme` on a Mac hub and on any container without `CAMSTACK_ADMIN_PASS`)
|
|
6726
|
+
* at the next restart.
|
|
6727
|
+
*
|
|
6728
|
+
* `resetPassword: true` is the one explicit exception — the operator's
|
|
6729
|
+
* one-shot recovery request (see `admin-password-reset.ts`): the configured
|
|
6730
|
+
* admin's password is set back to the configured one.
|
|
6731
|
+
*/
|
|
6732
|
+
async ensureAdminExists(options = {}) {
|
|
6712
6733
|
const adminUsername = this.config.get("auth.adminUsername");
|
|
6713
6734
|
const adminPassword = this.config.get("auth.adminPassword");
|
|
6714
|
-
if (!adminUsername || !adminPassword) return;
|
|
6735
|
+
if (!adminUsername || !adminPassword) return { kind: "not-configured" };
|
|
6715
6736
|
const existing = await this.findByUsername(adminUsername);
|
|
6716
6737
|
if (existing) {
|
|
6717
|
-
if (
|
|
6718
|
-
|
|
6738
|
+
if (options.resetPassword === true) {
|
|
6739
|
+
await this.resetPassword(existing.id, adminPassword);
|
|
6740
|
+
return {
|
|
6741
|
+
kind: "reset",
|
|
6742
|
+
username: adminUsername
|
|
6743
|
+
};
|
|
6744
|
+
}
|
|
6745
|
+
return {
|
|
6746
|
+
kind: "exists",
|
|
6747
|
+
username: adminUsername
|
|
6748
|
+
};
|
|
6719
6749
|
}
|
|
6750
|
+
if ((await this.listAll()).some((u) => u.isAdmin)) return {
|
|
6751
|
+
kind: "other-admin-exists",
|
|
6752
|
+
username: adminUsername
|
|
6753
|
+
};
|
|
6720
6754
|
await this.create({
|
|
6721
6755
|
username: adminUsername,
|
|
6722
6756
|
password: adminPassword,
|
|
@@ -6724,6 +6758,19 @@ var UserManager = class {
|
|
|
6724
6758
|
allowedProviders: "*",
|
|
6725
6759
|
allowedDevices: {}
|
|
6726
6760
|
});
|
|
6761
|
+
return {
|
|
6762
|
+
kind: "seeded",
|
|
6763
|
+
username: adminUsername
|
|
6764
|
+
};
|
|
6765
|
+
}
|
|
6766
|
+
/**
|
|
6767
|
+
* Does `username` still sign in with `password`? A hash comparison — the
|
|
6768
|
+
* password is never logged or stored. `false` when the user does not exist.
|
|
6769
|
+
*/
|
|
6770
|
+
async hasPassword(username, password) {
|
|
6771
|
+
const user = await this.findByUsername(username);
|
|
6772
|
+
if (!user) return false;
|
|
6773
|
+
return this.auth.comparePassword(password, user.passwordHash);
|
|
6727
6774
|
}
|
|
6728
6775
|
}, i$2 = class extends Error {
|
|
6729
6776
|
constructor(e, t) {
|
|
@@ -9031,6 +9078,204 @@ var TotpManager = class {
|
|
|
9031
9078
|
}
|
|
9032
9079
|
};
|
|
9033
9080
|
//#endregion
|
|
9081
|
+
//#region src/kernel/config-schema.ts
|
|
9082
|
+
/** Default data directory — used when CAMSTACK_DATA env var is not set */
|
|
9083
|
+
var DEFAULT_DATA_PATH = "camstack-data";
|
|
9084
|
+
/**
|
|
9085
|
+
* A list of browser origins from config.yaml (a YAML list) or from the
|
|
9086
|
+
* `CAMSTACK_CORS_ORIGINS` env var (one comma-separated string — env carries
|
|
9087
|
+
* only strings). Validation of each entry is the CORS policy's job
|
|
9088
|
+
* (`server/backend/src/api/cors/cors-policy.ts`), which logs what it rejects;
|
|
9089
|
+
* the schema only fixes the SHAPE so a typo cannot stop the hub from booting.
|
|
9090
|
+
*/
|
|
9091
|
+
var originListSchema = zod.z.preprocess((value) => typeof value === "string" ? value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0) : value, zod.z.array(zod.z.string()));
|
|
9092
|
+
var serverSchema = zod.z.object({
|
|
9093
|
+
port: zod.z.number().default(4443),
|
|
9094
|
+
host: zod.z.string().default("0.0.0.0"),
|
|
9095
|
+
dataPath: zod.z.string().default(DEFAULT_DATA_PATH),
|
|
9096
|
+
/**
|
|
9097
|
+
* EXTRA browser origins allowed to call this hub cross-origin (D707), on
|
|
9098
|
+
* top of the built-ins: the hub's own origin, the hosted viewer PWA and the
|
|
9099
|
+
* native app's opaque `null` origin. Bootstrap-owned on purpose — widening
|
|
9100
|
+
* who may read hub responses in a browser is a security decision, and the
|
|
9101
|
+
* policy is live from the first request, before the settings store exists.
|
|
9102
|
+
*/
|
|
9103
|
+
corsOrigins: originListSchema.default([])
|
|
9104
|
+
});
|
|
9105
|
+
var authSchema = zod.z.object({
|
|
9106
|
+
jwtSecret: zod.z.string().nullable().default(null),
|
|
9107
|
+
adminUsername: zod.z.string().default("admin"),
|
|
9108
|
+
adminPassword: zod.z.string().default("changeme")
|
|
9109
|
+
});
|
|
9110
|
+
var hubSchema = zod.z.object({
|
|
9111
|
+
url: zod.z.string().default("ws://localhost:4443/agent"),
|
|
9112
|
+
token: zod.z.string().default("")
|
|
9113
|
+
});
|
|
9114
|
+
var agentSchema = zod.z.object({
|
|
9115
|
+
name: zod.z.string().default(""),
|
|
9116
|
+
/** Port for the agent status page (minimal HTML) */
|
|
9117
|
+
statusPort: zod.z.number().default(4444)
|
|
9118
|
+
});
|
|
9119
|
+
var tlsSchema = zod.z.object({
|
|
9120
|
+
/**
|
|
9121
|
+
* Enable HTTPS (default: true). The certificate itself is never configured
|
|
9122
|
+
* here: the admin UI (Network → Local access) generates or uploads it
|
|
9123
|
+
* (D726), and boot serves whatever `tls/mode` says.
|
|
9124
|
+
*/
|
|
9125
|
+
enabled: zod.z.boolean().default(true) });
|
|
9126
|
+
/**
|
|
9127
|
+
* Bootstrap-time addon configuration — read PURELY from YAML, before the
|
|
9128
|
+
* kernel can talk to the settings-store. This breaks the chicken-and-egg
|
|
9129
|
+
* where the settings store itself is implemented by an addon: the kernel
|
|
9130
|
+
* needs to know WHICH addon to load first to provide the store, and that
|
|
9131
|
+
* decision can't itself live in the store.
|
|
9132
|
+
*
|
|
9133
|
+
* Backward-compatible: every field is optional + defaults reproduce the
|
|
9134
|
+
* current hard-coded behavior. Existing config.yaml files keep working.
|
|
9135
|
+
*/
|
|
9136
|
+
var bootstrapAddonsSchema = zod.z.object({
|
|
9137
|
+
/**
|
|
9138
|
+
* Addon implementing the `settings-store` capability. Loaded FIRST,
|
|
9139
|
+
* before any other addon is enabled — every other addon's enable
|
|
9140
|
+
* state, settings, and ordering lives in the store it provides.
|
|
9141
|
+
*
|
|
9142
|
+
* Default: '@camstack/addon-sqlite-storage' (the workspace's
|
|
9143
|
+
* default SQLite-backed store). Future alternatives could swap this
|
|
9144
|
+
* for postgres/redis without touching kernel code.
|
|
9145
|
+
*/
|
|
9146
|
+
settingsStoreAddon: zod.z.string().default("@camstack/addon-sqlite-storage"),
|
|
9147
|
+
/**
|
|
9148
|
+
* How the launcher provisions REQUIRED_PACKAGES into `data/addons/`
|
|
9149
|
+
* on startup.
|
|
9150
|
+
*
|
|
9151
|
+
* - `'npm'` — pull from the npm registry (production default).
|
|
9152
|
+
* - `'local'` — copy `packages/<X>/` from the workspace into
|
|
9153
|
+
* `data/addons/<X>/`. Use for the Electron-
|
|
9154
|
+
* packaged bundle and the e2e harness.
|
|
9155
|
+
* - `'symlink'` — point `data/addons/<X>` at the workspace source
|
|
9156
|
+
* dir via a directory symlink. Dev-only: a
|
|
9157
|
+
* workspace rebuild (`npm run build -w <X>`) is
|
|
9158
|
+
* immediately reflected at the next addon load,
|
|
9159
|
+
* no copy step. Falls back to `'local'` on
|
|
9160
|
+
* platforms that reject symlink creation (Windows
|
|
9161
|
+
* without developer-mode).
|
|
9162
|
+
*
|
|
9163
|
+
* The `CAMSTACK_INSTALL_SOURCE` env var, when set, wins over this
|
|
9164
|
+
* field. Leave undefined to keep the launcher's default behaviour
|
|
9165
|
+
* (npm when no workspace, local when a bundled addons dir is
|
|
9166
|
+
* present, …).
|
|
9167
|
+
*/
|
|
9168
|
+
installSource: zod.z.enum([
|
|
9169
|
+
"npm",
|
|
9170
|
+
"local",
|
|
9171
|
+
"symlink"
|
|
9172
|
+
]).optional(),
|
|
9173
|
+
/**
|
|
9174
|
+
* Override the kernel's hard-coded `AddonInstaller.REQUIRED_PACKAGES`.
|
|
9175
|
+
* Passing an array here REPLACES the default list entirely — useful
|
|
9176
|
+
* for stripped-down deployments (only the bundle of addons the
|
|
9177
|
+
* operator actually wants) and for forcing a different storage
|
|
9178
|
+
* backend at first boot.
|
|
9179
|
+
*
|
|
9180
|
+
* Leave undefined to use the kernel-shipped defaults.
|
|
9181
|
+
*/
|
|
9182
|
+
requiredAddons: zod.z.array(zod.z.string()).optional(),
|
|
9183
|
+
/**
|
|
9184
|
+
* Disable list applied AFTER the settings-store reports the enabled
|
|
9185
|
+
* set. Operator escape hatch — boot without a known-broken addon
|
|
9186
|
+
* without having to mutate the store.
|
|
9187
|
+
*/
|
|
9188
|
+
forceDisable: zod.z.array(zod.z.string()).default([])
|
|
9189
|
+
});
|
|
9190
|
+
/** Bootstrap config -- loaded from config.yaml ONLY at startup.
|
|
9191
|
+
* All other settings live in SQL (system_settings table). */
|
|
9192
|
+
var bootstrapSchema = zod.z.object({
|
|
9193
|
+
/** Server mode: 'hub' (full server) or 'agent' (worker node) */
|
|
9194
|
+
mode: zod.z.enum(["hub", "agent"]).default("hub"),
|
|
9195
|
+
server: serverSchema.default(serverSchema.parse({})),
|
|
9196
|
+
auth: authSchema.default(authSchema.parse({})),
|
|
9197
|
+
/** Hub connection config — only used when mode='agent' */
|
|
9198
|
+
hub: hubSchema.default(hubSchema.parse({})),
|
|
9199
|
+
/** Agent-specific config — only used when mode='agent' */
|
|
9200
|
+
agent: agentSchema.default(agentSchema.parse({})),
|
|
9201
|
+
/** TLS configuration */
|
|
9202
|
+
tls: tlsSchema.default(tlsSchema.parse({})),
|
|
9203
|
+
/**
|
|
9204
|
+
* Addon bootstrap directives — minimum addon set needed before the
|
|
9205
|
+
* kernel can reach the settings-store. See bootstrapAddonsSchema.
|
|
9206
|
+
* Spec: docs/superpowers/specs/2026-05-15-yaml-bootstrap-expansion.md
|
|
9207
|
+
*/
|
|
9208
|
+
bootstrap: bootstrapAddonsSchema.default(bootstrapAddonsSchema.parse({}))
|
|
9209
|
+
});
|
|
9210
|
+
//#endregion
|
|
9211
|
+
//#region src/builtins/local-auth/admin-account-boot.ts
|
|
9212
|
+
/**
|
|
9213
|
+
* The admin account at boot: seed it once, reset it only on the operator's
|
|
9214
|
+
* explicit one-shot request, and say so when it still has the default password.
|
|
9215
|
+
*
|
|
9216
|
+
* ## Why a trigger FILE, not a variable
|
|
9217
|
+
*
|
|
9218
|
+
* The configured password (`CAMSTACK_ADMIN_PASS` / `auth.adminPassword`) seeds
|
|
9219
|
+
* the admin on first boot and is never applied again — a password the operator
|
|
9220
|
+
* changes in the admin UI survives every restart. Recovering a forgotten
|
|
9221
|
+
* password therefore needs an explicit request, and that request must be
|
|
9222
|
+
* ONE-SHOT: an environment flag stays set in a container template until someone
|
|
9223
|
+
* remembers to remove it, and while it is set it reverts the password on every
|
|
9224
|
+
* boot — the very defect this replaced. A file the hub DELETES after acting on
|
|
9225
|
+
* it cannot be left armed: create `RESET_ADMIN_PASSWORD` in the node's data
|
|
9226
|
+
* directory (`/data` in the container), restart, and the configured admin's
|
|
9227
|
+
* password is set back to the configured one, once.
|
|
9228
|
+
*/
|
|
9229
|
+
/** The trigger's name, at the root of the node's data directory. */
|
|
9230
|
+
var ADMIN_PASSWORD_RESET_TRIGGER = "RESET_ADMIN_PASSWORD";
|
|
9231
|
+
async function reconcileAdminAccountAtBoot(input) {
|
|
9232
|
+
const { users, fs, logger } = input;
|
|
9233
|
+
const triggerPath = node_path.join(input.dataDir, ADMIN_PASSWORD_RESET_TRIGGER);
|
|
9234
|
+
const resetRequested = fs.exists(triggerPath);
|
|
9235
|
+
const outcome = await users.ensureAdminExists({ resetPassword: resetRequested });
|
|
9236
|
+
logOutcome(outcome, logger);
|
|
9237
|
+
if (resetRequested) consumeTrigger(triggerPath, outcome, input);
|
|
9238
|
+
const username = "username" in outcome ? outcome.username : null;
|
|
9239
|
+
const usesDefaultPassword = username !== null && await users.hasPassword(username, "changeme");
|
|
9240
|
+
if (usesDefaultPassword && username !== null) logger.warn("The admin account still uses the default password — change it in the admin UI (the first sign-in with it asks for a new one)", { meta: { username } });
|
|
9241
|
+
return {
|
|
9242
|
+
outcome,
|
|
9243
|
+
usesDefaultPassword
|
|
9244
|
+
};
|
|
9245
|
+
}
|
|
9246
|
+
function logOutcome(outcome, logger) {
|
|
9247
|
+
switch (outcome.kind) {
|
|
9248
|
+
case "seeded":
|
|
9249
|
+
logger.info("Admin account seeded from the configured credentials (first boot)", { meta: { username: outcome.username } });
|
|
9250
|
+
return;
|
|
9251
|
+
case "reset":
|
|
9252
|
+
logger.warn("Admin password reset to the configured password, as requested", { meta: { username: outcome.username } });
|
|
9253
|
+
return;
|
|
9254
|
+
case "other-admin-exists":
|
|
9255
|
+
logger.info("Configured admin username not seeded: another admin account already exists", { meta: { username: outcome.username } });
|
|
9256
|
+
return;
|
|
9257
|
+
case "not-configured":
|
|
9258
|
+
logger.warn("No admin username/password configured — no admin account seeded");
|
|
9259
|
+
return;
|
|
9260
|
+
case "exists": return;
|
|
9261
|
+
}
|
|
9262
|
+
}
|
|
9263
|
+
/** Delete the trigger after acting on it — a reset must never repeat by itself. */
|
|
9264
|
+
function consumeTrigger(triggerPath, outcome, input) {
|
|
9265
|
+
if (outcome.kind !== "reset") input.logger.warn("Admin password reset requested, but no configured admin account to reset", { meta: {
|
|
9266
|
+
trigger: triggerPath,
|
|
9267
|
+
outcome: outcome.kind
|
|
9268
|
+
} });
|
|
9269
|
+
try {
|
|
9270
|
+
input.fs.remove(triggerPath);
|
|
9271
|
+
} catch (err) {
|
|
9272
|
+
input.logger.error("Could not delete the admin password reset trigger — delete it by hand, or every restart resets the admin password again", { meta: {
|
|
9273
|
+
trigger: triggerPath,
|
|
9274
|
+
error: err instanceof Error ? err.message : String(err)
|
|
9275
|
+
} });
|
|
9276
|
+
}
|
|
9277
|
+
}
|
|
9278
|
+
//#endregion
|
|
9034
9279
|
//#region src/builtins/local-auth/auth-config-reader.ts
|
|
9035
9280
|
/**
|
|
9036
9281
|
* Every config path this reader can answer. Anything else resolves to
|
|
@@ -9066,8 +9311,9 @@ function narrow(value) {
|
|
|
9066
9311
|
//#region src/builtins/local-auth/auth-schema.ts
|
|
9067
9312
|
/**
|
|
9068
9313
|
* @durable class=config owner=local-auth
|
|
9069
|
-
* write="an operator creates a user, or `ensureAdminExists` seeds
|
|
9070
|
-
*
|
|
9314
|
+
* write="an operator creates a user, or `ensureAdminExists` seeds the configured
|
|
9315
|
+
* admin on first boot (or resets its password on the operator's one-shot
|
|
9316
|
+
* RESET_ADMIN_PASSWORD trigger); updated on scope, isAdmin and password edits"
|
|
9071
9317
|
* retention="none — a row goes only when an operator deletes the user. A
|
|
9072
9318
|
* `declareCollection` that adds a PK/UNIQUE/NOT-NULL-without-default column
|
|
9073
9319
|
* REBUILDS the table: every account is wiped and only the configured admin
|
|
@@ -9675,6 +9921,23 @@ var OauthSessionManager = class {
|
|
|
9675
9921
|
};
|
|
9676
9922
|
//#endregion
|
|
9677
9923
|
//#region src/builtins/local-auth/local-auth.addon.ts
|
|
9924
|
+
/**
|
|
9925
|
+
* Local Auth Addon — owns user accounts, API keys, scoped tokens,
|
|
9926
|
+
* and local password authentication.
|
|
9927
|
+
*
|
|
9928
|
+
* Capabilities registered:
|
|
9929
|
+
* - `auth-provider` (collection) — local password authentication
|
|
9930
|
+
* - `user-management` (singleton) — user CRUD, API keys, scoped tokens
|
|
9931
|
+
*
|
|
9932
|
+
* This addon owns the OAuth grant MACHINERY (codes, sessions, refresh) but
|
|
9933
|
+
* declares no `oauth-integration` client of its own, and must not start: which
|
|
9934
|
+
* clients exist is integration-specific knowledge and belongs to the addon that
|
|
9935
|
+
* owns the integration (D101). `homeassistant` moved to `homeassistant-export`;
|
|
9936
|
+
* `export-alexa` was always there.
|
|
9937
|
+
*
|
|
9938
|
+
* Extension: an OIDC addon can register another `auth-provider` entry.
|
|
9939
|
+
* The server's login flow iterates the `auth-provider` collection.
|
|
9940
|
+
*/
|
|
9678
9941
|
/** How often the auth tables are swept for dead rows. */
|
|
9679
9942
|
var AUTH_REAP_INTERVAL_MS = 24 * 36e5;
|
|
9680
9943
|
/**
|
|
@@ -9732,7 +9995,15 @@ var LocalAuthAddon = class extends require_dist.BaseAddon {
|
|
|
9732
9995
|
this.oauthSessionManager = new OauthSessionManager(store);
|
|
9733
9996
|
this.totpManager = new TotpManager(store);
|
|
9734
9997
|
try {
|
|
9735
|
-
await
|
|
9998
|
+
await reconcileAdminAccountAtBoot({
|
|
9999
|
+
users: this.userManager,
|
|
10000
|
+
dataDir: this.ctx.nodeDataDir,
|
|
10001
|
+
fs: {
|
|
10002
|
+
exists: (filePath) => node_fs.existsSync(filePath),
|
|
10003
|
+
remove: (filePath) => node_fs.rmSync(filePath, { force: true })
|
|
10004
|
+
},
|
|
10005
|
+
logger: this.ctx.logger
|
|
10006
|
+
});
|
|
9736
10007
|
const liveUsers = await this.userManager.listAll();
|
|
9737
10008
|
const liveIds = new Set(liveUsers.map((u) => u.id));
|
|
9738
10009
|
const removed = await this.scopedTokenManager.cleanupOrphans(liveIds);
|
|
@@ -9986,11 +10257,13 @@ var LocalAuthAddon = class extends require_dist.BaseAddon {
|
|
|
9986
10257
|
//#endregion
|
|
9987
10258
|
exports.ApiKeyManager = ApiKeyManager;
|
|
9988
10259
|
exports.AuthManager = AuthManager;
|
|
10260
|
+
exports.DEFAULT_DATA_PATH = DEFAULT_DATA_PATH;
|
|
9989
10261
|
exports.LocalAuthAddon = LocalAuthAddon;
|
|
9990
10262
|
exports.default = LocalAuthAddon;
|
|
9991
10263
|
exports.ScopedTokenManager = ScopedTokenManager;
|
|
9992
10264
|
exports.SettingsReadUnavailableError = SettingsReadUnavailableError;
|
|
9993
10265
|
exports.UserManager = UserManager;
|
|
10266
|
+
exports.bootstrapSchema = bootstrapSchema;
|
|
9994
10267
|
exports.isSettingsReadUnavailable = isSettingsReadUnavailable;
|
|
9995
10268
|
Object.defineProperty(exports, "require_ms", {
|
|
9996
10269
|
enumerable: true,
|