mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: prevent admin escalation when AUTH_ENABLED=false
When auth was disabled, users could log out, reach the login page, and authenticate with the default admin/admin credentials to gain full admin privileges — defeating the purpose of AUTH_ENABLED=false. Defense-in-depth fix across five layers: - Skip ensureDefaultAdmin() when auth is disabled (no admin user seeded) - Return 403 from POST /api/auth/login when auth is disabled - Return synthetic anonymous user from GET /api/auth/session when auth is disabled - Hide logout button in settings when auth is disabled - Redirect /login and /change-password to / via AuthGuard when auth is disabled Closes #90
This commit is contained in:
@@ -36,8 +36,10 @@ import { userFileRoutes } from "./routes/user-files.js";
|
||||
runMigrations();
|
||||
console.log("Database initialized");
|
||||
|
||||
// Create default admin user if no users exist
|
||||
await ensureDefaultAdmin();
|
||||
// Create default admin user if no users exist and auth is enabled
|
||||
if (env.AUTH_ENABLED) {
|
||||
await ensureDefaultAdmin();
|
||||
}
|
||||
|
||||
function ensureInstanceId() {
|
||||
const existing = db
|
||||
|
||||
@@ -160,6 +160,10 @@ export async function authRoutes(app: FastifyInstance): Promise<void> {
|
||||
"/api/auth/login",
|
||||
{ config: { rateLimit: { max: getLoginAttemptLimit, timeWindow: "1 minute" } } },
|
||||
async (request: FastifyRequest, reply: FastifyReply) => {
|
||||
if (!env.AUTH_ENABLED) {
|
||||
return reply.status(403).send({ error: "Authentication is disabled" });
|
||||
}
|
||||
|
||||
const body = request.body as { username?: string; password?: string } | null;
|
||||
|
||||
if (!body?.username || !body?.password) {
|
||||
@@ -230,6 +234,22 @@ export async function authRoutes(app: FastifyInstance): Promise<void> {
|
||||
|
||||
// GET /api/auth/session
|
||||
app.get("/api/auth/session", async (request: FastifyRequest, reply: FastifyReply) => {
|
||||
if (!env.AUTH_ENABLED) {
|
||||
return reply.send({
|
||||
user: {
|
||||
id: "anonymous",
|
||||
username: "anonymous",
|
||||
role: "user",
|
||||
mustChangePassword: false,
|
||||
permissions: getPermissions("user"),
|
||||
analyticsEnabled: null,
|
||||
analyticsConsentShownAt: null,
|
||||
analyticsConsentRemindAt: null,
|
||||
},
|
||||
expiresAt: null,
|
||||
});
|
||||
}
|
||||
|
||||
const token = extractToken(request);
|
||||
if (!token) {
|
||||
return reply.status(401).send({ error: "No session token provided" });
|
||||
@@ -238,7 +258,6 @@ export async function authRoutes(app: FastifyInstance): Promise<void> {
|
||||
const session = db.select().from(schema.sessions).where(eq(schema.sessions.id, token)).get();
|
||||
|
||||
if (!session || session.expiresAt < new Date()) {
|
||||
// Clean up expired session if it exists
|
||||
if (session) {
|
||||
db.delete(schema.sessions).where(eq(schema.sessions.id, token)).run();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user