=== SSF Login Guard – Login Protection & Recovery ===
Contributors: ssfllc
Tags: login security, two factor authentication, limit login attempts, woocommerce, recovery
Requires at least: 6.6
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 1.0.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Local login rate limits, observation mode, authenticator codes and documented recovery for WordPress and WooCommerce.

== Description ==

SSF Login Guard helps site owners introduce login protection carefully. Start in observation mode, review the detected connection and recovery instructions, then enable temporary restrictions after testing.

* Local rate limits per address and per account/address combination.
* Temporary escalating restrictions, without a global username-only password lockout.
* Observation mode and explicit trusted-proxy configuration.
* Authenticator-app TOTP and eight one-use recovery codes.
* WordPress login and WooCommerce login code fields.
* Password reset remains available while an address is restricted.
* Pseudonymized local events, retention cleanup and optional grouped email summaries.
* Authenticated administrator unlock and hosting-authorized WP-CLI recovery.

No SSF account is needed. No telemetry or external security service is enabled by this plugin. PHP Sodium is required for authenticator enrollment; rate limiting does not require Sodium. Use HTTPS on production websites and keep hosting time synchronized.

The separate paid SSF Login Guard Pro addon provides staff policies, staff enrollment reporting, saved configuration comparisons, assisted recovery and daily reports. It is not included in this package. Free protection has no trial expiry. Learn about the separate addon at https://ssfllc.com/ssf-login-guard/ .

== Installation ==

1. Upload the ssf-login-guard folder or install the ZIP through Plugins.
2. Activate and open Login Guard. Observation mode is the default.
3. Confirm the detected IP address and leave trusted proxies empty unless your host requires them.
4. Read recovery instructions, retain hosting access and keep your current administrator session open.
5. Test a separate administrator/customer login before enabling enforcement.
6. Optional: use the account security link in your WordPress profile or WooCommerce account dashboard to enroll an authenticator. Save the one-use recovery codes offline.

== Frequently Asked Questions ==

= Is this a complete firewall or a guarantee against compromise? =
No. It protects supported WordPress password authentication flows. It is not a web application firewall, malware scanner, backup service, passkey provider or protection against stolen active sessions. Keep WordPress and other plugins updated.

= Does observation mode disable two-factor authentication? =
No. Observation mode affects rate restrictions only. Once an account enrolls an authenticator, its code remains required.

= Can I recover from a lockout? =
Wait for the temporary restriction or use an authorized administrator's Clear temporary rate restrictions action. With hosting access run `wp ssf-login-guard unlock --yes`. For lost MFA, use one unused recovery code, or authorized hosting access to run `wp ssf-login-guard recover USER --yes`. This revokes sessions and resets MFA but never bypasses the WordPress password. As an emergency hosting-only option, temporarily set `define( 'SSFLG_RECOVERY_MODE', true );` in wp-config.php, sign in with the existing password, repair settings, then remove the constant immediately.

When the hosting recovery constant is active, open your account security page, enter your existing WordPress password and choose Disable my authenticator. This self-account repair does not require the lost code, but still requires a valid session, nonce and password. Other sessions are revoked and a one-hour Pro enrollment window is opened. Enroll again and remove the constant immediately; leaving it active weakens the site's login protection.

= What happens under counter-storage pressure? =
The detailed anonymous counter pool has a 20,000-row admission ceiling. At capacity, existing reached thresholds remain restricted even if another lock row cannot be allocated. New sources use a reserved pool of at most 65,536 keyed address slots, each expiring after 60 seconds, with a limit of the lower of 50 or your configured address threshold. Rare address-hash collisions share a short fallback limit. This bounds storage without globally locking all customers or silently allowing unlimited guesses. It is a pressure fallback, not a denial-of-service firewall. The dashboard shows a warning; use hosting/network protections for sustained distributed traffic. Actual storage errors cause a temporary error restriction where the database can retain it; repair database faults through hosting.

= Is WordPress multisite supported? =
No. Version 1.x supports single-site WordPress only and refuses multisite activation and protection hooks. It does not claim network-wide MFA isolation. Do not convert an enrolled installation to multisite without first planning account recovery and removing this plugin.

= What happens when WordPress security salts change? =
Authenticator secrets are encrypted using keys derived from WordPress salts. Changing these salts can make existing secrets unreadable. Preserve a secure backup and use hosting-authorized recovery to reenroll if needed. Recovery codes also depend on the site salts.

= What data is stored? =
Local rate counters and security events use keyed hashes of addresses and account identifiers. These are pseudonymous, not anonymous. No passwords or raw recovery codes are logged. Encrypted authenticator secrets and keyed one-use recovery code hashes are stored locally. Events are grouped by minute, retained for the configured period and pruned to a maximum history during hourly maintenance. Email summaries are opt-in and sent through the site's normal mail system to its administration email.

Administrative events also retain numeric actor IDs; assisted recovery can record the target user ID. These are attributable audit records, visible to authorized administrators, and are subject to the same retention. Recovery-code replacement retains the previous set unless all eight replacements are saved successfully.

= What about application passwords and XML-RPC? =
WordPress application passwords retain their core API-only authentication behavior. Treat them as sensitive API credentials and revoke unused ones. Interactive MFA applies to normal password login. Password-based XML-RPC cannot provide the code field; enrolled accounts should use core application passwords for supported API clients. This plugin is not an API-scope management product.

= Does it support every membership or custom login plugin? =
No such claim is made. Custom authentication must use WordPress's normal authentication hooks and render the extra code field. Test on staging. SSO, passkeys, custom REST login routes and direct auth-cookie creation by other plugins need a separate integration review.

= Do email summaries always arrive? =
Delivery depends on working WordPress mail and scheduling. A low-traffic site may run scheduled cleanup and summaries later than their nominal time. No paid external service is required.

= What happens on deactivation or removal? =
Deactivation stops this plugin's protection and scheduled cleanup but preserves its settings and local data. Deletion removes this plugin's own local tables, settings and MFA metadata. Retain a backup before removal. Pro is a separate addon.

== Changelog ==

= 1.0.0 =
Initial release: observation-first local login protection, authenticator enrollment, recovery and grouped security events.

== Upgrade Notice ==

= 1.0.0 =
Start in observation mode and verify hosting recovery before enforcing restrictions.
