The hook was passing an inline onSuccess callback to useListData, which included onSuccess in its internal refresh function's dependency array. This caused refresh to be recreated on each render, which triggered the useEffect, which fired the fetch, which completed and caused a re-render, creating an infinite loop. Wrap onSuccess in useCallback with empty dependencies so it maintains a stable reference across renders. This allows refresh to be stable when its dependencies don't change, breaking the cycle. Add documentation to Refactoring.md explaining the onSuccess stability requirement for useListData callers. Also add tests for useJailConfigs to verify it doesn't trigger infinite refetches with stable onSuccess callback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2.2 KiB
2.2 KiB
BanGUI — Architecture Issues & Refactoring Plan
This document catalogues architecture violations, code smells, and structural issues found during a full project review. Issues are grouped by category and prioritised.
Security Fixes
- Fixed open redirect vulnerability in
frontend/src/pages/LoginPage.tsxby validating the?next=parameter to ensure it is a relative path (starts with/but not//). The validation regex/^\/(?!\/)/.test(next)prevents protocol-relative URLs and external redirects. Invalid paths fall back to"/".
Completed Refactors
- Moved
Fail2BanConnectionErrorandFail2BanProtocolErrorfrombackend/app/utils/fail2ban_client.pyintobackend/app/exceptions.py. Updated all router, service, and test call sites to import these domain exceptions fromapp.exceptionsand retained backward compatibility through re-exporting inapp.utils.fail2ban_client. - Moved config file exceptions (
ConfigDirError,ConfigFileNotFoundError,ConfigFileExistsError,ConfigFileWriteError,ConfigFileNameError) frombackend/app/services/raw_config_io_service.pyintobackend/app/exceptions.py. Updated router and tests to import the shared domain exceptions fromapp.exceptions. - Added global domain exception handlers to
backend/app/main.pyso domain exceptions likeJailNotFoundError,ConfigValidationError, andConfigWriteErrormap consistently to 404, 400, and 500 responses. - Fixed stale activation tracking in
backend/app/routers/jail_config.pyby recordinglast_activationonly after a successful jail activation and preventing a failed activation attempt from leaving a stale runtime state record. - Fixed infinite re-fetch loop in
frontend/src/hooks/useJailConfigs.tsby wrapping theonSuccesscallback inuseCallbackwith empty dependencies. The bug occurred becauseuseListDataincludesonSuccessin its internalrefreshfunction's dependency array; an inline callback created a new reference on each render, causingrefreshto be recreated, which triggered theuseEffectagain, leading to an unbounded fetch loop. Callers ofuseListDatamust always wraponSuccesscallbacks inuseCallbackto maintain reference stability.