sparkle/libs/tls/Network.hpp

145 lines
5.8 KiB
C++
Raw Normal View History

2024-12-31 02:20:56 +05:00
#ifndef TLS_NETWORK_HPP_
#define TLS_NETWORK_HPP_
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <iostream>
#include <string>
#include <net/if.h>
#include <netdb.h>
#include <utils/types.hpp>
2025-01-13 14:40:21 +05:00
#include <gateway/Websocket.hpp>
2024-12-31 02:20:56 +05:00
using std::cout;
using std::cerr;
using std::endl;
class NetworkManager {
private:
2024-12-31 05:58:15 +05:00
WebSocket& web;
2024-12-31 02:20:56 +05:00
SSL_CTX* ctx;
int sock = -1;
std::unique_ptr<SSL, decltype(&SSL_free)> ssl = { nullptr, &SSL_free };
void handleSSLInitErrors() {
ERR_print_errors_fp(stderr);
abort();
}
void createSSLConnection(const std::string& hostname, const std::string& port) {
2025-01-14 05:18:08 +05:00
Logs::create(INFO, NETWORK, "SSL connection");
2025-01-13 14:40:21 +05:00
addrinfo hints = { 0 }, *res = { 0 };
2024-12-31 02:20:56 +05:00
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(hostname.c_str(), port.c_str(), &hints, &res) != 0) {
2025-01-14 05:18:08 +05:00
Logs::create(ERROR, NETWORK, "Failed to get address info for " + hostname + ":" + port);
2024-12-31 02:20:56 +05:00
handleSSLInitErrors();
}
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock == -1) {
2025-01-14 05:18:08 +05:00
Logs::create(ERROR, NETWORK, "Socket error");
close(sock);
2024-12-31 02:20:56 +05:00
handleSSLInitErrors();
}
if (connect(sock, res->ai_addr, res->ai_addrlen) == -1) {
2025-01-14 05:18:08 +05:00
Logs::create(ERROR, NETWORK, "Failed to connect to " + hostname + ":" + port);
2024-12-31 02:20:56 +05:00
close(sock);
handleSSLInitErrors();
}
ssl.reset(SSL_new(ctx));
if (!ssl) {
2025-01-14 05:18:08 +05:00
Logs::create(ERROR, NETWORK, "Failed to create SSL structure");
2024-12-31 02:20:56 +05:00
close(sock);
handleSSLInitErrors();
}
SSL_set_fd(ssl.get(), sock);
if (SSL_connect(ssl.get()) != 1) {
2025-01-14 05:18:08 +05:00
Logs::create(ERROR, NETWORK, "SSL connection failed");
2024-12-31 02:20:56 +05:00
close(sock);
handleSSLInitErrors();
}
freeaddrinfo(res);
}
2025-01-13 14:40:21 +05:00
NetworkManager& operator=(const NetworkManager&) = delete;
NetworkManager(const NetworkManager&) = delete;
2025-01-14 05:18:08 +05:00
NetworkManager() : web(WebSocket::getInstance()) {
Logs::create(INFO, NETWORK, "Network init");
2024-12-31 02:20:56 +05:00
if (!ctx) {
ctx = SSL_CTX_new(TLS_client_method());
if (!ctx) {
2025-01-14 05:18:08 +05:00
Logs::create(ERROR, NETWORK, "Failed to create SSL context");
2024-12-31 02:20:56 +05:00
handleSSLInitErrors();
}
OPENSSL_init_ssl(0, 0);
OPENSSL_add_all_algorithms_noconf();
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
createSSLConnection("discord.com", "443");
}
}
2025-01-13 14:40:21 +05:00
std::string parseJson(const std::string& response) {
unsigned long jsonStart = response.find("\r\n\r\n");
if (jsonStart == std::string::npos) {
return "";
}
jsonStart += 4;
std::string jsonString = response.substr(jsonStart);
unsigned long jsonBegin = jsonString.find('['), jsonEnd = jsonString.rfind(']');
if (jsonBegin == std::string::npos || jsonEnd == std::string::npos || jsonEnd < jsonBegin) {
return "";
}
jsonString = jsonString.substr(jsonBegin, jsonEnd - jsonBegin + 1);
jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\r'), jsonString.end());
jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\t'), jsonString.end());
jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\n'), jsonString.end());
jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\\'), jsonString.end());
jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\''), jsonString.end());
jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), ' '), jsonString.end());
try {
nlohmann::json jsonData = nlohmann::json::parse(jsonString);
return jsonData.dump();
2024-12-31 02:20:56 +05:00
}
2025-01-13 14:40:21 +05:00
catch (const nlohmann::json::parse_error& e) {
return "";
}
}
public:
static NetworkManager& getInstance() {
2025-01-14 05:18:08 +05:00
Logs::create(WARNING, NETWORK, "Instance event");
2025-01-13 14:40:21 +05:00
static NetworkManager instance;
2024-12-31 02:20:56 +05:00
return instance;
}
~NetworkManager() {
if (ctx) SSL_CTX_free(ctx);
close(sock);
}
2025-01-13 14:40:21 +05:00
std::string request(const std::string& method, const std::string& path, const std::string& data = "") {
#ifdef DEBUG
createSSLConnection("discord.com", "443");
#endif
2025-01-14 05:18:08 +05:00
auto net = [this, method, path, data, result = std::string("")]() mutable -> std::string {
2025-01-13 14:40:21 +05:00
std::string request = method + " " + path + " HTTP/1.1\r\nHost: discord.com\r\nAccept: application/json\r\nContent-Type: application/json\r\n";
request += "Authorization: " + web.getToken() + "\r\nContent-Length: " + std::to_string(data.length()) + "\r\n";
2024-12-31 04:46:39 +05:00
#ifdef DEBUG
request += "Connection: close\r\n\r\n";
#elif defined(RELEASE)
2024-12-31 02:20:56 +05:00
request += "Connection: keep-alive\r\n\r\n";
2024-12-31 04:46:39 +05:00
#endif
2024-12-31 02:20:56 +05:00
request += data;
if (SSL_write(ssl.get(), request.c_str(), request.length()) <= 0) {
2025-01-13 14:40:21 +05:00
std::cerr << "Failed to send request" << std::endl;
2024-12-31 02:20:56 +05:00
handleSSLInitErrors();
}
2025-01-14 05:18:08 +05:00
Logs::create(INFO, NETWORK, "Request " + method + " " + path);
2024-12-31 02:20:56 +05:00
#ifdef DEBUG
2025-01-13 14:40:21 +05:00
std::vector<char> buffer(1024);
int bytesRead;
while ((bytesRead = SSL_read(ssl.get(), buffer.data(), buffer.size())) > 0) {
result.append(buffer.data(), bytesRead);
if (bytesRead == buffer.size()) {
buffer.resize(buffer.size() * 2);
}
2024-12-31 02:20:56 +05:00
}
2025-01-14 05:18:08 +05:00
return parseJson(result);
#elif defined(RELEASE)
return result;
2024-12-31 02:20:56 +05:00
#endif
};
2025-01-14 05:18:08 +05:00
return net();
2024-12-31 02:20:56 +05:00
}
};
#endif