27 Commits

Autor SHA1 Mensagem Data
cc4506b918 submodules: sync with latest upstream 2021-10-26 10:47:02 +02:00
017932e673 Fix -wreturn-type warnings 2021-10-25 18:13:25 +02:00
ed61003636 C++20: Avoid implicit capture 2021-10-25 18:09:46 +02:00
ad42c0f046 handlers: HandlerPageEdit: canAccess(): Check with effectivePermisisons() 2021-10-25 18:07:23 +02:00
6304554358 Add [[maybe_unused]] to silence unhelpful warnings 2021-10-25 17:56:37 +02:00
0aa4bca6cc Fix gcc-11 etc. compilation errors 2021-10-25 13:31:40 +02:00
b41a5f4e5b fscache: removePrefix(): use starts_with() 2021-10-19 15:07:10 +02:00
873401694e Remove utils::hasKey(), as we now have .contains() 2021-10-19 12:48:45 +02:00
d035579da7 Makefile: Switch to C++20 2021-10-19 12:47:57 +02:00
eb292a7d79 CategoryDaoSqlite: deleteCategory(): Fix broken query 2021-10-12 20:10:35 +02:00
420e541e75 CLI: Implement category delete,show,list 2021-10-12 20:02:43 +02:00
c18178a50f SqliteQueryOption: build(): Handle includeInvisible = true properly 2021-10-12 20:02:03 +02:00
7a2f15cabe handlers: Introduce HandlerVersion to return the verison string 2021-10-10 22:39:35 +02:00
c9dc3416d7 TemplatePage: Change 'content' to shared_ptr 2021-10-10 22:32:13 +02:00
92be470545 Makefile: Remove LDFLAGS from .o compilation 2021-10-10 20:17:38 +02:00
d5485a833f CLIConsole: On 'exit', ask whether to quit attached instance 2021-10-10 20:15:28 +02:00
0bdb22c170 gateway: HttpGateway: convertRequest(): Don't convert param to std::string 2021-10-10 20:15:28 +02:00
eb49b013a7 Makefile: Add profile target 2021-10-10 20:15:28 +02:00
9593429f95 utils: trim(): Take string_view 2021-10-10 20:15:28 +02:00
86ac86b83f Response: addHeader(): Pass by value, not reference 2021-10-10 20:15:28 +02:00
92e7390056 utils: Pass by value where it makes sense 2021-10-10 20:15:28 +02:00
b1a8572eb6 utils: hasKey(), getKeyOrEmpty(), getAll(): Take params as references
Somehow, the fact that multimap was being copyied slipped through.
2021-10-10 20:15:28 +02:00
44ade88cae Template: createPage(): Take std::string_view 2021-10-10 20:15:28 +02:00
aadb623bf7 UserDaoSqlite: Remove redundant std::move 2021-10-08 23:38:22 +02:00
828d827c3d Adjust to new Template::getPage() returning value, not reference 2021-10-08 00:11:58 +02:00
8ffa64beea Template: Use MapCache, getPage(): Return value, not reference 2021-10-08 00:11:30 +02:00
e970ba1682 cache: MapCache: Introduce MapCache, thread-safe cache (key/value store) 2021-10-08 00:08:00 +02:00
45 arquivos alterados com 259 adições e 128 exclusões

Ver arquivo

@ -1,7 +1,7 @@
CXXFLAGS=-std=c++17 -O0 -g -no-pie -pipe -MMD -Wall -Wextra
RELEASE_CXXFLAGS=-std=c++17 -O3 -pipe -MMD -Wall -Wextra
CPPSTD=c++20
CXXFLAGS=-std=$(CPPSTD) -O0 -g -no-pie -pipe -MMD -Wall -Wextra
RELEASE_CXXFLAGS=-std=$(CPPSTD) -O3 -pipe -MMD -Wall -Wextra
LDFLAGS=-lsqlite3 -lpthread -lcrypto -lstdc++fs
INCLUDEFLAGS=-I submodules/sqlitemoderncpp/hdr -I submodules/cpp-httplib -I submodules/qssb.h
@ -35,14 +35,19 @@ GTEST_DIR = /home/data/SOURCES/gtest/googletest
GTESTS_TESTDIR = ./tests/
GTEST_CXXFLAGS=-std=c++17 -isystem $(GTEST_DIR)/include -I$(GTEST_DIR) -g -O0 -pipe -Wall -Wextra
GTEST_CXXFLAGS=-std=$(CPPSTD) -isystem $(GTEST_DIR)/include -I$(GTEST_DIR) -g -O0 -pipe -Wall -Wextra
GTEST_LDFLAGS=-lsqlite3 -g -O0 -lpthread -lcrypto -lstdc++fs
GTEST_OBJECTS=$(filter-out qswiki.o, $(WIKIOBJECTS))
.DEFAULT_GOAL := qswiki
release: CXXFLAGS=$(RELEASE_CXXFLAGS)
profile: CXXFLAGS=$(RELEASE_CXXFLAGS) -pg
profile: LDFLAGS+= -pg
release: qswiki
profile: qswiki
qswiki: $(WIKIOBJECTS)
$(CXX) $(WIKIOBJECTS) ${LDFLAGS} ${INCLUDEFLAGS} -o qswiki
@ -53,10 +58,10 @@ gtest: $(GTESTS_TESTDIR)/*.cpp $(GTEST_OBJECTS)
$(CXX) -o gtest $(GTESTS_TESTDIR)/*.cpp $(GTEST_OBJECTS) $(GTEST_CXXFLAGS) $(GTEST_DIR)/src/gtest_main.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_LDFLAGS)
%.o:%.cpp
$(CXX) ${CXXFLAGS} ${LDFLAGS} ${INCLUDEFLAGS} -c -o $@ $<
$(CXX) ${CXXFLAGS} ${INCLUDEFLAGS} -c -o $@ $<
version.o:version.cpp
$(CXX) ${CXXFLAGS} ${LDFLAGS} ${INCLUDEFLAGS} -DGITCOMMIT=\"$(shell git rev-parse --short HEAD)\" -c -o $@ $<
$(CXX) ${CXXFLAGS} ${INCLUDEFLAGS} -DGITCOMMIT=\"$(shell git rev-parse --short HEAD)\" -c -o $@ $<
clean:
rm -f $(OBJECTS) $(DEPENDS)

Ver arquivo

@ -21,7 +21,7 @@ Authenticator::Authenticator(UserDao &userDao)
// TODO: make failure counter configurable
bool Authenticator::isBanned(std::string ip)
{
if(utils::hasKey(loginFails, ip))
if(loginFails.contains(ip))
{
LoginFail &fl = loginFails[ip];
std::lock_guard<std::mutex> lock(fl.mutex);

2
cache/fscache.cpp externo
Ver arquivo

@ -46,7 +46,7 @@ void FsCache::removePrefix(std::string_view prefix)
// TODO: lock dir
for(auto &entry : std::filesystem::directory_iterator(std::filesystem::path{this->path}))
{
if(static_cast<std::string>(entry.path().filename()).find(prefix) == 0)
if(std::string_view(entry.path().filename().c_str()).starts_with(prefix) == 0)
{
std::filesystem::remove_all(entry);
}

1
cache/mapcache.cpp externo Arquivo normal
Ver arquivo

@ -0,0 +1 @@
#include "mapcache.h"

38
cache/mapcache.h externo Arquivo normal
Ver arquivo

@ -0,0 +1,38 @@
#ifndef MAPCACHE_H
#define MAPCACHE_H
#include <map>
#include <set>
#include <shared_mutex>
#include <optional>
/* Thread-Safe Key-Value store */
template <class T> class MapCache
{
private:
std::map<std::string, T> cache;
mutable std::shared_mutex sharedMutex;
public:
std::optional<T> find(const std::string &key) const
{
std::shared_lock<std::shared_mutex> lock(this->sharedMutex);
auto it = this->cache.find(key);
if(it != this->cache.end())
{
return it->second;
}
return {};
}
void set(const std::string &key, const T &val)
{
std::lock_guard<std::shared_mutex> lock{sharedMutex};
this->cache[key] = val;
}
void clear()
{
std::lock_guard<std::shared_mutex> lock{sharedMutex};
this->cache.clear();
}
};
#endif // MAPCACHE_H

50
cli.cpp
Ver arquivo

@ -54,7 +54,7 @@ std::pair<bool, std::string> CLIHandler::user_add(const std::vector<std::string>
return {true, ""};
}
std::pair<bool, std::string> CLIHandler::user_change_pw(const std::vector<std::string> &args)
std::pair<bool, std::string> CLIHandler::user_change_pw([[maybe_unused]] const std::vector<std::string> &args)
{
std::string username = args.at(0);
std::string password = args.at(1);
@ -75,19 +75,16 @@ std::pair<bool, std::string> CLIHandler::user_change_pw(const std::vector<std::s
userDao->save(*user);
}
else
{
return {false, "User not found"};
}
return {false, "User not found"};
}
std::pair<bool, std::string> CLIHandler::user_rename(const std::vector<std::string> &args)
std::pair<bool, std::string> CLIHandler::user_rename([[maybe_unused]] const std::vector<std::string> &args)
{
return {true, ""};
}
std::pair<bool, std::string> CLIHandler::user_set_perms(const std::vector<std::string> &args)
std::pair<bool, std::string> CLIHandler::user_set_perms([[maybe_unused]] const std::vector<std::string> &args)
{
auto userDao = this->db->createUserDao();
std::string username = args.at(0);
@ -107,7 +104,7 @@ std::pair<bool, std::string> CLIHandler::user_set_perms(const std::vector<std::s
return {false, "User not found"};
}
std::pair<bool, std::string> CLIHandler::user_list(const std::vector<std::string> &args)
std::pair<bool, std::string> CLIHandler::user_list([[maybe_unused]] const std::vector<std::string> &args)
{
auto userDao = this->db->createUserDao();
QueryOption o;
@ -138,7 +135,7 @@ std::pair<bool, std::string> CLIHandler::user_show(const std::vector<std::string
return {false, "User not found"};
}
std::pair<bool, std::string> CLIHandler::page_list(const std::vector<std::string> &args)
std::pair<bool, std::string> CLIHandler::page_list([[maybe_unused]] const std::vector<std::string> &args)
{
auto pageDao = this->db->createPageDao();
QueryOption o;
@ -163,7 +160,7 @@ std::pair<bool, std::string> CLIHandler::pageperms_set_permissions(const std::ve
return {true, ""};
}
std::pair<bool, std::string> CLIHandler::attach(const std::vector<std::string> &args)
std::pair<bool, std::string> CLIHandler::attach([[maybe_unused]] const std::vector<std::string> &args)
{
/* TODO: consider authentication */
pid_t pid = getpid();
@ -245,7 +242,38 @@ std::pair<std::string, std::vector<std::string>> CLIHandler::splitCommand(std::s
return {cmd, splitted};
}
std::pair<bool, std::string> CLIHandler::version(const std::vector<std::string> &args)
std::pair<bool, std::string> CLIHandler::version([[maybe_unused]] const std::vector<std::string> &args)
{
return {true, get_version_string()};
}
std::pair<bool, std::string> CLIHandler::category_list([[maybe_unused]] const std::vector<std::string> &args)
{
auto categoryDao = this->db->createCategoryDao();
auto categories = categoryDao->fetchList(QueryOption{});
std::stringstream stream;
for(std::string &cat : categories)
{
stream << cat << std::endl;
}
return {true, stream.str()};
}
std::pair<bool, std::string> CLIHandler::category_delete(const std::vector<std::string> &args)
{
auto categoryDao = this->db->createCategoryDao();
categoryDao->deleteCategory(args.at(0));
return {true, ""};
}
std::pair<bool, std::string> CLIHandler::category_show(const std::vector<std::string> &args)
{
auto categoryDao = this->db->createCategoryDao();
auto members = categoryDao->fetchMembers(args.at(0), QueryOption{});
std::stringstream stream;
for(std::string &member : members)
{
stream << member << std::endl;
}
return {true, stream.str()};
}

34
cli.h
Ver arquivo

@ -22,17 +22,20 @@ class CLIHandler
Config *conf;
protected:
std::pair<bool, std::string> attach(const std::vector<std::string> &args);
std::pair<bool, std::string> cli_help(const std::vector<std::string> &args);
std::pair<bool, std::string> user_add(const std::vector<std::string> &args);
std::pair<bool, std::string> user_change_pw(const std::vector<std::string> &args);
std::pair<bool, std::string> user_rename(const std::vector<std::string> &args);
std::pair<bool, std::string> user_set_perms(const std::vector<std::string> &args);
std::pair<bool, std::string> user_list(const std::vector<std::string> &args);
std::pair<bool, std::string> user_show(const std::vector<std::string> &args);
std::pair<bool, std::string> page_list(const std::vector<std::string> &args);
std::pair<bool, std::string> pageperms_set_permissions(const std::vector<std::string> &args);
std::pair<bool, std::string> version(const std::vector<std::string> &args);
std::pair<bool, std::string> attach([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> cli_help([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> user_add([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> user_change_pw([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> user_rename([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> user_set_perms([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> user_list([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> user_show([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> page_list([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> pageperms_set_permissions([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> version([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> category_list([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> category_delete([[maybe_unused]] const std::vector<std::string> &args);
std::pair<bool, std::string> category_show([[maybe_unused]] const std::vector<std::string> &args);
std::vector<struct cmd> cmds{
{{"user",
@ -50,6 +53,13 @@ class CLIHandler
1,
{{{"list", "- lists existing pages", 0, {}, &CLIHandler::page_list}}},
&CLIHandler::cli_help},
{"category",
"operation on categories",
1,
{{{"list", "- lists existing categories", 0, {}, &CLIHandler::category_list},
{"delete", " - deletes a category", 1, {}, &CLIHandler::category_delete},
{"show", " - shows pages of a category", 1, {}, &CLIHandler::category_show}}},
&CLIHandler::cli_help},
{"pageperms",
"set permissions on pages",
1,
@ -63,7 +73,7 @@ class CLIHandler
"exit cli",
0,
{},
[](CLIHandler *, const std::vector<std::string> &args) -> std::pair<bool, std::string>
[](CLIHandler *, [[maybe_unused]] const std::vector<std::string> &args) -> std::pair<bool, std::string>
{
exit(EXIT_SUCCESS);
return {true, ""};

Ver arquivo

@ -104,7 +104,17 @@ void CLIConsole::startInteractive()
auto pair = CLIHandler::splitCommand(input);
if(pair.first == "exit")
{
std::cout << "Exiting CLI";
if(attached)
{
std::cout << "You are attached. Quit attached instance too (y) or only this one(n)" << std::endl;
char response;
std::cin >> response;
if(response == 'y')
{
this->send("exit");
}
}
std::cout << "Exiting CLI" << std::endl;
exit(EXIT_SUCCESS);
}
if(pair.first == "attach")

Ver arquivo

@ -36,7 +36,7 @@ bool CLIServer::detachServer(std::string socketpath)
exit(EXIT_FAILURE);
}
auto worker = [=]
auto worker = [this, s]
{
while(true)
{

Ver arquivo

@ -42,6 +42,7 @@ std::optional<Category> CategoryDaoSqlite::find(std::string name)
{
throwFrom(e);
}
return {};
}
void CategoryDaoSqlite::save(const Category &c)
@ -64,9 +65,9 @@ void CategoryDaoSqlite::deleteCategory(std::string name)
try
{
*db << "BEGIN";
*db << "DELETE FROM categorymember WHERE catid = (SELECT id FROM category WHERE name = ?)" << name;
*db << "DELETE FROM category WHERE name = ?" << name;
*db << "BEGIN;";
*db << "DELETE FROM categorymember WHERE category = (SELECT id FROM category WHERE name = ?);" << name;
*db << "DELETE FROM category WHERE name = ?;" << name;
*db << "COMMIT;";
}
catch(sqlite::sqlite_exception &e)

Ver arquivo

@ -1,5 +1,6 @@
#ifndef PERMISSIONSDAO_H
#define PERMISSIONSDAO_H
#include <optional>
#include "../permissions.h"
#include "../user.h"
class PermissionsDao

Ver arquivo

@ -22,18 +22,17 @@ SOFTWARE.
bool SqliteDao::execBool(sqlite::database_binder &binder) const
{
bool result;
bool result = false;
try
{
bool result;
binder >> result;
return result;
}
catch(sqlite::sqlite_exception &e)
{
// TODO: well, we may want to check whether rows have found or not and thus log this here
return false;
result = false;
}
return result;
}
int SqliteDao::execInt(sqlite::database_binder &binder) const
@ -52,4 +51,5 @@ int SqliteDao::execInt(sqlite::database_binder &binder) const
{
throwFrom(e);
}
return 0;
}

Ver arquivo

@ -46,15 +46,18 @@ SqliteQueryOption &SqliteQueryOption::setPrependWhere(bool b)
std::string SqliteQueryOption::build()
{
std::string result;
if(this->prependWhere)
{
result += "WHERE ";
}
if(!o.includeInvisible && !this->visibleColumnName.empty())
{
if(this->prependWhere)
{
result += "WHERE ";
}
result += this->visibleColumnName + " = 1";
}
else
{
result += " 1 = 1";
}
result += " ORDER BY " + orderByColumnName;
if(o.order == ASCENDING)
{
@ -66,7 +69,8 @@ std::string SqliteQueryOption::build()
}
// TODO: limits for offset?
if(o.limit > 0)
{
result += " LIMIT " + std::to_string(o.limit) + " OFFSET " + std::to_string(o.offset);
}
return result;
}

Ver arquivo

@ -37,7 +37,6 @@ bool UserDaoSqlite::exists(std::string username)
std::optional<User> UserDaoSqlite::find(std::string username)
{
try
{
User user;
@ -48,7 +47,7 @@ std::optional<User> UserDaoSqlite::find(std::string username)
stmt >> std::tie(user.login, user.password, user.salt, perms, user.enabled);
user.permissions = Permissions{perms};
return std::move(user);
return user;
}
catch(const sqlite::errors::no_rows &e)
{
@ -58,6 +57,7 @@ std::optional<User> UserDaoSqlite::find(std::string username)
{
throwFrom(e);
}
return {};
}
std::optional<User> UserDaoSqlite::find(int id)
@ -71,7 +71,7 @@ std::optional<User> UserDaoSqlite::find(int id)
stmt >> std::tie(user.login, user.password, user.salt, perms, user.enabled);
user.permissions = Permissions{perms};
return std::move(user);
return user;
}
catch(const sqlite::errors::no_rows &e)
{
@ -81,6 +81,7 @@ std::optional<User> UserDaoSqlite::find(int id)
{
throwFrom(e);
}
return {};
}
std::vector<User> UserDaoSqlite::list(QueryOption o)
@ -116,7 +117,7 @@ std::vector<User> UserDaoSqlite::list(QueryOption o)
return result;
}
void UserDaoSqlite::deleteUser(std::string username)
void UserDaoSqlite::deleteUser([[maybe_unused]] std::string username)
{
// What to do with the contributions of the user?
}

Ver arquivo

@ -41,7 +41,7 @@ Request HttpGateway::convertRequest(httplib::Request request)
// TODO: this eats resources, where perhaps it does not need to. move it to request?
for(auto &it : request.params)
{
it.second = utils::html_xss(std::string{it.second});
it.second = utils::html_xss(it.second);
}
if(request.method == "GET")
{
@ -83,7 +83,8 @@ void HttpGateway::work(RequestWorker &worker)
{
httplib::Server server;
server.set_payload_max_length(this->maxPayloadLength);
auto handler = [&](const httplib::Request &req, httplib::Response &res) {
auto handler = [&](const httplib::Request &req, httplib::Response &res)
{
Request wikiRequest = convertRequest(req);
Logger::debug() << "httpgateway: received request " << wikiRequest;
Response wikiresponse = worker.processRequest(wikiRequest);

Ver arquivo

@ -34,7 +34,7 @@ void Handler::setGeneralVars(TemplatePage &page)
}
Response Handler::errorResponse(std::string errortitle, std::string errormessage, int status)
{
TemplatePage &error = this->templ->getPage("error");
TemplatePage error = this->templ->getPage("error");
error.setVar("title", createPageTitle(errortitle));
error.setVar("errortitle", errortitle);
error.setVar("errormessage", errormessage);

Ver arquivo

@ -36,12 +36,12 @@ class Handler
}
virtual Response handle(const Request &r);
virtual Response handleRequest(const Request &r)
virtual Response handleRequest([[maybe_unused]] const Request &r)
{
return this->errorResponse("Invalid action", "This action is not implemented yet");
}
virtual bool canAccess(const Permissions &perms)
virtual bool canAccess([[maybe_unused]] const Permissions &perms)
{
return false;
}

Ver arquivo

@ -32,7 +32,7 @@ Response HandlerAllCategories::handleRequest(const Request &r)
"No categories",
"This wiki does not have any categories defined yet or your query options did not yield any results");
}
TemplatePage &searchPage = this->templ->getPage("allcategories");
TemplatePage searchPage = this->templ->getPage("allcategories");
std::string body =
this->templ->renderSearch(resultList, [&](std::string str) { return this->urlProvider->category(str); });
searchPage.setVar("categorylist", body);

Ver arquivo

@ -32,7 +32,7 @@ Response HandlerAllPages::handleRequest(const Request &r)
{
return errorResponse("No pages", "This wiki does not have any pages yet");
}
TemplatePage &searchPage = this->templ->getPage("allpages");
TemplatePage searchPage = this->templ->getPage("allpages");
std::string body = this->templ->renderSearch(resultList);
searchPage.setVar("pagelist", body);
searchPage.setVar("title", createPageTitle("All pages"));

Ver arquivo

@ -33,7 +33,7 @@ Response HandlerCategory::handleRequest(const Request &r)
}
QueryOption qo = queryOption(r);
auto resultList = categoryDao->fetchMembers(categoryname, qo);
TemplatePage &searchPage = this->templ->getPage("show_category");
TemplatePage searchPage = this->templ->getPage("show_category");
std::string body = this->templ->renderSearch(resultList);
searchPage.setVar("pagelist", body);
searchPage.setVar("categoryname", categoryname);

Ver arquivo

@ -20,7 +20,7 @@ SOFTWARE.
*/
#include "handlerdefault.h"
Response HandlerDefault::handleRequest(const Request &r)
Response HandlerDefault::handleRequest([[maybe_unused]] const Request &r)
{
return Response::redirectTemporarily(this->urlProvider->index());
}
@ -29,7 +29,7 @@ HandlerDefault::~HandlerDefault()
{
}
bool HandlerDefault::canAccess(const Permissions &perms)
bool HandlerDefault::canAccess([[maybe_unused]] const Permissions &perms)
{
return true;
}

Ver arquivo

@ -33,7 +33,7 @@ SOFTWARE.
#include "handlerhistory.h"
#include "handlerpagedelete.h"
#include "handlerusersettings.h"
#include "handlerversion.h"
std::unique_ptr<Handler> HandlerFactory::createHandler(const std::string &action, Session &userSession)
{
if(action == "" || action == "index")
@ -80,6 +80,10 @@ std::unique_ptr<Handler> HandlerFactory::createHandler(const std::string &action
{
return produce<HandlerUserSettings>(userSession);
}
if(action == "version")
{
return produce<HandlerVersion>(userSession);
}
return produce<HandlerInvalidAction>(userSession);
}

Ver arquivo

@ -50,7 +50,8 @@ Response HandlerHistory::handleRequest(const Request &r)
std::vector<Revision> resultList;
auto revisionDao = this->database->createRevisionDao();
auto makeSortedLink = [&](unsigned int limit, unsigned int offset, unsigned int order) {
auto makeSortedLink = [&](unsigned int limit, unsigned int offset, unsigned int order)
{
if(!page.empty())
{
return this->urlProvider->pageHistorySort(page, limit, offset, order);
@ -122,7 +123,7 @@ Response HandlerHistory::handleRequest(const Request &r)
return response;
}
bool HandlerHistory::canAccess(const Permissions &perms)
bool HandlerHistory::canAccess([[maybe_unused]] const Permissions &perms)
{
return true; // This is a lie but we need to this a little more fine grained here, which we do in the handleRequest
}

Ver arquivo

@ -20,12 +20,12 @@ SOFTWARE.
*/
#include "handlerinvalidaction.h"
Response HandlerInvalidAction::handleRequest(const Request &r)
Response HandlerInvalidAction::handleRequest([[maybe_unused]] const Request &r)
{
return errorResponse("Invalid action", "No action defined for this action");
}
bool HandlerInvalidAction::canAccess(const Permissions &perms)
bool HandlerInvalidAction::canAccess([[maybe_unused]] const Permissions &perms)
{
return true;
}

Ver arquivo

@ -55,7 +55,7 @@ Response HandlerLogin::handleRequest(const Request &r)
{
page = "index";
}
TemplatePage &loginTemplatePage = this->templ->getPage("login");
TemplatePage loginTemplatePage = this->templ->getPage("login");
setGeneralVars(loginTemplatePage);
loginTemplatePage.setVar("loginurl", urlProvider->login(page));
loginTemplatePage.setVar("title", createPageTitle("Login"));
@ -66,7 +66,7 @@ Response HandlerLogin::handleRequest(const Request &r)
return result;
}
bool HandlerLogin::canAccess(const Permissions &perms)
bool HandlerLogin::canAccess([[maybe_unused]] const Permissions &perms)
{
return true;
}

Ver arquivo

@ -63,8 +63,9 @@ void HandlerPage::setPageVars(TemplatePage &page, std::string pagename)
if(!pagename.empty())
{
std::string headerlinks;
TemplatePage &headerlink = this->templ->getPage("_headerlink");
auto addHeaderLink = [&headerlinks, &headerlink](std::string href, std::string value) {
TemplatePage headerlink = this->templ->getPage("_headerlink");
auto addHeaderLink = [&headerlinks, &headerlink](std::string href, std::string value)
{
headerlink.setVar("href", href);
headerlink.setVar("value", value);
headerlinks += headerlink.render();

Ver arquivo

@ -23,9 +23,9 @@ SOFTWARE.
#include "../request.h"
#include "../parser.h"
bool HandlerPageEdit::canAccess(std::string page)
bool HandlerPageEdit::canAccess([[maybe_unused]] std::string page)
{
return this->userSession->user.permissions.canEdit();
return effectivePermissions(page).canEdit();
}
bool HandlerPageEdit::pageMustExist()
@ -121,7 +121,7 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename,
}
}
TemplatePage &templatePage = this->templ->getPage("page_creation");
TemplatePage templatePage = this->templ->getPage("page_creation");
templatePage.setVar("actionurl", urlProvider->editPage(pagename));
templatePage.setVar("content", body);
setPageVars(templatePage, pagename);

Ver arquivo

@ -128,7 +128,7 @@ Response HandlerPageView::handleRequest(PageDao &pageDao, std::string pagename,
return errorResponse("Database error", "While trying to fetch revision, a database error occured");
}
TemplatePage &page = this->templ->getPage(templatepartname);
TemplatePage page = this->templ->getPage(templatepartname);
Parser parser;
Response result;

Ver arquivo

@ -37,7 +37,7 @@ Response HandlerSearch::handleRequest(const Request &r)
{
return errorResponse("No results", "Your search for " + q + " did not yield any results.");
}
TemplatePage &searchPage = this->templ->getPage("search");
TemplatePage searchPage = this->templ->getPage("search");
std::string body = this->templ->renderSearch(resultList);
searchPage.setVar("pagelist", body);
searchPage.setVar("searchterm", q);

Ver arquivo

@ -51,7 +51,7 @@ Response HandlerUserSettings::handleRequest(const Request &r)
}
}
TemplatePage &userSettingsPage = this->templ->getPage("usersettings");
TemplatePage userSettingsPage = this->templ->getPage("usersettings");
setGeneralVars(userSettingsPage);
userSettingsPage.setVar("usersettingsurl", urlProvider->userSettings());
userSettingsPage.setVar("title", createPageTitle("User settings - " + this->userSession->user.login));
@ -62,7 +62,7 @@ Response HandlerUserSettings::handleRequest(const Request &r)
return result;
}
bool HandlerUserSettings::canAccess(const Permissions &perms)
bool HandlerUserSettings::canAccess([[maybe_unused]] const Permissions &perms)
{
return this->userSession->loggedIn;
}

9
handlers/handlerversion.cpp Arquivo normal
Ver arquivo

@ -0,0 +1,9 @@
#include "handlerversion.h"
#include "../version.h"
Response HandlerVersion::handleRequest([[maybe_unused]] const Request &r)
{
Response response;
response.setContentType("text/plain");
response.setBody(get_version_string());
return response;
}

18
handlers/handlerversion.h Arquivo normal
Ver arquivo

@ -0,0 +1,18 @@
#ifndef HANDLERVERSION_H
#define HANDLERVERSION_H
#include "handler.h"
class HandlerVersion : public Handler
{
public:
using Handler::Handler;
public:
Response handleRequest(const Request &r) override;
bool canAccess([[maybe_unused]] const Permissions &perms) override
{
return true;
}
};
#endif // HANDLERVERSION_H

Ver arquivo

@ -43,7 +43,7 @@ SOFTWARE.
#include "cliserver.h"
#include "version.h"
void sigterm_handler(int arg)
void sigterm_handler([[maybe_unused]] int arg)
{
// TODO: proper shutdown.
exit(EXIT_SUCCESS);
@ -180,7 +180,9 @@ int main(int argc, char **argv)
userdao->save(anon.value());
User::setAnon(anon.value());
Template siteTemplate{config.templateprefix, config.templatepath, config.urls, config.configVarResolver};
MapCache<TemplatePage> mapCache;
Template siteTemplate{config.templateprefix, config.templatepath, config.urls, config.configVarResolver,
mapCache};
UrlProvider urlProvider{config.urls};
auto cache = createCache(config.configVarResolver);

Ver arquivo

@ -59,7 +59,7 @@ Response RequestWorker::processRequest(const Request &r)
if(session.loggedIn && session.csrf_token != r.post("csrf_token"))
{
// TODO: this is code duplication
TemplatePage &error = this->templ->getPage("error");
TemplatePage error = this->templ->getPage("error");
error.setVar("errortitle", "Invalid csrf token");
error.setVar("errormessage", "Invalid csrf token");
return {403, error.render()};

Ver arquivo

@ -32,12 +32,12 @@ Response::Response(int http_status_code, std::string html)
this->html = std::move(html);
}
void Response::addHeader(const std::string &key, const std::string &value)
void Response::addHeader(std::string key, std::string value)
{
this->responseHeaders.insert(std::make_pair(key, value));
}
Response Response::redirectTemporarily(const std::string &url)
Response Response::redirectTemporarily(std::string url)
{
Response result;
result.addHeader("Location", url);

Ver arquivo

@ -27,8 +27,8 @@ class Response
return this->html;
}
void addHeader(const std::string &key, const std::string &value);
static Response redirectTemporarily(const std::string &url);
void addHeader(std::string key, std::string value);
static Response redirectTemporarily(std::string url);
void setStatus(int status)
{

Ver arquivo

@ -24,12 +24,25 @@ SOFTWARE.
#include "htmllink.h"
#include "logger.h"
Template::Template(std::string templateprefix, std::string templatepath, ConfigUrls &configUrls,
ConfigVariableResolver &configVarsResolver)
ConfigVariableResolver &configVarsResolver, MapCache<TemplatePage> &pageCache)
{
this->templateprefix = templateprefix;
this->templatepath = templatepath;
this->configUrls = &configUrls;
this->configVarResolver = &configVarsResolver;
this->pageCache = &pageCache;
}
TemplatePage Template::getPage(const std::string &pagename)
{
auto result = this->pageCache->find(pagename);
if(result)
{
return *result;
}
auto page = createPage(pagename);
this->pageCache->set(pagename, page);
return page;
}
std::string Template::getPartPath(std::string_view partname)
@ -54,7 +67,7 @@ std::string Template::resolveIncludes(std::string_view content)
return replacer.parse(content);
}
TemplatePage Template::createPage(std::string name)
TemplatePage Template::createPage(std::string_view name)
{
std::string content = loadResolvedPart(name);
Varreplacer replacer(this->templateprefix);
@ -65,16 +78,6 @@ TemplatePage Template::createPage(std::string name)
return TemplatePage(replacer.parse(content));
}
TemplatePage &Template::getPage(const std::string &pagename)
{
if(utils::hasKey(pagesMap, pagename))
{
return pagesMap[pagename];
}
pagesMap.insert(std::make_pair(pagename, createPage(pagename)));
return pagesMap[pagename];
}
// TODO: this restricts template a bit
std::string Template::renderSearch(const std::vector<std::string> &results,
std::function<std::string(std::string)> callback) const

Ver arquivo

@ -8,31 +8,29 @@
#include "response.h"
#include "searchresult.h"
#include "revision.h"
#include "cache/mapcache.h"
class Template
{
private:
ConfigVariableResolver *configVarResolver;
ConfigUrls *configUrls;
MapCache<TemplatePage> *pageCache;
std::string templateprefix;
std::string templatepath;
std::map<std::string, TemplatePage> pagesMap;
std::string resolveIncludes(std::string_view content);
std::string getPartPath(std::string_view partname);
std::string loadResolvedPart(std::string_view partname);
std::string loadPartContent(std::string_view partname);
TemplatePage createPage(std::string name);
TemplatePage createPage(std::string_view name);
public:
Template(std::string templateprefix, std::string templatepath, ConfigUrls &configUrls,
ConfigVariableResolver &configVarsResolver);
/* TODO: returning this as a reference is by no means a risk free business,
because between requests, different vars can be set conditionally,
thus creating a mess
*/
TemplatePage &getPage(const std::string &pagename);
ConfigVariableResolver &configVarsResolver, MapCache<TemplatePage> &pageCache);
TemplatePage getPage(const std::string &pagename);
std::string renderSearch(const std::vector<std::string> &results,
std::function<std::string(std::string)> callback) const;

Ver arquivo

@ -27,7 +27,7 @@ TemplatePage::TemplatePage()
TemplatePage::TemplatePage(std::string content)
{
this->content = content;
this->content = std::make_shared<std::string>(content);
}
void TemplatePage::setVar(const std::string &key, std::string value)
@ -40,5 +40,5 @@ std::string TemplatePage::render() const
Varreplacer replacer("{qswiki:");
replacer.addResolver("var",
[&](std::string_view key) { return utils::getKeyOrEmpty(this->varsMap, std::string(key)); });
return replacer.parse(this->content);
return replacer.parse(*this->content);
}

Ver arquivo

@ -3,10 +3,11 @@
#include <string>
#include <string_view>
#include <map>
#include <memory>
class TemplatePage
{
private:
std::string content;
std::shared_ptr<const std::string> content;
std::map<std::string, std::string> varsMap;
public:

Ver arquivo

@ -84,7 +84,7 @@ std::string utils::urldecode(std::string_view str)
return result;
}
std::vector<std::string> utils::split(const std::string &str, char delim)
std::vector<std::string> utils::split(std::string str, char delim)
{
std::vector<std::string> result;
std::stringstream stream(str);
@ -97,7 +97,7 @@ std::vector<std::string> utils::split(const std::string &str, char delim)
}
// TODO: can easily break if we pass a regex here
std::vector<std::string> utils::split(const std::string &str, const std::string &delim)
std::vector<std::string> utils::split(std::string str, const std::string &delim)
{
std::regex regex{delim + "+"};
return split(str, regex);
@ -112,7 +112,7 @@ std::vector<std::string> utils::split(const std::string &str, std::regex &regex)
return result;
}
std::string utils::strreplace(const std::string &str, const std::string &search, const std::string &replace)
std::string utils::strreplace(std::string str, const std::string &search, const std::string &replace)
{
std::string result = str;
auto searchlength = search.length();
@ -182,10 +182,9 @@ std::string utils::toISODate(time_t t)
return std::string{result};
}
std::string utils::trim(const std::string &str)
std::string utils::trim(std::string_view view)
{
std::string_view chars = " \t\n\r";
std::string_view view = str;
auto n = view.find_first_not_of(chars);
if(n != std::string_view::npos)
{

21
utils.h
Ver arquivo

@ -8,25 +8,20 @@
#include <map>
#include <regex>
#include <ctime>
#include <limits>
namespace utils
{
std::vector<std::string> split(const std::string &str, char delim);
std::vector<std::string> split(const std::string &str, const std::string &delim);
std::vector<std::string> split(std::string str, char delim);
std::vector<std::string> split(std::string str, const std::string &delim);
std::vector<std::string> split(const std::string &str, std::regex &regex);
std::string urldecode(std::string_view str);
std::string strreplace(const std::string &str, const std::string &search, const std::string &replace);
std::string strreplace(std::string str, const std::string &search, const std::string &replace);
std::string html_xss(std::string_view str);
std::string getenv(const std::string &key);
template <class T, class U> bool hasKey(const std::map<T, U> &map, T key)
{
auto k = map.find(key);
return k != map.end();
}
template <class T, class U> U getKeyOrEmpty(const std::map<T, U> &map, T key)
template <class T, class U> U getKeyOrEmpty(const std::map<T, U> &map, const T &key)
{
auto k = map.find(key);
if(k != map.end())
@ -36,7 +31,7 @@ template <class T, class U> U getKeyOrEmpty(const std::map<T, U> &map, T key)
return U();
}
template <class T, class U> U getKeyOrEmpty(std::multimap<T, U> map, T key)
template <class T, class U> U getKeyOrEmpty(const std::multimap<T, U> &map, const T &key)
{
auto k = map.find(key);
if(k != map.end())
@ -46,7 +41,7 @@ template <class T, class U> U getKeyOrEmpty(std::multimap<T, U> map, T key)
return U();
}
template <class T, class U> std::vector<U> getAll(std::multimap<T, U> map, T key)
template <class T, class U> std::vector<U> getAll(const std::multimap<T, U> &map, const T &key)
{
std::vector<U> result;
auto range = map.equal_range(key);
@ -93,7 +88,7 @@ template <class T> inline std::string toString(const T &v)
return std::string(v.begin(), v.end());
}
std::string trim(const std::string &str);
std::string trim(std::string_view view);
} // namespace utils
#endif

Ver arquivo

@ -60,12 +60,12 @@ std::string Varreplacer::makeReplacement(std::string_view varkeyvalue)
std::string_view value;
std::tie(key, value) = extractKeyAndValue(varkeyvalue);
if(utils::hasKey(keyValues, key))
if(keyValues.contains(key))
{
std::string replacementContent = keyValues[key];
return replacementContent;
}
else if(utils::hasKey(resolverFunctionsMap, key))
else if(resolverFunctionsMap.contains(key))
{
auto resolver = this->resolverFunctionsMap[key];