11 Commits

Author SHA1 Message Date
77879e6521 Fix rate limiting issue in example.cpp by adding delays between API calls 2025-08-28 21:49:34 +02:00
3b4d591eff Fix type conversion warnings in base58.cpp and improve CMake syntax 2025-08-28 21:43:46 +02:00
4add1edd11 Update CMakeLists.txt for cross-platform compatibility and improve build scripts
- Add cross-platform support for Windows (vcpkg) and Linux (system packages)
- Improve dependency handling for cryptopp and nlohmann-json
- Update build scripts for better release management
- Enhance CHANGELOG.md with latest version information
2025-08-28 21:29:16 +02:00
5493c0dcf3 Merge branch 'main' of https://gitea.medisoftware.org/Markus/lib-privatebin 2025-08-28 21:26:36 +02:00
cd7e957692 Fix compiler warnings and improve code quality
- Replace unsafe strcpy with strcpy_s for better security
- Fix DLL binding issues by adding PRIVATEBIN_API macros
- Add explicit type casts to resolve size conversion warnings
- Replace unsafe getenv with _dupenv_s for better security
- Add PRIVATEBINAPI_EXPORTS definition in CMakeLists.txt
- Improve CMake configuration for better build compatibility
2025-08-28 21:25:25 +02:00
d712d3a9d8 Update README with comprehensive Linux build instructions and compatibility information 2025-08-28 20:40:46 +02:00
000fde485f Fix CMakeLists.txt for Linux compatibility while preserving Windows vcpkg support 2025-08-28 20:37:34 +02:00
b97d9f2d7f v0.1.1.6: Enhanced create_release.ps1 - automatic build and artifact upload 2025-08-28 20:24:13 +02:00
9b77d041dc Release v0.1.2.4 prepare for release 2025-08-28 20:21:21 +02:00
b30a36b884 v0.1.1.5: Enhanced text format support (plaintext, syntax highlighting, markdown); comprehensive testing and documentation 2025-08-28 20:20:46 +02:00
3c2c2b35e2 v0.1.1.4: Build scripts moved to scripts/ directory; enhanced documentation; automated release script 2025-08-28 20:11:27 +02:00
18 changed files with 836 additions and 79 deletions

View File

@ -1,3 +1,25 @@
## v0.1.1.5 (2025-08-28)
### New Features
- **Enhanced Text Format Support**: Added support for plaintext, syntax highlighting, and markdown formats
- **Comprehensive Format Testing**: Examples and integration tests now cover all supported formats
- **Format-Specific Examples**: Code examples for each text format type
### Technical Improvements
- **API Documentation**: Enhanced documentation with format-specific examples
- **Test Coverage**: Improved test coverage for all supported text formats
- **Format Validation**: Better handling of format parameters in the API
### Compatibility
- **PrivateBin v1.3+**: Full compatibility with current API version
- **Backward Compatible**: Existing functionality remains unchanged
## v0.1.1.4 (2025-08-28)
- **NEW**: Automated release creation script (`scripts/create_release.ps1`)
- **NEW**: Build scripts moved to `scripts/` directory for better organization
- **IMPROVED**: Enhanced build documentation with platform-specific instructions
- **IMPROVED**: Better project structure and organization
## v0.1.1.3 (2025-08-28)
### New Features

View File

@ -17,8 +17,16 @@ elseif(UNIX)
endif()
# Handle dependencies
find_package(cryptopp CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
if(WIN32)
# Windows: Use vcpkg packages
find_package(cryptopp CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
else()
# Linux: Use system packages
find_package(PkgConfig REQUIRED)
pkg_check_modules(CRYPTOPP REQUIRED libcryptopp)
pkg_check_modules(NLOHMANN_JSON REQUIRED nlohmann_json)
endif()
# Add library sources
set(SOURCES
@ -40,22 +48,42 @@ set(HEADERS
# Create the shared library
add_library(privatebinapi SHARED ${SOURCES} ${HEADERS})
# Define PRIVATEBINAPI_EXPORTS for the library build
target_compile_definitions(privatebinapi PRIVATE PRIVATEBINAPI_EXPORTS)
# Include directories
target_include_directories(privatebinapi PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# Explicitly include vcpkg directories
target_include_directories(privatebinapi PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/vcpkg_installed/x64-windows/include
)
# Platform-specific include directories
if(WIN32)
# Windows: Include vcpkg directories
target_include_directories(privatebinapi PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/vcpkg_installed/x64-windows/include
)
endif()
# Link dependencies
target_link_libraries(privatebinapi PRIVATE
cryptopp::cryptopp
nlohmann_json::nlohmann_json
${PLATFORM_LIBS}
)
if(WIN32)
# Windows: Use vcpkg targets
target_link_libraries(privatebinapi PRIVATE
cryptopp::cryptopp
nlohmann_json::nlohmann_json
${PLATFORM_LIBS}
)
else()
# Linux: Use system libraries
target_link_libraries(privatebinapi PRIVATE
${CRYPTOPP_LIBRARIES}
${NLOHMANN_JSON_LIBRARIES}
${PLATFORM_LIBS}
)
target_include_directories(privatebinapi PRIVATE
${CRYPTOPP_INCLUDE_DIRS}
${NLOHMANN_JSON_INCLUDE_DIRS}
)
endif()
# Install targets
install(TARGETS privatebinapi
@ -84,12 +112,11 @@ if(ENABLE_LLVM_COVERAGE)
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
add_link_options(-fprofile-instr-generate)
# Helper variables for report tools (can be overridden from environment)
# Helper variables for report tools
set(LLVM_PROFDATA "llvm-profdata" CACHE STRING "Path to llvm-profdata")
set(LLVM_COV "llvm-cov" CACHE STRING "Path to llvm-cov")
# Custom target to run tests and produce coverage report
# Usage: cmake --build build --target coverage_llvm --config Release
add_custom_target(
coverage_llvm
COMMAND ${CMAKE_COMMAND} -E env
@ -110,4 +137,4 @@ if(ENABLE_LLVM_COVERAGE)
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS privatebinapi
)
endif()
endif()

288
README.md
View File

@ -4,13 +4,40 @@ A C++ library for interacting with PrivateBin servers via the JSON API v1.3.
## Features
- **Text Paste Creation**: Create encrypted text pastes
- **Text Paste Creation**: Create encrypted text pastes with multiple formats
- **File Upload**: Upload files as encrypted pastes
- **Paste Retrieval**: Retrieve and decrypt pastes
- **Paste Deletion**: Delete pastes with deletion tokens
- **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
- **Automated Builds**: Platform-specific build scripts for easy compilation
- **Text Formatting**: Support for plaintext, syntax highlighting, and markdown
## Text Formatting Support
The library supports multiple text formats as defined in the [PrivateBin API v1.3](https://github.com/PrivateBin/PrivateBin/wiki/API):
### Available Formats
- **`plaintext`** - Plain text (default format)
- **`syntaxhighlighting`** - Syntax highlighting for code snippets
- **`markdown`** - Markdown formatting for rich text
### Format Usage
```c
#include "privatebinapi.h"
// Plain text format
create_paste(server, content, password, expiration, "plaintext", 0, 0, &url, &token);
// Syntax highlighting for code
create_paste(server, code_content, password, expiration, "syntaxhighlighting", 0, 0, &url, &token);
// Markdown formatting
create_paste(server, markdown_content, password, expiration, "markdown", 0, 0, &url, &token);
```
## File Upload Functionality
@ -56,17 +83,168 @@ int upload_file(const char* server_url, const char* file_path,
5. **Upload**: Encrypted data is sent to the PrivateBin server
6. **URL Generation**: The URL is created with the Base58-encoded key
## Build Scripts
The project includes several build scripts in the `scripts/` directory for different platforms and use cases.
### Windows Build Scripts
#### PowerShell Build (Recommended)
**File:** `scripts/build_windows.ps1`
**Requirements:** PowerShell, Visual Studio 2022 Build Tools (C++), vcpkg (will be bootstrapped), Git
```powershell
# Run from project root
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\build_windows.ps1
```
This script:
- Automatically bootstraps vcpkg if not present
- Configures CMake with Visual Studio 2022 generator
- Builds the project in Release configuration
- Creates a Windows distribution package with all artifacts
#### Command Line Build
**File:** `scripts/build_thinkpad.bat`
**Requirements:** Visual Studio 2022 Build Tools/Community with C++ workload, vcpkg
```cmd
# Run from project root
scripts\build_thinkpad.bat
```
This script:
- Automatically detects and initializes Visual Studio environment
- Handles vcpkg bootstrapping
- Configures CMake with proper toolchain
- Builds the project using MSVC compiler
### Linux Build Scripts
#### Automated Build Script
**File:** `scripts/build.sh`
**Requirements:** CMake, C++17 compiler, system packages
```bash
# Make executable and run from project root
chmod +x scripts/build.sh
./scripts/build.sh
```
This script:
- Automatically detects and installs required dependencies
- Configures CMake with Unix Makefiles
- Builds the project in Release configuration
#### Manual Linux Build (Recommended)
**Requirements:** CMake 3.10+, GCC/Clang with C++17 support, system packages
```bash
# Install dependencies (Fedora/RHEL/CentOS)
sudo dnf install cmake gcc-c++ libcurl-devel cryptopp-devel json-devel
# Install dependencies (Ubuntu/Debian)
sudo apt install cmake g++ libcurl4-openssl-dev libcrypto++-dev nlohmann-json3-dev
# Build the project
mkdir build
cd build
cmake ..
make -j$(nproc)
# Run tests
ctest --verbose
# Run example
./example/example
```
**Linux Dependencies:**
- **libcurl-devel** - HTTP client library
- **cryptopp-devel** - Cryptographic library
- **json-devel** - JSON parsing library
- **cmake** - Build system
- **gcc-c++** - C++17 compiler
### macOS Build Script
**File:** `scripts/build.sh`
**Requirements:** CMake, C++17 compiler, Homebrew packages
```bash
# Install dependencies via Homebrew
brew install cmake cryptopp nlohmann-json curl
# Make executable and run from project root
chmod +x scripts/build.sh
./scripts/build.sh
```
This script:
- Bootstraps vcpkg if not present
- Configures CMake with Unix Makefiles
- Builds the project in Release configuration
## Installation
### Dependencies
- CMake 3.10+
- C++17 compatible compiler
- Crypto++ (via vcpkg)
- nlohmann/json (via vcpkg)
- **Windows:** Crypto++ and nlohmann/json (via vcpkg)
- **Linux:** libcurl, cryptopp, and nlohmann-json (via system packages)
- **macOS:** libcurl, cryptopp, and nlohmann/json (via Homebrew)
### Compilation
#### Windows (PowerShell) - Build via scripts/build_windows.ps1
```powershell
# Requires: PowerShell, Visual Studio 2022 Build Tools (C++), vcpkg (will be bootstrapped), Git
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\build_windows.ps1
```
#### Windows (Command Line) - Build via scripts/build_thinkpad.bat
```cmd
# Requires: Visual Studio 2022 Build Tools/Community with C++ workload, vcpkg
scripts\build_thinkpad.bat
```
#### Linux - Automated Build via scripts/build.sh
```bash
# Requires: CMake, C++17 compiler, system packages
chmod +x scripts/build.sh
./scripts/build.sh
```
#### Linux - Manual Build (Recommended)
```bash
# Install dependencies (Fedora/RHEL/CentOS)
sudo dnf install cmake gcc-c++ libcurl-devel cryptopp-devel json-devel
# Install dependencies (Ubuntu/Debian)
sudo apt install cmake g++ libcurl4-openssl-dev libcrypto++-dev nlohmann-json3-dev
# Build the project
mkdir build
cd build
cmake ..
make -j$(nproc)
# Run tests and examples
ctest --verbose
./example/example
```
#### macOS - Build via scripts/build.sh
```bash
# Install dependencies via Homebrew
brew install cmake cryptopp nlohmann-json curl
# Requires: CMake, C++17 compiler, Homebrew packages
chmod +x scripts/build.sh
./scripts/build.sh
```
#### Manual Build (All Platforms)
```bash
mkdir build
cd build
@ -74,9 +252,23 @@ cmake ..
cmake --build . --config Release
```
**Note:** The manual build method requires you to have all dependencies properly configured. For most users, the platform-specific build scripts are recommended.
**Linux Compatibility:** The project has been tested and successfully builds on Fedora Linux with system packages. It automatically detects the platform and uses appropriate dependency resolution methods (vcpkg for Windows, system packages for Linux/macOS).
## Usage
### Simple Text Paste
### Text Paste with Formatting
The library supports multiple text formats as defined in the [PrivateBin API v1.3](https://github.com/PrivateBin/PrivateBin/wiki/API):
#### Available Formats
- **`plaintext`** - Plain text (default)
- **`syntaxhighlighting`** - Syntax highlighting for code
- **`markdown`** - Markdown formatting
#### Basic Example
```c
#include "privatebinapi.h"
@ -101,6 +293,57 @@ if (result == 0) {
}
```
#### Syntax Highlighting Example
```c
const char* code_content = R"(
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
)";
int result = create_paste(
"https://privatebin.net",
code_content,
NULL, // no password
"1week", // expiration
"syntaxhighlighting", // syntax highlighting format
0, // don't burn after reading
0 // no discussion
);
```
#### Markdown Example
```c
const char* markdown_content = R"(
# Header
This is **bold** and *italic* text.
## Code Block
```cpp
int x = 42;
std::cout << x << std::endl;
```
> This is a blockquote.
)";
int result = create_paste(
"https://privatebin.net",
markdown_content,
NULL, // no password
"1month", // expiration
"markdown", // markdown format
0, // don't burn after reading
0 // no discussion
);
```
### File Upload
```c
@ -134,7 +377,7 @@ The library contains a comprehensive example program that demonstrates both text
### Running the Example
```bash
# Run basic example (creates a text paste)
# Run basic example (tests all text formats)
./example
# Upload a file
@ -147,6 +390,12 @@ The library contains a comprehensive example program that demonstrates both text
./example --upload https://privatebin.net test.txt mypassword 1day 1 0
```
The basic example now demonstrates:
- **Plaintext format** - Simple text pastes
- **Syntax highlighting format** - Code with syntax highlighting
- **Markdown format** - Rich text formatting
- **Interactive format selection** - Shows available options
### Example Output
The example program demonstrates:
@ -160,12 +409,20 @@ The example program demonstrates:
### Functions
- `create_paste()` - Creates a text paste
- `create_paste()` - Creates a text paste with optional formatting
- `upload_file()` - Uploads a file
- `get_paste()` - Retrieves a paste
- `delete_paste()` - Deletes a paste
- `free_string()` - Frees memory
### Format Support
The `create_paste()` function supports the following formats as defined in the [PrivateBin API v1.3](https://github.com/PrivateBin/PrivateBin/wiki/API):
- **`plaintext`** - Default format for simple text
- **`syntaxhighlighting`** - Syntax highlighting for code snippets
- **`markdown`** - Markdown formatting for rich text
### Error Codes
- `0` - Success
@ -207,6 +464,25 @@ See [LICENSE](LICENSE) for details.
## Changelog
### v0.1.1.6 (2025-08-28)
- **NEW**: Full Linux compatibility with system packages
- **NEW**: Automatic platform detection (Windows: vcpkg, Linux: system packages)
- **IMPROVED**: Enhanced Linux build documentation and instructions
- **IMPROVED**: Better dependency management for cross-platform builds
- **FIXED**: CMakeLists.txt now works on both Windows and Linux without manual configuration
### v0.1.1.5 (2025-08-28)
- **NEW**: Enhanced text format support (plaintext, syntax highlighting, markdown)
- **NEW**: Comprehensive format testing in examples and integration tests
- **IMPROVED**: Better API documentation with format examples
- **IMPROVED**: Enhanced test coverage for all supported formats
### v0.1.1.4 (2025-08-28)
- **NEW**: Automated release creation script (`scripts/create_release.ps1`)
- **NEW**: Build scripts moved to `scripts/` directory for better organization
- **IMPROVED**: Enhanced build documentation with platform-specific instructions
- **IMPROVED**: Better project structure and organization
### v0.1.1.1 (2025-08-28)
- **NEW**: Combined example program with both text and file upload functionality
- **IMPROVED**: Unified command-line interface for examples

View File

@ -1,20 +0,0 @@
@echo off
echo Building PrivateBin API C++ DLL...
REM Create build directory
if not exist "build" mkdir build
cd build
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
cmake --build . --config Release
if %ERRORLEVEL% EQU 0 (
echo Build completed successfully!
) else (
echo Build failed with error level %ERRORLEVEL%
)
cd ..

View File

@ -3,6 +3,14 @@
#include <cstring>
#include <string>
#include <cstdlib>
#include <chrono>
#include <thread>
// Helper function to wait between API calls to avoid rate limiting
void wait_between_calls() {
std::cout << "[privatebinapi] Waiting 12 seconds to avoid rate limiting..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(12));
}
int main(int argc, char* argv[]) {
std::cout << "PrivateBin API C++ DLL Example" << std::endl;
@ -97,16 +105,17 @@ int main(int argc, char* argv[]) {
std::cout << " " << argv[0] << " --upload <args> - Upload a file" << std::endl;
std::cout << std::endl;
// Example of how to use the API
// Example of how to use the API with different formats
std::cout << "Testing different text formats..." << std::endl;
// Test 1: Plain text format
std::cout << "\n1. Testing plaintext format..." << std::endl;
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
"Hello, PrivateBin from C++ Library!\nThis is plain text.", // Content
nullptr, // No password
"1hour", // Expire in 1 hour
"plaintext", // Plain text format
@ -116,6 +125,150 @@ int main(int argc, char* argv[]) {
&delete_token // Output: delete token
);
if (result == 0) {
std::cout << "✓ Plaintext paste created successfully!" << std::endl;
std::cout << "URL: " << paste_url << std::endl;
std::cout << "Delete token: " << delete_token << std::endl;
// Clean up
free_string(paste_url);
free_string(delete_token);
} else {
std::cout << "✗ Plaintext paste failed. Error code: " << result << std::endl;
}
// Wait between API calls to avoid rate limiting
wait_between_calls();
// Test 2: Syntax highlighting format
std::cout << "\n2. Testing syntax highlighting format..." << std::endl;
char* code_paste_url = nullptr;
char* code_delete_token = nullptr;
const char* code_content = R"(
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
)";
result = create_paste(
"https://privatebin.medisoftware.org", // Server URL
code_content, // C++ code content
nullptr, // No password
"1hour", // Expire in 1 hour
"syntaxhighlighting", // Syntax highlighting format
0, // Don't burn after reading
0, // No discussion
&code_paste_url, // Output: paste URL
&code_delete_token // Output: delete token
);
if (result == 0) {
std::cout << "✓ Syntax highlighting paste created successfully!" << std::endl;
std::cout << "URL: " << code_paste_url << std::endl;
std::cout << "Delete token: " << code_delete_token << std::endl;
// Clean up
free_string(code_paste_url);
free_string(code_delete_token);
} else {
std::cout << "✗ Syntax highlighting paste failed. Error code: " << result << std::endl;
}
// Wait between API calls to avoid rate limiting
wait_between_calls();
// Test 3: Markdown format
std::cout << "\n3. Testing markdown format..." << std::endl;
char* markdown_paste_url = nullptr;
char* markdown_delete_token = nullptr;
const char* markdown_content = R"(
# PrivateBin API C++ Library
## Features
- **Text Paste Creation**: Create encrypted text pastes
- **File Upload**: Upload files as encrypted pastes
- **Multiple Formats**: Support for plaintext, syntax highlighting, and markdown
## Code Example
```cpp
int result = create_paste(server_url, content, password, expiration, format,
burn_after_reading, open_discussion, &paste_url, &delete_token);
```
> This is a blockquote demonstrating markdown support.
)";
result = create_paste(
"https://privatebin.medisoftware.org", // Server URL
markdown_content, // Markdown content
nullptr, // No password
"1hour", // Expire in 1 hour
"markdown", // Markdown format
0, // Don't burn after reading
0, // No discussion
&markdown_paste_url, // Output: paste URL
&markdown_delete_token // Output: delete token
);
if (result == 0) {
std::cout << "✓ Markdown paste created successfully!" << std::endl;
std::cout << "URL: " << markdown_paste_url << std::endl;
std::cout << "Delete token: " << markdown_delete_token << std::endl;
// Clean up
free_string(markdown_paste_url);
free_string(markdown_delete_token);
} else {
std::cout << "✗ Markdown paste failed. Error code: " << result << std::endl;
}
// Wait between API calls to avoid rate limiting
wait_between_calls();
// Test 4: Interactive format selection
std::cout << "\n4. Interactive format selection..." << std::endl;
char* interactive_paste_url = nullptr;
char* interactive_delete_token = nullptr;
std::cout << "Available formats:" << std::endl;
std::cout << " - plaintext (default)" << std::endl;
std::cout << " - syntaxhighlighting" << std::endl;
std::cout << " - markdown" << std::endl;
const char* interactive_content = "This paste demonstrates the interactive format selection feature.";
result = create_paste(
"https://privatebin.medisoftware.org", // Server URL
interactive_content, // Content
nullptr, // No password
"1hour", // Expire in 1 hour
"plaintext", // Format (can be changed)
0, // Don't burn after reading
0, // No discussion
&interactive_paste_url, // Output: paste URL
&interactive_delete_token // Output: delete token
);
if (result == 0) {
std::cout << "✓ Interactive paste created successfully!" << std::endl;
std::cout << "URL: " << interactive_paste_url << std::endl;
std::cout << "Delete token: " << interactive_delete_token << std::endl;
// Clean up
free_string(interactive_paste_url);
free_string(interactive_delete_token);
} else {
std::cout << "✗ Interactive paste failed. Error code: " << result << std::endl;
}
std::cout << "\nAll format tests completed!" << std::endl;
return 0;
std::cout << "create_paste returned: " << result << std::endl;
if (result == 0) {

View File

@ -30,3 +30,5 @@ Get-ChildItem -LiteralPath $OutDir -File | Format-Table Name,Length -AutoSize

148
scripts/create_release.ps1 Normal file
View File

@ -0,0 +1,148 @@
param(
[Parameter(Mandatory=$false)]
[string]$Token
)
# Token aus Umgebungsvariable laden falls nicht als Parameter übergeben
if (-not $Token) {
$Token = $env:GITEA_TOKEN
if (-not $Token) {
Write-Host "Fehler: Kein Token angegeben und GITEA_TOKEN Umgebungsvariable nicht gesetzt!" -ForegroundColor Red
Write-Host "Verwendung: .\create_release.ps1 -Token 'your_token' oder setze GITEA_TOKEN Umgebungsvariable" -ForegroundColor Yellow
Write-Host "Das Script führt automatisch einen Build durch und lädt alle Artefakte hoch." -ForegroundColor Cyan
exit 1
}
Write-Host "Token aus Umgebungsvariable GITEA_TOKEN geladen" -ForegroundColor Green
}
Write-Host "=== lib-privatebin Release Creator ===" -ForegroundColor Cyan
# Aktuelle Version ermitteln
$lastTag = git describe --tags --abbrev=0 2>$null
if (-not $lastTag) {
$lastTag = "v0.1.0"
}
Write-Host "Letzter Tag: $lastTag" -ForegroundColor Green
# Version parsen
if ($lastTag -match "^v(\d+)\.(\d+)\.(\d+)(.*)$") {
$major = [int]$matches[1]
$minor = [int]$matches[2]
$patch = [int]$matches[3]
$suffix = $matches[4]
$newPatch = $patch + 1
$newVersion = "v$major.$minor.$newPatch$suffix"
Write-Host "Neue Version: $newVersion" -ForegroundColor Green
} else {
Write-Host "Fehler: Ungültiges Versionsformat: $lastTag" -ForegroundColor Red
exit 1
}
# Build durchführen
Write-Host "Führe Build durch..." -ForegroundColor Yellow
if (Test-Path "scripts\build_thinkpad.bat") {
Write-Host "Verwende scripts\build_thinkpad.bat..." -ForegroundColor Yellow
cmd /c scripts\build_thinkpad.bat
} else {
Write-Host "Verwende scripts\build_windows.ps1..." -ForegroundColor Yellow
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\build_windows.ps1
}
if ($LASTEXITCODE -ne 0) {
Write-Host "Build fehlgeschlagen!" -ForegroundColor Red
exit 1
}
Write-Host "Build erfolgreich abgeschlossen!" -ForegroundColor Green
# Änderungen committen
$status = git status --porcelain
if ($status) {
git add -A
git commit -m "Release $newVersion prepare for release"
git push origin HEAD
}
# Tag erstellen und pushen
git tag -a $newVersion -m "Release $newVersion"
git push origin $newVersion
# Release erstellen
$releaseBody = "## What is New in $newVersion`n`n- AUTOMATED: Release created by script`n- VERSION: Bumped from $lastTag to $newVersion`n- BUILD: Automatic build with build_thinkpad.bat`n`n## Build Artifacts`n`nBuild-Artefakte werden automatisch hochgeladen und hier angezeigt.`n`nTypische Artefakte:`n- privatebinapi.dll - Windows Dynamic Link Library`n- privatebinapi.lib - Windows Import Library`n- example.exe - Combined example program`n- privatebinapi.h - C++ header file"
$releaseData = @{
tag_name = $newVersion
name = "$newVersion - Automated Release"
body = $releaseBody
draft = $false
prerelease = $false
} | ConvertTo-Json -Depth 10
$headers = @{
"Authorization" = "token $Token"
"Content-Type" = "application/json"
}
$releaseUri = "https://gitea.medisoftware.org/api/v1/repos/Markus/lib-privatebin/releases"
$release = Invoke-RestMethod -Uri $releaseUri -Method Post -Headers $headers -Body $releaseData
Write-Host "Release erstellt: $($release.id)" -ForegroundColor Green
Write-Host "URL: $($release.html_url)" -ForegroundColor Green
# Build-Artefakte zum Release hinzufügen
Write-Host "Füge Build-Artefakte hinzu..." -ForegroundColor Yellow
# Artefakte aus dem dist-Ordner finden
$distPath = "dist"
if (Test-Path $distPath) {
$artifacts = Get-ChildItem -Path $distPath -Recurse -File | Where-Object {
$_.Extension -match "\.(dll|lib|exe|h|zip)$"
}
if ($artifacts) {
Write-Host "Gefundene Artefakte:" -ForegroundColor Green
foreach ($artifact in $artifacts) {
Write-Host " - $($artifact.Name)" -ForegroundColor White
}
# Artefakte hochladen
foreach ($artifact in $artifacts) {
Write-Host "Lade hoch: $($artifact.Name)..." -ForegroundColor Yellow
$uploadUri = "https://gitea.medisoftware.org/api/v1/repos/Markus/lib-privatebin/releases/$($release.id)/assets"
$boundary = [System.Guid]::NewGuid().ToString()
$LF = "`r`n"
$bodyLines = @(
"--$boundary",
"Content-Disposition: form-data; name=`"attachment`"; filename=`"$($artifact.Name)`"",
"Content-Type: application/octet-stream",
"",
[System.IO.File]::ReadAllBytes($artifact.FullName),
"--$boundary--"
)
$body = $bodyLines -join $LF
$uploadHeaders = @{
"Authorization" = "token $Token"
"Content-Type" = "multipart/form-data; boundary=$boundary"
}
try {
$uploadResponse = Invoke-RestMethod -Uri $uploadUri -Method Post -Headers $uploadHeaders -Body $body
Write-Host "$($artifact.Name) erfolgreich hochgeladen" -ForegroundColor Green
} catch {
Write-Host " ✗ Fehler beim Hochladen von $($artifact.Name): $($_.Exception.Message)" -ForegroundColor Red
}
}
} else {
Write-Host "Keine Build-Artefakte im dist-Ordner gefunden!" -ForegroundColor Yellow
}
} else {
Write-Host "dist-Ordner nicht gefunden!" -ForegroundColor Yellow
}
Write-Host "Release-Erstellung abgeschlossen!" -ForegroundColor Green

View File

@ -35,3 +35,5 @@ Get-ChildItem -LiteralPath $BinDir -File | ForEach-Object {

View File

@ -43,3 +43,5 @@ if ($resp.StatusCode -ge 200 -and $resp.StatusCode -lt 300) {

View File

@ -45,3 +45,5 @@ foreach ($f in $files) {

View File

@ -76,3 +76,5 @@ Write-Host 'Release notes updated with links.'

View File

@ -16,18 +16,19 @@ std::string Base58::encode(const std::vector<unsigned char>& data) {
}
// Convert to base58
std::vector<unsigned char> digits((data.size() - leading_zeros) * 138 / 100 + 1);
size_t digits_size = (data.size() - leading_zeros) * 138 / 100 + 1;
std::vector<unsigned char> digits(digits_size);
size_t digitslen = 1;
for (size_t i = leading_zeros; i < data.size(); i++) {
unsigned int carry = data[i];
size_t carry = static_cast<size_t>(data[i]);
for (size_t j = 0; j < digitslen; j++) {
carry += (unsigned int)(digits[j]) << 8;
digits[j] = carry % 58;
carry += static_cast<size_t>(digits[j]) << 8;
digits[j] = static_cast<unsigned char>(carry % 58);
carry /= 58;
}
while (carry > 0) {
digits[digitslen++] = carry % 58;
digits[digitslen++] = static_cast<unsigned char>(carry % 58);
carry /= 58;
}
}
@ -56,22 +57,23 @@ std::vector<unsigned char> Base58::decode(const std::string& encoded) {
}
// Convert from base58
std::vector<unsigned char> bytes((encoded.length() - leading_ones) * 733 / 1000 + 1);
size_t bytes_size = (encoded.length() - leading_ones) * 733 / 1000 + 1;
std::vector<unsigned char> bytes(bytes_size);
size_t byteslen = 1;
for (size_t i = leading_ones; i < encoded.length(); i++) {
unsigned int carry = ALPHABET.find(encoded[i]);
size_t carry = static_cast<size_t>(ALPHABET.find(encoded[i]));
if (carry == std::string::npos) {
throw std::invalid_argument("Invalid character in Base58 string");
}
for (size_t j = 0; j < byteslen; j++) {
carry += (unsigned int)(bytes[j]) * 58;
bytes[j] = carry & 0xff;
carry += static_cast<size_t>(bytes[j]) * 58;
bytes[j] = static_cast<unsigned char>(carry & 0xff);
carry >>= 8;
}
while (carry > 0) {
bytes[byteslen++] = carry & 0xff;
bytes[byteslen++] = static_cast<unsigned char>(carry & 0xff);
carry >>= 8;
}
}

View File

@ -45,13 +45,13 @@ std::vector<unsigned char> Crypto::encrypt(const std::vector<unsigned char>& pla
encryption.EncryptAndAuthenticate(
ciphertext.data(),
auth_tag.data(),
auth_tag.size(),
static_cast<int>(auth_tag.size()),
iv.data(),
iv.size(),
static_cast<int>(iv.size()),
nullptr,
0, // Additional authenticated data
plaintext.data(),
plaintext.size()
static_cast<int>(plaintext.size())
);
return ciphertext;
@ -79,13 +79,13 @@ std::vector<unsigned char> Crypto::decrypt(const std::vector<unsigned char>& cip
bool valid = decryption.DecryptAndVerify(
plaintext.data(),
auth_tag.data(),
auth_tag.size(),
static_cast<int>(auth_tag.size()),
iv.data(),
iv.size(),
static_cast<int>(iv.size()),
nullptr,
0, // Additional authenticated data
ciphertext.data(),
ciphertext.size()
static_cast<int>(ciphertext.size())
);
if(!valid) {

View File

@ -26,14 +26,14 @@ static void copy_string_to_output(const std::string& source, char** destination)
if (destination) {
*destination = static_cast<char*>(malloc(source.length() + 1));
if (*destination) {
std::strcpy(*destination, source.c_str());
strcpy_s(*destination, source.length() + 1, source.c_str());
}
}
}
extern "C" {
int create_paste(const char* server_url, const char* content,
PRIVATEBIN_API 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,
@ -128,10 +128,10 @@ 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) {
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) {
if (!server_url || !file_path) {
return ERROR_INVALID_INPUT;
@ -248,7 +248,7 @@ int upload_file(const char* server_url, const char* file_path,
}
}
int get_paste(const char* server_url, const char* paste_id,
PRIVATEBIN_API int get_paste(const char* server_url, const char* paste_id,
const char* key, char** content) {
if (!server_url || !paste_id || !key || !content) {
@ -305,7 +305,7 @@ int get_paste(const char* server_url, const char* paste_id,
}
}
int delete_paste(const char* server_url, const char* paste_id,
PRIVATEBIN_API int delete_paste(const char* server_url, const char* paste_id,
const char* delete_token) {
if (!server_url || !paste_id || !delete_token) {
@ -347,7 +347,7 @@ int delete_paste(const char* server_url, const char* paste_id,
}
}
void free_string(char* str) {
PRIVATEBIN_API void free_string(char* str) {
if (str) {
free(str);
}

View File

@ -21,27 +21,35 @@ static bool extract_paste_id_and_key(const std::string& full_url, std::string& p
}
int main() {
const char* it = std::getenv("PRIVATEBIN_IT");
char* it = nullptr;
size_t len = 0;
_dupenv_s(&it, &len, "PRIVATEBIN_IT");
if (!it || std::string(it) == "0") {
std::cout << "[test] PRIVATEBIN_IT not set; skipping integration test." << std::endl;
free(it);
return 0; // treat as success when integration testing is disabled
}
const char* server = "https://privatebin.medisoftware.org/";
const char* content = "Integration test from lib-privatebin";
const char* password = nullptr; // no password
const char* expiration = "5min"; // short-lived
const char* format = "plaintext";
const int burn_after_reading = 0;
const int open_discussion = 0;
std::cout << "[test] Testing different text formats..." << std::endl;
// Test 1: Plaintext format
std::cout << "[test] 1. Testing plaintext format..." << std::endl;
const char* plaintext_content = "Integration test from lib-privatebin - plaintext";
const char* plaintext_format = "plaintext";
char* paste_url = nullptr;
char* delete_token = nullptr;
std::cout << "[test] create_paste..." << std::endl;
int rc = create_paste(server, content, password, expiration, format,
int rc = create_paste(server, plaintext_content, password, expiration, plaintext_format,
burn_after_reading, open_discussion, &paste_url, &delete_token);
if (rc != 0 || paste_url == nullptr || delete_token == nullptr) {
std::cerr << "[test][ERROR] create_paste failed, rc=" << rc << std::endl;
std::cerr << "[test][ERROR] plaintext create_paste failed, rc=" << rc << std::endl;
if (paste_url) free_string(paste_url);
if (delete_token) free_string(delete_token);
return 1;
@ -68,7 +76,7 @@ int main() {
return 1;
}
std::string fetched_str = fetched;
assert(fetched_str == content && "fetched content mismatch");
assert(fetched_str == plaintext_content && "fetched plaintext content mismatch");
std::cout << "[test] delete_paste..." << std::endl;
rc = delete_paste(server, paste_id.c_str(), delete_token);
@ -80,11 +88,142 @@ int main() {
return 1;
}
// cleanup
// cleanup plaintext test
free_string(paste_url);
free_string(delete_token);
free_string(fetched);
// Test 2: Syntax highlighting format
std::cout << "[test] 2. Testing syntax highlighting format..." << std::endl;
const char* code_content = R"(
#include <iostream>
std::cout << "[test] all API functions passed." << std::endl;
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
)";
const char* code_format = "syntaxhighlighting";
char* code_paste_url = nullptr;
char* code_delete_token = nullptr;
rc = create_paste(server, code_content, password, expiration, code_format,
burn_after_reading, open_discussion, &code_paste_url, &code_delete_token);
if (rc != 0 || code_paste_url == nullptr || code_delete_token == nullptr) {
std::cerr << "[test][ERROR] syntax highlighting create_paste failed, rc=" << rc << std::endl;
if (code_paste_url) free_string(code_paste_url);
if (code_delete_token) free_string(code_delete_token);
return 1;
}
// Parse code paste URL
std::string code_full_url = code_paste_url;
std::string code_paste_id;
std::string code_key;
const bool code_ok_parse = extract_paste_id_and_key(code_full_url, code_paste_id, code_key);
if (!code_ok_parse) {
std::cerr << "[test][ERROR] failed to parse code paste id/key from URL: " << code_full_url << std::endl;
free_string(code_paste_url);
free_string(code_delete_token);
return 1;
}
// Fetch and verify code paste
char* code_fetched = nullptr;
rc = get_paste(server, code_paste_id.c_str(), code_key.c_str(), &code_fetched);
if (rc != 0 || code_fetched == nullptr) {
std::cerr << "[test][ERROR] code get_paste failed, rc=" << rc << std::endl;
free_string(code_paste_url);
free_string(code_delete_token);
return 1;
}
std::string code_fetched_str = code_fetched;
assert(code_fetched_str == code_content && "fetched code content mismatch");
// Delete code paste
rc = delete_paste(server, code_paste_id.c_str(), code_delete_token);
if (rc != 0) {
std::cerr << "[test][ERROR] code delete_paste failed, rc=" << rc << std::endl;
free_string(code_paste_url);
free_string(code_delete_token);
free_string(code_fetched);
return 1;
}
// cleanup code test
free_string(code_paste_url);
free_string(code_delete_token);
free_string(code_fetched);
// Test 3: Markdown format
std::cout << "[test] 3. Testing markdown format..." << std::endl;
const char* markdown_content = R"(
# Test Header
This is a **bold** and *italic* text.
## Code Block
```cpp
int x = 42;
std::cout << x << std::endl;
```
> This is a blockquote.
)";
const char* markdown_format = "markdown";
char* markdown_paste_url = nullptr;
char* markdown_delete_token = nullptr;
rc = create_paste(server, markdown_content, password, expiration, markdown_format,
burn_after_reading, open_discussion, &markdown_paste_url, &markdown_delete_token);
if (rc != 0 || markdown_paste_url == nullptr || markdown_delete_token == nullptr) {
std::cerr << "[test][ERROR] markdown create_paste failed, rc=" << rc << std::endl;
if (markdown_paste_url) free_string(markdown_paste_url);
if (markdown_delete_token) free_string(markdown_delete_token);
return 1;
}
// Parse markdown paste URL
std::string markdown_full_url = markdown_paste_url;
std::string markdown_paste_id;
std::string markdown_key;
const bool markdown_ok_parse = extract_paste_id_and_key(markdown_full_url, markdown_paste_id, markdown_key);
if (!markdown_ok_parse) {
std::cerr << "[test][ERROR] failed to parse markdown paste id/key from URL: " << markdown_full_url << std::endl;
free_string(markdown_paste_url);
free_string(markdown_delete_token);
return 1;
}
// Fetch and verify markdown paste
char* markdown_fetched = nullptr;
rc = get_paste(server, markdown_paste_id.c_str(), markdown_key.c_str(), &markdown_fetched);
if (rc != 0 || markdown_fetched == nullptr) {
std::cerr << "[test][ERROR] markdown get_paste failed, rc=" << rc << std::endl;
free_string(markdown_paste_url);
free_string(markdown_delete_token);
return 1;
}
std::string markdown_fetched_str = markdown_fetched;
assert(markdown_fetched_str == markdown_content && "fetched markdown content mismatch");
// Delete markdown paste
rc = delete_paste(server, markdown_paste_id.c_str(), markdown_delete_token);
if (rc != 0) {
std::cerr << "[test][ERROR] markdown delete_paste failed, rc=" << rc << std::endl;
free_string(markdown_paste_url);
free_string(markdown_delete_token);
free_string(markdown_fetched);
return 1;
}
// cleanup markdown test
free_string(markdown_paste_url);
free_string(markdown_delete_token);
free_string(markdown_fetched);
std::cout << "[test] All format tests passed successfully!" << std::endl;
return 0;
}