chore: migrate to v3 and adopt Doppler for secrets management #3

Open
kamil wants to merge 574 commits from v3-cleanup into main
2 changed files with 74 additions and 0 deletions
Showing only changes of commit 87b5ad1460 - Show all commits

View File

@@ -290,6 +290,7 @@ services:
POCKETBASE_ADMIN_EMAIL: "${POCKETBASE_ADMIN_EMAIL}"
POCKETBASE_ADMIN_PASSWORD: "${POCKETBASE_ADMIN_PASSWORD}"
AUTH_SECRET: "${AUTH_SECRET}"
DEBUG_LOGIN_TOKEN: "${DEBUG_LOGIN_TOKEN}"
PUBLIC_MINIO_PUBLIC_URL: "${MINIO_PUBLIC_ENDPOINT}"
# Valkey
VALKEY_ADDR: "valkey:6379"

View File

@@ -0,0 +1,73 @@
import { redirect, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { getUserByUsername, createUserSession } from '$lib/server/pocketbase';
import { createAuthToken } from '../../../../hooks.server';
import { env } from '$env/dynamic/private';
import { log } from '$lib/server/logger';
import { randomBytes } from 'node:crypto';
const AUTH_COOKIE = 'libnovel_auth';
const ONE_YEAR = 60 * 60 * 24 * 365;
/**
* GET /api/auth/debug-login?token=<DEBUG_LOGIN_TOKEN>&username=<username>
*
* One-shot debug bypass: verifies a shared secret token, then mints a real
* auth cookie for the given user (defaults to the first admin account) and
* redirects to /.
*
* Requires DEBUG_LOGIN_TOKEN env var to be set. Disabled (404) when the var
* is absent or empty.
*/
export const GET: RequestHandler = async ({ url, cookies, request }) => {
const debugToken = env.DEBUG_LOGIN_TOKEN ?? '';
if (!debugToken) {
error(404, 'Not found');
}
const provided = url.searchParams.get('token') ?? '';
// Constant-time comparison to prevent timing attacks
if (provided.length !== debugToken.length) {
log.warn('api/auth/debug-login', 'bad token attempt');
error(401, 'Invalid token');
}
let diff = 0;
for (let i = 0; i < debugToken.length; i++) {
diff |= provided.charCodeAt(i) ^ debugToken.charCodeAt(i);
}
if (diff !== 0) {
log.warn('api/auth/debug-login', 'bad token attempt');
error(401, 'Invalid token');
}
const username = url.searchParams.get('username') ?? 'kamil_alekber_2e99';
const user = await getUserByUsername(username);
if (!user) {
error(404, `User '${username}' not found`);
}
const authSessionId = randomBytes(16).toString('hex');
const userAgent = request.headers.get('user-agent') ?? '';
const ip =
request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ??
request.headers.get('x-real-ip') ??
'debug';
createUserSession(user.id, authSessionId, userAgent, ip).catch((e) =>
log.warn('api/auth/debug-login', 'createUserSession failed (non-fatal)', { err: String(e) })
);
const token = createAuthToken(user.id, user.username, user.role ?? 'user', authSessionId);
cookies.set(AUTH_COOKIE, token, {
path: '/',
httpOnly: true,
sameSite: 'lax',
maxAge: ONE_YEAR
});
log.info('api/auth/debug-login', 'debug login used', { username: user.username, ip });
const next = url.searchParams.get('next') ?? '/';
redirect(302, next);
};