Compare commits
9 Commits
a31d88c7b3
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ae1d33a14e | |||
| 610da575ea | |||
| 9b129f0255 | |||
| 8e77116027 | |||
| 70f7289c8c | |||
| d0de7b8f3b | |||
| f0f5846a4a | |||
| e90b08dbde | |||
| ffa59d4b36 |
2
Makefile
2
Makefile
@@ -53,7 +53,7 @@ profile: qswiki
|
|||||||
|
|
||||||
|
|
||||||
exile.o: submodules/exile.h/exile.c
|
exile.o: submodules/exile.h/exile.c
|
||||||
$(CC) -std=c99 -DHAVE_LANDLOCK=0 -c submodules/exile.h/exile.c -o exile.o
|
$(CC) -std=c99 -c submodules/exile.h/exile.c -o exile.o
|
||||||
|
|
||||||
qswiki: $(WIKIOBJECTS) exile.o
|
qswiki: $(WIKIOBJECTS) exile.o
|
||||||
$(CXX) $(shell shuf -e $(WIKIOBJECTS) exile.o ) ${LDFLAGS} ${INCLUDEFLAGS} -o qswiki
|
$(CXX) $(shell shuf -e $(WIKIOBJECTS) exile.o ) ${LDFLAGS} ${INCLUDEFLAGS} -o qswiki
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ SOFTWARE.
|
|||||||
*/
|
*/
|
||||||
#include "httpgateway.h"
|
#include "httpgateway.h"
|
||||||
#include "../logger.h"
|
#include "../logger.h"
|
||||||
|
#include <stdexcept>
|
||||||
HttpGateway::HttpGateway(std::string listenaddr, int port, uint64_t maxPayloadLength)
|
HttpGateway::HttpGateway(std::string listenaddr, int port, uint64_t maxPayloadLength)
|
||||||
{
|
{
|
||||||
this->listenaddr = listenaddr;
|
this->listenaddr = listenaddr;
|
||||||
@@ -34,6 +35,11 @@ bool HttpGateway::keepReading()
|
|||||||
|
|
||||||
Request HttpGateway::convertRequest(httplib::Request request)
|
Request HttpGateway::convertRequest(httplib::Request request)
|
||||||
{
|
{
|
||||||
|
if(!utils::is_printable_ascii(request.target))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid chars in URI: " + utils::catv(request.target));
|
||||||
|
}
|
||||||
|
|
||||||
Request result;
|
Request result;
|
||||||
result.setRequestMethod(request.method);
|
result.setRequestMethod(request.method);
|
||||||
result.setUrl(request.target);
|
result.setUrl(request.target);
|
||||||
@@ -55,6 +61,12 @@ Request HttpGateway::convertRequest(httplib::Request request)
|
|||||||
|
|
||||||
if(request.has_header("COOKIE"))
|
if(request.has_header("COOKIE"))
|
||||||
{
|
{
|
||||||
|
std::string cookie = request.get_header_value("COOKIE");
|
||||||
|
if(!utils::is_printable_ascii(cookie))
|
||||||
|
{
|
||||||
|
/* We better bail */
|
||||||
|
throw std::runtime_error("Cookie with non printable chars sent");
|
||||||
|
}
|
||||||
result.initCookies(request.get_header_value("COOKIE"));
|
result.initCookies(request.get_header_value("COOKIE"));
|
||||||
}
|
}
|
||||||
result.setIp("127.0.0.1");
|
result.setIp("127.0.0.1");
|
||||||
@@ -82,6 +94,27 @@ httplib::Response HttpGateway::convertResponse(Response response)
|
|||||||
void HttpGateway::work(RequestWorker &worker)
|
void HttpGateway::work(RequestWorker &worker)
|
||||||
{
|
{
|
||||||
httplib::Server server;
|
httplib::Server server;
|
||||||
|
server.set_exception_handler([](const httplib::Request& req, httplib::Response& res, std::exception_ptr ep) {
|
||||||
|
auto fmt = "<h1>Error 500</h1><p>%s</p>";
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::rethrow_exception(ep);
|
||||||
|
}
|
||||||
|
catch (std::exception &e)
|
||||||
|
{
|
||||||
|
std::string exception = utils::html_xss(e.what());
|
||||||
|
snprintf(buf, sizeof(buf), fmt, exception.c_str());
|
||||||
|
Logger::error() << "Exception caught in Httpgateway::work():" << utils::html_xss(utils::catv(e.what()));
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
snprintf(buf, sizeof(buf), fmt, "Unknown Exception");
|
||||||
|
Logger::error() << "Unknown exception caught in Httpgateway::work()";
|
||||||
|
}
|
||||||
|
res.set_content(buf, "text/html");
|
||||||
|
res.status = 500;
|
||||||
|
});
|
||||||
server.set_payload_max_length(this->maxPayloadLength);
|
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)
|
||||||
{
|
{
|
||||||
@@ -94,4 +127,5 @@ void HttpGateway::work(RequestWorker &worker)
|
|||||||
server.Get("/(.*)", handler);
|
server.Get("/(.*)", handler);
|
||||||
server.Post("/(.*)", handler);
|
server.Post("/(.*)", handler);
|
||||||
server.listen(this->listenaddr.c_str(), this->listenport);
|
server.listen(this->listenaddr.c_str(), this->listenport);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
9
logger.h
9
logger.h
@@ -2,6 +2,7 @@
|
|||||||
#define LOGGER_H
|
#define LOGGER_H
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include "utils.h"
|
||||||
class Logger
|
class Logger
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -24,7 +25,15 @@ class Logger
|
|||||||
{
|
{
|
||||||
(*out) << time(0) << " " << prefix;
|
(*out) << time(0) << " " << prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_convertible_v<T, std::string_view>)
|
||||||
|
{
|
||||||
|
(*out) << utils::catv(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
(*out) << val;
|
(*out) << val;
|
||||||
|
}
|
||||||
headerSent = true;
|
headerSent = true;
|
||||||
return *this; // or maybe out itself? probably not.
|
return *this; // or maybe out itself? probably not.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,8 +230,8 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
catch(const std::exception &e)
|
catch(const std::exception &e)
|
||||||
{
|
{
|
||||||
Logger::error() << e.what();
|
Logger::error() << utils::catv(e.what());
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << utils::catv(e.what()) << std::endl;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
29
request.cpp
29
request.cpp
@@ -86,7 +86,15 @@ void Request::initCookies(const std::string &cookiestr)
|
|||||||
|
|
||||||
std::string Request::get(const std::string &key) const
|
std::string Request::get(const std::string &key) const
|
||||||
{
|
{
|
||||||
return utils::getKeyOrEmpty(this->getVars, key);
|
std::string value = utils::getKeyOrEmpty(this->getVars, key);
|
||||||
|
/* In general all our expected GET values are printable and, for now, ascii.
|
||||||
|
* If not, it's not a normal request. So just return an empty string then.
|
||||||
|
* Exceptions are probably a bit too much */
|
||||||
|
if(!utils::is_printable_ascii(value))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Request::post(const std::string &key) const
|
std::string Request::post(const std::string &key) const
|
||||||
@@ -105,23 +113,18 @@ std::string Request::param(const std::string &key) const
|
|||||||
}
|
}
|
||||||
std::string Request::cookie(const std::string &key) const
|
std::string Request::cookie(const std::string &key) const
|
||||||
{
|
{
|
||||||
|
std::string value;
|
||||||
for(const Cookie &c : cookies)
|
for(const Cookie &c : cookies)
|
||||||
{
|
{
|
||||||
if(c.key == key)
|
if(c.key == key)
|
||||||
{
|
{
|
||||||
return c.value;
|
value = c.value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(utils::is_printable_ascii(value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Request::allGet(const std::string &key)
|
|
||||||
{
|
|
||||||
return utils::getAll(this->getVars, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> Request::allPost(const std::string &key)
|
|
||||||
{
|
|
||||||
return utils::getAll(this->postVars, key);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -34,9 +34,6 @@ class Request
|
|||||||
std::string post(const std::string &key) const;
|
std::string post(const std::string &key) const;
|
||||||
std::string cookie(const std::string &key) const;
|
std::string cookie(const std::string &key) const;
|
||||||
std::string param(const std::string &key) const;
|
std::string param(const std::string &key) const;
|
||||||
std::vector<std::string> allGet(const std::string &key);
|
|
||||||
std::vector<std::string> allPost(const std::string &key);
|
|
||||||
|
|
||||||
const std::vector<Cookie> &getCookies() const
|
const std::vector<Cookie> &getCookies() const
|
||||||
{
|
{
|
||||||
return this->cookies;
|
return this->cookies;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ bool SandboxLinux::enable(std::vector<std::string> fsPaths)
|
|||||||
struct exile_policy *policy = exile_init_policy();
|
struct exile_policy *policy = exile_init_policy();
|
||||||
if(policy == NULL)
|
if(policy == NULL)
|
||||||
{
|
{
|
||||||
Logger::error() << "Failed to init sandboxing policy (worker) ";
|
Logger::error() << "Failed to init sandboxing policy";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for(unsigned int i = 0; i < fsPaths.size(); i++)
|
for(unsigned int i = 0; i < fsPaths.size(); i++)
|
||||||
@@ -55,10 +55,8 @@ bool SandboxLinux::enable(std::vector<std::string> fsPaths)
|
|||||||
exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ | EXILE_FS_ALLOW_ALL_WRITE, path.c_str());
|
exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ | EXILE_FS_ALLOW_ALL_WRITE, path.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
policy->drop_caps = 1;
|
|
||||||
policy->not_dumpable = 1;
|
policy->not_dumpable = 1;
|
||||||
policy->no_new_privs = 1;
|
policy->no_new_privs = 1;
|
||||||
policy->mount_path_policies_to_chroot = 1;
|
|
||||||
policy->vow_promises = exile_vows_from_str("stdio wpath cpath rpath inet unix thread");
|
policy->vow_promises = exile_vows_from_str("stdio wpath cpath rpath inet unix thread");
|
||||||
if(exile_enable_policy(policy) != 0)
|
if(exile_enable_policy(policy) != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
Submodule submodules/exile.h updated: e711a1d53a...4cfdead5d0
37
utils.cpp
37
utils.cpp
@@ -214,3 +214,40 @@ std::string utils::trim(std::string_view view)
|
|||||||
}
|
}
|
||||||
return std::string{view};
|
return std::string{view};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string utils::catv(std::string_view view)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
result.reserve(view.length());
|
||||||
|
for(auto c : view)
|
||||||
|
{
|
||||||
|
if (!isascii(c))
|
||||||
|
{
|
||||||
|
result += "M-";
|
||||||
|
result += toascii(c);
|
||||||
|
}
|
||||||
|
else if(iscntrl(c))
|
||||||
|
{
|
||||||
|
result += '^';
|
||||||
|
result += c == '\177' ? '?': c | 0100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utils::is_printable_ascii(std::string view)
|
||||||
|
{
|
||||||
|
for(char c : view)
|
||||||
|
{
|
||||||
|
if( !(c >= ' ' && c <= '~'))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
4
utils.h
4
utils.h
@@ -91,6 +91,10 @@ template <class T> inline std::string toString(const T &v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string trim(std::string_view view);
|
std::string trim(std::string_view view);
|
||||||
|
std::string catv(std::string_view view);
|
||||||
|
|
||||||
|
bool is_printable_ascii(std::string view);
|
||||||
|
|
||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user