Repository navigation
fix: close three batch-4 review follow-ups - #174
Open
thedancingdeveloper wants to merge 3 commits into
Open
thedancingdeveloper wants to merge 3 commits into
thedancingdeveloper wants to merge 3 commits into
Conversation
start_engine moved AppState into the HTTP task and dropped StartupResult, which unlocked the data-dir flock immediately. The lock is now public on StartupResult and held in EngineState until the process exits.
After a refresh failed, discardFailedSession stored the other tab's refresh token in the access-token signal. The retry then sent that refresh token as a bearer. Keep the access token from ACCESS_KEY instead.
GET /api/history?days=100000000 panicked in Duration::days because the span does not fit in an i64 of milliseconds. Cap the window at 36500 days and return 400 instead.
thedancingdeveloper
left a comment
Collaborator
Author
There was a problem hiding this comment.
Security review: no blockers (head 4583c30)
I reviewed all three commits on current main (71fea38). All three batch-4 should-fix items are fixed correctly. CI: all 11 checks are green at this head: policy, rust, both Analyze jobs, desktop, frontend, e2e, container-smoke, CodeQL, dependency-review and runner-policy.
1. /api/history?days overflow (4583c30): fixed
h_history_listreturns a 400 fordays > MAX_HISTORY_DAYS(36,500, about 100 years) before computingUtc::now() - Duration::days(..).- In batch 4 I confirmed that 95,000,000 days still works and only values of about 100,000,000 and above panic, so the 36,500 cap is far inside chrono's range.
huge_days_query_is_rejected_instead_of_panickingdrives/api/history?days=100000000through the real handler and asserts a 400.- Nit: the check runs after the full
history_listload. Moving it to the top of the handler would skip that work for a rejected request.
2. Desktop single-instance lock (f205479): fixed
StartupResult.instance_lockis now public.start_engine()moves it out beforeresultis dropped, returns it, andstart()stores it in Tauri-managedEngineState, which lives until the app exits. A second desktop or headless instance on the same data dir is now refused for the whole session.- Should-fix (small): the desktop build now warns
field \lock` is never readandfield `instance_lock` is never read(seen in this PR'sdesktopCI log). They don't fail CI, but they invite someone to delete the "unused" field and reintroduce the bug. Rename them_lock/_instance_lock(the value is still held for the struct's lifetime), or add#[allow(dead_code)]with a comment saying the field is held for itsDrop`. - Nit:
moved_instance_lock_still_excludes_a_second_instanceonly shows that moving anInstanceLockdoesn't release it, which Rust guarantees. It doesn't exercise the desktop path, which can't easily be tested; the code change is what fixes it.
3. Refresh token in the access-token signal (0ba4e1d): fixed, plus a correction to my batch-4 description
discardFailedSession()now sets the signal fromgetAccessToken(), which islocalStorage['access_token'], the access token the other tab stored, never the refresh token. It also marks the sessionverified.- That's safe: if that token is bad, the next 401 spends the stored refresh token. If that refresh fails too,
stored === lastSpentRefreshholds and the tokens are cleared, so there's no loop. - Correction: in batch 4 I said this bug made the retry send
Bearer <refresh token>. That was wrong. The interceptor builds every header fromauthService.getAccessToken()(auth.interceptor.ts:35/48/60), which readslocalStorage, not the signal. The signal is only read inauthenticated = computed(() => !!this.accessToken() && this.verified())as a truthiness check. So the refresh token never left the browser in a header, and the old bug had no security impact. The fix is still the right cleanup. - Nit (regression tests): I applied only this PR's two spec changes to main's code and ran them.
- The new interceptor test passes on the old code. It describes behaviour that was already correct.
- The new service test fails on the old code only at
authenticated(), because of the newly addedverified.set(true). - Neither test checks that the signal holds the access token rather than the refresh token. If you want to pin that, assert on the signal's value, e.g. through a test-only accessor.
Notes
No dependency, CI or build-script changes. Not merged. This verdict covers only this head SHA.
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
GET /api/history?days=windows above 36500 sochrono::Duration::dayscannot panic on an overflowing millisecond span (days=100000000now returns 400).InstanceLockout ofStartupResultintoEngineStatebefore the startup result is dropped.ACCESS_KEYinstead of storing that tab's refresh token as the access token.nzb-web0.4.24 exposesStartupResult.instance_lock(previously private). The crate version is not bumped in this PR.Test plan
cargo test -p rustnzb(includeshuge_days_query_is_rejected_instead_of_panicking)cargo test -p nzb-web moved_instance_lock_still_excludes_a_second_instancecargo clippy --workspace -- -D warningscargo fmt --all --checknpm test -- --watch=falseinapps/rustnzb/frontend(154 passed, including the auth service and interceptor regressions)cargo testwas not run:libdbus-sysneeds systemlibdbus-1-dev, which is not installed here.