From dce9253afc815e453e6e2d0f2413106f1138b63b Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Wed, 4 Mar 2026 13:53:13 -0600 Subject: [PATCH] fix: exempt agent WebSocket connections from brute force IP bans Agent connections authenticate at the channel join level with token validation, so they should not be subject to IP-based brute force protection. This prevents legitimate agents from being banned when connecting to the server. Changes: - Exempt /socket/agent/websocket from all IP ban checks - Update documentation to reflect agent exemption - Agents still authenticate securely via token during channel join --- .../plugs/brute_force_protection.ex | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/towerops_web/plugs/brute_force_protection.ex b/lib/towerops_web/plugs/brute_force_protection.ex index 13d960de..da6f7c5c 100644 --- a/lib/towerops_web/plugs/brute_force_protection.ex +++ b/lib/towerops_web/plugs/brute_force_protection.ex @@ -16,6 +16,7 @@ defmodule ToweropsWeb.Plugs.BruteForceProtection do ## Exemptions - Authenticated users (conn.assigns[:current_user] present) + - Agent WebSocket connections (/socket/agent - authenticated at channel join) - Whitelisted IPs (checked via BruteForce context) ## Placement @@ -37,20 +38,29 @@ defmodule ToweropsWeb.Plugs.BruteForceProtection do def init(opts), do: opts def call(conn, _opts) do - ip_address = get_remote_ip(conn) - - # Check whitelist and ban status before routing - conn = check_and_block(conn, ip_address) - - # Only register 404 tracking if we didn't already halt the request - # (halted requests have already been sent, can't register before_send) - if conn.halted do + # Exempt agent WebSocket connections - they authenticate at channel join + if agent_websocket?(conn) do conn else - maybe_track_404(conn, ip_address) + ip_address = get_remote_ip(conn) + + # Check whitelist and ban status before routing + conn = check_and_block(conn, ip_address) + + # Only register 404 tracking if we didn't already halt the request + # (halted requests have already been sent, can't register before_send) + if conn.halted do + conn + else + maybe_track_404(conn, ip_address) + end end end + defp agent_websocket?(conn) do + conn.request_path == "/socket/agent/websocket" + end + defp check_and_block(conn, ip_address) do # Whitelist bypass if BruteForce.check_whitelist(ip_address) do