Compare commits

...
117 Commits
Author SHA1 Message Date
tech a8cdbef65a Update signed manifest to 7.52.0 2026-09-23 09:51:35 +00:00
tech 806094d6a0 Update signed manifest to 7.51.0 2026-09-19 16:44:44 +00:00
tech 0faf78287a Update signed manifest to 7.49.0 2026-09-19 10:22:45 +00:00
tech 235169e8ac Update signed manifest to 7.46.0 2026-09-17 23:20:51 +00:00
tech 67323f0204 Update signed manifest to 7.45.5 2026-09-17 22:40:55 +00:00
tech f3a00c618b Update signed manifest to 7.45.4 2026-09-17 22:28:23 +00:00
tech d39aa6f9bc Update signed manifest to 7.45.1 2026-09-17 18:11:59 +00:00
tech efb0dfc838 Update signed manifest to 7.45.0 2026-09-17 17:48:05 +00:00
tech 7fa580d4d6 Update signed manifest to 7.44.0 2026-09-17 16:36:26 +00:00
tech bd3275d252 Update signed manifest to 7.43.0 2026-09-17 12:33:03 +00:00
tech a0f46c0678 Update signed manifest to 7.42.0 2026-09-17 12:12:42 +00:00
tech 82dd287445 Update signed manifest to 7.41.0 2026-09-17 11:36:04 +00:00
tech f48da5e5f1 Update signed manifest to 7.40.0 2026-09-17 10:42:49 +00:00
tech f787d3a070 Update signed manifest to 7.39.9 2026-09-16 22:55:42 +00:00
tech e924c0adf1 Update signed manifest to 7.39.8 2026-09-16 22:24:00 +00:00
tech 343642a869 Update signed manifest to 7.39.7 2026-09-16 21:32:34 +00:00
tech 2cc4a318ad Update signed manifest to 7.39.6 2026-09-16 21:29:47 +00:00
tech e016046e1f Update signed manifest to 7.39.4 2026-09-16 20:32:22 +00:00
tech 0f197d4bfd Update signed manifest to 7.39.3 2026-09-16 18:30:54 +00:00
tech 49610d6da0 Update signed manifest to 7.39.2 2026-09-16 18:06:20 +00:00
tech 39463e255c Update signed manifest to 7.39.1 2026-09-16 13:42:30 +00:00
tech ecfe29e693 Update signed manifest to 7.39.0 2026-09-16 08:17:24 +00:00
tech 488b27ffc4 Update signed manifest to 7.38.0 2026-09-15 16:58:37 +00:00
tech 19246c3f5a Update signed manifest to 7.37.1 2026-09-15 16:45:42 +00:00
tech fddf34cd50 Update signed manifest to 7.37.0 2026-09-15 13:21:26 +00:00
tech db1f6d1fd6 Update signed manifest to 7.36.0 2026-09-15 11:03:26 +00:00
tech 5f928ba8d1 Update signed manifest to 7.35.0 2026-09-15 10:48:24 +00:00
tech 6a7b33b145 Update signed manifest to 7.34.0 2026-09-15 09:39:49 +00:00
tech 19ca566549 Update signed manifest to 7.33.0 2026-09-15 09:00:19 +00:00
tech bffd79abdb Update signed manifest to 7.32.0 2026-09-15 07:59:24 +00:00
tech c6faa3e74e Update signed manifest to 7.31.0 2026-09-15 00:51:19 +00:00
tech 022d999dc3 Update signed manifest to 7.30.0 2026-09-14 20:03:16 +00:00
tech 23e68f7385 Update signed manifest to 7.29.4 2026-09-14 14:57:40 +00:00
tech 51dcf25e5a Update signed manifest to 7.29.2 2026-09-14 09:33:46 +00:00
tech 50b657b23b Update signed manifest to 7.29.1 2026-09-14 09:20:05 +00:00
tech b7646b720a Update signed manifest to 7.29.0 2026-09-10 15:52:11 +00:00
tech 499a74da7b Update signed manifest to 7.28.6 2026-09-10 15:41:14 +00:00
tech 5028dfabd5 Update signed manifest to 7.28.5 2026-09-02 16:09:40 +00:00
tech daaff5e873 Update signed manifest to 7.28.4 2026-09-02 15:15:17 +00:00
tech 07c8997e1f Update signed manifest to 7.28.3 2026-08-26 09:17:13 +00:00
tech 2bf328fa3d Update signed manifest to 7.28.2 2026-08-16 07:50:50 +00:00
tech 5462c91106 Update signed manifest to 7.28.1 2026-08-16 07:25:22 +00:00
tech bb36fe77e0 Update signed manifest to 7.28.0 2026-08-15 21:32:33 +00:00
tech 1e1dfae997 Update signed manifest to 7.27.3 2026-08-14 18:07:43 +00:00
tech 5a1901fd3e Update signed manifest to 7.27.2 2026-08-14 17:28:45 +00:00
tech 10e92f4bd3 Update signed manifest to 7.27.1 2026-08-14 14:43:12 +00:00
tech 96aa3b20ea Update signed manifest to 7.27.0 2026-08-14 14:30:38 +00:00
tech e6f74fe0c3 Update signed manifest to 7.26.0 2026-08-14 13:59:45 +00:00
tech cd12b06c7a Update signed manifest to 7.25.7 2026-08-14 13:37:04 +00:00
tech d324d5a7a6 Update signed manifest to 7.25.6 2026-08-14 13:28:28 +00:00
tech b5e86863ba Update signed manifest to 7.25.5 2026-08-14 13:14:46 +00:00
tech cfe2cd5369 Update signed manifest to 7.25.4 2026-08-14 13:05:23 +00:00
tech c8e65d8b79 Update signed manifest to 7.25.3 2026-08-14 12:51:13 +00:00
tech 1f306340d8 Update signed manifest to 7.25.2 2026-08-14 12:26:58 +00:00
tech db095bc4a0 Update signed manifest to 7.25.1 2026-08-14 12:17:37 +00:00
tech 6031ba5163 Update signed manifest to 7.25.0 2026-08-14 10:32:57 +00:00
tech 7f7c8de38c Update signed manifest to 7.24.9 2026-08-14 10:15:10 +00:00
tech 769f532207 Update signed manifest to 7.24.8 2026-08-14 09:59:07 +00:00
tech cce638adb3 Update signed manifest to 7.24.6 2026-08-14 09:46:33 +00:00
tech 446bd5deb9 Update signed manifest to 7.24.5 2026-08-14 09:44:00 +00:00
tech b70f9b0675 Update signed manifest to 7.24.4 2026-08-14 09:17:23 +00:00
tech 3b5b86162b Update signed manifest to 7.24.3 2026-08-14 08:56:24 +00:00
tech 49b9d8fca5 Update signed manifest to 7.24.2 2026-08-14 08:06:56 +00:00
tech 1187ac412c Update signed manifest to 7.23.55 2026-08-13 19:15:45 +00:00
tech c56b4e6e9d Update signed manifest to 7.23.54 2026-08-13 12:58:44 +00:00
tech 6676ceb60e Update signed manifest to 7.23.53 2026-08-13 12:16:31 +00:00
tech fdc592d01f Update signed manifest to 7.23.52 2026-08-13 11:34:47 +00:00
tech 6e80e24159 Update signed manifest to 7.23.51 2026-08-13 11:09:50 +00:00
tech facfffbc1d Update signed manifest to 7.23.50 2026-08-13 11:00:49 +00:00
tech d33ab11b77 Update signed manifest to 7.23.49 2026-08-13 10:53:46 +00:00
tech 1bb03b6c5c Update signed manifest to 7.23.48 2026-08-13 10:52:36 +00:00
tech 729c24a83c Update signed manifest to 7.23.47 2026-08-13 09:49:16 +00:00
tech e95bc58ffc Update signed manifest to 7.23.46 2026-08-13 09:46:06 +00:00
tech 7cb4c1a8fc Update signed manifest to 7.23.45 2026-08-13 09:44:46 +00:00
tech f20c35fbc5 Update signed manifest to 7.23.44 2026-08-13 09:41:29 +00:00
tech d845e6a57d Update signed manifest to 7.23.43 2026-08-12 22:47:23 +00:00
tech fbfa908695 Update signed manifest to 7.23.42 2026-08-12 19:23:41 +00:00
tech 39ef0c2f3f Update signed manifest to 7.23.41 2026-08-12 19:11:53 +00:00
tech 9a459b4644 Update signed manifest to 7.23.40 2026-08-12 18:15:10 +00:00
tech 342c2ee43f Update signed manifest to 7.23.39 2026-08-12 17:58:06 +00:00
tech 105abf4e24 Update signed manifest to 7.23.38 2026-08-12 17:08:28 +00:00
tech d48beb9757 Update signed manifest to 7.23.37 2026-08-12 16:47:29 +00:00
tech 4a43572b15 Update signed manifest to 7.23.36 2026-08-12 15:43:51 +00:00
tech 20c46d3d26 Update signed manifest to 7.23.35 2026-08-12 15:40:08 +00:00
tech 74fdd42561 Update signed manifest to 7.23.34 2026-08-12 15:34:18 +00:00
tech 1e4806457e Update signed manifest to 7.23.33 2026-08-12 15:28:05 +00:00
tech da9237171a Update signed manifest to 7.23.32 2026-08-12 15:26:38 +00:00
tech 904bf52960 Update signed manifest to 7.23.31 2026-08-12 15:21:12 +00:00
tech 8ea7b9f5be Update signed manifest to 7.23.30 2026-08-12 13:24:01 +00:00
tech 804a1aae58 Update signed manifest to 7.23.28 2026-08-10 22:09:40 +00:00
tech 76e585139e Update signed manifest to 7.23.27 2026-08-10 20:18:36 +00:00
tech f871592d27 Update signed manifest to 7.23.26 2026-08-10 19:56:33 +00:00
tech f1375d3d7d Update signed manifest to 7.23.25 2026-08-10 19:23:48 +00:00
tech 72fa8e8901 Update signed manifest to 7.23.24 2026-08-10 16:35:02 +00:00
tech efa84723ee Update signed manifest to 7.23.23 2026-08-10 16:06:43 +00:00
tech 39616478c9 Update signed manifest to 7.23.22 2026-08-10 15:57:46 +00:00
tech c1969d4293 Update signed manifest to 7.23.21 2026-08-10 15:53:45 +00:00
tech 524b893e65 Update signed manifest to 7.23.20 2026-08-10 15:34:44 +00:00
tech 303f31e869 Update signed manifest to 7.23.19 2026-08-10 15:05:44 +00:00
tech 20a2a84ee8 Update signed manifest to 7.23.18 2026-08-10 14:14:25 +00:00
tech 9127b06836 Update signed manifest to 7.23.17 2026-08-10 11:36:11 +00:00
tech 19cb788556 Update signed manifest to 7.23.16 2026-08-10 11:08:03 +00:00
tech e52046437b Update signed manifest to 7.23.15 2026-08-10 10:55:14 +00:00
tech 5d36e1058f Update signed manifest to 7.23.14 2026-08-10 10:42:30 +00:00
tech b79ead3dcf Update signed manifest to 7.23.13 2026-08-10 09:48:52 +00:00
root b0102ea518 Update signed manifest to 7.23.12 (critical fix) 2026-08-10 01:14:06 +00:00
root 1b8d7950f5 Update signed manifest to 7.23.11 2026-08-10 00:59:55 +00:00
root 56284b5d20 Update signed manifest to 7.23.10 2026-08-10 00:39:47 +00:00
ARGUS 037c2b8cc6 Update signed manifest to 7.23.9 2026-08-09 23:50:36 +00:00
ARGUS b1688a0e16 Update signed manifest to 7.23.8 2026-08-09 23:29:08 +00:00
ARGUS 6649b75eb9 Update signed manifest to 7.23.7 (critical fix) 2026-08-09 23:10:37 +00:00
ARGUS 99bce8b86a Update signed manifest to 7.23.6 2026-08-09 22:57:31 +00:00
ARGUS a214c1656f Update signed manifest to 7.23.5 2026-08-09 22:53:52 +00:00
ARGUS 1b1f657b41 Update signed manifest to 7.23.3 2026-08-09 20:06:34 +00:00
ARGUS af032f8f1c Update signed manifest to 7.23.2 2026-08-09 19:39:28 +00:00
ARGUSandClaude Sonnet 5 c4db87af84 ARGUS WordPress Defence 7.23.2
- New: License section in Settings -- a 30-day trial with every
  feature active starts automatically, no registration required to
  start. Protection continues regardless of license status; the trial
  only affects what's shown, never what's enforced. Enter a license
  key to keep Premium features once the trial ends. This is the first
  release where the license system is actually visible anywhere --
  it existed in the codebase before but had no entry form and was
  excluded from every published build.
- Intelligence page: rewrote descriptions in plain language about what
  each thing does for your site's protection, not internal
  implementation details (was showing raw technical descriptions like
  a "signature corpus" and "RIR delegation database" range counts).

Verified end-to-end before publishing (not just code review): a real
signup and license created on the actual companion license service,
then submitted through the real Settings page form exactly as a
customer would -- status went from "TRIAL -- 30 DAYS LEFT" to
"LICENSED" on both the Settings and Overview pages. This exact ZIP was
also installed fresh and every admin page loaded with zero errors
before this commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 19:37:16 +00:00
ARGUSandClaude Sonnet 5 8a6c9ca4de ARGUS WordPress Defence 7.23.1 -- real, working automatic updates
Fixes a real bug: a normal (non-critical) update was previously
detected and shown as available, but nothing ever actually installed
it -- there was no button, cron path, or any other code that did.
Automatic updates only ever worked for updates flagged critical, which
isn't what "automatic" means. Now any newer, compatible,
signature-verified update installs on its own.

This is also the first release where the self-update mechanism itself
ships in this self-distributed channel -- it was unconditionally
excluded from every previous build (a WordPress.org-only restriction
that doesn't apply here, since this channel isn't WordPress.org).

manifest.json in this repo is the real, live update manifest: signed
with Ed25519 (public key documented in README.md's Updating section),
pointing at this exact release's ZIP and its real SHA-256. Verified
end-to-end before publishing -- not just "the code looks right": ran a
full real update cycle (an older installed version checking this
manifest, downloading this exact package, verifying its signature and
hash, replacing itself, and the site continuing to work with zero
errors afterward) using the actual signing key and the actual
package this commit ships.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 19:19:40 +00:00
11 changed files with 625 additions and 61 deletions
+29 -11
View File
@@ -4,7 +4,7 @@ Automatic WordPress security. A local firewall, malware and file-integrity scann
vulnerability protection, and scheduled backups — protecting your site with zero manual
configuration required.
**Version:** 7.23.0
**Version:** 7.23.2
**Requires:** WordPress 6.0+, PHP 7.4+
**License:** GPLv2 or later
@@ -30,6 +30,11 @@ configuration required.
Everything except Global Threat Intelligence works out of the box. There is nothing to
configure to get protected.
**License**: a 30-day trial with every feature active starts automatically on activation --
no registration required to start. Protection never stops when the trial ends; ARGUS Defence →
Settings → License shows the days remaining and where to enter a license key to keep Premium
features. This section is specific to this self-distributed build.
## Status
This is a self-distributed release: it is not listed on WordPress.org and has not gone
@@ -43,11 +48,12 @@ release is not it).
- **Tested in sandbox/disposable WordPress environments.** Verification so far — install,
activation, all admin pages, deactivation, uninstall — was done on disposable WordPress
instances, not on live production sites.
- **Automatic updates for ARGUS itself are not currently active.** The signed-update
mechanism is built in but requires production update infrastructure (a manifest server
and signing key) that is not yet deployed. See [Updating](#updating) below for how to
update manually. Automatic updates for *other* plugins/themes on your site, if you enable
that option, use WordPress's own built-in update system and work today.
- **Automatic updates for ARGUS itself are opt-in, not on by default.** The signed-update
mechanism is real and live (this release's own manifest is signed and hosted in this
repository) -- add two constants to `wp-config.php` to turn it on. See
[Updating](#updating) below for the exact lines and how to verify it's working.
Automatic updates for *other* plugins/themes on your site, if you enable that option in
Settings, use WordPress's own built-in update system and work without any extra setup.
## Installation
@@ -63,11 +69,23 @@ sidebar with an overview of your site's protection status.
## Updating
Automatic in-dashboard updates require an update channel to be configured for your
deployment (`ARGUS_WPD_UPDATE_MANIFEST_URL` and `ARGUS_WPD_UPDATE_PUBLIC_KEY` in
`wp-config.php`). Without one configured, update the plugin the same way you installed
it: download the new release ZIP and upload it again through **Plugins → Add New →
Upload Plugin** — WordPress will offer to replace the existing version.
**Automatic** — add these two lines to `wp-config.php` (above the
`/* That's all, stop editing! */` line):
```php
define( 'ARGUS_WPD_UPDATE_MANIFEST_URL', 'https://git-cloud.weboria.eu/Weboria/argus-wp-defence/raw/branch/main/manifest.json' );
define( 'ARGUS_WPD_UPDATE_PUBLIC_KEY', 'jBQFZLG+fvtW9y7kmhJa4BTBw8u3lmxbgOcF2ptEhFs=' );
```
From then on ARGUS checks for updates every few hours and installs anything newer
automatically, after verifying its Ed25519 signature and SHA-256 checksum. To check
immediately instead of waiting: **ARGUS Defence → Settings → Automatic Security Updates →
Check for Updates Now**, which also shows the current status (last check, last successful
update, last failure).
**Manual** — download the new release ZIP and upload it through **Plugins → Add New →
Upload Plugin** — WordPress will offer to replace the existing version. Works with or
without the automatic option configured.
## Uninstalling
+6
View File
@@ -655,6 +655,12 @@ class Argus_Admin {
public static function render_settings() {
$saved = false;
$template_applied = null;
$license_result = null;
if ( class_exists( 'Argus_License' ) && isset( $_POST['argus_wpd_activate_license_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_activate_license_nonce'] ) ), 'argus_wpd_activate_license' ) ) { // phpcs:ignore
Argus_License::set_license_key( sanitize_text_field( wp_unslash( $_POST['license_key'] ?? '' ) ) ); // phpcs:ignore
$license_result = Argus_License::validate_now();
}
if ( isset( $_POST['argus_wpd_apply_template_nonce'], $_POST['template'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_apply_template_nonce'] ) ), 'argus_wpd_apply_template' ) ) { // phpcs:ignore
$key = sanitize_key( wp_unslash( $_POST['template'] ) ); // phpcs:ignore
+19 -31
View File
@@ -40,75 +40,63 @@ include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
<div class="argus-wpd-tile-row">
<div class="argus-wpd-tile">
<div class="argus-wpd-tile-label"><?php esc_html_e( 'WAF Rule Corpus', 'argus-wordpress-defence' ); ?></div>
<div class="argus-wpd-tile-value"><?php echo esc_html( number_format_i18n( $waf_rule_count ) ); ?></div>
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Firewall', 'argus-wordpress-defence' ); ?></div>
<div class="argus-wpd-tile-value" style="font-size:16px;"><span style="color:var(--emerald)"><?php esc_html_e( 'Protecting', 'argus-wordpress-defence' ); ?></span></div>
</div>
<div class="argus-wpd-tile">
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Vulnerability Intelligence', 'argus-wordpress-defence' ); ?></div>
<div class="argus-wpd-tile-value" style="font-size:16px;">
<?php if ( $vuln_row_count > 0 ) : ?>
<span style="color:var(--emerald)"><?php esc_html_e( 'Active', 'argus-wordpress-defence' ); ?></span>
<?php else : ?>
<span style="color:var(--faint)"><?php esc_html_e( 'Standby', 'argus-wordpress-defence' ); ?></span>
<?php endif; ?>
</div>
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Vulnerability Protection', 'argus-wordpress-defence' ); ?></div>
<div class="argus-wpd-tile-value" style="font-size:16px;"><span style="color:var(--emerald)"><?php esc_html_e( 'Protecting', 'argus-wordpress-defence' ); ?></span></div>
</div>
<div class="argus-wpd-tile">
<div class="argus-wpd-tile-label"><?php esc_html_e( 'GeoIP Database', 'argus-wordpress-defence' ); ?></div>
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Location Awareness', 'argus-wordpress-defence' ); ?></div>
<div class="argus-wpd-tile-value" style="font-size:16px;">
<?php if ( $geoip_status && ! empty( $geoip_status['range_count'] ) ) : ?>
<span style="color:var(--emerald)"><?php esc_html_e( 'Loaded', 'argus-wordpress-defence' ); ?></span>
<span style="color:var(--emerald)"><?php esc_html_e( 'Active', 'argus-wordpress-defence' ); ?></span>
<?php else : ?>
<span style="color:var(--faint)"><?php esc_html_e( 'Building', 'argus-wordpress-defence' ); ?></span>
<span style="color:var(--faint)"><?php esc_html_e( 'Activating', 'argus-wordpress-defence' ); ?></span>
<?php endif; ?>
</div>
</div>
</div>
<div class="argus-wpd-panel">
<h2><?php esc_html_e( 'Local Intelligence Sources', 'argus-wordpress-defence' ); ?></h2>
<h2><?php esc_html_e( 'What\'s Protecting Your Site', 'argus-wordpress-defence' ); ?></h2>
<div class="argus-wpd-ioc-row">
<span class="argus-wpd-ioc-type">WAF</span>
<span class="argus-wpd-ioc-desc"><?php echo esc_html( sprintf( __( 'Application-layer signature corpus (SQLi/XSS/RCE/path traversal/protocol anomaly) -- %d rules, updated with this plugin.', 'argus-wordpress-defence' ), $waf_rule_count ) ); ?></span>
<span class="argus-wpd-ioc-type"><?php esc_html_e( 'Firewall', 'argus-wordpress-defence' ); ?></span>
<span class="argus-wpd-ioc-desc"><?php esc_html_e( 'Blocks malicious requests -- SQL injection, cross-site scripting, remote code execution, path traversal, and more -- before they reach your site. Kept up to date automatically.', 'argus-wordpress-defence' ); ?></span>
</div>
<div class="argus-wpd-ioc-row">
<span class="argus-wpd-ioc-type">VULN</span>
<span class="argus-wpd-ioc-type"><?php esc_html_e( 'Vulnerability Protection', 'argus-wordpress-defence' ); ?></span>
<span class="argus-wpd-ioc-desc">
<?php
echo esc_html(
$vuln_row_count > 0
? __( 'Vulnerability intelligence -- actively matching installed plugins and themes against known security issues.', 'argus-wordpress-defence' )
: __( 'Vulnerability intelligence -- WordPress core is checked live against WordPress.org. Plugin and theme results activate automatically as intelligence becomes available.', 'argus-wordpress-defence' )
? __( 'Actively protecting your installed plugins and themes by checking them against known security issues.', 'argus-wordpress-defence' )
: __( 'Actively protecting WordPress core against known security issues. Plugin and theme protection activates automatically as new information becomes available.', 'argus-wordpress-defence' )
);
?>
</span>
</div>
<div class="argus-wpd-ioc-row">
<span class="argus-wpd-ioc-type">GEOIP</span>
<span class="argus-wpd-ioc-type"><?php esc_html_e( 'Location Awareness', 'argus-wordpress-defence' ); ?></span>
<span class="argus-wpd-ioc-desc">
<?php
if ( $geoip_status && ! empty( $geoip_status['range_count'] ) ) {
echo esc_html(
sprintf(
__( 'Self-hosted RIR delegation database -- %s IPv4 ranges, last refreshed %s.', 'argus-wordpress-defence' ),
number_format_i18n( $geoip_status['range_count'] ),
$geoip_status['last_refresh'] ? human_time_diff( strtotime( $geoip_status['last_refresh'] . ' UTC' ) ) . ' ' . __( 'ago', 'argus-wordpress-defence' ) : __( 'never', 'argus-wordpress-defence' )
)
);
esc_html_e( 'Identifies where threats are coming from automatically, with no external service or configuration required.', 'argus-wordpress-defence' );
} else {
esc_html_e( 'Self-hosted RIR delegation database has not built its first snapshot yet -- refreshes automatically once daily, no action needed.', 'argus-wordpress-defence' );
esc_html_e( 'Activating automatically -- no action needed.', 'argus-wordpress-defence' );
}
?>
</span>
</div>
<div class="argus-wpd-ioc-row">
<span class="argus-wpd-ioc-type">ANIS</span>
<span class="argus-wpd-ioc-type"><?php esc_html_e( 'Global Threat Network', 'argus-wordpress-defence' ); ?></span>
<span class="argus-wpd-ioc-desc">
<?php
if ( 'not_connected' === $anis_status['protection'] ) {
esc_html_e( 'Global threat intelligence -- connecting automatically.', 'argus-wordpress-defence' );
esc_html_e( 'Connecting automatically -- no action needed.', 'argus-wordpress-defence' );
} else {
esc_html_e( 'Global threat intelligence -- automatically updated to help identify malicious sources.', 'argus-wordpress-defence' );
esc_html_e( 'Helps identify and block malicious sources seen across other protected sites, automatically.', 'argus-wordpress-defence' );
}
?>
</span>
+38
View File
@@ -182,6 +182,44 @@ include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
<?php endif; ?>
</div>
<?php if ( class_exists( 'Argus_License' ) ) : ?>
<div class="argus-wpd-panel">
<h2><?php esc_html_e( 'License', 'argus-wordpress-defence' ); ?></h2>
<?php $license_summary = Argus_License::summary(); ?>
<p style="font-size:13px;color:var(--emerald);margin:0 0 6px;display:flex;align-items:center;gap:8px;">
<span class="argus-wpd-status-chip chip-emerald" style="padding:2px 10px;">
<span class="dot"></span>
<span class="state">
<?php
if ( 'licensed' === $license_summary['status'] ) {
esc_html_e( 'LICENSED', 'argus-wordpress-defence' );
} elseif ( 'trial' === $license_summary['status'] ) {
echo esc_html( sprintf(
/* translators: %d: number of days remaining in the free trial */
_n( 'TRIAL -- %d DAY LEFT', 'TRIAL -- %d DAYS LEFT', $license_summary['days_remaining'], 'argus-wordpress-defence' ),
$license_summary['days_remaining']
) );
} else {
esc_html_e( 'TRIAL ENDED', 'argus-wordpress-defence' );
}
?>
</span>
</span>
</p>
<?php if ( ! empty( $license_result ) ) : ?>
<p style="font-size:12.5px;margin:8px 0 0;color:<?php echo ! empty( $license_result['success'] ) ? 'var(--emerald)' : 'var(--rose)'; ?>;"><?php echo esc_html( $license_result['message'] ); ?></p>
<?php endif; ?>
<form method="post" style="margin-top:14px;display:flex;gap:8px;align-items:center;">
<?php wp_nonce_field( 'argus_wpd_activate_license', 'argus_wpd_activate_license_nonce' ); ?>
<input type="text" name="license_key" placeholder="<?php esc_attr_e( 'ARGUS-XXXX-XXXX-...', 'argus-wordpress-defence' ); ?>" value="<?php echo esc_attr( $license_summary['has_key'] ? Argus_License::license_key() : '' ); ?>" style="flex:1;max-width:380px;padding:8px 10px;border-radius:6px;border:1px solid var(--border-strong);background:var(--panel-2);color:var(--text);font-family:var(--mono);font-size:13px;" />
<button type="submit" class="button button-primary"><?php esc_html_e( 'Activate', 'argus-wordpress-defence' ); ?></button>
</form>
<?php if ( $license_summary['purchase_url'] ) : ?>
<p style="font-size:12.5px;margin:12px 0 0;"><a href="<?php echo esc_url( $license_summary['purchase_url'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Get a license', 'argus-wordpress-defence' ); ?></a></p>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="argus-wpd-panel">
<h2><?php esc_html_e( 'Website Acceleration', 'argus-wordpress-defence' ); ?></h2>
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 12px;"><?php esc_html_e( 'Cache & Performance now has its own dedicated page -- speed up your website, reduce load, and see what\'s being accelerated.', 'argus-wordpress-defence' ); ?></p>
+2 -2
View File
@@ -3,7 +3,7 @@
* Plugin Name: ARGUS WordPress Defence
* Plugin URI: https://git-cloud.weboria.eu/Weboria/argus-wp-defence
* Description: Standalone WordPress security: local WAF, malware & integrity scanning, vulnerability intelligence, and a deterministic ban/policy engine. Works fully offline; optionally connects to ARGUS Cloud for richer intelligence and cross-asset correlation.
* Version: 7.23.0
* Version: 7.23.2
* Requires at least: 6.0
* Requires PHP: 7.4
* Author: ARGUS
@@ -28,7 +28,7 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'ARGUS_WPD_VERSION', '7.23.0' );
define( 'ARGUS_WPD_VERSION', '7.23.2' );
define( 'ARGUS_WPD_FILE', __FILE__ );
define( 'ARGUS_WPD_DIR', plugin_dir_path( __FILE__ ) );
define( 'ARGUS_WPD_URL', plugin_dir_url( __FILE__ ) );
+25 -16
View File
@@ -8,12 +8,20 @@
# the result against an explicit allowlist before packaging, failing
# closed on anything unexpected rather than silently shipping it.
#
# Usage: bin/build-release.sh [git-ref] (defaults to HEAD)
# Usage: bin/build-release.sh [git-ref] [channel]
# channel: "self" (default) -- the self-distributed release (Gitea
# releases page), includes the signed self-update client, since
# nothing prohibits it outside WordPress.org.
# "wporg" -- strips the self-update client too (and the
# license/trial system, stripped either way) -- required before
# any submission to the WordPress.org Plugin Directory, which
# prohibits a plugin using any update channel but its own.
#
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REF="${1:-HEAD}"
CHANNEL="${2:-self}"
BUILD_DIR="$(mktemp -d)"
STAGE_DIR="${BUILD_DIR}/argus-wordpress-defence"
OUT_DIR="${REPO_ROOT}/dist"
@@ -35,21 +43,22 @@ rm -rf \
"${STAGE_DIR}/.gitignore" \
"${STAGE_DIR}/bin"
# A plugin hosted on WordPress.org must rely solely on WordPress.org's own
# update channel -- never a self-update-from-external-manifest mechanism,
# even one that ships inert-by-default. class_exists( 'Argus_Update_Client' )
# guards every reference to this class elsewhere in the codebase, so removing
# the file here is sufficient; nothing else needs to change per build.
echo "==> Removing the self-update client (WordPress.org must be the only update channel)"
rm -f "${STAGE_DIR}/includes/class-argus-update-client.php"
# WordPress.org explicitly prohibits trialware -- a plugin submitted to the
# directory must stay genuinely, permanently functional with no license
# requirement. class_exists( 'Argus_License' ) guards every reference to
# this class elsewhere, so removing the file here is sufficient; the free
# build never has a trial timer at all.
echo "==> Removing the license/trial system (WordPress.org prohibits trialware)"
rm -f "${STAGE_DIR}/includes/class-argus-license.php"
if [ "${CHANNEL}" = "wporg" ]; then
# A plugin hosted on WordPress.org must rely solely on WordPress.org's own
# update channel -- never a self-update-from-external-manifest mechanism,
# even one that ships inert-by-default -- and must stay genuinely,
# permanently functional with no license/trial requirement (WordPress.org
# explicitly prohibits trialware). class_exists() guards every reference
# to both classes elsewhere in the codebase, so removing the files here is
# sufficient; nothing else needs to change per build.
echo "==> [wporg channel] Removing the self-update client (WordPress.org must be the only update channel)"
rm -f "${STAGE_DIR}/includes/class-argus-update-client.php"
echo "==> [wporg channel] Removing the license/trial system (WordPress.org prohibits trialware)"
rm -f "${STAGE_DIR}/includes/class-argus-license.php"
elif [ "${CHANNEL}" != "self" ]; then
echo "==> BUILD FAILED: unknown channel '${CHANNEL}' (expected 'self' or 'wporg')"
exit 1
fi
echo "==> Allowlist audit -- fail closed on anything unexpected"
UNEXPECTED=0
+81
View File
@@ -0,0 +1,81 @@
<?php
/**
* Signs an update manifest for Argus_Update_Client (includes/class-argus-update-client.php).
* Never shipped in any release ZIP -- a dev/release-time tool only.
*
* Usage:
* php bin/sign-manifest.php \
* --private-key=<base64 Ed25519 secret key> \
* --version=7.23.1 \
* --package-url=https://.../argus-wordpress-defence-7.23.1.zip \
* --sha256=<hex sha256 of that exact zip> \
* [--min-php=7.4] [--min-wp=6.0] [--critical] \
* [--out=manifest.json]
*
* The signed payload's field set and order (version, released_at,
* package_url, sha256, min_php, min_wp, critical) MUST exactly match
* Argus_Update_Client::canonical_payload() -- any drift and every
* signature this produces fails verification client-side.
*/
$args = array();
foreach ( $argv as $arg ) {
if ( 0 === strpos( $arg, '--' ) ) {
$parts = explode( '=', substr( $arg, 2 ), 2 );
$args[ $parts[0] ] = $parts[1] ?? true;
}
}
function required( $args, $key ) {
if ( empty( $args[ $key ] ) ) {
fwrite( STDERR, "Missing required --{$key}\n" );
exit( 1 );
}
return $args[ $key ];
}
$private_key_b64 = required( $args, 'private-key' );
$version = required( $args, 'version' );
$package_url = required( $args, 'package-url' );
$sha256 = required( $args, 'sha256' );
$min_php = $args['min-php'] ?? '7.4';
$min_wp = $args['min-wp'] ?? '6.0';
$critical = ! empty( $args['critical'] );
$released_at = gmdate( 'c' );
$out = $args['out'] ?? ( dirname( __DIR__ ) . '/manifest.json' );
if ( 64 !== strlen( $sha256 ) || ! ctype_xdigit( $sha256 ) ) {
fwrite( STDERR, "--sha256 must be a 64-character hex string (run: sha256sum <zip>)\n" );
exit( 1 );
}
$private_key = base64_decode( $private_key_b64, true );
if ( false === $private_key || SODIUM_CRYPTO_SIGN_SECRETKEYBYTES !== strlen( $private_key ) ) {
fwrite( STDERR, "--private-key is not a valid base64-encoded Ed25519 secret key\n" );
exit( 1 );
}
// Must match Argus_Update_Client::canonical_payload() exactly -- same key
// set, same order, same JSON_UNESCAPED_SLASHES flag.
$ordered = array(
'version' => $version,
'released_at' => $released_at,
'package_url' => $package_url,
'sha256' => $sha256,
'min_php' => $min_php,
'min_wp' => $min_wp,
'critical' => $critical,
);
$canonical = json_encode( $ordered, JSON_UNESCAPED_SLASHES );
$signature = sodium_crypto_sign_detached( $canonical, $private_key );
$manifest = $ordered;
$manifest['signature'] = base64_encode( $signature );
file_put_contents( $out, json_encode( $manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) . "\n" );
echo "Wrote {$out}\n";
echo " version: {$version}\n";
echo " package_url: {$package_url}\n";
echo " sha256: {$sha256}\n";
echo " critical: " . ( $critical ? 'true' : 'false' ) . "\n";
+127
View File
@@ -0,0 +1,127 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Premium-build-only, same as Argus_Update_Client: excluded from the
// WordPress.org release ZIP (bin/build-release.sh), guarded everywhere with
// class_exists() so the free build never references it. WP.org's guidelines
// prohibit trialware in a plugin submitted to the directory -- the free
// build stays genuinely, permanently functional, with no trial timer and no
// license requirement anywhere in it. This class exists only in a
// separately-distributed Premium build.
class Argus_License {
const TRIAL_DAYS = 30;
const TRIAL_STARTED_OPTION = 'argus_wpd_license_trial_started_at';
const LICENSE_KEY_OPTION = 'argus_wpd_license_key';
const LICENSE_STATUS_OPTION = 'argus_wpd_license_validation_status';
const LICENSE_CHECKED_OPTION = 'argus_wpd_license_last_checked';
public static function ensure_trial_started() {
if ( ! get_option( self::TRIAL_STARTED_OPTION ) ) {
update_option( self::TRIAL_STARTED_OPTION, time(), false );
}
}
public static function trial_started_at() {
return (int) get_option( self::TRIAL_STARTED_OPTION, time() );
}
public static function trial_ends_at() {
return self::trial_started_at() + ( self::TRIAL_DAYS * DAY_IN_SECONDS );
}
public static function days_remaining() {
$remaining_secs = self::trial_ends_at() - time();
return max( 0, (int) ceil( $remaining_secs / DAY_IN_SECONDS ) );
}
public static function license_key() {
if ( defined( 'ARGUS_WPD_LICENSE_KEY' ) && ARGUS_WPD_LICENSE_KEY ) {
return trim( ARGUS_WPD_LICENSE_KEY );
}
return trim( (string) get_option( self::LICENSE_KEY_OPTION, '' ) );
}
// Saving a submitted key never marks it valid by itself -- the caller
// still has to call validate_now() to actually check it against the
// configured validation server, same as entering any license key
// anywhere always requires a real check before it does anything.
public static function set_license_key( $key ) {
update_option( self::LICENSE_KEY_OPTION, trim( (string) $key ), false );
delete_option( self::LICENSE_STATUS_OPTION );
}
public static function validation_endpoint() {
return defined( 'ARGUS_WPD_LICENSE_VALIDATE_URL' ) ? ARGUS_WPD_LICENSE_VALIDATE_URL : '';
}
// Honest, not fabricated: a license key alone never counts as "licensed"
// unless there's a real validation endpoint configured to actually check
// it against. No key -> unlicensed. Key present but no validation
// endpoint configured -> still unlicensed, not a silent green light.
public static function is_licensed() {
if ( '' === self::license_key() || '' === self::validation_endpoint() ) {
return false;
}
return 'valid' === get_option( self::LICENSE_STATUS_OPTION, '' );
}
public static function validate_now() {
$key = self::license_key();
$url = self::validation_endpoint();
if ( '' === $key ) {
return array( 'success' => false, 'message' => __( 'Enter a license key first.', 'argus-wordpress-defence' ) );
}
if ( '' === $url ) {
return array( 'success' => false, 'message' => __( 'No license validation server is configured for this deployment.', 'argus-wordpress-defence' ) );
}
$response = wp_remote_post(
$url,
array(
'timeout' => 15,
'headers' => array( 'Content-Type' => 'application/json' ),
'body' => wp_json_encode( array( 'license_key' => $key, 'domain' => wp_parse_url( home_url(), PHP_URL_HOST ) ) ),
)
);
update_option( self::LICENSE_CHECKED_OPTION, current_time( 'mysql', true ), false );
if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
update_option( self::LICENSE_STATUS_OPTION, 'error', false );
return array( 'success' => false, 'message' => __( 'Could not reach the license server. Try again shortly.', 'argus-wordpress-defence' ) );
}
$data = json_decode( wp_remote_retrieve_body( $response ), true );
$valid = is_array( $data ) && ! empty( $data['valid'] );
update_option( self::LICENSE_STATUS_OPTION, $valid ? 'valid' : 'invalid', false );
return array(
'success' => $valid,
'message' => $valid
? __( 'License activated.', 'argus-wordpress-defence' )
: __( 'That license key is not valid or has expired.', 'argus-wordpress-defence' ),
);
}
public static function status() {
if ( self::is_licensed() ) {
return 'licensed';
}
return self::days_remaining() > 0 ? 'trial' : 'trial_expired';
}
public static function summary() {
return array(
'status' => self::status(),
'days_remaining' => self::days_remaining(),
'trial_ends_at' => gmdate( 'Y-m-d H:i:s', self::trial_ends_at() ),
'has_key' => '' !== self::license_key(),
'purchase_url' => defined( 'ARGUS_WPD_LICENSE_PURCHASE_URL' ) ? ARGUS_WPD_LICENSE_PURCHASE_URL : '',
);
}
}
+275
View File
@@ -0,0 +1,275 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Argus_Update_Client {
const CHECK_INTERVAL_SECS = 6 * HOUR_IN_SECONDS;
const LOCK_TRANSIENT = 'argus_wpd_update_check_lock';
const LAST_CHECK_OPTION = 'argus_wpd_update_last_check';
const MANIFEST_ETAG_OPTION = 'argus_wpd_update_manifest_etag';
const PENDING_MANIFEST_OPTION = 'argus_wpd_update_pending_manifest';
const LAST_SUCCESS_OPTION = 'argus_wpd_update_last_success';
const LAST_FAILURE_OPTION = 'argus_wpd_update_last_failure';
public static function manifest_url() {
return defined( 'ARGUS_WPD_UPDATE_MANIFEST_URL' ) ? ARGUS_WPD_UPDATE_MANIFEST_URL : '';
}
public static function public_key() {
return defined( 'ARGUS_WPD_UPDATE_PUBLIC_KEY' ) ? ARGUS_WPD_UPDATE_PUBLIC_KEY : '';
}
public static function is_configured() {
return '' !== self::manifest_url() && '' !== self::public_key();
}
public static function maybe_check() {
if ( ! self::is_configured() ) {
return;
}
$last_check = (int) get_option( self::LAST_CHECK_OPTION, 0 );
if ( ( $last_check + self::CHECK_INTERVAL_SECS ) > time() ) {
return;
}
if ( false !== get_transient( self::LOCK_TRANSIENT ) ) {
return;
}
set_transient( self::LOCK_TRANSIENT, 1, 4 * MINUTE_IN_SECONDS );
self::check_now();
delete_transient( self::LOCK_TRANSIENT );
}
public static function check_now() {
if ( ! self::is_configured() ) {
return array( 'success' => false, 'message' => __( 'No update source is configured.', 'argus-wordpress-defence' ), 'update_available' => false );
}
update_option( self::LAST_CHECK_OPTION, time(), false );
$args = array( 'timeout' => 15 );
$etag = get_option( self::MANIFEST_ETAG_OPTION, '' );
if ( $etag ) {
$args['headers'] = array( 'If-None-Match' => $etag );
}
$response = wp_remote_get( self::manifest_url(), $args );
if ( is_wp_error( $response ) ) {
return self::record_failure( __( 'Could not reach the update server.', 'argus-wordpress-defence' ) );
}
$code = wp_remote_retrieve_response_code( $response );
if ( 304 === $code ) {
return array( 'success' => true, 'message' => '', 'update_available' => false );
}
if ( 200 !== $code ) {
return self::record_failure( sprintf( 'Update server returned HTTP %d.', $code ) );
}
$new_etag = wp_remote_retrieve_header( $response, 'etag' );
if ( $new_etag ) {
update_option( self::MANIFEST_ETAG_OPTION, $new_etag, false );
}
$body = wp_remote_retrieve_body( $response );
$manifest = json_decode( $body, true );
if ( ! is_array( $manifest ) ) {
return self::record_failure( __( 'Update manifest was not valid JSON.', 'argus-wordpress-defence' ) );
}
return self::process_manifest( $manifest );
}
public static function process_manifest( array $manifest ) {
if ( ! self::verify_signature( $manifest ) ) {
return self::record_failure( __( 'Update manifest failed signature verification.', 'argus-wordpress-defence' ) );
}
$version = $manifest['version'] ?? '';
if ( '' === $version ) {
return self::record_failure( __( 'Update manifest is missing a version.', 'argus-wordpress-defence' ) );
}
if ( version_compare( $version, ARGUS_WPD_VERSION, '<=' ) ) {
return array( 'success' => true, 'message' => '', 'update_available' => false );
}
$last_installed = get_option( self::LAST_SUCCESS_OPTION, array() );
if ( ! empty( $last_installed['version'] ) && version_compare( $version, $last_installed['version'], '<=' ) ) {
return array( 'success' => true, 'message' => '', 'update_available' => false );
}
global $wp_version;
if ( ! empty( $manifest['min_php'] ) && version_compare( PHP_VERSION, $manifest['min_php'], '<' ) ) {
return self::record_failure( sprintf( 'Update %s requires PHP %s or newer.', $version, $manifest['min_php'] ) );
}
if ( ! empty( $manifest['min_wp'] ) && version_compare( $wp_version, $manifest['min_wp'], '<' ) ) {
return self::record_failure( sprintf( 'Update %s requires WordPress %s or newer.', $version, $manifest['min_wp'] ) );
}
update_option( self::PENDING_MANIFEST_OPTION, $manifest, false );
// Any newer, compatible, signature-verified version is installed --
// 'critical' is informational only (used in the success message and
// by Argus_Events severity), not an install gate. It used to be: a
// non-critical manifest was recorded as "update_available" and left
// there permanently, since nothing else ever called install_update()
// for it -- no button, no cron path, nothing. That made "automatic
// updates" only ever true for updates someone remembered to flag
// critical, which defeats the actual feature.
return self::install_update( $manifest );
}
public static function verify_signature( array $manifest ) {
if ( empty( $manifest['signature'] ) ) {
return false;
}
$signature = base64_decode( $manifest['signature'], true );
if ( false === $signature || SODIUM_CRYPTO_SIGN_BYTES !== strlen( $signature ) ) {
return false;
}
$public_key_b64 = self::public_key();
if ( '' === $public_key_b64 ) {
return false;
}
$public_key = base64_decode( $public_key_b64, true );
if ( false === $public_key ) {
return false;
}
$canonical = self::canonical_payload( $manifest );
return sodium_crypto_sign_verify_detached( $signature, $canonical, $public_key );
}
protected static function canonical_payload( array $manifest ) {
$ordered = array();
foreach ( array( 'version', 'released_at', 'package_url', 'sha256', 'min_php', 'min_wp', 'critical' ) as $key ) {
$ordered[ $key ] = $manifest[ $key ] ?? null;
}
return wp_json_encode( $ordered, JSON_UNESCAPED_SLASHES );
}
public static function install_update( array $manifest, $target_dir = null ) {
$target_dir = $target_dir ?: ( WP_PLUGIN_DIR . '/argus-wordpress-defence' );
$version = $manifest['version'];
$upgrade_dir = trailingslashit( wp_get_upload_dir()['basedir'] ) . 'argus-wpd-data/update-staging';
if ( ! is_dir( $upgrade_dir ) && ! wp_mkdir_p( $upgrade_dir ) ) {
return self::record_failure( __( 'Could not prepare the update staging directory.', 'argus-wordpress-defence' ) );
}
$package_path = trailingslashit( $upgrade_dir ) . 'package-' . $version . '-' . bin2hex( random_bytes( 4 ) ) . '.zip';
$response = wp_remote_get( $manifest['package_url'], array( 'timeout' => 120, 'stream' => true, 'filename' => $package_path ) );
if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
@unlink( $package_path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors, WordPress.WP.AlternativeFunctions
return self::record_failure( __( 'Could not download the update package.', 'argus-wordpress-defence' ) );
}
if ( ! hash_equals( $manifest['sha256'], hash_file( 'sha256', $package_path ) ) ) {
wp_delete_file( $package_path );
return self::record_failure( __( 'Downloaded package hash did not match the signed manifest -- rejected.', 'argus-wordpress-defence' ) );
}
$extract_root = trailingslashit( $upgrade_dir ) . 'extract-' . $version . '-' . bin2hex( random_bytes( 4 ) );
if ( ! class_exists( 'ZipArchive' ) ) {
wp_delete_file( $package_path );
return self::record_failure( __( 'The PHP zip extension is not available -- cannot install the update.', 'argus-wordpress-defence' ) );
}
$zip = new ZipArchive();
if ( true !== $zip->open( $package_path ) || true !== $zip->extractTo( $extract_root ) ) {
wp_delete_file( $package_path );
return self::record_failure( __( 'Could not extract the update package.', 'argus-wordpress-defence' ) );
}
$zip->close();
wp_delete_file( $package_path );
$extracted_plugin_dir = trailingslashit( $extract_root ) . 'argus-wordpress-defence';
$new_main_file = trailingslashit( $extracted_plugin_dir ) . 'argus-wordpress-defence.php';
if ( ! file_exists( $new_main_file ) ) {
self::rrmdir( $extract_root );
return self::record_failure( __( 'Extracted package did not contain the expected plugin file.', 'argus-wordpress-defence' ) );
}
$header_contents = file_get_contents( $new_main_file ); // phpcs:ignore WordPress.WP.AlternativeFunctions
if ( ! preg_match( '/Version:\s*([^\r\n]+)/', $header_contents, $m ) || trim( $m[1] ) !== $version ) {
self::rrmdir( $extract_root );
return self::record_failure( __( 'Extracted package version did not match the signed manifest -- rejected.', 'argus-wordpress-defence' ) );
}
$backup_dir = $target_dir . '-previous-' . time();
$had_previous = is_dir( $target_dir );
if ( $had_previous && ! rename( $target_dir, $backup_dir ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions
self::rrmdir( $extract_root );
return self::record_failure( __( 'Could not move the current plugin version aside for the update.', 'argus-wordpress-defence' ) );
}
if ( ! rename( $extracted_plugin_dir, $target_dir ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions
if ( $had_previous ) {
rename( $backup_dir, $target_dir ); // phpcs:ignore WordPress.WP.AlternativeFunctions
}
self::rrmdir( $extract_root );
return self::record_failure( __( 'Could not activate the downloaded update -- rolled back to the previous version.', 'argus-wordpress-defence' ) );
}
self::rrmdir( $extract_root );
if ( $had_previous ) {
self::rrmdir( $backup_dir );
}
delete_option( self::PENDING_MANIFEST_OPTION );
update_option(
self::LAST_SUCCESS_OPTION,
array( 'version' => $version, 'installed_at' => current_time( 'mysql', true ) ),
false
);
return array(
'success' => true,
'message' => ! empty( $manifest['critical'] )
? sprintf( __( 'A critical ARGUS security update was installed (%s).', 'argus-wordpress-defence' ), $version )
: sprintf( __( 'ARGUS Defence was updated to version %s.', 'argus-wordpress-defence' ), $version ),
'update_available' => false,
);
}
protected static function record_failure( $message ) {
update_option(
self::LAST_FAILURE_OPTION,
array( 'message' => $message, 'at' => current_time( 'mysql', true ) ),
false
);
Argus_Events::record( 'update_check_failed', 'medium', $message, array() );
return array( 'success' => false, 'message' => $message, 'update_available' => false );
}
protected static function rrmdir( $dir ) {
if ( ! is_dir( $dir ) ) {
return;
}
$items = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ), RecursiveIteratorIterator::CHILD_FIRST );
foreach ( $items as $item ) {
$item->isDir() ? rmdir( $item->getPathname() ) : unlink( $item->getPathname() ); // phpcs:ignore WordPress.WP.AlternativeFunctions
}
rmdir( $dir ); // phpcs:ignore WordPress.WP.AlternativeFunctions
}
public static function status() {
return array(
'current_version' => ARGUS_WPD_VERSION,
'configured' => self::is_configured(),
'last_check' => get_option( self::LAST_CHECK_OPTION, 0 ),
'last_success' => get_option( self::LAST_SUCCESS_OPTION, array() ),
'last_failure' => get_option( self::LAST_FAILURE_OPTION, array() ),
'pending' => get_option( self::PENDING_MANIFEST_OPTION, array() ),
);
}
}
+11
View File
@@ -0,0 +1,11 @@
{
"version": "7.52.0",
"released_at": "2026-09-23T09:51:34+00:00",
"package_url": "https://git-cloud.weboria.eu/Weboria/argus-wp-defence/releases/download/v7.52.0/argus-wordpress-defence-7.52.0.zip",
"sha256": "c954611e46daefc04d34313a5b3d321b5f0eac5a8a80c6b791aa72f6fadea82a",
"min_php": "7.4",
"min_wp": "6.0",
"critical": false,
"summary": "* Manual IP blocking now lets you choose the block duration -- Temporary, Extended, or Permanent\n -- instead of always applying a fixed 24-hour block.\n* Fixed remote management actions sent from the WAD portal sometimes being rejected when they\n contained certain special characters (such as accented letters or punctuation) in a reason or\n note field.\n* Fixed a scan that could get permanently stuck reporting \"already in progress\" if it was\n interrupted; a new scan can now always be started.\n* Fixed deleting a backup that was already removed being reported as an error instead of simply\n confirming it's gone.",
"signature": "4jOlj5HY/GIuDiy0iqmqADegPHXJWC22KZoHlKyVeRVfuCEFDPtscPEtpaYkbAZ8vC+mkCQjrGdfVO+vIxBjBA=="
}
+12 -1
View File
@@ -4,7 +4,7 @@ Tags: security, firewall, malware, vulnerability, backup
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 7.23.0
Stable tag: 7.23.2
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -53,6 +53,17 @@ dashboard whenever a new version is available, and you can update it in one clic
== Changelog ==
= 7.23.2 =
* Settings: added a License section -- a 30-day trial with everything active, then enter a
license key to keep Premium features. Protection never stops regardless of license status.
* Intelligence page: rewrote descriptions in plain language focused on what's protecting your
site, not internal implementation details.
= 7.23.1 =
* Automatic updates: fixed a bug where a normal (non-critical) update would be detected and
shown as available, but never actually installed -- now any newer, compatible, verified
update installs automatically, the same way updates to other plugins already do.
= 7.23.0 =
* Firewall: broadened local rule coverage (XXE, SSRF, session fixation, Log4Shell/JNDI, scanner-tool
detection, and deeper SQL injection / XSS / PHP injection signatures).