This commit is contained in:
+22
-4
@@ -22,7 +22,7 @@ import { setSessionManager } from '../engine/tools/browser.js';
|
||||
import { setUserFolderToolDeps } from '../engine/tools/user-folder.js';
|
||||
import { setSkillToolDeps } from '../engine/tools/skills.js';
|
||||
import { setAppDocsDeps } from '../engine/tools/app-docs.js';
|
||||
import { setupAuth, requireAuth, requireAdmin, isProviderConfigured } from './auth.js';
|
||||
import { setupAuth, requireAuth, requireAdmin, isProviderConfigured, isLocalEnabled, buildChangePasswordHandler } from './auth.js';
|
||||
import { canUserSeeTask } from './visibility.js';
|
||||
import { mountAdminApi } from './admin-api.js';
|
||||
import { createAdminGatewayApi } from './admin-gateway-api.js';
|
||||
@@ -238,14 +238,20 @@ export function createCoreServer(opts: CoreServerOptions): {
|
||||
const _hasAnyField = (p?: { clientId?: string; clientSecret?: string; callbackUrl?: string; baseUrl?: string }) =>
|
||||
!!(p?.clientId || p?.clientSecret || p?.callbackUrl || p?.baseUrl);
|
||||
const authIntended = _hasAnyField(_authProviders?.google) || _hasAnyField(_authProviders?.gitea);
|
||||
if (authIntended && !authUsable) {
|
||||
// Local email+password is a first-class auth mode: when enabled, auth is
|
||||
// active even without any OAuth provider.
|
||||
const localEnabled = !!opts.authConfig && isLocalEnabled(opts.authConfig);
|
||||
// Fail closed on a partial OAuth config ONLY when it would otherwise drop to
|
||||
// no-auth. If local auth is on, auth is already active (no fail-open), so a
|
||||
// half-configured OAuth provider just stays inactive rather than aborting boot.
|
||||
if (authIntended && !authUsable && !localEnabled) {
|
||||
throw new Error(
|
||||
'[auth] auth is partially configured: a provider has a client_id but is missing ' +
|
||||
'client_secret / callback_url (Gitea also needs base_url). Refusing to start in an ' +
|
||||
'insecure no-auth state — complete the provider config or remove it from config.yaml.',
|
||||
);
|
||||
}
|
||||
const authActive = authUsable;
|
||||
const authActive = authUsable || localEnabled;
|
||||
if (!authActive) {
|
||||
// No-auth single-user mode: per-user rows are owned by the synthetic
|
||||
// 'local' id, and several tables FK to users(id) (ssh_user_deks,
|
||||
@@ -256,6 +262,15 @@ export function createCoreServer(opts: CoreServerOptions): {
|
||||
let authenticateUpgrade: import('./auth.js').UpgradeAuthChecker | undefined;
|
||||
|
||||
if (authActive) {
|
||||
// Idempotently seed the shared `local` system admin (id='local', the same
|
||||
// owner the no-auth path uses) so an existing single-user / no-auth
|
||||
// deployment gains a login mid-stream and keeps its `local`-owned data.
|
||||
const bootstrap = opts.authConfig?.local?.bootstrapAdmin;
|
||||
if (localEnabled && bootstrap?.email && bootstrap?.password) {
|
||||
repo.upsertLocalSystemAdmin({ email: bootstrap.email, password: bootstrap.password });
|
||||
logger.info(`[auth] seeded local system admin id=local email=${bootstrap.email}`);
|
||||
}
|
||||
|
||||
const auth = setupAuth(
|
||||
repo,
|
||||
opts.authConfig!,
|
||||
@@ -280,6 +295,9 @@ export function createCoreServer(opts: CoreServerOptions): {
|
||||
res.json(req.user);
|
||||
});
|
||||
|
||||
// Self-service password change for local accounts (see auth.ts).
|
||||
app.post('/api/auth/password', requireAuth, express.json(), buildChangePasswordHandler(repo));
|
||||
|
||||
// Protect all API routes (except /api/version and /health)
|
||||
app.use('/api/local', requireAuth);
|
||||
app.use('/api/repos', requireAuth);
|
||||
@@ -304,7 +322,7 @@ export function createCoreServer(opts: CoreServerOptions): {
|
||||
|
||||
// Admin user management API (always mounted; protected by requireAdmin when auth is active)
|
||||
app.use('/api/admin', express.json());
|
||||
mountAdminApi(app, repo, authActive);
|
||||
mountAdminApi(app, repo, authActive, loadConfig()?.userFolderRoot ?? './data/users');
|
||||
|
||||
// AAO Gateway Phase 2a: admin-only CRUD over gateway_virtual_keys.
|
||||
// Enabled regardless of gateway.enabled so an admin can prep keys
|
||||
|
||||
Reference in New Issue
Block a user