ffl-python
ffl-python is the Python binding for the FastFileLink
CLI (FFL), which turns a file, folder, or stream into a browser-ready HTTPS link so the
recipient can download it without installing anything. It prefers a direct QUIC/WebRTC P2P
connection and falls back to a relayed/tunneled HTTPS link, with optional end-to-end
encryption. See the FFL repository for the full protocol and CLI details.
The package bundles the portable ffl.com APE and runs it behind a Python API,
powered by APEBind,
so callers do not need to locate or install a separate FFL
Installation
pip install ffl-python
This installs the ffl package with the bundled ffl.com APE included -- no separate
FFL install or PATH setup required.
Development
python -m venv .venv
.venv/Scripts/python -m pip install -e ".[dev]" # Windows
# or: .venv/bin/python -m pip install -e ".[dev]"
.\scripts\test.ps1 # Windows
# or: ./scripts/test.sh # Linux/macOS
.\scripts\build.ps1 # Windows
# or: ./scripts/build.sh # Linux/macOS
Share
import ffl
with ffl.share("release.zip", max_downloads=1, timeout_seconds=1800) as session:
print(session.link)
share() always requests a foreground FFL process and disables clipboard side effects,
which gives library callers a deterministic ShareSession they can stop or keep alive.
FFL's runtime-owned --json output is used internally to wait until session.link is
ready.
Multiple files are accepted directly:
session = ffl.share(["one.txt", "two.txt"], name="files.zip")
Text and bytes helpers own their temporary file until the share session is closed:
with ffl.share_text("hello", name="hello.txt") as session:
print(session.link)
Stream a source without a temporary file
share_stream() passes a binary file-like object directly to FFL stdin. It is useful
for database dumps, generated artifacts, and other data that should not first be
materialized as a separate temporary file:
with open("backup.tar", "rb") as source:
with ffl.share_stream(source, name="backup.tar") as session:
print(session.link)
Events
session.on(name, listener) follows FFL's integrated events:
| Semantic name | FFL event |
|---|---|
ready |
/share/available |
started |
/transfer/create |
progress |
/transfer/progress |
completed |
/transfer/complete |
failed |
/transfer/fail |
HTTP, WebRTC, and direct P2P also emit their own events, such as
/download/complete. Those stay on session.on_raw(). completed follows
/transfer/complete, so one transfer notifies that listener once. Each accepted
hook POST is answered with HTTP 200 and {}.
The bundled ffl.com emits these names.
Download
result = ffl.download("https://example.fastfilelink/...", output_path="download.bin")
print(result.output_path)
print(result.transfer_mode)
download() waits for the foreground FFL process to finish and returns a
DownloadResult. For cancellation, progress, or caller-controlled timeouts, use
start_download() and manage its DownloadSession explicitly.
Stream a download
download_stream() exposes FFL stdout as binary chunks without buffering the whole
file in memory:
with ffl.download_stream("https://example.fastfilelink/...") as transfer:
with open("output.bin", "wb") as target:
for chunk in transfer.iter_bytes():
target.write(chunk)
result = transfer.wait()
Consume iter_bytes() through EOF before calling wait(). Calling wait() with
unconsumed streamed stdout raises RuntimeError; this avoids silently discarding
binary data or deadlocking when the child process fills its stdout pipe.
Authentication secrets
For shares protected with HTTP Basic Auth, FFL supports FFL_AUTH_PASSWORD. Set it in
the application environment and pass only auth_user to keep the password out of the
FFL command line:
export FFL_AUTH_PASSWORD='use-your-secret-manager'
$env:FFL_AUTH_PASSWORD = 'use-your-secret-manager'
with ffl.share("release.zip", auth_user="deploy") as session:
print(session.link)
Do not also pass auth_password= when using this pattern: FFL gives the explicit CLI
option precedence over FFL_AUTH_PASSWORD. The environment variable applies to the
sharing side; pass download credentials explicitly when downloading a protected link.
Key generation
result = ffl.keygen("alice")
print(result.public_key_path)
print(result.private_key_path)
Version and raw access
print(ffl.version())
result = ffl.raw(["download", "--help"])
raw() is the escape hatch for new FFL options or commands that the semantic API has
not adopted yet.
Compared to magic-wormhole
magic-wormhole is the other Python tool commonly reached for to move a file between two machines. Both are ad hoc, non-account-based transfers you can drive from Python, but they differ in shape:
- Binding vs. native library.
ffl-pythonis a subprocess wrapper around the separateffl.comCLI binary -- WebRTC/QUIC, NAT traversal, and relay/tunnel fallback all happen in that external process.wormholeis a native, in-process Python package (Twisted-based); no external binary is involved. In practice, though, wormhole's own file-transfer path is also driven through its CLI machinery rather than a stable public library call --wormhole.create()covers generic message exchange, not file transfer directly. - Recipient experience. An FFL share is an HTTPS link: the recipient opens it in a
browser and downloads, no install required. A wormhole transfer is a short code
(e.g.
7-crossbow-clockwork) exchanged out-of-band; the recipient needs thewormholeCLI installed to redeem it. - Transport. FFL tries a direct WebRTC/QUIC P2P connection first, falls back to a plain P2P TCP connection, and falls back again to a relayed/tunneled HTTPS link if no P2P path is reachable at all. wormhole's own transit protocol does direct TCP with a relay fallback, with the connection authenticated by a SPAKE2 PAKE key derived from the code.
- Security default. wormhole is end-to-end encrypted on every transfer by
construction of the code exchange. FFL's end-to-end encryption is opt-in (
--e2ee); without it, data in transit is only as protected as the HTTPS connection to FFL's relay/tunnel infrastructure. - Feature surface. FFL adds application-layer conveniences wormhole doesn't have: a
secondary pickup-code/public-key recipient check layered on top of the link,
receipt-confirmation emails, a pluggable choice of tunnel backend when P2P isn't
reachable (built-in
default, plus Cloudflare, ngrok, Localtunnel, Loophole, Dev Tunnel, Bore, or a self-hosted sish tunnel via--preferred-tunnel, with custom tunnels configurable in~/.fastfilelink/tunnels.json), and general SOCKS5/HTTP proxy configuration (wormhole only knows how to route through Tor, via--tor).
Metadata
Release files for ffl-python 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ffl_python-0.1.6.tar.gz | 24.5 MB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ffl_python-0.1.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 49.2 MB
Release files / ffl_python-0.1.6.tar.gz
| Download URL | ffl_python-0.1.6.tar.gz |
|---|---|
| Size | 24.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4c5dd8a0b39109851045a67c1456e186eb9e443956b10b4a4d8aa9b4072abe75
|
|
BLAKE2b-256 checksum How to use checksums |
6148db13441d348a0d786e922d622ae044c871c873ce485b6a758036a54e437d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / ffl_python-0.1.6-py3-none-any.whl
| Download URL | ffl_python-0.1.6-py3-none-any.whl |
|---|---|
| Size | 24.6 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4ea202d989f5fdc8c7578efa66ef68310194113991cccaab77f53c13d0566f6c
|
|
BLAKE2b-256 checksum How to use checksums |
ee923215edafa4608a81b221a4a7339f273f8abf7bacd759dc3dbf95fcfa436f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logSecurity for ffl-python 0.1.6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for ffl_python-0.1.6.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.