Skip to content

fix: handle_event(next_round) missing early return causes double broadcast (#2418)#2707

Open
immortal71 wants to merge 1 commit intoOWASP:masterfrom
immortal71:fix/2418-next-round-double-broadcast
Open

fix: handle_event(next_round) missing early return causes double broadcast (#2418)#2707
immortal71 wants to merge 1 commit intoOWASP:masterfrom
immortal71:fix/2418-next-round-double-broadcast

Conversation

@immortal71
Copy link
Contributor

@immortal71 immortal71 commented Mar 20, 2026

Summary

Fixes #2418

In copi.owasp.org/lib/copi_web/live/player_live/show.ex, the handle_event(next_round) function had a control-flow bug: Elixir has no early returns, so the outer if/else block was not the last expression in the function. This caused the final three lines (Game.find, Endpoint.broadcast, {:noreply, ...}) to always execute unconditionally, regardless of which branch ran.

Root Cause

`elixir
if round_open?(game) do
..
{:noreply, assign(socket, :game, game)} # value discarded - NOT an early return
else
..
end

These always ran -- even when waiting for the 100ms timer
{:ok, updated_game} = Game.find(game.id)
CopiWeb.Endpoint.broadcast(...)
{:noreply, assign(socket, :game, updated_game)}
`

Fix

Moved Game.find + Endpoint.broadcast + {:noreply, ...} into the else branch so the outer if/else is the last expression of the function. Each branch now returns the correct value

…OWASP#2418)

Elixir has no early returns; the final three lines (Game.find,
Endpoint.broadcast, {:noreply, ...}) executed unconditionally because
the outer if/else was not the last expression in the function.

Fix: move Game.find + broadcast + noreply into the else branch so the
outer if/else is the function's last expression and each branch's value
is properly returned.

- round_open? true + can_continue? true: closes round, schedules 100ms
  timer, returns immediately - no premature broadcast
- round_open? true + can_continue? false: returns {:noreply, socket}
  unchanged - no spurious state change
- round_open? false: advances rounds_played, optionally sets
  finished_at, broadcasts exactly once

Fixes OWASP#2418
Copilot AI review requested due to automatic review settings March 20, 2026 14:16
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a control-flow bug in the Player LiveView’s "next_round" handler where logic after an if/else was unintentionally executed for all branches, causing double broadcasts and premature state updates.

Changes:

  • Moves Game.find/1, Endpoint.broadcast/3, and the final {:noreply, ...} into the else branch so the if/else is the function’s last expression.
  • Ensures the "round_open?" branches return without performing an immediate broadcast when a delayed :proceed_to_next_round is scheduled.

@immortal71
Copy link
Contributor Author

@sydseter is this good to go ??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: handle_event("next_round") missing early return causes double broadcast and premature game state update

2 participants