import 'dart:convert'; import 'package:shelf/shelf.dart'; import 'package:shelf_router/shelf_router.dart'; import '../database/database.dart'; class AuthHandler { final AppDatabase db; AuthHandler(this.db); Router get router { final router = Router(); router.post('/login', _login); router.post('/logout', _logout); router.get('/me', _getCurrentUser); return router; } /// POST /api/auth/login Future _login(Request request) async { try { print('[Auth] Login attempt received'); final bodyStr = await request.readAsString(); print('[Auth] Request body: $bodyStr'); final payload = jsonDecode(bodyStr) as Map; final username = payload['username'] as String?; final password = payload['password'] as String?; if (username == null || password == null) { print('[Auth] Missing username or password'); return Response(400, body: jsonEncode({ 'success': false, 'error': 'Username and password are required', }), headers: {'Content-Type': 'application/json'},); } print('[Auth] Verifying credentials for user: $username'); // Verify credentials final user = db.verifyCredentials(username, password); if (user == null) { print('[Auth] Invalid credentials for user: $username'); return Response(401, body: jsonEncode({ 'success': false, 'error': 'Invalid credentials', }), headers: {'Content-Type': 'application/json'},); } print('[Auth] User verified, creating session for userId: ${user.id}'); // Create session final session = db.createSession(user.id); print('[Auth] Session created with token: ${session.token.substring(0, 8)}...'); return Response.ok(jsonEncode({ 'success': true, 'user': user.toJson(), 'token': session.token, }), headers: {'Content-Type': 'application/json'},); } catch (e, stackTrace) { print('[Auth] ERROR during login: $e'); print('[Auth] Stack trace: $stackTrace'); return Response.internalServerError( body: jsonEncode({'success': false, 'error': e.toString()}), headers: {'Content-Type': 'application/json'}, ); } } /// POST /api/auth/logout Future _logout(Request request) async { try { final token = _extractToken(request); if (token == null) { return Response(401, body: jsonEncode({ 'success': false, 'error': 'Unauthorized', }), headers: {'Content-Type': 'application/json'},); } db.deleteSession(token); return Response.ok(jsonEncode({ 'success': true, }), headers: {'Content-Type': 'application/json'},); } catch (e) { return Response.internalServerError( body: jsonEncode({'success': false, 'error': e.toString()}), headers: {'Content-Type': 'application/json'}, ); } } /// GET /api/auth/me Future _getCurrentUser(Request request) async { try { final token = _extractToken(request); if (token == null) { return Response(401, body: jsonEncode({ 'success': false, 'error': 'Unauthorized', }), headers: {'Content-Type': 'application/json'},); } final session = db.findSessionByToken(token); if (session == null) { return Response(401, body: jsonEncode({ 'success': false, 'error': 'Invalid or expired session', }), headers: {'Content-Type': 'application/json'},); } final user = db.findUserById(session.userId); if (user == null) { return Response(404, body: jsonEncode({ 'success': false, 'error': 'User not found', }), headers: {'Content-Type': 'application/json'},); } return Response.ok(jsonEncode({ 'user': user.toJson(), }), headers: {'Content-Type': 'application/json'},); } catch (e) { return Response.internalServerError( body: jsonEncode({'success': false, 'error': e.toString()}), headers: {'Content-Type': 'application/json'}, ); } } /// Extract token from Authorization header or cookie String? _extractToken(Request request) { // Try Authorization header first final authHeader = request.headers['authorization']; if (authHeader != null && authHeader.startsWith('Bearer ')) { return authHeader.substring(7); } // Try cookie final cookie = request.headers['cookie']; if (cookie != null) { final parts = cookie.split(';'); for (final part in parts) { final trimmed = part.trim(); if (trimmed.startsWith('session=')) { return trimmed.substring(8); } } } return null; } }