mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-16 16:45:07 +00:00
674781e57a
verify() asked Cache::has(), verified, then Cache::put(). Between the read and the write the key is free, so two requests carrying the same code could both be told yes -- which is exactly what the replay guard exists to prevent, and the window an intercepted code has is the whole of its validity either side. The claim is now the answer: Cache::add() writes only if the key is absent, so of two requests carrying the same valid code exactly one gets true back. That is the same mechanism, for the same reason, as the preview log's debounce -- "Cache::add is the whole mechanism: it writes only if the key is absent ... without a read-then-write race between two of them". Verification still happens first, so a wrong code never touches the cache and cannot burn the window for the code the person is about to type correctly. One test, modelling the interleaving it is about: the winner's claim has landed, and the loser's has() answers from before that write. Without the fix the loser is signed in.