=== ThreatHive.net Firewall ===
Contributors: threathive
Tags: firewall, security, blocklist, ip blocking, threat intelligence
Requires at least: 5.8
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.0.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Blocks visitors whose IP address is on the free ThreatHive.net threat-intelligence blocklist. Fast, no database queries per request.

== Description ==

ThreatHive.net Firewall blocks requests from IP addresses on the ThreatHive.net blocklist, which is built from open-source threat feeds and honeypots.

* Downloads the blocklist on a schedule you choose (every 15 minutes to daily).
* Compiles the list (about 200,000 addresses) into a sorted binary file. Each request is checked with a binary search of about 10 microseconds, with no database queries and without loading the list into memory.
* Blocked visitors get a small HTTP 403 page.
* Status page: list size, last update, blocked requests and unique IPs (today, 7 days, 30 days, all time), daily, weekly and monthly charts, top blocked IPs, and an IP checker.
* Dashboard widget with protection status and the top 20 blocked IPs.
* Monitor mode records listed IPs without blocking them.
* Allowlist for IPs and CIDR ranges that must never be blocked.
* Detects Cloudflare, Cloudflare Tunnel and reverse proxies. Forwarded headers are trusted only from Cloudflare's published ranges, the server itself (optional, on by default) or proxies you list, so they cannot be spoofed from untrusted peers. A trusted proxy must set or append the forwarded header itself; the plugin tests this when you trust a proxy and refuses one that passes client headers through. An untrusted proxy is flagged on the status page with a one-click "Trust" button.
* Single-site, or network-activated on multisite (one configuration for the whole network, managed in Network Admin).

All features are free. There are no paid tiers, accounts or API keys.

= Performance =

* The IP check runs before the rest of the plugin loads, and the plugin loads first among plugins.
* Optionally, the check can be included from wp-config.php so it blocks before page-cache drop-ins. The status page shows the exact line for your site.
* Updates use conditional requests (ETag / If-Modified-Since) and SHA-256 change detection, so an unchanged list costs a few bytes and no rebuild.

= Security =

* The blocklist is fetched over HTTPS only, with TLS verification, a 32 MB size cap, a fixed URL and no redirects. The download itself is not signed; optional Ed25519 signature checking is built in for when the feed publishes signatures.
* Sanity limits against a broken or tampered feed: private and reserved addresses, and single entries broader than /16 (IPv4) or /48 (IPv6), are ignored; a list covering more than 2% of all IPv4 addresses or with more than 3 million entries is always rejected; a list that shrinks by more than 80% or grows to more than 10 times its previous coverage is held back until an administrator accepts it. In every rejected case the previous list stays active.
* The blocklist is data only; no code is ever downloaded or executed, and the gate's own configuration is stored as JSON and never executed.
* If the list is missing the plugin blocks nothing, so a failed update cannot take your site offline.
* Logging of blocked requests is capped per day, so a flood cannot fill the disk, and statistics use bounded memory.
* On nginx (which ignores .htaccess) the plugin checks daily whether its data directory is reachable from the web and shows the exact nginx rule to add if it is.

== External services ==

This plugin connects to the following external services. It does not send any information about your visitors to them.

= ThreatHive.net blocklist =

The blocklist this plugin enforces. It is required for the plugin to work.

* What is requested: a plain-text file of IP addresses from https://threathive.net/hiveblocklist.txt.
* When: once shortly after activation, then at the interval chosen in the settings (default every 15 minutes), and when an administrator clicks "Update now".
* What is sent: a standard HTTPS GET request. The service necessarily sees your server's IP address. The request includes the User-Agent "ThreatHive.net-Firewall/VERSION (WordPress)" and, when available, the ETag / Last-Modified values of the previous download, so unchanged lists are not transferred again. Your site URL, visitor IP addresses and statistics are not sent.
* Service provider: ThreatHive.net, https://threathive.net/

= Cloudflare IP ranges =

Used to recognise requests that reach your site through Cloudflare, so the real visitor IP can be read safely from the CF-Connecting-IP header.

* What is requested: the public lists https://www.cloudflare.com/ips-v4 and https://www.cloudflare.com/ips-v6.
* When: at most once a week, and only while "Client IP source" is set to "Automatic" or "CF-Connecting-IP". A bundled copy of the ranges is used until the first refresh, or if it fails.
* What is sent: a standard HTTPS GET request with the User-Agent above. No site or visitor data is sent.
* Service provider: Cloudflare, Inc. [Terms of use](https://www.cloudflare.com/website-terms/), [Privacy policy](https://www.cloudflare.com/privacypolicy/)

== Privacy ==

When a request from a listed IP address is blocked (or recorded in monitor mode), the IP address and date are stored on your own server, in wp-content/threathive-firewall, to produce the statistics. These IP-level records are deleted automatically after the retention period you choose (1–90 days, default 30). Daily totals without IP addresses are kept for up to about 13 months for the trend charts. Nothing is sent to ThreatHive.net or anyone else.

Suggested text for your privacy policy is available under Settings → Privacy → Policy Guide.

The block page does not link to any external site unless you enable the "Block page link" setting (off by default).

== Installation ==

1. Upload the plugin from Plugins → Add New → Upload Plugin, or install it from the plugin directory, then activate it. On multisite, network-activate it from Network Admin → Plugins.
2. Open "ThreatHive Firewall" in the admin menu. The first download starts within seconds.
3. Check "Your IP" on the status page. If your own IP is listed, add it to the allowlist.
4. If your site is behind a reverse proxy or load balancer other than Cloudflare, add its IP addresses to "Trusted proxies". Cloudflare is detected automatically.

== Frequently Asked Questions ==

= Will this slow down my site? =

No. Each request does a binary search of a small file (about 18 reads of 8 bytes) and no database queries. The blocklist is never loaded into memory on normal requests.

= What happens if threathive.net is unreachable? =

The plugin keeps using the last downloaded list and shows the error on the status page.

= I locked myself out. How do I turn the firewall off? =

Add `define( 'THFW_DISABLE', true );` to wp-config.php, or rename the plugin folder over FTP or SFTP. Then add your IP to the allowlist.

= My IP is listed but should not be. =

Contact ThreatHive.net through https://threathive.net/ to request delisting. Meanwhile, add the IP to the allowlist.

= How do I enable early loading from wp-config.php? =

Copy the lines shown under "Early loading" on the plugin's status page (they also pin the data directory). In wp-config.php, paste them between these two lines:

`/* Add any custom values between this line and the "stop editing" line. */`

`/* That's all, stop editing! Happy publishing. */`

If your server uses PHP OPcache, restart PHP (PHP-FPM or the web server) afterwards so the edited wp-config.php is loaded. Then reload the status page; it should show "Active via wp-config.php".

= Does the plugin use WP-Cron? =

Yes. WP-Cron runs when your site receives traffic. For exact timing on low-traffic sites, call wp-cron.php from a real system cron job.

== Changelog ==

= 1.0.1 =
* Security: the gate configuration is now JSON read as data (runtime.json.php); the old executable runtime.php is removed on upgrade.
* Security: the wp-config.php line now pins the data directory, and the plugin re-checks requests itself if an early run used a different directory, so protection cannot silently fail open.
* Security: feed downloads no longer follow redirects; total-coverage cap (2% of IPv4), growth check (10x) and 3 million entry cap; optional Ed25519 feed signatures.
* Security: proxies are tested before they are trusted (a proxy that passes client X-Forwarded-For through is refused), "Re-test proxy" button, and trusting the server's own address is now a setting.
* Security: stricter .htaccess guard for data files, and a daily nginx exposure check with the rule to add.
* Robustness: statistics use bounded, streamed reads and heavy aggregation runs in the hourly cron; updater lock can no longer get stuck after a fatal error.
* IPv4-mapped IPv6 addresses (::ffff:a.b.c.d) in the allowlist and proxy list now match.
* Multisite: network activation required; one network-wide configuration in Network Admin.

= 1.0.0 =
* Initial release.
