Add login security retention and legal terms

This commit is contained in:
JB
2026-07-25 03:10:56 -04:00
parent 78dc5dcc98
commit 008d295ffb
16 changed files with 196 additions and 36 deletions
+15 -3
View File
@@ -9,18 +9,23 @@ import { avatarUrl } from '$lib/avatar';
import { deleteUploadedAvatar } from '$lib/server/avatars';
import { canRemoveAuthenticationMethod, getAuthenticationMethods } from '$lib/server/auth/methods';
import { getPagination } from '$lib/server/pagination';
import { purgeExpiredLoginMetadata } from '$lib/server/auth/session';
export const load: PageServerLoad = async ({ cookies, params, url }) => {
const operator = await requirePermission(await getSessionUser(cookies), 'users.view');
const database = await getDatabase();
await purgeExpiredLoginMetadata();
const loginQuery = url.searchParams.get('loginQ')?.trim() ?? '';
const loginStatus = ['success', 'failed'].includes(url.searchParams.get('loginStatus') ?? '') ? String(url.searchParams.get('loginStatus')) : '';
const buildQuery = url.searchParams.get('buildQ')?.trim() ?? '';
const buildVisibility = ['draft', 'private', 'public'].includes(url.searchParams.get('buildVisibility') ?? '') ? String(url.searchParams.get('buildVisibility')) : '';
const commentQuery = url.searchParams.get('commentQ')?.trim() ?? '';
const pattern = (value: string) => `%${value.replaceAll('%', '\\%').replaceAll('_', '\\_')}%`;
const loginWhere = `user_id=? AND provider LIKE ? ESCAPE '\\'${loginStatus ? ' AND succeeded=?' : ''}`;
const loginArgs: unknown[] = [params.id, pattern(loginQuery), ...(loginStatus ? [loginStatus === 'success' ? 1 : 0] : [])];
const loginWhere = `login_events.user_id=? AND (provider LIKE ? ESCAPE '\\' OR COALESCE(ip_address,'') LIKE ? ESCAPE '\\'
OR COALESCE(client_name,'') LIKE ? ESCAPE '\\' OR COALESCE(operating_system,'') LIKE ? ESCAPE '\\'
OR COALESCE(failure_reason,'') LIKE ? ESCAPE '\\')${loginStatus ? ' AND succeeded=?' : ''}`;
const loginPattern = pattern(loginQuery);
const loginArgs: unknown[] = [params.id, loginPattern, loginPattern, loginPattern, loginPattern, loginPattern, ...(loginStatus ? [loginStatus === 'success' ? 1 : 0] : [])];
const buildWhere = `owner_id=? AND (title LIKE ? ESCAPE '\\' COLLATE NOCASE OR slug LIKE ? ESCAPE '\\' COLLATE NOCASE)${buildVisibility ? ' AND visibility=?' : ''}`;
const buildArgs: unknown[] = [params.id, pattern(buildQuery), pattern(buildQuery), ...(buildVisibility ? [buildVisibility] : [])];
const commentWhere = `comments.user_id=? AND (comments.body LIKE ? ESCAPE '\\' COLLATE NOCASE OR builds.title LIKE ? ESCAPE '\\' COLLATE NOCASE)`;
@@ -51,7 +56,14 @@ export const load: PageServerLoad = async ({ cookies, params, url }) => {
(await database.prepare('SELECT * FROM permissions ORDER BY name')).all(),
(await database.prepare('SELECT role_id FROM user_roles WHERE user_id=?')).all(params.id),
(await database.prepare('SELECT permission_id FROM user_permissions WHERE user_id=?')).all(params.id),
(await database.prepare(`SELECT provider,succeeded,created_at FROM login_events WHERE ${loginWhere} ORDER BY created_at DESC LIMIT ? OFFSET ?`)).all(...loginArgs, loginPagination.perPage, loginPagination.offset),
(await database.prepare(`SELECT login_events.provider,login_events.succeeded,login_events.created_at,
login_events.ip_address,login_events.user_agent,login_events.client_name,login_events.operating_system,
login_events.device_type,login_events.location_country,login_events.location_region,login_events.location_city,
login_events.failure_reason,login_events.risk_flags,login_events.credential_id,login_events.session_id,
login_events.session_ended_at,login_events.session_end_reason,login_events.sensitive_purged_at,
sessions.expires_at AS session_expires_at
FROM login_events LEFT JOIN sessions ON sessions.id=login_events.session_id
WHERE ${loginWhere} ORDER BY login_events.created_at DESC LIMIT ? OFFSET ?`)).all(...loginArgs, loginPagination.perPage, loginPagination.offset),
(await database.prepare(`SELECT id,title,slug,visibility,updated_at FROM builds WHERE ${buildWhere} ORDER BY updated_at DESC LIMIT ? OFFSET ?`)).all(...buildArgs, buildPagination.perPage, buildPagination.offset),
(await database.prepare(`SELECT comments.id,comments.body,comments.created_at,builds.title,builds.slug
FROM comments JOIN builds ON builds.id=comments.build_id WHERE ${commentWhere} ORDER BY comments.created_at DESC LIMIT ? OFFSET ?`)).all(...commentArgs, commentPagination.perPage, commentPagination.offset)