Build: successful library and example compilation; merge file upload into unified example program; update CMakeLists.txt
This commit is contained in:
@ -8,6 +8,8 @@
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#define PRIVATEBIN_API_VERSION "1.3"
|
||||
|
||||
@ -126,6 +128,126 @@ int create_paste(const char* server_url, const char* content,
|
||||
}
|
||||
}
|
||||
|
||||
int upload_file(const char* server_url, const char* file_path,
|
||||
const char* password, const char* expiration,
|
||||
int burn_after_reading, int open_discussion,
|
||||
char** paste_url, char** delete_token) {
|
||||
|
||||
if (!server_url || !file_path) {
|
||||
return ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
try {
|
||||
// Read the file content
|
||||
std::ifstream file(file_path, std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "[privatebinapi] Failed to open file: " << file_path << std::endl;
|
||||
return ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Get file size
|
||||
file.seekg(0, std::ios::end);
|
||||
std::streamsize file_size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
// Check if file is too large (PrivateBin typically has limits)
|
||||
if (file_size > 100 * 1024 * 1024) { // 100MB limit
|
||||
std::cerr << "[privatebinapi] File too large: " << file_size << " bytes" << std::endl;
|
||||
return ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Read file content into vector
|
||||
std::vector<unsigned char> file_content(file_size);
|
||||
if (!file.read(reinterpret_cast<char*>(file_content.data()), file_size)) {
|
||||
std::cerr << "[privatebinapi] Failed to read file content" << std::endl;
|
||||
return ERROR_INVALID_INPUT;
|
||||
}
|
||||
file.close();
|
||||
|
||||
// Generate a random 32-byte paste key
|
||||
std::vector<unsigned char> paste_key = Crypto::generate_key(32);
|
||||
|
||||
// If password provided, append it to the paste key
|
||||
std::string paste_passphrase(reinterpret_cast<char*>(paste_key.data()), paste_key.size());
|
||||
if (password) {
|
||||
paste_passphrase += password;
|
||||
}
|
||||
|
||||
// Compress the file content
|
||||
std::cerr << "[privatebinapi] compress file..." << std::endl;
|
||||
std::vector<unsigned char> compressed_data = Crypto::compress(file_content);
|
||||
|
||||
// Generate random salt and IV
|
||||
std::vector<unsigned char> salt = Crypto::generate_key(8);
|
||||
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 file..." << std::endl;
|
||||
std::vector<unsigned char> auth_tag;
|
||||
std::vector<unsigned char> cipher_text = Crypto::encrypt(
|
||||
compressed_data, derived_key, iv, auth_tag);
|
||||
|
||||
// Create the JSON structure for file upload
|
||||
json paste_json = JsonParser::create_paste_json(
|
||||
cipher_text, auth_tag, iv, salt,
|
||||
expiration ? expiration : "1day",
|
||||
"plaintext", // Files are treated as plaintext
|
||||
burn_after_reading != 0,
|
||||
open_discussion != 0);
|
||||
|
||||
// Note: File metadata is not added to avoid server compatibility issues
|
||||
// The file content is encrypted and uploaded as a binary paste
|
||||
|
||||
// Serialize JSON
|
||||
std::string json_data = paste_json.dump();
|
||||
|
||||
// Send POST request
|
||||
HttpClient client;
|
||||
std::string response;
|
||||
if (!client.post(server_url, json_data, response)) {
|
||||
return ERROR_NETWORK;
|
||||
}
|
||||
|
||||
// Parse response
|
||||
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;
|
||||
}
|
||||
|
||||
// Encode the paste key with Base58
|
||||
std::string encoded_key = Base58::encode(paste_key);
|
||||
|
||||
// Construct the full URL
|
||||
std::string full_url = url + "#" + encoded_key;
|
||||
|
||||
// Copy results to output parameters
|
||||
copy_string_to_output(full_url, paste_url);
|
||||
copy_string_to_output(del_token, delete_token);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[privatebinapi] file upload error: " << e.what() << std::endl;
|
||||
return ERROR_CRYPTO;
|
||||
} catch (...) {
|
||||
std::cerr << "[privatebinapi] unknown file upload error" << std::endl;
|
||||
return ERROR_CRYPTO;
|
||||
}
|
||||
}
|
||||
|
||||
int get_paste(const char* server_url, const char* paste_id,
|
||||
const char* key, char** content) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user