fix(license): drop an activation token that no longer stands for this machine (#367) #388

Merged
maximus merged 3 commits from issue-367-stale-activation-token into main 2026-10-05 23:23:02 +00:00

3 commits

Author SHA1 Message Date
le king fu
2cbc886653 fix(license): apply the review follow-ups on the license stack head
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 1m47s
PR Check — Rust / rust (pull_request) Successful in 3m40s
Follow-ups of the three /pr-review passes on #386, #387 and #388, applied
on the stack head before the fast-forward merge:

- #386: pin the relay of the revoked state by revocationCheckLauncher
  (a launcher passing false instead of wasRevoked passed the whole suite),
  and say in the rate budget comment that two checks in one minute bring
  the machine-limit path to 6 requests.
- #387 S1: the fake `t` of the removal tests and of the License card tests
  marks what it translates, so a string that skipped `t` fails its test.
- #387 S2: pin that storing another key stops on Storage while the
  previous token cannot be dropped, the previous key staying.
- #387 S3: reload the license context after a failed removal too. Rust
  deletes the key first, so a token that resisted left the key gone while
  the card kept showing it under "the key was not removed".
- #388: pin that an unreadable token stays (the directory case could not
  tell, its deletion fails anyway).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:13:36 -04:00
le king fu
fd90de5424 docs(license): align the English tip and the price test notes with #367
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 1m46s
PR Check — Rust / rust (pull_request) Successful in 3m22s
The English in-app tip now says, as the French one does, that the
revoked license is that of a refunded key left next to the current key,
not the key itself. The header of the price tests says that the tests of
the stored token call fetch_price_in with a temporary data directory,
instead of claiming that every test bypasses the token file.

Resolves #367

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 18:02:07 -04:00
le king fu
ed35570121 fix(license): drop an activation token that no longer stands for this machine
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 1m49s
PR Check — Rust / rust (pull_request) Successful in 3m21s
A data directory written by v0.15.0 or earlier can hold a valid key next
to the activation token of another license, typically a refunded hence
revoked one. The License card read "Activated", market prices were
refused, and "Activate" was never offered: the folder could not recover
without a manual file removal.

- Prices: a 403 license_revoked drops the refused token, and only while
  the file still holds it, so an activation that lands while the refused
  request is in flight keeps its new token (CWE-367). The key's revoked
  state is never written from this route. The token is read through
  ACTIVATION_FILE by the directory-based read_stored_activation_token_in,
  in fetch_price_in, testable without AppHandle.
- Machine list: list_activated_machines returns { machines,
  token_dropped }. A complete list that names this machine under neither
  identifier drops a token that activates this machine, when the OS id is
  readable and the token is the one on disk when the list was asked for.
  An error, a revoked key or a rate limit drops nothing.
  machines_from_verify counts the rows it skips, which the list still
  tolerates. This also gives "Activate" back to a machine deactivated from
  another computer.
- Front: the activation status is read again after every list load; a
  fixed log line (ACTIVATION_TOKEN_LOG) is written on token_dropped and on
  a price refused as revoked; the revoked-license price message invites to
  activate the machine again.
- Docs: architecture, ADR 0017 (#365 amendment), ADR 0020 (rule 4), user
  guide and in-app tips, changelogs.

Resolves #367

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 17:58:25 -04:00