File URL
A secure file sharing system that uses multi-layer encryption and client-side decryption to protect files.
If you don't have an atSign yet, you'll need to register and activate one:
- Go to my.atsign.com/go
- Purchase or get a free atSign (like @alice, @mycompany, etc.)
- Complete the registration process
# Using compiled binary
# Replace @youratSign with your actual atSign (e.g., @alice)
at_activate -a @youratSign
Follow the prompts to:
- Enter the one-time password (OTP) sent to your email/SMS
- Create a backup of your keys file e.g send to another machine using furl!
Important: Keep your atSign keys safe! They're stored in your home directory/.atsign/keys and are needed to send an encrypted file with furl or other atsign apps.
Using latest Binary Release for your OS/Arch
# Replace @youratSign with your actual atSign (e.g., @alice)
# Uses the default server at https://furl.host
furl @youratSign path/to/file.txt 1h
# Or share with a custom message
furl @youratSign path/to/file.txt 1h -m "Here's the file you requested"This will:
- Encrypt the file with ChaCha20
- Generate a 9-character strong PIN with special characters
- Upload encrypted file to filebin.net
- Store encrypted metadata on atPlatform
- Display a URL and PIN for the recipient
Send the recipient:
- URL: The URL displayed after successful upload
- PIN: The 9-character code displayed during upload
The recipient:
- Opens the URL in their browser
- Enters the PIN
- Clicks "Download & Decrypt"
- Gets the original file automatically decrypted
Original File → ChaCha20 Encrypt → Upload to filebin.net
↓
ChaCha20 Key → PIN Encrypt → Store on atPlatform
atPlatform → Get Encrypted Metadata → PIN Decrypt → ChaCha20 Key
filebin.net → Get Encrypted File → ChaCha20 Decrypt → Original File
- File Encryption: Each file is encrypted with a unique 256-bit ChaCha20 key
- Key Protection: The ChaCha20 key is encrypted using a PIN-derived key
- Separation: File data and encryption keys are stored separately
- Client-Side: All decryption happens in the recipient's browser
- Zero-Knowledge: Servers never see plaintext files or PINs
- Dart SDK
- Activated atSign (get one at atsign.com, then activate with
at_activatebinary ordart run bin/at_activate.dart) - Network connectivity for atPlatform and filebin.net
If you want to run your own furl server instead of using the default server at https://furl.host, follow these instructions:
- Rust and wasm-pack (required for browser decryption)
Before using the web interface, you must build the WASM module:
# Install Rust (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install wasm-pack
cargo install wasm-pack
# Build the WASM crypto module
cd wasm-crypto
# On Linux/macOS:
./build.sh
# On Windows:
build.bat
# Or manually with wasm-pack:
# wasm-pack build --target web --out-dir ../web/wasm
cd ..
# Now you can use both CLI and web interface# Start the unified server (default port 8080)
furl-server
# Or specify a custom port
furl-server --port 8090
# Or use command line options
furl-server --port 3000 --web-root public# Start the unified server (default port 8080)
dart run bin/furl_server.dart
# Or specify a custom port
dart run bin/furl_server.dart 8090
# Or use command line options
dart run bin/furl_server.dart --port 3000 --web-root publicOnce your server is running, specify it when sharing files:
# Using compiled binary with custom server
furl @alice document.pdf 1h --server http://localhost:8080
# Using Dart with custom server
dart run bin/furl.dart @alice document.pdf 1h --server http://localhost:8080Your files will then be accessible via your custom server URL instead of the default https://furl.host.
# Using compiled binary
furl @alice document.pdf 1h
# With verbose output
furl @alice document.pdf 1h -v
# With quiet mode (no progress bars)
furl @alice document.pdf 1h -q
# With a custom message for the recipient
furl @alice document.pdf 1h -m "Here is the contract"
# Using Dart (for development)
dart run bin/furl.dart @alice document.pdf 1h
# With verbose output
dart run bin/furl.dart @alice document.pdf 1h -v
# Parameters:
# @alice - Your atSign
# document.pdf - File to encrypt and share
# 1h - TTL (1 hour, can use: 30s, 10m, 2h, 7d, or seconds)
# -v - Verbose output (optional)
# -q - Quiet mode - no progress bars (optional)
# -m "message" - Custom message for recipient (max 140 chars, optional)- Default Port: 8080
- Command Line Options:
--port <port>- Specify server port--web-root <path>- Specify web files directory (default: web)--help- Show help message
- API Endpoints (prefixed with
/api/):GET /api/atsign/{atSign}- Resolve atSign to atServerGET /api/fetch/{atSign}/{keyName}- Fetch encrypted metadataGET /api/download?url={url}- Proxy file downloadsGET /api/health- Health check
- Web Interface:
GET /- Redirects to furl.htmlGET /furl.html- File decryption interface- Static files served from web/ directory
REQUIRED: Furl now uses pure WebAssembly (WASM) for all browser-based decryption to ensure optimal performance and consistent behavior. The web interface requires WASM support and will not fall back to JavaScript crypto APIs.
To build and use the WASM module (required for browser decryption):
- Rust: Install from rustup.rs
- wasm-pack: Install with
cargo install wasm-pack - Modern Browser: Chrome, Firefox, Safari, or Edge with WebAssembly support
# Navigate to the WASM crypto directory
cd wasm-crypto
# On Linux/macOS - use the build script:
./build.sh
# On Windows - use the batch script:
build.bat
# Or manually with wasm-pack:
wasm-pack build --target web --out-dir ../web/wasm
# The generated files will be in web/wasm/Permission denied on macOS/Linux:
chmod +x build.sh
./build.shMissing Rust/wasm-pack:
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
# Install wasm-pack
cargo install wasm-packBuild fails with target error:
# Add the wasm32 target
rustup target add wasm32-unknown-unknownModule not found in browser:
Check that files were generated in web/wasm/ directory:
wasm_crypto.jswasm_crypto_bg.wasmpackage.json
The web interface requires the WASM module for decryption:
- Pure WASM: No JavaScript crypto fallbacks - ensures consistent performance
- Memory Efficient: Streaming decryption with chunked processing
- File System API: Large files can be streamed directly to disk (Chrome/Edge)
- Progress Tracking: Real-time progress updates during download and decryption
- All file sizes: Consistent WASM-accelerated ChaCha20 decryption
- Memory efficient: Constant memory usage regardless of file size
- Streaming: Download and decrypt simultaneously for large files
- Direct to disk: Files >10MB can bypass browser memory entirely
The WASM module source is in wasm-crypto/src/lib.rs and uses:
chacha20crate for ChaCha20 encryption primitiveswasm-bindgenfor JavaScript integrationjs-sysfor browser API access
Important: WASM module must be built before browser decryption will work. Build artifacts are excluded from the repository.
- Layer 1: ChaCha20 file encryption
- Layer 2: PIN-protected key encryption
- Layer 3: Separate storage of files and metadata
- Layer 4: Client-side decryption only
- Servers never see plaintext files
- PINs never leave the recipient's browser
- Zero-knowledge architecture
- Forward secrecy (unique keys per file)
- Requires both URL and PIN
- Time-limited access (TTL)
- Single-use URLs (can be configured)
The PIN serves as a shared secret that enables secure key exchange:
- Key Protection: Protects the ChaCha20 encryption key with an additional layer
- Zero-Knowledge: PIN never leaves the recipient's browser
- Access Control: Requires both URL and PIN for file access
- Forward Secrecy: Each file gets a unique PIN and ChaCha20 key
Upload (Sender):
1. Generate random 9-char PIN
2. Derive key: PIN_Key = SHA256(PIN_bytes + Salt_bytes)
3. Encrypt: Encrypted_ChaCha20_Key = ChaCha20(ChaCha20_Key, PIN_Key)
4. Store encrypted ChaCha20 key + salt in atPlatform
5. Share URL + PIN with recipient
Download (Recipient):
1. Enter PIN in browser
2. Derive same key: PIN_Key = SHA256(PIN_bytes + Salt_bytes)
3. Decrypt: ChaCha20_Key = ChaCha20-DECRYPT(Encrypted_ChaCha20_Key, PIN_Key)
4. Use ChaCha20_Key to decrypt the downloaded file
bin/
furl.dart # Main CLI tool for encryption/upload
furl_server.dart # Unified server (API + Web)
web/
furl.html # Client-side decryption interface
wasm-crypto.js # WASM crypto module loader
wasm/ # WebAssembly crypto module (built from wasm-crypto/)
wasm-crypto/ # WASM source code (Rust)
src/lib.rs # ChaCha20 WASM implementation
test/
furl_test.dart # Tests
SECURITY_DESIGN.md # Detailed security analysis
- "Failed to authenticate": Make sure your atSign is activated
- "Could not fetch data": Ensure API server is running on correct port
- "Failed to download file": Check network connectivity to filebin.net
- "Invalid PIN": Ensure you're entering the exact 9-character PIN
- "WASM module not available": Build the WASM module with
wasm-packfirst
Run with -v flag for verbose output:
# Using compiled binary
furl @alice file.txt 1h -v
# Using Dart
dart run bin/furl.dart @alice file.txt 1h -v# Test unified server health
curl http://localhost:8080/api/health
# Test web interface
curl http://localhost:8080/furl.html- PIN Strength: 9 characters provide ~60 bits of entropy
- Key Derivation: Uses SHA-256 (could be enhanced with PBKDF2)
- Transport: Uses HTTPS for all external communications
- Storage: No sensitive data stored on servers
For detailed security analysis, see SECURITY_DESIGN.md.
dart test# On Unix/Linux/macOS
./run-all-tests.sh
# On Windows
run-all-tests.bat# Core functionality tests (crypto and CLI validation only)
dart test test/crypto_test.dart test/cli_validation_test.dart test/furl_test.dart
# Server integration tests (requires process spawning)
dart test test/server_test.dart
# Performance tests (local development only)
dart test test/performance_test.dart
# End-to-end tests (requires network)
dart test test/e2e_test.dartNote: Performance and E2E tests are excluded from CI builds to prevent flaky failures. Use the comprehensive test runners for complete local validation.
furl/
├── bin/ # Executable scripts
│ ├── furl.dart # Main CLI tool for encryption/upload
│ └── furl_server.dart # Unified server (API + Web)
├── web/ # Web interface
│ ├── furl.html # Client-side decryption interface
│ ├── wasm-crypto.js # WASM crypto module loader
│ └── wasm/ # WebAssembly crypto module (generated)
├── wasm-crypto/ # WASM source code
│ ├── src/lib.rs # Rust ChaCha20 implementation
│ └── Cargo.toml # Rust dependencies
├── test/ # Test suite
│ └── furl_test.dart # Security and integration tests
├── README.md # This file
├── SECURITY_DESIGN.md # Detailed security analysis
├── CHANGELOG.md # Version history
└── LICENSE # GPL v3 license
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass:
dart test - Submit a pull request
This project is provided as-is for educational and research purposes.