the owner can create accounts
POST /api/users plus an Add-account form in Settings > User management. Until now createUser had one call site — bootstrap, gated on an empty user table — so every non-owner account anywhere had been inserted into Postgres by hand. Created accounts are Active. The column defaults to Unverified and signin refuses anything else with a bare UNAUTHORIZED, which is exactly what made the hand-INSERT route look like a wrong password. Also closes a hole found while reading the write path: a second Super Admin was storable. The CHECK constraint pins user 1's role but cannot see other rows, and getOwnerUser() was LIMIT 1 with no ORDER BY, so two holders would have made "who owns this server" a question the query plan answered — and that answer feeds the agent sidecar's identity, vault access and origin scoping. Both write paths now refuse the role and getOwnerUser() orders by id. USER_DIRS and provisionUserDirs move into data-path.ts so the create handler and scripts/provision-user-dirs.ts cannot disagree about what an account's skeleton is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,26 +16,10 @@
|
||||
|
||||
import { mkdirSync, existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const DATA_PATH = process.env.DATA_PATH ?? join(process.cwd(), 'data');
|
||||
|
||||
// Mirrors the shape the owner's root grew organically. Most of these are also created on demand by
|
||||
// whichever feature owns them (attachments, dashboards, email_accounts…), so pre-creating them buys
|
||||
// legibility more than function — the tree shows what a user has without having to use it first.
|
||||
//
|
||||
// `home` is the exception, and the reason this exists at all: nothing creates it today. getOwnerHomeDir
|
||||
// returns process.env.HOME_DIR whenever it is set, which it always is on a real install, so the
|
||||
// per-user home has never actually been reached. It is where a non-owner's sessions will run.
|
||||
const USER_DIRS = [
|
||||
'home',
|
||||
'attachments',
|
||||
'cache',
|
||||
'dashboards',
|
||||
'email_accounts',
|
||||
'general_chat_sessions',
|
||||
'logs',
|
||||
'sidecar',
|
||||
] as const;
|
||||
// The list and DATA_PATH itself come from the platform rather than being restated here. The owner's
|
||||
// create-account handler provisions the same skeleton, and a script that drifted from it would produce
|
||||
// accounts that differ by how they were made. Importing data-path.ts pulls in no database and no server.
|
||||
import { DATA_PATH, USER_DIRS } from '../src/servers/data-path';
|
||||
|
||||
const DRY_RUN = process.env.DRY_RUN === '1';
|
||||
const emails = process.argv.slice(2).filter(Boolean);
|
||||
|
||||
Reference in New Issue
Block a user