[3.7.2] - 2026-05-06
AeroCrypt overlay, IntroHub & community polish, CLI security hardening, 2 new image-CDN providers
A wide release that consolidates the v3.7.2 community wishlist (#161), promotes the rclone-crypt overlay to a first-class encryption layer next to AeroVault, ships an external GPT 5.5 high audit pass on the CLI / MCP / AI core dispatcher with 17 paired security fixes, adds two new native image-CDN provider integrations (ImageKit and Uploadcare, taking the protocol grid from 22 to 24), restructures the custom titlebar around an explicit 3-cluster layout, surfaces SFTP idle-reconnect transparently, and clears every shippable item EhudKirsh and Tom raised on the wishlist thread. The bundled aerovault crate moves to 0.3.5 (routine maintenance, no format change). Cryptographic primitives are otherwise untouched.
Added
- AeroCrypt overlay (rclone-crypt) as a first-class encryption layer: closes the rclone-crypt overlay (APPENDIX-S) as a first-class layer alongside AeroVault. Folder transfers now traverse encrypted directory trees end to end via two new backend commands (
rclone_crypt_provider_download_folder,rclone_crypt_provider_upload_folder) with BFS depth 64 and per-level dirIV resolution. Filename obfuscation (bucket-based, ASCII + Latin-1) is wired throughobfuscate_name/deobfuscate_name. A newrclone_crypt_provider_create_remotecommand initialises the dirIV in an optional subpath. The toolbar gains an AeroCrypt button next to the AeroVault overlay button, the remote path bar shows anAEROCRYPTbadge while the overlay is active, and the post-connect banner auto-detectsrcloneCryptEnabledfrom imported configurations. The unlock dialog, renamed "AeroCrypt Rclone Crypt overlay", supports both Open existing and Create new with an obfuscate-filenames toggle. 15 new tests cover obfuscate roundtrip and end-to-end smoke (standard, off, obfuscate) on empty, single-chunk, and multi-chunk content; 42/42cargo test rclone_cryptpass on release profile. CLI parity ships with theRcloneFilenameEncryption::Obfuscatevariant. - ImageKit (23rd protocol): native REST API integration as a first-class
StorageProvider. Auth via private key (HTTP Basic), endpointapi.imagekit.io. Full trait surface (list, upload, download, delete, mkdir, rename, move, search), plus media-CDN passthrough for transformations and folder operations. 20 GB media + 20 GB bandwidth/month free tier. Visible in IntroHub Discover under Photo & Media, exposed in CrossProfile, IconPicker (Media category) and SessionTabs. - Uploadcare (24th protocol): native REST + Upload API integration. Auth via public + secret key, endpoints
api.uploadcare.com(REST) andupload.uploadcare.com(multipart). Cursor-based listing, store-once semantics mapped to AeroFTP's directory model. EU-based, GDPR-friendly. Same surfaces wired as ImageKit. - Custom titlebar 3-cluster layout (
T-TOPBAR-3-CLUSTER, carry-over from [#133], recap in [#161]): the right side of the unified VS Code-style titlebar is now grouped into three explicit clusters. Cluster 1 (page nav) holds Connect / Disconnect with a fixed minimum width, eliminating the click-shift drift reported in [#129] (clicking Disconnect, then the new Connect button, shifted icons enough that a fast aimed click could land on Lock or Settings). Cluster 2 (utility) holds Cyber Toolkit (cyber theme only), AeroVault, Lock and Settings without internal separators. Cluster 3 (window) holds Minimize, Maximize, Close. No new props, no new i18n keys, no behaviour changes outside the layout fix. - About > Technical: library version check: a new "Check Updates" button in the Linked Libraries section queries crates.io for each of the 12 tracked libraries (russh, russh-sftp, suppaftp, reqwest, keyring, aerovault, aes-gcm, argon2, zip, sevenz-rust, quick-xml, oauth2). Each row shows current version, an inline upgrade arrow when a newer release exists, and a colour-coded status badge (green check, yellow up-arrow, red triangle for major bumps). Reuses the existing
check_crate_versionsTauri command, no extra backend cost. The aerovault crate is now part of the tracked set. - Support modal Reviews section: the heart-icon Support dialog grows a new "Leave a Review" block between the fiat donation grid and the crypto section. Two side-by-side buttons: the existing SourceForge review link (relocated from the About > Support tab where it was harder to discover), and a new entry pointing at the
axpdev-lab.aeroftp-mcplisting on Visual Studio Marketplace. Both render with their official brand SVG inline (no external asset). Translated in all 47 locales. - My Servers table per-column alignment (Ehud, [#161]): the column manager popover (gear icon in the table header) gains three small
L/C/Rbuttons next to each column toggle. Default alignment is sentence-aware (numerics like Used / Total / % default to right, icon-based columns default to centre, text columns default to left), but each column can be overridden. The override persists in the same vault entry that already stores visibility, order and width. Applies to both the<th>/<td>text-* class and the inner flex justify so labels and content stay coherent. - Sticky header in the My Servers table (Ehud, [#161]): the table header was already styled
sticky top-0but the inneroverflow-x-autowrapper was capturing sticky positioning, so it drifted away with the rows. Removed the wrapper, horizontal scroll now lives on the panel container, header stays pinned during vertical scroll. - Ctrl+T cycles theme everywhere outside text inputs (#171): the menu label and the toolbar tooltip have advertised
Ctrl+Tfor a while, but the binding was never actually registered. Now wired throughuseKeyboardShortcutswith the globalisTextEditingTarget()guard so the shortcut works on the connection screen, the file panels, IntroHub, AeroSync, AeroVault, and any other surface, while focus inside Monaco / xterm / form fields still preserves their native semantics. Cycleslight->dark->tokyo->cyber->auto. - Ctrl+S saves inside the Monaco editor (#171): the editor button tooltip has shown
Ctrl+Sfor a while but it was a placebo. Registered as a Monacoeditor.addAction(so it does not collide with the global keyboard hook, which by design suppresses Ctrl combos inside.monaco-editorfor terminal SIGINT compatibility). The keybinding writes through the livehandleSaveclosure via a ref pattern, so it always sees the latestonSaveprop andoriginalContent. Works in DevTools editor, AeroFile editor, and any future Monaco mount. - AeroFile -> Editor -> Terminal drag-to-run (
T-EDITOR-DRAG-RUN, carry-over from [#147]): drag a.ps1,.shor.pyfrom AeroFile into AeroTools Editor to open and edit, then drag from the Editor header into the Terminal area to stage the run command. Extension mapping is automatic (.ps1->pwsh <quoted-path>,.sh->bash <quoted-path>,.py->python <quoted-path>). Path validation runs before command composition; shell quoting is applied to defeat filename-injection edge cases. The command is inserted into the prompt without auto-pressing Enter so the user can review before running. Visual drop-target highlight on Editor and Terminal tab buttons and panel surfaces; inline feedback after the Terminal drop readsCommand inserted in terminal. Press Enter to run.Translated in all 47 locales.
Fixed
- SFTP silent reconnect on idle session disconnect (T-AUTO-RECONNECT-IDLE, [#161]): Tom reported that AeroFTP threw
Failed to change directory: Path not found: Directory not found: session closedafter the SFTP session sat idle for ~10 minutes, forcing a manual disconnect and reconnect with loss of the cwd context. Two changes ship together. (a) Error classification: russh emitssession closedwhen the server's idle reaper kills the SFTP channel, bothcdandcd_upwere wrapping this underProviderError::NotFound, producing the misleading prefix Tom saw. All russh call sites inproviders/sftp.rsnow route throughclassify_russh_err, which upgrades transport-level error strings to a newProviderError::ConnectionLostvariant. (b) Auto-recovery:provider_change_dir,provider_go_upandprovider_list_filesretry once after a silent reconnect when the live op returnsConnectionLost. The reconnect reuses the in-memorySftpConfig(no vault hit, no UI prompt) and best-effort restores the previous cwd before replaying the user's click. Lifecycle is surfaced via the newprovider-sessionTauri event, which the frontend converts into an info+success toast pair (Session expired, reconnecting...thenReconnected to server). Translated in all 47 locales. - Codex CLI security audit (CLI-AUDIT-01..17): an external GPT 5.5 high audit on 2026-05-06 surfaced 17 findings on the CLI and AI core / MCP dispatcher surface. All resolved in this release. Highlights (full report and per-finding evidence in
docs/security-evidence/AEROFTP-CLI-AUDIT-2026-05-06.md):- GUI tool execution now enforces backend approval:
execute_ai_toolinai_tools.rsnow runs the same allowed-tools check and per-tool approval validators that the CLI / MCP path runs, instead of relying on UI-only gating (CLI-AUDIT-01). - MCP / AI core remote dispatcher path validation: local upload / download paths now go through the strict validators (null bytes, traversal, control chars, option-like forms, length cap), and remote paths share the same validation layer (CLI-AUDIT-02).
server_execis strictly read-only: rejectsget/put/mkdir/rm/mvwith an explicit-use error pointing at the documented mutative tools, restoring the contract documented in AGENTS.md (CLI-AUDIT-03).- MCP profile lookup requires exact id / name or a unique substring: ambiguous matches return a structured error listing candidates instead of silently picking the first substring match (CLI-AUDIT-04).
local_copy_filesandlocal_stat_batchvalidate every path: single-file branch and recursive walk both refuse symlinks before any copy, batch stat returns per-item error JSON for denied entries (CLI-AUDIT-05, CLI-AUDIT-06).- SFTP packet parser is bounds-checked end to end: oversized packets are rejected, malformed packets get a status failure, worker-channel errors no longer panic the bridge (CLI-AUDIT-07).
.aerotmpwrites usecreate_newand refuse symlinked temp paths: predictable resume through a symlinked temp file is gone; resume is gated on regular-file metadata checks (CLI-AUDIT-08).- Inline upload temp files use
tempfile::Builder::tempfile(): removes predictable filename paths in world-writable temp dirs in both the CLI and MCP paths (CLI-AUDIT-09). - Daemon auth token created with
O_NOFOLLOW+ mode 0600: permissions are set during creation through the open handle, not hardened after the fact (CLI-AUDIT-10). sync --direction <invalid>fails before connecting: returns JSON error and exit code 5 instead of no-opping and exiting 0 (CLI-AUDIT-11).sync-doctorresolves remote paths the same waysyncdoes: profiles withinitialPathare no longer inspected against a different remote tree (CLI-AUDIT-12).sync-doctor --checksumno longer suggests the non-existentsync --checksumflag (CLI-AUDIT-13).transferchecks cancellation between plan and execution: cancelled runs return exit code 130 instead of reporting success (CLI-AUDIT-14).agent-info --jsontreats a missing profile list as empty (matchesprofiles --json, CLI-AUDIT-15).- CLI help footer documents the extended exit-code contract: 9, 10, 11, 130 (CLI-AUDIT-16).
- Direct
rsa = "0.9"dependency removed fromCargo.toml,jsonwebtokenswitched toaws-lc-rswithdefault-features = falseand explicit features["aws-lc-rs", "hmac", "use_pem"](CLI-AUDIT-17). The two remaining transitive RSA paths (sigstore -> openidconnect, russh -> internal-russh-forked-ssh-key) are documented inaudit.tomlwith written threat-model justifications and tracked for a future deep-session decommission indocs/dev/roadmap/APPENDIX-RUSSH_RSA-Decommission-Plan.md(gitignored).
- GUI tool execution now enforces backend approval:
- Ctrl+T (theme cycle) and Ctrl+S (editor save) actually work (#171, reported by @legion1978): both shortcuts were advertised in menu labels and editor button tooltips but the bindings were never registered. Fix wired in this release. Window resize / overlap glitches reported on Manjaro Cinnamon (Muffin) remain under investigation for v3.7.3, no other user has reported them yet.
- My Servers table header capitalization (Ehud, [#161]): every header in the table view now reads
Host,Name,Health,Path, ... instead ofHOST,NAME, etc. The classuppercasewas forcing every header into all-caps regardless of the i18n value. Same change applied to the column-manager dropdown title for consistency. - "Detailed server cards" toolbar toggle removed (Ehud, [#161]): the toggle was redundant with the column manager (which already hides the Health column) and with the Settings > Appearance checkbox that controls the same setting. The button is gone.
- CLI
aeroftp-cli profilesno longer spills onto a second row on narrow terminals (Ehud, [#161]): output now respects the current terminal width. Shrinkable columns (Name, Badges, Subtitle, Paths) share whatever width is left after the fixed columns; the per-column cap is computed dynamically fromcrossterm::terminal::size(). Default 30-char cap on wide terminals, floor of 8 chars per shrinkable column on narrow terminals. Side fix: the Badges cell usestruncate_cellso a long provider label (e.g. "Cloudflare R2") no longer overflows. - CLI
--breakdownis now a single unified table (Ehud, [#161]): the legacy layout printed the per-protocol breakdown as a separate table after a duplicated summary line. The unified layout reuses one separator style and folds the global TOTAL into the breakdown table as the last row. Plain (non---breakdown) output is unchanged. - CLI
--hide=fav,favorite,favouriteandfavsall accepted (Ehud, [#161]): the alias surface was implemented but only documented forfavorite. Help text rewritten to make every variant obvious. - Esc closes the active Quick Connect form tab (Ehud, [#161]): mirrors the X click. Gated to skip when focus is in a text input so native Esc behaviour on autocomplete dropdowns is preserved.
- Delete confirmation no longer says "Delete 1 selected items?" (Ehud, [#161]): the message is now built from the actual selection: a single file shows its name (
Delete file "<name>"?), a single folder shows its name labelled as folder, batches show separate counts when files and folders are mixed (Delete N files and M folders?). Translated in all 47 languages. - Selection cleared when leaving AeroFile for the connection screen (Ehud, [#161]): without this, pressing Delete on the connection screen surfaced a Delete dialog from a stale selection.
- Backspace no longer surfaces "Path must be absolute" when AeroFile is closed (Ehud, [#161]): the shortcut now no-ops on the connection screen and guards against an empty current path.
- Draggable modals (AeroVault, Settings, Master Password, Mount Manager, Health Check, Speed Test, Dependencies, Shortcuts, MCP, ...) close on the first X click (Ehud, [#161]): the drag hook checked
event.target instanceof HTMLElementbefore honouring an interactive child, but Lucide icons render as SVG elements which are notHTMLElementinstances on WebKit. That made the drag handler grab the pointer when the user clicked the X icon directly, swallowing the click. Switched toinstanceof Element, one-line fix that unlocks all draggable modals using the shared hook. - S3Drive connection failed with a generic network error: the S3Drive registry preset shipped with
pathStyle: false, so the client built virtual-hosted-style URLs (https://<bucket>.storage.kapsa.io/...). Kapsa.io (the Storj-backed S3 endpoint behind S3Drive) does not resolve bucket-as-subdomain in DNS, so every probe failed before reaching auth. Switched the preset to path-style (storage.kapsa.io/<bucket>/). Existing profiles either still work as saved or can be flipped via Edit > Advanced > Path Style. - The
@toolbar toggle did nothing on Cloud and S3 cards: the hide-username toggle was only honored for hostname protocols (FTP, FTPS, SFTP, WebDAV custom). On Cloud OAuth and S3 cards it was a no-op.getServerSubtitlenow treatsshowUsername === falseas a global suppression with a sensible fallback per branch: hostname protocols still showhost[:port], S3 / opaque-token API providers fall back to host (endpoint) when one is stored, OAuth providers collapse to empty (the brand title is enough). Eye and@are independent of each other as before. - Some S3 access keys were treated as opaque tokens and hidden: Tencent (
AKID+ 32 chars), Mega S3, Quotaless and Cloudflare R2 all use access key formats long enough (32 to 56 characters) to trip the generic opaque-token heuristic, which left those S3 cards with an empty subtitle while AWS / Wasabi / Storj / Backblaze were fine. The heuristic is now bypassed forproto === 's3'since the access key IS the intended identifier. The mask is still applied so only the prefix is visible. - kDrive, Jottacloud, FileLu, Drime, Yandex Disk cards were blank under the email column: these providers authenticate via API key, login token or OAuth Client ID rather than a profile email. The previous logic specifically required the username to look like an email (
includes('@')) before showing it, so non-email tokens collapsed to empty. The card now displays the stored token masked, so two profiles of the same provider are distinguishable. Drime stays empty by design because it does not capture any per-profile identifier. - Yandex Disk was empty even after the previous fix: Yandex was hitting the OAuth branch first (which still requires
@), and itsusernamefield is normally empty because Client ID and Client Secret live in the vault. Two paired changes: (a) the OPAQUE_TOKEN branch is now evaluated before OAuth so Yandex falls into the right path; (b) on a successful (re)connect,MyServersPanelwritescredentials.clientIdintoserver.usernameas a stable per-profile identifier. Once a saved Yandex profile is reconnected once, the card shows the masked Client ID and is properly distinguishable from sibling profiles. Until then the host fallback (cloud-api.yandex.net) is shown so the card is not blank. - Drag-to-reorder permanently locked in grid view after sorting the table: the grid view shares the column-config store with the table view. The
canDraggate wastableColumns.sort === nullfor both views, so any sort persisted by a previous list-view session left grid drag permanently disabled with no visible reason. Decoupled: in grid view drag is always allowed (no sort UI to conflict with), in list view the existing rule still holds (sort lock disables manual reorder). - Drag-to-reorder did not start in list view at all (WebKitGTK quirk): WebKitGTK does not reliably fire
dragstarton<tr draggable>, even when sort is null andcanDragis true. The cursor turned into the grab hand on hover but pressing-and-dragging produced nothing. Moved thedraggableattribute andonDragStarthandler from the row down to the index<td>, where dragstart fires correctly. The row keeps the drop-side handlers (onDragEnter/onDragOver/onDrop) so users can release on any column of the destination row. A "Drag to reorder" tooltip on the index cell, translated in all 47 locales, makes the affordance discoverable. - Cross-Profile selection badge hidden under the connect button: when a card was marked as source or destination for a Cross-Profile transfer, the colored corner indicator rendered before the connect button in DOM order, so the larger button overlapped the smaller badge and partially obscured it. Added
z-10on the indicator. The badge now reads cleanly on top. @toggle now fully collapses the subtitle row: whengetServerSubtitlereturns empty, the subtitle div is removed from the DOM (not just blanked), so grid cards actually shrink instead of leaving an empty space. Hostname protocols also drop the host fallback when the toggle is off, matching the OAuth branch behavior for visual consistency.- View-mode toggle simplified: rendered as a single button advertising the inactive view (Grid switches to List, List switches to Grid) instead of the previous active+inactive pair. Halves the toolbar real-estate without losing affordance.
- Search input padding regression on smaller base font sizes: search input padding bumped from
pl-9topl-10with pointer-events disabled on the icon, fixing a placeholder collision reported by users running the app at non-default browser base font sizes. - StatusBar storage quota palette aligned with MyServers: the dual-panel StatusBar quota bar ran on its own ad-hoc palette (purple < 70%, amber < 90%, red beyond) while the MyServers card bar already used
getStorageTonewith the user-configurable warn/critical thresholds. Switched StatusBar to the shared helper so both surfaces show the same emerald to amber to red gradient and respond to the same Settings sliders. The HardDrive icon next to the bar now follows the same tone too instead of being permanently purple.
Changed
aerovault0.3.4 -> 0.3.5: routine upstream maintenance bump. Cryptographic primitives were not touched (aes-gcm-siv 0.11, aes-siv 0.7, aes-kw 0.2, argon2 0.5, chacha20poly1305 0.10, hmac 0.12, sha2 0.10, hkdf 0.12, zeroize 1). No format or API changes. The crate is also added to the runtime Dependencies panel under the Security category and to the About > Technical Linked Libraries list.- Direct
rsa = "0.9"dependency removed,jsonwebtokenmigrated toaws-lc-rs. Direct-dep RSA exposure is now zero. Companionaudit.tomldocuments the two remaining transitive paths with written threat-model justifications. - ROADMAP: the "From the Community" section is now split into two parallel streams. A per-release Wishlist thread tracks small UX paper cuts and quick wins, closes when the corresponding release ships, and stays close to the issue tracker. A permanent COMMUNITY ROADMAP thread tracks big features that need multi-day or multi-week scope and stays open across releases. Carry-over items get stable T-codes (
T-EDITOR-DRAG-RUN,T-PROTOCOL-COMPARISON-DOCS,T-TOPBAR-3-CLUSTER) so contributors can refer to them across cycles. AddedT-MULTI-USERto the big-feature list (per-user profile partitioning with titlebar selector, F2 rename, separate import/export, separate AeroSync settings, vault schema migration,--user <name>CLI flag).T-TOPBAR-3-CLUSTERandT-EDITOR-DRAG-RUNship in this release;T-PROTOCOL-COMPARISON-DOCScarries over to the next cycle (requires per-protocol API vs WebDAV trade-off documentation grounded in real test runs against each backend).T-MANUAL-QUOTAfiled for the v3.7.3 wishlist (manual storage capacity for non-reporting providers, optionalmanualQuotafield per saved server).
Internal
- CI: Windows build whisper-rs-sys cache fix:
windows-latestrunner image rolled from Visual Studio 17 2022 to Visual Studio 18 2026 preview, and the rust-cache restoredCMakeCache.txtfrom a prior VS17 run still pinned the old generator, so cmake-rs aborted with "generator does not match the generator used previously". Two paired changes: (a) Swatinem/rust-cacheprefix-key: 'v2-whisper-vs18'invalidates every cached entry that may carry stale CMake state; (b) the runtime cleanup step now nukes the wholewhisper-rs-sys-*build dir on Windows instead of just the innerout/(some runners hadout/build/CMakeCache.txtsurvive depending on cmake-rs internal layout). - CI: delta-sync password-only fixture timeout 15m -> 25m: the
fallback-fixturejob uses an isolated rust-cache shared-key (delta-sync-fallback) that is invalidated wheneverCargo.lockchurns (deps-bump PRs from Dependabot, scheduled batch bumps, Tauri ecosystem upgrades). On a cold cache the workspace + Tauri + aeroftp lib compile takes 18-22 minutes before the integration test binary links, which exceeded the previous 15m ceiling and silently cancelled the run, leaving multiple deps-bump PRs stuck in red. The sibling key-auth lane fits comfortably in 11 minutes with a warm default cache, so it stays at 15m. 25m on the fallback lane gives enough headroom for cold-start runs without parking PRs forever. - Security: documented
audit.tomlignores:src-tauri/.cargo/audit.tomlnow lists every RUSTSEC ID we ignore alongside a written threat-model justification, so external reviewers (NLnet, OpenSSF, OSSSign) can assess each one inline.cargo auditnow exits 0 with documented acceptance for two transitive RSA paths (Marvin attack, requires observable RSA decrypt operations, never reachable in our code paths) and for the Tauri 2.x stack unmaintained / unsound transitives (gtk-rs GTK3 bindings, glib 0.18, proc-macro-error, fxhash, unic-*, rand 0.7.3 build-dep), all expected to clear when Tauri ships GTK4 wry. - Dependency maintenance:
dompurify3.4.1 -> 3.4.2,@tauri-apps/cli2.10.1 -> 2.11.0 (#155),webpki-roots0.26.11 -> 1.0.6 (#151),rustls0.23.38 -> 0.23.40 (#159),tauri-plugin-dialog2.7.0 -> 2.7.1 (#157),country-flag-icons1.6.16 -> 1.6.17 (#152),dtolnay/rust-toolchainpinned to a commit hash (#150), Tauri ecosystem 2.10 -> 2.11 (#168), Rust deps batch (tokio, reqwest, quick-xml, blake3, [#169]). - i18n: 13 new keys translated into all 47 locales via the GLM batch method.
support.reviewsSection,support.reviewSourceforge,support.reviewVscode,introHub.table.dragToReorder, plus the 9-keydialog.deleteOne*/dialog.deleteFiles*/table.alignmentGroup/table.alignLeft|Center|Rightset from the Ehud batch. AeroCrypt overlay strings translated in all 47 locales as well.i18n:validateis clean (0 errors, 0 warnings, 0 placeholders).
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage