=== Silverback Login ===
Contributors:      whebbworks
Author:            Whebb Works
Author URI:        https://whebb.works
Plugin URI:        https://silverbacklogin.com
Tags:              login, security, 2fa, hide login, password, two factor, hibp
Requires at least: 6.0
Tested up to:      6.5
Requires PHP:      7.4
Stable tag:        0.2.1
License:           GPLv2 or later
License URI:       https://www.gnu.org/licenses/gpl-2.0.html

A focused login security suite for WordPress — hide the login URL, require email 2FA, and own the full password lifecycle.

== Description ==

Silverback Login is a login security suite. It locks down the front door of your site:

* **Hide login URL** — replace `wp-login.php` and `/wp-admin/` with a custom slug. Anonymous visitors hitting the default URLs get a 404 (or a configurable redirect).
* **Email two-step verification** — after a correct password, send a 6-digit code to the user's email. Trusted devices stay trusted for 30 days.
* **Force-all password reset** — one-click button for emergencies: every user (including you) gets sent to the profile screen on their next admin page load and held there until they pick a new password. Optional checkbox also ends every active session for breach response.
* **Breached-password screening (HIBP)** — every new password is checked against the Have I Been Pwned k-anonymity range API. Only the first 5 hash characters ever leave your server. Fails open if HIBP is unreachable.
* **Last-5 password reuse prevention** — the user's last five password hashes are kept and checked on every change. Always on.
* **Forced password rotation** — optional. Choose 3, 6, 9, or 12 months. When a user's password expires they're sent to the profile screen and held there until they pick a new one.
* **Inactive-account lock** — optional. A daily background job locks accounts that haven't logged in within the configured window. Administrators are never auto-locked. A batch summary email goes to every admin when accounts are locked.
* **Slug-change email** — when an admin regenerates or edits the login URL, every administrator gets an email with the new URL so the URL has a permanent inbox record.
* **Two-screen settings** — Login and Policy. Most modules are correct by default and intentionally have no toggle.

The full roadmap also includes a session & login-history panel on each profile, per-role login URLs, scheduled URL rotation, risk-based 2FA prompting, and TOTP opt-up.

== Installation ==

1. Upload the `silverback-login` folder to `/wp-content/plugins/`.
2. Activate **Silverback Login** from the Plugins screen.
3. Note the random login URL shown in the activation notice and the email sent to every administrator. `wp-login.php` and `/wp-admin/` are now blocked for anonymous visitors.
4. Visit Settings → Silverback to change the slug, enable email 2FA, or set a rotation policy.

**Emergency disable.** Two filesystem-level escape hatches, both via `wp-config.php`:

`define( 'SILVERBACK_DISABLE_HIDE_LOGIN', true );` — restore default `wp-login.php` and `/wp-admin/` access immediately. Use this if you lose the custom URL.

`define( 'SILVERBACK_DISABLE_2FA', true );` — disable email 2FA. Use this if SMTP is broken and you can't receive the verification code.

Or temporarily rename / deactivate the plugin via FTP to restore everything to vanilla WordPress.

== Frequently Asked Questions ==

= Will activating this plugin lock me out? =

No. On activation the plugin generates a random login slug, shows it to you in an admin notice, and emails it to every administrator. Email 2FA is **off by default** — you turn it on once you've confirmed outgoing mail works on your site. Rotation and inactive-lock are also off by default.

= Does this rewrite core files? =

No. It intercepts requests via WordPress hooks. Deactivation cleanly restores the default login URL and stops the inactive-account cron job.

= How does the breach check work? =

The Have I Been Pwned password API uses k-anonymity: you SHA-1 the password locally, send only the first 5 characters, and HIBP returns a list of hash suffixes to check against. The full password — and even its full hash — never leaves your server.

= What if HIBP is down? =

The check fails open: the password is allowed through. We'd rather let one weak password slip than block legitimate password resets when an external API is down. Reuse prevention is local so it always runs regardless.

= I forgot my login URL. How do I find it? =

Try these in order:

1. **Email.** The URL is mailed to every administrator on activation and on every change. Search your inbox for "Login URL has changed" or "Silverback Login activated".
2. **Hosting panel.** Plesk's WordPress Toolkit, WP Engine, Kinsta, Cloudways, SpinupWP, and most managed hosts have a one-click "Log in to WordPress" feature that bypasses the URL entirely (it uses filesystem-level auth tokens).
3. **WP-CLI.** If you have SSH access: `wp option get silverback_options --format=json` and look for the `login_slug` field.
4. **Database.** Open `phpMyAdmin` (or equivalent), find `wp_options`, search for `silverback_options`, the value is a serialized array containing `login_slug`.
5. **Emergency disable.** Add `define( 'SILVERBACK_DISABLE_HIDE_LOGIN', true );` to `wp-config.php`. The default `/wp-login.php` will work again. Log in, copy the slug from Settings → Silverback, save it somewhere safe, remove the line.

= What if I get locked out entirely (e.g. SMTP is broken and 2FA is on)? =

Same recovery toolbox, plus the 2FA escape hatch: `define( 'SILVERBACK_DISABLE_2FA', true );` in wp-config.php. You can combine both constants if needed. Remove them once you're back in. As a last resort, rename the `silverback-login/` folder in `/wp-content/plugins/` to disable the plugin entirely — your settings persist for when you re-enable it.

= What happens when I delete the plugin? =

`uninstall.php` wipes every piece of plugin state: the settings option, the force-reset timestamp, every `_silverback_*` user meta row (password history, last-login timestamps, trusted devices, locked flags), in-flight 2FA challenge transients, and the inactive-scan cron. Standard practice for a security plugin — leaving cryptographic material in the database after the plugin is gone is data you no longer have tooling to manage.

== Changelog ==

= 0.2.1 =
* Fix: admin sidebar menu label under Settings now reads "Silverback Login" to match the page title. Was left as just "Silverback" during the 0.2.0 rename.

= 0.2.0 =
* Rename: project renamed from "Silverback Security" to **Silverback Login** to disambiguate from existing "Silverback Security" companies (physical security firms and pentesting consulting). Folder is now `silverback-login/`, text domain `silverback-login`, settings URL `options-general.php?page=silverback-login`, plugin URI `silverbacklogin.com`, PHPDoc package `Silverback_Login`. Internal class names, option keys, user meta keys, the cron hook, the trusted-device cookie name, and the 2FA transient prefix all keep their `silverback_*` / `Silverback_*` identifiers — settings, password history, trusted devices, and the inactive-scan schedule carry over IF you upgrade via FTP (replace the folder; do NOT click Plugins → Delete on the old `silverback-security/` folder, as that fires uninstall.php and wipes the database).

= 0.1.10 =
* New: `uninstall.php`. When the plugin is deleted (not just deactivated), every piece of plugin state is wiped: settings, force-reset timestamp, activation-slug transient, in-flight 2FA challenge transients, every `_silverback_*` user meta row, and the inactive-scan cron event. Security-tool norm: don't leave hashed passwords or device tokens lingering after the user has said "remove this plugin."
* New: when the inactive-account cron locks one or more users, every administrator now receives a single batch summary email listing the usernames and emails affected, with WP-CLI unlock instructions.
* Fix: `scan_inactive_accounts()` now excludes admins at the query level via `role__not_in` rather than checking `$user->roles` (which isn't populated when get_users is called with an array `fields` parameter).

= 0.1.9 =
* New: the login URL is now emailed to every administrator on activation and on every slug change. The email becomes a permanent inbox record — closes the "I forgot to write down the activation notice" recovery gap.
* New: `SILVERBACK_DISABLE_HIDE_LOGIN` constant. Define it as `true` in `wp-config.php` and hide-login disengages immediately.
* Docs: two new FAQ entries — "I forgot my login URL" and "What if I get locked out entirely" — walking through the full recovery toolbox.

= 0.1.8 =
* Change: the "Force all users to change password" button no longer auto-exempts the admin who clicked it. The clicking admin walks the same gate as everyone else.
* New: optional "Also immediately end every active session" checkbox next to the force-reset button. When ticked, every existing session across every user is destroyed (the clicking admin's current session preserved). Use for breach response.

= 0.1.7 =
* Rename: plugin renamed from "WP Silverback" to "Silverback Security". (This name was subsequently changed again in 0.2.0 — see above.)
* New: "Force all users to change password on next login" button under Two-Step Email Verification. Backed by a single global timestamp — scales to any user count.
* New: when an admin regenerates the slug and saves, every other administrator gets an email with the new URL.
* Change: slug wordlist filtered to 4+ letter words only. ~120 words, ~14,400 combinations.

= 0.1.6 =
* Fix: saving one settings tab no longer wipes the other tab's values. Hidden tab marker so the sanitizer only updates fields owned by the active tab.

= 0.1.5 =
* New: two-word random slug generator (`cedar-river`, `harbor-moss`) from a curated wordlist of neutral English nouns. The plugin name no longer appears anywhere in the URL.
* New: a Regenerate button next to the slug field on the settings page.

= 0.1.4 =
* Change: blocked requests to `/wp-login.php` and `/wp-admin/` both now show the same WordPress-default-styled 404 page.

= 0.1.3 =
* Change: removed the "Hide login URL" checkbox. The slug field is the single source of truth — empty = off.
* Fix: clean stand-alone 404 page for admin-area blocked requests.

= 0.1.2 =
* Fix: pre-initialize `$user_login` and `$error` before requiring `wp-login.php` so PHP 8 "Undefined variable" warnings don't leak into the form.

= 0.1.1 =
* Fix: PHP 8 fatal "Undefined constant AUTOSAVE_INTERVAL" when hitting the custom login URL. wp-login.php is now loaded on `wp_loaded`.
* New: admin notice when Permalinks are set to "Plain".

= 0.1.0 =
* Initial release.
* Hide login URL with configurable slug and redirect behaviour.
* Email two-step verification with trusted-device cookie.
* HIBP breached-password screening.
* Last-5 password reuse prevention.
* Optional forced password rotation (3 / 6 / 9 / 12 months).
* Optional inactive-account lock with daily cron scanner.
