You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
webfish/WebhookMessage.hpp

151 lines
3.4 KiB

/*
Copyright 2018 Denes Matetelki <denes@matetelki.com>
This file is part of webfish.
webfish is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License v3 as published by the Free
Software Foundation.
webfish is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License v3 for
more details.
You should have received a copy of the GNU General Public License v3 along
with webfish. If not, see
https://www.gnu.org/licenses/gpl-3.0.html.
*/
#ifndef WEBHOOK_MESSAGE_HPP
#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)
{
TRACE;
}
bool buildMessage( const void *msgPart,
const size_t msgLen )
{
TRACE;
m_buffer = std::string( (const char*) msgPart, msgLen );
/// @todo use it!
// not using getExpectedLength
onMessageReady();
return true;
}
void onMessageReady()
{
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.");
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(const std::string status) const {
const auto t = std::time(nullptr);
const auto tm = *std::localtime(&t);
std::ostringstream oss;
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 << "Server: webfish(0.1)\r\n" \
"Content-Type: text/plain;charset=utf-8\r\n" \
"Content-Length: 10\r\n" \
"Connection: close\r\n" \
"\r\n" \
"Processed\n";
return oss.str();
}
Message* clone()
{
TRACE;
return new WebhookMessage(m_param);
}
std::string getBuffer()
{
TRACE;
return m_buffer;
}
protected:
size_t getExpectedLength()
{
TRACE;
return 0;
}
};
#endif // WEBHOOK_MESSAGE_HPP