precompiled headers
parent
0c8ab4f082
commit
7c4c4ee28f
|
@ -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>
|
|
@ -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>
|
|
@ -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>"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
2
libs/BLT
2
libs/BLT
|
@ -1 +1 @@
|
||||||
Subproject commit d3ed46686eb0667c9824fbba5f90519efd2a50c3
|
Subproject commit 215220f98b0ac4a87fe4a233de16650cf6d0b968
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
106
src/main.cpp
106
src/main.cpp
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue