From 22a89031c3f6e363db9c8e74dfc52eb932c5734d Mon Sep 17 00:00:00 2001 From: Brett Laptop Date: Fri, 18 Aug 2023 20:00:47 -0400 Subject: [PATCH] login/logout + /login.html already logged in will redirect to home --- crow_test/data/db/users.sqlite | Bin 20480 -> 20480 bytes crow_test/data/session/.expirations | 1 + crow_test/data/session/7IgWbfRRG3liKhkP.json | 1 + crow_test/webcontent/not_authorized.response | 0 libs/BLT | 2 +- src/main.cpp | 176 ++++++++++++++----- 6 files changed, 133 insertions(+), 47 deletions(-) create mode 100644 crow_test/data/session/7IgWbfRRG3liKhkP.json create mode 100644 crow_test/webcontent/not_authorized.response diff --git a/crow_test/data/db/users.sqlite b/crow_test/data/db/users.sqlite index 3b5d3a3aef77f8ab413853c0b43dccc507576654..9f8cabf2b68246bbbefed1e908515a05520caec0 100644 GIT binary patch delta 122 zcmZozz}T>Wae_3X_(U0JM)8dar{oy9CTq*rhK0E47nSFlnY-kbI2mLVrMPDX6hsCE zxRvEanOm3@S>zQ(nP`Uxnw5tp=B1ldBo+E4Mj1GU7DRX_d!!bZCpv3;mIoPFSQ>go al|%$+n?xjg6bCwP{wL2Uz{s`8Kmh<}XD03d delta 122 zcmZozz}T>Wae_3X*hCp;MzM_vr{owpCu_^sh824GReBU8I~pb#x<;Dm7v~!lc^JE8 zIA!Medb_yfIeP`?WG1FomU#GPn1mT*XBkyin)oIehPwKjr-bX5My8~v`Gx118>f^z a7iH$>mpP{z`gx>p{wL2Uz{t7CKmh<;H79BS diff --git a/crow_test/data/session/.expirations b/crow_test/data/session/.expirations index f6e0594..2af2d9c 100644 --- a/crow_test/data/session/.expirations +++ b/crow_test/data/session/.expirations @@ -1 +1,2 @@ l5yQfzNDLXuq6Ic1 1692481044 +7IgWbfRRG3liKhkP 1692489339 diff --git a/crow_test/data/session/7IgWbfRRG3liKhkP.json b/crow_test/data/session/7IgWbfRRG3liKhkP.json new file mode 100644 index 0000000..c9db0f4 --- /dev/null +++ b/crow_test/data/session/7IgWbfRRG3liKhkP.json @@ -0,0 +1 @@ +{"clientID":"50a21c33-66c4-5a0f-902f-9434632025e6","clientToken":"TF/rwm67DntB0hrdGiPpYRPFvnZ786r8nrZ4+WQ6wUang4xbqNaZ0AUpXKcHeswaC+IwR0891JZtXP+4XcHsQA=="} \ No newline at end of file diff --git a/crow_test/webcontent/not_authorized.response b/crow_test/webcontent/not_authorized.response new file mode 100644 index 0000000..e69de29 diff --git a/libs/BLT b/libs/BLT index 1d03938..bbbf0ba 160000 --- a/libs/BLT +++ b/libs/BLT @@ -1 +1 @@ -Subproject commit 1d03938f950568dd1082abfd55f664ede6023995 +Subproject commit bbbf0ba2e57ae202aa83cd2c8178f772a2e14a78 diff --git a/src/main.cpp b/src/main.cpp index 17fb101..a158511 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,9 @@ #include #include +using Session = crow::SessionMiddleware; +using CrowApp = crow::App; + class BLT_CrowLogger : public crow::ILogHandler { public: @@ -42,13 +45,106 @@ class BLT_CrowLogger : public crow::ILogHandler } }; -inline crow::response redirect(const std::string& loc) +struct site_params { - crow::response res; - res.redirect(loc); + CrowApp& app; + cs::CacheEngine& engine; + const crow::request& req; + const std::string& name; +}; + +inline crow::response redirect(const std::string& loc = "/", int code = 303) +{ + crow::response res(code); + res.set_header("Location", loc); return res; } +/** + * Note this function destroys the user's session and any login related cookies! + */ +void destroyUserSession(CrowApp& app, const crow::request& req) +{ + auto& session = app.get_context(req); + auto& cookie_context = app.get_context(req); + + session.set("clientID", ""); + session.set("clientToken", ""); + cookie_context.set_cookie("clientID", ""); + cookie_context.set_cookie("clientToken", ""); +} + +bool checkAndUpdateUserSession(CrowApp& app, const crow::request& req) +{ + auto& session = app.get_context(req); + auto& cookie_context = app.get_context(req); + + auto s_clientID = session.get("clientID", ""); + auto s_clientToken = session.get("clientToken", ""); + + auto c_clientID = cookie_context.get_cookie("clientID"); + auto c_clientToken = cookie_context.get_cookie("clientToken"); + + if ((!c_clientID.empty() && !c_clientToken.empty()) && (s_clientID != c_clientID || s_clientToken != c_clientToken)) + { + session.set("clientID", c_clientID); + session.set("clientToken", c_clientToken); + return true; + } + return false; +} + +bool isUserLoggedIn(CrowApp& app, const crow::request& req) +{ + auto& session = app.get_context(req); + auto s_clientID = session.get("clientID", ""); + auto s_clientToken = session.get("clientToken", ""); + return cs::isUserLoggedIn(s_clientID, s_clientToken); +} + +bool isUserAdmin(CrowApp& app, const crow::request& req) +{ + auto& session = app.get_context(req); + auto s_clientID = session.get("clientID", ""); + return cs::isUserAdmin(cs::getUserFromID(s_clientID)); +} + +crow::response handle_root_page(const site_params& params) +{ + //auto page = crow::mustache::load("index.html"); // + //return "Hello There

Suck it " + name + "

"; +// BLT_TRACE(req.body); +// for (const auto& h : req.headers) +// BLT_TRACE("Header: %s = %s", h.first.c_str(), h.second.c_str()); +// BLT_TRACE(req.raw_url); +// BLT_TRACE(req.url); +// BLT_TRACE(req.remote_ip_address); +// for (const auto& v : req.url_params.keys()) +// BLT_TRACE("URL: %s = %s", v.c_str(), req.url_params.get(v)); + if (params.name.ends_with(".html")) + { + crow::mustache::context ctx; + // we don't want to pass all get parameters to the context to prevent leaking + auto referer = params.req.url_params.get("referer"); + if (referer) + ctx["referer"] = referer; + auto page = crow::mustache::compile(params.engine.fetch(params.name)); + return page.render(ctx); + } + +// crow::mustache::context ctx({{"person", name}}); +// auto user_page = crow::mustache::compile(engine.fetch("index.html")); + + return params.engine.fetch("default.html"); +} + +crow::response handle_auth_page(const site_params& params, uint32_t required_perms) +{ + + + return handle_root_page(params); +} + int main(int argc, const char** argv) { blt::logging::setLogOutputFormat( @@ -58,9 +154,8 @@ int main(int argc, const char** argv) blt::arg_parse parser; parser.addArgument(blt::arg_builder("--tests").setAction(blt::arg_action_t::STORE_TRUE).build()); + parser.addArgument(blt::arg_builder({"--port", "-p"}).setDefault(8080).build()); parser.addArgument(blt::arg_builder("token").build()); - parser.addArgument(blt::arg_builder("user").build()); - parser.addArgument(blt::arg_builder("pass").build()); auto args = parser.parse_args(argc, argv); cs::jellyfin::setToken(blt::arg_parse::get(args["token"])); cs::jellyfin::processUserData(); @@ -71,13 +166,11 @@ int main(int argc, const char** argv) static BLT_CrowLogger bltCrowLogger{}; crow::logger::setHandler(&bltCrowLogger); - using Session = crow::SessionMiddleware; - const auto session_age = 24 * 60 * 60; const auto cookie_age = 180 * 24 * 60 * 60; BLT_INFO("Init Crow with compression and logging enabled!"); - crow::App app{Session{ + CrowApp app{Session{ // customize cookies crow::CookieParser::Cookie("session").max_age(session_age).path("/"), // set session id length (small value only for demonstration purposes) @@ -112,33 +205,24 @@ int main(int argc, const char** argv) } ); + CROW_ROUTE(app, "/login.html")( + [&app, &engine](const crow::request& req) -> crow::response { + if (isUserLoggedIn(app, req)) + return redirect("/"); + return handle_root_page({app, engine, req, "login.html"}); + } + ); + + CROW_ROUTE(app, "/logout.html")( + [&app](const crow::request& req) -> crow::response { + destroyUserSession(app, req); + return redirect("/"); + } + ); + CROW_ROUTE(app, "/")( - [&](const crow::request& req, const std::string& name) -> crow::response { - //auto page = crow::mustache::load("index.html"); // - //return "Hello There

Suck it " + name + "

"; -// BLT_TRACE(req.body); -// for (const auto& h : req.headers) -// BLT_TRACE("Header: %s = %s", h.first.c_str(), h.second.c_str()); -// BLT_TRACE(req.raw_url); -// BLT_TRACE(req.url); -// BLT_TRACE(req.remote_ip_address); -// for (const auto& v : req.url_params.keys()) -// BLT_TRACE("URL: %s = %s", v.c_str(), req.url_params.get(v)); - if (name.ends_with(".html")) - { - crow::mustache::context ctx; - // we don't want to pass all get parameters to the context to prevent leaking - auto referer = req.url_params.get("referer"); - if (referer) - ctx["referer"] = referer; - auto page = crow::mustache::compile(engine.fetch(name)); - return page.render(ctx); - } - - crow::mustache::context ctx({{"person", name}}); - auto user_page = crow::mustache::compile(engine.fetch("index.html")); - - return user_page.render(ctx); + [&app, &engine](const crow::request& req, const std::string& name) -> crow::response { + return handle_root_page({app, engine, req, name}); } ); @@ -147,21 +231,21 @@ int main(int argc, const char** argv) cs::parser::Post pp(req.body); auto& session = app.get_context(req); - crow::response res(303); - std::string user_agent; for (const auto& h : req.headers) - { if (h.first == "User-Agent") + { user_agent = h.second; - } + break; + } // either redirect to clear the form if failed or pass user to index if (cs::checkUserAuthorization(pp)) { cs::cookie_data data = cs::createUserAuthTokens(pp, user_agent); - if (!cs::storeUserData(pp["username"], user_agent, data)){ + if (!cs::storeUserData(pp["username"], user_agent, data)) + { BLT_ERROR("Failed to update user data"); } @@ -173,17 +257,15 @@ int main(int argc, const char** argv) cookie_context.set_cookie("clientID", data.clientID).path("/").max_age(cookie_age); cookie_context.set_cookie("clientToken", data.clientToken).path("/").max_age(cookie_age); } - res.set_header("Location", pp.hasKey("referer") ? pp["referer"] : "/"); + return redirect(pp.hasKey("referer") ? pp["referer"] : "/"); } else - res.set_header("Location", "/login.html"); - - return res; + return redirect("login.html"); } ); CROW_ROUTE(app, "/")( - [&engine]() { - return engine.fetch("index.html"); + [&engine, &app](const crow::request& req) { + return handle_root_page({app, engine, req, "index.html"}); } ); @@ -206,7 +288,9 @@ int main(int argc, const char** argv) } } ); - app.port(8080).multithreaded().run(); + auto port = blt::arg_parse::get_cast(args["port"]); + BLT_INFO("Starting Crow website on port %d", port); + app.port(port).multithreaded().run(); cs::requests::cleanup(); cs::auth::cleanup();