login/logout + /login.html already logged in will redirect to home

main
Brett 2023-08-18 20:00:47 -04:00
parent 0b9997cae8
commit 22a89031c3
6 changed files with 133 additions and 47 deletions

Binary file not shown.

View File

@ -1 +1,2 @@
l5yQfzNDLXuq6Ic1 1692481044 l5yQfzNDLXuq6Ic1 1692481044
7IgWbfRRG3liKhkP 1692489339

View File

@ -0,0 +1 @@
{"clientID":"50a21c33-66c4-5a0f-902f-9434632025e6","clientToken":"TF/rwm67DntB0hrdGiPpYRPFvnZ786r8nrZ4+WQ6wUang4xbqNaZ0AUpXKcHeswaC+IwR0891JZtXP+4XcHsQA=="}

@ -1 +1 @@
Subproject commit 1d03938f950568dd1082abfd55f664ede6023995 Subproject commit bbbf0ba2e57ae202aa83cd2c8178f772a2e14a78

View File

@ -14,6 +14,9 @@
#include <crow/middlewares/session.h> #include <crow/middlewares/session.h>
#include <crow/middlewares/cookie_parser.h> #include <crow/middlewares/cookie_parser.h>
using Session = crow::SessionMiddleware<crow::FileStore>;
using CrowApp = crow::App<crow::CookieParser, Session>;
class BLT_CrowLogger : public crow::ILogHandler class BLT_CrowLogger : public crow::ILogHandler
{ {
public: 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; CrowApp& app;
res.redirect(loc); 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; 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<Session>(req);
auto& cookie_context = app.get_context<crow::CookieParser>(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<Session>(req);
auto& cookie_context = app.get_context<crow::CookieParser>(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<Session>(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<Session>(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 "<html><head><title>Hello There</title></head><body><h1>Suck it " + name + "</h1></body></html>";
// 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) int main(int argc, const char** argv)
{ {
blt::logging::setLogOutputFormat( blt::logging::setLogOutputFormat(
@ -58,9 +154,8 @@ int main(int argc, const char** argv)
blt::arg_parse parser; blt::arg_parse parser;
parser.addArgument(blt::arg_builder("--tests").setAction(blt::arg_action_t::STORE_TRUE).build()); 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("token").build());
parser.addArgument(blt::arg_builder("user").build());
parser.addArgument(blt::arg_builder("pass").build());
auto args = parser.parse_args(argc, argv); auto args = parser.parse_args(argc, argv);
cs::jellyfin::setToken(blt::arg_parse::get<std::string>(args["token"])); cs::jellyfin::setToken(blt::arg_parse::get<std::string>(args["token"]));
cs::jellyfin::processUserData(); cs::jellyfin::processUserData();
@ -71,13 +166,11 @@ int main(int argc, const char** argv)
static BLT_CrowLogger bltCrowLogger{}; static BLT_CrowLogger bltCrowLogger{};
crow::logger::setHandler(&bltCrowLogger); crow::logger::setHandler(&bltCrowLogger);
using Session = crow::SessionMiddleware<crow::FileStore>;
const auto session_age = 24 * 60 * 60; const auto session_age = 24 * 60 * 60;
const auto cookie_age = 180 * 24 * 60 * 60; const auto cookie_age = 180 * 24 * 60 * 60;
BLT_INFO("Init Crow with compression and logging enabled!"); BLT_INFO("Init Crow with compression and logging enabled!");
crow::App<crow::CookieParser, Session> app{Session{ CrowApp app{Session{
// customize cookies // customize cookies
crow::CookieParser::Cookie("session").max_age(session_age).path("/"), crow::CookieParser::Cookie("session").max_age(session_age).path("/"),
// set session id length (small value only for demonstration purposes) // 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, "/<string>")( CROW_ROUTE(app, "/<string>")(
[&](const crow::request& req, const std::string& name) -> crow::response { [&app, &engine](const crow::request& req, const std::string& name) -> crow::response {
//auto page = crow::mustache::load("index.html"); // return handle_root_page({app, engine, req, name});
//return "<html><head><title>Hello There</title></head><body><h1>Suck it " + name + "</h1></body></html>";
// 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);
} }
); );
@ -147,21 +231,21 @@ int main(int argc, const char** argv)
cs::parser::Post pp(req.body); cs::parser::Post pp(req.body);
auto& session = app.get_context<Session>(req); auto& session = app.get_context<Session>(req);
crow::response res(303);
std::string user_agent; std::string user_agent;
for (const auto& h : req.headers) for (const auto& h : req.headers)
{
if (h.first == "User-Agent") if (h.first == "User-Agent")
{
user_agent = h.second; user_agent = h.second;
} break;
}
// either redirect to clear the form if failed or pass user to index // either redirect to clear the form if failed or pass user to index
if (cs::checkUserAuthorization(pp)) if (cs::checkUserAuthorization(pp))
{ {
cs::cookie_data data = cs::createUserAuthTokens(pp, user_agent); 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"); 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("clientID", data.clientID).path("/").max_age(cookie_age);
cookie_context.set_cookie("clientToken", data.clientToken).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 } else
res.set_header("Location", "/login.html"); return redirect("login.html");
return res;
} }
); );
CROW_ROUTE(app, "/")( CROW_ROUTE(app, "/")(
[&engine]() { [&engine, &app](const crow::request& req) {
return engine.fetch("index.html"); 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<int32_t>(args["port"]);
BLT_INFO("Starting Crow website on port %d", port);
app.port(port).multithreaded().run();
cs::requests::cleanup(); cs::requests::cleanup();
cs::auth::cleanup(); cs::auth::cleanup();