Files
dockhand/routes/api/auth/login/+server.ts
Jarek Krochmalski 62e3c6439e Initial commit
2025-12-28 21:16:03 +01:00

118 lines
3.3 KiB
TypeScript

import { json } from '@sveltejs/kit';
import type { RequestHandler } from '@sveltejs/kit';
import {
authenticateLocal,
authenticateLdap,
getEnabledLdapConfigs,
createUserSession,
isRateLimited,
recordFailedAttempt,
clearRateLimit,
verifyMfaToken,
isAuthEnabled
} from '$lib/server/auth';
import { getUser, getUserByUsername } from '$lib/server/db';
// POST /api/auth/login - Authenticate user
export const POST: RequestHandler = async ({ request, cookies, getClientAddress }) => {
// Check if auth is enabled
if (!(await isAuthEnabled())) {
return json({ error: 'Authentication is not enabled' }, { status: 400 });
}
try {
const { username, password, mfaToken, provider = 'local' } = await request.json();
if (!username || !password) {
return json({ error: 'Username and password are required' }, { status: 400 });
}
// Rate limiting by IP and username
const clientIp = getClientAddress();
const rateLimitKey = `${clientIp}:${username}`;
const { limited, retryAfter } = isRateLimited(rateLimitKey);
if (limited) {
return json(
{ error: `Too many login attempts. Please try again in ${retryAfter} seconds.` },
{ status: 429 }
);
}
// Attempt authentication based on provider
let result: any;
let authProviderType: 'local' | 'ldap' | 'oidc' = 'local';
if (provider.startsWith('ldap:')) {
// LDAP provider with specific config ID (e.g., "ldap:1")
const configId = parseInt(provider.split(':')[1], 10);
result = await authenticateLdap(username, password, configId);
authProviderType = 'ldap';
} else if (provider === 'ldap') {
// Generic LDAP (will try all enabled configs)
result = await authenticateLdap(username, password);
authProviderType = 'ldap';
} else {
result = await authenticateLocal(username, password);
authProviderType = 'local';
}
if (!result.success) {
recordFailedAttempt(rateLimitKey);
return json({ error: result.error || 'Authentication failed' }, { status: 401 });
}
// Handle MFA if required
if (result.requiresMfa) {
if (!mfaToken) {
// Return that MFA is required
return json({ requiresMfa: true }, { status: 200 });
}
// Verify MFA token
const user = await getUserByUsername(username);
if (!user || !(await verifyMfaToken(user.id, mfaToken))) {
recordFailedAttempt(rateLimitKey);
return json({ error: 'Invalid MFA code' }, { status: 401 });
}
// MFA verified, create session
const session = await createUserSession(user.id, authProviderType, cookies);
clearRateLimit(rateLimitKey);
return json({
success: true,
user: {
id: user.id,
username: user.username,
email: user.email,
displayName: user.displayName,
isAdmin: user.isAdmin
}
});
}
// No MFA, create session directly
if (result.user) {
const session = await createUserSession(result.user.id, authProviderType, cookies);
clearRateLimit(rateLimitKey);
return json({
success: true,
user: {
id: result.user.id,
username: result.user.username,
email: result.user.email,
displayName: result.user.displayName,
isAdmin: result.user.isAdmin
}
});
}
return json({ error: 'Authentication failed' }, { status: 401 });
} catch (error) {
console.error('Login error:', error);
return json({ error: 'Login failed' }, { status: 500 });
}
};