Skip to content

Releases: gclinian/SafeDrop

SafeDrop v1.7.1

Choose a tag to compare

@github-actions github-actions released this 03 Jun 02:52

Community contribution — interface-aware desktop discovery. Thanks to
@JianBin0218 (PR #1).

Fixed

  • Desktop discovery now computes each interface's directed broadcast
    from its real netmask
    instead of assuming /24. The previous /24
    guess produced the wrong broadcast on non-/24 LANs — most notably an
    iPhone Personal Hotspot (172.20.10.x is a /28, broadcast
    172.20.10.15), so phones on a hotspot never discovered the desktop.
    Now uses psutil to enumerate active, up interfaces and derive the
    broadcast per interface (safedrop/discovery.py).
  • Multi-homed machines send each directed broadcast out the right
    interface.
    _broadcast_endpoints() pairs each broadcast target
    with its source IP and binds the send socket to that source, so a
    box with e.g. a Radmin/VPN adapter + Wi-Fi no longer leaks the
    Wi-Fi broadcast onto the VPN interface (or vice-versa).
  • The status bar's local-IP display now lists every active interface
    IP (_local_ip_display()).

Changed

  • New runtime dependency: psutil>=5.9 (interface enumeration).
  • pyproject.toml → 1.7.1.

Tests

  • tests/test_discovery.py rewritten around the new
    BroadcastInterface model: netmask-derived broadcast (incl. the /28
    hotspot case), down-adapter skipping, per-source-IP endpoint binding,
    multi-interface IP display. 104 / 104 green.

Note: this release is desktop-Python only. The iOS native discovery
already computes per-interface broadcasts from netmask via
getifaddrs (shipped in 1.7.0), so it was already correct for the
hotspot case.

SafeDrop v1.7.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 17:34

The "iOS actually works on real hardware" release. Fixes the iOS
discovery interop bug (iOS couldn't see or be seen by other devices)
and completes sender-side pair-code display on iOS + Android.

Fixed — iOS discovery interop (the big one)

  • iOS now broadcasts to the subnet-directed address + loopback, not
    just 255.255.255.255. The global broadcast is routinely dropped on
    real Wi-Fi (VPN default routes, AP client isolation, iOS's network
    stack) — the subnet broadcast (e.g. 192.168.1.255, computed per
    interface from its netmask via getifaddrs) is what actually reaches
    peers. This is why other devices couldn't see iOS. (Same root
    cause + fix as the Python discovery fix in 1.6.x.)

  • iOS Discovery rewritten from an actor to a final class on a
    dedicated DispatchQueue.
    The listen loop's blocking recvfrom
    (1 s timeout) was running on Swift's cooperative thread pool (via
    actor + Task.detached), which starves the pool and stalls the
    loops on real devices — the exact anti-pattern TransferManager
    already fixed. This is why iOS couldn't see others. Now all
    blocking socket I/O runs on ioQueue; peer state is lock-guarded.

  • Verified on the iOS Simulator: a Python peer discovers the iOS
    device (via subnet broadcast 192.168.0.100), and the iOS app's
    Nearby devices list shows the Python peer — both directions.

    On a real device, iOS will show the Local Network permission
    prompt on first launch (driven by NSLocalNetworkUsageDescription

    • NSBonjourServices, already in Info.plist). The user must tap
      Allow or discovery stays dark — this is an OS requirement, not
      a SafeDrop setting.

Fixed — sender-side pair-code display (completes 1.6.2)

  • iOS: a confirmation sheet now appears on the sender showing the
    4-digit pair code while waiting for the receiver to Accept
    (OutboundPairPrompt published from TransferManager.sendText /
    sendFile, rendered as OutboundPairSheet). Auto-dismisses when the
    transfer proceeds, completes, is rejected, or fails.
  • Android: same — OutboundPairDialog derived from the outbound
    transfer's pending state + non-empty pairCode, with a Hide
    button. Both now honor SPEC §5.1 (both sides display the same code).

Changed

  • SPEC.md §5.1 documents the multi-target broadcast (loopback +
    subnet + global) and the "blocking I/O off the cooperative pool"
    rule for all platforms.
  • pyproject.toml → 1.7.0.

Tests

  • Python suite unchanged at 103/103 (this release is iOS/Android +
    SPEC; no Python code touched). iOS + Android both build clean.

SafeDrop v1.6.2

Choose a tag to compare

@github-actions github-actions released this 02 Jun 17:16

Bugfix — the desktop GUI sender never displayed the pair code,
breaking the visual man-in-the-middle check the protocol is designed
around. SPEC.md requires both sides to show the same 4-digit code;
the receiver's Accept dialog showed it, but the sender showed nothing,
so the user had nothing to compare against.

Fixed

  • Sender-side pair-code verification (safedrop/gui.py). When you
    start a transfer, a "Verify pair code" window now appears on the
    sender showing the 4-digit code, and stays up while waiting for the
    receiver to Accept — mirroring the receiver's dialog. It auto-
    dismisses once the transfer proceeds (transferring), completes, is
    rejected, or fails. The code is already carried on the wire and in
    TransferState.pair_code; this is purely the missing display.

Tests

  • New test_sender_surfaces_pair_code_before_transfer in
    tests/test_e2e.py: asserts the sender emits a non-empty 4-digit
    pair code while the transfer is still pending (before bytes flow),
    and that it matches the code the receiver independently derives.
    103 tests green.

Known gaps (follow-ups, not in this release)

  • iOS surfaces the pair code only after the transfer finishes
    (in a status line), not during the pre-Accept verification window.
  • Android sender does not show the pair code at verification time.
    Both should mirror the desktop fix to fully honor SPEC §pair_code.

SafeDrop v1.6.1

Choose a tag to compare

@github-actions github-actions released this 26 May 14:55

Patch — make the desktop install path actually one line. No
protocol changes, no new dependencies.

Added

  • scripts/install.sh — one-key installer for macOS + Linux.
    Verifies Python 3.10+, asserts tkinter is importable (with a clear,
    platform-specific fix on failure), creates a hermetic venv at
    ~/.local/share/safedrop/venv, installs safedrop[mcp] from PyPI
    (or --from-release against the latest GitHub Release wheel), and
    drops safedrop-gui / safedrop / safedrop-mcp /
    safedrop-mcp-tokens / safedrop-agent / safedrop-beacon
    launchers into ~/.local/bin. Idempotent.
  • scripts/install.ps1 — PowerShell counterpart for Windows. Venv
    lives at %LOCALAPPDATA%\SafeDrop\venv; .cmd launchers under
    %LOCALAPPDATA%\SafeDrop\bin. Same flow, same error messages.

Changed

  • README "Quick start" now leads with the one-line install:
    curl -fsSL https://raw.githubusercontent.com/gclinian/SafeDrop/main/scripts/install.sh | bash
    
    (and the iwr | iex Windows equivalent). The previous
    git clone + venv + pip install -e flow is preserved under a new
    Desktop — manual install subsection for the security-conscious.
  • docs/landing.html install snippet updated to match.

Tests

  • Smoke-verified scripts/install.sh --from-release against the
    published v1.6.0 wheel: pulls the .whl from GitHub Releases,
    installs into a fresh venv, launchers fire correctly,
    safedrop ls runs without errors.

SafeDrop v1.6.0

Choose a tag to compare

@github-actions github-actions released this 26 May 13:01

The "actually finish v1.6 + introduce the project" release. Closes
out the cross-platform native rendering of v1.6 primitives and ships
the docs needed to onboard new users / contributors.

Added — native notification rendering on all 3 platforms

  • Python tkinter banner for inbound show_notification. gui.py
    subscribes to safedrop.notifications.bus.on_notification and pops
    a transient Toplevel (auto-dismiss after 8 s, color-coded by
    info/warn/error).
  • iOS UNUserNotificationCenter — new show_notification handler
    in ios/SafeDrop/Tools.swift drops a system banner via
    UNTimeIntervalNotificationTrigger. App requests .alert + .sound
    authorization on launch.
  • Android NotificationManager — new show_notification handler
    in android/.../net/ToolRegistry.kt posts via
    NotificationCompat.Builder with a lazy-created channel. Added
    POST_NOTIFICATIONS permission to AndroidManifest and runtime
    request via ActivityResultContracts.RequestPermission in
    MainActivity for API 33+.
  • Moved notification_tools.py from safedrop_mcp/ to
    safedrop/notifications.py so the desktop GUI can use it without
    the [mcp] extra installed. MCP server imports updated.

Added — iOS token management UI

  • New ios/SafeDrop/TokenAdminView.swift — SwiftUI screen that calls
    the cross-device peer tools (tokens_list, tokens_mint,
    tokens_revoke) on a selected SafeDrop peer (the desktop running
    safedrop-mcp). Mint form with label / scope / TTL fields;
    one-time secret reveal sheet on success.
  • Toolbar key icon in HomeView opens TokenAdminView when the
    selected peer advertises safedrop.tools.

Added — introducing the project

  • docs/landing.html — single-page self-contained landing page
    (no external deps, dark theme, hero + features + architecture
    diagram + install snippet + cross-platform capability matrix +
    security model + roadmap). The thing you link from a README badge.
  • docs/pitch.md — 30-second + 2-minute pitches for a HN post /
    Twitter thread.
  • docs/demo-recipes.md — six tight live-demo recipes (each
    ~30-90 s), with exact commands + audience-facing punchline. Covers
    cross-platform AirDrop, agent-with-phone-camera, two-agent mesh,
    state handoff, mobile token mint, and Tailscale cross-LAN.

Changed

  • pyproject.toml → 1.6.0.

SafeDrop v1.3.0 — the MCP fabric release

Choose a tag to compare

@gclinian gclinian released this 20 May 06:04

The "MCP fabric" release. SafeDrop is no longer just a LAN
file/clipboard tool — it's a scoped, auditable, cross-device Model
Context Protocol fabric that any AI agent (Claude Code, Cursor, Goose,
Cline, Hermes via Ollama, cloud agents over HTTPS, …) can plug into.

Downloads

File What it is How to install
SafeDrop-ios-1.3.0-unsigned.ipa iOS 17+ app, arm64, unsigned (208 KB) Re-sign with your own Apple ID via AltStore or Sideloadly; SafeDrop uses no entitlements that break re-signing. Full guide: ios/DISTRIBUTION.md
SafeDrop-android-1.3.0-debug.apk Android 8.0+ (API 26+) debug APK (19 MB) adb install -r SafeDrop-android-1.3.0-debug.apk or sideload via file manager
safedrop-1.3.0-py3-none-any.whl / .tar.gz Python desktop / CLI / MCP server pip install safedrop-1.3.0-py3-none-any.whl[mcp] then safedrop-mcp or python -m safedrop

Highlights

  • iOS Phase 1 client — native Swift/SwiftUI, same X25519 + Fernet
    protocol as Python and Android, byte-for-byte interoperable
    (system_info, read_clipboard, write_clipboard).
  • MCP HTTP / Streamable transport with bearer-token auth + per-token
    scope enforcement (safedrop-mcp --http).
  • Capability tokens (safedrop-mcp-tokens mint --scope ... --ttl ...)
    persisted to ~/.safedrop/tokens.json, instantly revocable.
  • Per-agent policy via --allow / --deny / --profile. Run
    multiple safedrop-mcp instances side-by-side, each with its own
    scope.
  • MCP bridge — import any other MCP server (mcp-server-filesystem,
    mcp-server-github, …) into the SafeDrop fabric; their tools become
    callable from every paired peer on the LAN.
  • register_local_tool — agents add new tools at runtime via
    HTTP callback URLs.
  • Trust + audit UIs on Python, Android, and iOS — review and
    revoke saved (peer, tool) decisions.

See CHANGELOG.md
for the full per-version log and MCP_AGENT_GUIDE.md
for the agent-integration deep dive.

Tests

Ran 38 tests in 14.0s — OK

Covers protocol e2e, cross-language interop (Python ↔ Kotlin ↔ Swift
all derive the same pair code from the same shared secret), policy,
tokens, HTTP transport, bridge, dynamic tool registration.

Platforms

Platform Status
macOS / Linux / Windows desktop ✅ files, clipboard, MCP server, CLI, trust + audit UI
Android (8.0+) ✅ files, clipboard, tools (take_photo etc.), trust + audit UI
iOS (17+) ✅ Phase 1 — tools, trust + audit UI. File picker on the roadmap.

License: MIT.