feat: implement MoloApp plans 01-15 with integration
Full C++23 framework tree: runtime, observability, security, data, app, realtime, supervisor, clients, CLI, example plus enterprise tenancy, audit, operability, governance, supplychain. Postgres via docker compose for tests.
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
#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<std::string, std::string> 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
|
||||
Reference in New Issue
Block a user