Skip to content

Releases: axpdev-lab/aeroftp

AeroFTP v3.6.10

28 Apr 19:33

Choose a tag to compare

[3.6.10] - 2026-04-28

MEGA Native canonical crypto, 2FA modal hookup, TOTP QR, mouse Back button

Same-day rollup on top of v3.6.8. The originally-tagged v3.6.9 build was deleted before a Linux release was published because the GitHub Actions Snap step was dying silently during LXD setup on three consecutive reruns; the work that was already in v3.6.9 (2FA modal hookup, TOTP QR, mouse Back button) is rolled into this v3.6.10 cut together with a critical MEGA Native crypto interop fix that landed in parallel. The Snap workflow step is marked continue-on-error: true so the rest of the Linux release pipeline (deb / rpm / AppImage signing and upload) is no longer blocked when the Snap action-build crashes; Snap Store stays on v3.6.8 until we either pin a newer action ref or move the Snap build to its own job (tracked for v3.7.0).

Fixed

  • MEGAcmd login on Linux/macOS (critical) — saved-profile connect against the MEGAcmd backend was failing every time on Unix with Extra args required in non-interactive mode. Usage: login [...] email password | exportedfolderurl#key | session. The Unix path was passing only the email as a CLI arg and piping the password to stdin, on the assumption (carried forward from AUTH-01 audit notes) that this kept it out of ps listings. In reality mega-login is a non-interactive one-shot wrapper that talks to the background mega-cmd-server and does not read stdin at all in that mode; the stdin trick only worked inside the interactive mega-cmd shell, which AeroFTP never invokes. Fixed by passing email + password as CLI args on every platform, matching what rclone, the official MEGA Sync, and every other MEGAcmd integration already does. The brief ps exposure window during login (~1s) is the same surface area that env var or password-file alternatives would have, so there is no real security regression. Reproduced by @aleimob on a fresh Ubuntu install with a saved MEGA-CMD profile against dev@aeroftp.app.
  • MEGA Native upload interoperability with MEGA Web (critical) — file node keys uploaded by AeroFTP through the MEGA Native API were stored in a non-canonical layout (raw 16-byte file key followed by nonce + meta-MAC), so AeroFTP could decrypt its own uploads but MEGA Web, MEGA Mobile, and any other official MEGA client derived the AES key from the canonical obfuscated layout and decrypted the payload with the wrong key, producing what looked like ciphertext-on-display. The fix in mega_crypto.rs::pack_node_key() now stores the MEGA-compatible obfuscated 32-byte node key, unpack_node_key_with_mac() derives the AES key by XOR-ing the first 16 bytes against the nonce / meta-MAC half, compute_attr_key() uses the canonical key for file attributes, and meta_mac() condenses the chunk MAC with the required [mac[0..4] ^ mac[4..8], mac[8..12] ^ mac[12..16]] XOR pairs. A unpack_node_key_legacy() fallback is kept so AeroFTP can still read files uploaded by the buggy older builds; download paths verify the canonical MAC first, then fall back to the legacy layout if needed. Existing legacy uploads must be re-uploaded if they need to open in MEGA Web (MEGA Web cannot use the legacy fallback). Independently verified end-to-end with megajs decoding the file name and plaintext from a fresh share link, and visually verified by the user in MEGA Web.
  • 2FA prompt modal did not open from saved-card click (issue #128 follow-up) — saved-card connect goes through onSavedServerConnect and tab reconnect goes through switchSession. Neither path called tryShowTwoFactorPrompt, so the modal advertised in v3.6.8 never appeared when users clicked a saved MEGA / Filen / Internxt card whose persisted session had expired. The dispatcher is now wired into all three catch handlers; pattern matching against the backend's E_MFAREQUIRED / ENOTOKEN messages is shared so the matching surface is identical across paths. Test reproduction confirmed by the original reporter (@EhudKirsh).

Added

  • Mouse Back button (button code 3) closes the topmost modal — the side button on gaming and productivity mice (the one that fires event.button === 3 and event.buttons === 8 in the HTML mouse events spec) now triggers a synthetic Escape keydown event that bubbles to the topmost open modal, dialog, dropdown or popover. Every dialog in the app already wires Esc (TwoFactorPromptDialog, HostKeyDialog, OverwriteDialog, SettingsPanel, VaultPanel, AISettingsPanel, ConnectionScreen, the delete-profile confirmation, the Quick Connect form, etc.), so re-routing Back through the same channel gives correct stacked-modal behavior with zero per-component churn: the topmost handler closes and self-removes, the next Back closes the next layer, all the way back to the My Servers home. Implemented as a single useMouseBackButton() hook mounted at the App root: listens for mousedown, mouseup and auxclick in the capture phase, suppresses the WebKitGTK history-back default that was beginning to fire on recent builds, and synthesizes the Escape on mouseup so the gesture timing matches what the user expects on releasing the side button. (reported by @EhudKirsh)
  • AeroFTP master password TOTP setup QR code — Settings > Security > Two-Factor Authentication > Setup now renders the actual QR code (qrcode.react QRCodeSVG, level M, 180px on a white tile so it scans cleanly under the Cyber / Tokyo Night themes) instead of just the otpauth URI as copyable text, so the user can point Authy / Google Authenticator / 1Password / Bitwarden directly at the dialog. Account name in the URI changed from "AeroFTP Vault" to "Desktop 2FA" because Authy was rendering the entry as the awkward "AeroFTP : AeroFTP Vault" duplication. The URI also now carries a Google-extension image=https://docs.aeroftp.app/web-app-manifest-512x512.png parameter so authenticators that honor it (FreeOTP+, Yubico Authenticator, Bitwarden, recent Google Authenticator) can show the AeroFTP logo. Authy ignores image= and pulls icons from a Twilio-internal database, so an AeroFTP logo there would require a separate submission to Twilio support; until then Authy will fall back to its generic icon, which is a vendor limitation, not a URI problem.

Changed

  • Agent / MCP / CLI internal cleanup pass — coordinated set of refactors across agent_session.rs, ai_core/{agent_tools, gui_tools, tools}.rs, ai_tools.rs, bin/aeroftp_cli.rs (+326 lines, the largest single delta), cross_profile_transfer.rs, lib.rs, mcp/tools.rs, profile_auth_state.rs, providers/{azure, jottacloud, xml_text}.rs, and speedtest.rs. Same-batch cleanup that landed alongside the MEGA Native crypto fix; behavior-preserving changes that improve consistency across the agent, MCP and CLI surfaces. No public API change.

Notes on accessibility

The Back-button hook is the first slice of a broader keyboard-and-pointer accessibility pass that landed on the v3.6.x roadmap after @EhudKirsh's feedback on issue #133. The remaining slices (full Tab-order audit on the Settings panel, Arrow-key navigation between My Servers cards, Enter to connect / Shift to multi-select, and "Forward mouse button (button code 4) → repeat last action") are scheduled for v3.7.0 because each one needs its own focus-management review across the 42 modals in the app, and shipping them piecemeal would create gaps where some screens listen and others do not. Tab and Enter already work where the underlying HTML controls are focusable, so the gap is concentrated in custom-rendered grids and chip lists rather than in form inputs.

Notes on the v3.6.9 tag

A v3.6.9 tag was briefly created earlier in the day on commit 78c322f with the modal-hookup / QR / mouse-back work. The Linux leg of its release pipeline failed three consecutive times because of a deterministic silent crash in snapcore/action-build@3bdaa03e during LXD setup, with no log output past the AppImage repackaging step. No Linux artifacts were ever published on that tag (only Windows .msi / .exe and macOS .dmg made it to the GitHub release page); the tag and the partial release were both deleted before any Linux user could install from them. v3.6.10 supersedes that effort with the same code plus the MEGA Native crypto interop fix and the workflow change that allows the rest of the Linux pipeline to ship even when the Snap step crashes.

Downloads:

  • Windows: .msi installer, .exe, or .zip portable (no installation required)
  • macOS: .dmg disk image
  • Linux: .deb, .rpm, .snap, or .AppImage

Download AeroFTP

AeroFTP v3.6.8

28 Apr 13:24

Choose a tag to compare

[3.6.8] - 2026-04-28

Community wishlist quick wins + MEGA 2FA + Filen TOTP persistence

A focused patch release built around the v3.6.8 wishlist thread (issue #133) plus two long-standing items from issue #128 (MEGA 2FA TOTP and the Filen TOTP-persisted-after-save bug). Twelve community-reported items land together so the rest of the thread can be triaged on a fresh baseline. No MCP surface changes; the VS Code extension does not need a bump.

Fixed

  • Yandex Disk preset "Docs" link 404 — the registry entry for yandexdisk-webdav pointed at yandex.com/support/disk-desktop-windows/start/webdav-client.html, which no longer exists. Repointed to yandex.com/support/disk/ (verified 200 OK). (reported by @EhudKirsh)
  • WebDAV Edit form helper links — the provider footer with Create Account / Docs / Generate password buttons was hidden in Edit mode via a editingProfileId guard, so users editing a Yandex / OpenDrive / Koofr profile could not jump back to the docs or password generator. The guard is gone; the footer renders the same on first connect and on Edit. (reported by @EhudKirsh)
  • WebDAV Edit form Server Endpoint URL editable in Edit — the Server Endpoint URL and Port fields were locked on first connect for pre-configured providers but became editable on Edit, which was easy to break by accident. Both fields are now readOnly when selectedProvider.defaults?.server is set, with a muted visual state. (reported by @EhudKirsh)
  • OneDrive logo misshapen at small sizes — the previous SVG layered three paths on a 24x24 box, producing an outline that did not look like the canonical Microsoft cloud icon, especially in the Discover Services grid. Redrawn with the standard 4-cloud composition on a 32x24 viewBox, four fill stops. (reported by @EhudKirsh)
  • Speed Test modal "Run comparison" button cropped at large font sizes — the modal used pt-[5vh] + max-h-[90vh], leaving the footer below the fold for users on 19 / 22 px font sizes. Vertical budget expanded to pt-[2vh] pb-[2vh] + max-h-[96vh]. (reported by @EhudKirsh)
  • Activity Log badge counter ignored the active filter — the bottom-bar Log badge counted every emitted event, so it crept up to 99+ even when the panel was filtered to Errors only. The panel now persists filterType and showCloudSync in localStorage and broadcasts CustomEvents on every change; App.tsx subscribes and recomputes the badge using the same filter predicates as the panel. (reported by @EhudKirsh)
  • Provider icons in the Choose Icon dialog silently failed to select — Hetzner, MinIO, Koofr, FileLu, Blomp, OpenDrive, FeliCloud, Pixelunion, Aspnix, DriveHQ, Quotaless, Jianguoyun, Yandex Disk, Immich and other PNG-backed provider logos render as <img>, but reactLogoToSvgDataUrl() searched for an <svg> and returned null, so the click was a no-op. Added an <img> fallback that returns the image src as the data URL — works unchanged with the existing customIconUrl consumer. (reported by @EhudKirsh)
  • Custom icons "No custom icons yet" placeholder shown next to an existing icon — the empty-state copy contradicted the Current / On-server section above when a user had already picked an icon. The placeholder is now suppressed when either is non-empty. (reported by @EhudKirsh)
  • Filen TOTP code persisted across reconnects (issue #128) — the 6-digit 2FA Code field was saved into the profile's options.two_factor_code on connect, so a reconnect a few minutes later replayed yesterday's code and the API rejected it with "Wrong Two Factor Authentication code". TOTPs are single-use and rotate every 30 seconds; the saved-profile path now strips two_factor_code from optionsToSave on both Edit and New Server flows, the same way Filen / Internxt / MEGA web clients ask for the code on every login. (reported by @EhudKirsh)

Added

  • Hide username on My Servers cards — new toggle in the toolbar (AtSign icon, persists across sessions as aeroftp_hide_server_username). When active, the user@host subtitle becomes host-only across grid and list views, freeing visual space and removing the email leak. (reported by @EhudKirsh)
  • Drag and drop on Custom icons upload box — files dropped on the box are ingested through the same ingestIconBytes() path as the file picker. Visual feedback while a file is hovered: solid blue border and a "Drop file to upload" label. Allowed extensions: SVG, PNG, JPG / JPEG, GIF, WEBP, ICO. (reported by @EhudKirsh)
  • Custom icons delete confirmation — removing an icon from the library now goes through a confirmation prompt that includes the icon's own name in the message, same surface as the existing profile delete dialog. (reported by @EhudKirsh)
  • Activity Log multi-select filter — the single-pick <select> dropdown is gone, replaced by a button + popover with one checkbox per operation (Connect, Disconnect, Upload, Download, Delete, Restore, Navigate, Errors) plus an "All" reset entry at the top. Empty selection is the new "show all" state, so users can mix Errors + File operations without losing one when they pick the other. State migrates automatically from the legacy single-pick value. (reported by @EhudKirsh)
  • MEGA 2FA TOTP support (issue #128) — Quick Connect MEGA gains a "2FA Code" field below Password, mirroring the Filen / Internxt block (6-digit numeric, inputMode="numeric", autoComplete="one-time-code"). Backend: MegaConfig extended with two_factor_code: Option<String> deserialized from extra["two_factor_code"]; both login_v1 and login_v2 inject "mfa": <code> into the us (login) request when present. Server returns -26 (E_MFAREQUIRED) when the field is absent on a 2FA-enabled account, and -9 / -16 on a wrong code; both surface to the user as the same generic auth failure as a wrong password, with no extra plumbing required. (reported by @EhudKirsh)

Changed

  • Six new i18n keys translated to all 47 languages:savedServers.showUsername, savedServers.hideUsername, iconPicker.confirmDelete, iconPicker.dropHere, activityPanel.filterMenu.title, activityPanel.filterMenu.selected. Validation: 46/46 locales clean, 0 missing, 0 orphan, 0 placeholder.

Downloads:

  • Windows: .msi installer, .exe, or .zip portable (no installation required)
  • macOS: .dmg disk image
  • Linux: .deb, .rpm, .snap, or .AppImage

Download AeroFTP

AeroFTP v3.6.7

27 Apr 15:59

Choose a tag to compare

[3.6.7] - 2026-04-27

Share-link reliability and UX paper cuts

A focused patch release. The headline is a silent regression on MEGA Native share-link generation that surfaced during an interoperability test session against MEGA's own infrastructure: the URL we built used the internal node handle instead of the public handle returned by the API, so links opened on mega.nz with "File cannot be accessed". Same encryption key, wrong path component, no error from our side. The fix lands together with a CLI verification flag and a few small UX wins voted up on the v3.6.7 wishlist.

Fixed

  • MEGA Native share linkaeroftp-cli link --profile <mega-native> was building mega.nz/file/<internal-node-handle>#<key> instead of mega.nz/file/<public-handle>#<key>. The encryption key portion was always correct, only the 8-character handle in the path was wrong, so generated links opened on a "File cannot be accessed" page on mega.nz. Fix: capture the public handle returned by the MEGA API l (export) command and use that in the URL. mega_native.rs::create_share_link.
  • S3 explicit endpoint precedence — when a saved server profile has both a configured S3 endpoint and a host populated by the GUI, the explicit endpoint now wins. Also detects bucket-addressing errors and reports them as ProviderError::Configuration so they are actionable on the CLI side. (commit 27d2ccc8, originally merged via #132 into the local tree, formally rolled into this release.)
  • Edit Server form, S3 Path-Style toggle — the Path-Style URLs checkbox was wired into QuickConnect via ProtocolSelector but never plumbed into Settings > Servers > Edit Server, so users could not flip the toggle on a saved profile after creation. Now exposed in the S3 section of Edit Server, sharing the existing protocol.pathStyle i18n key. Surfaced by @voland-key on #132.
  • Edit Server form, Public URL Base scope — the "Public URL Base" field was rendered in Edit Server for every protocol including S3 / Azure / MEGA / Filen / GitHub / OAuth providers, with a caption that explicitly reads "Enter the HTTP URL that maps to your FTP root folder". The field is only meaningful for filesystem-mounted protocols whose tree maps to a plain HTTP service. Now gated to FTP / SFTP / WebDAV; other providers build their share links via native APIs and do not consume this field.

Changed (FTP layer — suppaftp 8.0.1 to 8.0.3)

  • suppaftp upgraded from 8.0.1 to 8.0.3 after a fresh upstream review (analysis archived in docs/dev/reports/2026-04-27-suppaftp-upgrade-analysis.md). The pin held since 8.0.2 introduced an ungated std::os::fd::AsFd call that broke Windows builds. Upstream still ships that code in 8.0.3, but it is feature-gated behind tokio-async-native-tls, which AeroFTP does not enable (we use tokio-rustls-aws-lc-rs). Verified by reading tokio_ftp/tls/native_tls.rs in the upstream 8.0.3 source. The legacy FTP_CLIENT crate stays pinned at 8.0.1 because it uses the broken feature.
  • The upgrade brings 14 upstream fixes that affect AeroFTP's hot path: undefined behavior in the tokio TLS tcp_stream() borrow chain (PR 135); replaced unwrap() panics on server-controlled EPSV / SIZE / MDTM responses with proper error handling (PR 146); infinite loop in async feat() on mid-response disconnect (PR 137) and the same fix for read_response_in() on multiline + disconnect (PR 138); data_connection_open flag now set only after successful open, removing a class of false DataConnectionAlreadyOpen errors (PR 136); MLSX parser accepts cdir / pdir per RFC 3659 (PR 139) and 4-digit unix.mode like 0755 (PR 140); DOS LIST parser handles sizes with commas like 1,234,567 (PR 142); parse_lstime adjusts year for future dates the way GNU ls does (PR 143); DOS time parser handles a space before AM/PM (PR 144); abort() no longer appends when the server sends a direct 226 (PR 141); active mode uses EPRT for IPv6 (PR 145); cwd() accepts 200 Command OK in addition to 250 for non-RFC-959 servers (PR 153). All cargo check / cargo clippy --all-targets -- -D warnings clean.

Added

  • aeroftp-cli link --verify — optional reachability probe. After the share link is generated, the CLI runs an HTTP GET against the URL with a 15-second timeout, follows up to 5 redirects, and reports the resulting status code. Exits with code 4 on a non-2xx/3xx status. JSON output gains a verified: { http_status, ok } block. Useful in CI smoke tests and post-release validation to catch silent regressions like the MEGA one above. Uses GET, not HEAD: SigV4-presigned URLs across S3-compatible providers reject HEAD when only host is in SignedHeaders.
  • CLI smoke step for --verify flagcli-smoke.yml now asserts that aeroftp-cli link --help advertises --verify, so removing the flag accidentally fails CI on every supported OS (Linux / macOS / Windows). Live reachability probes against credentialed profiles stay an operator-side check; the smoke verifies surface, not transport.
  • BLAKE3 in the File Properties Checksum tab — fifth row alongside MD5 / SHA-1 / SHA-256 / SHA-512. The blake3 crate was already vendored for the Hash Forge Cyber tool, so this is purely surface plumbing: backend calculate_checksum accepts "blake3" (alias "b3"), the dialog renders a new row, the props type widens accordingly. Output is the standard hex-encoded digest.
  • Esc clears narrowing on My Servers — pressing Escape while focused on the My Servers grid (no input selected, no modal open) clears the search query and resets the active filter chip back to "All". Mirrors the v3.6.6 Esc gesture that clears file selections in AeroFile panels and answers a wishlist follow-up.

Changed

  • File Properties dialog widened from 420 px to 560 px (capped at 92 vw), and the Checksum row no longer truncates the digest. SHA-512 (128 hex characters) and BLAKE3 (64 hex characters) are now readable on a single line where the viewport allows, wrapping cleanly otherwise. The (label / value / copy) row uses break-all and items-start so long hashes do not overflow the column or push the copy button off-screen.

Downloads:

  • Windows: .msi installer, .exe, or .zip portable (no installation required)
  • macOS: .dmg disk image
  • Linux: .deb, .rpm, .snap, or .AppImage

Download AeroFTP

AeroFTP v3.6.6

27 Apr 00:34

Choose a tag to compare

[3.6.6] - 2026-04-27

Agent surface, onboarding polish, server speedtest, community wishlist

The full v3.6.6 cycle ran in roughly 36 hours and is shaped by two parallel community feedback waves. Issue #125 (@EhudKirsh) — a clean reproduction of CLI/Terminal bugs — prompted a 4-Sonnet black-box audit of the AI-agent surface that surfaced 13 friction points; the same thread invited Ehud to point an AI assistant at agent-info --json and agent-bootstrap --json, and the audit closes that loop. Issue #130 (@scottonanski) reframed the first-run empty state, and most of the onboarding polish ships in response. Issue #129 stayed open as the v3.6.6 wishlist thread, and many of the small UX wins below answer specific items voted up there.

Added

  • aeroftp-cli agent-connect <profile> + MCP tool aeroftp_agent_connect — single-shot connect surface for AI agents. Returns one JSON payload with per-block status (connect, capabilities, quota, path), replacing the boilerplate sequence connect → about → df → ls /. Block status values are ok / unsupported / unavailable / error; agents read connect.status for the go/no-go decision and degrade gracefully on the rest. Live-connect allowlist (FTP / FTPS / SFTP / WebDAV / S3 / GitHub / GitLab) is documented inline in --help. For protocols outside the allowlist (pCloud, Filen, Dropbox, etc.) the response still includes valid capabilities, path and profile blocks; only the connect block reports status: "unsupported" and the CLI exits 0 because the rest of the payload is still actionable. New lib module agent_session.rs is the single source of truth, also translating profile.options camelCase keys (bucket, region, tlsMode, privateKeyPath, …) into ProviderConfig.extra snake_case so S3 / Azure / SFTP-key / FTPS profiles connect via vault for the first time on the agent path.
  • agent-info --json exposes a protocol_features map keyed by protocol → list of feature tokens (share_links, resume, server_copy, versions, thumbnails, change_tracking, etc.) plus an agent_connect_supported_protocols array. Collapses what used to require N agent-connect calls (one per profile) into a single batch query — driven by the audit's Battery D where one agent had to walk 69 profiles to discover share-link capability.
  • head -c / --bytes <N> byte-range preview for remote files. Works on binary content (returns base64 in JSON when bytes aren't valid UTF-8) and reports bytes_returned / total_size / truncated / encoding. Closes the audit's Battery A "no way to get the first 4KB without a full download" gap.
  • ls --limit N, --files-only, --dirs-only flags. Summary now carries truncated: bool and total_before_limit: int so agents can detect partial results unambiguously. Same trio added to find, plus a --name <glob> alias for the positional pattern (the natural first-attempt form for agents who expect named args).
  • Cross-profile multi-select on My Servers — click a server card body to toggle Cross-Profile selection (icon button still triggers Connect). Up to two cards selected; third click drops the oldest FIFO. Indigo ring + arrow-up-right badge for source, emerald + arrow-down-left for destination. Always-visible Cross-Profile button in the toolbar with three brightness states (0 / 1 / 2 selected) and a counter badge. Right-click context menu offers Set as source / destination for direct assignment. Drag-to-reorder now works while a filter chip is active or a search query is typed.
  • Server SpeedTest — new isolated benchmark dialog and CLI parity. GUI: Single / Compare tabs, multi-select up to 8 servers, parallel selector, ranked compare table with tri-state integrity, history summary card with regression warning (last < median × 0.7), Esc cancels running test. CLI: speed subcommand upgraded with random non-compressible payload (was zeros), SHA-256 integrity, TTFB measurement, --no-integrity flag, --json-out. New speed-compare subcommand emits JSON v1, CSV, and Markdown reports. redact_url_for_display() is applied to every report and error path so passwords never appear in stdout / JSON / CSV / MD; csv_cell_safe() neutralizes spreadsheet formula triggers (=, +, -, @); md_cell_safe() escapes pipes / newlines / backslashes. Streaming download to NamedTempFile with TTFB measurement, tempfile pre-allocation before connect to eliminate orphan/leak windows, SQLite history (WAL, 0600/0700 perms, 1000-row cap, server_name forced NULL at insert as defense in depth), spawn_blocking for SHA-256 hashing and random payload generation. 22 speedtest lib tests + 6 CLI tests for redact_url, CSV/MD escaping. Schema aeroftp.speedtest.v1 is stable across CLI and GUI.
  • Selected-server chips on the Compare tab — each chip shows the display name, protocol tag, and an inline X to remove the server from the comparison without scrolling the list.
  • Provider IconPicker dialog (closes Ehud's wishlist ask in #129 modeled on KeePassXC's icon library) — replaces the bare file dialog under "Choose icon" with a structured picker. "Provider icons" tab shows every entry in PROVIDER_LOGOS grouped by catalog category with curated popularity priority; "Custom icons" tab is the user's persisted library (localStorage aeroftp-custom-icons) with per-icon trash button. Live free-text search. SVG support throughout: Tauri file dialog accepts .svg and stores them as data:image/svg+xml;base64,… data URLs without canvas rasterization, preserving vector fidelity at every render size. Always consumed via <img src> so embedded scripts are sandboxed. Live re-detection on dialog open: "On server" card auto-fires detect_*_favicon and surfaces the live result, with a "Matches server" check on the In Use card when the live and saved values agree.
  • Server Health Check legend — dialog header shows the threshold dots inline (green 80+, yellow 50-79, red <50) instead of only on hover; ScoreGauge stacks /100 under the numeric score. Closes Ehud's specific "name the boundaries" ask in #129 for both single-server and Check All runs.
  • Two WebDAV provider presets (closes Ehud's #129 suggestions): OpenDrive WebDAV (opendrive-webdav, server https://webdav.opendrive.com, regular login password) and Yandex Disk WebDAV (yandexdisk-webdav, server https://webdav.yandex.ru, app-specific password with deep-link to id.yandex.com/security/app-passwords). Both appear automatically in the Discover catalog under WebDAV.
  • passwordGenUrl field on ProviderConfig — surfaces in the connection-form footer as a "Generate password" link (amber, key icon) next to the existing Create Account / Docs links. Wired up for Koofr WebDAV and Yandex WebDAV.
  • PasswordStrengthBar in the Export Encrypted Backup flow — same component as AeroVault, gives users a 0-100 score with color-coded feedback while typing. Was previously only inside Vault; parity was the user-visible ask.
  • File associations for .aeroftp and .aeroftp-keystore — Tauri fileAssociations extended with application/x-aeroftp (server-profiles export bundle) and application/x-aeroftp-keystore (full keystore). Linux MIME XML extended with both new types alongside the existing AeroVault entry. Per-format icons not shipped yet — file managers fall back to the generic AeroFTP icon.
  • "Close to tray instead of quitting" Settings toggle (closes Ehud's #129 follow-up). When enabled, clicking the window close button hides AeroFTP to the system tray instead of terminating, so background tasks like AeroCloud sync keep running. Independent from "Start minimized on autostart"; default off to preserve existing behaviour. Esc on either panel now clears file selections when no modal/dialog/preview is open, mirroring the right-click-empty-area gesture.
  • mkdir --json reports already_existed: bool so audit trails distinguish "I created it" from "it was already there" on idempotent -p invocations.
  • Inline saved-profile inventory in agent-bootstrap --json plus per-profile auth_state (valid / expired / needs_refresh / no_credentials / unknown) wired into all three list surfaces (profiles --json, agent-bootstrap --json, MCP aeroftp_list_servers). Eliminates the round-trip an agent had to do after agent-bootstrap and stops connect-then-fail loops on profiles whose OAuth tokens expired silently. New profile_auth_state lib module is the single source of truth; pure local, never touches the network.

Changed

  • First-run empty state on My Servers (issue #130, @scottonanski) — visible "+ New" header label instead of icon-only +. Empty state now reads "Get started" with a primary CTA "Add your first server" (was "Quick Connect", which read as "rapid versus what?") and a 2x3 category grid (Protocols / S3 / WebDAV / Cloud / Media / Developer) that jumps straight into the relevant Discover slice in one click.
  • Cross-Profile gating — toolbar button, card click selection, and right-click "Set as source / destination" menu items are now gated on servers.length > 1. Selecting a single server as source/destination was nonsensical and used to ship a confusing badge in the toolbar.
  • Discover service cards — replaced the responsive grid-cols-1/2/3/4/5 cascade with auto-fill minmax(260px, 1fr). Earlier breakpoints were truncating provider names to "Cloudflar...", "Backblaz...", "S3 Co...". The auto-fill grid keeps each card readable and only adds columns when the panel actually has room. WebDAV preset logos (OpenDrive, Yandex Disk) mapped to the existing PROVIDER_LOGOS so the new presets show proper icons everywhere (Discover, ConnectionScreen, SessionTabs, SettingsPanel, MyServers).
  • My Servers grid breakpointsgrid-cols-2 md:3 lg:4 xl:5 2xl:6 with p-1 breathing room so the selection ring is no longer clipped at the edges. IntroHub container spans the same width as the...
Read more

AeroFTP v3.6.5

26 Apr 07:12

Choose a tag to compare

[3.6.5] - 2026-04-26

CLI polish + cross-provider correctness sweep

Drop-in patch driven by an end-to-end stress test of aeroftp-cli 3.6.4 against real provider accounts (S3, Backblaze, Storj, FTPS, Dropbox, Google Drive, OneDrive, Box, Koofr, Zoho WorkDrive, kDrive, Drime). The session surfaced four recurring correctness defects that span 8 providers, plus a dozen ergonomics rough edges that became visible only when the CLI is driven by an external AI agent rather than a human typing one command at a time. Fixes are surface-level and contained to the CLI binary plus per-provider trait impls; no architectural change.

Fixed

  • FTP CLI now respects the server-provided home directory - aeroftp-cli was issuing a hard CWD / after login, which overrode the home directory negotiated by the FTP server (typically /home/user on non-chroot installations like default vsftpd) and landed the session at the filesystem root, which is usually non-writable. This surfaced in a head-to-head benchmark vs rclone where the same put rel/path/file.txt worked under rclone but produced 550 Permission denied here. Three coordinated fixes: the FTP provider skips the post-login CWD when initial_path is bare / (aligning with rclone, lftp, FileZilla, ftp(1) and curl which all defer to PWD post-login); the CLI path resolver now returns empty for empty user input so the provider's canonical default kicks in instead of an artificial absolute root; and mkdir -p preserves relative-vs-absolute semantics instead of always prefixing /, so mkdir -p rel/path issues MKD rel/MKD rel/path (which the server can satisfy under the user's home) instead of MKD /rel/path (which non-chroot servers reject for the same write-permission reason). Absolute paths like /etc continue to target the filesystem root verbatim. Validated end-to-end against vsftpd in a Docker harness, no regression on the existing chroot case.
  • OAuth saved servers can now be renamed from the Edit dialog (issue #127) - In My Servers, hovering over an OAuth tile (Google Drive, Dropbox, OneDrive, Box, pCloud, Zoho WorkDrive, Yandex Disk, 4shared) and clicking the Edit pen now opens a form whose display name is editable, matching the behaviour of WebDAV / E2E / API providers. Two root causes: the OAuthConnect "Active" branch (rendered when tokens already exist for the provider) skipped the Save toggle and the Connection Name input entirely, so there was no field to type into. And the OAuth save callback in ConnectionScreen searched for the existing profile by name === saveName, so the moment the user changed the name the lookup failed and a brand-new profile was created next to the original instead of renaming it. Fix: render the Save toggle + name input in the Active branch (gated on the same wantToSave flag the inactive branch uses), and prefer the explicit editingProfileId over the name-match heuristic when persisting an OAuth edit. OAuth-specific fields (clientId, clientSecret, scope, region) stay locked - renaming a saved server is purely a local label change.
  • find glob matched as substring across 7 providersaeroftp-cli find /path "*.txt" was returning report.TXT.rtf and any file whose name contained the literal txt, because the per-provider find() implementations forwarded the pattern straight to the upstream search API (which is substring-by-name on most clouds) without re-applying glob semantics on the response. Affected: Dropbox, OneDrive, Box, Koofr, Zoho WorkDrive, Drime, kDrive. Fix: server-side query is now broad-prefiltered (glob characters stripped, only the literal portion sent), then the response is re-filtered client-side via the shared matches_find_pattern helper that powers the rest of the CLI. Google Drive (already filtered against its own catalog) gets the same belt-and-braces second pass.
  • mkdir + put failing on empty-prefix object storesaeroftp-cli put file.bin s3://bucket/key returned exit=2 "Parent does not exist" on a fresh bucket because the put plumbing was issuing a separate mkdir call before the upload, which is a hard error on S3 / Azure / Backblaze (no real directory primitive). Fix: skip the parent-directory pre-flight when the provider declares is_object_store(). Validated end-to-end on Backblaze and Storj.
  • ls of a missing FTPS path returned exit=0 with (empty directory) — the unhappy path was indistinguishable from an actually empty directory, so scripts piping the output couldn't tell. Fix: return exit=2 "Path not found" when the upstream LIST rejects the resolved path. The empty-directory case (path exists, no entries) still exits 0.
  • Dropbox get of a missing file took 3.5s + 3 retries before failing — the path/lookup/not_found JSON error was being classified as transient and retried, instead of as a permanent client error. Fix: detect path/not_found upstream and return exit=2 immediately. Drops the failure latency from ~3.5 s to ~150 ms.
  • Koofr WebDAV default Remote Path was /dav/Koofr/ (issue #126) — the discovery preset paired server: https://app.koofr.net/dav/Koofr with basePath: /dav/Koofr/, so the joined request URL doubled to /dav/Koofr/dav/Koofr/..., which Koofr rejected with Invalid credentials. Fix: default basePath is now /. Existing saved profiles need to be edited once.

Added

  • Inline rename for saved servers (issue #127) - In addition to unlocking rename via the Edit dialog, My Servers tiles now support a faster path: right-click → "Rename (F2)" turns the tile name into an editable input with a green check / grey X for confirm / cancel, plus an F2 hotkey that renames the currently hovered tile. Enter and blur commit, Escape cancels. Works in both grid and list view, and applies to every provider class (OAuth included). The right-click variant lives next to the existing Edit voice in the context menu.
  • Protocol class label on My Servers tiles (issue #127 bonus) - Tiles now show a second small chip next to the protocol brand badge: OAuth (indigo), API (sky), WebDAV (purple), E2E (emerald), S3 (orange), Azure (blue), AeroCloud (cyan). FTP / FTPS / SFTP keep only the existing protocol badge to avoid duplication. The new label makes the WebDAV-Koofr vs API-Koofr distinction (and similar pairs across cloud providers) visible at a glance, parity with the Discover Services page.

Changed

  • Throughput parity with rclone on FTP / SFTP / WebDAV - Head-to-head profiling on Docker loopback exposed three avoidable bottlenecks in the upload path. (1) The plain-FTP uploader was paying a 100ms-2s "TLS drain" sleep before finalize_put_stream on every transfer; the sleep is a real workaround for a TLS/TCP close_notify race but has no effect on plain FTP. Gating it behind tls_active cuts a single-100MB upload on Docker FTP from 2.74s to 0.72s (37 MB/s -> 138 MB/s, -74%) and a 500x10K bulk-of-small-files run from 14.68s to 2.72s (-82%, now ahead of rclone with --transfers 4). (2) The SFTP default buffer was 32 KiB - the conservative protocol minimum - which caps loopback throughput at ~35 MB/s. Raised to 256 KiB (OpenSSH 8+ and russh-sftp negotiate larger packets in practice anyway, and 1 MiB only adds another ~5 MB/s on top). 100MB Docker SFTP: 3.71s -> 2.37s (-36%). --chunk-size / --buffer-size still override. (3) The WebDAV streaming PUT body was built with the default ReaderStream capacity of 8 KiB, churning syscalls. Bumped to 256 KiB. 100MB Docker WebDAV: 1.26s -> 0.84s (-33%). No protocol-level changes; tested in CI with the existing FTP/SFTP/WebDAV smoke jobs.
  • aeroftp-cli polish pass for the AI-agent demo path:
    • pget is now a real subcommand (alias for get --segments 4); the banner cell stops being a lie.
    • Banner protocol count and the connect "Unsupported protocol" error now derive from a single SUPPORTED_URL_SCHEMES constant, so they cannot drift apart again.
    • Subcommand help screens no longer reprint the ASCII banner. Banner is suppressed when stderr isn't a TTY, when AEROFTP_NO_BANNER is set, or when --no-banner is on the command line. Top-level --help still shows it once.
    • 11 connection globals (--bucket, --region, --container, --token, --tls, --key, --key-passphrase, --password-stdin, --insecure, --trust-host-key, --two-factor) move under a Connection options heading so per-subcommand help is no longer 30 random flags. 6 output flags move under Output options.
    • 39 sentinel default_value = "_" arguments now carry hide_default_value = true so subcommand help stops rendering [default: _] for every URL/path positional.
    • cleanup description rewritten to a single accurate sentence (was a confusing two-line run-on suggesting it handled duplicates, which it doesn't — that lives in dedupe).
    • dedupe gained the missing description.
    • tree --depth help no longer leaks the internal "TypeId mismatch" implementation note.
    • Invalid URL error now suggests --profile <name> when the input has no scheme, instead of leaking the raw url::ParseError message.

Skipped — flagged for follow-up

  • --exclude rename: sync already has a local --exclude (with -e short) whose Vec<String> semantics differ from the global --exclude-global; unifying them would force a refactor of the per-command merge loop. Out of scope for a polish pass; tracked for a dedicated PR with proper test coverage.

Downloads:

  • Windows: .msi installer, .exe, or .zip portable (no installation required)
  • macOS: .dmg disk image
  • Linux: .deb, .rpm, .snap, or .AppImage

Download AeroFTP

AeroFTP v3.6.4

25 Apr 19:50

Choose a tag to compare

[3.6.4] - 2026-04-25

Patch release: Windows keystore export fix + autostart UX + update opt-out

Small but high-impact patch release driven by two community bug reports (issues #123 and #124). The headline fix unblocks the Settings → Backup → Export Keystore flow on Windows, where every export was leaving an orphan .tmp file behind and surfacing an "Access is denied (os error 5)" error. Three quality-of-life settings round out the release.

Fixed

  • Windows keystore export os error 5 (issue #124) — Exporting a vault backup from Settings → Backup raised "IO error: Access is denied. (os error 5)" on every Windows machine and left an aeroftp_keystore_*.tmp file in place of the final .aeroftp-keystore. Root cause: the atomic write helper opened the freshly-written temp file with File::open (read-only on Windows) and then called sync_all, which on Windows maps to FlushFileBuffers and requires a GENERIC_WRITE handle. The flush failed before the rename ran. Fix: keep the existing write handle through flush + sync_all and gate the parent-directory fsync to Unix only, since File::open on a directory needs FILE_FLAG_BACKUP_SEMANTICS on Windows and is a no-op for durability there anyway.
  • Windows internal Terminal frozen on Start (issue #125) — Opening AeroTools → Terminal → Start on Windows produced a blinking cursor with no shell prompt and no response to keystrokes; the only escape was restarting the app. Root cause: the launcher passed -Command "function prompt { ... }" to PowerShell to inject a colored prompt, but on Windows 10 with the default ExecutionPolicy the parser stalled inside -Command, spawn_command never returned, the Tauri invoke awaited forever, the frontend never received a session id, and every keystroke was silently dropped at the connected-tab gate. Fix: drop the prompt customization on Windows and start PowerShell as a plain -NoLogo interactive shell. Linux and macOS were unaffected. A user-level colored prompt can be added via $PROFILE if desired.
  • NSIS installer now reports the PATH change in the install log (issue #125 follow-up) — After registering $INSTDIR in HKCU\Environment\Path, the installer now prints "Open a NEW terminal to run 'aeroftp-cli'" so users who installed via WinGet/UniGetUI in an already-open PowerShell are not surprised when aeroftp-cli is "not recognized" — existing shells cache %PATH% at launch and need to be reopened.

Added

  • Password strength meter on the keystore backup form — The Export Keystore section now shows the same animated 4-segment strength bar already used by AeroVault, with a 0–100 score and a colour-coded label (Weak/Fair/Strong/Excellent). Reuses PasswordStrengthBar so future tweaks land in both places at once.
  • Start minimized to tray on autostart (issue #123) — New "Start minimized to tray" checkbox under Settings → General → Startup (visible only when "Launch on system startup" is enabled). When the OS launches AeroFTP from the autostart entry, the main window stays hidden and only the tray icon appears, matching the behaviour expected from background sync apps. Manual launches (double-click on the desktop or Start menu shortcut) always show the window. Detection uses a new --autostart argument passed by tauri-plugin-autostart and surfaced to the frontend via is_autostart_launch. Default off — existing users see no change.
  • Don't check for updates toggle (issue #123) — New checkbox under Settings → General → Software Updates that disables both the 5-second startup check and the periodic 24-hour check. The manual "Check for Updates" button continues to work, so the option simply gives users who manage AeroFTP through external package managers (WinGet, AUR, Snap auto-refresh) a way to opt out of the in-app update prompts and bandwidth.

Changed

  • NSIS installer no longer reinstates the desktop shortcut on every upgrade (issue #123) — On a fresh install the bundler still creates Desktop\AeroFTP.lnk as before. On an upgrade, however, the installer now snapshots the desktop shortcut state in the pre-install hook and, if the user had previously deleted the shortcut, removes the one the bundler just recreated. Users who keep the shortcut see no change.
  • Windows NSIS post-install hooks now actually run (issue #125 root cause) — From v3.6.2 onward the installer hook file defined the four lifecycle hooks as CUSTOM_{PRE,POST}_{INSTALL,UNINSTALL}, but Tauri's bundled installer.nsi invokes them gated on !ifmacrodef NSIS_HOOK_{PRE,POST}{INSTALL,UNINSTALL}. The macro names didn't match, so !ifmacrodef returned false and every hook in the file was skipped silently — the HKCU PATH registration, the .aerovault file association, the VC++ Runtime bootstrap, the new desktop-shortcut snapshot logic — none of it ran in any shipped Windows installer. Renaming the macros to the names Tauri actually checks for activates all of them in v3.6.4. Existing installs with no PATH entry will get one on the next upgrade. Diagnosed thanks to a Windows-side investigation reported in docs/dev/aeroftp-windows-path-hook-bug-report-2026-04-25.md.
  • Silent uninstall preserves user data — The pre-uninstall hook prompts the user via three MessageBox dialogs to selectively remove saved servers, AI chat history and cache. Now that the hook actually runs, those dialogs would have surfaced during every WinGet upgrade (which silently uninstalls the old version before installing the new one), either popping blocking modals or — depending on Windows version — defaulting to "yes" and wiping data. The hook now bails out early via IfSilent, preserving everything when not in interactive mode.
  • Cross-Profile Transfer pre-selects the active server — When the dialog is opened from the remote pane while connected, the source profile and source path are now pre-populated from the active session, so the most common flow (copy from the server you're already looking at to another saved server) takes one click instead of three. Source/destination filtering — already in place — still excludes the chosen source from the destination list.

Translations

  • All four new settings labels and descriptions translated across the 47 supported locales.

Downloads:

  • Windows: .msi installer, .exe, or .zip portable (no installation required)
  • macOS: .dmg disk image
  • Linux: .deb, .rpm, .snap, or .AppImage

Download AeroFTP

AeroFTP v3.6.3

25 Apr 12:12

Choose a tag to compare

[3.6.3] - 2026-04-25

Unified Tool Dispatcher + Cloud Provider Sweep + AeroVault Pro Foundations

The post-3.6.2 sprint consolidates three years of organically-grown AeroAgent surface into a single, audited tool engine shared by the Tauri GUI, the standalone aeroftp-cli binary and the MCP server. In parallel, eighteen cloud providers gain trash management, version history, share links and label/tag CRUD, while the desktop backend grows new pillars (server health diagnostics, TOTP 2FA scaffold, vault history) that prepare the ground for AeroVault Pro and the upcoming biometric unlock work.

Added

  • Unified AI tool dispatcher (T3 Gate 2) — All AeroAgent tools (53 entries across local, system, remote and RAG/memory areas) now flow through a single ai_core::tools::dispatch_tool with surface-aware filtering (GUI / CLI / MCP). Per-area handler modules (local_tools.rs, system_tools.rs, remote_tools.rs, agent_tools.rs) host the canonical implementations; per-surface ToolCtx impls (TauriToolCtx, CliToolCtx, McpToolCtx) bridge to the appropriate runtime. The legacy execute_ai_tool / execute_cli_tool / mcp::execute_tool dispatchers stay as thin fast-path wrappers, eliminating the long-standing drift between three parallel match statements. 11 parity tests prove identical output across surfaces; the security regression suite gains an Area B check ensuring system_tools always delegates shell_execute to the canonical denylist source. Behavioural wins: local_trash is now available on CLI, clipboard_* and archive_compress/archive_decompress use native Rust libraries instead of subprocess shellouts (no more xclip/zip/tar/7z runtime dependencies on CLI), and validate_path adopts component-aware matching so /bootcamp is no longer falsely flagged as /boot.
  • Provider trait expansion — 7 new optional methods: list_trash, restore_from_trash, permanent_delete, list_versions, download_version, restore_version, create_share_link, get_storage_quota. The RemoteEntry struct grows MIME type, owner/group, octal permissions, symlink target, and a free-form metadata bag. Box, Google Drive, Dropbox, OneDrive, Zoho WorkDrive light up the full feature matrix.
  • Box Pro feature set: trash management, file move/comment/collaboration, watermark (Enterprise), folder locks (Enterprise), inline tag chips with PRO badge.
  • Google Drive starring + comments + properties: star/unstar from context menu, add comments via prompt dialog, set custom key-value properties and description; file listing now includes starred, description, properties fields.
  • Dropbox tag management + Trash Manager: full tag CRUD via Dropbox Tags API (reuses generic BoxTagsDialog); dedicated modal for deleted files (restore + permanent delete).
  • OneDrive Trash Manager: full recycle bin lifecycle (move to trash, list, restore, permanent delete).
  • Zoho WorkDrive labels + versioning: list team labels, get/add/remove labels on files via ZohoLabelsDialog with color-coded toggle list; list versions, download specific version, restore/promote version through the StorageProvider trait.
  • Server Health Check — Real-time diagnostics for saved servers: DNS / TCP / TLS / HTTP probes with latency stats, 0–100 health score, SVG radial gauge, latency bars, Canvas 2D area chart for trend. Right-click any server card → Connect / Edit / Duplicate / Health Check / Delete (useContextMenu hook). Batch health check across all saved servers in parallel with healthy/degraded/unreachable summary.
  • TOTP 2FA scaffold (totp.rs) — RFC 6238 authenticator core ready for the optional vault second factor: issuer, period, digits, base32 secret import/export, code verification with drift window. Will surface in Settings > Security in a follow-up release.
  • Vault history (vault_history.rs) — SQLite-backed recents tracker for AeroVault Pro: last-opened timestamp, security badges, dedupe by canonical path. Powers the new VaultHome recents grid and "reopen" one-click flow.
  • AeroAgent server context tools registered in unified registry: server_list_saved, server_exec, plus the full aeroftp_*remote_* alias map (including newly-registered server_list_saved alias).
  • Aerorsync standalone serve binarybin/aerorsync_serve.rs (renamed from rsync_proto_serve.rs) ships as a separate [[bin]] target for capture/test workflows.

Changed

  • rsync_native_proto/ module renamed to aerorsync/ — Aligns the experimental Rust-native rsync protocol implementation with the AeroFTP product naming. 41 source files, the capture harness, all fixtures and the standalone serve binary move under src-tauri/src/aerorsync/. CI workflows, Cargo bin section, lib.rs module declaration and the integration test path are updated to match. No on-the-wire changes: the protocol stays byte-identical to v3.6.x.
  • AeroAgent tool count: 53 unified registry entries — formerly counted as ~47 across three parallel dispatchers, now consolidated into a single TOOL_DEFINITIONS table where the same handler runs unmodified on GUI, CLI and MCP.
  • CLI relative-path resolution snapshot at process startCliToolCtx::new() captures std::env::current_dir() once at construction and exposes it via ToolCtx::context_local_path(). Eliminates the silent regression where the unified dispatcher saw paths "as-is" instead of resolved against cwd. Behaviour matches the legacy CLI resolve_path closure exactly.
  • shell_execute working_dir validation hardened — The unified system_tools::shell_execute now runs validate_path(working_dir, ...) against the system deny-list (/etc/shadow, /proc, /sys, /boot, /root, /etc/ssh, /etc/sudoers, …) before delegating to the legacy GUI helper, restoring CLI parity that was lost during Area B migration.
  • upload_many / delete_many now report real elapsed seconds — the placeholder elapsed_secs: 0u64 returned to MCP and AI clients is replaced with Instant::now().elapsed().as_secs() measured around the inner loop.
  • Vite 5 → 8 + @vitejs/plugin-react 4 → 6 — Major bump of the frontend build chain. Dev server, production build and Tauri packaging stay green. package-lock.json regenerated.
  • Cargo.lock refreshed — picks up transitive dependency churn from the v3.6.x feature work (provider crates, ai_core additions, server_health, totp, vault history, aerorsync rename).

Fixed

  • SFTP symlink-aware listingSftpProvider::list() now follows symlinks via sftp.metadata() so directory traversal works on NAS devices that report symlinks for share roots (WD MyCloud, Synology DSM6, ASUSTOR ADM).
  • Azure Blob server-side copyCopy Blob API with x-ms-copy-source and safe resolve_blob_path() prefix resolution; eliminates the GET+PUT roundtrip for in-account moves.
  • local_trash now available on CLI — was GUI-only in the legacy dispatcher; the unified registry exposes it on both surfaces with the same semantics.
  • path_style no longer false-coalesced in App.tsx — Drop the || false on effectiveParams.options?.pathStyle and cloudServer.options?.pathStyle so explicit user choices (true / false / undefined) reach the backend faithfully without being squashed.
  • vault_remote.rs validation tightened — null-byte rejection on remote vault paths, symlink refusal on Unix mode lookup, parent canonicalization before opening .aerovault files served from remote providers.

Security

  • russh 0.59 → 0.60.1 — Closes Dependabot HIGH (GHSA-f5v4-2wr6-hqmg): pre-auth DoS via unbounded allocation in the keyboard-interactive auth handler. AeroFTP exposes a russh-based SSH server through aeroftp-cli serve sftp, so the fix is mandatory. The bump required updating the ed25519 server-key generation call site to the new CryptoRng bound — added a narrow rand_010 (rand 0.10) alias for that single line, with the rest of the codebase staying on rand 0.8.
  • rand 0.8.5 → 0.8.6 — Closes Dependabot LOW (GHSA-cq8v-f236-94qc): rand was unsound when paired with a custom logger using rand::rng(). Direct dep bump only; the build-time-only transitive rand 0.7.3 (pulled by phf_generator 0.8.0 / selectors 0.24.0 in the Tauri stack) is left in place — not in the runtime path and the upstream chain is locked at this combination by Tauri's wry dependency.
  • validate_path component-aware matchingpath_matches_prefix(path, prefix) helper replaces 11 occurrences of s.starts_with(d). Eliminates false positives on prefix matches (e.g. /bootcamp was being blocked as if it were under /boot).
  • Single source of truth for shell_execute denylist — Both the GUI fast-path and the new system_tools::shell_execute delegate to ai_tools::shell_execute for the canonical 35+ regex denylist + meta-character filter. The CI security regression script (security-regression.cjs) now actively verifies this delegation chain stays intact.

Internal

  • 53 entries in TOOL_DEFINITIONS distributed: Area A local_* = 21, Area B clipboard/shell/archive = 5, Area C remote_*/aeroftp_*/server_exec = 24 (incl. server_list_saved alias), Area D rag_*/agent_memory_* = 3.
  • tool_parity.rs integration test suite — 11 tests proving identical output across GUI and CLI surfaces for local_read, local_write, local_mkdir, local_delete, local_grep, shell_execute, rag_index, rag_search, plus 3 remote alias parity tests with a FakeRemoteBackend.
  • security-regression.cjs Area B coverage — verifies system_tools::shell_execute calls crate::ai_tools::shell_execute (single denylist source) and validates working_dir against the deny-list before the call.
  • Quality bar at closure: cargo check --features aerorsync --lib, cargo clippy --all-targets --features aerorsync -- -D warnings, cargo test --features aerorsync --lib (1018 / 1018 passed)...
Read more

AeroFTP v3.6.1

23 Apr 21:58

Choose a tag to compare

[3.6.1] - 2026-04-23

Windows First-Class Delta Sync + PR-T08 Eligibility Gate + Dependency Security

The "historical step" release: byte-level delta sync becomes a first-class citizen on Windows, with no bundled rsync.exe, no WSL requirement, and no reliance on any external binary. Windows rides the native rsync 31/32 wire protocol re-implemented in pure Rust (clean-room, GPL-3.0-or-later) that previously lived behind an opt-in cargo feature; from this release the feature is default-on and the protocol module is part of the mainline tree.

Added

  • Windows cross-OS delta sync: SftpProvider::delta_transport() dispatches cross-platform. When the proto_native_rsync feature is compiled in (default from this release) and a session has SFTP + SSH key auth, Windows uses the native Rust rsync implementation end-to-end; the binary-rsync classic fallback stays available on Unix through the same DeltaTransport trait surface. No binary shipping, no WSL dependency.
  • Delta Sync eligibility gate (PR-T08): before starting an AeroSync run, a cached Tauri probe (sftp_probe_delta_eligibility, 5 s timeout) verifies that the current session can actually exercise the delta path. When it can't, a modal surfaces the sanitized reason, a "Don't show again for this server" persistent preference on the saved profile, and a "Learn more" link to the public docs page. The modal fires only when the delta toggle is on and the server is SFTP — classic-only sessions are never interrupted.
  • Fallback reason surfacing (PR-T05): FileOutcome and TransferEvent carry an optional fallback_reason populated only when the delta path was attempted for the file and fell through transparently. SyncPanel renders a grey classic badge (with the sanitized reason as tooltip) next to affected files — distinguishing "classic by design" from "classic after delta attempt". 7 new i18n keys translated in all 47 supported languages.
  • CI Windows native build lane: new windows-native job in delta-sync-integration.ymlcargo check with and without feature, unit tests with and without feature on windows-latest. Catches cross-OS regressions at PR time.

Fixed

  • SFTP upload mtime preservation: SftpProvider::upload() now sets remote atime+mtime to the local source's mtime after a successful upload, using SFTP ACMODTIME. Before this fix, every sync after an upload saw remote_mtime > local_mtime and spuriously re-uploaded unchanged files. Observed live on SSH MyCloud HD: second sync after a single-file change now reports uploaded=1 / skipped=1 where the pre-fix behavior was uploaded=2.
  • Versioning archive name collision: SyncVersioning::archive_file now produces -1, -2, ... suffixed names when a second version lands with the same filename (unique_archive_path helper). Retention windows no longer silently clobber archived copies of the same file.
  • CloudPanel versioning_strategy type round-trip: the field is now a tagged union that mirrors the Rust CloudVersioningStrategy shape (disabled / trash_can / simple / staggered) instead of a stringly-typed sentinel, so the select round-trips without downstream parsing.

Security

Changed

  • proto_native_rsync feature is default-on: the native rsync protocol implementation is now compiled by default. Build with --no-default-features if you want a leaner binary without native delta support (classic binary rsync stays available on Unix regardless).
  • rsync_native_proto/ module moved into the tree: the native implementation, previously gitignored as a scaffold, is now versioned mainline source. Large capture harnesses (Docker images, rsync reference binaries, frozen transcripts) stay out of git via targeted .gitignore patterns on their specific subdirectories.
  • Native rsync toggle eligible on Windows: native_rsync_feature_compiled() no longer requires cfg(unix) — the dispatch is now cross-platform, so the runtime toggle surfaces on any OS where the feature is compiled in.
  • CI retrigger surface widened: delta-sync-integration.yml paths: filter now includes lib.rs, settings.rs, and Cargo.lock, so future changes that affect the delta stack transitively retrigger the lane automatically.

Licensing note

The native rsync module (src-tauri/src/rsync_native_proto/) is an independent clean-room Rust re-implementation of the rsync wire protocol. No rsync source code was copied; dependencies are permissively-licensed Rust crates (russh, ssh2, zstd, xxhash-rust). The rsync project itself is GPL-3.0-or-later and AeroFTP is GPL-3.0-or-later as well, so licence compatibility is unconditional. See src-tauri/src/rsync_native_proto/README.md for full details.

Downloads:

  • Windows: .msi installer, .exe, or .zip portable (no installation required)
  • macOS: .dmg disk image
  • Linux: .deb, .rpm, .snap, or .AppImage

Download AeroFTP

AeroFTP v3.6.0

22 Apr 14:30

Choose a tag to compare

[3.6.0] - 2026-04-22

AeroSync UX Upgrade + Critical SSH Host-Key Fix

Release focused on making the AeroSync optimized-transfer path visible to the user and on a critical SSH host-key dialog fix. The optimization logic has been progressively landed over the last weeks; this release is the moment it becomes visible in the product.

Added

  • Delta Savings widget in AeroSync: when a file travels through the optimized transfer path during sync, an inline badge next to the file's status marks it; at the end of the run an "Optimized transfer" summary card aggregates N files · bytes saved · speedup. When the effective speedup falls below 1.5x the card switches to a neutral "Optimized transfer" variant to avoid misleading framing. The widget is fully theme-aware across light/dark/tokyo/cyber and hidden entirely when no file benefited from the path. Translated in all 47 supported languages.
  • Per-file breakdown in aeroftp_sync_tree MCP tool: the response now carries summary.delta_files[] (array of {path, bytes_sent, total_size, speedup}) capped at 500 entries, plus a summary.delta_files_truncated flag when a run crosses the cap. Aggregate counters in summary.delta_savings keep counting past the cap. Both keys are omitted on runs where no file used the optimized path, preserving the absence-vs-null contract with the existing delta_savings block.

Fixed

  • Critical: Host Key Changed dialog no longer reappears after Accept: the russh library reports the changed-key line number as 1-based; the internal sftp_remove_host_key command was treating it as a 0-based array index, which meant Accept surgically removed the line after the stale entry instead of the stale one itself. Repeated Accept clicks piled valid entries on top of the original stale one, and every subsequent connection hit the stale line first and re-triggered the dialog. The fix uses 1-based indexing correctly and now also prunes any other plaintext entry for the same (host, port, algorithm) tuple that matches the incoming key's algorithm — so files already corrupted by earlier broken attempts get cleaned up in the same pass. 11 new unit tests pin the regression cases (line zero rejected, 1-based indexing, duplicate pruning, host-mismatch corruption guard, hashed-entry tolerance).

Changed

  • Optimized transfer path reachable from SyncPanel on SFTP: earlier releases had the decision wired in the unified sync core only — AeroSync UI actually iterates per-file commands that never entered that branch. This release extends the decision to upload_file / download_file / provider_upload_file / provider_download_file so sessions with SFTP + SSH key authentication + a capable remote now actually exercise the optimization in the day-to-day UI flow. The decision remains self-gated (silent fallback to classic when the session is not eligible); hard rejections (SSH host-key mismatch, permission denied) surface as transfer errors without silent retry.
  • TransferEvent now propagates optional delta_stats: the event emitted to the frontend on complete carries per-file stats from the optimized path when applicable (serialized with skip_serializing_if, absent for classic transfers — no wire overhead for non-SFTP providers). Frontend accumulates these into the session-level summary client-side.

MCP (pre-release carryovers from v3.6.0 cycle)

  • aeroftp_read_file soft-truncate dentro hard cap: oversized file (oltre preview_kb ma entro il cap 1 MB) ritornano contenuto troncato con truncated:true invece di errore duro. Il validator rifiuta solo oltre il hard cap 1 MB. Elimina i retry forzati che gli agent facevano quando incontravano file appena oltre la finestra di preview richiesta.
  • aeroftp_check_tree espone compare_method anche sul gruppo match: il JSON di ritorno ora include groups.match dettagliato alla pari di differ/missing_local/missing_remote. Ogni entry porta compare_method: "checksum" | "size" così l'agent sa se il match è stato crittograficamente verificato o è fallback dimensionale (tipicamente su FTP che non ha checksum server-side).

Build / CI

  • Dedicated fallback-fixture CI lane: delta-sync-integration.yml gains a second job running against the password-only SFTP Docker fixture. Covers the silent-fallback branch (password-only sessions) and the hard-rejection contract so a regression on those paths cannot ship unnoticed. Protected by nick-fields/retry@v3 (2 attempts, 10s wait) for Docker-on-runner flakiness. Both jobs block PRs on failure.

Internals

  • SyncReport domain types expanded: DeltaSavingsSummary (aggregate) and new DeltaFileEntry (per-file breakdown) are public types; DELTA_FILES_CAP = 500 exposed as a crate-level constant. The accumulator is one branch driving both aggregate and per-file tracking — impossible to drift.
  • Stderr sanitizer hardened: /home/<user>, /Users/<user>, C:\Users\<user> and .ssh/* path segments redacted before fallback_reason / hard_error messages flow to UI, logs, or MCP responses. Message capped at 512 characters to keep response arrays bounded.
  • RsyncStats.warnings downgraded to pub(crate): entries may contain remote file paths and must not leak without sanitization.

Downloads:

  • Windows: .msi installer, .exe, or .zip portable (no installation required)
  • macOS: .dmg disk image
  • Linux: .deb, .rpm, .snap, or .AppImage

Download AeroFTP

AeroFTP v3.5.9

20 Apr 21:56

Choose a tag to compare

[3.5.9] - 2026-04-20

CLI Agent Experience Polish

Follow-up patch to v3.5.8 focused entirely on the CLI surface. All items are small, independent, and addressed in one coherent pass so an agent using aeroftp-cli against a generic FTP hoster has the same UX quality the MCP server got in v3.5.8.

Added

  • plan[] in sync --dry-run --json: every candidate operation is now listed with {op, path, local_size, remote_size, conflict_path}. Real (non-dry-run) runs omit the field via skip_serializing_if, so legacy parsers that never asked for dry-run see the exact same shape. Agents no longer have to fall back to parsing the text-verbose output to build an execution plan.

Fixed

  • Missing-parent uploads now explain the failure: put runs a pre-flight stat on the remote parent directory. If the parent is missing the CLI errors out with "Parent directory '/X/Y' does not exist on the remote. Create it first with: aeroftp-cli mkdir -p '/X/Y'" — one crisp message instead of three retries of a generic 553 Can't open that file: No such file or directory returned by the hoster. is_retryable_exit now excludes exit code 2 (not-found) so the retry loop stops burning attempts on stable failures.
  • Sync remote scanner auto-reconnects on transport failure: sync_core::scan_remote_tree now classifies list() errors against the same is_transport_level pattern used by the MCP pool (variant matches on NotConnected/ConnectionFailed/Timeout/NetworkError/IoError plus message patterns like "Data connection is already open", "broken pipe", "connection reset"). When it fires, the provider is disconnected and reconnected, then list() is retried once. Previously the scanner logged a warning and treated the failure as an empty directory — which let sync silently duplicate files that actually existed on the remote.
  • ls follow-up hint no longer ships a literal *.ext placeholder: suggest_ls_followup now renders "*" so agents copy-pasting the hint get real results. The *.ext string survives only in bootstrap playbook JSON where it is documented as a placeholder the user must substitute.

Build

  • cli-smoke Windows runner installs Strawberry Perl: the openssl-sys vendored build pulled in transitively by ssh2 = "=0.9.5" requires Params::Check to configure OpenSSL, and the stock windows-latest Perl no longer ships it. Added a choco install strawberryperl step gated by runner.os == 'Windows'. Linux and macOS jobs are unaffected.

Downloads:

  • Windows: .msi installer, .exe, or .zip portable (no installation required)
  • macOS: .dmg disk image
  • Linux: .deb, .rpm, .snap, or .AppImage

Download AeroFTP