#ifndef CPPHTTPLIB_OPENSSL_SUPPORT #define CPPHTTPLIB_OPENSSL_SUPPORT #endif #include "GetbinClient.hpp" #include "httplib.hpp" #include #include #include #include using json = nlohmann::json; static constexpr const char* SERVER_HOST = "getbin.xyz"; GetbinClient::GetbinClient() {} bool GetbinClient::download(const std::string& toolName, const std::string& arch, const std::string& outPath) { httplib::SSLClient cli(SERVER_HOST, 443); std::string object_path = "/object/" + toolName + ":" + arch; auto res = cli.Get(object_path.c_str()); if (!res || res->status != 200) { std::cerr << "[GetbinClient::download] HTTP request failed (no response)." << std::endl; return false; } std::ofstream ofs(outPath, std::ios::binary); if (!ofs) return false; ofs.write(res->body.data(), res->body.size()); return ofs.good(); } bool GetbinClient::upload(const std::string& archivePath, std::string& outUrl, std::string& outHash, const std::string& token) { httplib::SSLClient cli(SERVER_HOST,443); httplib::MultipartFormDataItems items; // Read file std::ifstream ifs(archivePath, std::ios::binary); if (!ifs) { std::cerr << "[GetbinClient::upload] Failed to open archive file: " << archivePath << std::endl; return false; } std::string file_content((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); // Compose metadata (minimal, can be extended) json metadata = { {"labeltags", json::array()} }; // Try to extract tool:arch from filename std::string filename = archivePath.substr(archivePath.find_last_of("/\\") + 1); size_t dot = filename.find('.'); std::string labeltag = dot != std::string::npos ? filename.substr(0, dot) : filename; metadata["labeltags"].push_back(labeltag); items.push_back({"file", file_content, filename, "application/gzip"}); items.push_back({"metadata", metadata.dump(), "", "application/json"}); httplib::Headers headers = { {"Authorization", "Bearer " + token} }; //cli.enable_server_certificate_verification(false); // TEMPORARY cli.set_ca_cert_path("/etc/ssl/certs/ca-certificates.crt"); auto res = cli.Put("/upload", headers, items); if (!res) { std::cerr << "[GetbinClient::upload] HTTP request failed (no response)." << std::endl; return false; } if (res->status != 200 && res->status != 201) { std::cerr << "[GetbinClient::upload] HTTP error: status code " << res->status << std::endl; std::cerr << "[GetbinClient::upload] Response body: " << res->body << std::endl; return false; } // Parse response for URL/hash try { auto resp_json = json::parse(res->body); if (resp_json.contains("url")) outUrl = resp_json["url"].get(); if (resp_json.contains("hash")) outHash = resp_json["hash"].get(); } catch (const std::exception& e) { std::cerr << "[GetbinClient::upload] Failed to parse JSON response: " << e.what() << std::endl; std::cerr << "[GetbinClient::upload] Response body: " << res->body << std::endl; return false; } catch (...) { std::cerr << "[GetbinClient::upload] Unknown error while parsing JSON response." << std::endl; std::cerr << "[GetbinClient::upload] Response body: " << res->body << std::endl; return false; } return true; } bool GetbinClient::getHash(const std::string& toolName, const std::string& arch, std::string& outHash) { httplib::SSLClient cli(SERVER_HOST, 443); std::string exists_path = "/exists/" + toolName + ":" + arch; auto res = cli.Get(exists_path.c_str()); if (!res || res->status != 200) return false; // Try to parse hash from response body (assume plain text or JSON) try { // Try JSON auto resp_json = json::parse(res->body); if (resp_json.contains("hash")) { outHash = resp_json["hash"].get(); return true; } } catch (...) { // Not JSON, treat as plain text outHash = res->body; return !outHash.empty(); } return false; }