From 9b8779a00ba684f99474cc3de63cdb812a1d3741 Mon Sep 17 00:00:00 2001 From: bert hubert Date: Thu, 25 Jan 2024 13:35:30 +0100 Subject: [PATCH] make sure that images from disabled users disappear, plus add test cases. Closes #27. --- serv.cc | 16 +++++-------- support.cc | 12 +++++++--- support.hh | 1 + testrunner.cc | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/serv.cc b/serv.cc index caf8cf1..ed122c2 100644 --- a/serv.cc +++ b/serv.cc @@ -10,15 +10,6 @@ #include "git_version.h" using namespace std; -/* -Todo: - if a user is disabled, do images/posts turn into 404s? - opengraph data for previews, how? iframe? - - how do we deal with errors? 500? or a JSON thing? - plan: never do 500, always set an 'ok' field -*/ - void checkImageOwnership(LockedSqw& lsqw, Users& u, const std::string& user, const std::string& imgid) { if(!u.userHasCap(user, Capability::Admin)) { @@ -57,6 +48,9 @@ bool shouldShow(Users& u, const std::string& user, unordered_map(row["public"])) // not public, no show return false; + if(u.isUserDisabled(get(row["user"]))) + return false; + time_t pubUntil = get(row["publicUntilTstamp"]); return (!pubUntil || time(0) < pubUntil); } @@ -150,6 +144,7 @@ int trifectaMain(int argc, const char**argv) fmt::print("WARNING: No admin users are defined, try --rnd-admin-password\n"); } + // this is here to insert opengraph tags into the HTML, because crawlers won't execute javascript for us sws.d_svr.set_file_request_handler([&sws, &canURL](const httplib::Request& req, httplib::Response& res) { if(req.path=="/") { string searchString=""; @@ -194,7 +189,7 @@ int trifectaMain(int argc, const char**argv) sws.wrapGet({}, "/getPost/:postid", [](auto& cr) { string postid = cr.req.path_params.at("postid"); nlohmann::json j; - + j["ok"]=0; auto post = cr.lsqw.query("select user, public, title, publicUntilTstamp from posts where id=?", {postid}); if(post.size() != 1) { j["images"] = nlohmann::json::array(); @@ -212,6 +207,7 @@ int trifectaMain(int argc, const char**argv) else j["can_touch_post"] = 0; j["publicUntilExpired"] = until && (time(0) < until); + j["ok"]=1; } return j; }); diff --git a/support.cc b/support.cc index da84919..2a6409e 100644 --- a/support.cc +++ b/support.cc @@ -219,7 +219,7 @@ bool Users::userHasCap(const std::string& user, const Capability& cap, const htt auto c = d_lsqw.query("select count(1) as c from users where user=? and disabled=0 and admin=1", {user}); ret = (c.size()==1 && get(c[0]["c"])==1); } else if(cap==Capability::EmailAuthenticated && req) { - auto c = d_lsqw.query("select count(1) as c from sessions where user=? and authenticated=1 and id=?", {user, getSessionID(*req)}); + auto c = d_lsqw.query("select count(1) as c from sessions where user=? and disabled=0 and authenticated=1 and id=?", {user, getSessionID(*req)}); ret = (c.size()==1 && get(c[0]["c"])==1); } return ret; @@ -244,6 +244,12 @@ bool Users::hasPassword(const std::string& user) return res.size() == 1 && !get(res[0]["pwhash"]).empty(); } +bool Users::isUserDisabled(const std::string& user) +{ + auto res = d_lsqw.query("select disabled from users where user=?", {user}); + return res.size() == 0 || (get(res.at(0).at("disabled")) == 1); +} + bool Users::checkPassword(const std::string& user, const std::string& password) const { auto res = d_lsqw.query("select pwhash, caps from users where user=? and disabled=0", {user}); @@ -473,8 +479,8 @@ void SimpleWebSystem::standardFunctions() cr.lsqw.query("update users set disabled = ? where user=?", {disabled, user}); if(disabled) { cr.lsqw.query("delete from sessions where user=?", {user}); // XX candidate for Sessions class - } - cr.log({{"action", "change-user-disabled"}, {"who", user}}); + } // "to" is used in another log action as a string + cr.log({{"action", "change-user-disabled"}, {"who", user}, {"to", to_string(disabled)}}); return nlohmann::json{{"ok", 1}}; }); diff --git a/support.hh b/support.hh index dd2bb69..edb2306 100644 --- a/support.hh +++ b/support.hh @@ -73,6 +73,7 @@ struct Users void delUser(const std::string& user); bool userHasCap(const std::string& user, const Capability& cap, const httplib::Request* req=0); bool hasPassword(const std::string& user); + bool isUserDisabled(const std::string& user); // user that doesn't exist is also disabled LockedSqw& d_lsqw; }; diff --git a/testrunner.cc b/testrunner.cc index 0dc22d9..b732a17 100644 --- a/testrunner.cc +++ b/testrunner.cc @@ -521,6 +521,71 @@ TEST_CASE("web admin tests") { CHECK(found == true); } +TEST_CASE("disable user test") { + httplib::Client cli("127.0.0.1", 9999); + + auto adminSession = getTFS().doLogin(); + auto katySession = createAndLoginUser(cli, adminSession, "katy", "katy123"); + + httplib::MultipartFormDataItems items = { + { "file", "123 test content", "hello2.png", "image/png" } + }; + auto res = cli.Post("/upload", katySession, items); + REQUIRE(res != 0); + nlohmann::json j = nlohmann::json::parse(res->body); + CHECK(j["postId"] != ""); + + cout<body == items[0].content); + + res = cli.Post("/change-user-disabled/katy/1", adminSession); + REQUIRE(res != 0); CHECK(nlohmann::json::parse(res->body)["ok"] == 1); + + res = cli.Get("/i/"+id); // should no longer work + REQUIRE(res != 0); CHECK(res->body != items[0].content); + + res = cli.Get("/i/"+id, katySession); // should no longer work + REQUIRE(res != 0); CHECK(res->body != items[0].content); + + res = cli.Get("/i/"+id, adminSession); // should still work + REQUIRE(res != 0); CHECK(res->body == items[0].content); + + res = cli.Get("/getPost/"+postid, adminSession); // should still work + REQUIRE(res != 0); CHECK(nlohmann::json::parse(res->body)["ok"] == 1); + + res = cli.Get("/getPost/"+postid); // anon + REQUIRE(res != 0); CHECK(nlohmann::json::parse(res->body)["ok"] == 0); + + res = cli.Get("/getPost/"+postid, katySession); // katy + REQUIRE(res != 0); CHECK(nlohmann::json::parse(res->body)["ok"] == 0); + + auto stuff = [&]() { + getTFS().doLogin("katy", "katy123"); + }; + CHECK_THROWS_AS(stuff(), const std::exception&); + + res = cli.Post("/change-user-disabled/katy/0", adminSession); + REQUIRE(res != 0); CHECK(nlohmann::json::parse(res->body)["ok"] == 1); + + katySession = getTFS().doLogin("katy", "katy123"); + + res = cli.Get("/i/"+id, katySession); // retry + REQUIRE(res != 0); CHECK(res->body == items[0].content); + + res = cli.Get("/i/"+id); // anon + REQUIRE(res != 0); CHECK(res->body == items[0].content); + + res = cli.Get("/getPost/"+postid, katySession); // katy + REQUIRE(res != 0); CHECK(nlohmann::json::parse(res->body)["ok"] == 1); + + res = cli.Get("/getPost/"+postid); // anon + REQUIRE(res != 0); CHECK(nlohmann::json::parse(res->body)["ok"] == 1); +} + TEST_CASE("change my password") { httplib::Client cli("127.0.0.1", 9999);