github spieglt/FlyingCarpet v10.0.0
Flying Carpet 10.0.0

3 hours ago

The Android version is available on the Play Store, or an APK is available here if you would like to sideload. It supports Android 10/SDK 29 and up.

The iOS version is available here or search the App Store for "Flying Carpet File Transfer".

Flying Carpet 10.0

Flying Carpet 10 adds Shared Network mode and rebuilds the encryption on the Noise
Protocol Framework.

⚠️ Version 10 is a breaking change. v10 devices cannot transfer with v9 or earlier —
you'll get a clear version-mismatch message instead of a hang. Update every device you
transfer between.

Shared Network mode

Until now Flying Carpet always created its own ad-hoc WiFi hotspot. You can now transfer over
a WiFi or wired network that both devices are already on — useful at home or in an office,
and much faster to start when there's a network handy.

  • Discovery is authenticated: devices announce themselves on port 3290 with an HMAC keyed
    from the transfer password, so you only ever see peers that hold your password.
  • The receiver generates a single-use password and displays it (with a QR code); the sender
    types or scans it. No Bluetooth involved, and the two devices' operating systems don't
    matter — no need to select the peer's OS.
  • This is what finally makes Apple-to-Apple transfers work. iPhone↔Mac transfers were
    impossible in hotspot mode because neither device can host for the other. Join both to the
    same network — including a hotspot you made manually beforehand — and it just works. This
    also unblocks Android↔iOS, which had been broken by the iOS WiFi path (#131).
  • Wired connections are supported (#124). A desktop on ethernet can transfer with a phone
    on WiFi, as long as they're on the same network — and a machine with no WiFi card at all
    can now use Flying Carpet for the first time (#93).
  • Interface picker: a labeled dropdown showing each interface's IP, with unusable ones
    hidden, for machines with several NICs.
  • No hotspot means no ad-hoc WiFi connection to drop partway through a large transfer (#130).

Rebuilt encryption

Every transfer, in both modes, now runs a
Noise_NNpsk0_25519_ChaChaPoly_SHA256 handshake (X25519 + ChaCha20-Poly1305 + SHA-256), with
the pre-shared key derived from your password by PBKDF2-HMAC-SHA256 at 600,000 iterations.

  • Forward secrecy. Recording a transfer and cracking the password later no longer reveals
    the files — each transfer has fresh ephemeral keys.
  • Metadata is encrypted too. Filenames, file sizes, and the file count used to travel in
    the clear; they're now inside the encrypted channel along with the contents.
  • Tamper-evident. The plaintext version/mode preamble is bound into the Noise handshake as
    the prologue, so modifying a single byte of it fails the handshake rather than going
    unnoticed. This also closes the door on future downgrade attacks.
  • Replaces the previous SHA-256/AES-256-GCM per-chunk scheme; Noise is now the sole cipher.
  • Discovery announcements are signed with a key derived from the stretched PSK, so no fast
    hash of your password ever goes on the air — every offline guess costs a full 600k-iteration
    PBKDF2.
  • Generated passwords are now 10 characters instead of 8 (~2⁵⁸ instead of ~2⁴⁷),
    foreclosing a precomputed-table attack over the whole password space.
  • Full design writeup: docs/shared-network-crypto.md. All three implementations (Rust,
    Kotlin, Swift) are held together by shared known-answer test vectors.

Hotspot mode keeps WPA2 underneath, so it's now encrypted twice over.

macOS ↔ Linux Bluetooth now works

Hotspot transfers between a Mac and a Linux machine previously required manually pairing the
two in System Settings first, and often failed afterward with "Peer removed pairing
information".

Root cause: macOS advertises with a public address and dual-mode flags, and BlueZ's bearer
tiebreak prefers classic BR/EDR on a tie — so Linux was connecting over classic Bluetooth,
which macOS serves no GATT over. Linux now bonds over an LE socket first, which pins the
bearer to LE permanently, and keeps the bond for macOS peers so their rotating address stays
resolvable. Pairing also surfaces the 6-digit code in the app for confirmation (real MITM
protection), and declining now aborts the transfer cleanly instead of hanging.

Other fixes and improvements

Desktop (Windows/Linux)

  • File selection now comes first everywhere: hotspot joiners pick files and then get
    prompted for the password, instead of needing the host's password before the file dialog
    would open.
  • The UI recovers if a transfer task panics or is aborted, instead of freezing (#118).
  • The Windows firewall UAC prompt no longer appears on every transfer (#129). The check
    for an existing rule passed the rule name to netsh with literal quotes around it, so it
    never matched and the rule was re-added every time. Both rules are also added under a
    single elevated command now, so the one-time prompt is one prompt, not two.
  • Windows Bluetooth: recovers from GATT enumeration failures (0x8000FFFF) against
    already-paired iPhones — retries, then re-pairs once within the same transfer, rather than
    failing the run. Advertising is now explicitly stopped after the credential exchange.
  • Linux: stale flyingCarpet_* NetworkManager connections are pruned at startup and the
    hotspot is torn down on window close (#51).
  • Linux Bluetooth: cached BlueZ entries are purged and discovery is LE-only, so a
    previously-paired device (an audio device, say) can no longer be picked up as the transfer
    peer and then fail with "Could not find service UUID on scanned device" (#106).
  • The WiFi Direct failure message now points at shared network mode (#115).
  • Edge/WebView2 no longer offers previously typed transfer passwords in an autofill dropdown.

Android

  • Fixed an intermittent iOS→Android hotspot failure ("Empty key" crash or a silent stall)
    caused by a BLE credential-exchange race across two GATT connections.
  • Fixed a stuck hotspot flag that made repeat transfers hang with "hotspot already running";
    GATT client and server are now properly closed between transfers.
  • Successful shared-network receives no longer end with a spurious
    "Discovery error: StandaloneCoroutine was cancelled".
  • Output box auto-scrolls; the transfer log survives screen rotation (it previously could
    overflow the Binder transaction limit and vanish); every line is mirrored to logcat under
    the tag FlyingCarpet, so a full transfer log can finally be pulled with
    adb logcat -s FlyingCarpet for bug reports (#130).
  • Bluetooth pairing that's declined or fails now aborts the transfer instead of waiting
    forever; failed GATT reads no longer propagate empty values as the peer's OS or password.
  • Missing Bluetooth permissions are distinguished from missing hardware, and the switch
    stays usable so you can re-grant (#101).
  • Password-prompt dialog buttons are readable in dark mode.

Security hardening

  • Received filenames are sanitized against path traversal on all five platforms before
    touching the filesystem.
  • Header values from the peer (file count, filename length, chunk size) are bounds-checked
    before they're used to size allocations.
  • Fixed a Windows WiFi-profile XML injection via the SSID/password fields.
  • Dependency updates closing 6 Dependabot advisories, including CVE-2026-42184 in Tauri
    (is_local_url() misclassifying remote URLs as trusted local origins on Windows/Android,
    allowing a remote page to invoke local-only IPC commands). Also CVE-2026-25727 (time),
    CVE-2026-25541 (bytes), and fixes in serde_with and rand.

Send Folder is consistent everywhere

Sending a folder now recreates that folder inside the destination the receiving device
chose, with the contents inside, on all five platforms. Previously only macOS did this —
everywhere else the folder's contents were dumped loose into the destination. Sending
individual files is unchanged: they still arrive flat.

This also fixes sending a folder that contains sub-folders from Android to Windows or Linux,
which used to fail outright, and two cases where the desktop app aborted a transfer:
selecting a folder whose top level holds only sub-folders, and dropping two folders (or
files from two different directories) at once.

The in-app instructions were also wrong about how to send a folder — they told you to drag it
onto the window, which Android and macOS have no handler for, and which is not something a
screen reader user can do (#122). Each platform's help text now describes the control it
actually has, and says what arrives on the other end.

Don't miss a new FlyingCarpet release

NewReleases is sending notifications on new releases.