precompiled headers

main
Brett 2023-09-07 00:36:09 -04:00
parent 0c8ab4f082
commit 7c4c4ee28f
16 changed files with 415 additions and 190 deletions

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/static/css/index.css">
<style>
{{@../static/css/menu_bar.css}}
{{@../static/css/body.css}}
</style>
<meta charset="UTF-8">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="author" content="Brett">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{$SITE_TITLE}}</title>
</head>
{{@body_begin.part}}
<div class="body">
<div class="center">
{{CURRENT_POST}}
</div>
</div>
{{@body_end.part}}
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/static/css/index.css">
<style>
{{@../static/css/menu_bar.css}}
{{@../static/css/body.css}}
</style>
<meta charset="UTF-8">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="author" content="Brett">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{$SITE_TITLE}}</title>
</head>
{{@body_begin.part}}
<div class="body">
<div class="center">
{{CURRENT_POST}}
</div>
</div>
{{@body_end.part}}
</html>

View File

@ -9,7 +9,8 @@
#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 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 SITE_FILES_PATH "/home/brett/projects/cpp/crowsite/crow_test"
#define CROWSITE_FILES_PATH "/home/brett/Documents/code/c++/crowsite/crow_test" #define CROWSITE_FILES_PATH "/home/brett/Documents/code/c++/crowsite/crow_test"
#define CROWSITE_STATIC_ENDPOINT "/static/<path>" #define CROWSITE_STATIC_ENDPOINT "/static/<path>"

View File

@ -8,6 +8,7 @@
#ifndef CROWSITE_CROW_PCH_H #ifndef CROWSITE_CROW_PCH_H
#define CROWSITE_CROW_PCH_H #define CROWSITE_CROW_PCH_H
#include <crowsite/config.h>
#include "crow/query_string.h" #include "crow/query_string.h"
#include "crow/http_parser_merged.h" #include "crow/http_parser_merged.h"
#include "crow/ci_map.h" #include "crow/ci_map.h"

View File

@ -8,69 +8,16 @@
#ifndef CROWSITE_HOME_H #ifndef CROWSITE_HOME_H
#define CROWSITE_HOME_H #define CROWSITE_HOME_H
#include <crowsite/site/cache.h>
#include <crowsite/util/crow_session_util.h> #include <crowsite/util/crow_session_util.h>
#include <crowsite/util/crow_conversion.h>
namespace cs namespace cs
{ {
inline crow::response handle_root_page(const site_params& params) crow::response handle_login_request(const crow::request& req, CrowApp& app);
{
//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; crow::response handle_root_page(const site_params& params);
cs::context context;
generateRuntimeContext(params, context); crow::response handle_auth_page(const site_params& params);
// 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);
}
} }

View File

@ -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 <crowsite/crow_pch.h>
#include "crowsite/site/cache.h"
namespace cs
{
void establishHomeRoutes(CrowApp& app, CacheEngine& engine);
void establishProjectRoutes(CrowApp& app, CacheEngine& engine);
}
#endif //CROWSITE_ROUTING_H

View File

@ -7,28 +7,109 @@
#include <sqlite3.h> #include <sqlite3.h>
#include <type_traits> #include <type_traits>
#include <filesystem>
#include "blt/std/assert.h"
namespace cs::sql 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) static int prepareStatement(sqlite3* db, const std::string& sqlStatement, sqlite3_stmt** ppStmt)
{ {
return sqlite3_prepare_v2(db, sqlStatement.c_str(), static_cast<int>(sqlStatement.size()) + 1, ppStmt, nullptr); return sqlite3_prepare_v2(db, sqlStatement.c_str(), static_cast<int>(sqlStatement.size()) + 1, ppStmt, nullptr);
} }
class statement class database
{ {
friend class statement_base_helper;
private: private:
sqlite3_stmt* stmt = nullptr; std::string path;
sqlite3* db; sqlite3* db;
int err;
public: public:
statement(sqlite3* db, const std::string& statement): db(db) database(const std::string& dbLocation): path(dbLocation)
{ {
err = prepareStatement(db, statement, &stmt); std::filesystem::create_directories(dbLocation.substr(0, dbLocation.find_last_of('/') + 1));
if (err) if (int err = sqlite3_open_v2(
BLT_ERROR("Failed to execute statement, error code %d, error: %s.", err, sqlite3_errstr(err)); 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! * @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 #endif //CROWSITE_SQL_HELPER_H

View File

@ -14,6 +14,8 @@
namespace cs namespace cs
{ {
constexpr auto session_age = 24 * 60 * 60;
constexpr auto cookie_age = 180 * 24 * 60 * 60;
struct site_params struct site_params
{ {
@ -37,4 +39,9 @@ namespace cs
void generateRuntimeContext(const site_params& params, cs::context& context); void generateRuntimeContext(const site_params& params, cs::context& context);
} }
#define CS_SESSION cs::checkAndUpdateUserSession(app, req); \
auto& session = app.get_context<Session>(req); \
auto s_clientID = session.get("clientID", ""); \
auto s_clientToken = session.get("clientToken", ""); \
#endif //CROWSITE_CROW_SESSION_UTIL_H #endif //CROWSITE_CROW_SESSION_UTIL_H

@ -1 +1 @@
Subproject commit d3ed46686eb0667c9824fbba5f90519efd2a50c3 Subproject commit 215220f98b0ac4a87fe4a233de16650cf6d0b968

View File

@ -17,7 +17,7 @@ using namespace blt;
namespace cs namespace cs
{ {
sqlite3* user_database; cs::sql::database* user_database;
// https://stackoverflow.com/questions/5288076/base64-encoding-and-decoding-with-openssl // https://stackoverflow.com/questions/5288076/base64-encoding-and-decoding-with-openssl
@ -191,28 +191,15 @@ namespace cs
void auth::init() void auth::init()
{ {
// TODO: proper multithreading // TODO: proper multithreading
auto path = cs::fs::createDataFilePath("db/"); const auto path = cs::fs::createDataFilePath("db/users.sqlite");
auto dbname = "users.sqlite"; BLT_TRACE("Using %s for users database", path.c_str());
auto full_path = path + dbname; user_database = new sql::database(path);
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);
}
sql::statement v { sql::statement v {
user_database, user_database,
"SELECT SQLITE_VERSION()" "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()) if (!v.execute())
BLT_WARN("Failed to execute statement with error code: %d msg: %s", v.error(), sqlite3_errstr(v.error())); 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() void auth::cleanup()
{ {
sqlite3_close_v2(user_database); delete(user_database);
} }
} }

View File

@ -136,6 +136,7 @@ namespace cs
case TokenType::CLOSE: case TokenType::CLOSE:
return "CLOSE"; return "CLOSE";
} }
throw LexerSyntaxError("Unable to determine type of token");
} }
struct Token struct Token
@ -254,6 +255,7 @@ namespace cs
default: default:
blt_throw(LexerSyntaxError("Weird token found while parsing tokens, type: " + decodeName(next.type))); blt_throw(LexerSyntaxError("Weird token found while parsing tokens, type: " + decodeName(next.type)));
} }
return false;
} }
bool expr(const context& context) bool expr(const context& context)
@ -298,11 +300,6 @@ namespace cs
return str[index] == '{' && str[index + 1] == '{' && str[index + 2] == c; return str[index] == '{' && str[index + 1] == '{' && str[index + 2] == c;
} }
static std::string consumeToEndTemplate(const std::string& tokenName)
{
}
static void getTagLocations(std::vector<size_t>& tagLocations, const std::string& tag, const std::string& data) static void getTagLocations(std::vector<size_t>& tagLocations, const std::string& tag, const std::string& data)
{ {
RuntimeLexer lexer(data); RuntimeLexer lexer(data);

View File

@ -4,8 +4,103 @@
* See LICENSE file for license detail * See LICENSE file for license detail
*/ */
#include <crowsite/site/home.h> #include <crowsite/site/home.h>
#include <crowsite/util/crow_conversion.h>
#include <blt/std/logging.h>
namespace cs namespace cs
{ {
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");
}
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<Session>(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<crow::CookieParser>(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");
}
} }

View File

@ -8,29 +8,57 @@
#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>
#include <crowsite/sql_helper.h>
#include <blt/std/time.h>
namespace cs namespace cs
{ {
sql::database* posts_database;
response_info handleProjectPage(const request_info& req) response_info handleProjectPage(const request_info& req)
{ {
std::string buffer; if (req.url_params.contains("post"))
buffer += "<html><head></head><body>"; {
auto htmlData = loadMarkdownAsHTML(cs::fs::createDataFilePath("Billionaire Propaganda.md")); BLT_TRACE(req.url_params.at("post"));
buffer += htmlData; sql::statement posts(posts_database, "SELECT file FROM posts WHERE postID=?;");
buffer += "</body>"; posts.set(req.url_params.at("post"), 0);
posts.execute();
return {loadMarkdownAsHTML(cs::fs::createDataFilePath(posts.get<std::string>(2)))};
}
return {buffer}; return {""};
} }
void posts_init() 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() void posts_cleanup()
{ {
delete posts_database;
} }

View File

@ -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 <crowsite/site/routing.h>
#include <blt/std/logging.h>
#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, "/<string>")(
[&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)
{
}
}

View File

@ -55,13 +55,13 @@ namespace cs
{ {
std::string createStaticFilePath(const std::string& file) 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('/')) if (!path.ends_with('/'))
path += '/'; path += '/';
path += file; path += file;
// prevent crow from hanging web responses when we make a typo in the filename // prevent crow from hanging web responses when we make a typo in the filename
if (!std::filesystem::exists(path)) if (!std::filesystem::exists(path.substr(0, path.find_last_of('/'))))
throw std::runtime_error("Unable to create file path because file does not exist!"); throw std::runtime_error("Unable to create file path because path does not exist!");
return path; return path;
} }
@ -72,8 +72,8 @@ namespace cs
path += '/'; path += '/';
path += "webcontent/"; path += "webcontent/";
path += file; path += file;
if (!std::filesystem::exists(path)) if (!std::filesystem::exists(path.substr(0, path.find_last_of('/'))))
throw std::runtime_error("Unable to create file path because file does not exist!"); throw std::runtime_error("Unable to create file path because folder does not exist!");
return path; return path;
} }
@ -84,8 +84,8 @@ namespace cs
path += '/'; path += '/';
path += "data/"; path += "data/";
path += file; path += file;
if (!std::filesystem::exists(path)) if (!std::filesystem::exists(path.substr(0, path.find_last_of('/'))))
throw std::runtime_error("Unable to create file path because file does not exist!"); throw std::runtime_error("Unable to create file path because folder does not exist!");
return path; return path;
} }
} }

View File

@ -11,11 +11,7 @@
#include <crowsite/site/posts.h> #include <crowsite/site/posts.h>
#include <crowsite/util/crow_log.h> #include <crowsite/util/crow_log.h>
#include <crowsite/util/crow_conversion.h> #include <crowsite/util/crow_conversion.h>
#include <crowsite/site/routing.h>
#define CS_SESSION cs::checkAndUpdateUserSession(app, req); \
auto& session = app.get_context<Session>(req); \
auto s_clientID = session.get("clientID", ""); \
auto s_clientToken = session.get("clientToken", ""); \
int main(int argc, const char** argv) int main(int argc, const char** argv)
{ {
@ -27,6 +23,7 @@ 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("--standalone").setAction(blt::arg_action_t::STORE_TRUE).build());
parser.addArgument(blt::arg_builder({"--port", "-p"}).setDefault(8080).build()); parser.addArgument(blt::arg_builder({"--port", "-p"}).setDefault(8080).build());
parser.addArgument(blt::arg_builder("token").setRequired().build()); parser.addArgument(blt::arg_builder("token").setRequired().build());
auto args = parser.parse_args(argc, argv); auto args = parser.parse_args(argc, argv);
@ -39,17 +36,14 @@ int main(int argc, const char** argv)
static BLT_CrowLogger bltCrowLogger{}; static BLT_CrowLogger bltCrowLogger{};
crow::logger::setHandler(&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!"); BLT_INFO("Init Crow with compression and logging enabled!");
CrowApp app{Session{ CrowApp app{Session{
// customize cookies // 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) // set session id length (small value only for demonstration purposes)
16, 16,
// init the store // 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.use_compression(crow::compression::GZIP);
app.loglevel(crow::LogLevel::WARNING); app.loglevel(crow::LogLevel::WARNING);
@ -74,73 +68,7 @@ int main(int argc, const char** argv)
BLT_INFO("Creating routes"); BLT_INFO("Creating routes");
CROW_ROUTE(app, "/favicon.ico")( cs::establishHomeRoutes(app, engine);
[](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, "/<string>")(
[&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<Session>(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<crow::CookieParser>(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");
}
);
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) {
@ -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)( CROW_CATCHALL_ROUTE(app)(
[&engine]() { [&engine]() {
return engine.fetch("default.html"); return engine.fetch("default.html");
@ -187,8 +109,26 @@ 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<int32_t>(args["port"]); auto port = blt::arg_parse::get_cast<int32_t>(args["port"]);
BLT_INFO("Starting Crow website on port %d", port); BLT_INFO("Starting Crow website on port %d", port);
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(); app.port(port).multithreaded().run();
cs::posts_cleanup(); cs::posts_cleanup();