Checking client hostname and secret

master
denes 6 years ago
parent dacda254ee
commit e10515affa

@ -21,15 +21,27 @@ https://www.gnu.org/licenses/gpl-3.0.html.
#define WEBHOOK_MESSAGE_HPP
#include <cpp_utils/Message.hpp>
#include <cpp_utils/TcpConnection.hpp>
#include <iomanip> // put_time
#include <ctime>
#include <sstream>
#include <vector>
#include <stdexcept>
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<WebhookMessageParam*>(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<TcpConnection*>(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();
}

@ -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 <denes@matetelki.com>"
);
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<void*>(
const_cast<char*>(script_path.c_str())));
WebhookMessage msg(reinterpret_cast<void*>(&p));
const std::string host("127.0.0.1");
std::string port;

Loading…
Cancel
Save