Skip to content

[6 / 7] - Security tab #203

Open
TheSCREWEDSoftware wants to merge 6 commits into
azerothcore:masterfrom
TheSCREWEDSoftware:6_user_security2fa
Open

[6 / 7] - Security tab #203
TheSCREWEDSoftware wants to merge 6 commits into
azerothcore:masterfrom
TheSCREWEDSoftware:6_user_security2fa

Conversation

@TheSCREWEDSoftware

@TheSCREWEDSoftware TheSCREWEDSoftware commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Split from the main PR: #197

Split by Claude

New Security tab with password change (shows last-changed date, optional no-reuse of last 10 hashed passwords) and 2FA for Website (authenticator or email) and In-game. 2FA becomes required for login + password changes; removals notify the user (security tab + top of profile, whether self or staff). Admin tools to check/remove a user's 2FA + backup codes. Connection logging (website + last in-game IP, opt-in) with GeoIP country lookup, plus the Recent-Connections lists (10 on profile, 50-at-a-time on the security tab, current IP highlighted). Makes WP-2FA a required, non-disableable plugin.

Mentioned here #201 fixed in current PR

image image image image image image

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Security panel for password management and two-factor authentication configuration with recent connections log.
    • Added Dark Mode toggle in admin bar for WordPress dashboard.
    • Added login history tracking with GeoIP country detection.
    • Enhanced character ordering with visual reset functionality.
  • Improvements

    • Redesigned Mail Return page with sidebar character selection and enhanced mail card display including item quality indicators.
    • Redesigned Tools page with organized columns for server integration, web integration, and security settings.
    • Redesigned Item Restoration with character sidebar and quality-color-coded item cards.
    • Improved 2FA management including backup code removal and admin controls.
  • Security

    • Added character ownership verification for item restoration requests.
    • Passwords now synchronize between website and in-game accounts.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a Security user panel page (password change with history enforcement and SOAP sync, website/in-game 2FA gates using TOTP and email, admin removal logging, recent connections with GeoIP); a new ConnectionLogger module logging login history with ip-api GeoIP backfill; a Dark Mode admin bar toggle; a shared AcoreCharColors utility; and overhauled UIs for character ordering, mail return, item restoration, unstuck, Tools admin panel, and resurrection scroll, with security hardening across forms via nonces and ownership checks.

Changes

Security, 2FA, Connection Logging, Dark Mode & UI Overhaul

Layer / File(s) Summary
AcoreCharColors utility and boot wiring
src/acore-wp-plugin/src/Utils/AcoreCharColors.php, src/acore-wp-plugin/src/boot.php, src/acore-wp-plugin/src/Manager/Opts.php, src/acore-wp-plugin/src/Hooks/Various/tgmplugin_activator.php, src/acore-wp-plugin/src/Manager/Soap/SmartstoneService.php
New AcoreCharColors static utility class centralizes WoW class/race/faction constants and row style generation. Three new Opts fields added for security logging, old passwords, and GeoIP. WP 2FA plugin registered as required via TGMPA. Both new modules wired into boot.php.
ConnectionLogger: login history table, GeoIP lookup, and cron backfill
src/acore-wp-plugin/src/Hooks/User/ConnectionLogger.php, src/acore-wp-plugin/src/Hooks/User/Include.php
New file creates acore_login_history DB table, logs website and in-game login IPs on wp_login with trusted-proxy-aware IP resolution, looks up GeoIP country via ip-api with rate-limit blocking, and schedules a 5-minute cron to bulk-resolve Unknown-country rows via ip-api batch endpoint.
PasswordHandler: password change with history, SOAP sync, and 2FA gate
src/acore-wp-plugin/src/Hooks/User/PasswordHandler.php
New file handles the acore_change_password admin_init action: validates old/new passwords, enforces reuse prevention from stored history, syncs to in-game via SOAP (blocks website change on SOAP failure), records history capped at 10, updates password and acore_password_changed_at meta, and manages transient-backed flash messages.
ServerInfoApi: TOTP helpers and new 2FA/connection REST endpoints
src/acore-wp-plugin/src/Components/ServerInfo/ServerInfoApi.php
Adds global TOTP/Base32 validation, WP2FA code validation with fallback decryption, and 2FA enabled/transient-key/self-removal helpers. Extends REST API with server-info/module, admin 2fa-check/remove/backup-codes-remove/login-history, and user-facing remove-ingame-2fa/verify-website-2fa/request-email-2fa/verify-email-2fa/2fa-status/connections endpoints.
ToolsApi and ACoreServices: item restore ownership validation
src/acore-wp-plugin/src/Components/Tools/ToolsApi.php, src/acore-wp-plugin/src/Manager/ACoreServices.php
ToolsApi.ItemRestore validates item as positive integer and checks character ownership before executing SOAP; both item-restore routes gain is_user_logged_in permission callbacks. ACoreServices.getRestorableItemsByCharacter adds account-ownership verification and returns richer fields; new currentAccountOwnsCharacterName method added.
Security page: controller, view, menu wiring, and full template
src/acore-wp-plugin/src/Components/UserPanel/UserController.php, src/acore-wp-plugin/src/Components/UserPanel/UserView.php, src/acore-wp-plugin/src/Components/UserPanel/UserMenu.php, src/acore-wp-plugin/src/Components/UserPanel/Pages/SecurityPage.php
UserController gains showSecurityPage, getIngame2faStatus, and getTwoFaData; UserView gains getSecurityRender; UserMenu registers the Security submenu. SecurityPage.php renders a nonce-protected password form, website 2FA TOTP/email gates, in-game 2FA badge with removal form, admin removal warnings, recent connections table with load-more, and a 20s 2FA-status polling loop.
User.php profile hooks: password timestamps, expansion picker, 2FA warnings, recent connections
src/acore-wp-plugin/src/Hooks/User/User.php
Records acore_password_changed_at on password update and reset. Replaces expansion select with a radio picker with inline JS arrow movement. Hardens expansion save validation. Adds acore_profile_2fa_removal_warning (reads admin log + in-game totp_secret), hides WP2FA blocks and password fields on standard profile, and adds a "Recent Connections" section.
Tools admin page: module-aware UI, 2FA management, and JS overhaul
src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php
Precomputes acore_modules_csv to conditionally disable resurrection scroll controls; adds nonce field; expands to Web Integration (security logging, GeoIP, 2FA remove flows with REST calls), Name Unlock Settings, and User Login History panels; adds confirm modal. Client-side JS rewired with ajaxPost/wire2fa helpers, paginated login history, and modal-based threshold management.
Dark mode: admin bar toggle, AJAX handler, and CSS enqueue
src/acore-wp-plugin/src/Hooks/Various/DarkMode.php
Registers admin-bar dark mode node, admin_body_class filter, enqueues three CSS layers, injects inline JS for AJAX toggle, outputs late admin_head inline styles for WP2FA modal sizing and dark-mode UI overrides, and injects theme.css into the WP2FA setup wizard for dark-mode users.
Character order UI: reset action, AcoreCharColors rows, sortable position
src/acore-wp-plugin/src/Components/CharactersMenu/CharactersController.php, src/acore-wp-plugin/src/Components/CharactersMenu/CharactersView.php
Controller adds nonce check and resetCharacterOrder helper. View uses AcoreCharColors for styled rows with level/race/class icons, position numbers, and adds a Reset Order button; jQuery sortable updated to recalculate displayed positions on sort.
Mail return: sidebar selector, card layout, quality icons, Wowhead upgrades
src/acore-wp-plugin/src/Components/MailReturnMenu/MailReturnController.php, src/acore-wp-plugin/src/Components/MailReturnMenu/MailReturnView.php, src/acore-wp-plugin/web/assets/mail-return/mail-return.js
Controller adds m.cod and it.Quality to mail queries. View switches to sidebar character list with AcoreCharColors and wp_localize_script. JS changes trigger to card click, rebuilds mail entries with faction/class styling, level badges, COD label, quality-colored item grids, and upgrades Wowhead icon URLs to large JPGs.
Item restoration: sidebar layout, card UI, nonce-authenticated restore, quality borders
src/acore-wp-plugin/src/Components/UserPanel/Pages/ItemRestorationPage.php
Replaces dropdown/table with a sidebar character list and item card grid using AcoreCharColors. JS fetches restorable items via nonce-authenticated REST, renders cards with Wowhead icons and formatted delete dates, removes restored cards on success, renumbers remaining cards, and colors card borders by quality class.
Unstuck, RAF, and Resurrection Scroll UI hardening
src/acore-wp-plugin/src/Components/UnstuckMenu/UnstuckView.php, src/acore-wp-plugin/src/Components/UserPanel/Pages/RafProgressPage.php, src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollMenu.php, src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollView.php, src/acore-wp-plugin/src/Components/UserPanel/UserView.php
Unstuck switches to wp_localize_script and adds output escaping. RAF adds wp_nonce_field and updates layout/copy. Resurrection scroll menu gates behind isAvailable() checking module CSV; view updates badge classes to success/danger. UserView updates acore-css versions and power-js args. UserController.showRafProgress adds nonce check and absint validation.
CSS: unified character list, mail return grid, profile sub-pages, item restoration cards
src/acore-wp-plugin/web/assets/css/main.css, src/acore-wp-plugin/web/assets/css/theme.css
main.css replaces char-order/char-unstuck blocks with unified .acore-char-list system, rewrites mail return UI into grid layout with item icon slots, and adds profile sub-page and item restoration card grid styling. theme.css introduces CSS variables, item-quality card borders, security page/connection table, WP2FA modal, myCRED, and dark-mode button overrides.
CSS: dark-mode.css comprehensive dark admin overrides
src/acore-wp-plugin/web/assets/css/dark-mode.css
Adds dark-mode overrides across profile headings, security page, expansion selector, admin bar toggle, Bootstrap 5 variables, postboxes, cards, character rows, form inputs, mail entries, admin tables, buttons, notices, myCred widgets, resurrection scroll page, expansion level badges, and mail return page.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SecurityPage
  participant REST as WP REST API
  participant ServerInfoApi
  participant GameDB as Game DB
  participant WP2FA as WP2FA Plugin

  rect rgba(100, 149, 237, 0.5)
    Note over User,WP2FA: Website 2FA TOTP Gate
    User->>SecurityPage: enter 6-digit TOTP code
    SecurityPage->>REST: POST verify-website-2fa
    REST->>ServerInfoApi: acore_wp2fa_code_is_valid()
    ServerInfoApi->>WP2FA: is_valid_authcode (preferred)
    WP2FA-->>ServerInfoApi: valid
    ServerInfoApi->>ServerInfoApi: set unlock transient
    ServerInfoApi-->>SecurityPage: 200 OK
    SecurityPage->>SecurityPage: reveal WP2FA management panel
  end

  rect rgba(255, 140, 0, 0.5)
    Note over User,GameDB: In-game 2FA removal
    User->>SecurityPage: submit optional TOTP + remove
    SecurityPage->>REST: POST remove-ingame-2fa
    REST->>ServerInfoApi: check unlock transient or fresh TOTP
    ServerInfoApi->>GameDB: UPDATE account SET totp_secret=NULL
    GameDB-->>ServerInfoApi: ok
    ServerInfoApi-->>SecurityPage: success
    SecurityPage->>SecurityPage: reload page after delay
  end

  rect rgba(34, 139, 34, 0.5)
    Note over User,SecurityPage: Password change
    User->>SecurityPage: submit new password
    SecurityPage->>REST: admin_init PasswordHandler
    REST->>REST: validate old/new, check history
    REST->>GameDB: SOAP setAccountPassword
    GameDB-->>REST: ok
    REST->>REST: wp_set_password + record history
    REST-->>SecurityPage: redirect with success
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐇 Hoppity-hop through the code I go,
2FA gates and dark modes all aglow,
TOTP tokens validated with care,
GeoIP backfills cron'd through the air,
Character rows styled in faction's hue —
This rabbit approves every line brand new!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title '[6 / 7] - Security tab' refers to a major feature (Security tab implementation) present in the changeset, but is vague by using a numbered series marker '[6/7]' which lacks context without additional PR history. The title is minimally descriptive of the actual content. Consider a more descriptive title that summarizes the main feature without relying on series numbering, such as 'Add Security tab with password management and 2FA configuration' or similar, to make the PR clear when reviewed independently.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 19

🧹 Nitpick comments (2)
src/acore-wp-plugin/web/assets/mail-return/mail-return.js (1)

43-47: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

expansionColor() appears unused.

This helper is defined within the success callback, but the level badge (Lines 109-114) derives its data-exp slug inline via lvlExp and relies on CSS for coloring. expansionColor is not referenced within the callback scope. Consider removing it as dead code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/acore-wp-plugin/web/assets/mail-return/mail-return.js` around lines 43 -
47, The `expansionColor()` function defined within the success callback is not
referenced anywhere in the callback scope and represents dead code. The level
badge styling (lines 109-114) derives its color through CSS classes based on the
`data-exp` attribute rather than using the `expansionColor()` function. Remove
the entire `expansionColor()` function definition as it is unused and
unnecessary.
src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php (1)

399-402: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent confirmation UX in wire2fa removal.

This handler uses the native confirm() dialog, while the rest of the page (backup-code removal, threshold delete, reset) routes through the styled acoreConfirm modal defined at Line 551. Consider using acoreConfirm here too for consistent look/behavior (note its callback is async, so the removal logic moves inside the callback).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php` around lines
399 - 402, Replace the native confirm() dialog in the wire2fa removal handler
with the acoreConfirm modal for consistent styling and behavior across the page.
Remove the synchronous confirm() check and instead wrap the removal logic
(username assignment and subsequent operations) inside the async callback of
acoreConfirm, passing the confirmation message and callback function to maintain
the same user experience as other removal handlers like backup-code removal and
threshold delete already implemented on this page.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php`:
- Around line 250-251: The input element with the name attribute
acore_name_unlock_allowed_banned_names_table is directly echoing the value from
Opts::I()->acore_name_unlock_allowed_banned_names_table into the HTML value
attribute without escaping, which creates a stored XSS vulnerability. Wrap the
echoed value with the esc_attr() function to properly escape it before rendering
it into the attribute, matching the approach already applied to the numeric
input at Line 149. This ensures that any special characters like quotes or
script tags are safely encoded and cannot break out of the attribute.
- Around line 595-601: Add a guard clause before the foreach loop that iterates
over Opts::I()->acore_name_unlock_thresholds to check if the value is actually
an array using is_array(). If the value is not an array, assign an empty array
to a local variable instead. Then iterate over this validated variable in the
foreach loop instead of directly using Opts::I()->acore_name_unlock_thresholds.
This prevents warnings in PHP 7.x and TypeErrors in PHP 8 when the database
value has been corrupted or overwritten with a non-array value.

In `@src/acore-wp-plugin/src/Components/CharactersMenu/CharactersController.php`:
- Around line 49-56: In the resetCharacterOrder method, the account ID retrieved
from getAcoreAccountId() is not validated before being used in the bindValue
call on line 55. If getAcoreAccountId returns a non-numeric or false value, the
update query could execute with incorrect account scope. Add validation
immediately after retrieving $accId to ensure it is a positive integer, and only
execute the prepare, bindValue, and executeQuery statements if the validation
passes.

In `@src/acore-wp-plugin/src/Components/CharactersMenu/CharactersView.php`:
- Around line 72-85: The current character reordering implementation using
jQuery sortable on line 74 only supports drag-and-drop interaction, which is not
accessible to keyboard-only users. Add an accessible alternative reordering
mechanism by implementing per-row up/down button controls (e.g., move up/move
down buttons for each character row) that allow keyboard navigation and
interaction. These controls should manipulate the same characterorder[] input
field values and update the position display (acore-char-pos) just like the
sortable implementation does, ensuring the same data structure is maintained
when the order is submitted.
- Around line 48-49: The race-icon and class-icon img tags in the
CharactersView.php file are missing alt attributes, which are required for
accessibility and assistive technologies. Add alt attributes to both img
elements (the one with class="race-icon" and the one with class="class-icon")
using the same escaped values from their respective title attributes, which call
AcoreCharColors::getRaceName() and AcoreCharColors::getClassName() methods.

In `@src/acore-wp-plugin/src/Components/ServerInfo/ServerInfoApi.php`:
- Around line 152-159: The function acore_ingame_2fa_enabled accepts a $userId
parameter but ignores it and instead calls $services->getAcoreAccountId() to
retrieve the current session account ID. This causes the function to always
check the 2FA status for the current user rather than the requested user.
Replace the call to getAcoreAccountId() with the $userId parameter that was
passed to the function so that the query checks the correct user's 2FA status.
- Around line 447-456: The remove-ingame-2fa endpoint does not rate-limit TOTP
code validation attempts, making it vulnerable to brute force attacks despite
requiring authentication. After each failed TOTP validation in this endpoint
(whether from format validation with preg_match or code validation with
acore_wp2fa_code_is_valid), increment and check a rate-limiting transient
similar to what verify-website-2fa uses for its 5-attempt limit. Before
processing any fresh TOTP code validation, check if the rate limit transient has
been exceeded and return an error if so. Use a consistent transient key
mechanism based on acore_2fa_unlock_key or similar to track failed attempts
across this endpoint.
- Around line 200-207: The code calls stripos($result, $pattern) on the result
from ServerInfoApi::serverInfo() without validating that $result is a string,
which will cause a TypeError if the method throws an exception or returns a
non-string value. Wrap the ServerInfoApi::serverInfo() call in a try-catch block
to handle any exceptions, then add type validation to ensure $result is a string
before iterating through $errorPatterns and calling stripos(). Follow the
exception handling and response type validation pattern used in the
server-modules endpoint (referenced in the comment as lines 247-254) to ensure
consistent error handling throughout the code.

In `@src/acore-wp-plugin/src/Components/Tools/ToolsApi.php`:
- Around line 30-31: The callback function for the REST endpoint needs to
implement error handling to convert expected exceptions from character lookup
failures into REST errors. Wrap the call to ToolsApi::ItemRestoreList within a
try-catch block, catch exceptions that may be thrown by
getRestorableItemsByCharacter() (such as those for invalid or non-owned
characters), and return a WP_Error object with an appropriate error code and
message instead of allowing the exception to propagate as a generic server
failure.
- Around line 19-22: The executeCommand method call is missing authorization for
the recovery item itself. While the code verifies that the character belongs to
the current account using ACoreServices::I()->currentAccountOwnsCharacterName(),
it does not validate that the recovery_item (identified by the item variable)
belongs to that character and account. Add a helper method that performs a
joined lookup validating that the recovery_item.Id matches the provided
character's guid, belongs to the current account, and is not deleted (checking
deleteDate IS NULL). Execute this authorization check before calling
executeCommand to prevent unauthorized item restoration.

In `@src/acore-wp-plugin/src/Components/UserPanel/Pages/ItemRestorationPage.php`:
- Around line 199-202: The error message is being set in the errorBox within the
catch block, but the errorBox is inside the hidden `#item-restore-content`
container that was hidden earlier at line 117. Before setting the error message
in the errorBox, unhide the `#item-restore-content` container by setting its
display property to visible or block. This ensures the error message becomes
visible to the user when the catch block executes and populates the errorBox
with the error message.
- Around line 217-235: Replace the fragile string matching logic in the restore
response handler with structured response checking. Change the condition that
currently checks if data is a string containing 'mail' to instead check if
data.success equals true. When success is true, extract the message from
data.message instead of using the raw data string for the successBox.textContent
assignment. Keep the remaining card removal, renumbering, and content visibility
logic unchanged. This ensures the success detection is based on an explicit flag
rather than brittle text matching.

In `@src/acore-wp-plugin/src/Components/UserPanel/Pages/RafProgressPage.php`:
- Around line 14-21: The conditional on line 14 in RafProgressPage.php is
checking the wrong configuration key for gating the same-IP warning notice.
Currently it checks end_raf_on_same_ip, but the backend enforcement in
UserController::showRafProgress() uses check_ip instead. Update the condition on
line 14 to check Opts::I()->eluna_raf_config['check_ip'] === '1' instead of
end_raf_on_same_ip to ensure the frontend warning text aligns with the actual
server-side enforcement behavior.

In `@src/acore-wp-plugin/src/Components/UserPanel/Pages/SecurityPage.php`:
- Around line 220-267: The WP2FA management HTML stored in the $wp2faHtml
variable is being rendered inside hidden panels (display:none) in both the
$websiteTotpEnabled and $websiteEmailEnabled branches, which exposes sensitive
backup codes and settings in the page source before verification. Remove the
$wp2faHtml from the hidden acore-2fa-panel divs in both the TOTP gate and email
gate branches so the management UI is never present in the DOM before the gate
passes. After verification succeeds and the unlock transient is set, reload the
page or fetch the protected panel server-side to ensure acore-2fa-panel is only
rendered with its HTML content when the user has been properly authenticated.

In `@src/acore-wp-plugin/src/Components/UserPanel/UserController.php`:
- Around line 54-68: The IP checking logic in UserController.php is vulnerable
to spoofing because it directly accepts HTTP_CLIENT_IP and HTTP_X_FORWARDED_FOR
headers without validation. Replace the manual IP extraction code that checks
$_SERVER['HTTP_CLIENT_IP'], $_SERVER['HTTP_X_FORWARDED_FOR'], and
$_SERVER['REMOTE_ADDR'] with a call to the trusted helper function
acore_resolve_client_ip() which already validates against configured trusted
proxies. Use the return value from this helper function to set activeUserIp
instead of the current approach that applies the wpb_get_ip filter manually.
- Around line 217-221: The getModel() method in UserController is dead code that
is never called and contains a misleading docblock stating it returns a
non-existent UserModel class while actually returning $this. Remove the entire
getModel() method definition including its docblock from the UserController
class since it has no dependencies and serves no purpose.

In `@src/acore-wp-plugin/src/Hooks/User/ConnectionLogger.php`:
- Around line 34-58: The acore_log_login function makes blocking HTTP requests
during the login flow via acore_lookup_country calls, which can stall the login
by up to 6 seconds. Replace the acore_lookup_country($ip) call with
acore_geoip_known_country($ip) to use only the local database cache instead of
making synchronous HTTP requests. Store Unknown as the country value when the IP
is not found in the local cache, and allow the existing 5-minute backfill cron
job to resolve these Unknown rows asynchronously using the batch endpoint,
completely removing blocking outbound calls from the login path.

In `@src/acore-wp-plugin/src/Hooks/User/User.php`:
- Around line 759-764: The notice displays $lastWebRemoval['staff'] without
checking if it exists, causing an undefined-index warning when the entry is a
self-removal (where staff is not set). Modify the printf statement to
conditionally display different text based on whether $lastWebRemoval['staff']
is set. If the staff key exists, display the current message with the staff
member name. If it does not exist (self-removal case), display an alternative
message indicating that the user removed their own Website 2FA. Use isset() or
array_key_exists() to safely check for the staff key before accessing it.

In `@src/acore-wp-plugin/web/assets/mail-return/mail-return.js`:
- Around line 98-104: The safeName variable is not properly escaped for HTML
attribute context, specifically for double quotes. When safeName is interpolated
into the title and data-wowhead attributes, double quote characters in item
names will break out of the quoted attribute value, causing malformed markup.
Replace all instances where safeName is used within the attribute values (inside
title="..." and data-wowhead="..." on the lines building itemsHtml) with a
version that escapes double quotes as HTML entities. Use a method that replaces
" with " when safeName is placed into these attribute contexts to prevent
attribute injection.

---

Nitpick comments:
In `@src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php`:
- Around line 399-402: Replace the native confirm() dialog in the wire2fa
removal handler with the acoreConfirm modal for consistent styling and behavior
across the page. Remove the synchronous confirm() check and instead wrap the
removal logic (username assignment and subsequent operations) inside the async
callback of acoreConfirm, passing the confirmation message and callback function
to maintain the same user experience as other removal handlers like backup-code
removal and threshold delete already implemented on this page.

In `@src/acore-wp-plugin/web/assets/mail-return/mail-return.js`:
- Around line 43-47: The `expansionColor()` function defined within the success
callback is not referenced anywhere in the callback scope and represents dead
code. The level badge styling (lines 109-114) derives its color through CSS
classes based on the `data-exp` attribute rather than using the
`expansionColor()` function. Remove the entire `expansionColor()` function
definition as it is unused and unnecessary.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3cb53f54-e9eb-4eb1-97fa-a4ad1f265af3

📥 Commits

Reviewing files that changed from the base of the PR and between 94af292 and c4263c7.

📒 Files selected for processing (31)
  • src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php
  • src/acore-wp-plugin/src/Components/CharactersMenu/CharactersController.php
  • src/acore-wp-plugin/src/Components/CharactersMenu/CharactersView.php
  • src/acore-wp-plugin/src/Components/MailReturnMenu/MailReturnController.php
  • src/acore-wp-plugin/src/Components/MailReturnMenu/MailReturnView.php
  • src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollMenu.php
  • src/acore-wp-plugin/src/Components/ResurrectionScrollMenu/ResurrectionScrollView.php
  • src/acore-wp-plugin/src/Components/ServerInfo/ServerInfoApi.php
  • src/acore-wp-plugin/src/Components/Tools/ToolsApi.php
  • src/acore-wp-plugin/src/Components/UnstuckMenu/UnstuckView.php
  • src/acore-wp-plugin/src/Components/UserPanel/Pages/ItemRestorationPage.php
  • src/acore-wp-plugin/src/Components/UserPanel/Pages/RafProgressPage.php
  • src/acore-wp-plugin/src/Components/UserPanel/Pages/SecurityPage.php
  • src/acore-wp-plugin/src/Components/UserPanel/UserController.php
  • src/acore-wp-plugin/src/Components/UserPanel/UserMenu.php
  • src/acore-wp-plugin/src/Components/UserPanel/UserView.php
  • src/acore-wp-plugin/src/Hooks/User/ConnectionLogger.php
  • src/acore-wp-plugin/src/Hooks/User/Include.php
  • src/acore-wp-plugin/src/Hooks/User/PasswordHandler.php
  • src/acore-wp-plugin/src/Hooks/User/User.php
  • src/acore-wp-plugin/src/Hooks/Various/DarkMode.php
  • src/acore-wp-plugin/src/Hooks/Various/tgmplugin_activator.php
  • src/acore-wp-plugin/src/Manager/ACoreServices.php
  • src/acore-wp-plugin/src/Manager/Opts.php
  • src/acore-wp-plugin/src/Manager/Soap/SmartstoneService.php
  • src/acore-wp-plugin/src/Utils/AcoreCharColors.php
  • src/acore-wp-plugin/src/boot.php
  • src/acore-wp-plugin/web/assets/css/dark-mode.css
  • src/acore-wp-plugin/web/assets/css/main.css
  • src/acore-wp-plugin/web/assets/css/theme.css
  • src/acore-wp-plugin/web/assets/mail-return/mail-return.js

Comment thread src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php
Comment thread src/acore-wp-plugin/src/Components/AdminPanel/Pages/Tools.php
Comment thread src/acore-wp-plugin/src/Components/UserPanel/UserController.php
Comment thread src/acore-wp-plugin/src/Components/UserPanel/UserController.php
Comment thread src/acore-wp-plugin/src/Hooks/User/ConnectionLogger.php
Comment thread src/acore-wp-plugin/src/Hooks/User/User.php
Comment thread src/acore-wp-plugin/web/assets/mail-return/mail-return.js
TheSCREWEDSoftware added a commit to TheSCREWEDSoftware/acore-cms that referenced this pull request Jun 24, 2026
(Resume generated by Claude)

**PR azerothcore#199 — Characters Menu**
- Fixed typo: "succesfully" → "successfully" in save confirmation
- Fixed broken sentence in the Order Character Screen description
- Extended `user-select: none` to cover all `.acore-char-row` elements, not just `button`

**PR azerothcore#200 — Mail Return**
- *(issues covered by later PRs — no unique fixes)*

**PR azerothcore#201 — Item Restoration**
- Added `alt=` attributes to race/class icons in `CharactersView.php`
- `ToolsApi`: `ItemRestoreList` now catches exceptions and returns a 403 instead of a 500
- `ToolsApi` + `ACoreServices`: **Security fix** — `ItemRestore` now verifies the recovery item belongs to the character, not just that the user owns the character name (IDOR vulnerability)

**PR azerothcore#202 — Unstuck / Scroll / RAF**
- `ItemRestorationPage`: removed brittle `data.includes('mail')` success check — any HTTP success now triggers the success path

**PR azerothcore#203 — Security Tab**
- `CharactersController`: `resetCharacterOrder()` now guards against invalid/null account ID before running UPDATE
- `Tools.php`: added `esc_attr()` on banned-names table input (XSS fix)
- `Tools.php`: added `is_array()` guard on thresholds `foreach`
- `Tools.php` + `SettingsController`: added sentinel input so deleting all thresholds actually clears them in the DB
- `Tools.php`: GeoIP hidden fallback `value="0"` is now always rendered, not conditionally

**PR azerothcore#204 — Admin Settings / CSRF**
- `AcoreCharColors`: removed unused `$fDark`, unknown race IDs now get a neutral color instead of Horde red
- `MailReturnView`: added `esc_url()` on race/class icon `src` attributes
- `DarkMode`: added `dmToggleInFlight` flag to prevent overlapping AJAX requests on rapid dark mode clicks
@TheSCREWEDSoftware

Copy link
Copy Markdown
Contributor Author

The reviews are valid for this, but the are fixed in the on the way to latest PR and including he last PR #205

PR #203 — Security Tab

  • CharactersController: resetCharacterOrder() now guards against invalid/null account ID before running UPDATE
  • Tools.php: added esc_attr() on banned-names table input (XSS fix)
  • Tools.php: added is_array() guard on thresholds foreach
  • Tools.php + SettingsController: added sentinel input so deleting all thresholds actually clears them in the DB
  • Tools.php: GeoIP hidden fallback value="0" is now always rendered, not conditionally

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.

1 participant