Skip to content

Simple, self-hostable filesharing application with builtin end-to-end encryption

License

Notifications You must be signed in to change notification settings

TobiasMarschner/ferrishare

Repository files navigation

FerriShare

FerriShare is a simple, self-hostable and open-source
filesharing application with builtin end-to-end-encryption

Features

  • Securely share files with anyone using a simple drag-and-drop upload-page in your browser
    • Files and filenames are encrypted in your browser before being uploaded, and the key is stored in the download link's fragment (the part after the #), which is never sent to the server
    • The server cannot decrypt or view the contents of the file
    • Files automatically expire after a chosen duration (1 hour, 1 day or 1 week)
    • Uploaders receive two links: A public download link and a private administration link
      • The latter shows download statistics and allows the uploader to delete a file early
  • Builtin IP-based rate limiting
    • Dual-stack support: Uses either a full IPv4 address or a client's /64 IPv6 subnet
    • Limits the maximum number of uploads per IP (can be configured)
    • Limits the maximum number of HTTP requests per IP (can be configured)
  • Configurable limits for maximum filesize and maximum storage quota
  • Password-protected site-wide administration panel
    • shows total usage statistics and allows for early file deletion
  • Configurable Privacy Policy (with default template) and Legal Notice, if you need those.
  • Fast, efficient and memory-safe backend written entirely in Rust, powered by tokio, axum, tera and sqlx
  • SQLite-database for metadata storage, allowing you to deploy the entire application in a single container
  • Accessible frontend with a 400 Lighthouse Score
    • Templating is performed on the backend. JavaScript is only used when necessary.
    • Best practices: Font subsetting, permanent caching for static assets, response compression, ...

✨ Demo and Screenshots

You can test FerriShare on the official demo instance!

Left to right: Upload Page, Public Download Page, Private Admin Page

Screenshot of an uploaded file's admin page

Site-wide Administration Panel

Screenshot of an uploaded file's admin page

📥 Installation and Configuration

Warning

While I have taken great care to correctly deploy the cryptographic primitives used in this project, I am not an expert in cryptography and this project has not been independently audited.

I cannot guarantee that the implementation or design of the system is secure.
You can review the cryptographic architectural notes provided further below, or directly examine the code responsible for encrypting and decrypting files.

If you spot any issues, please let me know in the project's issue tracker.

FerriShare must be run behind a reverse proxy. There are two major reasons for this:

  1. To encrypt files the frontend makes use of the WebCrypto-API, which requires a secure context.
    • This means the application must be serverd via HTTPS or on localhost.
  2. Providing a robust and configurable TLS backend is non-trivial, and out of scope for FerriShare.

Commonly used reverse-proxies include Traefik, Caddy and nginx.
In the instructions presented below we will be using a very simple Traefik setup.

With Docker (recommended)

Architecture Support

The repository provides prebuilt Docker images on GitHub's Container Registry for the following architectures:

  • amd64 a.k.a. x86_64 for Intel and AMD processors
  • arm64 a.k.a. 64-bit ARMv8 for modern ARM servers or SBCs (e.g. Raspberry Pis)
  • arm/v7 a.k.a. 32-bit ARMv7 for older ARM processors (e.g. older Raspberry Pis)

If your architecture is not on the list, you'll have to build the image yourself.

Setup Instructions

  1. Ensure both Docker and Docker Compose are setup and working on your machine.
    • Both rootful and rootless variants are supported
  2. Create a folder for the application on your machine and cd into it.
    • For example: mkdir ferrishare; cd ferrishare
  3. Download a copy of the repository's docker-compose.yml into said folder
    • In it is an example setup hosting FerriShare behind Traefik on localhost. The compose-file is commented to help you better understand how to adapt it to your needs.
  4. Download all of the images by invoking docker compose pull
  5. Configuration: Invoke docker compose run --rm -it ferrishare --init
    • This will start FerriShare's interactive configuration wizard that will guide you through all options and create all necessary files in the ./data-subdirectory.
    • You can re-run this wizard later in case you wish to reconfigure the app. It does not touch the database or uploaded files. The templates in ./data/user_templates will only be created if they do not already exist.
  6. Launch: Invoke docker compose up to launch the app in the foreground
    • Alternatively: Use docker compose up -d to run the containers in the background
  7. Test it out: Use your favorite web browser to navigate to localhost:3000

From Source

Refer to the building locally from source instructions provided further down.

Architectural Notes

FerriShare is built as a traditional Multi-Page Application (MPA) where templating is performed fully on the backend. In that sense there is no real separation of frontend and backend, they're intertwined. JavaScript is only served where required, specifically the upload and download endpoints as that's where the client-side encryption takes place.

Repository Structure

Path Purpose
src/ Rust sources for the backend
templates/ HTML and JS template sources for the frontend
migrations/ Schema files for the application's SQLite database
font/ The project's latin and icon fonts -- check the folder's README for details
favicon/ The project's favicon -- check the folder's README for details
readme/ Screenshots and images for the README
Cargo.toml, Cargo.lock Rust project files defining dependencies and build behavior for the backend
package.json, package-lock.json npm project files used to setup the Tailwind CLI
main.tw.css, tailwind.config.js Main stylesheet and Tailwind config used to generate the CSS bundle
Dockerfile Protable build and packaging instructions (using multi-stage builds)
docker-compose.yml Example application setup with Traefik, useful for developement or as a quick start

Cryptography

  • Files are encyrpted with AES-GCM providing both confidentiality and integrity thanks to its AEAD nature.
  • The WebCrypto-API provided by the browser is used to actually perform the en- and decryption.
    • The key is generated with window.crypto.subtle.generateKey(...), which uses a strong CSPRNG.
    • IVs are chosen deterministically and are never reused.
      • Two messages are encrypted with the key: The filename, using IV 0, and the filedata, using IV 1.
  • The maximum safe message length with AES-GCM is 2^39 - 256 bits ≈ 64 GB.
    • However, the WebCrypto-API limits the maximum message length to just 2GiB.
    • This limit for the maximum filesize is enforced during configuration setup.

🛠️ Building Locally

With Docker (recommended)

The instructions for building FerriShare with Docker are almost the same as the normal installation and configuration instructions above, but with two main differences:

  • Instead of creating an empty folder, grab a copy of the source code. You have two options:
    • Go to the releases page, download the Source code archive for the release you want to run, extract it and cd into it.
    • Clone the repository and cd into it. Important: This repository uses Git LFS to store large binary assets. Make sure Git LFS is setup and installed on your machine before cloning.
  • Invoke docker compose build instead of docker compose pull.
    • This causes docker compose to build the ferrishare-image locally from the repository sources instead of pulling them from the online registry.

The provided Dockerfile uses multi-stage builds to both cache stages of the build-process and ensure the final image is as slim as possible. It uses cargo-chef to cache downloads and builds of all Rust dependencies, significantly speeding up subsequent builds of the application. The actual Dockerfile is properly commented, check it out to understand the full build process.

From Source

Don't want to use Docker? No problem.

You will need a Linux box, as all the instructions are written for a Linux machine. MacOS and Windows have not been tested, although the former might work.

  1. Make sure you have Rust and Node with npm setup on your machine.
  2. Grab a copy of the source code. You have two options:
    • Go to the releases page, download the Source code archive for the release you want to run, extract it and cd into it.
    • Clone the repository and cd into it. Important: This repository uses Git LFS to store large binary assets. Make sure Git LFS is setup and installed on your machine before cloning.
  3. Install all Node dependencies by invoking npm install
    • This installs the Tailwind CLI, which is required to build the CSS bundle of the app
  4. Build the CSS bundle by invoking npm run build:tw
    • If you prefer, you can also launch Tailwind's development server with npm run dev:tw
  5. Build the actual application with cargo build --release
  6. Configuration: Invoke cargo run --release -- --init (that -- in the middle is not a typo)
    • This will start FerriShare's interactive configuration wizard that will guide you through all options and create all necessary files in the ./data-subdirectory.
    • You can re-run this wizard later in case you wish to reconfigure the app. It does not touch the database or uploaded files. The templates in ./data/user_templates will only be created if they do not already exist.
  7. Launch: Invoke cargo run --release to launch the app in the foreground
    • Important: You're running and accessing the app directly without a reverse-proxy, which only works for local development. For this to work you must configure a proxy-depth of 0, otherwise FerriShare will refuse your HTTP requests.

Note that resources served on the /static/-endpoint are served with an infinite cache policy. During local development, you may want to disable browser caching to ensure your changes are always reflected in the browser.

Documentation

Installation is fully documented in this README.

Configuration is documented in FerriShare itself through its interactive configuration wizard that can be invoked with the --init-flag.

The source code itself is properly documented, but the docs aren't hosted online. If you'd like to browse the module-level documentation you can clone the repository and invoke cargo doc --no-deps --open, assuming Rust is setup on your system.

License and Contributing

FerriShare is released under the terms of the MIT License. Contributions are welcome!


Where does the name come from?
It's a simple portmanteau of 'Ferris', the Rust mascot, and 'share' from 'Fileshare'.