#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class BLT_CrowLogger : public crow::ILogHandler { public: void log(std::string message, crow::LogLevel crow_level) final { blt::logging::log_level blt_level; switch (crow_level) { case crow::LogLevel::DEBUG: blt_level = blt::logging::log_level::DEBUG; break; case crow::LogLevel::INFO: blt_level = blt::logging::log_level::INFO; break; case crow::LogLevel::WARNING: blt_level = blt::logging::log_level::WARN; break; case crow::LogLevel::ERROR: blt_level = blt::logging::log_level::ERROR; break; case crow::LogLevel::CRITICAL: blt_level = blt::logging::log_level::FATAL; break; } BLT_LOG("Crow: %s", blt_level, message.c_str()); } }; inline crow::response redirect(const std::string& loc) { crow::response res; res.redirect(loc); return res; } int main(int argc, const char** argv) { blt::logging::setLogOutputFormat( "\033[94m[${{FULL_TIME}}]${{RC}} ${{LF}}[${{LOG_LEVEL}}]${{RC}} \033[35m(${{FILE}}:${{LINE}})${{RC}} ${{CNR}}${{STR}}${{RC}}\n" ); cs::requests::init(); blt::arg_parse parser; parser.addArgument(blt::arg_builder("--tests").setAction(blt::arg_action_t::STORE_TRUE).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(); cs::auth::init(); BLT_INFO("Starting site %s.", SITE_NAME); crow::mustache::set_global_base(SITE_FILES_PATH); 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{ // customize cookies crow::CookieParser::Cookie("session").max_age(session_age).path("/"), // set session id length (small value only for demonstration purposes) 16, // init the store crow::FileStore{std::string(SITE_FILES_PATH) + "/data/session", session_age}}}; app.use_compression(crow::compression::GZIP); app.loglevel(crow::LogLevel::WARNING); BLT_INFO("Creating static context"); cs::StaticContext context; context["SITE_TITLE"] = SITE_TITLE; context["SITE_NAME"] = SITE_NAME; context["SITE_VERSION"] = SITE_VERSION; context["BEE_MOVIE"] = beemovie_script; context["SITE_BACKGROUND"] = "/static/images/backgrounds/2023-05-26_23.18.23.png"; BLT_INFO("Starting cache engine"); cs::CacheSettings settings; cs::CacheEngine engine(context, settings); BLT_INFO("Creating routes"); CROW_ROUTE(app, "/favicon.ico")( [](crow::response& local_fav_res) { local_fav_res.compressed = false; local_fav_res.set_static_file_info_unsafe(cs::fs::createStaticFilePath("images/favicon.ico")); local_fav_res.set_header("content-type", "image/x-icon"); local_fav_res.end(); } ); 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); } ); CROW_ROUTE(app, "/res/login").methods(crow::HTTPMethod::POST)( [&app](const crow::request& req) { 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; } // 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); cs::storeUserData(pp["username"], user_agent, data); session.set("clientID", data.clientID); session.set("clientToken", data.clientToken); if (pp.hasKey("remember_me") && pp["remember_me"][0] == 'T') { auto& cookie_context = app.get_context(req); 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"] : "/"); } else res.set_header("Location", "/login.html"); return res; } ); CROW_ROUTE(app, "/")( [&engine]() { return engine.fetch("index.html"); } ); CROW_CATCHALL_ROUTE(app)( [&engine]() { return engine.fetch("default.html"); } ); app.tick( std::chrono::seconds(1), [&app, &args]() -> void { if (!args.contains("tests")) return; static uint64_t timer = 0; const uint64_t wait = 10; timer++; if (timer > wait) { app.stop(); } } ); app.port(8080).multithreaded().run(); cs::requests::cleanup(); cs::auth::cleanup(); return 0; }