[4.1.3] - 2026-07-11
Archive Encryption and Compression at a Glance, Crypt-Overlay Scope with Keyfile 2FA, Safer CLI Deletes, Faster SFTP Listing and macOS Stable
A polish-and-hardening release: AeroFTP surfaces archive encryption, real compression method and AeroVault generation at a glance in both the local and remote file browsers without downloading anything, the crypt overlay now shows plaintext outside its bound subtree and decrypts only inside it across the GUI, CLI and MCP and gains an optional keyfile second factor, the destructive CLI delete verbs get a real dry-run preview with recursion now opt-in, recursive SFTP listing is about three times faster, macOS is promoted from beta to stable, and a broad security audit runs the length of the cycle. Pre-tag commit audit: PASS, the final pre-release audit closed six integrity, fail-open and race residuals; 47 languages translated.
Added
- Optional keyfile second factor for native AeroCrypt: a "something you have" file mixed into the key derivation (stronger than rclone's password2) with no change to the on-disk object format; generate a transfer-safe keyfile from the GUI or CLI, make a vault keyfile-only (an empty password is legal), and the keyfile path travels through profile export/import as a re-pointable pointer that resolves fail-closed at connect across GUI, CLI and MCP (@EhudKirsh, #272).
- Archive encryption, compression and AeroVault generation surfaced at a glance in the local file browser: a padlock next to the Type (closed emerald for a strong cipher, amber for weak ZipCrypto, open grey for a detectable but unprotected archive) for password-protected zip, 7z and RAR showing the real detected cipher (AES 256/192/128, ZipCrypto, RAR5 AES-256, RAR4 AES-128), an optional Encryption column, a Compression column with the real method (Deflate, BZip2, LZMA, LZMA2, PPMd, Zstd, or Store for an uncompressed archive), and an AeroVault generation chip (v2/v3/v4) on our own
.aerovault,.aeroftpand.aeroftp-keystorecontainers; detection reads only the archive header lazily and never downloads or opens the file, and a locked archive gets a dedicated draggable unlock modal that names the real cipher. - New Date format setting (Settings > General): choose how dates render app-wide (Localized, ISO 8601, DD/MM/YYYY or MM/DD/YYYY), applied live to the file browser and every other date with no restart; localized dates now follow the selected app language instead of the OS locale.
- The same encryption and AeroVault surfacing on the remote panel: an
.aerovault,.aeroftpor.aeroftp-keystoreon a remote, plus password-protected third-party zip and 7z, show the padlock, Encryption column and AeroVault chip without downloading the file, reading only the header via provider ranged reads; scoped to the range-capable transports (SFTP, FTP/FTPS, S3, WebDAV, Backblaze B2, Koofr, and now Azure Blob, Uploadcare, Cloudinary and ImageKit) and degrading to no badge where a transport cannot serve byte ranges. - The crypt overlay now shows plaintext outside its bound subtree and decrypts only inside it, from the CLI and MCP too (CWP-20C):
ls,tree,lsjsonand the MCP listing tools were reporting a scoped-overlay remote whose root is not the vault as empty or as only its encrypted items; the read path is now scope-aware (decrypt strictly below the anchor, pass everything at or outside it through as raw plaintext) while every write stays fail-closed so plaintext can never land where ciphertext is expected, verified live on Filen and lab SFTP (@EhudKirsh, #369, #266). - CLI
--no-cryptconnect flag to bypass a bound crypt overlay and connect raw, mirroring the GUI crypt button and closing a CLI-parity gap (#390). - Full S3 trash and version management: browse soft-deleted objects and delete markers under a prefix, undelete, copy-forward an older version to current, purge a single version, and empty the trash with a dry-run preview, from the GUI, the CLI (
versions trash/versions purge/versions empty-trash) and MCP; the crypt overlay is peeled to the concrete S3 provider so names decrypt while every operation round-trips on the raw key, andmkdirno longer writes a zero-byte directory marker that rendered as a phantom empty file on some gateways (@EhudKirsh, #266). - A real dry-run for the destructive CLI delete verbs:
aeroftp-cli rm --dry-runandpurge --dry-runprint the exact files and directories that would go plus the bytes reclaimed and delete nothing, the MCPaeroftp_delete/aeroftp_delete_manytools take the samedry_runreturningwould_delete: truewith the byte total, andrm/purgenow honour the global filters (--include,--exclude-global,--min-size/--max-size,--min-age/--max-age,--files-from) so a filtered recursive delete removes only the matching files and the directories it empties in doing so. - New
aeroftp-cli inventorysubcommand: the authoritative, drift-proof inventory of every CLI subcommand and MCP tool read straight from the in-code registries, emitted as JSON, a Markdown table or a--checkCI drift gate, with a committed snapshot atdocs/COMMAND-INVENTORY.json(the real counts: 90 CLI subcommands, 73 MCP tools, 39 agent tools). lsjson --ndjsonstreaming and a listing spinner: a recursivelsjson -Rcan stream one compact JSON object per line as each entry is discovered, and a stderr progress spinner names the directory being listed on a TTY; the default sorted-array output is unchanged byte for byte and a pipe or redirect stays pure JSON.profile-import --dry-runand nativeexport aeroftp/import aeroftpaliases: preview which profiles a.aeroftpbundle would add or skip as duplicates without touching the vault or keyring, and reach our own format from theexport/importfamilies next to the foreign ones.profile-addcan seed the credential in one step:--password-stdinplus new--credential-json/--credential-json-filewrite into the same vault key the GUI Edit modal uses, so a CLI-created profile is immediately connectable; the sources are validated before the profile is persisted, so a malformed blob fails fast with no orphan profile.- First-run host-config import for the Flatpak: a consent-gated, copy-only import of the native
~/.config/aeroftpon first run (nothing is overwritten and the vault still needs its password), from the GUI first-run prompt andaeroftp-cli flatpak-import, so a user moving from the.debdoes not see an empty app (#310).
Changed
- macOS promoted from beta to stable: it boots and runs cleanly on Intel and Apple Silicon, so the release dmg drops the
-betasuffix (nowAeroFTP_<ver>_<arch>.dmg) and the README badge and Platform Status row read stable alongside Linux and Windows; the dmg is still not Apple-signed, so Gatekeeper needs the documentedxattrworkaround. - Recursive listing over SFTP is about three times faster:
SftpProvider::listwas issuing one serialLSTATper directory entry purely to test the symlink bit, which theREADDIRreply already carried, and this dominated every recursive walk (the GUI panel, sync scan,ls -R,tree,size,rmdirs, the delete plan); the mode now comes from the attributes already in hand and the few real per-entry follow-ups (attr-less recovery, symlink resolution) are pipelined over the one SFTP channel, measured at roughly 42s down to 16s on a 620-entry walk and 37s down to 12s on a symlink-heavy one, with byte-identical output. - DEFLATE level 1 now stays in the native tools' size band: on this build flate2 resolves to the zlib-rs backend whose level 1 is a speed-first preset that ran about 40% larger than
gzip -1on text, so user level 1 is now pinned to backend level 2 at every DEFLATE entry point (zip, tar.gz, standalone gz and the size estimator), which comes out smaller and still faster thangzip -1; 7z level 1 was evaluated and deliberately left as-is, byte-identical toxz -1(#406). - Shared 6-box TOTP input across the 2FA Quick Connect pages: the Two-Factor Code entry is now one digit-only, paste-and-autofocus 6-box component reused on every 2FA page, and the kDrive Drive ID field is narrowed to its 10-digit numeric shape (@EhudKirsh, #369).
- Connection and profile edit polish: a duplicated profile now appends at the tail instead of jumping to the top, editing a saved OAuth or API profile can save a name or local-path change without re-running the sign-in (a Save/Cancel pair disabled until a field actually changes, applied to the live session immediately), and the FileLu Native API entry now shows the FILELU MODES tab bar like the S3 and WebDAV entries.
- The MCP listing tools now return one entry shape:
aeroftp_treeroutes every entry through the sameentry_jsonchokepoint aslist_files,search_filesandfile_infoand adds only itsdepthfield, so a recursive listing is exactly a flat listing plusdepth; the CLIlsjsonfield names are frozen with a doc comment so no future cleanup can quietly break the scripts that parse them. - The
--checkershelp is now honest: it promised parallel metadata probes, but the--no-traversestat sweep runs sequentially today, so the help now says so and points at the provider-pool refactor as where it becomes a real concurrency gate.
Fixed
- Filen local S3 and WebDAV bridges auto-detect HTTP/HTTPS at connect: a mismatch between the profile and the protocol chosen in the Filen app no longer blocks the connection, the loopback IP is pinned to avoid a
local.*.filen.ioDNS failure on Windows, and the Filen WebDAV Quick Connect drops the manual selector for an auto-detect note (#389). - Ejecting a removable drive while AeroFile is inside it steps the view back to Home instead of leaving a stale view of the removed drive, matching the system file explorer (@EhudKirsh, #351).
- The Filen Quick Connect no longer prints LOCAL twice: the local bridge modes read WebDAV and S3 under a single LOCAL badge, as the MEGA page already did (@EhudKirsh, #369).
- The pCloud Drive OAuth credentials link is renamed Manage credentials and points at the my_apps console so it reads honestly, translated across all locales (@EhudKirsh, #369).
- The overall Transfer Queue progress bar no longer pegs at 98-100% during a folder upload: it now climbs on the backend's real aggregate byte total, fixed upfront from the pre-scan, instead of a lazily-enqueued item count (@EhudKirsh, #364).
- With the crypt overlay on, uploading into a plaintext-named folder created while the overlay was off no longer creates a phantom encrypted folder and misplaces the file: the write is refused with a clear message, and arming the overlay re-anchors you out of a hidden plaintext folder to a valid encrypted location while keeping you in place inside a genuine encrypted subfolder (#390).
- The 2FA 6-box code input no longer skips a box on each keystroke: typing a digit advanced the caret by two boxes because the fill helper and the single-digit path both stepped forward; focus now advances one box at a time on all three pages, with paste and backspace unchanged (@EhudKirsh, #369).
- The red View Trash button now works under the crypt overlay for the cloud providers (Google Drive, pCloud, MEGA, kDrive, Koofr, Box, OpenDrive, Jottacloud, Dropbox): trash, restore and empty downcast the live provider box, but under Crypt that box is the overlay decorator, so a shared helper now peels the overlay to the inner transport before every provider-specific downcast, and the trash listing decodes the display name to plaintext where restore keys on an opaque id (@EhudKirsh, #397).
- Saving, uploading or downloading over SFTP no longer hangs about ten minutes before falling back: the native rsync delta probe had no bounded timeout on the russh leg, so an SFTP-only server that never answers blocked it and the negative cache re-probed per file; each probe is now bounded to 8 seconds and a failure is cached for 30 minutes, so a rsync-less remote falls back to plain SFTP within seconds and is not re-probed per file (@coolfocks, #398).
- A second double-click during a slow listing no longer overshoots the target (a relative
..on FTP going up twice): remote and local navigation now use a synchronous in-flight latch that ignores a re-entrant navigation, and the listing spinner carries a Cancel that discards the in-flight result and releases the latch so a stalled navigation never traps you (@JonathanHarford, #401). - The batch delete, upload and download triggers no longer fire a duplicate op on a second click: the four batch handlers are now gated by a synchronous in-flight latch that covers the toolbar, keyboard shortcuts and context menu at once, the toolbar buttons grey out while in flight, and the scanning toast carries a Cancel that breaks the batch loops so an external stall never traps the user.
- Every foreground remote listing is now visible, named and genuinely interruptible: the connect handlers plus
switchSession,switchGitHubBranchand the AeroCloud tab issued their initial listing through a raw invoke that bypassed the spinner, and the old Cancel only bumped a frontend counter while the listing kept running; the abort now happens in the backend under a cancellation token via a newcancel_remote_listingcommand that touches no provider state, so cancelling a blocked connect tears the half-open session down and returns you to My Servers, while cancelling a drill-in leaves you where you were. - Connect no longer hangs forever in an endless spinner when a Tauri command dies by panic: every FTPS connection from the GUI was panicking before it ever spoke to the server because rustls could not auto-select a crypto backend with both
aws-lc-rsandringin the tree (the CLI already pinned it, the GUI never did), and a panicking async command never sent an IPC response so the spinner and its Cancel went dead; the crypto provider is now installed once at startup and the connect family runs under a panic-safe catch plus a 120s frontend backstop, so a panic becomes a normal error the UI renders. - InfiniCLOUD's July 2026 SSO migration is handled: the provider Sign-up link is repointed at the new portal (the old teracloud.jp form now 404s) and the REST v2 discovery and quota calls send
X-InfiniCLOUD-API-KEYalongside the legacyX-TeraCLOUD-API-KEY; existing profiles are unaffected since the data plane still uses the Apps Connection password. - Connecting or navigating to a remote path that does not exist is now fast and honest instead of hanging or blaming your credentials: on chroot FTP accounts a missing directory could hang forever behind the spinner because an MLSD opened a PASV data connection the server never serviced (a control-only MLST probe now fails fast in about a second), and a post-login 550 is reported as a path-not-found with guidance to edit or clear the Remote Path instead of "Check credentials".
- The in-app updater no longer offers a
.debdownload on Arch: it now detects pacman and degrades to notify-only, exactly as on Snap and Flatpak (#310). - The AUR
aeroftp-binpackage was repaired: a launcher wrapper had destroyedargv[0]soaeroftp-cliandaftpopened the GUI for every flag-first call, the desktop file carried one of five file associations with a duplicate menu entry, and the icon was pinned to a moving branch; none of this ever affected.deb,.rpmor AppImage (#310). - The My Servers list no longer stays scrolled under the header after you edit a profile: the shared scroll container that a tall Edit form scrolls down now resets to the top on every tab change.
- The standalone extract/password window now follows the app theme (light, dark, auto) instead of always rendering light, reading the saved theme (falling back to the OS preference on auto) before render.
- The Transfer Queue no longer ticks a completed check on a failed transfer that shares a filename with a live one: the status transition is now a pure guard that refuses to move an
erroritem tocompleted, while a genuine retry still completes because it re-enterstransferringfirst. - The Linux desktop entry now categorizes as
Network;FileTransfer;(wasUtility;) with the full eight-format MimeType and a Keywords line, converging every Linux package format; the stale in-repoaur/folder was also removed. - The
archive_compressagent tool schema now states the real default level (5, 7-Zip Normal) instead of the stale 6. - Two version gates so a mis-versioned snap cannot ship:
build-snapnow runs a version guard right after checkout and the manifest-match gate additionally compares all four manifests to the tag on tag builds, closing the gap that once let a 4.0.8 snap publish under the 4.0.9 release. - SourceForge publishing is now an explicit, curated release step (installers plus Sigstore attestations, not the whole-release mirror that had grown the project to 44.5 GiB), uploaded through AeroFTP's own SFTP integration with retention pruning.
Security
- AeroFile vertical security audit complete (bundle B1, 17/17): the whole-archive extractors enforce decompression-bomb ceilings and zip metadata detection gets a passive OOM clamp, the zip-slip guard is consolidated across zip/7z/tar/rar, the Cryptomator vault walk gains a cycle guard and all its metadata reads (dir.c9r, name.c9s, masterkey and vault config) are size-capped against a hostile vault, image previews get decode limits, and the local file operations (cross-panel move, paste, drag-drop, inline and batch rename, Extract here) now refuse or pre-flag a silent overwrite.
- Integer-overflow guards on the remote archive-detect path: two hazards on attacker-controlled zip64 and 7z offsets that in a release build could wrap past the bounds check and panic the detection task are now guarded with checked arithmetic, with no behavior change on well-formed archives and never a wrong badge.
- The S3 trash no longer purges files nobody deleted: the trash view had reported the live current version of every key under a prefix as trash, so
empty-trashcould hard-delete live files irreversibly with no undo; a key is now trash only when its current version is a delete marker, the filter moved into a unit-tested pure function, and the bug was caught by a live test against a versioned AWS bucket before any release carried it (@EhudKirsh, #266). - Recursive delete over MCP is now opt-in and fail-closed:
recursivewas declared on every delete tool and read by none, and the MCP backend calledrmdir_recursiveon any directory, so anaeroftp_deletewith no flag silently erased the whole subtree while the GUI and CLI only unlinked a single entry; recursion now routes through a newdelete_recursivewhose default refuses rather than pretending, and a non-recursive delete of a non-empty directory answers "pass recursive=true" instead of a raw SFTP failure. - No recursive walk follows a symlink-to-directory any more:
listresolves a symlink-to-directory tois_dir = trueso callers can render it, and fifteen walkers gated their descent on that alone and walked straight into asub/loop -> ..cycle up to the depth cap, sormdirs,get -r,sync,dedupe,cleanupand the MCPstorage_quotaand delete preview miscounted or double-wrote; the invariant now lives onRemoteEntry::is_walkable_dir()and gates every descent, with the entry still reported as a directory so only the traversal is refused. - A sandboxed install can no longer lock a native install's vault: in the zero-password AutoKeyring default the vault passphrase lived in one shared OS-keyring slot, so a Flatpak or Snap initialising its own vault overwrote the native passphrase and left the still-intact native
vault.dbundecryptable (total credential loss to the user); the slot is now namespaced per install scope and a sandbox reads but never writes the native slot, reproduced and fixed after our own Flatpak live test locked the maintainer's vault. - macOS releases now ship signed: the dmg had been globbed under its
-betaname before the rename ran, so nothing was signed (v4.1.2 shipped two dmgs and zero.dmg.sigstore.json); the dmg is now signed under its real name so the in-app updater, which pins the same workflow identity for every platform, can verify it. - crossbeam-epoch bumped 0.9.18 to 0.9.20 (Cargo.lock only), clearing RUSTSEC-2026-0204 (an invalid pointer dereference in its
fmt::Pointerimpl) and restoring a cleancargo auditgate. - In-app updater signature verification is now honest and visible: a genuine sigstore verification failure now shows a distinct amber "Signature not verified (SHA-256 only)" badge instead of green and is echoed in the centered install overlay, the download progress bar turns green at 100%, and the update and verify strings are translated across all 46 locales; sigstore stays advisory with SHA-256 as the install gate (the hard block is planned for v4.1.4), and the same path was further hardened to distinguish an absent Sigstore bundle from an unparseable or unreachable one and to stage the artifact and its bundle as exclusive, collision-safe files.
- Final pre-release audit residuals closed: S3 batch delete rejects malformed 2xx bodies, FTP uses the MLST anti-hang probe only when that verb is advertised and preserves fallback on transient errors, and the local and remote batch-delete latches stay held through the actual async operation.
Contributors
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage