Plugin Directory

Changeset 3482336


Ignore:
Timestamp:
03/14/2026 01:30:45 AM (3 weeks ago)
Author:
shift8
Message:

Improvements to IP bans, bug fixes, more tests

Location:
atomic-edge-security/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • atomic-edge-security/trunk/admin/js/admin.js

    r3480349 r3482336  
    395395                var actionCell;
    396396                if (log.is_blocked) {
    397                     actionCell = '<span class="atomicedge-blocked-badge" title="This IP is blocked" style="color:#b32d2e;font-weight:600;">' +
    398                         '<span class="dashicons dashicons-lock" style="font-size:14px;width:14px;height:14px;margin-top:3px;"></span> Blocked</span>';
     397                    actionCell = '<span class="atomicedge-blacklisted-badge" title="This IP is blacklisted" style="color:#b32d2e;font-weight:600;">' +
     398                        '<span class="dashicons dashicons-lock" style="font-size:14px;width:14px;height:14px;margin-top:3px;"></span> Blacklisted</span>';
    399399                } else {
    400                     actionCell = '<button type="button" class="button button-small atomicedge-block-ip" data-ip="' + self.escapeHtml(log.client_ip || '') + '">Block IP</button>';
     400                    actionCell = '<button type="button" class="button button-small atomicedge-blacklist-ip" data-ip="' + self.escapeHtml(log.client_ip || '') + '">Blacklist</button>';
    401401                }
    402402                var row = '<tr>' +
     
    411411            });
    412412
    413             // Bind block IP buttons — blocks go to Adaptive Defense (not IP blacklist).
    414             $tbody.find('.atomicedge-block-ip').on('click', function() {
     413            // Bind blacklist buttons — adds IP to the Access Control IP blacklist.
     414            $tbody.find('.atomicedge-blacklist-ip').on('click', function() {
    415415                var $btn = $(this);
    416416                var ip = $btn.data('ip');
    417417                if (confirm(atomicedgeAdmin.strings.confirm)) {
    418                     self.blockIpFromWafLogs(ip, $btn);
     418                    self.blacklistIpFromWafLogs(ip, $btn);
    419419                }
    420420            });
     
    579579         * Block an IP from the WAF logs page via Adaptive Defense.
    580580         *
    581          * This sends the block to the AD system (ActorProfile), NOT the
    582          * Access Control IP blacklist (SiteSettings).  The existing
    583          * ajax_block_ip AJAX handler + api->block_ip() method are reused.
     581         * This adds the IP to the Access Control IP blacklist
     582         * (SiteSettings.ip_blacklist) via the existing ajax_add_ip_blacklist
     583         * AJAX handler + api->add_ip_blacklist() method.
    584584         *
    585585         * @param {string} ip      IP address.
    586586         * @param {jQuery} $button The button element to update on success.
    587587         */
    588         blockIpFromWafLogs: function(ip, $button) {
     588        blacklistIpFromWafLogs: function(ip, $button) {
    589589            var self = this;
    590590
     
    593593            }
    594594
    595             this.ajax('atomicedge_block_ip', {
     595            var description = 'Added from WordPress on ' + this.formatTimestamp();
     596
     597            this.ajax('atomicedge_add_ip_blacklist', {
    596598                ip: ip,
    597                 reason: 'Blocked from WAF logs'
     599                description: description
    598600            }, function() {
    599                 // Reload WAF logs so the is_blocked badge appears.
     601                // Reload WAF logs so the blacklisted badge appears.
    600602                if ($('#atomicedge-waf-table').length) {
    601603                    self.loadWafLogs();
     
    606608                    $button.prop('disabled', true)
    607609                        .removeClass('button-small')
    608                         .addClass('atomicedge-blocked-btn')
    609                         .html('<span class="dashicons dashicons-yes-alt" style="margin-top:3px;color:#00a32a;"></span> Blocked');
    610                 }
    611 
    612                 self.showNotice(ip + ' has been blocked via Adaptive Defense.', 'success');
     610                        .addClass('atomicedge-blacklisted-btn')
     611                        .html('<span class="dashicons dashicons-yes-alt" style="margin-top:3px;color:#00a32a;"></span> Blacklisted');
     612                }
     613
     614                self.showNotice(ip + ' has been added to the IP blacklist.', 'success');
    613615            }, function(errData) {
    614616                if ($button) {
    615                     $button.prop('disabled', false).text('Block IP');
     617                    $button.prop('disabled', false).text('Blacklist');
    616618                }
    617619                var message = (errData && errData.message) ? errData.message : atomicedgeAdmin.strings.error;
     
    13571359
    13581360        /**
    1359          * AJAX helper
    1360          */
    1361         ajax: function(action, data, success, error) {
     1361         * AJAX helper.
     1362         *
     1363         * On nonce expiry the helper transparently refreshes the nonce and
     1364         * retries the original request once. If the retry also fails the
     1365         * error is surfaced to the caller normally.
     1366         *
     1367         * @param {string}   action   WordPress AJAX action name.
     1368         * @param {Object}   data     POST data (action & nonce are added automatically).
     1369         * @param {Function} success  Callback on success (receives response.data).
     1370         * @param {Function} error    Callback on failure (receives response.data).
     1371         * @param {boolean}  _isRetry Internal flag — do not set manually.
     1372         */
     1373        ajax: function(action, data, success, error, _isRetry) {
    13621374            var self = this;
    13631375            data = data || {};
     
    13701382                data: data,
    13711383                success: function(response) {
     1384                    // Transparent nonce refresh: if the server flags a nonce
     1385                    // error and this is not already a retry, fetch a fresh
     1386                    // nonce and replay the request.
     1387                    if (!response.success && response.data && response.data.nonce_error && !_isRetry) {
     1388                        self.refreshNonceAndRetry(action, data, success, error);
     1389                        return;
     1390                    }
     1391
    13721392                    if (response.success) {
    13731393                        if (typeof success === 'function') {
     
    13941414
    13951415        /**
     1416         * Fetch a fresh nonce from the server and replay the failed request.
     1417         *
     1418         * The refresh endpoint is cookie-authenticated (no nonce required)
     1419         * so it succeeds even when the original nonce has expired.
     1420         *
     1421         * @param {string}   action  Original AJAX action.
     1422         * @param {Object}   data    Original POST data.
     1423         * @param {Function} success Original success callback.
     1424         * @param {Function} error   Original error callback.
     1425         */
     1426        refreshNonceAndRetry: function(action, data, success, error) {
     1427            var self = this;
     1428
     1429            $.ajax({
     1430                url: atomicedgeAdmin.ajaxUrl,
     1431                type: 'POST',
     1432                data: { action: 'atomicedge_refresh_nonce' },
     1433                success: function(response) {
     1434                    if (response.success && response.data && response.data.nonce) {
     1435                        // Store the fresh nonce for all future requests.
     1436                        atomicedgeAdmin.nonce = response.data.nonce;
     1437                        // Replay the original request (flagged as retry).
     1438                        self.ajax(action, data, success, error, true);
     1439                    } else {
     1440                        self.showNotice(
     1441                            'Your session has expired. Please refresh the page and try again.',
     1442                            'error'
     1443                        );
     1444                    }
     1445                },
     1446                error: function() {
     1447                    self.showNotice(
     1448                        'Your session has expired. Please refresh the page and try again.',
     1449                        'error'
     1450                    );
     1451                }
     1452            });
     1453        },
     1454
     1455        /**
    13961456         * Validate IP address or CIDR
    13971457         */
  • atomic-edge-security/trunk/atomicedge.php

    r3476684 r3482336  
    44 * Plugin URI: https://atomicedge.io/wordpress
    55 * Description: Connect your WordPress site to Atomic Edge WAF/CDN for advanced security protection, analytics, and access control management.
    6  * Version: 2.5.0
     6 * Version: 2.5.1
    77 * Requires at least: 5.8
    88 * Requires PHP: 7.4
     
    2626
    2727// Plugin constants.
    28 define( 'ATOMICEDGE_VERSION', '2.5.0' );
     28define( 'ATOMICEDGE_VERSION', '2.5.1' );
    2929define( 'ATOMICEDGE_PLUGIN_FILE', __FILE__ );
    3030define( 'ATOMICEDGE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
  • atomic-edge-security/trunk/includes/class-atomicedge-ajax.php

    r3480349 r3482336  
    103103        add_action( 'wp_ajax_atomicedge_delete_actor', array( $this, 'ajax_delete_actor' ) );
    104104        add_action( 'wp_ajax_atomicedge_dismiss_detection', array( $this, 'ajax_dismiss_detection' ) );
     105
     106        // Nonce refresh (lightweight, no nonce required — cookie-authenticated).
     107        add_action( 'wp_ajax_atomicedge_refresh_nonce', array( $this, 'ajax_refresh_nonce' ) );
    105108    }
    106109
     
    119122        $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
    120123        if ( ! $nonce || ! wp_verify_nonce( $nonce, 'atomicedge_ajax' ) ) {
    121             wp_send_json_error( array( 'message' => __( 'Security check failed.', 'atomic-edge-security' ) ) );
     124            wp_send_json_error( array(
     125                'message'     => __( 'Security check failed.', 'atomic-edge-security' ),
     126                'nonce_error' => true,
     127            ) );
    122128        }
    123129
     
    297303        if ( ! $this->api->is_valid_ip( $ip ) ) {
    298304            wp_send_json_error( array( 'message' => __( 'Invalid IP address or CIDR range.', 'atomic-edge-security' ) ) );
     305        }
     306
     307        // Dev mode: return simulated success (only when not connected to real API).
     308        if ( $this->should_use_dev_mode() ) {
     309            wp_send_json_success( array(
     310                'message' => sprintf(
     311                    /* translators: %s: IP address */
     312                    __( '[Dev Mode] IP %s has been added to the blacklist.', 'atomic-edge-security' ),
     313                    esc_html( $ip )
     314                ),
     315            ) );
    299316        }
    300317
     
    14621479
    14631480    /**
     1481     * Return a fresh nonce so the client can retry after expiry.
     1482     *
     1483     * This endpoint intentionally skips nonce verification — the wp_ajax_
     1484     * hook already proves the user is logged in (cookie-authenticated), and
     1485     * the only value returned is a new nonce which is harmless to expose.
     1486     * A capability check ensures only admins can obtain a nonce.
     1487     *
     1488     * @return void
     1489     */
     1490    public function ajax_refresh_nonce() {
     1491        if ( ! current_user_can( 'manage_options' ) ) {
     1492            wp_send_json_error( array( 'message' => __( 'Unauthorized.', 'atomic-edge-security' ) ) );
     1493        }
     1494
     1495        wp_send_json_success( array( 'nonce' => wp_create_nonce( 'atomicedge_ajax' ) ) );
     1496    }
     1497
     1498    /**
    14641499     * Get the user ID for 2FA operations.
    14651500     *
  • atomic-edge-security/trunk/readme.txt

    r3476684 r3482336  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 2.5.0
     7Stable tag: 2.5.1
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    112112
    113113== Changelog ==
     114
     115= 2.5.1 =
     116* CHANGE: WAF Logs "Block IP" button renamed to "Blacklist" — now adds IPs to edge-level IP Blacklist instead of Adaptive Defense
     117* NEW: Dev mode support for WAF logs blacklist button
     118* NEW: AJAX nonce auto-refresh — expired nonces are transparently refreshed without page reload
    114119
    115120= 2.5.0 =
Note: See TracChangeset for help on using the changeset viewer.