filen_client 0.2.0
filen_client: ^0.2.0 copied to clipboard
Unofficial Dart client and CLI for Filen.io end-to-end-encrypted cloud storage — login, list, encrypted upload/download with batching and resume, plus a WebDAV bridge.
Filen CLI (Dart Edition) #
An unofficial Command Line Interface for Filen.io, written in Dart.
This CLI provides comprehensive file management capabilities with batch operations, resume support, recursive uploads/downloads, conflict handling, integrity verification, WebDAV server, and more - all directly from your terminal.
⚠️ Note: This is early work in progress.
✨ Features #
Core Capabilities #
- 🔐 Secure Authentication: Login with email/password and optional 2FA support
- 📂 Path Resolution: Use standard file paths (e.g.,
/Documents/Report.pdf) instead of raw UUIDs - 💾 Intelligent Caching: 10-minute cache for folder/file listings with automatic invalidation on mutations
- 🔄 Batch Operations: Resume interrupted uploads/downloads with chunk-level state persistence
- 🚀 Bounded Chunk Concurrency: Uploads and downloads transfer multiple 1 MB chunks in parallel, bounded by a semaphore + memory budget (
maxConcurrentChunks, default 4). In-order hashing and set-based resume are preserved; tiny files stay sequential. - 🧵 File-Level Batch Concurrency: Directory uploads/downloads transfer multiple whole files at once (
maxWorkers, default 4) — the big win when syncing many files (~3–4× faster than serial in practice). Total chunks in flight across all files are capped by one shared budget; batch-state writes are serialized; a single file ormaxWorkers<=1stays sequential. - ⚡ Retry Logic: Automatic retry with exponential backoff for network and server errors (5xx)
- ✅ Integrity Verification: SHA-512 hash verification without downloading files
- 🌐 WebDAV Server: Mount your Filen drive as a local network drive
File Operations #
- List (
ls): Browse folders with detailed or compact views, full UUID display - Upload (
up): Chunked uploads with resume from interrupted chunks, progress tracking - Download (
dl,download-path): Single file or recursive folder downloads with resume - Move (
mv): Move files/folders between directories or rename them - Copy (
cp): Copy files using download-upload workflow - Trash (
rm,trash-path): Move items to trash with confirmation - Delete (
delete-path): Permanently delete items (requires confirmation) - Mkdir (
mkdir): Create directories recursively with timestamp preservation - Rename (
rename-path): Rename files or folders in place - Verify (
verify): Verify uploaded files using SHA-512 metadata comparison
Advanced Features #
- 🔍 Search (
search): Server-side search across your entire drive - 🔎 Find (
find): Recursively find files matching glob patterns with depth control - 🌳 Tree (
tree): Visual folder hierarchy with configurable depth - ♻️ Trash Management: List, restore by UUID or name, and permanently delete trashed items
- 📊 Detailed Listings: Show modification times, full UUIDs, file sizes with
-dflag - 🎯 Pattern Matching: Include/exclude files using glob patterns
- 📦 Chunk-Level Resume: Resume uploads from exact chunk where interrupted
WebDAV Server Features #
- 🖥️ Virtual Filesystem: Mount Filen as local drive (Windows/macOS/Linux)
- 📁 Full Read/Write Access: Browse, upload, download, rename, delete via file explorer
- 🔒 Authentication: Basic auth with configurable credentials
- ⚙️ Background Mode: Run server as daemon process
- 🔄 Auto-sync: Changes made via WebDAV instantly sync to Filen
Smart Conflict Handling #
--on-conflict skip: Skip existing files (default, safe)--on-conflict overwrite: Always overwrite existing files--on-conflict newer: Only transfer if remote/local file is newer (requires-p)
Upload Resume System #
- Automatic State Saving: Progress saved every 10 chunks or 5 seconds
- UUID Persistence: Same file UUID and upload key across resume sessions
- Hash Continuation: SHA-512 hash calculated correctly across interrupted sessions
- Error Recovery: Graceful handling of network failures with saved state
📋 Prerequisites #
- Dart SDK: Version 2.12 or higher - Get Dart
- For WebDAV (optional):
- macOS: Built-in WebDAV client
- Windows: Built-in WebDAV client (or use WinSCP, Cyberduck)
- Linux:
davfs2package (sudo apt install davfs2)
🚀 Installation #
-
Clone the repository:
git clone <repository-url> cd filen-dart -
Install dependencies:
dart pub get -
(Optional) Compile to standalone binary:
dart compile exe filen.dart -o filen # Now you can run: ./filen <command>
📖 Usage #
Running from Source #
dart filen.dart <command> [options] [arguments]
Running Compiled Binary #
./filen <command> [options] [arguments]
🎯 Commands #
Authentication #
| Command | Description |
|---|---|
login |
Authenticate with email/password (supports 2FA) |
logout |
Clear stored credentials |
whoami |
Show current user information |
File Management #
| Command | Arguments | Description |
|---|---|---|
ls [path] |
Optional path (default: /) |
List folder contents |
mkdir <path> |
Folder path to create | Create folder(s) recursively |
up <sources...> |
Local files/folders + optional target | Upload files or directories |
dl <uuid-or-path> |
File UUID or path | Download a single file |
download-path <path> |
Remote file or folder path | Download file/folder (supports recursion) |
mv <source> <dest> |
Source and destination paths | Move or rename items |
cp <source> <dest> |
Source and destination paths | Copy files |
rm <path> |
Path to trash | Move to trash |
rename <path> <new_name> |
Path and new name | Rename file or folder |
verify <uuid-or-path> <local-file> |
Remote UUID/path + local file | Verify upload integrity |
Trash Operations #
| Command | Arguments | Description |
|---|---|---|
list-trash |
None | Show all trashed items with UUIDs |
restore-uuid <uuid> |
Item UUID + optional -t <dest> |
Restore item by UUID |
restore-path <name> |
Item name + optional -t <dest> |
Restore item by name |
delete-path <path> |
Path to delete | Permanently delete (requires confirmation) |
Search & Discovery #
| Command | Arguments | Description |
|---|---|---|
search <query> |
Search term | Search files across entire drive |
find <path> <pattern> |
Start path + glob pattern | Recursively find matching files |
tree [path] |
Optional start path | Show folder structure as tree |
resolve <path> |
Path to resolve | Debug path resolution (shows UUID) |
WebDAV Server #
| Command | Arguments | Description |
|---|---|---|
webdav-start |
Optional --port and -b |
Start WebDAV server |
webdav-stop |
None | Stop background WebDAV server |
webdav-status |
None | Check if server is running |
webdav-test |
None | Test connection to server |
webdav-mount |
None | Show OS-specific mount instructions |
webdav-config |
None | Show server configuration |
mount |
Optional --port |
Start WebDAV in foreground (deprecated, use webdav-start) |
System #
| Command | Description |
|---|---|
config |
Show configuration paths and API endpoints |
help |
Display comprehensive help message |
🎛️ Global Options #
| Flag | Short | Description |
|---|---|---|
--verbose |
-v |
Enable debug output (shows crypto operations, API calls) |
--force |
-f |
Skip confirmations for destructive operations |
--uuids |
Show full UUIDs in listings (default: truncated) | |
--detailed |
-d |
Show detailed file info (includes full UUIDs, timestamps) |
--recursive |
-r |
Recursive operations for directories |
--preserve-timestamps |
-p |
Preserve file modification times |
--target <path> |
-t |
Specify destination path |
--on-conflict <mode> |
Conflict resolution: skip, overwrite, newer |
|
--include <pattern> |
Include only files matching pattern (can use multiple) | |
--exclude <pattern> |
Exclude files matching pattern (can use multiple) | |
--depth <n> |
-l |
Max depth for tree command (default: 3) |
--maxdepth <n> |
Max depth for find command (default: -1 = infinite) | |
--background |
-b |
Run WebDAV server in background |
--port <n> |
WebDAV server port (default: 8080) | |
--webdav-debug |
Enable WebDAV debug logging |
💡 Examples #
Basic Operations #
Login with 2FA:
dart filen.dart login
# Prompts for email, password, and 2FA code if enabled
List files with details and full UUIDs:
dart filen.dart ls /Documents -d
Show folder tree:
dart filen.dart tree /Projects -l 2
Check current user:
dart filen.dart whoami
Upload Examples #
Upload single file:
dart filen.dart up report.pdf /Documents/Reports
Upload directory recursively with timestamp preservation:
dart filen.dart up ~/Projects/MyApp /Backups/MyApp -r -p
Upload with progress and get UUID for verification:
dart filen.dart up largefile.zip /Backups
# Output shows:
# 📤 Uploading: largefile.zip (173.1 MB)
# Uploading... 174/174 chunks (100.0%)
# ✅ Upload complete
# 🆔 UUID: abc123-def456-ghi789-jkl012-mno345
# 📊 SHA-512: a1b2c3d4e5f6...
Upload only PDF files, excluding temps:
dart filen.dart up ~/Documents/* /Backup -r \
--include "*.pdf" --exclude "*_temp*"
Upload with conflict handling:
# Skip existing files (default)
dart filen.dart up photos/ /Photos -r --on-conflict skip
# Overwrite all existing files
dart filen.dart up photos/ /Photos -r --on-conflict overwrite
# Only upload if local file is newer (requires -p)
dart filen.dart up photos/ /Photos -r --on-conflict newer -p
Resume interrupted upload:
# Start upload
dart filen.dart up hugefile.tar.gz /Backups
# (Press Ctrl+C to interrupt)
# Resume from exact chunk where it stopped
dart filen.dart up hugefile.tar.gz /Backups
# Output shows:
# 🔄 Resuming batch...
# 📤 Resuming: hugefile.tar.gz from chunk 12 (173.1 MB)
# Uploading... 12/174 chunks (6.9%)
Verification Examples #
Verify by path (easiest method):
dart filen.dart verify /Documents/report.pdf report.pdf
Verify by UUID (after upload):
dart filen.dart verify abc123-def456-ghi789-jkl012-mno345 report.pdf
Output:
🔍 Verifying upload of: report.pdf
Remote UUID: abc123-def456-ghi789-jkl012-mno345
📊 Hashing local file...
📋 Fetching metadata from server...
✅ Verification successful - hashes match!
Download Examples #
Download by path:
dart filen.dart dl /Documents/Report.pdf
Download by UUID:
dart filen.dart dl a8a8a36f-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Download folder recursively with timestamps:
dart filen.dart download-path /Projects/MyApp -r -p
Download only newer files:
dart filen.dart download-path /Photos -r \
--on-conflict newer -p -t ~/Downloads/Photos
Resume interrupted download:
# If download was interrupted, run the same command again
dart filen.dart download-path /LargeBackup -r
# Skips completed files, resumes from interruption point
Search & Find #
Search across entire drive:
dart filen.dart search "invoice"
Find all PDFs in Documents:
dart filen.dart find /Documents "*.pdf"
Find images with depth limit:
dart filen.dart find / "*.jpg" --maxdepth 3
Find with verbose output:
dart filen.dart find / "*.mp3" --maxdepth 2 -v
Move & Rename #
Rename a file:
dart filen.dart rename /Photos/IMG_001.jpg vacation_start.jpg
Move to different folder:
dart filen.dart mv /Photos/vacation_start.jpg /Photos/2024/
Move and rename simultaneously:
dart filen.dart mv /Photos/old_name.jpg /Archive/archived_photo.jpg
Trash Operations #
Move to trash:
dart filen.dart rm /OldFiles/temp.txt
List trash with full UUIDs:
dart filen.dart list-trash --uuids
Restore from trash by name:
dart filen.dart restore-path "important.doc" -t /Recovered
Restore from trash by UUID:
dart filen.dart restore-uuid abc123-def456-... -t /Documents
Permanently delete (with confirmation):
dart filen.dart delete-path /OldFiles/junk.txt
# Prompts: ⚠️ WARNING: This will PERMANENTLY delete...
Force delete (skip confirmation):
dart filen.dart delete-path /OldFiles/junk.txt -f
WebDAV Server Examples #
Start WebDAV server in foreground:
dart filen.dart webdav-start
# Server runs until Ctrl+C
Start WebDAV server in background:
dart filen.dart webdav-start -b
# Output:
# ✅ WebDAV server started in background (PID: 12345)
# URL: http://localhost:8080/
# User: filen
# Pass: filen-webdav
Start on custom port:
dart filen.dart webdav-start -b --port 9090
Check server status:
dart filen.dart webdav-status
# Output:
# ✅ WebDAV server is running in background.
# PID: 12345
# URL: http://localhost:8080/
Test server connection:
dart filen.dart webdav-test
# Output:
# ✅ Connection successful! (Received 207 Multi-Status)
Show mount instructions:
dart filen.dart webdav-mount
Stop background server:
dart filen.dart webdav-stop
WebDAV Mounting #
macOS (Finder):
# 1. Start server
dart filen.dart webdav-start -b
# 2. In Finder, press Cmd+K
# 3. Enter: http://localhost:8080
# 4. Username: filen
# 5. Password: filen-webdav
Windows (File Explorer):
# 1. Start server
dart filen.dart webdav-start -b
# 2. Open File Explorer
# 3. Right-click "This PC" → "Map network drive"
# 4. Enter: http://localhost:8080
# 5. Check "Connect using different credentials"
# 6. Username: filen
# 7. Password: filen-webdav
Linux (davfs2):
# 1. Install davfs2
sudo apt install davfs2
# 2. Start server
dart filen.dart webdav-start -b
# 3. Mount
sudo mkdir -p /mnt/filen
sudo mount -t davfs http://localhost:8080 /mnt/filen
# Enter username: filen
# Enter password: filen-webdav
# 4. Access your files
cd /mnt/filen
ls -la
Advanced Workflows #
Large file upload with verification:
# Upload large file
dart filen.dart up movie.mp4 /Videos
# Output shows UUID, copy it, then verify
dart filen.dart verify /Videos/movie.mp4 movie.mp4
Backup with resume support:
# Start backup
dart filen.dart up ~/Documents /Backup/Documents -r -p
# If interrupted by network failure, resume with same command
dart filen.dart up ~/Documents /Backup/Documents -r -p
# Completed files are skipped, interrupted file resumes from last chunk
Selective sync with patterns:
# Upload only source code, exclude builds
dart filen.dart up ~/Projects/MyApp /Code/MyApp -r \
--include "*.dart" --include "*.yaml" \
--exclude "build/*" --exclude ".dart_tool/*"
Compare and sync only newer files:
# Upload only files newer than remote
dart filen.dart up ~/Sync /Cloud/Sync -r -p --on-conflict newer
# Download only files newer than local
dart filen.dart download-path /Cloud/Sync -r -p --on-conflict newer
WebDAV + CLI hybrid workflow:
# 1. Start WebDAV for browsing
dart filen.dart webdav-start -b
# 2. Browse via file explorer (mounted at http://localhost:8080)
# 3. Use CLI for bulk operations
dart filen.dart up ~/LargeBackup /Backups -r -p
# 4. Verify critical files
dart filen.dart verify /Backups/important.zip ~/LargeBackup/important.zip
# 5. Stop WebDAV when done
dart filen.dart webdav-stop
Debug path resolution:
dart filen.dart resolve /Documents/SubFolder/file.pdf
# Shows full metadata and UUID
🗂️ Configuration #
Storage Locations #
Credentials:
- macOS/Linux:
~/.filen-cli/credentials.json - Windows:
%USERPROFILE%\.filen-cli\credentials.json
Batch State Files:
- macOS/Linux:
~/.filen-cli/batch_states/ - Windows:
%USERPROFILE%\.filen-cli\batch_states\
WebDAV PID File:
- macOS/Linux:
~/.filen-cli/webdav.pid - Windows:
%USERPROFILE%\.filen-cli\webdav.pid
State files enable chunk-level resume functionality. They contain:
- File UUIDs and upload keys
- Last successfully uploaded chunk number
- Operation status (pending, uploading, interrupted, completed)
- Automatically deleted when operations complete successfully
View Configuration #
dart filen.dart config
Shows:
- Config directory path
- Credentials file location
- Batch state directory
- WebDAV PID file location
- API endpoints (gateway, ingest, egest)
WebDAV Configuration #
Default settings:
- Host:
localhost - Port:
8080 - Username:
filen - Password:
filen-webdav - Protocol: HTTP (no SSL in current version)
View WebDAV config:
dart filen.dart webdav-config
🔧 Troubleshooting #
Resume Interrupted Operations #
If an upload or download is interrupted (network failure, Ctrl+C, crash):
- Simply run the same command again
- The CLI will:
- Load the previous batch state
- Skip already completed files
- Resume interrupted file from last successful chunk
- Continue uploading remaining files
Example:
# Upload interrupted at chunk 50/200
dart filen.dart up bigfile.zip /Backups
^C # Interrupted
# Resume - continues from chunk 51
dart filen.dart up bigfile.zip /Backups
# Output: 📤 Resuming: bigfile.zip from chunk 51 (...)
WebDAV Troubleshooting #
Server won't start:
# Check if already running
dart filen.dart webdav-status
# If stuck, stop it
dart filen.dart webdav-stop
# Clear stale PID file if needed
rm ~/.filen-cli/webdav.pid
# Try again
dart filen.dart webdav-start -b
Can't connect to server:
# Test connection
dart filen.dart webdav-test
# Check if server is running
dart filen.dart webdav-status
# Try different port if 8080 is busy
dart filen.dart webdav-start -b --port 9090
Port already in use:
# Use custom port
dart filen.dart webdav-start -b --port 9090
Authentication fails on mount:
- Username:
filen - Password:
filen-webdav - Make sure to enter exactly as shown (case-sensitive)
Clear Batch States #
If you want to force a fresh start (ignoring previous state):
# Remove all batch state files
rm -rf ~/.filen-cli/batch_states/
# Or remove specific batch
rm ~/.filen-cli/batch_states/batch_state_<batch-id>.json
Verify Upload Integrity #
After uploading important files, verify they arrived correctly:
# By path (easiest)
dart filen.dart verify /path/to/remote/file.pdf local/file.pdf
# By UUID (if you saved it from upload output)
dart filen.dart verify abc123-def456-... local/file.pdf
This compares SHA-512 hashes without downloading the file.
Debug Mode #
Enable verbose output to troubleshoot issues:
dart filen.dart up file.pdf /Documents -v
Shows:
- API requests and responses
- Crypto operations (encryption, hashing)
- Cache operations
- Chunk upload progress
- State save operations
- Error stack traces
Common Issues #
"Not logged in" error:
dart filen.dart login
"Path not found" error:
# Verify path exists
dart filen.dart ls /Documents
# Or resolve to see details
dart filen.dart resolve /Documents/file.pdf
Stale cache issues:
# Cache auto-invalidates, but you can force refresh by waiting 10 minutes
# Or trigger invalidation by modifying the folder (upload/delete/move)
Upload shows wrong progress:
# This happens if resuming - it re-hashes previous chunks first
# Progress bar starts from resume point, not from 0%
WebDAV server process orphaned:
# Find and kill manually
ps aux | grep filen.dart
kill <PID>
# Clear PID file
rm ~/.filen-cli/webdav.pid
🏗️ Architecture #
Key Components #
- FilenCLI: Command-line interface and argument parsing
- FilenClient: API client with caching, retry logic, and crypto operations
- ConfigService: Credential and batch state management
- DigestSink: Helper for SHA-512 hash calculation
- InternxtFileSystem: Virtual filesystem implementation for WebDAV
- ShelfDAV: WebDAV protocol handler
Technical Features #
- Caching: 10-minute TTL for folder/file listings, invalidated on mutations
- Retry Logic: Exponential backoff (1s, 2s, 4s) for network/5xx errors
- Conflict Detection: Handles 409 errors with automatic re-fetch and delay
- Batch Processing: State-based resumable operations with chunk-level granularity
- Hash Calculation: Continuous SHA-512 hashing across upload sessions
- Parent Cache Invalidation: Automatic cache clearing on file/folder mutations
- WebDAV Virtual FS: FUSE-like filesystem layer for WebDAV access
Upload Process #
- File chunked into 1MB pieces
- Each chunk encrypted with random file key
- SHA-512 hash calculated as chunks upload
- Progress saved every 10 chunks or 5 seconds
- On interruption: UUID, upload key, and last chunk saved
- On resume: Same UUID/key used, continue from next chunk
- Hash recalculated from beginning (fast read-only pass)
- Upload completed: Hash stored in encrypted metadata
WebDAV Architecture #
- Virtual Filesystem: Maps Filen paths to WebDAV resources
- On-Demand Loading: Folders/files fetched as accessed
- Write-Through Caching: Changes immediately sync to Filen
- Authentication: Basic auth with hardcoded credentials
- Locking Support: WebDAV locking for concurrent access
🔐 Security #
- End-to-End Encryption: All files encrypted client-side before upload
- Zero-Knowledge: Master keys never leave your device
- Secure Storage: Credentials stored in user home directory (chmod 600 recommended)
- 2FA Support: Optional two-factor authentication
- No Password Storage: Only encrypted credentials stored
- WebDAV Security:
- HTTP only (no SSL in current version) - use only on trusted networks
- Basic authentication (credentials sent in headers)
- Recommended for localhost access only
🚧 Known Limitations #
WebDAV #
- No SSL/TLS: HTTP only, not recommended for remote access
- Concurrent Access: Limited locking support
- Hardcoded Credentials: Username/password cannot be customized (yet)
General #
- File Size: Very large files may encounter memory issues
- Windows WebDAV: May require registry tweaks for large files
🧪 Development & Testing #
The library is split into focused modules under lib/ (crypto, api,
auth, cache, drive, upload, download, config, paths,
webdav_filesystem, …) behind the FilenClient facade, with a unit test per
module under test/.
Run the unit tests (no network, no credentials):
dart pub get
dart analyze --fatal-infos
dart test --exclude-tags=live
Coverage (per-file thresholds in tool/check_coverage.dart):
dart test --coverage=coverage --exclude-tags=live
dart pub global activate coverage
dart pub global run coverage:format_coverage \
--lcov --in=coverage --out=coverage/lcov.info --report-on=lib
dart run tool/check_coverage.dart coverage/lcov.info
Live tests run against a real Filen account. They authenticate via
FILEN_EMAIL / FILEN_PASSWORD, or fall back to a saved CLI session
(~/.filen-cli/credentials.json, overridable with FILEN_CREDENTIALS). They
are confined to a sentinel folder and clean up on teardown. The live tag is
skipped by default, so force it explicitly:
FILEN_EMAIL=you@example.com FILEN_PASSWORD=secret \
dart test --tags live --run-skipped
# or, reusing an existing CLI login:
dart test --tags live --run-skipped
CI (.github/workflows/ci.yml) runs on push/PR to main: analyze
(--fatal-infos + dart format check), test (unit tests + coverage report),
and compile (binary build + help smoke check). Live tests are excluded in
CI.
📄 License #
This project is licensed under the Mozilla Public License 2.0 (MPL-2.0) — weak copyleft: modifications to these files stay open, but you can use it in any app (including proprietary). See the LICENSE file for details.
⚠️ Disclaimer #
This is an unofficial tool and is not affiliated with Filen.io.
- Use at your own risk
- Always maintain backups of critical data
- Test operations on non-critical files first
- Verify important uploads using the
verifycommand - WebDAV server is experimental - use with caution
- We assume no liability for data loss or corruption