You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[scanner] nps-relay: day-cap rejection in handleRegister leaves the per-IP registration slot consumed #557
netlify/nps-relay/relay.tshandleRegister reserves the per-IP registration slot and then increments the global per-day counter as two independent conditional writes (relay.ts:747-762). When the IP reservation succeeds and the day counter then returns 429 (MAX_REGISTRATIONS_PER_DAY reached), the request is rejected but the IP slot stays recorded. The comment above says "a limit that is hit never leaves a registration behind" — true, but the inverse is not: a refused registration still consumes one of the IP's MAX_REGISTRATIONS_PER_IP_PER_WINDOW = 3 slots for the 24h window.
The same pattern was fixed for handleSubmit in #555 (Closes #554): the IP slot is released via releaseSlot when the second reservation refuses. handleRegister was not covered by that change.
Effect: once the daily cap is hit, every retry from a client burns an IP slot; after three retries the IP is locked out of registering for 24h, which outlasts the day roll-over that would have let it through. The lost create-only race at relay.ts:775-786 (!created.modified) likewise leaves both the IP slot and the day count consumed without a registration, though that path is far rarer.
Expected
A registration refused by the day cap must not consume the independent per-IP registration quota: call releaseSlot(store, <REGISTER_IP_RATE_PREFIX key>, now) when dayDenied is returned, mirroring the handleSubmit fix.
Repro (unit)
Fake store where the day-counter record already holds {count: MAX_REGISTRATIONS_PER_DAY} and the register-IP record is empty: the response is 429 and afterwards the register-IP key holds one timestamp. Repeat three times and a fourth registration from the same IP on a later (fresh) day is also 429 even though the day counter is clear.
Fix sketch
In handleRegister, on dayDenied, await releaseSlot(store, ipKey, now) before returning; add a test next to releases the per-IP slot when the install limit refuses the submission in relay.test.ts asserting the register-IP record is empty after a day-cap refusal.
Activity