=== Spam Account Defender ===
Contributors: nasruleam
Tags: spam, registration, security, firewall, anti-spam
Requires at least: 5.0
Tested up to: 6.7
Stable tag: 1.1.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Practical, privacy-conscious protection against spam account registrations.

== Description ==

Spam Account Defender helps site owners prevent suspicious WordPress registrations before they become accounts. The free Standard edition works independently and keeps its core protection available without a key.

**Key Features:**

* Honeypot and form-timing registration protection
* Suspicious username and email-pattern checks
* Disposable-email, rate-limit, brute-force, and basic IP-blocking safeguards
* Manual spam account scans, flagged-account review, and safelist tools
* Administrator accounts are always protected from spam cleanup
* WordPress personal-data exporter, eraser, privacy-policy guidance, and uninstall cleanup

== Optional Pro Add-on ==

Spam Account Defender Pro is a separately distributed add-on that requires this free plugin. It adds configurable Admin Guard controls, verified crawler detection and reporting, CPU Guard, scheduled scans, opt-in automated cleanup, Role Conversion, advanced firewall controls, advanced log exports, and REST/XML-RPC hardening. Standard does not require a license key and does not ship Pro runtime code or Pro AJAX endpoints.

== Installation ==

1. Upload the `wp-spam-account-defender` folder to the `/wp-content/plugins/` directory
2. Activate the plugin through the 'Plugins' menu in WordPress
3. Configure the settings via the new 'Spam Defender' menu item in your admin dashboard

== Frequently Asked Questions ==

= Will this plugin slow down my website? =

No, WP Spam Account Defender is designed to be lightweight and only activates during registration attempts.

= Is this compatible with other security plugins? =

Yes, our plugin works alongside most security plugins without conflicts.

= Does it work with membership plugins? =

Yes, the plugin is compatible with popular membership and user registration plugins.

= How do I know if it's working? =

The plugin keeps basic security records locally in the WordPress database. Pro adds the separate advanced activity-log view and export tools.

= Can I customize the security level? =

Yes, you can adjust the security threshold from the settings page to balance between security and user convenience.

== Screenshots ==

1. Dashboard with statistics
2. Security settings configuration
3. Flagged-account review and safelist

== Changelog ==

= 1.1.1 =
* Restored the full flagged-account review interface (avatars, registration dates, pagination, bulk safelist/delete) after the Standard/Pro split.
* Added the `sad_protected_roles` and `sad_firewall_request_exempt` extension filters so add-ons can protect additional roles without shipping code in Standard.
* Corrected documentation: detailed activity logs and crawler DNS verification are Pro features, not part of Standard.

= 1.1.0 =
* Reorganized the product into a complete Standard edition and a separately distributed Spam Account Defender Pro add-on.
* Standard keeps registration protection, rate limiting, brute-force protection, basic IP blocking, manual scans, flagged-account review, safelist, and automatic Administrator protection.
* Added an in-dashboard Pro upgrade and License & Plan experience without changing the existing command-center design.
* Moved verified crawler checks, CPU Guard, role conversion, scheduled automation, advanced firewall controls, advanced logging/export, configurable Admin Guard, and REST/XML-RPC hardening to the optional Pro add-on.

= 1.0.68 =
* Performance: DNS bot-verification results are now cached per IP for one hour so that `gethostbyaddr()`/`dns_get_record()` blocking network calls are not repeated on every page load for the same visitor.
* Performance: Customer IP activity writes are debounced via a transient so that `update_option()` no longer fires on every authenticated page load — only once per hour per IP.
* Performance: CPU core count is cached permanently in a WordPress option after first detection, eliminating repeated `shell_exec('nproc')` calls.
* Performance: CPU monitoring cron interval changed from every 60 seconds to every 5 minutes, reducing the frequency of WP-Cron wake-ups that previously spiked load on every page view.
* Security: Added `wp_unslash()` before `sanitize_text_field()` in `clear_logs()`, `manage_whitelist()`, and related handlers to prevent double-encoding of backslash sequences (WordPress Coding Standards requirement).
* Security: `block_access()` now uses `wp_die()` with a translatable string for the non-admin path instead of bare `die()`, making it i18n-compliant and consistent.
* Security: Removed two debug `error_log()` calls that wrote settings data to the server log on every save.
* Cleanup: Removed two orphaned AJAX methods (`update_rate_limit_settings`, `update_ip_block_settings`) that were never registered as action handlers.
* Cleanup: Removed unused `$verification_data` class property from `SAD_Spam_Detector`.
* Cleanup: Deleted `admin/css/admin-styles.css` — a superseded 316-line CSS file that was never enqueued and duplicated selectors already in `admin-style.css`.
* Lifecycle: `wp_add_privacy_policy_content()` is now called during plugin setup so the plugin's data-collection practices appear in the WordPress Privacy Policy page editor.
* Lifecycle: `sad_spam_score` user meta key added to the GDPR eraser and exporter.
* Lifecycle: `uninstall.php` now deletes all ~30 options the plugin creates, including `sad_safelist`, rate-limit settings, scan settings, CPU thresholds, and detection-feature flags that were previously left behind after uninstall.
* Compatibility: `Domain Path: /languages` header added; `languages/` directory created; text domain loaded via `load_plugin_textdomain()` on `init`.
* Compatibility: `Tested up to` header updated to 6.7.
* Compatibility: `date()` replaced with `gmdate()` in cleanup query to ensure UTC-consistent date calculations regardless of server timezone.

= 1.0.67 =
* Fixed critical registration bypass: `is_machine_generated_username()` was previously called only on the `user_register` action — after the account was already written to the database — so it could mark accounts as spam but could not prevent them from being created. The check is now also wired into the `registration_errors` filter, which fires before WordPress creates the account, causing machine-generated usernames (e.g. `qfhgusxyep`, `kmvknyfuin`, `estlvzwvsv`, `idjilrijso`) to be rejected at the gate. Respects the existing "detect username patterns" setting.
* Fixed timer-bypass vector: bots that POST directly to `wp-login.php?action=register` without the hidden `registration_start_time` field previously skipped the timing check entirely (the guard was `if (isset(...) && !== '')`, so a missing field was silently allowed). A missing timer field is now treated the same as an invalid one and triggers the same registration error, closing the direct-POST bypass.

= 1.0.63 =
* Fixed false-positive spam detection: `is_machine_generated_username()` was flagging real names from Urdu, Arabic, Slavic, and other traditions that naturally have fewer vowels relative to consonants (e.g. "mohsinshahzad2212"). The vowel-ratio threshold has been tightened from 0.35 to 0.20 and the consonant-ratio floor raised from 0.60 to 0.65, so only strings with genuinely machine-like character distribution (< 1 vowel per 5 letters) trigger this signal.
* Fixed double-counting bug in `check_existing_user()`: `$post_count` and `$comment_count` were initialised to 0 at the top of the function, causing the `empty_account` (+2) check to fire for every user — including brand-new accounts whose counts were never fetched — on top of the `no_activity` (+2) check for the same condition. Both signals are now awarded inside the single block that actually fetches the counts, so they can only fire once and only for accounts old enough to be inspected.

= 1.0.62 =
* Fixed fatal error: `monitor_cpu_usage()` was declared private but registered as a WordPress cron-event callback; changed to public so WordPress can invoke it via `do_action`.
* Fixed registration-record pollution: the rate-limit record was appended to stored history even when honeypot, timing, or rate-limit checks blocked the attempt, which could exhaust quotas for legitimate users.
* Fixed strict-equality comparison (`=== 0`) against values returned as strings by `count_user_posts()` and `get_comments(count: true)`; both are now cast to int before comparison.
* Fixed PHP notice: `$_POST['log_type']` was accessed without an `isset()` guard in `get_logs()` and `export_logs()`.
* Fixed PHP notice: `$data['verified']` and `$data['last_verified']` accessed without `isset()` when rendering the customer IP table.
* Fixed PHP notice: `$firewall_settings['request_limit']` / `['time_window']` accessed without a null-guard when the option has not been saved yet.
* Fixed `scan_all_users()` calling the full `setup()` method to rehydrate patterns on AJAX requests; this re-registered all WordPress hooks and caused duplicates. The method now re-initialises patterns and weights inline without touching hooks.
* Fixed `$cpu_status` variable potentially being undefined when `convert_no_role_users_to_customer()` returns after an empty user batch; it is now initialised before the loop.
* Fixed timezone: replaced bare `date()` calls in the dashboard widget and dashboard template with `date_i18n()` so output honours the WordPress timezone setting.
* Fixed CSV export: replaced `date()` in the export filename with `gmdate()` for consistent UTC filenames.
* Removed all bare `error_log()` calls from `class-firewall.php` that ran unconditionally on every customer login, bot check, and request; they flooded PHP error logs in production.
* Removed unused `new SAD_Spam_Detector()` instantiation inside `SAD_Dashboard_Widget::render_widget_content()`.
* Removed dead JavaScript `exportLogs` method (never called; used the wrong AJAX approach for a file-download response).
* Removed dead JavaScript `initializeIpManagement` (lowercase) method that was never called and duplicated the working `initializeIPManagement`.
* Added `esc_attr()` to the hidden registration-timer field output.
* Added `sad_spam_training_data` to the uninstall cleanup list; it was missing and left behind on plugin removal.

= 1.0.61 =
* Hardened debug logging for production environments by guarding `WP_DEBUG`, using exclusive file locks, and removing raw settings dumps from logs.

= 1.0.60 =
* Added WordPress personal-data exporter and eraser support for detector metadata and user-linked security records.
* Added uninstall cleanup for plugin options and user metadata.
* Added privacy documentation for registration IPs, bot logs, verification data, and retention.

= 1.0.59 =
* Prepared the plugin for WordPress.org review with a slug-matching text domain and normalized active translations.
* Removed obsolete unreferenced legacy classes that used invalid plugin constants and duplicate architecture.
* Hardened admin settings and whitelist handlers with normalized POST arrays and safer stored-option handling.

= 1.0.58 =
* Fixed dead log export and clear-log JavaScript bindings.
* Changed log export to use a real CSV download POST matching the server response.
* Hardened log retrieval and export against malformed stored log options and empty pagination.
* Repaired the detector PHPUnit harness so private scoring/monitoring paths are invoked through reflection after setup.

= 1.0.57 =
* Fixed role conversion discovery for users whose capabilities metadata is the serialized empty-role value `a:0:{}`.
* Made role conversion honor the CPU Guard toggle and tolerate unavailable CPU load data.

= 1.0.56 =
* Aligned cleanup and dashboard spam totals to count every account marked with `sad_spam_status=spam`, including accounts without a role.
* Clamped cleanup retention and batch settings before deletion queries execute.

= 1.0.55 =
* Fixed CPU Guard state propagation so critical CPU limits apply to registrations handled in later requests.
* Hardened CPU load and core detection against unavailable data, zero-core results, and invalid threshold ordering.
* Normalized saved CPU thresholds so warning always remains below critical.

= 1.0.54 =
* Made the IP Blocking toggle authoritative for rate-limit and brute-force block creation.
* Made firewall search-bot bypasses honor the active bot-verification setting.

= 1.0.53 =
* Fixed Search Engine Bot Settings toggle persistence by wiring both bot controls to the active `sad_bot_verification` option.
* Registered the existing bot settings and bot statistics AJAX endpoints.
* Hardened bot statistics against malformed stored log entries and simplified duplicate firewall verification logic.

= 1.0.52 =
* Fixed the registration protection pipeline by attaching honeypot, timer, and rate-limit validation to WordPress's actual `registration_errors` filter.
* Replaced request-ending `wp_die()` calls with registration errors so users receive normal validation feedback and other registration hooks can complete safely.
* Added focused tests for honeypot and submission-timing failures.

= 1.0.51 =
* Moved CPU settings into the main dashboard as a full-width CPU Guard card.
* Added an on/off switch for the Security Activity Feed.
* Removed the separate CPU Settings admin submenu.

= 1.0.50 =
* Removed the global admin update notice.
* Kept version bookkeeping active without showing update marketing copy across wp-admin.

= 1.0.49 =
* Reworked Security Tools into full-width rows with consistent spacing.
* Improved detection for unusual consonant-pair username patterns.

= 1.0.48 =
* Improved detection of consonant-heavy, machine-generated usernames.
* Replaced duplicated account metrics with unique trust-signal metrics in the dashboard.

= 1.0.47 =
* Updated the dashboard to a white minimalist interface inspired by the supplied references.
* Bumped the plugin and asset cache version to 1.0.47.

= 1.0.46 =
* Fixed manual cleanup so it no longer obeys the automatic-cleanup toggle or scheduled retention window.
* Added explicit cleanup results and refreshed dashboard statistics after deletion.
* Rebuilt the dashboard as a command center with a security hero, dark overview band, metric tiles, live protection cards, and responsive tool grid.

= 1.0.45 =
* Added a shared visual progress rail and recoverable busy states to dashboard actions.
* Added success and error completion states for settings, scans, cleanup, logs, exports, toggles, and whitelist controls.
* Refined the dashboard with a clean Apple-inspired surface, spacing, typography, shadows, and responsive behavior.

= 1.0.44 =
* Fixed `SAD_PLUGIN_URL` to include the required trailing slash so admin JavaScript and CSS load from valid URLs.
* Restored the dashboard's jQuery, AJAX, toggles, Save Settings, Scan, Cleanup, logs, and whitelist interactions.

= 1.0.43 =
* Fixed the admin asset enqueue hook so the dashboard JavaScript and styles load on the actual `sad-dashboard` menu page.
* Restored working toggles, Save Settings, Scan, Cleanup, log, and whitelist controls.

= 1.0.42 =
* Synchronized the stable tag with the plugin runtime version.
* Removed staging credential files from the distributable plugin package.
* Added release-integrity verification to the end-to-end website audit.

= 1.0.41 =
* Connected the inner Scan, Cleanup, and Save Settings controls that previously had no JavaScript handlers.
* Persisted spam detection factor checkboxes and cleanup frequency settings.

= 1.0.40 =
* Fixed the undefined JavaScript `toolId` error that prevented settings toggles and related controls from working.

= 1.0.39 =
* Corrected existing-account scoring so machine-generated usernames combined with empty author accounts reach the medium detection threshold.

= 1.0.38 =
* Expanded existing-account scans to detect machine-generated usernames, suspicious email structures, empty inactive author accounts, and shared registration IPs.
* Added detection logging for accounts identified during scheduled or manual scans.

= 1.0.37 =
* Fixed the manual Scan Now AJAX path so detector patterns and learned weights initialize before scanning.
* Added visible server and network error feedback and reliable button recovery after failed scan requests.
* Decoupled on-demand scans from the scheduled-scan enable/disable setting.

= 1.0.36 =
* Fixed admin AJAX registration, settings persistence, log actions, and IP removal endpoints.
* Fixed dashboard selector/nonce mismatches, duplicate handlers, empty-log export, and bot-log clearing.
* Fixed role-conversion UI status reporting and settings validation.

= 1.0.35 =
* Hardened role conversion with feature gating, valid-role checks, bounded batches, and persisted CPU pause state.

= 1.0.34 =
* Connected scheduled spam-account cleanup, supported legacy marking metadata, protected cleanup settings, and returned cleanup results.

= 1.0.33 =
* Connected and cleaned up scheduled maintenance hooks, normalized CPU utilization, validated ML training data, and rate-limited CPU alerts.

= 1.0.32 =
* Hardened firewall client-IP handling, bot hostname boundaries, configurable limits, block expiry, and malformed option handling.

= 1.0.31 =
* Unified bot access logging and hardened firewall bot forward-DNS verification.

= 1.0.30 =
* Honored registration protection and scheduled-scan settings, validated registration records, aligned scoring, and added spam detection logs.

= 1.0.29 =
* Hardened claimed-search-bot verification with forward and reverse DNS checks.
* Enforced the bot-verification setting before performing DNS lookups.
* Added hostname boundary checks to prevent look-alike domains from passing suffix validation.

= 1.0.28 =
* Fixed registration scoring so valid email addresses are not incorrectly scored as invalid.
* Restored validated learned spam-pattern weights on each request.
* Fixed verification statistics/metadata consistency and added a working, expiring verification URL handler.
* Preserved non-browser registrations by enforcing the timer only when the native form supplies it.
* Hardened registration records and IP handling against malformed data and spoofed forwarding headers.
* Applied configured detection switches and threshold levels to scheduled scans.

= 1.0.27 =
* Major layout improvements to the dashboard interface:
  - Redesigned status cards for better visibility and alignment
  - Enhanced responsive design for all screen sizes
  - Improved card layouts and spacing
* Significant architectural improvements:
  - Enhanced version detection and upgrade handling
  - Improved file structure and path handling
  - Better compatibility with different WordPress configurations
* Fixed various UI and functionality issues:
  - Corrected status cards alignment and responsiveness
  - Improved plugin version detection
  - Enhanced file path handling for better reliability

= 1.0.26 =
* Consolidated Registration Monitoring and Protection features into a single unified interface
* Enhanced registration validation options with combined feature set
* Updated dashboard layout for better clarity and usability

= 1.0.25 =
* Reorganized dashboard layout with clear sections:
  - First row: Three main status cards (Security Monitoring, Account Status, Spam Scan)
  - Second row: Security Tools optimized for single-row display
  - Third row: Logs & Activity section
  - Fourth row: Customer IP Whitelist
* Improved responsive design for better mobile experience
* Enhanced visual hierarchy for better usability

= 1.0.24 =
* UI: Enhanced tooltips with improved accessibility
* UI: Added subtle card hover effects for better visual feedback
* UI: Improved tooltip contrast and visibility
* A11y: Added ARIA attributes for better screen reader support
* A11y: Enhanced keyboard navigation for tooltips
* Technical: Optimized tooltip animations
* Technical: Added high contrast support for forced colors mode

= 1.0.22 =
* Enhanced firewall protection with improved spam domain detection
* Added machine learning capabilities for pattern detection
* Improved admin interface with better UX
* Performance optimizations for faster processing
* Added more detailed logging capabilities

= 1.0.21 =
* Fixed compatibility issue with WooCommerce registrations
* Improved detection of automated bot registrations
* Added support for WordPress 6.4

= 1.0.20 =
* Initial public release

== Upgrade Notice ==

= 1.0.36 =
All protection pipelines and the administration UI were audited end-to-end and hardened.

= 1.0.27 =
This update includes major improvements to the dashboard interface and plugin architecture, with enhanced version detection and better compatibility. The update also fixes various UI issues and improves overall reliability.
= 1.0.26 =
This update combines Registration Monitoring and Protection features into a single, more powerful interface while maintaining all existing functionality.

== Current Active Pipeline Status ==

1.0.61 — Production and WordPress.org submission audit complete; privacy lifecycle, uninstall cleanup, all seven pipelines, secure logging, and the clean submission package are active.

== Privacy ==

Spam Account Defender stores security data required to detect and investigate abusive registrations. Depending on enabled features, this may include registration IP addresses, usernames, email addresses, bot user agents, verification status, spam scores, detection reasons, and security event timestamps.

Data is stored in the site's WordPress database and is only used by the site's administrators for security operations. Registration records, local detection logs, rate-limit records, and safelist entries remain until an administrator removes them or uninstalls the plugin. WordPress personal-data export and erasure tools include user-linked data maintained by this plugin. Site owners should document their retention period and privacy contact in their own privacy policy.

== External Services ==
The Standard edition does not send registration, account, or security data to an external API. It performs local checks and stores its security records in the site's own WordPress database.

This plugin does not send data to a third-party API. Search-engine bot verification may perform reverse and forward DNS lookups through the site's hosting environment to confirm that a crawler's network address matches its claimed domain.
