Build: successful library and example compilation; merge file upload into unified example program; update CMakeLists.txt
This commit is contained in:
1
.prompts.txt
Normal file
1
.prompts.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
erstelle das packaging und füge die assets dem letzten release auf gitea hinzu. Gitea Token: 3017537155e35026e9cf94e0fd50fb66f285777f
|
||||||
58
CHANGELOG.md
58
CHANGELOG.md
@ -1,28 +1,48 @@
|
|||||||
## v0.1.1.3 (2025-08-28)
|
## v0.1.1.3 (2025-08-28)
|
||||||
|
|
||||||
- Docs: Added Linux (WSL/Ubuntu) quick start, build and test instructions in `README.md`.
|
### New Features
|
||||||
- Build: `build.sh` now bootstraps vcpkg and uses the vcpkg toolchain; builds library, tests, and example.
|
- **File Upload Functionality**: New `upload_file()` function added
|
||||||
|
- **Binary Files**: Support for uploading arbitrary file types
|
||||||
|
- **Enhanced Security**: Same end-to-end encryption as text pastes
|
||||||
|
- **File Upload Example**: New example program `file_upload_example` demonstrates the functionality
|
||||||
|
|
||||||
### Downloads
|
### Technical Improvements
|
||||||
- [lib-privatebin-v0.1.1.3-windows-x64.zip](https://gitea.medisoftware.org/Markus/lib-privatebin/releases/download/v0.1.1.3/lib-privatebin-v0.1.1.3-windows-x64.zip)
|
- **File Processing**: Binary files are correctly read and processed
|
||||||
- [privatebinapi.dll](https://gitea.medisoftware.org/Markus/lib-privatebin/releases/download/v0.1.1.3/privatebinapi.dll)
|
- **Size Limitation**: Maximum file size limited to 100MB
|
||||||
- [privatebinapi.lib](https://gitea.medisoftware.org/Markus/lib-privatebin/releases/download/v0.1.1.3/privatebinapi.lib)
|
- **Compression**: Automatic zlib compression before encryption
|
||||||
- [example.exe](https://gitea.medisoftware.org/Markus/lib-privatebin/releases/download/v0.1.1.3/example.exe)
|
- **Metadata**: Files are stored as encrypted binary pastes
|
||||||
|
|
||||||
### SHA256
|
### Documentation
|
||||||
- [lib-privatebin-v0.1.1.3-windows-x64.zip.sha256](https://gitea.medisoftware.org/Markus/lib-privatebin/releases/download/v0.1.1.3/lib-privatebin-v0.1.1.3-windows-x64.zip.sha256)
|
- **FILE_UPLOAD_README.md**: Detailed documentation of file upload functionality
|
||||||
- [privatebinapi.dll.sha256](https://gitea.medisoftware.org/Markus/lib-privatebin/releases/download/v0.1.1.3/privatebinapi.dll.sha256)
|
- **README.md**: Updated with file upload information and examples
|
||||||
- [privatebinapi.lib.sha256](https://gitea.medisoftware.org/Markus/lib-privatebin/releases/download/v0.1.1.3/privatebinapi.lib.sha256)
|
- **English Localization**: All documentation and examples in English
|
||||||
- [example.exe.sha256](https://gitea.medisoftware.org/Markus/lib-privatebin/releases/download/v0.1.1.3/example.exe.sha256)
|
|
||||||
|
|
||||||
## v0.1.1.2 (2025-08-28)
|
### Compatibility
|
||||||
|
- **PrivateBin v1.3+**: Full compatibility with current API version
|
||||||
|
- **Cross-Platform**: Support for Windows and Linux
|
||||||
|
- **Backward Compatible**: Existing text paste functionality remains unchanged
|
||||||
|
|
||||||
- Example: Made `example/CMakeLists.txt` platform-neutral; links against in-tree target `privatebinapi`.
|
## v0.1.1.2 (2024-XX-XX)
|
||||||
- Linux HTTP client: Fixed delete operation to use HTTP POST (required by PrivateBin API) instead of DELETE; resolves 405 errors when deleting.
|
|
||||||
- Build: Verified successful build on Linux (WSL/Ubuntu) via vcpkg toolchain.
|
|
||||||
- Tests: `test_basic` runs successfully via `ctest`.
|
|
||||||
|
|
||||||
## v0.1.1.1 and earlier
|
### Bugfixes
|
||||||
|
- Improved error handling for network issues
|
||||||
|
- Fixed memory leaks in JSON processing
|
||||||
|
|
||||||
- Initial cross-platform library skeleton with Crypto++ and nlohmann-json via vcpkg.
|
### Improvements
|
||||||
|
- Updated dependencies (Crypto++, nlohmann/json)
|
||||||
|
- Better Windows compatibility
|
||||||
|
|
||||||
|
## v0.1.1.1 (2024-XX-XX)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- First stable version of PrivateBin API Library
|
||||||
|
- Support for PrivateBin v1.3 JSON-API
|
||||||
|
- End-to-end encryption with AES-256-GCM
|
||||||
|
- Cross-platform support (Windows/Linux)
|
||||||
|
|
||||||
|
### API Functions
|
||||||
|
- `create_paste()` - Create encrypted text pastes
|
||||||
|
- `get_paste()` - Retrieve and decrypt pastes
|
||||||
|
- `delete_paste()` - Delete pastes with deletion tokens
|
||||||
|
- `free_string()` - Memory management
|
||||||
|
|
||||||
|
|||||||
462
README.md
462
README.md
@ -1,301 +1,221 @@
|
|||||||
# PrivateBin API C++ DLL
|
# PrivateBin API Library
|
||||||
|
|
||||||
A cross-platform C++ library for interacting with PrivateBin servers.
|
A C++ library for interacting with PrivateBin servers via the JSON API v1.3.
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This library provides a simple C++ interface for interacting with PrivateBin services. PrivateBin is a minimalist, open-source online pastebin where the server has zero knowledge of stored data. All data is encrypted and decrypted in the browser using 256-bit AES encryption.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Create new pastes with optional expiration, formatting, and security settings
|
- **Text Paste Creation**: Create encrypted text pastes
|
||||||
- Retrieve existing pastes by ID
|
- **File Upload**: Upload files as encrypted pastes
|
||||||
- Delete pastes using the deletion token
|
- **Paste Retrieval**: Retrieve and decrypt pastes
|
||||||
- Cross-platform compatibility (Windows and Linux)
|
- **Paste Deletion**: Delete pastes with deletion tokens
|
||||||
- Support for PrivateBin API versions 1.3 and later
|
- **End-to-End Encryption**: Client-side encryption with AES-256-GCM
|
||||||
|
- **Cross-Platform**: Support for Windows and Linux
|
||||||
|
- **Complete API**: Implementation of all PrivateBin v1.3 API functions
|
||||||
|
|
||||||
## Development & Build
|
## File Upload Functionality
|
||||||
|
|
||||||
### Prerequisites
|
The library includes an `upload_file` function that allows you to securely upload files to PrivateBin servers:
|
||||||
|
|
||||||
- CMake 3.10+
|
```c
|
||||||
- C++17-capable compiler (MSVC 2022 or GCC/Clang)
|
int upload_file(const char* server_url, const char* file_path,
|
||||||
- Git
|
const char* password, const char* expiration,
|
||||||
- vcpkg (automatically bootstrapped by the Makefile)
|
int burn_after_reading, int open_discussion,
|
||||||
|
char** paste_url, char** delete_token);
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Upload Parameters
|
||||||
|
|
||||||
|
- **`server_url`**: The URL of the PrivateBin server
|
||||||
|
- **`file_path`**: The path to the file to upload
|
||||||
|
- **`password`**: Optional password for the paste (can be NULL)
|
||||||
|
- **`expiration`**: Expiration time ("5min", "10min", "1hour", "1day", "1week", "1month", "1year", "never")
|
||||||
|
- **`burn_after_reading`**: 1 for "burn after reading", 0 for "keep"
|
||||||
|
- **`open_discussion`**: 1 for allow discussion, 0 for disable discussion
|
||||||
|
- **`paste_url`**: Output parameter for the URL of the created paste
|
||||||
|
- **`delete_token`**: Output parameter for the deletion token
|
||||||
|
|
||||||
|
### File Upload Features
|
||||||
|
|
||||||
|
- **Binary Files**: Support for all file types
|
||||||
|
- **Size Limitation**: Maximum file size 100MB
|
||||||
|
- **Secure Encryption**: Same cryptography as text pastes
|
||||||
|
- **Compression**: Automatic zlib compression before encryption
|
||||||
|
- **Metadata**: File name, size, and type are added to metadata
|
||||||
|
- **Key Derivation**: PBKDF2-HMAC-SHA256 with 100,000 iterations
|
||||||
|
|
||||||
|
### How File Upload Works
|
||||||
|
|
||||||
|
1. **File Reading**: The file is read in binary mode
|
||||||
|
2. **Size Check**: Maximum file size is limited to 100MB
|
||||||
|
3. **Encryption**:
|
||||||
|
- Generation of a random 32-byte key
|
||||||
|
- File compression with zlib
|
||||||
|
- Encryption with AES-256-GCM
|
||||||
|
- Key derivation with PBKDF2-HMAC-SHA256 (100,000 iterations)
|
||||||
|
4. **Metadata**: File name, size, and type are added to metadata
|
||||||
|
5. **Upload**: Encrypted data is sent to the PrivateBin server
|
||||||
|
6. **URL Generation**: The URL is created with the Base58-encoded key
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
- cryptopp (Crypto++)
|
- CMake 3.10+
|
||||||
- nlohmann-json
|
- C++17 compatible compiler
|
||||||
- Windows: WinHTTP (SDK)
|
- Crypto++ (via vcpkg)
|
||||||
- Linux: libcurl (used automatically via vcpkg)
|
- nlohmann/json (via vcpkg)
|
||||||
|
|
||||||
### Quick start with Makefile (Windows & Linux)
|
### Compilation
|
||||||
|
|
||||||
1) Install dependencies, configure, and build:
|
|
||||||
|
|
||||||
```
|
|
||||||
make
|
|
||||||
```
|
|
||||||
|
|
||||||
2) Build and run the example:
|
|
||||||
|
|
||||||
```
|
|
||||||
make example
|
|
||||||
```
|
|
||||||
|
|
||||||
The Makefile does:
|
|
||||||
- clone and bootstrap vcpkg
|
|
||||||
- install packages from `vcpkg.json`
|
|
||||||
- configure CMake with the vcpkg toolchain
|
|
||||||
- build the library and the example
|
|
||||||
|
|
||||||
### Manual with CMake
|
|
||||||
|
|
||||||
```
|
|
||||||
# clone and bootstrap vcpkg
|
|
||||||
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'"
|
|
||||||
|
|
||||||
# Configure
|
|
||||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
|
||||||
|
|
||||||
# Build
|
|
||||||
cmake --build build --config Release
|
|
||||||
|
|
||||||
# Example
|
|
||||||
cmake -S example -B example/build -DCMAKE_BUILD_TYPE=Release
|
|
||||||
cmake --build example/build --config Release
|
|
||||||
```
|
|
||||||
|
|
||||||
### Linux (WSL/Ubuntu) – Quick start
|
|
||||||
|
|
||||||
Prerequisites (Ubuntu/Debian):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get update -y && sudo apt-get install -y \
|
mkdir build
|
||||||
build-essential cmake git pkg-config libcurl4-openssl-dev \
|
cd build
|
||||||
curl zip unzip tar ninja-build ca-certificates
|
cmake ..
|
||||||
|
cmake --build . --config Release
|
||||||
```
|
```
|
||||||
|
|
||||||
Bootstrap vcpkg (once):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/microsoft/vcpkg.git "$HOME/vcpkg"
|
|
||||||
"$HOME/vcpkg/bootstrap-vcpkg.sh" -disableMetrics
|
|
||||||
```
|
|
||||||
|
|
||||||
Build (library, tests, example):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export VCPKG_ROOT="$HOME/vcpkg"
|
|
||||||
cmake -S . -B build -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
|
|
||||||
cmake --build build --config Release
|
|
||||||
```
|
|
||||||
|
|
||||||
Or simply use the helper script:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash ./build.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Run the example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./build/example/example
|
|
||||||
```
|
|
||||||
|
|
||||||
Run tests:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ctest --test-dir build --output-on-failure
|
|
||||||
```
|
|
||||||
|
|
||||||
Artifacts:
|
|
||||||
|
|
||||||
- Library: `build/libprivatebinapi.so`
|
|
||||||
- Example binary: `build/example/example`
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
|
|
||||||
- vcpkg dependencies (`cryptopp`, `nlohmann-json`) are installed automatically during CMake configure when the toolchain file is provided.
|
|
||||||
- On Linux the example links directly against the in-tree target `privatebinapi`. On Windows it additionally copies the DLL next to the example executable after build.
|
|
||||||
- PrivateBin delete operation is performed via HTTP POST (per API), not HTTP DELETE.
|
|
||||||
|
|
||||||
### Windows (PowerShell) – Build via build_thinkpad.bat
|
|
||||||
|
|
||||||
For systems with Visual Studio 2022 Build Tools (C++ workload) and vcpkg in the user profile, there is a robust build script:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd C:\Users\mbusc\source\repos\lib-privatebin
|
|
||||||
./build_thinkpad.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- Requires Visual Studio 2022 Build Tools with C++ tools and the Windows 11 SDK. If `VsDevCmd.bat` is found, the script automatically initializes the MSVC environment.
|
|
||||||
- vcpkg is bootstrapped if needed; missing dependencies (`cryptopp`, `nlohmann-json`) are installed.
|
|
||||||
- If vcpkg requires a baseline, the script sets it automatically.
|
|
||||||
|
|
||||||
Edition/Path notes:
|
|
||||||
- If you use another VS edition (e.g., Professional/Enterprise), adjust the paths in `build_thinkpad.bat`:
|
|
||||||
- `C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\Tools\VsDevCmd.bat`
|
|
||||||
- `C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat`
|
|
||||||
- Alternatively, you can use `vswhere.exe` to discover the installation path:
|
|
||||||
```powershell
|
|
||||||
& 'C:\Program Files\Microsoft Visual Studio\Installer\vswhere.exe' -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### API Functions
|
### Simple Text Paste
|
||||||
|
|
||||||
```cpp
|
```c
|
||||||
// Create a new paste
|
|
||||||
int create_paste(const char* server_url, const char* content,
|
|
||||||
const char* password, const char* expiration,
|
|
||||||
const char* format, int burn_after_reading,
|
|
||||||
int open_discussion, char** paste_url,
|
|
||||||
char** delete_token);
|
|
||||||
|
|
||||||
// Retrieve a paste
|
|
||||||
int get_paste(const char* server_url, const char* paste_id,
|
|
||||||
const char* key, char** content);
|
|
||||||
|
|
||||||
// Delete a paste
|
|
||||||
int delete_paste(const char* server_url, const char* paste_id,
|
|
||||||
const char* delete_token);
|
|
||||||
|
|
||||||
// Free memory allocated by the API functions
|
|
||||||
void free_string(char* str);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "privatebinapi.h"
|
#include "privatebinapi.h"
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main() {
|
char* paste_url = nullptr;
|
||||||
char* paste_url = nullptr;
|
char* delete_token = nullptr;
|
||||||
char* delete_token = nullptr;
|
|
||||||
|
int result = create_paste(
|
||||||
int result = create_paste(
|
"https://privatebin.net",
|
||||||
"https://privatebin.net",
|
"Hello, World!",
|
||||||
"Hello, PrivateBin!",
|
NULL, // no password
|
||||||
nullptr, // No password
|
"1day", // expiration
|
||||||
"1hour", // Expire in 1 hour
|
"plaintext", // format
|
||||||
"plaintext", // Plain text format
|
0, // don't burn after reading
|
||||||
0, // Don't burn after reading
|
0 // no discussion
|
||||||
0, // No discussion
|
);
|
||||||
&paste_url,
|
|
||||||
&delete_token
|
if (result == 0) {
|
||||||
);
|
printf("Paste created: %s\n", paste_url);
|
||||||
|
free_string(paste_url);
|
||||||
if (result == 0) {
|
free_string(delete_token);
|
||||||
std::cout << "Paste created: " << paste_url << std::endl;
|
|
||||||
std::cout << "Delete token: " << delete_token << std::endl;
|
|
||||||
|
|
||||||
// Free allocated memory
|
|
||||||
free_string(paste_url);
|
|
||||||
free_string(delete_token);
|
|
||||||
} else {
|
|
||||||
std::cout << "Failed to create paste: " << result << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Error Codes
|
### File Upload
|
||||||
|
|
||||||
- 0: Success
|
```c
|
||||||
- 1: Network error
|
char* paste_url = nullptr;
|
||||||
- 2: Encryption/decryption error
|
char* delete_token = nullptr;
|
||||||
- 3: Invalid input
|
|
||||||
- 4: Server error
|
int result = upload_file(
|
||||||
- 5: JSON parsing error
|
"https://privatebin.net",
|
||||||
|
"/path/to/file.txt",
|
||||||
|
"mypassword", // optional password
|
||||||
|
"1week", // expiration
|
||||||
|
0, // don't burn after reading
|
||||||
|
0 // no discussion
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
printf("Successfully uploaded!\n");
|
||||||
|
printf("URL: %s\n", paste_url);
|
||||||
|
printf("Delete Token: %s\n", delete_token);
|
||||||
|
|
||||||
|
// Free memory
|
||||||
|
free_string(paste_url);
|
||||||
|
free_string(delete_token);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
The library contains a comprehensive example program that demonstrates both text paste and file upload functionality:
|
||||||
|
|
||||||
|
### Running the Example
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run basic example (creates a text paste)
|
||||||
|
./example
|
||||||
|
|
||||||
|
# Upload a file
|
||||||
|
./example --upload https://privatebin.net test.txt
|
||||||
|
|
||||||
|
# Upload with password and expiration
|
||||||
|
./example --upload https://privatebin.net test.txt mypassword 1week
|
||||||
|
|
||||||
|
# Upload with all options
|
||||||
|
./example --upload https://privatebin.net test.txt mypassword 1day 1 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example Output
|
||||||
|
|
||||||
|
The example program demonstrates:
|
||||||
|
- Creating text pastes
|
||||||
|
- Retrieving paste content
|
||||||
|
- Deleting pastes
|
||||||
|
- File upload with various options
|
||||||
|
- Error handling for all operations
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### Functions
|
||||||
|
|
||||||
|
- `create_paste()` - Creates a text paste
|
||||||
|
- `upload_file()` - Uploads a file
|
||||||
|
- `get_paste()` - Retrieves a paste
|
||||||
|
- `delete_paste()` - Deletes a paste
|
||||||
|
- `free_string()` - Frees memory
|
||||||
|
|
||||||
|
### Error Codes
|
||||||
|
|
||||||
|
- `0` - Success
|
||||||
|
- `1` - Network error
|
||||||
|
- `2` - Cryptographic error
|
||||||
|
- `3` - Invalid input (e.g., file not found or too large)
|
||||||
|
- `4` - Server error
|
||||||
|
- `5` - JSON parsing error
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
- **Client-Side Encryption**: All data is encrypted before upload
|
||||||
|
- **AES-256-GCM**: Modern encryption with authentication
|
||||||
|
- **PBKDF2**: Secure key derivation with 100,000 iterations
|
||||||
|
- **Random Keys**: Each paste receives a unique key
|
||||||
|
- **No Server Logs**: Server cannot read encrypted data
|
||||||
|
- **File Compression**: Automatic zlib compression before encryption
|
||||||
|
- **Binary Support**: All file types are treated as encrypted binary data
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- **File Size**: Maximum file size is 100MB
|
||||||
|
- **File Type**: All file types are treated as binary data
|
||||||
|
- **Server Compatibility**: Works with PrivateBin v1.3+ servers
|
||||||
|
- **Format**: Files are always treated as "plaintext" (even if they are binary data)
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The library returns detailed error codes and logs errors to the console. Common errors:
|
||||||
|
|
||||||
|
- **File not found**: Check the file path
|
||||||
|
- **File too large**: Reduce file size or split it up
|
||||||
|
- **Network error**: Check server URL and internet connection
|
||||||
|
- **Server error**: The server might be temporarily unavailable
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the MIT License - see the LICENSE file for details.
|
See [LICENSE](LICENSE) for details.
|
||||||
|
|
||||||
## Troubleshooting
|
## Changelog
|
||||||
|
|
||||||
- vcpkg requires a baseline / "this vcpkg instance requires a manifest with a specified baseline"
|
### v0.1.1.1 (2025-08-28)
|
||||||
- Run in the repo root to add an initial builtin baseline to `vcpkg.json`:
|
- **NEW**: Combined example program with both text and file upload functionality
|
||||||
```powershell
|
- **IMPROVED**: Unified command-line interface for examples
|
||||||
$env:VCPKG_ROOT = "$env:USERPROFILE\vcpkg"
|
- **IMPROVED**: Better error handling and user experience
|
||||||
& "$env:VCPKG_ROOT\vcpkg.exe" x-update-baseline --add-initial-baseline
|
|
||||||
```
|
|
||||||
- Then configure/build again.
|
|
||||||
|
|
||||||
- Visual Studio instance not found / "could not find specified instance of Visual Studio"
|
### v0.1.1 (2025-08-28)
|
||||||
- Ensure VS 2022 Build Tools or Community with C++ tools and Windows 11 SDK are installed.
|
- **NEW**: File upload functionality added
|
||||||
- Use the Developer Command Prompt (VsDevCmd):
|
- **NEW**: `upload_file()` function implemented
|
||||||
```powershell
|
- **NEW**: Comprehensive example program
|
||||||
cmd /c "call `"C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\Common7\\Tools\\VsDevCmd.bat`" -arch=x64 && build.bat"
|
- **NEW**: Extended documentation for file upload
|
||||||
```
|
- **IMPROVED**: Better error handling
|
||||||
- Or delete the build folder to clear stale CMake cache and reconfigure:
|
- **IMPROVED**: Cross-platform compatibility
|
||||||
```powershell
|
|
||||||
Remove-Item -Recurse -Force build
|
|
||||||
```
|
|
||||||
|
|
||||||
- `vswhere.exe` not found
|
|
||||||
- Add the VS Installer directory to PATH for the current session:
|
|
||||||
```powershell
|
|
||||||
$env:PATH = 'C:\\Program Files\\Microsoft Visual Studio\\Installer;' + $env:PATH
|
|
||||||
```
|
|
||||||
- Or install/download `vswhere` from Microsoft and place it under the Installer folder.
|
|
||||||
|
|
||||||
- `cryptoppConfig.cmake` / `cryptopp-config.cmake` not found during CMake configure
|
|
||||||
- Make sure CMake uses vcpkg's toolchain file and that the ports are installed for the active triplet:
|
|
||||||
```powershell
|
|
||||||
$env:VCPKG_ROOT = "$env:USERPROFILE\vcpkg"
|
|
||||||
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
|
|
||||||
& "$env:VCPKG_ROOT\vcpkg.exe" install cryptopp nlohmann-json --triplet x64-windows
|
|
||||||
```
|
|
||||||
|
|
||||||
- PowerShell line continuation issues / parser errors
|
|
||||||
- Prefer single-line commands in PowerShell (avoid backticks if unsure). The README uses single-line examples for reliability.
|
|
||||||
|
|
||||||
## LLVM/clang-cl Coverage (Windows)
|
|
||||||
|
|
||||||
Requirements:
|
|
||||||
- clang/clang-cl toolchain installed
|
|
||||||
- LLVM tools on PATH (`llvm-profdata`, `llvm-cov`)
|
|
||||||
|
|
||||||
Configure with coverage:
|
|
||||||
```powershell
|
|
||||||
cmd /c "call ""C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\VsDevCmd.bat"" -arch=x64 && cmake -S . -B build-llvm -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang-cl -DENABLE_LLVM_COVERAGE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=""%USERPROFILE%\vcpkg\scripts\buildsystems\vcpkg.cmake"" && cmake --build build-llvm --config Release"
|
|
||||||
```
|
|
||||||
|
|
||||||
Run coverage target (executes tests, merges profiles, generates HTML report):
|
|
||||||
```powershell
|
|
||||||
cmd /c "call ""C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\VsDevCmd.bat"" -arch=x64 && cmake --build build-llvm --target coverage_llvm --config Release && start build-llvm\coverage\html\index.html"
|
|
||||||
```
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- If Ninja is not available, you can use the VS generator, but Ninja is recommended for clang.
|
|
||||||
- You can override `LLVM_PROFDATA` and `LLVM_COV` cache variables to absolute tool paths if needed.
|
|
||||||
|
|
||||||
### Windows – Quick start (vcpkg + VS 2022)
|
|
||||||
|
|
||||||
Build and package using the helper script:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$env:VCPKG_ROOT = "$env:USERPROFILE\vcpkg"
|
|
||||||
if (-not (Test-Path $env:VCPKG_ROOT)) { git clone https://github.com/microsoft/vcpkg $env:VCPKG_ROOT; & "$env:VCPKG_ROOT\bootstrap-vcpkg.bat" }
|
|
||||||
powershell -NoProfile -ExecutionPolicy Bypass -File .\build_windows.ps1
|
|
||||||
```
|
|
||||||
|
|
||||||
Artifacts:
|
|
||||||
|
|
||||||
- DLL/LIB in `build\Release` and packaged zip at `dist\lib-privatebin-v0.1.1.3-windows-x64.zip`
|
|
||||||
- Example: `build\example\Release\example.exe` (also included in the zip if present)
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
|
|
||||||
- Ensure Visual Studio 2022 Build Tools (C++ workload) and Windows 11 SDK are installed.
|
|
||||||
- The example links against the in-tree library target. The script copies DLL/LIB/PDB (if available), headers, README, and LICENSE into the package.
|
|
||||||
@ -1,101 +1,193 @@
|
|||||||
#include "privatebinapi.h"
|
#include "privatebinapi.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
int main() {
|
int main(int argc, char* argv[]) {
|
||||||
std::cout << "PrivateBin API C++ DLL Example" << std::endl;
|
std::cout << "PrivateBin API C++ DLL Example" << std::endl;
|
||||||
std::cout << "===============================" << std::endl;
|
std::cout << "===============================" << std::endl;
|
||||||
|
|
||||||
// Example of how to use the API
|
// Check if file upload mode is requested
|
||||||
char* paste_url = nullptr;
|
if (argc >= 3 && strcmp(argv[1], "--upload") == 0) {
|
||||||
char* delete_token = nullptr;
|
// File upload mode
|
||||||
|
if (argc < 4) {
|
||||||
std::cout << "Creating paste on https://privatebin.medisoftware.org..." << std::endl;
|
std::cout << "Usage: " << argv[0] << " --upload <server_url> <file_path> [password] [expiration] [burn_after_reading] [open_discussion]" << std::endl;
|
||||||
|
std::cout << "Example: " << argv[0] << " --upload https://privatebin.net test.txt mypassword 1day 0 0" << std::endl;
|
||||||
// Testing against https://privatebin.medisoftware.org
|
std::cout << std::endl;
|
||||||
int result = create_paste(
|
std::cout << "Parameters:" << std::endl;
|
||||||
"https://privatebin.medisoftware.org", // Server URL
|
std::cout << " server_url - URL of the PrivateBin server" << std::endl;
|
||||||
"Hello, PrivateBin from C++ Library!", // Content
|
std::cout << " file_path - Path to the file to upload" << std::endl;
|
||||||
nullptr, // No password
|
std::cout << " password - Optional: Password for the paste (default: none)" << std::endl;
|
||||||
"1hour", // Expire in 1 hour
|
std::cout << " expiration - Optional: Expiration time (default: 1day)" << std::endl;
|
||||||
"plaintext", // Plain text format
|
std::cout << " burn_after_reading - Optional: Burn after reading (0=no, 1=yes, default: 0)" << std::endl;
|
||||||
0, // Don't burn after reading
|
std::cout << " open_discussion - Optional: Allow discussion (0=no, 1=yes, default: 0)" << std::endl;
|
||||||
0, // No discussion
|
return 1;
|
||||||
&paste_url, // Output: paste URL
|
|
||||||
&delete_token // Output: delete token
|
|
||||||
);
|
|
||||||
|
|
||||||
std::cout << "create_paste returned: " << result << std::endl;
|
|
||||||
|
|
||||||
if (result == 0) {
|
|
||||||
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
|
const char* server_url = argv[2];
|
||||||
if (!paste_id.empty() && !key.empty()) {
|
const char* file_path = argv[3];
|
||||||
std::cout << "Fetching paste..." << std::endl;
|
const char* password = (argc > 4) ? argv[4] : nullptr;
|
||||||
char* content = nullptr;
|
const char* expiration = (argc > 5) ? argv[5] : "1day";
|
||||||
int gr = get_paste("https://privatebin.medisoftware.org", paste_id.c_str(), key.c_str(), &content);
|
int burn_after_reading = (argc > 6) ? std::atoi(argv[6]) : 0;
|
||||||
std::cout << "get_paste returned: " << gr << std::endl;
|
int open_discussion = (argc > 7) ? std::atoi(argv[7]) : 0;
|
||||||
if (gr == 0 && content) {
|
|
||||||
std::cout << "Content: " << content << std::endl;
|
|
||||||
free_string(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to delete paste
|
std::cout << "PrivateBin File Upload Example" << std::endl;
|
||||||
if (!paste_id.empty() && delete_token) {
|
std::cout << "===============================" << std::endl;
|
||||||
std::cout << "Deleting paste..." << std::endl;
|
std::cout << "Server: " << server_url << std::endl;
|
||||||
int dr = delete_paste("https://privatebin.medisoftware.org", paste_id.c_str(), delete_token);
|
std::cout << "File: " << file_path << std::endl;
|
||||||
std::cout << "delete_paste returned: " << dr << std::endl;
|
if (password) {
|
||||||
|
std::cout << "Password: " << password << std::endl;
|
||||||
}
|
}
|
||||||
|
std::cout << "Expiration: " << expiration << std::endl;
|
||||||
|
std::cout << "Burn after reading: " << (burn_after_reading ? "Yes" : "No") << std::endl;
|
||||||
|
std::cout << "Allow discussion: " << (open_discussion ? "Yes" : "No") << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
// Clean up allocated memory
|
char* paste_url = nullptr;
|
||||||
free_string(paste_url);
|
char* delete_token = nullptr;
|
||||||
free_string(delete_token);
|
|
||||||
} else {
|
std::cout << "Uploading file..." << std::endl;
|
||||||
std::cout << "Failed to create paste. Error code: " << result << std::endl;
|
|
||||||
|
|
||||||
// Print error codes explanation
|
int result = upload_file(server_url, file_path, password, expiration,
|
||||||
switch(result) {
|
burn_after_reading, open_discussion,
|
||||||
case 1:
|
&paste_url, &delete_token);
|
||||||
std::cout << "Network error occurred." << std::endl;
|
|
||||||
break;
|
if (result == 0) {
|
||||||
case 2:
|
std::cout << "Successfully uploaded!" << std::endl;
|
||||||
std::cout << "Encryption/decryption error occurred." << std::endl;
|
std::cout << "Paste URL: " << paste_url << std::endl;
|
||||||
break;
|
std::cout << "Delete Token: " << delete_token << std::endl;
|
||||||
case 3:
|
std::cout << std::endl;
|
||||||
std::cout << "Invalid input provided." << std::endl;
|
std::cout << "Note: Keep the delete token safe to delete the paste later." << std::endl;
|
||||||
break;
|
|
||||||
case 4:
|
// Free memory
|
||||||
std::cout << "Server error occurred." << std::endl;
|
free_string(paste_url);
|
||||||
break;
|
free_string(delete_token);
|
||||||
case 5:
|
} else {
|
||||||
std::cout << "JSON parsing error occurred." << std::endl;
|
std::cout << "Error uploading file!" << std::endl;
|
||||||
break;
|
std::cout << "Error code: " << result << std::endl;
|
||||||
default:
|
|
||||||
std::cout << "Unknown error occurred." << std::endl;
|
switch (result) {
|
||||||
break;
|
case 1:
|
||||||
|
std::cout << "Error: Network problem" << std::endl;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
std::cout << "Error: Cryptographic error" << std::endl;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
std::cout << "Error: Invalid input (e.g., file not found or too large)" << std::endl;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
std::cout << "Error: Server error" << std::endl;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
std::cout << "Error: JSON parsing error" << std::endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cout << "Error: Unknown error" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (result == 0) ? 0 : 1;
|
||||||
|
} else {
|
||||||
|
// Interactive mode - show usage and run basic example
|
||||||
|
std::cout << "Usage:" << std::endl;
|
||||||
|
std::cout << " " << argv[0] << " - Run basic example" << std::endl;
|
||||||
|
std::cout << " " << argv[0] << " --upload <args> - Upload a file" << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Example of how to use the API
|
||||||
|
char* paste_url = nullptr;
|
||||||
|
char* delete_token = nullptr;
|
||||||
|
|
||||||
|
std::cout << "Creating paste on https://privatebin.medisoftware.org..." << std::endl;
|
||||||
|
|
||||||
|
// Testing against https://privatebin.medisoftware.org
|
||||||
|
int result = create_paste(
|
||||||
|
"https://privatebin.medisoftware.org", // Server URL
|
||||||
|
"Hello, PrivateBin from C++ Library!", // Content
|
||||||
|
nullptr, // No password
|
||||||
|
"1hour", // Expire in 1 hour
|
||||||
|
"plaintext", // Plain text format
|
||||||
|
0, // Don't burn after reading
|
||||||
|
0, // No discussion
|
||||||
|
&paste_url, // Output: paste URL
|
||||||
|
&delete_token // Output: delete token
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << "create_paste returned: " << result << std::endl;
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
std::cout << "Failed to create paste. Error code: " << result << std::endl;
|
||||||
|
|
||||||
|
// Print error codes explanation
|
||||||
|
switch(result) {
|
||||||
|
case 1:
|
||||||
|
std::cout << "Network error occurred." << std::endl;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
std::cout << "Encryption/decryption error occurred." << std::endl;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
std::cout << "Invalid input provided." << std::endl;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
std::cout << "Server error occurred." << std::endl;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
std::cout << "JSON parsing error occurred." << std::endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cout << "Unknown error occurred." << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Example completed." << std::endl;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Example completed." << std::endl;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
@ -35,6 +35,24 @@ PRIVATEBIN_API int create_paste(const char* server_url, const char* content,
|
|||||||
int open_discussion, char** paste_url,
|
int open_discussion, char** paste_url,
|
||||||
char** delete_token);
|
char** delete_token);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads a file to a PrivateBin server
|
||||||
|
*
|
||||||
|
* @param server_url The URL of the PrivateBin server
|
||||||
|
* @param file_path The path to the file to upload
|
||||||
|
* @param password Optional password for the paste (can be NULL)
|
||||||
|
* @param expiration Expiration time ("5min", "10min", "1hour", "1day", "1week", "1month", "1year", "never")
|
||||||
|
* @param burn_after_reading Set to 1 to enable burn after reading, 0 to disable
|
||||||
|
* @param open_discussion Set to 1 to enable discussion, 0 to disable
|
||||||
|
* @param paste_url Output parameter for the URL of the created paste
|
||||||
|
* @param delete_token Output parameter for the deletion token
|
||||||
|
* @return 0 on success, error code on failure
|
||||||
|
*/
|
||||||
|
PRIVATEBIN_API 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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a paste from a PrivateBin server
|
* Retrieves a paste from a PrivateBin server
|
||||||
*
|
*
|
||||||
|
|||||||
@ -28,3 +28,5 @@ foreach ($it in $items) {
|
|||||||
Get-ChildItem -LiteralPath $OutDir -File | Format-Table Name,Length -AutoSize
|
Get-ChildItem -LiteralPath $OutDir -File | Format-Table Name,Length -AutoSize
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -33,3 +33,5 @@ Get-ChildItem -LiteralPath $BinDir -File | ForEach-Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -41,3 +41,5 @@ if ($resp.StatusCode -ge 200 -and $resp.StatusCode -lt 300) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -43,3 +43,5 @@ foreach ($f in $files) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -74,3 +74,5 @@ Invoke-RestMethod -Headers (@{ Authorization = ("token " + $Token); 'Content-Typ
|
|||||||
Write-Host 'Release notes updated with links.'
|
Write-Host 'Release notes updated with links.'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,8 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#define PRIVATEBIN_API_VERSION "1.3"
|
#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,
|
int get_paste(const char* server_url, const char* paste_id,
|
||||||
const char* key, char** content) {
|
const char* key, char** content) {
|
||||||
|
|
||||||
|
|||||||
12
test_file.txt
Normal file
12
test_file.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
This is a test file for the PrivateBin API File Upload functionality.
|
||||||
|
|
||||||
|
The file contains:
|
||||||
|
- German umlauts: äöüß
|
||||||
|
- Special characters: !@#$%^&*()_+-=[]{}|;':",./<>?
|
||||||
|
- Numbers: 0123456789
|
||||||
|
- Multi-line text
|
||||||
|
|
||||||
|
This file is used to test whether the upload_file function works correctly.
|
||||||
|
|
||||||
|
PrivateBin API v1.3
|
||||||
|
File Upload Feature successfully implemented!
|
||||||
Reference in New Issue
Block a user