diff --git a/WebhookMessage.hpp b/WebhookMessage.hpp index 375422b..a267526 100644 --- a/WebhookMessage.hpp +++ b/WebhookMessage.hpp @@ -21,15 +21,27 @@ https://www.gnu.org/licenses/gpl-3.0.html. #define WEBHOOK_MESSAGE_HPP #include +#include #include // put_time #include #include +#include + +#include + + class WebhookMessage : public Message { public: + struct WebhookMessageParam { + const std::string script_path; + const std::string client; + const std::string secret; + }; + WebhookMessage( void *msgParam = 0) : Message(msgParam) { @@ -52,37 +64,63 @@ public: { TRACE; -// LOG_BEGIN(Logger::INFO) -// LOG_PROP("buffer", m_buffer) -// LOG_PROP("host", m_connection->getHost()) -// LOG_PROP("port", m_connection->getPort()) -// LOG_END("Got message."); - - /// @todo check the source and pass is any and reply with 400 or 404 - - int status = system((const char*)m_param); - - std::string r = generateReply(status == 0); - m_connection->send(r.c_str(), r.length()); + LOG_BEGIN(Logger::INFO) + LOG_PROP("buffer", m_buffer) + LOG_PROP("host", m_connection->getHost()) + LOG_PROP("port", m_connection->getPort()) + LOG_END("Got message."); + + std::string reply; + + WebhookMessageParam* p = reinterpret_cast(m_param); + + try { + if (m_connection->getHost() != p->client) { + reply = generateReply("403 Forbidden"); + throw std::runtime_error("Client is not from the hostname we expect."); + } + + if (m_buffer.find("POST /gitea-webhook/post HTTP/1.1") != 0) { + reply = generateReply("400 Bad Request"); + throw std::runtime_error("Received msg is not a gitea-webhook"); + } + + const std::string s = "\"secret\": \"" + p->secret + "\""; + if (m_buffer.find(s) == std::string::npos) { + reply = generateReply("401 Unauthorized"); + throw std::runtime_error("Received msg does not contain the secret."); + } + + } catch (const std::exception& e) { + LOG (Logger::ERR, e.what()); + m_connection->send(reply.c_str(), reply.length()); + m_buffer.clear(); + dynamic_cast(m_connection)->disconnect(); + return; + } + + int status = system(p->script_path.c_str()); + reply = generateReply(status == 0 ? "200 OK": "500 Internal Server Error"); + + m_connection->send(reply.c_str(), reply.length()); m_buffer.clear(); } - std::string generateReply(bool ok = true) const { + std::string generateReply(const std::string status) const { const auto t = std::time(nullptr); const auto tm = *std::localtime(&t); std::ostringstream oss; - oss << "HTTP/1.1 "; - oss << (ok ? "200 OK" : "500 Internal Server Error") << "\r\n"; + oss << "HTTP/1.1 " << status << "\r\n"; // Fri, 08 Feb 2019 12:35:37 GMT oss << "Date: " << std::put_time(&tm, "%a, %d %b %Y %T %Z") << "\r\n"; - oss << "X-Content-Type-Options: nosniff\r\n" \ + oss << "Server: webfish(0.1)\r\n" \ "Content-Type: text/plain;charset=utf-8\r\n" \ "Content-Length: 10\r\n" \ - "Server: webfish(0.1)\r\n" \ + "Connection: close\r\n" \ "\r\n" \ - "Processed\r\n"; + "Processed\n"; return oss.str(); } diff --git a/main.cpp b/main.cpp index 85e47a3..9f08202 100644 --- a/main.cpp +++ b/main.cpp @@ -37,16 +37,24 @@ https://www.gnu.org/licenses/gpl-3.0.html. int main(int argc, char* argv[]) { - ArgParse a("A simple HTTP server that bites on Gitea webhooks.", + ArgParse a("A simple HTTP server that bites on webhooks.", "Homepage: http://matetelki.eu:3000/denes/webfish\n" \ "Author: Denes Matetelki " ); - a.addArgument("-p", "Listenning port (default is 5050)", - ArgParse::ValueType::INT); - a.addArgument("-f", "File to execute on receiving a POST message", + a.addArgument("-f", "File to execute on receiving a message", ArgParse::ValueType::STRING, ArgParse::Required::REQUIRED, ArgParse::Required::REQUIRED); + a.addArgument("-c", "Client hostname to check", + ArgParse::ValueType::STRING, + ArgParse::Required::REQUIRED, + ArgParse::Required::REQUIRED); + a.addArgument("-p", "Listenning port (default is 5050)", + ArgParse::ValueType::INT); + a.addArgument("-s", "Look for a line in the msg body with '\"secret\": \"SECRET\"'", + ArgParse::ValueType::STRING, + ArgParse::Required::REQUIRED, + ArgParse::Required::REQUIRED); /// @todo Add log verbosity as option @@ -62,12 +70,12 @@ int main(int argc, char* argv[]) Logger::createInstance(); Logger::init(std::cout); - Logger::setLogLevel(Logger::DEBUG); + Logger::setLogLevel(Logger::ERR); + std::string script_path; a.argAsString("-f", script_path); -// std::filesystem fpath(script_path); - struct stat st; + struct stat st; if (stat(script_path.c_str(), &st) < 0) { LOG_STATIC( Logger::ERR, "Parameter file not found."); Logger::destroy(); @@ -79,9 +87,22 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } + std::string client; + if (a.foundArg("-c")) + a.argAsString("-c", client); + std::string secret; + if (a.foundArg("-s")) + a.argAsString("-s", secret); + + LOG_BEGIN(Logger::INFO) + LOG_PROP("script_path", script_path) + LOG_PROP("client", client) + LOG_PROP("secret", secret) + LOG_END_STATIC("Command line parameters"); + + WebhookMessage::WebhookMessageParam p = { script_path, client, secret}; - WebhookMessage msg(reinterpret_cast( - const_cast(script_path.c_str()))); + WebhookMessage msg(reinterpret_cast(&p)); const std::string host("127.0.0.1"); std::string port;