fix: require magic string in portable marker to prevent false portable mode on scoop installs#1126
Merged
cjpais merged 3 commits intocjpais:mainfrom Mar 26, 2026
Merged
Conversation
…e mode Scoop's extras bucket extracts the NSIS installer via #/dl.7z, which can leave a stale empty portable file next to the exe. This caused portable::init() to falsely trigger portable mode on non-portable scoop installs, storing data in Data/ next to the exe (wiped on each update). Changes: - portable.rs: only enable portable mode when marker contains "Handy Portable Mode"; extracted is_valid_portable_marker() with tests - installer.nsi: write magic string when creating marker file - installer.nsi: validate magic string in update auto-detect block - installer.nsi: allow desktop shortcut creation from finish page checkbox in portable mode (was silently doing nothing) - commands/mod.rs + lib.rs: expose is_portable() as a Tauri command - UpdateChecker.tsx: show manual-update popup for portable installs instead of attempting auto-install (which would download MSI) - en/translation.json: add i18n strings for portable update popup Fixes cjpais#1124 Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…matting Add portableUpdateTitle, portableUpdateMessage, portableUpdateButton to all 17 non-English locales (English fallback text) so check:translations passes. Also run prettier on the PR's modified files to fix format:check. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
v0.8.0 created an empty `portable` marker file. Users who manually update (drop new exe in place) would silently lose portable mode since the new magic-string check rejects empty files. Migration: if the marker exists but has invalid/empty content AND a `Data/` directory is present, treat it as a real portable install and rewrite the marker with the magic string. This handles the v0.8.0 → new upgrade path without regressing the scoop false-positive fix (scoop does not create a Data/ directory). Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
sdkxhyp49q-coder
approved these changes
Mar 24, 2026
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1124
Scoop's extras bucket extracts the NSIS installer via
#/dl.7z, which leaves a stale emptyportablefile next to the exe. This causedportable::init()to falsely trigger portable mode on non-portable scoop installs — data ends up inData/next to the exe, which is wiped on everyscoop update.Root cause
The original portable marker check only tested file existence (
exe_dir.join("portable").exists()), so any file namedportable— including the empty one left by scoop's extraction — would activate portable mode.Fix
portable.rs: read the marker file and only enable portable mode if it contains the magic string"Handy Portable Mode"(whitespace-trimmed). Extracted tois_valid_portable_marker()with unit tests.installer.nsi(marker creation): write"Handy Portable Mode"into the file instead of creating an empty file.installer.nsi(update auto-detect): validate the magic string before setting$PortableMode = 1, so updates also respect the new format.v0.8.0 migration
v0.8.0 shipped with an empty marker file. Users who manually update (drop new exe in place) would silently lose portable mode since the new check rejects empty files. Migration logic in
portable::init(): if the marker exists but has invalid/empty content and aData/directory is present alongside it, treat it as a real portable install and rewrite the marker with the magic string in place. This safely distinguishes a real v0.8.0 portable install (hasData/) from a scoop extraction artifact (noData/).Additional fixes included
is_portableTauri command;UpdateCheckernow shows a manual-update dialog (with GitHub Releases link) instead of attempting an auto-install that would download the MSI and break portable layout.Test plan
scoop install extras/handy) — app should start in normal mode, data in%APPDATA%Data/next to exeData/) — app stays in portable mode, marker upgraded to magic stringcargo test portable::tests— 6 tests pass🤖 Generated with Claude Code