diff --git a/handlers/handler.cpp b/handlers/handler.cpp index 3162a00..4113950 100644 --- a/handlers/handler.cpp +++ b/handlers/handler.cpp @@ -98,7 +98,10 @@ Response Handler::handle(const Request &r) Permissions Handler::effectivePermissions(std::string page) { - return this->database->createPermissionsDao() - ->find(page, this->userSession->user.login) - .value_or(this->userSession->user.permissions); + Permissions &userPerms = this->userSession->user.permissions; + if(userPerms.isAdmin()) + { + return userPerms; + } + return this->database->createPermissionsDao()->find(page, this->userSession->user.login).value_or(userPerms); } diff --git a/handlers/handlerpageedit.cpp b/handlers/handlerpageedit.cpp index e3d34be..e7eab90 100644 --- a/handlers/handlerpageedit.cpp +++ b/handlers/handlerpageedit.cpp @@ -24,6 +24,7 @@ SOFTWARE. #include "../parser.h" #include "../revisionrenderer.h" + bool HandlerPageEdit::canAccess([[maybe_unused]] std::string page) { return effectivePermissions(page).canEdit(); @@ -56,7 +57,8 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename, { if(!effectivePermissions(from).canRead()) { - return this->errorResponse("Permission denied", "No access permissions, so you can't use this page as a template"); + return this->errorResponse("Permission denied", + "No access permissions, so you can't use this page as a template"); } body = revisiondao->getCurrentForPage(from)->content; } @@ -77,6 +79,7 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename, std::string visiblecmd = parser.extractCommand("visible", newContent); std::string rename = parser.extractCommand("rename", newContent); std::string customtitle = parser.extractCommand("pagetitle", newContent); + std::vector perms = parser.extractCommands("permissions", newContent); Page page; std::optional currentPage = pageDao.find(pagename); if(currentPage) @@ -91,6 +94,33 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename, } pagename = rename; } + + for(const std::string &perm : perms) + { + auto splitted = utils::split(perm, '|'); + if(splitted.size() != 2) + { + return this->errorResponse("Invalid command", "permissions command is misformated"); + } + auto permissionDao = this->database->createPermissionsDao(); + auto currentPermission = permissionDao->find(pagename, splitted[0]); + + Permissions newPermissions = Permissions{splitted[1]}; + if(!currentPermission || newPermissions != currentPermission.value()) + { + if(this->userSession->user.permissions.canSetPagePerms()) + { + permissionDao->save(pagename, splitted[0], newPermissions); + } + else + { + this->database->rollbackTransaction(); + return errorResponse("Invalid permissions", + "You don't have permission to change page permissions"); + } + } + } + page.current_revision = current_revision; page.listed = !(visiblecmd == "0"); page.name = pagename; @@ -130,7 +160,7 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename, TemplatePage templatePage = this->templ->getPage("page_creation_preview"); templatePage.setVar("actionurl", urlProvider->editPage(pagename)); - RevisionRenderer revisionRenderer { *this->templ, *this->database, *this->urlProvider }; + RevisionRenderer revisionRenderer{*this->templ, *this->database, *this->urlProvider, *this->userSession}; templatePage.setVar("preview_content", revisionRenderer.renderContent(newContent)); templatePage.setVar("content", newContent); diff --git a/iparser.h b/iparser.h index da37009..0b7dc69 100644 --- a/iparser.h +++ b/iparser.h @@ -16,6 +16,8 @@ class IParser public: virtual std::string extractCommand(std::string cmdname, const std::string &content) const = 0; + virtual std::vector extractCommands(std::string cmdname, const std::string &content) const = 0; + virtual std::vector extractHeadlines(const std::string &content) const = 0; virtual inline std::string parse(const PageDao &pagedao, UrlProvider &provider, const std::string &content) const { diff --git a/parser.cpp b/parser.cpp index c9b94f3..6d6c517 100644 --- a/parser.cpp +++ b/parser.cpp @@ -82,6 +82,28 @@ std::string Parser::extractCommand(std::string cmdname, const std::string &conte } return ""; } + +std::vector Parser::extractCommands(std::string cmdname, const std::string &content) const +{ + std::vector result; + + std::string cmd = "[cmd:" + cmdname + "]"; + std::string cmdend = "[/cmd:" + cmdname + "]"; + + std::string_view view = content; + size_t pos = 0; + while((pos = view.find(cmd)) != std::string::npos) + { + view.remove_prefix(pos); + view.remove_prefix(cmd.size()); + if((pos = view.find(cmdend)) != std::string::npos) + { + result.emplace_back(view.substr(0, pos)); + } + } + return result; +} + std::string Parser::processLink(const PageDao &pageDao, UrlProvider &urlProvider, std::smatch &match) const { std::string linktag = match.str(1); @@ -148,7 +170,7 @@ std::string Parser::parse(const PageDao &pagedao, UrlProvider &provider, const s std::string result; // we don't care about commands, but we nevertheless replace them with empty strings std::regex tagfinder( - R"(\[(b|i|u|s|li||ul|ol|code|blockquote|img|link|wikilink|h\d|cmd:visible|cmd:rename|cmd:redirect|cmd:pagetitle|cmd:allowinclude|category|dynamic:postlist|dynamic:includepage|dynamic:getvar|dynamic:setvar)*?\]((\s|\S)*?)\[/\1])"); + R"(\[(b|i|u|s|li||ul|ol|code|blockquote|img|link|wikilink|h\d|cmd:visible|cmd:rename|cmd:redirect|cmd:pagetitle|cmd:allowinclude|cmd:permissions|category|dynamic:postlist|dynamic:includepage|dynamic:getvar|dynamic:setvar)*?\]((\s|\S)*?)\[/\1])"); result = utils::regex_callback_replacer( tagfinder, content, [&](std::smatch &match) @@ -180,7 +202,7 @@ std::string Parser::parse(const PageDao &pagedao, UrlProvider &provider, const s } if(tag == "code" || tag == "blockquote") { - return "
<" + tag + ">"+ utils::strreplace(content, "\r\n", "\n") + "
"; + return "
<" + tag + ">" + utils::strreplace(content, "\r\n", "\n") + "
"; } return callback(tag, content); }); diff --git a/parser.h b/parser.h index eca8085..f47d22c 100644 --- a/parser.h +++ b/parser.h @@ -9,7 +9,8 @@ class Parser : public IParser std::string processImage(std::smatch &match) const; public: - std::string extractCommand(std::string cmdname, const std::string &content) const; + std::string extractCommand(std::string cmdname, const std::string &content) const override; + std::vector extractCommands(std::string cmdname, const std::string &content) const override; std::vector extractHeadlines(const std::string &content) const override; std::vector extractCategories(const std::string &content) const override; using IParser::parse; diff --git a/permissions.cpp b/permissions.cpp index 7a3644f..c6175a5 100644 --- a/permissions.cpp +++ b/permissions.cpp @@ -20,7 +20,8 @@ SOFTWARE. */ #include "permissions.h" -static const std::map permmap = {{"can_read", PERM_CAN_READ}, +static const std::map permmap = {{"can_nothing", PERM_CAN_NOTHING}, + {"can_read", PERM_CAN_READ}, {"can_edit", PERM_CAN_EDIT}, {"can_page_history", PERM_CAN_PAGE_HISTORY}, {"can_global_history", PERM_CAN_GLOBAL_HISTORY}, @@ -29,7 +30,8 @@ static const std::map permmap = {{"can_read", PERM_CAN_READ}, {"can_create", PERM_CAN_CREATE}, {"can_see_category_list", PERM_CAN_SEE_CATEGORY_LIST}, {"can_see_links_here", PERM_CAN_SEE_LINKS_HERE}, - {"can_search", PERM_CAN_SEARCH}}; + {"can_search", PERM_CAN_SEARCH}, + {"can_set_page_perms", PERM_CAN_SET_PAGE_PERMS}}; Permissions::Permissions(int permissions) { diff --git a/permissions.h b/permissions.h index d66a937..f6ab1b6 100644 --- a/permissions.h +++ b/permissions.h @@ -1,6 +1,7 @@ #ifndef PERMISSIONS_H #define PERMISSIONS_H +#define PERM_CAN_NOTHING 0 #define PERM_CAN_READ 1 << 0 #define PERM_CAN_EDIT 1 << 1 #define PERM_CAN_PAGE_HISTORY 1 << 2 @@ -11,6 +12,8 @@ #define PERM_CAN_SEE_CATEGORY_LIST 1 << 7 #define PERM_CAN_SEE_LINKS_HERE 1 << 8 #define PERM_CAN_SEARCH 1 << 9 +#define PERM_CAN_SET_PAGE_PERMS 1 << 10 +#define PERM_IS_ADMIN (1L<<31)-1 #include #include @@ -54,10 +57,16 @@ class Permissions return this->permissions; } + bool canNothing() const + { + return this->permissions == PERM_CAN_NOTHING; + } + bool canRead() const { return this->permissions & PERM_CAN_READ; } + bool canEdit() const { return this->permissions & PERM_CAN_EDIT; @@ -95,12 +104,27 @@ class Permissions return this->permissions & PERM_CAN_SEE_PAGE_LIST; } + bool canSetPagePerms() const + { + return this->permissions & PERM_CAN_SET_PAGE_PERMS; + } + + bool isAdmin() const + { + return this->permissions == PERM_IS_ADMIN; + } + std::string toString() const { return Permissions::toString(this->permissions); } static std::string toString(int perms); + + bool operator==(const Permissions &o) const + { + return this->permissions == o.permissions; + } }; #endif // PERMISSIONS_H