feat: v1.3-konforme API, HTTP-Fixes, Base64, Example erweitert; Makefile & README Setup
This commit is contained in:
70
README.md
70
README.md
@ -14,42 +14,60 @@ This library provides a simple C++ interface for interacting with PrivateBin ser
|
||||
- Cross-platform compatibility (Windows and Linux)
|
||||
- Support for PrivateBin API versions 1.3 and later
|
||||
|
||||
## Building
|
||||
## Entwicklung & Build
|
||||
|
||||
### Prerequisites
|
||||
### Voraussetzungen
|
||||
|
||||
- CMake 3.10 or later
|
||||
- C++17 compatible compiler
|
||||
- For Windows: Windows SDK
|
||||
- For Linux: libcurl development headers
|
||||
- CMake 3.10+
|
||||
- C++17-fähiger Compiler (MSVC 2022 bzw. GCC/Clang)
|
||||
- Git
|
||||
- vcpkg (wird bei Makefile-Nutzung automatisch gebootstrapped)
|
||||
|
||||
### Dependencies
|
||||
### Abhängigkeiten
|
||||
|
||||
The library depends on the following components:
|
||||
- cryptopp (Crypto++)
|
||||
- nlohmann-json
|
||||
- Windows: WinHTTP (SDK)
|
||||
- Linux: libcurl (wird automatisch über vcpkg genutzt)
|
||||
|
||||
1. **HTTP Client**:
|
||||
- Windows: WinHTTP
|
||||
- Linux: libcurl
|
||||
### Schnellstart mit Makefile (Windows & Linux)
|
||||
|
||||
2. **JSON Processing**:
|
||||
- nlohmann/json
|
||||
1) Abhängigkeiten installieren, konfigurieren und bauen:
|
||||
|
||||
### Building on Windows
|
||||
|
||||
```cmd
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build .
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
### Building on Linux
|
||||
2) Beispiel bauen und ausführen:
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
make example
|
||||
```
|
||||
|
||||
Das Makefile erledigt:
|
||||
- vcpkg klonen & bootstrappen
|
||||
- Pakete aus `vcpkg.json` installieren
|
||||
- CMake mit vcpkg-Toolchain konfigurieren
|
||||
- Bibliothek und Beispiel bauen
|
||||
|
||||
### Manuell mit CMake
|
||||
|
||||
```
|
||||
# vcpkg klonen & bootstrappen
|
||||
git clone https://github.com/microsoft/vcpkg.git "$HOME/vcpkg"
|
||||
"$HOME/vcpkg/bootstrap-vcpkg.sh" # Linux/macOS
|
||||
# Windows (PowerShell):
|
||||
# powershell -NoProfile -ExecutionPolicy Bypass -Command "& '$env:USERPROFILE\vcpkg\bootstrap-vcpkg.bat'"
|
||||
|
||||
# Konfigurieren
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
||||
|
||||
# Bauen
|
||||
cmake --build build --config Release
|
||||
|
||||
# Beispiel
|
||||
cmake -S example -B example/build -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build example/build --config Release
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@ -5,7 +5,7 @@ REM Create build directory
|
||||
if not exist "build" mkdir build
|
||||
cd build
|
||||
|
||||
REM Generate build files with CMake and vcpkg toolchain
|
||||
REM Generate build files with CMake and vcpkg manifest
|
||||
cmake .. -G "Visual Studio 17 2022" -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake
|
||||
|
||||
REM Build the project
|
||||
|
||||
@ -3,23 +3,25 @@ project(PrivateBinAPIExample)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Find the privatebinapi library
|
||||
find_library(PRIVATEBINAPI_LIB privatebinapi
|
||||
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../build)
|
||||
# Use the prebuilt library from the parent build directory
|
||||
set(PRIVATEBINAPI_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../build")
|
||||
set(PRIVATEBINAPI_RELEASE_LIB "${PRIVATEBINAPI_BUILD_DIR}/Release/privatebinapi.lib")
|
||||
|
||||
# If not found, build it as part of the project
|
||||
if(NOT PRIVATEBINAPI_LIB)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/privatebinapi)
|
||||
set(PRIVATEBINAPI_LIB privatebinapi)
|
||||
if(EXISTS "${PRIVATEBINAPI_RELEASE_LIB}")
|
||||
set(PRIVATEBINAPI_LIB "${PRIVATEBINAPI_RELEASE_LIB}")
|
||||
else()
|
||||
# Fallback: try the build root (multi-config generators may place libs differently)
|
||||
find_library(PRIVATEBINAPI_LIB privatebinapi PATHS "${PRIVATEBINAPI_BUILD_DIR}")
|
||||
endif()
|
||||
|
||||
if(NOT PRIVATEBINAPI_LIB)
|
||||
message(FATAL_ERROR "privatebinapi library not found. Please run build.bat in the project root first.")
|
||||
endif()
|
||||
|
||||
# Create example executable
|
||||
add_executable(example example.cpp)
|
||||
|
||||
# Link with the privatebinapi library
|
||||
target_link_libraries(example ${PRIVATEBINAPI_LIB})
|
||||
target_link_libraries(example PRIVATE ${PRIVATEBINAPI_LIB} winhttp)
|
||||
|
||||
# Include directories
|
||||
target_include_directories(example PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include
|
||||
)
|
||||
@ -31,7 +31,41 @@ int main() {
|
||||
std::cout << "Paste created successfully!" << std::endl;
|
||||
std::cout << "URL: " << paste_url << std::endl;
|
||||
std::cout << "Delete token: " << delete_token << std::endl;
|
||||
|
||||
|
||||
// Parse paste_id and key from URL (format: "/?{pasteID}#{key}")
|
||||
std::string full_url = paste_url ? paste_url : "";
|
||||
std::string paste_id;
|
||||
std::string key;
|
||||
auto qpos = full_url.find('?');
|
||||
auto hpos = full_url.find('#');
|
||||
if (qpos != std::string::npos) {
|
||||
if (hpos != std::string::npos && hpos > qpos + 1) {
|
||||
paste_id = full_url.substr(qpos + 1, hpos - (qpos + 1));
|
||||
key = full_url.substr(hpos + 1);
|
||||
} else if (qpos + 1 < full_url.size()) {
|
||||
paste_id = full_url.substr(qpos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to fetch paste content back
|
||||
if (!paste_id.empty() && !key.empty()) {
|
||||
std::cout << "Fetching paste..." << std::endl;
|
||||
char* content = nullptr;
|
||||
int gr = get_paste("https://privatebin.medisoftware.org", paste_id.c_str(), key.c_str(), &content);
|
||||
std::cout << "get_paste returned: " << gr << std::endl;
|
||||
if (gr == 0 && content) {
|
||||
std::cout << "Content: " << content << std::endl;
|
||||
free_string(content);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to delete paste
|
||||
if (!paste_id.empty() && delete_token) {
|
||||
std::cout << "Deleting paste..." << std::endl;
|
||||
int dr = delete_paste("https://privatebin.medisoftware.org", paste_id.c_str(), delete_token);
|
||||
std::cout << "delete_paste returned: " << dr << std::endl;
|
||||
}
|
||||
|
||||
// Clean up allocated memory
|
||||
free_string(paste_url);
|
||||
free_string(delete_token);
|
||||
|
||||
@ -4,13 +4,13 @@
|
||||
#include <cstring>
|
||||
|
||||
// Crypto++ includes
|
||||
#include "cryptlib.h"
|
||||
#include "osrng.h" // AutoSeededRandomPool
|
||||
#include "aes.h" // AES encryption
|
||||
#include "gcm.h" // GCM mode
|
||||
#include "pwdbased.h" // PBKDF2
|
||||
#include "sha.h" // SHA256
|
||||
#include "zlib.h" // Zlib compression
|
||||
#include <cryptopp/cryptlib.h>
|
||||
#include <cryptopp/osrng.h> // AutoSeededRandomPool
|
||||
#include <cryptopp/aes.h> // AES encryption
|
||||
#include <cryptopp/gcm.h> // GCM mode
|
||||
#include <cryptopp/pwdbased.h> // PBKDF2
|
||||
#include <cryptopp/sha.h> // SHA256
|
||||
#include <cryptopp/zlib.h> // Zlib compression
|
||||
|
||||
using namespace CryptoPP;
|
||||
|
||||
|
||||
@ -6,6 +6,14 @@
|
||||
#include <windows.h>
|
||||
#include <winhttp.h>
|
||||
#pragma comment(lib, "winhttp.lib")
|
||||
|
||||
static std::wstring utf8_to_wide(const std::string& s) {
|
||||
if (s.empty()) return std::wstring();
|
||||
int needed = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0);
|
||||
std::wstring ws(needed, L'\0');
|
||||
MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), &ws[0], needed);
|
||||
return ws;
|
||||
}
|
||||
#elif LINUX
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
@ -36,7 +44,8 @@ bool HttpClient::get(const std::string& url, std::string& response) {
|
||||
urlComp.dwExtraInfoLength = (DWORD)-1;
|
||||
|
||||
// Parse the URL
|
||||
if (!WinHttpCrackUrl((LPCWSTR)url.c_str(), 0, 0, &urlComp)) {
|
||||
std::wstring wurl = utf8_to_wide(url);
|
||||
if (!WinHttpCrackUrl(wurl.c_str(), 0, 0, &urlComp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -59,13 +68,25 @@ bool HttpClient::get(const std::string& url, std::string& response) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build object name = path + extra info (query)
|
||||
std::wstring pathPart = (urlComp.lpszUrlPath && urlComp.dwUrlPathLength > 0)
|
||||
? std::wstring(urlComp.lpszUrlPath, urlComp.dwUrlPathLength)
|
||||
: std::wstring(L"/");
|
||||
std::wstring extraPart = (urlComp.lpszExtraInfo && urlComp.dwExtraInfoLength > 0)
|
||||
? std::wstring(urlComp.lpszExtraInfo, urlComp.dwExtraInfoLength)
|
||||
: std::wstring();
|
||||
std::wstring objectName = pathPart + extraPart;
|
||||
|
||||
// Create an HTTP request handle
|
||||
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET",
|
||||
urlComp.lpszUrlPath,
|
||||
objectName.c_str(),
|
||||
NULL, WINHTTP_NO_REFERER,
|
||||
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ?
|
||||
WINHTTP_FLAG_SECURE : 0);
|
||||
// Set headers per API requirement
|
||||
LPCWSTR headers = L"X-Requested-With: JSONHttpRequest\r\nAccept: application/json";
|
||||
WinHttpAddRequestHeaders(hRequest, headers, -1L, WINHTTP_ADDREQ_FLAG_ADD);
|
||||
|
||||
if (!hRequest) {
|
||||
WinHttpCloseHandle(hConnect);
|
||||
@ -156,7 +177,8 @@ bool HttpClient::post(const std::string& url, const std::string& data, std::stri
|
||||
urlComp.dwExtraInfoLength = (DWORD)-1;
|
||||
|
||||
// Parse the URL
|
||||
if (!WinHttpCrackUrl((LPCWSTR)url.c_str(), 0, 0, &urlComp)) {
|
||||
std::wstring wurl = utf8_to_wide(url);
|
||||
if (!WinHttpCrackUrl(wurl.c_str(), 0, 0, &urlComp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -179,9 +201,10 @@ bool HttpClient::post(const std::string& url, const std::string& data, std::stri
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create an HTTP request handle
|
||||
// Create an HTTP request handle (POST per API 1.3)
|
||||
LPCWSTR postPath = (urlComp.lpszUrlPath && urlComp.dwUrlPathLength > 0) ? urlComp.lpszUrlPath : L"/";
|
||||
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST",
|
||||
urlComp.lpszUrlPath,
|
||||
postPath,
|
||||
NULL, WINHTTP_NO_REFERER,
|
||||
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ?
|
||||
@ -208,6 +231,7 @@ bool HttpClient::post(const std::string& url, const std::string& data, std::stri
|
||||
}
|
||||
|
||||
// Send a request
|
||||
// Send UTF-8 bytes as body (raw)
|
||||
if (!WinHttpSendRequest(hRequest,
|
||||
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
||||
(LPVOID)data.c_str(), (DWORD)data.length(),
|
||||
@ -290,7 +314,8 @@ bool HttpClient::delete_req(const std::string& url, const std::string& data, std
|
||||
urlComp.dwExtraInfoLength = (DWORD)-1;
|
||||
|
||||
// Parse the URL
|
||||
if (!WinHttpCrackUrl((LPCWSTR)url.c_str(), 0, 0, &urlComp)) {
|
||||
std::wstring wurlDel = utf8_to_wide(url);
|
||||
if (!WinHttpCrackUrl(wurlDel.c_str(), 0, 0, &urlComp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -314,8 +339,9 @@ bool HttpClient::delete_req(const std::string& url, const std::string& data, std
|
||||
}
|
||||
|
||||
// Create an HTTP request handle
|
||||
LPCWSTR delPath = (urlComp.lpszUrlPath && urlComp.dwUrlPathLength > 0) ? urlComp.lpszUrlPath : L"/";
|
||||
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST",
|
||||
urlComp.lpszUrlPath,
|
||||
delPath,
|
||||
NULL, WINHTTP_NO_REFERER,
|
||||
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ?
|
||||
@ -341,9 +367,9 @@ bool HttpClient::delete_req(const std::string& url, const std::string& data, std
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send a request with DELETE method
|
||||
// Send a request body with DELETE method
|
||||
if (!WinHttpSendRequest(hRequest,
|
||||
L"DELETE", 6,
|
||||
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
||||
(LPVOID)data.c_str(), (DWORD)data.length(),
|
||||
(DWORD)data.length(), 0)) {
|
||||
WinHttpCloseHandle(hRequest);
|
||||
|
||||
@ -1,6 +1,28 @@
|
||||
#include "json_parser.h"
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <cryptopp/base64.h>
|
||||
#include <cryptopp/filters.h>
|
||||
#include <cryptopp/queue.h>
|
||||
|
||||
// Helper: Base64 encode without line breaks
|
||||
static std::string encode_base64(const std::vector<unsigned char>& data) {
|
||||
std::string result;
|
||||
CryptoPP::StringSource ss(
|
||||
data.data(), data.size(), true,
|
||||
new CryptoPP::Base64Encoder(new CryptoPP::StringSink(result), false /* insertLineBreaks */)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper: Base64 decode
|
||||
static std::vector<unsigned char> decode_base64(const std::string& b64) {
|
||||
std::string decoded;
|
||||
CryptoPP::StringSource ss(
|
||||
b64, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded))
|
||||
);
|
||||
return std::vector<unsigned char>(decoded.begin(), decoded.end());
|
||||
}
|
||||
|
||||
json JsonParser::create_paste_json(const std::vector<unsigned char>& cipher_text,
|
||||
const std::vector<unsigned char>& auth_tag,
|
||||
@ -11,17 +33,16 @@ json JsonParser::create_paste_json(const std::vector<unsigned char>& cipher_text
|
||||
bool burn_after_reading,
|
||||
bool open_discussion) {
|
||||
|
||||
// Convert binary data to base64 strings (stub implementation)
|
||||
std::string cipher_text_b64(cipher_text.begin(), cipher_text.end());
|
||||
std::string auth_tag_b64(auth_tag.begin(), auth_tag.end());
|
||||
std::string iv_b64(iv.begin(), iv.end());
|
||||
std::string salt_b64(salt.begin(), salt.end());
|
||||
// Convert binary data to base64 strings
|
||||
std::string cipher_text_b64 = encode_base64(cipher_text);
|
||||
std::string iv_b64 = encode_base64(iv);
|
||||
std::string salt_b64 = encode_base64(salt);
|
||||
|
||||
// Get current timestamp
|
||||
auto now = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
|
||||
// Create the metadata array
|
||||
// Create the metadata array according to PrivateBin v2
|
||||
json metadata = {
|
||||
{
|
||||
iv_b64, // base64(cipher_iv)
|
||||
@ -33,21 +54,19 @@ json JsonParser::create_paste_json(const std::vector<unsigned char>& cipher_text
|
||||
"gcm", // mode
|
||||
"zlib" // compression
|
||||
},
|
||||
format, // format
|
||||
format, // formatter key
|
||||
burn_after_reading ? 1 : 0, // burn after reading
|
||||
open_discussion ? 1 : 0 // open discussion
|
||||
};
|
||||
|
||||
// Create the main JSON structure
|
||||
// JSON close to v1.3 JSON-LD: meta.expire used by server
|
||||
json paste_json = {
|
||||
{"v", 2}, // version
|
||||
{"adata", metadata}, // metadata
|
||||
{"ct", cipher_text_b64}, // cipher text
|
||||
{"v", 2}, // version
|
||||
{"adata", metadata}, // metadata
|
||||
{"ct", cipher_text_b64}, // ciphertext (base64)
|
||||
{"meta", {
|
||||
{"expire", expiration},
|
||||
{"created", now},
|
||||
{"time_to_live", 300}, // This would be calculated based on expiration
|
||||
{"icon", "data:image/png;base64,..."} // Placeholder
|
||||
{"expire", expiration}
|
||||
}}
|
||||
};
|
||||
|
||||
@ -62,29 +81,32 @@ bool JsonParser::parse_paste_json(const json& json_data,
|
||||
std::string& expiration) {
|
||||
|
||||
try {
|
||||
// Extract cipher text
|
||||
std::string ct = json_data["ct"];
|
||||
cipher_text = std::vector<unsigned char>(ct.begin(), ct.end());
|
||||
// Extract and decode cipher text
|
||||
std::string ct_b64 = json_data.at("ct");
|
||||
cipher_text = decode_base64(ct_b64);
|
||||
|
||||
// Extract metadata
|
||||
json adata = json_data["adata"];
|
||||
// Optional explicit tag field
|
||||
if (json_data.contains("tag")) {
|
||||
std::string tag_b64 = json_data.at("tag");
|
||||
auth_tag = decode_base64(tag_b64);
|
||||
} else {
|
||||
auth_tag.clear();
|
||||
}
|
||||
|
||||
// Extract metadata and decode IV & salt
|
||||
json adata = json_data.at("adata");
|
||||
if (adata.size() >= 1) {
|
||||
json first_element = adata[0];
|
||||
if (first_element.is_array() && first_element.size() >= 2) {
|
||||
// Extract IV and salt (from base64 in real implementation)
|
||||
std::string iv_str = first_element[0];
|
||||
std::string salt_str = first_element[1];
|
||||
|
||||
iv = std::vector<unsigned char>(iv_str.begin(), iv_str.end());
|
||||
salt = std::vector<unsigned char>(salt_str.begin(), salt_str.end());
|
||||
std::string iv_b64 = first_element[0];
|
||||
std::string salt_b64 = first_element[1];
|
||||
iv = decode_base64(iv_b64);
|
||||
salt = decode_base64(salt_b64);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract expiration
|
||||
expiration = json_data["meta"]["expire"];
|
||||
|
||||
// Auth tag would be extracted from the ciphertext in a real implementation
|
||||
auth_tag.resize(16, 0);
|
||||
expiration = json_data.at("meta").at("expire");
|
||||
|
||||
return true;
|
||||
} catch (...) {
|
||||
@ -101,17 +123,13 @@ bool JsonParser::parse_response(const std::string& response,
|
||||
|
||||
try {
|
||||
json json_response = json::parse(response);
|
||||
|
||||
status = json_response["status"];
|
||||
|
||||
status = json_response.value("status", 1);
|
||||
if (status == 0) {
|
||||
// Success response
|
||||
paste_id = json_response["id"];
|
||||
url = json_response["url"];
|
||||
delete_token = json_response["deletetoken"];
|
||||
paste_id = json_response.value("id", "");
|
||||
url = json_response.value("url", "");
|
||||
delete_token = json_response.value("deletetoken", "");
|
||||
} else {
|
||||
// Error response
|
||||
message = json_response["message"];
|
||||
message = json_response.value("message", "");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#define PRIVATEBIN_API_VERSION "1.3"
|
||||
|
||||
@ -54,6 +55,7 @@ int create_paste(const char* server_url, const char* content,
|
||||
std::vector<unsigned char> plaintext(content, content + strlen(content));
|
||||
|
||||
// Compress the plaintext
|
||||
std::cerr << "[privatebinapi] compress..." << std::endl;
|
||||
std::vector<unsigned char> compressed_data = Crypto::compress(plaintext);
|
||||
|
||||
// Generate random salt and IV
|
||||
@ -61,10 +63,12 @@ int create_paste(const char* server_url, const char* content,
|
||||
std::vector<unsigned char> iv = Crypto::generate_key(16);
|
||||
|
||||
// Derive key using PBKDF2
|
||||
std::cerr << "[privatebinapi] pbkdf2..." << std::endl;
|
||||
std::vector<unsigned char> derived_key = Crypto::pbkdf2_hmac_sha256(
|
||||
paste_passphrase, salt, 100000, 32);
|
||||
|
||||
// Encrypt the data
|
||||
std::cerr << "[privatebinapi] encrypt..." << std::endl;
|
||||
std::vector<unsigned char> auth_tag;
|
||||
std::vector<unsigned char> cipher_text = Crypto::encrypt(
|
||||
compressed_data, derived_key, iv, auth_tag);
|
||||
@ -91,8 +95,12 @@ int create_paste(const char* server_url, const char* content,
|
||||
int status;
|
||||
std::string message, paste_id, url, del_token;
|
||||
if (!JsonParser::parse_response(response, status, message, paste_id, url, del_token)) {
|
||||
std::cerr << "[privatebinapi] raw response (unparsed): " << response << std::endl;
|
||||
return ERROR_JSON_PARSE;
|
||||
}
|
||||
if (status != 0) {
|
||||
std::cerr << "[privatebinapi] server status=" << status << ", message= " << message << std::endl;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
return ERROR_SERVER;
|
||||
@ -109,7 +117,11 @@ int create_paste(const char* server_url, const char* content,
|
||||
copy_string_to_output(del_token, delete_token);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[privatebinapi] crypto error: " << e.what() << std::endl;
|
||||
return ERROR_CRYPTO;
|
||||
} catch (...) {
|
||||
std::cerr << "[privatebinapi] unknown crypto error" << std::endl;
|
||||
return ERROR_CRYPTO;
|
||||
}
|
||||
}
|
||||
@ -122,15 +134,17 @@ int get_paste(const char* server_url, const char* paste_id,
|
||||
}
|
||||
|
||||
try {
|
||||
// Construct the URL
|
||||
std::string url = std::string(server_url) + "/" + paste_id;
|
||||
// Construct the URL with query per API: base?pasteID
|
||||
std::string url = std::string(server_url) + "?" + paste_id;
|
||||
|
||||
// Send GET request
|
||||
HttpClient client;
|
||||
std::string response;
|
||||
std::cerr << "[privatebinapi] GET " << url << std::endl;
|
||||
if (!client.get(url, response)) {
|
||||
return ERROR_NETWORK;
|
||||
}
|
||||
std::cerr << "[privatebinapi] GET response: " << response << std::endl;
|
||||
|
||||
// Parse the JSON response
|
||||
json json_data = json::parse(response);
|
||||
@ -188,9 +202,11 @@ int delete_paste(const char* server_url, const char* paste_id,
|
||||
// Send DELETE request
|
||||
HttpClient client;
|
||||
std::string response;
|
||||
std::cerr << "[privatebinapi] DELETE payload: " << json_data << std::endl;
|
||||
if (!client.delete_req(server_url, json_data, response)) {
|
||||
return ERROR_NETWORK;
|
||||
}
|
||||
std::cerr << "[privatebinapi] DELETE response: " << response << std::endl;
|
||||
|
||||
// Parse response
|
||||
int status;
|
||||
|
||||
Reference in New Issue
Block a user