Plugin Directory

Changeset 3763398


Ignore:
Timestamp:
10/24/2026 02:43:36 PM (21 hours ago)
Author:
joegomega
Message:

Update to version 2.19.0 from GitHub

Location:
mega-ai
Files:
6 added
4 edited
1 copied

Legend:

Unmodified
Added
Removed
  • mega-ai/tags/2.19.0/mega.php

    r3763355 r3763398  
    33Plugin Name: MEGA AI
    44Description: Connect your WordPress website to MEGA for automated SEO optimization and content management.
    5 Version: 2.17.2
     5Version: 2.19.0
    66Author: MEGA
    77Author URI: https://gomega.ai
    … …  
    3636require_once(__DIR__ . '/phone-replace.php');
    3737require_once(__DIR__ . '/page-cache-purge.php');
     38// Request authentication, signature v2 (see AGENTS.md, "Signature v2"). Loads its own helpers.
     39require_once(__DIR__ . '/auth-v2.php');
    3840
    3941use WP_REST_Server;
    … …  
    4446class MegaPlugin {
    4547    private static $namespace = 'mega';
    46     private static $version = '2.17.2';
     48    private static $version = '2.19.0';
    4749
    4850    // Editor (widget) endpoints.
    … …  
    161163   
    162164    // Default settings
    163     private static $default_public_key_endpoint = 'https://cdn.gomega.ai/keys/wp-public.key';
     165    private static $default_public_key_endpoint = MegaSigKeyPin::DEFAULT_ENDPOINT;
    164166    private static $default_change_log_endpoint = 'https://app.gomega.ai/api/agents/cms/change-log';
    165167    private static $change_log_max_queue_events = 100;
    … …  
    179181    /** The single plugin instance, for static callers outside the class. */
    180182    private static $instance;
     183    private $auth_v2 = null;
    181184
    182185    public function __construct() {
    … …  
    243246        \MegaIntentRunner::register();
    244247        MegaSandbox::register_hooks();
     248        MegaAuthV2::register_hooks();
    245249    }
    246250   
    … …  
    662666            $response->header('Pragma', 'no-cache');
    663667            $response->header('Expires', '0');
     668            $auth_result = MegaAuthV2::response_header_value();
     669            if ($auth_result !== null) {
     670                $response->header('X-Mega-Auth-Result', $auth_result);
     671            }
    664672        }
    665673       
    … …  
    680688   
    681689    /**
    682      * Authenticate requests using signature verification
     690     * Authenticate requests: signature v2 when the request carries v2 headers or the site is locked to
     691     * v2, otherwise the legacy v1 check below. See MegaAuthV2.
    683692     */
    684693    private function authenticate($request) {
     694        if ($this->auth_v2 === null) {
     695            $this->auth_v2 = new MegaAuthV2();
     696        }
     697        return $this->auth_v2->authenticate($request, array($this, 'authenticate_v1'));
     698    }
     699
     700    /**
     701     * Legacy (v1) authentication: RSA signature over the site identifier. Public only because
     702     * MegaAuthV2 calls it back; never call it directly.
     703     */
     704    public function authenticate_v1($request) {
    685705        $signature = $request->get_header('Signature');
    686706       
    … …  
    792812        }
    793813       
     814        // MEGA's own endpoint: the key must be one we ship a fingerprint for. A customer-set custom
     815        // endpoint keeps its legacy unpinned behaviour (v2 never reads that setting).
     816        if ($public_key_endpoint === self::$default_public_key_endpoint) {
     817            $pin = MegaSigKeyPin::check_pem($public_key);
     818            if (!$pin['ok']) {
     819                return new \WP_Error(
     820                    'mega_auth_key_pin_mismatch',
     821                    'Authentication failed: the public key served by the key endpoint is not one this plugin trusts.',
     822                    array('status' => 500, 'key_error' => $pin['error'])
     823                );
     824            }
     825            // Verify against exactly the key that passed the pin, not the raw response body.
     826            $public_key = $pin['pem'];
     827        }
     828
    794829        // Verify signature
    795830        $decoded_signature = base64_decode($signature, true);
    … …  
    15311566        }
    15321567
    1533         $response = array(
    1534             'seo_plugin' => $this->detect_seo_plugin(),
    1535             'change_log_secret' => $this->ensure_change_log_secret(),
    1536             'active_plugins' => $active_plugins,
    1537             'inactive_plugins' => $inactive_plugins
    1538         );
     1568        // The secret leaves the site only to a v1-authenticated request on a site that has not locked
     1569        // to v2: under v2 it is provisioned through the identifier rotation, never over this route.
     1570        $response = array('seo_plugin' => $this->detect_seo_plugin());
     1571        if (MegaAuthV2::authenticated_by_v1_on_unlocked_site()) {
     1572            $response['change_log_secret'] = $this->ensure_change_log_secret();
     1573        }
     1574        $response['active_plugins'] = $active_plugins;
     1575        $response['inactive_plugins'] = $inactive_plugins;
    15391576        // Omit (rather than send a fake {}/[]) when either check couldn't be
    15401577        // taken, so the platform can tell "clean" from "unknown".
    … …  
    72317268        </form>
    72327269        <?php
     7270        MegaAuthV2::render_admin_panel();
    72337271    }
    72347272   
    … …  
    1056310601// Without this the hourly sweep stays scheduled with no listener after deactivation.
    1056410602MegaSandbox::register_lifecycle(__FILE__);
     10603MegaAuthV2::register_lifecycle(__FILE__);
  • mega-ai/tags/2.19.0/readme.txt

    r3763355 r3763398  
    44Requires at least: 4.4
    55Tested up to: 6.8
    6 Stable tag: 2.17.2
     6Stable tag: 2.19.0
    77Requires PHP: 7.2
    88License: GPLv2 or later
    … …  
    139139
    140140== Changelog ==
     141= 2.19.0 =
     142* Security: stronger request authentication. The plugin can now verify requests that carry a per-request signature over the method, address, query, body and a single-use nonce, so a captured request is of little use to anyone else. MEGA turns this on for a site; until then requests are authenticated with the older signature format as before. Once a site has accepted its first such request it stops accepting the older signature format.
     143* Security: MEGA's public key is checked against fingerprints built into the plugin before it is used to verify a signature (the older format too, when the default key address is in use), and the verified key is cached for an hour.
     144* Change: `GET /mega/v1/plugins` returns `change_log_secret` only to an older-format request on a site that has not switched.
     145* Feature: if MEGA cannot connect after a server or proxy change, an administrator can reset request authentication from Settings > MEGA, or with `wp mega auth-reset`. Nothing can reset it remotely.
     146* Change: replay records for the new signatures are kept in the options table and removed hourly.
     147
    141148= 2.17.2 =
    142149* Packaging: the WordPress.org release no longer includes development and test files.
  • mega-ai/trunk/mega.php

    r3763355 r3763398  
    33Plugin Name: MEGA AI
    44Description: Connect your WordPress website to MEGA for automated SEO optimization and content management.
    5 Version: 2.17.2
     5Version: 2.19.0
    66Author: MEGA
    77Author URI: https://gomega.ai
    … …  
    3636require_once(__DIR__ . '/phone-replace.php');
    3737require_once(__DIR__ . '/page-cache-purge.php');
     38// Request authentication, signature v2 (see AGENTS.md, "Signature v2"). Loads its own helpers.
     39require_once(__DIR__ . '/auth-v2.php');
    3840
    3941use WP_REST_Server;
    … …  
    4446class MegaPlugin {
    4547    private static $namespace = 'mega';
    46     private static $version = '2.17.2';
     48    private static $version = '2.19.0';
    4749
    4850    // Editor (widget) endpoints.
    … …  
    161163   
    162164    // Default settings
    163     private static $default_public_key_endpoint = 'https://cdn.gomega.ai/keys/wp-public.key';
     165    private static $default_public_key_endpoint = MegaSigKeyPin::DEFAULT_ENDPOINT;
    164166    private static $default_change_log_endpoint = 'https://app.gomega.ai/api/agents/cms/change-log';
    165167    private static $change_log_max_queue_events = 100;
    … …  
    179181    /** The single plugin instance, for static callers outside the class. */
    180182    private static $instance;
     183    private $auth_v2 = null;
    181184
    182185    public function __construct() {
    … …  
    243246        \MegaIntentRunner::register();
    244247        MegaSandbox::register_hooks();
     248        MegaAuthV2::register_hooks();
    245249    }
    246250   
    … …  
    662666            $response->header('Pragma', 'no-cache');
    663667            $response->header('Expires', '0');
     668            $auth_result = MegaAuthV2::response_header_value();
     669            if ($auth_result !== null) {
     670                $response->header('X-Mega-Auth-Result', $auth_result);
     671            }
    664672        }
    665673       
    … …  
    680688   
    681689    /**
    682      * Authenticate requests using signature verification
     690     * Authenticate requests: signature v2 when the request carries v2 headers or the site is locked to
     691     * v2, otherwise the legacy v1 check below. See MegaAuthV2.
    683692     */
    684693    private function authenticate($request) {
     694        if ($this->auth_v2 === null) {
     695            $this->auth_v2 = new MegaAuthV2();
     696        }
     697        return $this->auth_v2->authenticate($request, array($this, 'authenticate_v1'));
     698    }
     699
     700    /**
     701     * Legacy (v1) authentication: RSA signature over the site identifier. Public only because
     702     * MegaAuthV2 calls it back; never call it directly.
     703     */
     704    public function authenticate_v1($request) {
    685705        $signature = $request->get_header('Signature');
    686706       
    … …  
    792812        }
    793813       
     814        // MEGA's own endpoint: the key must be one we ship a fingerprint for. A customer-set custom
     815        // endpoint keeps its legacy unpinned behaviour (v2 never reads that setting).
     816        if ($public_key_endpoint === self::$default_public_key_endpoint) {
     817            $pin = MegaSigKeyPin::check_pem($public_key);
     818            if (!$pin['ok']) {
     819                return new \WP_Error(
     820                    'mega_auth_key_pin_mismatch',
     821                    'Authentication failed: the public key served by the key endpoint is not one this plugin trusts.',
     822                    array('status' => 500, 'key_error' => $pin['error'])
     823                );
     824            }
     825            // Verify against exactly the key that passed the pin, not the raw response body.
     826            $public_key = $pin['pem'];
     827        }
     828
    794829        // Verify signature
    795830        $decoded_signature = base64_decode($signature, true);
    … …  
    15311566        }
    15321567
    1533         $response = array(
    1534             'seo_plugin' => $this->detect_seo_plugin(),
    1535             'change_log_secret' => $this->ensure_change_log_secret(),
    1536             'active_plugins' => $active_plugins,
    1537             'inactive_plugins' => $inactive_plugins
    1538         );
     1568        // The secret leaves the site only to a v1-authenticated request on a site that has not locked
     1569        // to v2: under v2 it is provisioned through the identifier rotation, never over this route.
     1570        $response = array('seo_plugin' => $this->detect_seo_plugin());
     1571        if (MegaAuthV2::authenticated_by_v1_on_unlocked_site()) {
     1572            $response['change_log_secret'] = $this->ensure_change_log_secret();
     1573        }
     1574        $response['active_plugins'] = $active_plugins;
     1575        $response['inactive_plugins'] = $inactive_plugins;
    15391576        // Omit (rather than send a fake {}/[]) when either check couldn't be
    15401577        // taken, so the platform can tell "clean" from "unknown".
    … …  
    72317268        </form>
    72327269        <?php
     7270        MegaAuthV2::render_admin_panel();
    72337271    }
    72347272   
    … …  
    1056310601// Without this the hourly sweep stays scheduled with no listener after deactivation.
    1056410602MegaSandbox::register_lifecycle(__FILE__);
     10603MegaAuthV2::register_lifecycle(__FILE__);
  • mega-ai/trunk/readme.txt

    r3763355 r3763398  
    44Requires at least: 4.4
    55Tested up to: 6.8
    6 Stable tag: 2.17.2
     6Stable tag: 2.19.0
    77Requires PHP: 7.2
    88License: GPLv2 or later
    … …  
    139139
    140140== Changelog ==
     141= 2.19.0 =
     142* Security: stronger request authentication. The plugin can now verify requests that carry a per-request signature over the method, address, query, body and a single-use nonce, so a captured request is of little use to anyone else. MEGA turns this on for a site; until then requests are authenticated with the older signature format as before. Once a site has accepted its first such request it stops accepting the older signature format.
     143* Security: MEGA's public key is checked against fingerprints built into the plugin before it is used to verify a signature (the older format too, when the default key address is in use), and the verified key is cached for an hour.
     144* Change: `GET /mega/v1/plugins` returns `change_log_secret` only to an older-format request on a site that has not switched.
     145* Feature: if MEGA cannot connect after a server or proxy change, an administrator can reset request authentication from Settings > MEGA, or with `wp mega auth-reset`. Nothing can reset it remotely.
     146* Change: replay records for the new signatures are kept in the options table and removed hourly.
     147
    141148= 2.17.2 =
    142149* Packaging: the WordPress.org release no longer includes development and test files.
Note: See TracChangeset for help on using the changeset viewer.