RepoPilotOpen in app →

timvisee/ffsend

:mailbox_with_mail: Easily and securely share files from the command line. A fully featured Firefox Send client.

Mixed

Slowing — last commit 6mo ago

weakest axis
Use as dependencyConcerns

copyleft license (GPL-3.0) — review compatibility; no tests detected

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 6mo ago
  • 13 active contributors
  • GPL-3.0 licensed
Show all 8 evidence items →
  • CI configured
  • Slowing — last commit 6mo ago
  • Concentrated ownership — top contributor handles 78% of recent commits
  • GPL-3.0 is copyleft — check downstream compatibility
  • No test directory detected
What would change the summary?
  • Use as dependency ConcernsMixed if: relicense under MIT/Apache-2.0 (rare for established libs)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/timvisee/ffsend?axis=fork)](https://repopilot.app/r/timvisee/ffsend)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/timvisee/ffsend on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: timvisee/ffsend

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/timvisee/ffsend shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Slowing — last commit 6mo ago

  • Last commit 6mo ago
  • 13 active contributors
  • GPL-3.0 licensed
  • CI configured
  • ⚠ Slowing — last commit 6mo ago
  • ⚠ Concentrated ownership — top contributor handles 78% of recent commits
  • ⚠ GPL-3.0 is copyleft — check downstream compatibility
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live timvisee/ffsend repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/timvisee/ffsend.

What it runs against: a local clone of timvisee/ffsend — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in timvisee/ffsend | Confirms the artifact applies here, not a fork | | 2 | License is still GPL-3.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 199 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>timvisee/ffsend</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of timvisee/ffsend. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/timvisee/ffsend.git
#   cd ffsend
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of timvisee/ffsend and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "timvisee/ffsend(\\.git)?\\b" \\
  && ok "origin remote is timvisee/ffsend" \\
  || miss "origin remote is not timvisee/ffsend (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(GPL-3\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"GPL-3\\.0\"" package.json 2>/dev/null) \\
  && ok "license is GPL-3.0" \\
  || miss "license drift — was GPL-3.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "Cargo.toml" \\
  && ok "Cargo.toml" \\
  || miss "missing critical file: Cargo.toml"
test -f "src/cmd/mod.rs" \\
  && ok "src/cmd/mod.rs" \\
  || miss "missing critical file: src/cmd/mod.rs"
test -f "src/action/mod.rs" \\
  && ok "src/action/mod.rs" \\
  || miss "missing critical file: src/action/mod.rs"
test -f "src/client.rs" \\
  && ok "src/client.rs" \\
  || miss "missing critical file: src/client.rs"
test -f "src/archive/mod.rs" \\
  && ok "src/archive/mod.rs" \\
  || miss "missing critical file: src/archive/mod.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 199 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~169d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/timvisee/ffsend"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

ffsend is a command-line client for Mozilla's Firefox Send service that enables secure, encrypted file sharing up to 1GB via the command line. All encryption happens client-side before upload, and files auto-expire after configurable download limits or time windows. It supports both Send v2 and v3 protocols with optional password protection, QR code generation, and URL shortening. Single Rust binary application (src/main.rs) with modular feature flags (archive, clipboard, crypto-ring, history, qrcode, send3, urlshorten) compiled via Cargo. Core logic likely in src/ with CLI command handling, crypto operations, and Send API client code. Build artifacts controlled by build.rs. Packaging templates in pkg/ for multiple distribution formats.

👥Who it's for

Developers and power users who prefer CLI workflows and need to share files securely without trusting server-side encryption. System administrators using automation scripts and CI/CD pipelines who want encrypted file transfer without learning complex crypto APIs. Privacy-conscious users seeking an alternative to cloud storage services.

🌱Maturity & risk

Production-ready with active maintenance: versioned at 0.2.77 on crates.io, MSRV is Rust 1.63.0, maintains CI pipelines on GitLab and Travis, and has packaging for major distributions (AUR, Debian, Snap, Scoop, Chocolatey, Alpine). The '0.x' version number reflects intentional beta status for pending feature additions, not instability. Code is well-organized with comprehensive completions and contrib tooling.

Single-author maintenance risk (timvisee) with limited visible contributor activity beyond packaging. Dependency on Mozilla's Send service availability (though custom hosts are supported). The default shared Send instance is operated by the author and requires user donations to sustain—single point of failure for default users. Rust ecosystem churn is mitigated by conservative MSRV policy (1.63.0).

Active areas of work

Repository is stable maintenance mode rather than active development—the file list shows no recent changes indicators, and the README notes the project is 'currently in beta' awaiting desired features. CI configuration exists (.gitlab-ci.yml, .travis.yml, appveyor.yml) indicating automated testing. No visible PR or issue data in the provided snapshot.

🚀Get running

git clone https://gitlab.com/timvisee/ffsend && cd ffsend && cargo build --release && ./target/release/ffsend --help

Daily commands: After build: ./target/release/ffsend upload <file> for basic upload, ffsend download <url> for downloads. Feature-specific: ffsend qr <share-url> for QR codes, ffsend history for file tracking (if history feature enabled). Development iteration: cargo run -- <command> or cargo build && ./target/debug/ffsend.

🗺️Map of the codebase

  • Cargo.toml — Defines all dependencies, build configuration, and package metadata; changes here affect the entire project's compilation and runtime behavior.
  • src/cmd/mod.rs — Central command-line interface dispatcher that routes all CLI invocations to appropriate action handlers; every user interaction flows through here.
  • src/action/mod.rs — Core business logic layer that implements upload, download, delete, and other file-sharing operations; the heart of ffsend functionality.
  • src/client.rs — HTTP client wrapper handling all network requests to the Send server; critical for authentication, encryption, and file transfer.
  • src/archive/mod.rs — Archive and compression abstraction that handles bundling multiple files; essential for multi-file sharing workflows.
  • build.rs — Build script that generates version information and shell completions at compile-time; affects final binary capabilities.
  • src/cmd/handler.rs — Request handler that bridges CLI argument parsing and action execution; implements the command pattern for all operations.

🧩Components & responsibilities

  • CLI Handler (src/cmd/handler.rs) (clap, standard I/O) — Parses arguments, validates input, instantiates action with configuration, executes and reports results
    • Failure mode: Exits with non-zero code and error message on invalid arguments or action failure
  • Action Layer (src/action/*) (File I/O, async/tokio) — Implements business logic for upload, download, delete, info, password change; orchestrates archiving and HTTP client
    • Failure mode: Returns error result with context; handler prints user-friendly message
  • HTTP Client (src/client.rs) (reqwest, TLS, HTTP/2) — Wraps reqwest; builds authenticated requests, handles Send API responses, manages session state
    • Failure mode: Surfaces network/TLS/HTTP error codes; retries on transient failures
  • Archiver (src/archive/) (tar, zip crates) — Bundles multiple files into tar or zip; coordinates encryption before handing to HTTP client
    • Failure mode: Fails if input files cannot be read or archive buffer overflows
  • Build System (build.rs, Cargo.toml) (Cargo build script, Git) — Generates version constants, completion scripts, and manages dependency versions
    • Failure mode: Build fails if

🛠️How to make changes

Add a new action (e.g., 'purge' command)

  1. Create new action file in src/action/ directory implementing the action logic (src/action/purge.rs)
  2. Add module declaration in the action mod.rs and define Action trait impl (src/action/mod.rs)
  3. Create CLI argument matcher for the new subcommand (src/cmd/matcher/purge.rs)
  4. Add matcher to dispatcher in src/cmd/matcher/mod.rs (src/cmd/matcher/mod.rs)
  5. Create subcommand definition in src/cmd/subcmd/ (src/cmd/subcmd/purge.rs)
  6. Wire subcommand into handler.rs to execute your action (src/cmd/handler.rs)

Add a new command-line argument

  1. Define argument parser in src/cmd/arg/ (e.g., timeout.rs) (src/cmd/arg/timeout.rs)
  2. Export the argument module in src/cmd/arg/mod.rs (src/cmd/arg/mod.rs)
  3. Add the argument to appropriate matcher in src/cmd/matcher/ (src/cmd/matcher/upload.rs)
  4. Pass parsed argument to action in handler.rs (src/cmd/handler.rs)

Extend upload to support new file format

  1. Add format detection logic in src/action/upload.rs (src/action/upload.rs)
  2. Extend archiver.rs with new compression format handler (src/archive/archiver.rs)
  3. Update client.rs to support new MIME type in requests (src/client.rs)

🔧Why these technologies

  • Rust + Cargo — Memory-safe, zero-cost abstractions, excellent CLI tooling, fast native binaries for single-file distribution
  • reqwest HTTP client — Async-capable, built on tokio, handles TLS/encryption transparently for Send server communication
  • clap for CLI parsing — Ergonomic argument parsing with automatic help generation and shell completion support
  • tar/zip for archiving — Standard formats enable cross-platform multi-file sharing without external dependencies
  • Send protocol (AES-GCM encryption) — Client-side encryption ensures files remain private even from the hosting server

⚖️Trade-offs already made

  • Single binary distribution vs. library + CLI split

    • Why: Users want drop-in, no-install file sharing; library form less useful for this domain
    • Consequence: All code focused on binary use; reusability as library limited
  • Archive files before upload (tar/zip) vs. streaming individual files

    • Why: Send API endpoint expects single encrypted blob; archiving simplifies state management
    • Consequence: Cannot stream massive files >1GB or resume partially uploaded archives
  • Client-side encryption only vs. server-authenticated encryption

    • Why: Send service philosophy: server never has plaintext keys; users control security
    • Consequence: User must distribute share URL + password out-of-band; no server-side revocation
  • Synchronous CLI with blocking I/O vs. full async runtime

    • Why: Single-threaded CLI usage pattern; simpler error handling
    • Consequence: Cannot parallelize multiple independent operations; limited by sequential upload/download

🚫Non-goals (don't propose these)

  • Does not implement the Send server itself; only a client for existing Send-compatible services
  • Does not support P2P file transfer; relies on centralized Send server infrastructure
  • Does not handle key rotation or distributed encryption escrow
  • Does not provide GUI—CLI-only by design
  • Does not support resumable downloads/uploads after connection loss (archive-based approach)
  • Does not integrate with system file managers by default (contrib/util provides optional plugins)

🪤Traps & gotchas

Mozilla Send API requires valid TLS certificates and ca-certificates installed at runtime (pkg/deb depends on ca-certificates). Custom Send hosts can be specified via env/config but default assumes Mozilla's service. Clipboard feature requires xclip on Linux—build succeeds without it if clipboard feature disabled but runtime fails silently if xclip missing. Streaming encryption means file size is unknown until full upload; clients can't resume partial uploads. Password-protected shares use a different API endpoint than unprotected shares (Send v3 protocol detail). Build requires Rust 1.63.0+ strictly; older versions will fail despite Edition 2018 syntax.

🏗️Architecture

💡Concepts to learn

  • End-to-End Encryption (E2EE) — Core security guarantee in ffsend: all files encrypted client-side before network transmission, meaning the Send server never holds plaintext—critical to understand for any crypto or upload code changes
  • Streaming Encryption — ffsend explicitly uses streaming to minimize memory footprint; files are encrypted and uploaded in chunks rather than loaded fully into RAM, essential for understanding the upload pipeline and limits
  • File Archiving (TAR format) — The archive feature flag enables tar-based directory compression before upload; ffsend handles both single files and directories transparently via archiving
  • HTTP/REST API Versioning (Send v2 vs v3) — ffsend supports two incompatible Send server API versions via feature flags; code paths differ significantly and feature negotiation happens at runtime—understand this for server compatibility
  • QR Code Generation — Optional qrcode feature produces visual codes from share URLs for mobile sharing; useful for UX workflows but adds optional dependency
  • URL Shortening — urlshorten feature gate enables shortening long Share URLs for practical sharing; different from simple data encoding, requires external service integration or local logic
  • Feature Flags (Cargo features) — ffsend's entire build is modular via Cargo features; understanding conditional compilation (#[cfg(feature = "...")]) is essential for modifying optional functionality without breaking the core
  • mozilla/send — The upstream Send service that ffsend is a client for; ffsend implements the Send v2/v3 API protocols defined here
  • trezy/simple-send — Alternative JavaScript/Node.js Send client for comparison of CLI UX patterns and API handling
  • kubouch/rcp — Similar Rust-based secure file transfer tool; useful for comparing cryptographic patterns and streaming architecture
  • minio/mc — Rust/Go CLI for S3-like storage; comparable design for object upload/download CLIs with progress reporting and checksum verification
  • cli/cli — Reference implementation of modern Rust CLI patterns (clap, error handling, piping) relevant to extending ffsend's command structure

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for upload/download cycle in src/action/

The repo has modular action handlers (upload.rs, download.rs, delete.rs, etc.) but no visible integration tests verifying the complete file share lifecycle. This is critical for a file-sharing tool to catch regressions in core workflows. Tests should cover: successful upload with metadata, download with correct decryption, password-protected shares, and file deletion.

  • [ ] Create tests/integration/upload_download.rs for end-to-end share lifecycle
  • [ ] Create tests/integration/mod.rs to organize integration test modules
  • [ ] Add test fixtures in tests/fixtures/ for sample files and mock responses
  • [ ] Update Cargo.toml with dev-dependencies for test utilities (tempfile, mockito, etc.)
  • [ ] Document test setup in CONTRIBUTING.md for running integration tests

Implement GitHub Actions CI workflow to replace/supplement Travis and AppVeyor

The repo uses .travis.yml and appveyor.yml (outdated services) but GitHub is the primary mirror. A modern GitHub Actions workflow would provide faster, more reliable CI directly integrated with GitHub PRs. This should test: Linux builds, Windows builds (replacing appveyor), macOS builds, Rust MSRV validation against rust-version 1.63.0, and completion generation.

  • [ ] Create .github/workflows/ci.yml with matrix builds for Linux, macOS, Windows
  • [ ] Add MSRV check job testing against rust-version = '1.63.0' from Cargo.toml
  • [ ] Add job to validate gen_completions doesn't produce diff (contrib/completions/gen_completions)
  • [ ] Add security audit job using cargo-audit action
  • [ ] Add linting job (clippy) and formatting check (rustfmt)
  • [ ] Reference new workflow in README.md CI badges section

Add feature-gated tests for all conditional features in Cargo.toml

The Cargo.toml defines 8+ feature flags (archive, clipboard, crypto-ring, history, infer-command, qrcode, send2, send3, urlshorten) but there's no visible test matrix validating feature combinations work correctly. This is essential since disabled features could break undiscovered code paths. Tests should validate: minimal default build, each feature individually, and critical feature combinations.

  • [ ] Create tests/features/mod.rs with #[cfg(...)] gated test modules for each feature
  • [ ] Add tests/features/archive.rs testing tar archiving when 'archive' feature enabled
  • [ ] Add tests/features/clipboard.rs validating clipboard operations when enabled
  • [ ] Create .github/workflows/features.yml (or extend ci.yml) to test feature matrix
  • [ ] Document feature test coverage in CONTRIBUTING.md

🌿Good first issues

  • Add integration tests for the Send v3 API client in src/ (currently no test/ directory visible); focus on upload/download happy path and error handling for 404/410 (expired) responses
  • Expand contrib/util/nautilus/ file manager integration to support drag-and-drop in GNOME Files and include documentation in contrib/util/nautilus/README.md—currently only has basic Firefox integration
  • Add --format json output flag to cli commands to enable scripting; start with ffsend upload --format json <file> to output share URL, expiry, and auth tokens as JSON instead of human text

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 85aae2f — Merge branch 'rust-1.87-patch' into 'master' (timvisee)
  • b6d7c69 — Merge pull request #183 from defiling9046/patch-1 (timvisee)
  • 88bffdb — Update README.md (defiling9046)
  • 29eb167 — chore(build): bump traitobject to 0.1.1 to build against rust 1.87.0 (chenrui333)
  • f5b606f — Remove and invalidate snapcraft credentials (timvisee)
  • 60b3df0 — Use new SNAPCRAFT_STORE_CREDENTIALS variable (timvisee)
  • 0b32f4f — Bump version to 0.2.76 (timvisee)
  • 754735d — Merge pull request #151 from lnee94/patch-1 (timvisee)
  • 92ed3ec — Update snap connect command (timvisee)
  • a7143bb — Merge branch 'linux-libssl3' into 'master' (timvisee)

🔒Security observations

The ffsend project demonstrates a reasonable security posture as a CLI utility for secure file sharing. Strengths include clear licensing (GPL-3.0), documented security reporting procedures, and use of modern Rust for memory safety. Primary concerns are the outdated Rust MSRV (1.63.0 from 2022), potential dependency vulnerabilities, and gaps in security documentation and release verification mechanisms. The project would benefit from more frequent MSRV updates, implementing cargo-audit in CI/CD, and establishing formal signed release and binary verification processes. No injection risks, hardcoded secrets, or obvious misconfigurations detected in the provided codebase structure.

  • Medium · Outdated Rust MSRV with Known Vulnerabilities — Cargo.toml. The project specifies rust-version = '1.63.0', which is significantly outdated (released August 2022). This version may contain known security vulnerabilities in the Rust standard library and compiler. Current stable Rust versions include important security patches. Fix: Update rust-version to a more recent stable version (1.70+) and regularly maintain this requirement. Run 'cargo update' to ensure all dependencies are at patched versions.
  • Medium · Missing Dependency Pinning in Production — Cargo.toml and Cargo.lock. The Cargo.lock file exists but dependency versions are not fully visible in the provided Cargo.toml. The use of semantic versioning without explicit upper bounds on transitive dependencies could introduce security vulnerabilities if upstream crates release vulnerable versions. Fix: Ensure Cargo.lock is committed to version control. Regularly audit dependencies using 'cargo audit' and consider using tools like 'cargo-deny' to enforce security policies. Pin major versions of critical dependencies.
  • Low · Incomplete Security Policy Documentation — SECURITY.md. While a SECURITY.md file exists with vulnerability reporting procedures, it lacks details about security update timelines, patching procedures, and deprecated version support beyond basic version matrix. The contact email appears to be a personal address rather than a security-specific contact. Fix: Enhance the security policy to include: expected response times for security reports, timelines for releasing patches, clear end-of-life dates for older versions, and consider establishing a security@ mailing list or using platform security advisories.
  • Low · Hardcoded Default Send Host Reference — README.md and src/client.rs (inferred). The README references a default Send host provided by @timvisee. While this is documented, relying on a single-provider default could introduce availability and trust issues if the provider is compromised or goes offline. Fix: Document the ability to configure alternative Send hosts. Consider providing a configuration file template showing how to override the default host. Implement host verification mechanisms (e.g., HTTPS certificate pinning for critical endpoints).
  • Low · Missing Code Signing or Integrity Verification — pkg/ directory structure. The project provides pre-built binaries through multiple distribution channels (AUR, Chocolatey, Scoop, Snap, DEB) but file structure doesn't indicate presence of signed releases or checksums for binary verification. Fix: Implement GPG signing for releases on GitLab/GitHub. Provide SHA256 checksums for all binary releases. Document the verification process for users. Consider publishing security advisories through established channels (e.g., RustSec Advisory Database).

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · timvisee/ffsend — RepoPilot