fix(auth): dynamically sync WJ server clock offset for submission window - #69
Closed
JackyTJie wants to merge 1 commit into
Closed
fix(auth): dynamically sync WJ server clock offset for submission window#69JackyTJie wants to merge 1 commit into
JackyTJie wants to merge 1 commit into
Conversation
Port of 67c6d3c (deployed on fix/production-deploy) to main. The WJ questionnaire platform's server clock runs progressively slow (~7s/day; measured ~-230s on 2026-09-08), causing "Submission timestamp outside validity window" failures for all OTP verifications. Sample the offset from the WJ API response's Date header on every get_latest_answer call (NTP-style; same clock domain as submitted_at) and correct submitted_at before the validity-window check, with a 60s residual jitter tolerance. A rolling EWMA estimate is kept in Redis (wj:clock:offset, 48h TTL) as fallback; when no sample is available the check degrades to a fixed 220s tolerance. Adds AUTH.TIMESTAMP_JITTER_TOLERANCE (default 60) plus tests covering sampling, EWMA blending, correction acceptance, replay rejection, and fallback behavior. Porting compatibility fixes (required for the touched modules to import and run on this base, matching the production branch): - apps/auth: parenthesize multi-exception except clauses (invalid Python 3 syntax) - apps/auth: int()-cast OTP_TIMEOUT read from settings
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.
Problem
The WJ questionnaire platform's server clock runs progressively slow (~7s/day; measured ~230s slow on 2026-09-08). The OTP verification compares
initiated_at(our clock) againstsubmitted_at(WJ clock), so the growing skew breaks all signup/login/password-reset flows withSubmission timestamp outside validity window.Fix (port of 67c6d3c, already live on fix/production-deploy)
NTP-style dynamic calibration instead of a hard-coded tolerance:
get_latest_answersamples the WJ clock offset from each API response'sDateheader (RTT midpoint corrected; same clock domain assubmitted_at— verified against the measured drift history)submitted_atis corrected by the offset before the window check; residual jitter tolerance 60s (AUTH.TIMESTAMP_JITTER_TOLERANCE)wj:clock:offset, 48h TTL) as fallback; no sample at all → fixed 220s legacy windowPorting compatibility fixes
Required for the touched modules to import/run on this base (same as production branch):
exceptclauses inapps/auth(invalid Python 3 syntax on main —utils.py/views.pycurrently cannot import)int()-castOTP_TIMEOUT(env override is a string; arithmetic would raise)Tests
apps/auth/tests/test_clock_offset.py— 13 tests: sampler accuracy, EWMA blending, corrected acceptance at -300s drift, replay rejection, legacy fallback. All pass. Verified live against wj.sjtu.edu.cn: sampler reports -230.4s, matching independentcurlmeasurement.fix/production-deploy(Turnstile retry refactor, syllabus fixes, etc.) — this PR is only the clock fix; the rest still needs a separate merge-back decision.