#include "App.hpp" #include "../fw/Cookies.hpp" #include "../fw/Data.hpp" #include "../fw/Router.hpp" #include "../fw/Validate.hpp" namespace molo::example::app { void register_security_demo(fw::Router& router, Services& services) { fw::Auth* auth = services.auth.get(); fw::SessionStore* sessions = services.sessions.get(); fw::UploadStore* uploads = services.uploads.get(); std::string secret = services.cookie_secret; router.get("/auth/me", "auth-me", [auth](fw::Request req) { std::string user, password; if (!fw::parse_basic_auth(req.headers.get("Authorization"), user, password)) return fw::JsonResponse("{\"error\":\"basic auth required\"}", 401); if (!auth->check(user, password)) return fw::JsonResponse("{\"error\":\"bad credentials\"}", 403); return fw::JsonResponse( "{\"user\":\"" + fw::json_escape(user) + "\"}", 200); }); router.post("/auth/login", "auth-login", [auth](fw::Request req) { auto input = fw::parse_json_object_flat(req.body); if (input.empty()) input = fw::parse_form(req.body); if (!input.count("username") || !input.count("password")) return fw::JsonResponse("{\"error\":\"username and password required\"}", 400); if (!auth->check(input["username"], input["password"])) return fw::JsonResponse("{\"error\":\"bad credentials\"}", 403); return fw::JsonResponse( "{\"user\":\"" + fw::json_escape(input["username"]) + "\"}", 200); }); router.get("/sessions/counter", "session-counter", [sessions, secret](fw::Request req) { std::string raw = req.cookie_or("session", ""); std::string id; std::map data; bool fresh = false; if (raw.empty() || !fw::cookie_verify(raw, secret, id) || !sessions->get(id, data)) { id = sessions->create(); fresh = true; data.clear(); } long count = 0; if (data.count("count")) { try { count = std::stol(data["count"]); } catch (...) { count = 0; } } ++count; sessions->put(id, "count", std::to_string(count)); fw::Response res(200, "{\"count\":" + std::to_string(count) + ",\"fresh\":" + (fresh ? "true" : "false") + "}", "application/json"); res.headers.set( "Set-Cookie", fw::make_set_cookie("session", fw::cookie_sign(id, secret), "/", true, false, "Lax", 3600)); return res; }); router.post("/uploads/file", "upload", [uploads](fw::Request req) { std::string filename = req.query_or("filename", "upload.txt"); std::string content_type = req.headers.get("Content-Type"); if (content_type.empty()) content_type = "text/plain"; fw::UploadInfo info; std::string error; if (!uploads->store(filename, content_type, req.body, info, error)) { if (error == "file too large") return fw::JsonResponse("{\"error\":\"" + error + "\"}", 413); if (error == "content type not allowed") return fw::JsonResponse("{\"error\":\"" + error + "\"}", 415); return fw::JsonResponse("{\"error\":\"" + error + "\"}", 400); } return fw::JsonResponse("{\"file\":\"" + fw::json_escape(info.filename) + "\",\"size\":" + std::to_string(info.size) + "}", 201); }); } } // namespace molo::example::app