|
|
|
@ -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();
|
|
|
|
|
}
|
|
|
|
|