reorder some of the main files

main
Brett 2023-08-29 11:48:55 -04:00
parent 92c059912e
commit 0c8ab4f082
25 changed files with 532 additions and 282 deletions

View File

@ -11,6 +11,8 @@ set(CROW_FEATURES compression)
cmake_policy(SET CMP0057 NEW) cmake_policy(SET CMP0057 NEW)
#find_package(Crow) #find_package(Crow)
set(PRECOMPILED_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/crowsite/crow_pch.h")
set(CROW_BUILD_TESTS OFF) set(CROW_BUILD_TESTS OFF)
set(CROW_BUILD_EXAMPLES OFF) set(CROW_BUILD_EXAMPLES OFF)
set(CROW_INSTALL OFF) set(CROW_INSTALL OFF)
@ -43,7 +45,7 @@ include_directories(${OPENSSL_INCLUDE_DIR})
file(GLOB_RECURSE source_files src/*.cpp) file(GLOB_RECURSE source_files src/*.cpp)
add_executable(crowsite ${source_files}) add_executable(crowsite ${source_files} ${PRECOMPILED_HEADER})
target_compile_definitions(crowsite PUBLIC CROW_ENABLE_COMPRESSION) target_compile_definitions(crowsite PUBLIC CROW_ENABLE_COMPRESSION)
@ -70,3 +72,5 @@ if (${ENABLE_TSAN} MATCHES ON)
target_compile_options(crowsite PRIVATE -fsanitize=thread) target_compile_options(crowsite PRIVATE -fsanitize=thread)
target_link_options(crowsite PRIVATE -fsanitize=thread) target_link_options(crowsite PRIVATE -fsanitize=thread)
endif () endif ()
target_precompile_headers(crowsite PRIVATE ${PRECOMPILED_HEADER})

View File

@ -9,10 +9,10 @@
#include <blt/std/hashmap.h> #include <blt/std/hashmap.h>
//#define CROW_STATIC_DIRECTORY "/home/brett/projects/cpp/crowsite/crow_test/static/" //#define CROW_STATIC_DIRECTORY "/home/brett/projects/cpp/crowsite/crow_test/static/"
#define CROW_STATIC_DIRECTORY "/home/brett/Documents/code/c++/crowsite/crow_test/static/" #define CROWSITE_STATIC_DIRECTORY "/home/brett/Documents/code/c++/crowsite/crow_test/static/"
//#define SITE_FILES_PATH "/home/brett/projects/cpp/crowsite/crow_test" //#define SITE_FILES_PATH "/home/brett/projects/cpp/crowsite/crow_test"
#define SITE_FILES_PATH "/home/brett/Documents/code/c++/crowsite/crow_test" #define CROWSITE_FILES_PATH "/home/brett/Documents/code/c++/crowsite/crow_test"
#define CROW_STATIC_ENDPOINT "/static/<path>" #define CROWSITE_STATIC_ENDPOINT "/static/<path>"
#define MILES_SITE #define MILES_SITE
#undef MILES_SITE #undef MILES_SITE

View File

@ -6,6 +6,6 @@
#define CROWSITE_CROW_INCLUDES_H #define CROWSITE_CROW_INCLUDES_H
#include <crowsite/config.h> #include <crowsite/config.h>
#include "crow.h" #include <crowsite/crow_pch.h>
#endif //CROWSITE_CROW_INCLUDES_H #endif //CROWSITE_CROW_INCLUDES_H

View File

@ -0,0 +1,42 @@
#pragma once
/*
* Created by Brett on 29/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#ifndef CROWSITE_CROW_PCH_H
#define CROWSITE_CROW_PCH_H
#include "crow/query_string.h"
#include "crow/http_parser_merged.h"
#include "crow/ci_map.h"
#include "crow/TinySHA1.hpp"
#include "crow/settings.h"
#include "crow/socket_adaptors.h"
#include "crow/json.h"
#include "crow/mustache.h"
#include "crow/logging.h"
#include "crow/task_timer.h"
#include "crow/utility.h"
#include "crow/common.h"
#include "crow/http_request.h"
#include "crow/websocket.h"
#include "crow/parser.h"
#include "crow/http_response.h"
#include "crow/multipart.h"
#include "crow/routing.h"
#include "crow/middleware.h"
#include "crow/middleware_context.h"
#include "crow/compression.h"
#include "crow/http_connection.h"
#include "crow/http_server.h"
#include "crow/app.h"
#include "crow/middlewares/session.h"
#include "crow/middlewares/cookie_parser.h"
using Session = crow::SessionMiddleware<crow::FileStore>;
using CrowApp = crow::App<crow::CookieParser, Session>;
#endif //CROWSITE_CROW_PCH_H

View File

@ -1,19 +0,0 @@
//
// Created by brett on 21/08/23.
//
#ifndef CROWSITE_CROW_UTILITY_H
#define CROWSITE_CROW_UTILITY_H
#include <crow/http_response.h>
namespace cs {
inline crow::response redirect(const std::string& loc = "/", int code = 303)
{
crow::response res(code);
res.set_header("Location", loc);
return res;
}
}
#endif //CROWSITE_CROW_UTILITY_H

View File

@ -6,14 +6,13 @@
#define CROWSITE_CACHE_H #define CROWSITE_CACHE_H
#include <crowsite/site/web.h> #include <crowsite/site/web.h>
#include <crowsite/util/crow_typedef.h>
#include <filesystem> #include <filesystem>
#include <blt/std/hashmap.h> #include <blt/std/hashmap.h>
namespace cs namespace cs
{ {
using RuntimeContext = HASHMAP<std::string, std::string>;
class LexerSyntaxError : public std::runtime_error class LexerSyntaxError : public std::runtime_error
{ {
public: public:
@ -54,7 +53,7 @@ namespace cs
std::string renderedPage; std::string renderedPage;
}; };
StaticContext& m_Context; context& m_Context;
CacheSettings m_Settings; CacheSettings m_Settings;
HASHMAP<std::string, CacheValue> m_Pages; HASHMAP<std::string, CacheValue> m_Pages;
@ -75,11 +74,11 @@ namespace cs
void prune(uint64_t amount); void prune(uint64_t amount);
public: public:
explicit CacheEngine(StaticContext& context, const CacheSettings& settings = {}); explicit CacheEngine(context& context, const CacheSettings& settings = {});
const std::string& fetch(const std::string& path); const std::string& fetch(const std::string& path);
std::string fetch(const std::string& path, const RuntimeContext& context); std::string fetch(const std::string& path, const context& context);
}; };
} }

View File

@ -0,0 +1,77 @@
#pragma once
/*
* Created by Brett on 27/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#ifndef CROWSITE_HOME_H
#define CROWSITE_HOME_H
#include <crowsite/site/cache.h>
#include <crowsite/util/crow_session_util.h>
#include <crowsite/util/crow_conversion.h>
namespace cs
{
inline 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"))
{
checkAndUpdateUserSession(params.app, params.req);
auto& session = params.app.get_context<Session>(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");
}
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);
}
}
#endif //CROWSITE_HOME_H

View File

@ -9,21 +9,14 @@
#define CROWSITE_POSTS_H #define CROWSITE_POSTS_H
#include <crowsite/site/cache.h> #include <crowsite/site/cache.h>
#include <crow/http_request.h> #include <crowsite/util/crow_fix.h>
#include <crow/http_response.h>
namespace cs namespace cs
{ {
struct request_info { void posts_init();
CacheEngine& engine; void posts_cleanup();
const crow::request& req;
std::string clientID; response_info handleProjectPage(const request_info& req);
std::string tokenID;
std::string path;
};
crow::response handleProjectPage(const request_info& req);
} }
#endif //CROWSITE_POSTS_H #endif //CROWSITE_POSTS_H

View File

@ -8,28 +8,11 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <crowsite/config.h> #include <crowsite/config.h>
#include <crowsite/util/crow_typedef.h>
#include <utility> #include <utility>
namespace cs { namespace cs {
class StaticContext {
private:
HASHMAP<std::string, std::string> replacements;
public:
inline auto begin() {
return replacements.begin();
}
inline auto end() {
return replacements.end();
}
inline std::string& operator[](const std::string& key){
return replacements[key];
}
inline void add(const std::string& key, const std::string& value){
replacements[key] = value;
}
};
class HTMLPage { class HTMLPage {
private: private:
std::string m_SiteData; std::string m_SiteData;

View File

@ -0,0 +1,29 @@
#pragma once
/*
* Created by Brett on 29/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#ifndef CROWSITE_CROW_CONVERSION_H
#define CROWSITE_CROW_CONVERSION_H
#include "crow/http_response.h"
#include <crowsite/util/crow_fix.h>
namespace cs
{
crow::response toResponse(cs::response_info res);
inline crow::response redirect(const std::string& loc, int code = 303)
{
crow::response res(code);
res.set_header("Location", loc);
return res;
}
}
#endif //CROWSITE_CROW_CONVERSION_H

View File

@ -0,0 +1,45 @@
#pragma once
/*
* Created by Brett on 27/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#ifndef CROWSITE_CROW_FIX_H
#define CROWSITE_CROW_FIX_H
/**
* Basically waste a bunch of time to both a. reduce the compile time of using crow
* and b. reduce the runtime overhead of crow, by increasing runtime in some respects
* TODO: explain why this is better later, maybe test as well.
*/
#include <vector>
#include <optional>
#include <blt/std/hashmap.h>
#include "crowsite/site/cache.h"
#include "crowsite/util/crow_typedef.h"
namespace cs
{
query_string toQueryString(const std::vector<char*>& kv);
struct request_info
{
std::string raw_url; ///< The full URL containing the `?` and URL parameters.
std::string clientID;
std::string tokenID;
std::string path;
query_string url_params; ///< The parameters associated with the request. (everything after the `?` in the URL)
CacheEngine& engine;
std::optional<header_map> headers{};
};
struct response_info
{
std::string body;
std::optional<context> ctx{};
};
}
#endif //CROWSITE_CROW_FIX_H

View File

@ -0,0 +1,20 @@
#pragma once
/*
* Created by Brett on 29/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#ifndef CROWSITE_CROW_LOG_H
#define CROWSITE_CROW_LOG_H
#include <string>
#include <crow/logging.h>
class BLT_CrowLogger : public crow::ILogHandler
{
public:
void log(std::string message, crow::LogLevel crow_level) final;
};
#endif //CROWSITE_CROW_LOG_H

View File

@ -0,0 +1,40 @@
#pragma once
/*
* Created by Brett on 29/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#ifndef CROWSITE_CROW_SESSION_UTIL_H
#define CROWSITE_CROW_SESSION_UTIL_H
#include "crowsite/site/auth.h"
#include "crow_typedef.h"
#include "crowsite/site/cache.h"
namespace cs
{
struct site_params
{
CrowApp& app;
cs::CacheEngine& engine;
const crow::request& req;
const std::string& name;
};
/**
* Note this function destroys the user's session and any login related cookies!
*/
void destroyUserSession(CrowApp& app, const crow::request& req);
bool checkAndUpdateUserSession(CrowApp& app, const crow::request& req);
bool isUserLoggedIn(CrowApp& app, const crow::request& req);
bool isUserAdmin(CrowApp& app, const crow::request& req);
void generateRuntimeContext(const site_params& params, cs::context& context);
}
#endif //CROWSITE_CROW_SESSION_UTIL_H

View File

@ -0,0 +1,20 @@
#pragma once
/*
* Created by Brett on 28/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#ifndef CROWSITE_CROW_TYPEDEF_H
#define CROWSITE_CROW_TYPEDEF_H
#include <string>
namespace cs
{
typedef HASHMAP<std::string, std::string> header_map;
typedef HASHMAP<std::string, std::string> query_string;
typedef HASHMAP<std::string, std::string> context;
}
#endif //CROWSITE_CROW_TYPEDEF_H

View File

@ -469,6 +469,11 @@ namespace crow
} }
return ret; return ret;
} }
inline const std::vector<char*>& getValues() const
{
return key_value_pairs_;
}
std::vector<std::string> keys() const std::vector<std::string> keys() const
{ {

View File

@ -4,6 +4,7 @@
#include <crowsite/site/auth.h> #include <crowsite/site/auth.h>
#include <crowsite/config.h> #include <crowsite/config.h>
#include <crowsite/requests/jellyfin.h> #include <crowsite/requests/jellyfin.h>
#include <crowsite/utility.h>
#include "blt/std/logging.h" #include "blt/std/logging.h"
#include "blt/std/uuid.h" #include "blt/std/uuid.h"
#include <openssl/sha.h> #include <openssl/sha.h>
@ -190,7 +191,7 @@ namespace cs
void auth::init() void auth::init()
{ {
// TODO: proper multithreading // TODO: proper multithreading
auto path = (std::string(SITE_FILES_PATH) + "/data/db/"); auto path = cs::fs::createDataFilePath("db/");
auto dbname = "users.sqlite"; auto dbname = "users.sqlite";
auto full_path = path + dbname; auto full_path = path + dbname;
BLT_TRACE("Using %s for users database", full_path.c_str()); BLT_TRACE("Using %s for users database", full_path.c_str());

View File

@ -224,14 +224,14 @@ namespace cs
} }
} }
static inline bool isTrue(const RuntimeContext& context, const std::string& token) static inline bool isTrue(const context& context, const std::string& token)
{ {
//BLT_DEBUG("isTrue for token '%s' contains? %s", token.c_str(), context.contains(token) ? "True" : "False"); //BLT_DEBUG("isTrue for token '%s' contains? %s", token.c_str(), context.contains(token) ? "True" : "False");
return context.contains(token) && !context.at(token).empty(); return context.contains(token) && !context.at(token).empty();
} }
// http://www.cs.unb.ca/~wdu/cs4613/a2ans.htm // http://www.cs.unb.ca/~wdu/cs4613/a2ans.htm
bool factor(const RuntimeContext& context) bool factor(const context& context)
{ {
if (!hasNextToken()) if (!hasNextToken())
blt_throw(LexerSyntaxError("Processing boolean factor but no token was found!")); blt_throw(LexerSyntaxError("Processing boolean factor but no token was found!"));
@ -256,7 +256,7 @@ namespace cs
} }
} }
bool expr(const RuntimeContext& context) bool expr(const context& context)
{ {
auto fac = factor(context); auto fac = factor(context);
if (!hasNextToken()) if (!hasNextToken())
@ -281,7 +281,7 @@ namespace cs
processString(); processString();
} }
bool eval(const RuntimeContext& context) bool eval(const context& context)
{ {
return expr(context); return expr(context);
} }
@ -335,7 +335,7 @@ namespace cs
return tagLocations[0]; return tagLocations[0];
} }
static std::string searchAndReplace(const std::string& data, const RuntimeContext& context) static std::string searchAndReplace(const std::string& data, const context& context)
{ {
RuntimeLexer lexer(data); RuntimeLexer lexer(data);
std::string results; std::string results;
@ -373,7 +373,7 @@ namespace cs
if (lexer.hasTemplatePrefix('/')) if (lexer.hasTemplatePrefix('/'))
lexer.consumeToken(); lexer.consumeToken();
else else
blt_throw(LexerSyntaxError("Ending token not found!")); blt_throw(LexerSyntaxError("Ending token not found!"));
} else } else
results += lexer.consume(); results += lexer.consume();
@ -389,8 +389,8 @@ namespace cs
return (double) (v) / 1000000000.0; return (double) (v) / 1000000000.0;
} }
CacheEngine::CacheEngine(StaticContext& context, const CacheSettings& settings): m_Context(context), CacheEngine::CacheEngine(context& ctx, const CacheSettings& settings): m_Context(ctx),
m_Settings((settings)) m_Settings((settings))
{} {}
uint64_t CacheEngine::calculateMemoryUsage(const std::string& path, const CacheEngine::CacheValue& value) uint64_t CacheEngine::calculateMemoryUsage(const std::string& path, const CacheEngine::CacheValue& value)
@ -571,7 +571,7 @@ namespace cs
page.getRawSite() = resolvedSite; page.getRawSite() = resolvedSite;
} }
std::string CacheEngine::fetch(const std::string& path, const RuntimeContext& context) std::string CacheEngine::fetch(const std::string& path, const context& context)
{ {
auto fetched = fetch(path); auto fetched = fetch(path);
return RuntimeLexer::searchAndReplace(fetched, context); return RuntimeLexer::searchAndReplace(fetched, context);

View File

@ -0,0 +1,11 @@
/*
* Created by Brett on 27/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#include <crowsite/site/home.h>
namespace cs
{
}

View File

@ -4,6 +4,7 @@
* See LICENSE file for license detail * See LICENSE file for license detail
*/ */
#include <crowsite/site/posts.h> #include <crowsite/site/posts.h>
#include <crowsite/site/auth.h>
#include <crowsite/utility.h> #include <crowsite/utility.h>
#include <crowsite/util/md_to_html.h> #include <crowsite/util/md_to_html.h>
#include <blt/std/logging.h> #include <blt/std/logging.h>
@ -11,7 +12,7 @@
namespace cs namespace cs
{ {
crow::response handleProjectPage(const request_info& req) response_info handleProjectPage(const request_info& req)
{ {
std::string buffer; std::string buffer;
buffer += "<html><head></head><body>"; buffer += "<html><head></head><body>";
@ -19,9 +20,18 @@ namespace cs
buffer += htmlData; buffer += htmlData;
buffer += "</body>"; buffer += "</body>";
return buffer; return {buffer};
}
void posts_init()
{
}
void posts_cleanup()
{
} }
} }

View File

@ -0,0 +1,22 @@
/*
* Created by Brett on 27/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#include <crowsite/util/crow_fix.h>
namespace cs
{
query_string toQueryString(const std::vector<char*>& key_values)
{
query_string query_kv;
for (const auto& kv : key_values)
{
std::string str(kv);
auto equ_loc = str.find('=');
query_kv[str.substr(0, equ_loc)] = str.substr(equ_loc+1, str.size());
}
return query_kv;
}
}

View File

@ -0,0 +1,50 @@
/*
* Created by Brett on 29/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#include <crowsite/util/crow_log.h>
#include <crowsite/util/crow_conversion.h>
#include <blt/std/logging.h>
void BLT_CrowLogger::log(std::string message, crow::LogLevel crow_level)
{
blt::logging::log_level blt_level = blt::logging::log_level::NONE;
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());
}
namespace cs
{
crow::response toResponse(cs::response_info res)
{
if (res.ctx.has_value())
{
auto v = crow::mustache::compile(res.body);
crow::mustache::context ctx;
for (const auto& c : res.ctx.value())
ctx[c.first] = c.second;
return v.render(ctx);
}
return res.body;
}
}

View File

@ -0,0 +1,88 @@
/*
* Created by Brett on 29/08/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#include <crowsite/util/crow_session_util.h>
#include <crowsite/crow_pch.h>
namespace cs
{
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));
}
void generateRuntimeContext(const site_params& params, cs::context& context)
{
auto& session = params.app.get_context<Session>(params.req);
auto s_clientID = session.get("clientID", "");
auto s_clientToken = session.get("clientToken", "");
if (cs::isUserLoggedIn(s_clientID, s_clientToken))
{
auto username = cs::getUserFromID(s_clientID);
auto perms = cs::getUserPermissions(username);
auto isAdmin = cs::isUserAdmin(username);
context["_logged_in"] = "True";
context["_username"] = username;
if (isAdmin)
context["_admin"] = "True";
if (perms & cs::PERM_READ_FILES)
context["_read_files"] = "True";
if (perms & cs::PERM_WRITE_FILES)
context["_write_files"] = "True";
if (perms & cs::PERM_CREATE_POSTS)
context["_create_posts"] = "True";
if (perms & cs::PERM_CREATE_COMMENTS)
context["_create_comments"] = "True";
if (perms & cs::PERM_CREATE_SHARES)
context["_create_shares"] = "True";
if (perms & cs::PERM_EDIT_POSTS)
context["_edit_posts"] = "True";
if (perms & cs::PERM_EDIT_COMMENTS)
context["_edit_comments"] = "True";
}
}
}

View File

@ -47,7 +47,7 @@ namespace cs {
std::string str() std::string str()
{ {
std::string out (buffer, buffer + used_size); std::string out (buffer, used_size);
return out; return out;
} }
}; };

View File

@ -55,7 +55,7 @@ namespace cs
{ {
std::string createStaticFilePath(const std::string& file) std::string createStaticFilePath(const std::string& file)
{ {
auto path = std::string(CROW_STATIC_DIRECTORY); auto path = std::string(CROWSITE_STATIC_DIRECTORY);
if (!path.ends_with('/')) if (!path.ends_with('/'))
path += '/'; path += '/';
path += file; path += file;
@ -67,7 +67,7 @@ namespace cs
std::string createWebFilePath(const std::string& file) std::string createWebFilePath(const std::string& file)
{ {
auto path = std::string(SITE_FILES_PATH); auto path = std::string(CROWSITE_FILES_PATH);
if (!path.ends_with('/')) if (!path.ends_with('/'))
path += '/'; path += '/';
path += "webcontent/"; path += "webcontent/";
@ -79,7 +79,7 @@ namespace cs
std::string createDataFilePath(const std::string& file) std::string createDataFilePath(const std::string& file)
{ {
auto path = std::string(SITE_FILES_PATH); auto path = std::string(CROWSITE_FILES_PATH);
if (!path.ends_with('/')) if (!path.ends_with('/'))
path += '/'; path += '/';
path += "data/"; path += "data/";

View File

@ -3,191 +3,19 @@
#include <crowsite/utility.h> #include <crowsite/utility.h>
#include <crowsite/site/cache.h> #include <crowsite/site/cache.h>
#include <crowsite/beemovie.h> #include <crowsite/beemovie.h>
#include <crowsite/crow_utility.h>
#include <crowsite/requests/jellyfin.h> #include <crowsite/requests/jellyfin.h>
#include <crowsite/requests/curl.h> #include <crowsite/requests/curl.h>
#include <blt/parse/argparse.h> #include <blt/parse/argparse.h>
#include <crowsite/site/auth.h> #include <crowsite/site/auth.h>
#include <crow/middlewares/session.h> #include <crowsite/site/home.h>
#include <crow/middlewares/cookie_parser.h>
#include <crowsite/site/posts.h> #include <crowsite/site/posts.h>
#include <crowsite/util/memory_reader.h> #include <crowsite/util/crow_log.h>
#include <crowsite/util/crow_conversion.h>
using Session = crow::SessionMiddleware<crow::FileStore>; #define CS_SESSION cs::checkAndUpdateUserSession(app, req); \
using CrowApp = crow::App<crow::CookieParser, Session>; auto& session = app.get_context<Session>(req); \
auto s_clientID = session.get("clientID", ""); \
class BLT_CrowLogger : public crow::ILogHandler auto s_clientToken = session.get("clientToken", ""); \
{
public:
void log(std::string message, crow::LogLevel crow_level) final
{
blt::logging::log_level blt_level = blt::logging::log_level::NONE;
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());
}
};
struct site_params
{
CrowApp& app;
cs::CacheEngine& engine;
const crow::request& req;
const std::string& name;
};
/**
* 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));
}
void generateRuntimeContext(const site_params& params, cs::RuntimeContext& context)
{
auto& session = params.app.get_context<Session>(params.req);
auto s_clientID = session.get("clientID", "");
auto s_clientToken = session.get("clientToken", "");
if (cs::isUserLoggedIn(s_clientID, s_clientToken))
{
auto username = cs::getUserFromID(s_clientID);
auto perms = cs::getUserPermissions(username);
auto isAdmin = cs::isUserAdmin(username);
context["_logged_in"] = "True";
context["_username"] = username;
if (isAdmin)
context["_admin"] = "True";
if (perms & cs::PERM_READ_FILES)
context["_read_files"] = "True";
if (perms & cs::PERM_WRITE_FILES)
context["_write_files"] = "True";
if (perms & cs::PERM_CREATE_POSTS)
context["_create_posts"] = "True";
if (perms & cs::PERM_CREATE_COMMENTS)
context["_create_comments"] = "True";
if (perms & cs::PERM_CREATE_SHARES)
context["_create_shares"] = "True";
if (perms & cs::PERM_EDIT_POSTS)
context["_edit_posts"] = "True";
if (perms & cs::PERM_EDIT_COMMENTS)
context["_edit_comments"] = "True";
}
}
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"))
{
checkAndUpdateUserSession(params.app, params.req);
auto& session = params.app.get_context<Session>(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::RuntimeContext 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 cs::redirect("/login.html");
return handle_root_page(params);
}
int main(int argc, const char** argv) int main(int argc, const char** argv)
{ {
@ -207,7 +35,7 @@ int main(int argc, const char** argv)
cs::auth::init(); cs::auth::init();
BLT_INFO("Starting site %s.", SITE_NAME); BLT_INFO("Starting site %s.", SITE_NAME);
crow::mustache::set_global_base(SITE_FILES_PATH); crow::mustache::set_global_base(CROWSITE_FILES_PATH);
static BLT_CrowLogger bltCrowLogger{}; static BLT_CrowLogger bltCrowLogger{};
crow::logger::setHandler(&bltCrowLogger); crow::logger::setHandler(&bltCrowLogger);
@ -221,26 +49,28 @@ int main(int argc, const char** argv)
// set session id length (small value only for demonstration purposes) // set session id length (small value only for demonstration purposes)
16, 16,
// init the store // init the store
crow::FileStore{std::string(SITE_FILES_PATH) + "/data/session", session_age}}}; crow::FileStore{std::string(CROWSITE_FILES_PATH) + "/data/session", session_age}}};
app.use_compression(crow::compression::GZIP); app.use_compression(crow::compression::GZIP);
app.loglevel(crow::LogLevel::WARNING); app.loglevel(crow::LogLevel::WARNING);
BLT_INFO("Creating static context"); BLT_INFO("Creating static context");
cs::StaticContext context; cs::context static_context;
context["SITE_TITLE"] = SITE_TITLE; static_context["SITE_TITLE"] = SITE_TITLE;
context["SITE_NAME"] = SITE_NAME; static_context["SITE_NAME"] = SITE_NAME;
context["SITE_VERSION"] = SITE_VERSION; static_context["SITE_VERSION"] = SITE_VERSION;
context["BEE_MOVIE"] = beemovie_script; static_context["BEE_MOVIE"] = beemovie_script;
context["SITE_BACKGROUND"] = "/static/images/backgrounds/2023-05-26_23.18.23.png"; static_context["SITE_BACKGROUND"] = "/static/images/backgrounds/2023-05-26_23.18.23.png";
context["MENU_BAR_COLOR"] = "#335"; static_context["MENU_BAR_COLOR"] = "#335";
context["MENU_BAR_HOVER"] = "#223"; static_context["MENU_BAR_HOVER"] = "#223";
context["MENU_BAR_ACTIVE"] = "#7821be"; static_context["MENU_BAR_ACTIVE"] = "#7821be";
BLT_INFO("Starting cache engine"); BLT_INFO("Starting cache engine");
cs::CacheSettings settings; cs::CacheSettings settings;
cs::CacheEngine engine(context, settings); cs::CacheEngine engine(static_context, settings);
cs::posts_init();
BLT_INFO("Creating routes"); BLT_INFO("Creating routes");
@ -255,22 +85,22 @@ int main(int argc, const char** argv)
CROW_ROUTE(app, "/login.html")( CROW_ROUTE(app, "/login.html")(
[&app, &engine](const crow::request& req) -> crow::response { [&app, &engine](const crow::request& req) -> crow::response {
if (isUserLoggedIn(app, req)) if (cs::isUserLoggedIn(app, req))
return cs::redirect("/"); return cs::redirect("/");
return handle_root_page({app, engine, req, "login.html"}); return cs::handle_root_page({app, engine, req, "login.html"});
} }
); );
CROW_ROUTE(app, "/logout.html")( CROW_ROUTE(app, "/logout.html")(
[&app](const crow::request& req) -> crow::response { [&app](const crow::request& req) -> crow::response {
destroyUserSession(app, req); cs::destroyUserSession(app, req);
return cs::redirect("/"); return cs::redirect("/");
} }
); );
CROW_ROUTE(app, "/<string>")( CROW_ROUTE(app, "/<string>")(
[&app, &engine](const crow::request& req, const std::string& name) -> crow::response { [&app, &engine](const crow::request& req, const std::string& name) -> crow::response {
return handle_root_page({app, engine, req, name}); return cs::handle_root_page({app, engine, req, name});
} }
); );
@ -314,29 +144,27 @@ int main(int argc, const char** argv)
CROW_ROUTE(app, "/projects/<path>")( CROW_ROUTE(app, "/projects/<path>")(
[&engine, &app](const crow::request& req, const std::string& path) { [&engine, &app](const crow::request& req, const std::string& path) {
checkAndUpdateUserSession(app, req); CS_SESSION;
auto& session = app.get_context<Session>(req);
auto s_clientID = session.get("clientID", "");
auto s_clientToken = session.get("clientToken", "");
return cs::handleProjectPage({engine, req, s_clientID, s_clientToken, path}); return toResponse(
cs::handleProjectPage({req.raw_url, s_clientID, s_clientToken, path, cs::toQueryString(req.url_params.getValues()), engine}));
} }
); );
CROW_ROUTE(app, "/projects/")( CROW_ROUTE(app, "/projects/")(
[&engine, &app](const crow::request& req) { [&engine, &app](const crow::request& req) {
checkAndUpdateUserSession(app, req); CS_SESSION;
auto& session = app.get_context<Session>(req);
auto s_clientID = session.get("clientID", "");
auto s_clientToken = session.get("clientToken", "");
return cs::handleProjectPage({engine, req, s_clientID, s_clientToken, "index.html"}); return toResponse(
cs::handleProjectPage(
{req.raw_url, s_clientID, s_clientToken, "index.html", cs::toQueryString(req.url_params.getValues()), engine}
));
} }
); );
CROW_ROUTE(app, "/")( CROW_ROUTE(app, "/")(
[&engine, &app](const crow::request& req) { [&engine, &app](const crow::request& req) {
return handle_root_page({app, engine, req, "index.html"}); return cs::handle_root_page({app, engine, req, "index.html"});
} }
); );
@ -363,6 +191,8 @@ int main(int argc, const char** argv)
BLT_INFO("Starting Crow website on port %d", port); BLT_INFO("Starting Crow website on port %d", port);
app.port(port).multithreaded().run(); app.port(port).multithreaded().run();
cs::posts_cleanup();
cs::requests::cleanup(); cs::requests::cleanup();
cs::auth::cleanup(); cs::auth::cleanup();