Skip to content

V5 egui rewrite - #17

Merged
spieglt merged 14 commits into
masterfrom
v5-egui-rewrite
Sep 26, 2026
Merged

spieglt merged 14 commits into
masterfrom
v5-egui-rewrite

Conversation

@spieglt

@spieglt spieglt commented Sep 18, 2026

Copy link
Copy Markdown
Owner

No description provided.

spieglt and others added 14 commits September 16, 2026 21:35
sodiumoxide has been deprecated since 2021 (RUSTSEC-2021-0137) and pinned
libsodium 1.0.18 from 2019. The secretstream now comes from dryoc and the two
key derivation functions from RustCrypto's argon2 and scrypt, so there is no C
toolchain left in the shipping build.

The file format is unchanged. The legacy path turned out to be scrypt rather
than argon2i, because sodiumoxide's pwhash module re-exports
scryptsalsa208sha256; the parameters libsodium derives internally from its
opslimit and memlimit are now written out as named constants next to the
argon2id ones.

Also fixed, from a review of the existing code:

- a truncated file is reported as truncated instead of as a wrong password
- an input too short to be encrypted can no longer truncate the output file,
  because the signature is read before the output is created
- encrypting a file over itself is refused rather than destroying the input
- the output handle is closed before the failed-run cleanup deletes it, which
  never worked on Windows
- key derivation returns an error instead of unwrapping, and the stack copy of
  the derived key is zeroized
- reads interrupted by a signal are retried

Output path and password-policy helpers moved here from the CLI so the GUI
shares one implementation.

Tests: fixtures produced by libsodium before the migration, both interop
directions at single- and multi-chunk sizes, the two legacy formats, and the
safety properties above. sodiumoxide stays as a dev-dependency so the format is
checked against the reference implementation rather than against itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- the 12-character minimum applied only to the interactive prompt, so
  --password and --password-file bypassed it entirely; it now applies whatever
  the source, and counts characters rather than bytes
- -o <directory> was ignored when the input lived elsewhere on disk, because
  pushing an absolute path onto a PathBuf replaces the whole thing; only the
  input's file name is used now, which is what --help promises
- failures printed to stderr but exited 0, so scripts could not detect them
- a password file's trailing newline is ignored, with a fallback to the raw
  contents so files encrypted by earlier versions still decrypt
- progress output is flushed, so it appears while working rather than all at
  once at the end

The brute-force test no longer loops forever: it makes a fixed number of
attempts, asserts each one fails and leaves no output behind, and prints the
extrapolated cost of an exhaustive search.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Qt 5.15 is end of life, and the hand-written C++/Rust FFI in adapter/ was where
the severe bugs were: null pointers that segfaulted the process and panics that
aborted it across the boundary. The new GUI is Rust talking to the core crate
directly, so that boundary is gone rather than hardened, and it builds to a
single self-contained binary of about 16 MB against the 34 MB Qt AppImage.

Behaviour follows the Qt version: a drop area with dialogs over it and the
progress bar along the bottom of the window. The work now runs on a worker
thread, so the window stays responsive instead of freezing until the file is
finished.

New: a File > Open menu item with a native file picker, and `cloaker <file>` on
the command line so the app can serve as a file handler. The About box has the
current copyright and contact address, and now says that Cloaker 4 and 5 can
read each other's files, which the unchanged format makes true.

The tests drive the interface headlessly through egui_kittest: password
validation, the modals, the file-argument handling, and the position of the
progress bar.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- CI runs rustfmt, clippy and the tests on Linux, macOS and Windows. Pushing a
  tag builds all three platforms, smoke-tests each binary and opens a draft
  release with the artifacts attached.
- the AppImage recipe in the README is the one actually run on a Linux box,
  including the icon size linuxdeploy insists on and the environment variable
  that avoids needing FUSE
- Cargo.lock is committed now that these crates build executables: pinning the
  exact crypto dependencies is what makes a release reproducible
- RELEASE.md lists what still needs a human before publishing, chiefly the
  Windows and macOS builds, which nothing has compiled yet

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows and macOS both build and run, and drag and drop and saving work on
Linux, all confirmed by hand. The remaining Linux GUI checks stay open.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The check that stops Cloaker writing over its own input compared canonicalized
paths. A hard link is a second name for the same file, so its path resolves
differently: choosing one as the output passed the check, creating the output
truncated the input, and encryption then reported success over an empty file.

The check now uses the same-file crate, which compares the files themselves
(device and inode on Unix, volume serial number and file index on Windows).
Both the CLI and the GUI go through main_routine, so both are covered.

New tests for a hard link, which failed before this change, and for a
symlink, which was already caught.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The release workflow downloaded linuxdeploy from its moving "continuous" build
and ran it unverified, and every action was referenced by a movable tag. Both
feed into the artifacts that get published.

- linuxdeploy is pinned to the 1-alpha-20251107-1 release and checked against
  its SHA-256 before it runs; the hash matches the digest GitHub records for
  the asset. curl now fails on an HTTP error instead of saving the error page.
- every action in both workflows is pinned to a commit SHA, with the version
  kept as a comment. rust-toolchain is passed `toolchain: stable` explicitly,
  since a commit SHA no longer carries it in the ref name.

Checked locally: the pinned linuxdeploy builds a working AppImage, and the
checksum step passes the genuine binary and fails one with a byte appended.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every manual check is now done: the rest of the Linux GUI pass (folder and
multi-file drops, Tab and Enter, cancelling the save dialog, saving over an
existing file, responsiveness on large files), an end-to-end run of the CLI,
Cloaker.js interop, and the security review with its two follow-up fixes. CI
has passed on all three platforms.

Adds the analysis of the Argon2id settings, with timings for libsodium's three
levels measured on real hardware, as the context for the one open decision:
the settings are adequate but light for file encryption, and raising them needs
a file format that records its parameters.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
No known technology breaks Argon2id or the cipher, so the question is how fast
an attacker can guess. Bounding the largest attacker at about 10^10 guesses a
second (a million top GPUs, from memory-bandwidth arithmetic), a strong
password is safe at the current settings for anywhere from 90 years (five random
words) to over a million years (12 random characters), and a weak password
falls in seconds at any setting. Custom chips and quantum computers don't
change that.

That revises the recommendation: raising the settings is a marginal gain,
so 5.0 can ship at the current level with full compatibility with Cloaker 4 and
Cloaker.js, leaving a format that records its parameters as future work.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`build.rs` embeds the resources with winresource when the target is Windows. The product name
and file description are set to Cloaker: they default to the package name, which is what Task
Manager and the "Open with" list would have shown.

`assets/cloaker.ico` was unusable — a single entry claiming 256x256 that held a 600x600 PNG.
It is rebuilt from the same artwork at 16, 24, 32, 48, 64, 128 and 256 px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The CLI hardcoded v5.0 and the About box 5.0, so both would go stale on the next bump. The
CLI also printed an author line above the description, and still described the crypto as
sodiumoxide/libsodium, which the 5.0 rewrite replaced with dryoc and RustCrypto. The file
format is unchanged, so the description now names that instead of the library.

`cloaker_cli --version` now prints "Cloaker 5.0.0" rather than "Cloaker v5.0", matching the
GUI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`prompt_password_stdout` is gone in 7; `prompt_password` replaces it and writes the prompt to
the terminal device instead of stdout, which keeps it out of the ciphertext when encrypting to
stdout with -E. The bump also drops winapi 0.2 and kernel32-sys from the tree.

RELEASE.md: the test counts said 41 in one place and 43 in another. It is 42, plus the
fixture-rewriting test that is #[ignore]d.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The password policy is not changing for 5.0, so the analysis behind that and its checklist item
come out. The README's "Planned features" entry asking about a 14- or 16-character minimum goes
with them, and its Windows section no longer asks for the build script that now exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- the Linux CLI ships as a plain binary next to the AppImage. A command line
  tool needs no bundle, and the AppImage never carried it anyway: it holds one
  app.
- the Linux job builds on ubuntu-22.04, the oldest runner on offer. The
  AppImage bundles no libraries (the GUI links only libc, libm and libgcc and
  dlopens libGL, X11, Wayland and xkbcommon at runtime) and it does not carry
  glibc either, so the build machine sets the floor. ubuntu-latest would have
  ruled out Debian 12, RHEL 9 and Ubuntu 22.04.
- macOS builds both architectures and merges them with lipo, so the app and the
  CLI run on Intel and Apple Silicon. The runner is Apple Silicon and Apple's
  SDK carries both, so this needs no second runner. The bundle is archived with
  ditto, which is what notarisation expects.
- nothing is zipped together any more: six assets, with each CLI keeping its
  _cli name. Only the macOS app is archived, because a bundle is a directory.

The Linux packaging was run locally and both artifacts report their version.
The macOS steps can't be tested off a Mac and are unverified until a tag runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@spieglt
spieglt merged commit 9f16ee2 into master Sep 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant