From 29c657df8fdb4e09ab631eb915a63f8a3b5dddb3 Mon Sep 17 00:00:00 2001 From: Vladislav Oleshko Date: Tue, 21 Jun 2022 15:38:22 +0300 Subject: [PATCH] Add session id preset, remove boost filesystem, small fixes --- examples/middlewares/example_session.cpp | 55 ++++++++++++++++-------- include/crow/middlewares/session.h | 40 +++++++++-------- include/crow/mustache.h | 5 +-- include/crow/utility.h | 28 +++++++++--- 4 files changed, 83 insertions(+), 45 deletions(-) diff --git a/examples/middlewares/example_session.cpp b/examples/middlewares/example_session.cpp index 11d2758f2..c3b1b287f 100644 --- a/examples/middlewares/example_session.cpp +++ b/examples/middlewares/example_session.cpp @@ -1,7 +1,8 @@ #include "crow.h" #include "crow/middlewares/session.h" -crow::response redirect() { +crow::response redirect() +{ crow::response rsp; rsp.redirect("/"); return rsp; @@ -10,7 +11,7 @@ crow::response redirect() { int main() { // Choose a storage kind for: - // - InMemoryStore stores all entries in memory + // - InMemoryStore stores all entries in memory // - FileStore stores all entries in json files using Session = crow::SessionMiddleware; @@ -18,16 +19,15 @@ int main() // Check out the existing ones for guidelines // Make sure the CookieParser is registered before the Session - crow::App app {Session{ - // choose a secret key for sigining cookies - "MY_SECRET_KEY", - // customize cookies - crow::CookieParser::Cookie("session").max_age(/*one day*/24 * 60 * 60).path("/"), - // set session_id length (small value only for demonstration purposes) - 4, - // init the store - crow::InMemoryStore{} - }}; + crow::App app{Session{ + // choose a secret key for sigining sessions ids + "MY_SECRET_KEY", + // customize cookies + crow::CookieParser::Cookie("session").max_age(/*one day*/ 24 * 60 * 60).path("/"), + // set session id length (small value only for demonstration purposes) + 4, + // init the store + crow::InMemoryStore{}}}; // List all values CROW_ROUTE(app, "/") @@ -37,13 +37,16 @@ int main() // atomically increase number of views // if "views" doesn't exist, it'll be default initialized - session.apply("views", [](int v){ return v + 1; }); + session.apply("views", [](int v) { + return v + 1; + }); // get all currently present keys auto keys = session.keys(); std::string out; - for (const auto& key: keys) out += "

" + key + " = " + session.string(key) + "

"; + for (const auto& key : keys) + out += "

" + key + " = " + session.string(key) + "

"; return out; }); @@ -96,18 +99,34 @@ int main() std::lock_guard l(session.mutex()); - if (session.get("views", 0) % 2 == 0) { + if (session.get("views", 0) % 2 == 0) + { session.set("even", true); - } else { + } + else + { session.evict("even"); } return redirect(); }); + // Manually hand out session ids + // This allows sharing sessions between devices or binding them to users, etc. + // Session ids are signed so they don't have to be random tokens + CROW_ROUTE(app, "/login") + ([&](const crow::request& req) { + auto& session = app.get_context(req); + + if (!session.exists()) + { + session.preset_id("user_email@email.com"); + } + }); + app.port(18080) - //.multithreaded() - .run(); + //.multithreaded() + .run(); return 0; } diff --git a/include/crow/middlewares/session.h b/include/crow/middlewares/session.h index a7c63603d..516a2a0e6 100644 --- a/include/crow/middlewares/session.h +++ b/include/crow/middlewares/session.h @@ -21,10 +21,8 @@ // fallback to boost otherwise #ifdef CROW_CAN_USE_CPP17 #include -#include #else #include "boost/variant.hpp" -#include "boost/filesystem.hpp" #endif namespace crow @@ -34,7 +32,7 @@ namespace crow { using multi_value_types = black_magic::S; - /// A multi_value is a safe variant wrapper with json support + /// A multi_value is a safe variant wrapper with json conversion support #ifdef CROW_CAN_USE_CPP17 struct multi_value { @@ -156,6 +154,8 @@ namespace crow { if (rv.nt() == num_type::Floating_point) return multi_value{rv.d()}; + else if (rv.nt() == num_type::Unsigned_integer) + return multi_value{rv.u()}; else return multi_value{rv.i()}; } @@ -170,6 +170,7 @@ namespace crow struct CachedSession { std::string session_id; + std::string requested_session_id; std::unordered_map entries; // values that were changed after last load @@ -206,7 +207,7 @@ namespace crow } // Check wheter this session is already present - bool valid() { return bool(node); } + bool exists() { return bool(node); } // Get a value by key or fallback if it doesn't exist or is of another type template @@ -220,6 +221,14 @@ namespace crow return fallback; } + // Request a special session id for the store + // WARNING: it does not check for collisions! + void preset_id(std::string id) + { + check_node(); + node->requested_session_id = std::move(id); + } + // Set a value by key template void set(const std::string& key, T value) @@ -348,7 +357,12 @@ namespace crow // generate new id if (ctx.node->session_id == "") { - ctx.node->session_id = next_id(); + // check for requested id + ctx.node->session_id = std::move(ctx.node->requested_session_id); + if (ctx.node->session_id == "") + { + ctx.node->session_id = utility::random_alphanum(id_length_); + } auto& cookies = all_ctx.template get(); store_id(cookies, ctx.node->session_id); } @@ -452,12 +466,7 @@ namespace crow // FileStore stores all data as json files in a folder struct FileStore { -#ifdef CROW_CAN_USE_CPP17 - using path_t = std::filesystem::path; -#else - using path_t = std::string; -#endif - FileStore(const path_t& folder): + FileStore(const std::string& folder): path(folder) {} @@ -485,12 +494,7 @@ namespace crow std::string get_filename(const std::string& key) { -#ifdef CROW_CAN_USE_CPP17 - return path / (key + ".json"); -#else - using namespace boost::filesystem; - return (path / (key + ".json")).string(); -#endif + return utility::join_path(path, key + ".json"); } bool contains(const std::string& key) @@ -499,7 +503,7 @@ namespace crow return file.good(); } - path_t path; + std::string path; }; } // namespace crow diff --git a/include/crow/mustache.h b/include/crow/mustache.h index f77f0775c..c58dcc7e8 100644 --- a/include/crow/mustache.h +++ b/include/crow/mustache.h @@ -643,10 +643,7 @@ namespace crow inline std::string default_loader(const std::string& filename) { std::string path = detail::get_template_base_directory_ref(); - if (!(path.back() == '/' || path.back() == '\\')) - path += '/'; - path += filename; - std::ifstream inf(path); + std::ifstream inf(utility::join_path(path, filename)); if (!inf) { CROW_LOG_WARNING << "Template \"" << filename << "\" not found."; diff --git a/include/crow/utility.h b/include/crow/utility.h index 937e326ef..30287ab00 100644 --- a/include/crow/utility.h +++ b/include/crow/utility.h @@ -12,6 +12,10 @@ #include "crow/settings.h" +#ifdef CROW_CAN_USE_CPP17 +#include +#endif + // TODO(EDev): Adding C++20's [[likely]] and [[unlikely]] attributes might be useful #if defined(__GNUG__) || defined(__clang__) #define CROW_LIKELY(X) __builtin_expect(!!(X), 1) @@ -780,17 +784,31 @@ namespace crow } } } - - inline std::string random_alphanum(std::size_t size) { - static const char alphabet[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + + inline std::string random_alphanum(std::size_t size) + { + static const char alphabet[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; std::random_device dev; std::mt19937 rng(dev()); - std::uniform_int_distribution dist(0, sizeof(alphabet)-2); + std::uniform_int_distribution dist(0, sizeof(alphabet) - 2); std::string out; out.reserve(size); - for (std::size_t i = 0; i < size; i++) out.push_back(alphabet[dist(rng)]); + for (std::size_t i = 0; i < size; i++) + out.push_back(alphabet[dist(rng)]); return out; } + inline std::string join_path(std::string path, const std::string& fname) + { +#ifdef CROW_CAN_USE_CPP17 + return std::filesystem::path(path) / fname; +#else + if (!(path.back() == '/' || path.back() == '\\')) + path += '/'; + path += fname; + return path; +#endif + } + } // namespace utility } // namespace crow