Hakanai (儚い)
A minimalist one-time secret sharing service built on zero-knowledge principles.
Version 2.0 Changes
⚠️ BREAKING CHANGES:
- Redis-based token system: Token authentication now uses Redis instead of files/environment variables
- Anonymous access support: New
--allow-anonymousoption enables public access with size limits - Configuration changes: Size limits now specified in KB instead of MB
- Automatic token generation: Admin token automatically created on first startup
Philosophy
Hakanai embodies the Japanese concept of transience - secrets that exist only for a moment before vanishing forever. No accounts, no tracking, no persistence. Just ephemeral data transfer with mathematical privacy guarantees.
Core Principles
- Zero-Knowledge: The server never sees your data. All encryption happens client-side.
- Single View: Secrets self-destruct after one access. No second chances.
- No Metadata: We store only encrypted bytes and an ID. Nothing else.
- Minimalist: One function only - share secrets that disappear.
How It Works
- Your client (CLI or browser) encrypts the secret locally
- Sends only the ciphertext to our server
- You share the link with the decryption key (either embedded in URL or separately)
- Recipient views once, then it's gone forever
Enhanced Security Mode
With the --separate-key option, Hakanai provides enhanced security by separating the secret URL from the decryption key:
- Traditional mode: One URL contains both secret ID and key (
/s/uuid#key) - Separate key mode: Secret URL (
/s/uuid) and key are provided separately - Defense in depth: Share URL and key through different communication channels
- Reduced attack surface: No cryptographic material in any single URL
Security Model
We implement true client-side encryption - your secrets are encrypted before leaving your device and decrypted only after retrieval. The server is just a temporary dead drop that forgets everything.
Note: This project focuses on the application-layer encryption. Transport security (HTTPS/TLS) should be handled by a reverse proxy or load balancer in front of the server.
Built for those who believe privacy isn't about having something to hide - it's about having something to protect.
Installation
Prerequisites
- Rust 2024 edition or later
- Redis server (for backend storage)
- Standard Rust toolchain (
cargo,rustc)
From Source
# Clone the repository
# Build all components
# Binaries will be in:
# - ./target/release/hakanai (CLI)
# - ./target/release/hakanai-server (Server)
Using Docker Compose
The easiest way to run Hakanai is with Docker Compose, which includes both the server and a Valkey (Redis-compatible) database:
# Start the services
# The server will be available at http://localhost:8080
# View logs
# Stop the services
# Stop and remove volumes (clears all stored secrets)
For production deployment, create your own docker-compose.override.yml:
services:
hakanai:
environment:
HAKANAI_ALLOW_ANONYMOUS: "true"
HAKANAI_ANONYMOUS_UPLOAD_SIZE_LIMIT: "64"
Usage
Server
# Start with default settings (port 8080, Redis on localhost)
# Admin token will be generated and logged on first startup
# Or with custom configuration
# Enable anonymous access (allows public secret creation with size limits)
# Configure anonymous size limits (humanized format)
# Enable admin token system for token management
# Combined: admin system + anonymous access
# Production setup with admin token and monitoring
v2.0 Token System:
- Admin token:
- Optional: Only created with
--enable-admin-tokenflag - No expiration: Permanent tokens since they're not recoverable
- Purpose: Future admin API for token management
- Recovery:
--reset-admin-tokenflag (requires server restart)
- Optional: Only created with
- User tokens:
- Default behavior: Always created on first startup
- 30-day TTL: Automatic expiration for security
- Recovery:
--reset-default-tokenflag (clears all user tokens)
- Anonymous access: Optional public access with configurable size limits
- ⚠️ BREAKING:
HAKANAI_TOKENSenvironment variable removed in v2.0
Token Recovery Options:
# Reset admin token (creates new admin token)
# Reset user token (clears all user tokens, creates new default)
# Emergency: Direct Redis access
Configuration Validation: The server validates flag combinations on startup to prevent invalid configurations:
--reset-admin-tokenrequires--enable-admin-token--anonymous-size-limitcannot exceed--upload-size-limit- Invalid combinations result in startup failure with clear error messages
CLI
Sending a Secret
# Send from stdin (default: 24 hour expiration)
|
# Send from a file
# Send with custom TTL
|
# Send to custom server
|
# Send with authentication token (required if server has token whitelist)
|
# Generate separate key for enhanced security (key and URL shared via different channels)
|
# Output:
# Secret sent successfully!
#
# Secret link: https://hakanai.example.com/s/uuid
# Key: base64-encoded-key
# Combine options
Retrieving a Secret
# Get using the full URL returned by send
# Get using the short link format
# Get using separate key (when --separate-key was used)
# Secret is displayed and immediately destroyed on server
Creating User Tokens (Admin Only)
# Create a user token with admin privileges
# Create token with humanized size limits
# Create token with custom server and settings
Size Format Options:
- Plain numbers: bytes (e.g.,
1024) - 'k' suffix: kilobytes (e.g.,
500k) - 'm' suffix: megabytes (e.g.,
1m) - Decimal values supported (e.g.,
1.5m,2.5k)
Note: You can also retrieve secrets using a web browser by visiting the server URL and pasting the secret link.
Web Interface
Hakanai now includes a web interface for users who prefer not to use the CLI:
- Visit the server root (e.g.,
https://hakanai.example.com/) to access the web interface - Create new secrets at
/create- supports both text and file uploads - Paste a hakanai URL to retrieve secrets directly in your browser
- The same zero-knowledge encryption is maintained - all encryption/decryption happens in your browser
- Dark/Light Mode Toggle: Automatic system preference detection with manual override
- Mobile-friendly responsive design
- Multi-language support (English and German) with automatic browser language detection
API Reference
📚 For complete API documentation, visit /docs on your running server.
The documentation is automatically generated from the OpenAPI specification, ensuring it always reflects the current API state. Both human-readable docs and machine-readable specs are kept in perfect sync.
POST /api/v1/secret
Create a new secret.
Headers:
Authorization: Bearer {token}(required if server has token whitelist)
Request:
Response:
Error Responses:
401 Unauthorized: Invalid or missing token when server requires authentication400 Bad Request: Invalid request body
GET /api/v1/secret/{id}
Retrieve a secret (one-time access).
Response:
200 OK: Plain text secret data404 Not Found: Secret doesn't exist or has expired410 Gone: Secret was already accessed by someone else
GET /s/{id}
Short link for secret retrieval.
Response:
- For CLI clients: Plain text secret data
- For browsers: HTML page for secret retrieval
404 Not Found: Secret doesn't exist or has expired410 Gone: Secret was already accessed by someone else
GET /logo.svg
Serves the hakanai logo.
GET /icon.svg
Serves the hakanai icon.
GET /scripts/hakanai-client.js
Serves the JavaScript client library for browser-based encryption/decryption. The client is implemented in TypeScript and automatically compiled to JavaScript during the build process for browser compatibility.
TypeScript Client Architecture:
- Source: TypeScript files in
server/src/typescript/ - Compiled Output: JavaScript files in
server/src/includes/ - Build Integration: Automatic compilation via
build.rsduring cargo build - Type Safety: Comprehensive type definitions with strict type checking
- Browser Compatibility: Feature detection with graceful fallback
TypeScript Client API:
// Create a client instance
const client = ;
// Create payload from text
const encoder = ;
const textBytes = encoder.;
const payload = client.; // optional filename parameter
payload.;
// Create payload from file bytes
const fileBytes = ; // from FileReader
const filePayload = client.;
filePayload.;
// Send payload
const secretUrl = await client.; // TTL in seconds
// Retrieve payload
const retrievedPayload = await client.;
const originalText = retrievedPayload.; // for text data
const originalBytes = retrievedPayload.; // for binary data
GET /
Web interface for retrieving secrets - shows a form to paste hakanai URLs.
GET /create
Web interface for creating secrets - supports text input and file uploads.
GET /docs
Auto-generated API documentation page - comprehensive reference for developers using the REST API.
GET /openapi.json
OpenAPI 3.0 specification file - the source of truth for API documentation and tooling integration (Postman, code generators, etc.).
POST /api/v1/admin/tokens
Create user tokens (admin authentication required).
Headers:
Authorization: Bearer {admin-token}(required)
Request:
Response:
Error Responses:
401 Unauthorized: Invalid or missing admin token400 Bad Request: Invalid request body
GET /ready
Readiness check endpoint - returns 200 OK when the server is ready to accept requests.
GET /healthy
Health check endpoint - returns 200 OK when the server and all dependencies (Redis) are healthy.
GET /s/{id}
Short link format for retrieving secrets. Dual-mode endpoint:
- Returns raw decrypted data for CLI clients
- Returns HTML page for browser clients (based on User-Agent)
Static Assets
/style.css- CSS stylesheet/i18n.js- Internationalization support (compiled from TypeScript)/get-secret.js- JavaScript for secret retrieval page (compiled from TypeScript)/create-secret.js- JavaScript for secret creation page (compiled from TypeScript)/common-utils.js- Shared utilities (compiled from TypeScript)/hakanai-client.js- Main client library (compiled from TypeScript)
Note: All JavaScript files are compiled from TypeScript sources during the build process.
Development
Project Structure
hakanai/
├── lib/ # Core library (client, crypto, models)
├── cli/ # Command-line interface
├── server/ # Actix-web server
└── Cargo.toml # Workspace configuration
Building
# Build entire workspace (includes TypeScript compilation and HTML generation)
# Build release version
# Build TypeScript client only (compiles .ts to .js)
# Clean TypeScript compiled files
# TypeScript type checking only (no compilation)
Build-Time Template Generation
The server uses build-time template generation for consistent and efficient HTML serving:
Generated Files (auto-generated, do not edit directly):
server/src/includes/docs_generated.html- API documentation from OpenAPI specserver/src/includes/create-secret.html- Create secret page with version substitutionserver/src/includes/get-secret.html- Retrieve secret page with version substitution
Note: These files are excluded from git and regenerated on every build.
Source Templates (edit these):
server/src/templates/docs.html- API documentation templateserver/src/templates/endpoint.html- Individual endpoint templateserver/src/templates/create-secret.html- Create secret page templateserver/src/templates/get-secret.html- Retrieve secret page template
How it works:
server/build.rsruns during compilation- Templates in
templates/directory are processed with tinytemplate - Variables like
{version}are substituted with build-time values - Generated HTML files are embedded in the binary with
include_bytes! - No runtime string replacement needed - templates are pre-processed
Template Variables:
{version}- Cargo package version (e.g., "1.3.2"){title},{description}- From OpenAPI spec{endpoints}- Generated endpoint documentation
This approach ensures version consistency and eliminates runtime overhead.
Testing
# Run all tests
# Run specific test
# Run TypeScript tests
# Run tests with coverage (if cargo-tarpaulin installed)
The project includes comprehensive test coverage with:
- 190+ total tests across all components
- Factory pattern for dependency injection in CLI tests
- Mock observers to prevent console interference during testing
- Proper test isolation with tempfile for all file operations
Code Quality
# Format code
# Run linter (warnings as errors)
RUSTFLAGS="-Dwarnings"
# TypeScript compilation (automatically checks types)
Architecture
Hakanai implements a zero-knowledge architecture:
- Client-side encryption: All encryption/decryption happens in the client
- Server ignorance: Server only stores encrypted blobs with UUIDs
- Automatic destruction: Secrets self-destruct after first access or TTL
- No persistence: No logs, no backups, no recovery
Components
- hakanai-lib: Core functionality including:
- Generic
Client<T>trait for flexible client implementations CryptoClientfor AES-256-GCM encryption/decryption with integratedPayloadserializationWebClientfor HTTP transport- Shared data models (
Payload,PostSecretRequest,PostSecretResponse) - Comprehensive memory safety with automatic zeroization
- Generic
- hakanai (CLI): User-friendly command-line interface
- hakanai-server: RESTful API server with Redis backend
- TypeScript Client: Modern browser-based implementation with comprehensive type safety
- Full TypeScript Implementation: Complete rewrite in TypeScript with strict type checking
- Automatic Compilation: TypeScript sources compiled to JavaScript during build process
- Type-Safe Architecture: Comprehensive interfaces and type definitions
- Zero-Knowledge Maintained: Same cryptographic security as Rust client
- Browser Compatibility: Comprehensive feature detection with graceful fallback
- Enhanced Error Handling: Structured error types with detailed messages
- Chunked Processing: Efficient handling of large files with 8KB chunks
- Modular Architecture: Clean separation with dedicated classes for crypto, utils, and i18n
- Bytes-based PayloadData Interface: Unified approach for text and binary data
payload.setFromBytes(bytes)- Sets data from raw bytes with automatic base64 encodingpayload.decode()- Decodes to text with proper Unicode handlingpayload.decodeBytes()- Decodes to binary data as Uint8Arraypayload.data- Readonly base64-encoded data field
Security & Deployment Notes
Security Architecture
Hakanai follows a separation of concerns security model:
- Application Layer: Zero-knowledge encryption, secure token handling, input validation
- Infrastructure Layer: TLS termination, rate limiting, DDoS protection (handled by reverse proxy)
Production Deployment
The server is designed to run behind a reverse proxy (nginx, Caddy, etc.) which handles:
- TLS termination and HTTPS enforcement
- Rate limiting and DDoS protection
- Request filtering and header sanitization
- Response compression (gzip, etc.) for improved performance
For production deployments:
- Always use authentication tokens to prevent unauthorized secret creation
- Configure reverse proxy for TLS, rate limiting, and security headers
- Monitor server logs (structured logging with tracing middleware included)
- Set appropriate Redis memory limits and eviction policies
- Enable OpenTelemetry for comprehensive observability
Security Audit Results
- ✅ Comprehensive security audit completed (2025-07-17)
- ✅ Overall security rating: A- (production ready with minor improvements)
- ✅ No Critical or High priority vulnerabilities - only 3 low-priority operational improvements remain
- ✅ Production ready with proper infrastructure configuration
- ✅ Zero-knowledge architecture properly implemented with strong cryptographic foundations
- ✅ Comprehensive memory safety with automatic zeroization and secure cleanup
Current Status
- ✅ One-time access enforcement
- ✅ Automatic expiration with configurable TTL
- ✅ No user tracking or accounts
- ✅ Client-side AES-256-GCM encryption
- ✅ Token-based authentication with SHA-256 hashing
- ✅ Redis backend storage with connection pooling
- ✅ Web interface for browser-based retrieval
- ✅ Binary file support with progress tracking
- ✅ Short link format (
/s/{id}) for easier sharing - ✅ Internationalization support (English and German)
- ✅ OpenTelemetry integration for comprehensive observability
- ✅ Comprehensive test coverage (195+ total tests: 125+ Rust, 70+ TypeScript including comprehensive serialization tests)
- ✅ Docker deployment with Valkey/Redis included
- ✅ Enhanced TypeScript Client: Bytes-based PayloadData interface with type safety
- ✅ Unified Data Handling: Consistent approach for text and binary data across all clients
- ✅ Access Tracking: Returns 410 Gone status if secret was already accessed
- ✅ Dark/Light Mode: System preference detection with manual toggle and localStorage persistence
- ✅ Health Endpoints:
/healthyand/readyendpoints for monitoring and orchestration
Security Implementation
- ✅ Zero-knowledge architecture: All encryption/decryption client-side
- ✅ AES-256-GCM encryption: Industry-standard authenticated encryption
- ✅ Secure random generation: Cryptographically secure nonces with OsRng
- ✅ Memory safety: Pure Rust implementation, no unsafe code
- ✅ Generic client architecture: Type-safe payload handling with trait abstractions
- ✅ Simplified architecture:
CryptoClient<Payload>→WebClient<Vec<u8>>with clear security boundaries - ✅ Input validation: Comprehensive UUID, TTL, and data validation
- ✅ Error security: Generic error messages prevent information disclosure
- ✅ Web security: CSP headers, XSS prevention, secure DOM manipulation
Configuration
Server Environment Variables
HAKANAI_PORT: Server port (default: 8080)HAKANAI_LISTEN_ADDRESS: Bind address (default: 0.0.0.0)HAKANAI_REDIS_DSN: Redis connection string (default: redis://127.0.0.1:6379/)HAKANAI_UPLOAD_SIZE_LIMIT: Maximum upload size (default: 10m, supports humanized format like 1m, 500k, 1024)HAKANAI_ALLOW_ANONYMOUS: Allow anonymous access (default: false)HAKANAI_ANONYMOUS_UPLOAD_SIZE_LIMIT: Upload size limit for anonymous users (default: 32k, supports humanized format)HAKANAI_ENABLE_ADMIN_TOKEN: Enable admin token system (default: false)HAKANAI_CORS_ALLOWED_ORIGINS: Comma-separated allowed CORS origins (default: none)HAKANAI_MAX_TTL: Maximum allowed TTL in seconds (default: 604800, 7 days)OTEL_EXPORTER_OTLP_ENDPOINT: OpenTelemetry collector endpoint (optional, enables OTEL when set)
Server Command-line Options
--port: Override the port number--listen: Override the listen address--redis-dsn: Override the Redis connection string--allow-anonymous: Allow anonymous access without authentication--anonymous-size-limit: Set upload size limit for anonymous users (supports humanized format like 32k, 1m)--enable-admin-token: Enable admin token system for token management--reset-admin-token: Force regenerate admin token (requires --enable-admin-token)--reset-user-tokens: Clear all user tokens and create new default token
Security Features
- Zero-Knowledge Architecture: All encryption/decryption happens client-side
- AES-256-GCM Encryption: Industry-standard authenticated encryption
- Secure Random Generation: Cryptographically secure nonce generation with OsRng
- Token-based Authentication: Redis-backed token system with automatic admin token generation
- SHA-256 Token Hashing: Authentication tokens are securely hashed before storage
- Request Logging: Built-in request logging middleware for monitoring and debugging
- One-time Access: Secrets are automatically deleted after first retrieval
- Input Validation: Proper UUID validation and TTL enforcement
- Error Handling: Secure error messages that don't leak sensitive information
- CORS Security: Restrictive CORS policy by default, explicit origin allowlist required
- Security Headers: The application sets these security headers:
X-Frame-Options: DENY- Prevents clickjacking attacksX-Content-Type-Options: nosniff- Prevents MIME type sniffingStrict-Transport-Security: max-age=31536000; includeSubDomains- Enforces HTTPS- Additional headers (CSP, etc.) should be configured at the reverse proxy level
Observability
When OTEL_EXPORTER_OTLP_ENDPOINT is set, Hakanai exports:
- Traces: Distributed tracing for all HTTP requests
- Metrics: Application performance and usage metrics
- Logs: Structured logs with trace correlation
The server automatically detects service name and version from Cargo metadata and includes resource information about the OS, process, and runtime environment.
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass and clippy is happy
- Submit a pull request
License
(c) Daniel Brendgen-Czerwonk, 2025. Licensed under MIT license.