diff --git a/crow_test/webcontent/projects/post.html b/crow_test/webcontent/projects/post.html new file mode 100644 index 0000000..9434f82 --- /dev/null +++ b/crow_test/webcontent/projects/post.html @@ -0,0 +1,23 @@ + + + + + + + + + + + {{$SITE_TITLE}} + + {{@body_begin.part}} +
+
+ {{CURRENT_POST}} +
+
+ {{@body_end.part}} + diff --git a/crow_test/webcontent/projects/projects.html b/crow_test/webcontent/projects/projects.html new file mode 100644 index 0000000..9434f82 --- /dev/null +++ b/crow_test/webcontent/projects/projects.html @@ -0,0 +1,23 @@ + + + + + + + + + + + {{$SITE_TITLE}} + + {{@body_begin.part}} +
+
+ {{CURRENT_POST}} +
+
+ {{@body_end.part}} + diff --git a/include/crowsite/config.h b/include/crowsite/config.h index 85aeec2..761e324 100644 --- a/include/crowsite/config.h +++ b/include/crowsite/config.h @@ -9,7 +9,8 @@ #include //#define CROW_STATIC_DIRECTORY "/home/brett/projects/cpp/crowsite/crow_test/static/" -#define CROWSITE_STATIC_DIRECTORY "/home/brett/Documents/code/c++/crowsite/crow_test/static/" +#undef CROW_STATIC_DIRECTORY +#define CROW_STATIC_DIRECTORY "/home/brett/Documents/code/c++/crowsite/crow_test/static/" //#define SITE_FILES_PATH "/home/brett/projects/cpp/crowsite/crow_test" #define CROWSITE_FILES_PATH "/home/brett/Documents/code/c++/crowsite/crow_test" #define CROWSITE_STATIC_ENDPOINT "/static/" diff --git a/include/crowsite/crow_pch.h b/include/crowsite/crow_pch.h index 1f8aa86..25b17cb 100644 --- a/include/crowsite/crow_pch.h +++ b/include/crowsite/crow_pch.h @@ -8,6 +8,7 @@ #ifndef CROWSITE_CROW_PCH_H #define CROWSITE_CROW_PCH_H +#include #include "crow/query_string.h" #include "crow/http_parser_merged.h" #include "crow/ci_map.h" diff --git a/include/crowsite/site/home.h b/include/crowsite/site/home.h index 90e0881..7d4fddc 100644 --- a/include/crowsite/site/home.h +++ b/include/crowsite/site/home.h @@ -8,69 +8,16 @@ #ifndef CROWSITE_HOME_H #define CROWSITE_HOME_H -#include #include -#include namespace cs { + + crow::response handle_login_request(const crow::request& req, CrowApp& app); - inline 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")) - { - checkAndUpdateUserSession(params.app, params.req); - auto& session = params.app.get_context(params.req); - auto s_clientID = session.get("clientID", ""); - auto s_clientToken = session.get("clientToken", ""); - auto user_perms = cs::getUserPermissions(cs::getUserFromID(s_clientID)); - - crow::mustache::context ctx; - cs::context context; - - generateRuntimeContext(params, context); - - // pass perms in - if (user_perms & cs::PERM_ADMIN) - ctx["_admin"] = true; - - if (cs::isUserLoggedIn(s_clientID, s_clientToken)) - { - ctx["_logged_in"] = true; - } else - { - ctx["_not_logged_in"] = true; - } - - // we don't want to pass all get parameters to the context to prevent leaking information - auto referer = params.req.url_params.get("referer"); - if (referer) - ctx["referer"] = referer; - auto page = crow::mustache::compile(params.engine.fetch(params.name, context)); - return page.render(ctx); - } - - return params.engine.fetch("default.html"); - } + crow::response handle_root_page(const site_params& params); - inline crow::response handle_auth_page(const site_params& params) - { - if (isUserAdmin(params.app, params.req)) - return redirect("/login.html"); - - - return handle_root_page(params); - } + crow::response handle_auth_page(const site_params& params); } diff --git a/include/crowsite/site/routing.h b/include/crowsite/site/routing.h new file mode 100644 index 0000000..aa17f5f --- /dev/null +++ b/include/crowsite/site/routing.h @@ -0,0 +1,20 @@ +#pragma once +/* + * Created by Brett on 01/09/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ + +#ifndef CROWSITE_ROUTING_H +#define CROWSITE_ROUTING_H + +#include +#include "crowsite/site/cache.h" + +namespace cs +{ + void establishHomeRoutes(CrowApp& app, CacheEngine& engine); + void establishProjectRoutes(CrowApp& app, CacheEngine& engine); +} + +#endif //CROWSITE_ROUTING_H diff --git a/include/crowsite/sql_helper.h b/include/crowsite/sql_helper.h index 396328c..5045457 100644 --- a/include/crowsite/sql_helper.h +++ b/include/crowsite/sql_helper.h @@ -7,29 +7,110 @@ #include #include +#include +#include "blt/std/assert.h" namespace cs::sql { + class sql_error : public std::runtime_error + { + public: + sql_error(const std::string& error): std::runtime_error(error) + {} + }; + static int prepareStatement(sqlite3* db, const std::string& sqlStatement, sqlite3_stmt** ppStmt) { return sqlite3_prepare_v2(db, sqlStatement.c_str(), static_cast(sqlStatement.size()) + 1, ppStmt, nullptr); } - class statement + class database { + friend class statement_base_helper; + private: - sqlite3_stmt* stmt = nullptr; + std::string path; sqlite3* db; - int err; public: - statement(sqlite3* db, const std::string& statement): db(db) + database(const std::string& dbLocation): path(dbLocation) { - err = prepareStatement(db, statement, &stmt); - if (err) - BLT_ERROR("Failed to execute statement, error code %d, error: %s.", err, sqlite3_errstr(err)); + std::filesystem::create_directories(dbLocation.substr(0, dbLocation.find_last_of('/') + 1)); + if (int err = sqlite3_open_v2( + path.c_str(), &db, + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX, + nullptr + ) != SQLITE_OK) + { + BLT_FATAL("Unable to create database connection! err %d msg %s", err, sqlite3_errstr(err)); + std::exit(1); + } } + database(database&& move) + { + db = move.db; + path = move.path; + move.db = nullptr; + } + + database& operator=(database&& move) + { + db = move.db; + path = move.path; + move.db = nullptr; + return *this; + } + + database(const database& copy) = delete; + + database& operator=(const database& copy) = delete; + + ~database() + { + sqlite3_close_v2(db); + } + }; + + class statement_base_helper + { + protected: + sqlite3_stmt* stmt = nullptr; + int err; + + statement_base_helper(const database& db, const std::string& statement, bool throw_errors) + { + err = prepareStatement(db.db, statement, &stmt); + if (err != SQLITE_OK) + { + if (throw_errors) + { + BLT_THROW(std::runtime_error( + "Failed to prepare statement '" + statement + "', error code " + std::to_string(err) + ", error: " + + sqlite3_errstr(err))); + } else + BLT_ERROR("Failed to prepare statement, error code %d, error: %s.", err, sqlite3_errstr(err)); + } + } + }; + + class statement : public statement_base_helper + { + public: + statement(statement&& move) = delete; + + statement(const statement& copy) = delete; + + statement& operator=(statement&& move) = delete; + + statement& operator=(const statement& copy) = delete; + + statement(const database& db, const std::string& statement, bool throw_errors = true): statement_base_helper(db, statement, throw_errors) + {} + + statement(const database* db, const std::string& statement, bool throw_errors = true): statement_base_helper(*db, statement, throw_errors) + {} + /** * @return true if the last statement failed. Should be checked after construction! */ @@ -121,6 +202,12 @@ namespace cs::sql }; + inline void auto_statement(const database* db, const std::string& stmt, bool throw_errors = true){ + statement s(db, stmt, throw_errors); + if (!s.execute() && throw_errors) + BLT_THROW(sql_error("Unable to execute statement '" + stmt + "'. Error: " + std::to_string(s.error()) + sqlite3_errstr(s.error()))); + } + } #endif //CROWSITE_SQL_HELPER_H diff --git a/include/crowsite/util/crow_session_util.h b/include/crowsite/util/crow_session_util.h index 6a66e59..e8919db 100644 --- a/include/crowsite/util/crow_session_util.h +++ b/include/crowsite/util/crow_session_util.h @@ -14,6 +14,8 @@ namespace cs { + constexpr auto session_age = 24 * 60 * 60; + constexpr auto cookie_age = 180 * 24 * 60 * 60; struct site_params { @@ -37,4 +39,9 @@ namespace cs void generateRuntimeContext(const site_params& params, cs::context& context); } +#define CS_SESSION cs::checkAndUpdateUserSession(app, req); \ + auto& session = app.get_context(req); \ + auto s_clientID = session.get("clientID", ""); \ + auto s_clientToken = session.get("clientToken", ""); \ + #endif //CROWSITE_CROW_SESSION_UTIL_H diff --git a/libs/BLT b/libs/BLT index d3ed466..215220f 160000 --- a/libs/BLT +++ b/libs/BLT @@ -1 +1 @@ -Subproject commit d3ed46686eb0667c9824fbba5f90519efd2a50c3 +Subproject commit 215220f98b0ac4a87fe4a233de16650cf6d0b968 diff --git a/src/crowsite/site/auth.cpp b/src/crowsite/site/auth.cpp index 298504b..b219394 100644 --- a/src/crowsite/site/auth.cpp +++ b/src/crowsite/site/auth.cpp @@ -17,7 +17,7 @@ using namespace blt; namespace cs { - sqlite3* user_database; + cs::sql::database* user_database; // https://stackoverflow.com/questions/5288076/base64-encoding-and-decoding-with-openssl @@ -191,28 +191,15 @@ namespace cs void auth::init() { // TODO: proper multithreading - auto path = cs::fs::createDataFilePath("db/"); - auto dbname = "users.sqlite"; - auto full_path = path + dbname; - BLT_TRACE("Using %s for users database", full_path.c_str()); - std::filesystem::create_directories(path); - if (int err = sqlite3_open_v2(full_path.c_str(), &user_database, - SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX, - nullptr - ) != SQLITE_OK) - { - BLT_FATAL("Unable to create database connection! err %d msg %s", err, sqlite3_errstr(err)); - std::exit(1); - } + const auto path = cs::fs::createDataFilePath("db/users.sqlite"); + BLT_TRACE("Using %s for users database", path.c_str()); + user_database = new sql::database(path); sql::statement v { user_database, "SELECT SQLITE_VERSION()" }; - if (v.fail()) - BLT_WARN("Failed to create statement with error code: %d msg: %s", v.error(), sqlite3_errstr(v.error())); - if (!v.execute()) BLT_WARN("Failed to execute statement with error code: %d msg: %s", v.error(), sqlite3_errstr(v.error())); @@ -237,6 +224,6 @@ namespace cs void auth::cleanup() { - sqlite3_close_v2(user_database); + delete(user_database); } } \ No newline at end of file diff --git a/src/crowsite/site/cache.cpp b/src/crowsite/site/cache.cpp index a3aea5d..7046870 100644 --- a/src/crowsite/site/cache.cpp +++ b/src/crowsite/site/cache.cpp @@ -136,6 +136,7 @@ namespace cs case TokenType::CLOSE: return "CLOSE"; } + throw LexerSyntaxError("Unable to determine type of token"); } struct Token @@ -254,6 +255,7 @@ namespace cs default: blt_throw(LexerSyntaxError("Weird token found while parsing tokens, type: " + decodeName(next.type))); } + return false; } bool expr(const context& context) @@ -297,12 +299,7 @@ namespace cs return false; return str[index] == '{' && str[index + 1] == '{' && str[index + 2] == c; } - - static std::string consumeToEndTemplate(const std::string& tokenName) - { - - } - + static void getTagLocations(std::vector& tagLocations, const std::string& tag, const std::string& data) { RuntimeLexer lexer(data); diff --git a/src/crowsite/site/home.cpp b/src/crowsite/site/home.cpp index 194269b..f10b9f0 100644 --- a/src/crowsite/site/home.cpp +++ b/src/crowsite/site/home.cpp @@ -4,8 +4,103 @@ * See LICENSE file for license detail */ #include +#include +#include namespace cs { - + + 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")) + { + checkAndUpdateUserSession(params.app, params.req); + auto& session = params.app.get_context(params.req); + auto s_clientID = session.get("clientID", ""); + auto s_clientToken = session.get("clientToken", ""); + auto user_perms = cs::getUserPermissions(cs::getUserFromID(s_clientID)); + + crow::mustache::context ctx; + cs::context context; + + generateRuntimeContext(params, context); + + // pass perms in + if (user_perms & cs::PERM_ADMIN) + ctx["_admin"] = true; + + if (cs::isUserLoggedIn(s_clientID, s_clientToken)) + { + ctx["_logged_in"] = true; + } else + { + ctx["_not_logged_in"] = true; + } + + // we don't want to pass all get parameters to the context to prevent leaking information + auto referer = params.req.url_params.get("referer"); + if (referer) + ctx["referer"] = referer; + auto page = crow::mustache::compile(params.engine.fetch(params.name, context)); + return page.render(ctx); + } + + return params.engine.fetch("default.html"); + } + + crow::response handle_auth_page(const site_params& params) + { + if (isUserAdmin(params.app, params.req)) + return redirect("/login.html"); + + + return handle_root_page(params); + } + + crow::response handle_login_request(const crow::request& req, CrowApp& app) + { + cs::parser::Post pp(req.body); + auto& session = app.get_context(req); + + std::string user_agent; + + for (const auto& h : req.headers) + if (h.first == "User-Agent") + { + user_agent = h.second; + break; + } + + // either cs::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)) + { + BLT_ERROR("Failed to update user data"); + return cs::redirect("login.html"); + } + + 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); + } + return cs::redirect(pp.hasKey("referer") ? pp["referer"] : "/"); + } else + return cs::redirect("login.html"); + } } \ No newline at end of file diff --git a/src/crowsite/site/posts.cpp b/src/crowsite/site/posts.cpp index 133f86a..2617411 100644 --- a/src/crowsite/site/posts.cpp +++ b/src/crowsite/site/posts.cpp @@ -8,29 +8,57 @@ #include #include #include +#include +#include namespace cs { + sql::database* posts_database; response_info handleProjectPage(const request_info& req) { - std::string buffer; - buffer += ""; - auto htmlData = loadMarkdownAsHTML(cs::fs::createDataFilePath("Billionaire Propaganda.md")); - buffer += htmlData; - buffer += ""; + if (req.url_params.contains("post")) + { + BLT_TRACE(req.url_params.at("post")); + sql::statement posts(posts_database, "SELECT file FROM posts WHERE postID=?;"); + posts.set(req.url_params.at("post"), 0); + posts.execute(); + return {loadMarkdownAsHTML(cs::fs::createDataFilePath(posts.get(2)))}; + } - return {buffer}; + return {""}; } void posts_init() { - + + posts_database = new sql::database(cs::fs::createDataFilePath("db/posts.sqlite")); + + sql::auto_statement( + posts_database, + "CREATE TABLE IF NOT EXISTS posts(postID INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT, title TEXT, file TEXT);" + ); + + sql::auto_statement( + posts_database, + "CREATE TABLE IF NOT EXISTS modifications(postID INTEGER, date TEXT, FOREIGN KEY(postID) REFERENCES posts(postID));" + ); + + sql::auto_statement( + posts_database, + "CREATE TABLE IF NOT EXISTS tags(postID INTEGER, tag TEXT, FOREIGN KEY(postID) REFERENCES posts(postID));" + ); + + sql::auto_statement( + posts_database, + "CREATE TABLE IF NOT EXISTS types(postID INTEGER, type INTEGER, FOREIGN KEY(postID) REFERENCES posts(postID));" + ); + } void posts_cleanup() { - + delete posts_database; } diff --git a/src/crowsite/site/routing.cpp b/src/crowsite/site/routing.cpp new file mode 100644 index 0000000..305f3d6 --- /dev/null +++ b/src/crowsite/site/routing.cpp @@ -0,0 +1,69 @@ +/* + * Created by Brett on 01/09/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ +#include +#include +#include "crowsite/util/crow_session_util.h" +#include "crowsite/utility.h" +#include "crowsite/util/crow_conversion.h" +#include "crowsite/site/home.h" + +namespace cs +{ + inline void createLoginRoutes(CrowApp& app, CacheEngine& engine) + { + CROW_ROUTE(app, "/login.html")( + [&app, &engine](const crow::request& req) -> crow::response { + if (cs::isUserLoggedIn(app, req)) + return cs::redirect("/"); + return cs::handle_root_page({app, engine, req, "login.html"}); + } + ); + + CROW_ROUTE(app, "/logout.html")( + [&app](const crow::request& req) -> crow::response { + cs::destroyUserSession(app, req); + return cs::redirect("/"); + } + ); + + CROW_ROUTE(app, "/res/login").methods(crow::HTTPMethod::POST)( + [&app](const crow::request& req) { + return cs::handle_login_request(req, app); + } + ); + } + + void establishHomeRoutes(CrowApp& app, CacheEngine& engine) + { + 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(); + } + ); + + createLoginRoutes(app, engine); + + CROW_ROUTE(app, "/")( + [&app, &engine](const crow::request& req, const std::string& name) -> crow::response { + return cs::handle_root_page({app, engine, req, name}); + } + ); + + CROW_ROUTE(app, "/")( + [&engine, &app](const crow::request& req) { + return cs::handle_root_page({app, engine, req, "index.html"}); + } + ); + } + + void establishProjectRoutes(CrowApp& app, CacheEngine& engine) + { + + } +} \ No newline at end of file diff --git a/src/crowsite/utility.cpp b/src/crowsite/utility.cpp index 2c57374..5f59452 100644 --- a/src/crowsite/utility.cpp +++ b/src/crowsite/utility.cpp @@ -55,13 +55,13 @@ namespace cs { std::string createStaticFilePath(const std::string& file) { - auto path = std::string(CROWSITE_STATIC_DIRECTORY); + auto path = std::string(CROW_STATIC_DIRECTORY); if (!path.ends_with('/')) path += '/'; path += file; // prevent crow from hanging web responses when we make a typo in the filename - if (!std::filesystem::exists(path)) - throw std::runtime_error("Unable to create file path because file does not exist!"); + if (!std::filesystem::exists(path.substr(0, path.find_last_of('/')))) + throw std::runtime_error("Unable to create file path because path does not exist!"); return path; } @@ -72,8 +72,8 @@ namespace cs path += '/'; path += "webcontent/"; path += file; - if (!std::filesystem::exists(path)) - throw std::runtime_error("Unable to create file path because file does not exist!"); + if (!std::filesystem::exists(path.substr(0, path.find_last_of('/')))) + throw std::runtime_error("Unable to create file path because folder does not exist!"); return path; } @@ -84,8 +84,8 @@ namespace cs path += '/'; path += "data/"; path += file; - if (!std::filesystem::exists(path)) - throw std::runtime_error("Unable to create file path because file does not exist!"); + if (!std::filesystem::exists(path.substr(0, path.find_last_of('/')))) + throw std::runtime_error("Unable to create file path because folder does not exist!"); return path; } } diff --git a/src/main.cpp b/src/main.cpp index 2849805..cfcd5f2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,11 +11,7 @@ #include #include #include - -#define CS_SESSION cs::checkAndUpdateUserSession(app, req); \ - auto& session = app.get_context(req); \ - auto s_clientID = session.get("clientID", ""); \ - auto s_clientToken = session.get("clientToken", ""); \ +#include int main(int argc, const char** argv) { @@ -27,6 +23,7 @@ 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("--standalone").setAction(blt::arg_action_t::STORE_TRUE).build()); parser.addArgument(blt::arg_builder({"--port", "-p"}).setDefault(8080).build()); parser.addArgument(blt::arg_builder("token").setRequired().build()); auto args = parser.parse_args(argc, argv); @@ -39,17 +36,14 @@ int main(int argc, const char** argv) static BLT_CrowLogger bltCrowLogger{}; crow::logger::setHandler(&bltCrowLogger); - const auto session_age = 24 * 60 * 60; - const auto cookie_age = 180 * 24 * 60 * 60; - BLT_INFO("Init Crow with compression and logging enabled!"); CrowApp app{Session{ // customize cookies - crow::CookieParser::Cookie("session").max_age(session_age).path("/"), + crow::CookieParser::Cookie("session").max_age(cs::session_age).path("/"), // set session id length (small value only for demonstration purposes) 16, // init the store - crow::FileStore{std::string(CROWSITE_FILES_PATH) + "/data/session", session_age}}}; + crow::FileStore{std::string(CROWSITE_FILES_PATH) + "/data/session", cs::session_age}}}; app.use_compression(crow::compression::GZIP); app.loglevel(crow::LogLevel::WARNING); @@ -74,73 +68,7 @@ int main(int argc, const char** argv) 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, "/login.html")( - [&app, &engine](const crow::request& req) -> crow::response { - if (cs::isUserLoggedIn(app, req)) - return cs::redirect("/"); - return cs::handle_root_page({app, engine, req, "login.html"}); - } - ); - - CROW_ROUTE(app, "/logout.html")( - [&app](const crow::request& req) -> crow::response { - cs::destroyUserSession(app, req); - return cs::redirect("/"); - } - ); - - CROW_ROUTE(app, "/")( - [&app, &engine](const crow::request& req, const std::string& name) -> crow::response { - return cs::handle_root_page({app, engine, req, name}); - } - ); - - 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); - - std::string user_agent; - - for (const auto& h : req.headers) - if (h.first == "User-Agent") - { - user_agent = h.second; - break; - } - - // either cs::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)) - { - BLT_ERROR("Failed to update user data"); - return cs::redirect("login.html"); - } - - 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); - } - return cs::redirect(pp.hasKey("referer") ? pp["referer"] : "/"); - } else - return cs::redirect("login.html"); - } - ); + cs::establishHomeRoutes(app, engine); CROW_ROUTE(app, "/projects/")( [&engine, &app](const crow::request& req, const std::string& path) { @@ -162,12 +90,6 @@ int main(int argc, const char** argv) } ); - CROW_ROUTE(app, "/")( - [&engine, &app](const crow::request& req) { - return cs::handle_root_page({app, engine, req, "index.html"}); - } - ); - CROW_CATCHALL_ROUTE(app)( [&engine]() { return engine.fetch("default.html"); @@ -187,9 +109,27 @@ int main(int argc, const char** argv) } } ); + +// int flags = fcntl(0, F_GETFL, 0); +// fcntl(0, F_SETFL, flags | O_NONBLOCK); + auto port = blt::arg_parse::get_cast(args["port"]); BLT_INFO("Starting Crow website on port %d", port); - app.port(port).multithreaded().run(); + + if (args.contains("standalone")) + { + auto crw = app.port(port).multithreaded().run_async(); + std::string line; + while (crw.valid()) + { + //std::cin.clear(std::ios::badbit | std::ios::failbit | std::ios::eofbit); + std::getline(std::cin, line); + + if (!line.empty()) + BLT_TRACE(line); + } + } else + app.port(port).multithreaded().run(); cs::posts_cleanup();