-- furt-lua/src/auth.lua -- API Key authentication system -- Dragons@Work Digital Sovereignty Project local IpUtils = require("src.ip_utils") local RateLimiter = require("src.rate_limiter") local Auth = {} -- Load configuration local config = require("config.server") -- Authenticate incoming request function Auth.authenticate_request(request) local api_key = request.headers["x-api-key"] if not api_key then return false, "Missing X-API-Key header", 401 end -- Check if API key exists in config local key_config = config.api_keys and config.api_keys[api_key] if not key_config then return false, "Invalid API key", 401 end -- Get client IP local client_ip = IpUtils.get_client_ip(request) -- Check IP restrictions if not IpUtils.is_ip_allowed(client_ip, key_config.allowed_ips) then return false, "IP address not allowed", 403 end -- Check rate limits local rate_ok, rate_message, rate_info = RateLimiter:check_api_and_ip_limits(api_key, client_ip) if not rate_ok then return false, rate_message, 429, rate_info end -- Return auth context return true, { api_key = api_key, key_name = key_config.name, permissions = key_config.permissions or {}, client_ip = client_ip, rate_info = rate_info } end -- Check if user has specific permission function Auth.has_permission(auth_context, required_permission) if not auth_context or not auth_context.permissions then return false end -- No permission required = always allow for authenticated users if not required_permission then return true end -- Check for specific permission or wildcard for _, permission in ipairs(auth_context.permissions) do if permission == required_permission or permission == "*" then return true end end return false end -- Create auth middleware wrapper for route handlers function Auth.create_protected_route(required_permission, handler) return function(request, server) -- Authenticate request local auth_success, auth_result, status_code, rate_info = Auth.authenticate_request(request) if not auth_success then local error_response = { error = auth_result, timestamp = os.time() } -- Add rate limit info to error if available if rate_info then error_response.rate_limit = rate_info end return server:create_response(status_code or 401, error_response, nil, nil, request) end -- Check permissions if required_permission and not Auth.has_permission(auth_result, required_permission) then return server:create_response(403, { error = "Insufficient permissions", required = required_permission, available = auth_result.permissions }, nil, nil, request) end -- Add auth context to request request.auth = auth_result -- Get rate limit headers local rate_headers = RateLimiter:get_rate_limit_headers(auth_result.rate_info) -- Call original handler local result = handler(request, server) -- If result is a string (already formatted response), return as-is if type(result) == "string" then return result end -- If handler returned data, create response with rate limit headers return server:create_response(200, result, "application/json", rate_headers, request) end end -- Get authentication status for debug/monitoring function Auth.get_auth_status(auth_context) if not auth_context then return { authenticated = false } end return { authenticated = true, api_key_name = auth_context.key_name, permissions = auth_context.permissions, client_ip = auth_context.client_ip, rate_limit_remaining = auth_context.rate_info and auth_context.rate_info.api_key and auth_context.rate_info.api_key.remaining, ip_rate_limit_remaining = auth_context.rate_info and auth_context.rate_info.ip and auth_context.rate_info.ip.remaining } end return Auth