| @@ -2,56 +2,8 @@ | ||
| 2 | 2 | |
| 3 | 3 | namespace CryptX; |
| 4 | 4 | |
| 5 | 5 | final class Config { |
| 6 | - /** | |
| 7 | - * Default configuration options for the application. | |
| 8 | - * | |
| 9 | - * This array provides the default settings and values for various | |
| 10 | - * features and behaviors of the application. These options can be | |
| 11 | - * customized to suit specific implementation requirements. | |
| 12 | - * | |
| 13 | - * Keys and their purposes: | |
| 14 | - * - 'version': The version of the application (default: null). | |
| 15 | - * - 'at': Replacement string for the "@" symbol (default: ' [at] '). | |
| 16 | - * - 'dot': Replacement string for the "." symbol (default: ' [dot] '). | |
| 17 | - * - 'css_id': CSS ID to use for specific elements (default: ''). | |
| 18 | - * - 'css_class': CSS class to use for specific elements (default: ''). | |
| 19 | - * - 'the_content': Flag to enable processing on content (default: 1). | |
| 20 | - * On block themes this filter is swapped for 'render_block' | |
| 21 | - * at runtime, see CryptX::initializePluginFilters(). There is | |
| 22 | - * no separate option for it. | |
| 23 | - * - 'the_meta_key': Flag to enable processing on meta keys (default: 1). | |
| 24 | - * - 'the_excerpt': Flag to enable processing on excerpts (default: 1). | |
| 25 | - * - 'comment_text': Flag to enable processing on comments (default: 1). | |
| 26 | - * - 'widget_text': Flag to enable processing in widgets (default: 1). | |
| 27 | - * - 'java': Flag indicating JavaScript-related configurations (default: 1). | |
| 28 | - * - 'load_java': Flag to enable JavaScript loading (default: 1). | |
| 29 | - * - 'opt_linktext': Option for link text settings (default: 0). | |
| 30 | - * - 'autolink': Flag to enable auto-linking of content (default: 1). | |
| 31 | - * - 'alt_linktext': Alternative text for links (default: ''). | |
| 32 | - * - 'alt_linkimage': Alternative image for links (default: ''). | |
| 33 | - * - 'http_linkimage_title': Link image title with HTTP reference (default: ''). | |
| 34 | - * - 'alt_linkimage_title': Alternative title for the link image (default: ''). | |
| 35 | - * - 'excludedIDs': IDs to exclude from processing (default: ''). | |
| 36 | - * - 'metaBox': Flag to enable or disable meta box features (default: 1). | |
| 37 | - * - 'alt_uploadedimage': Alternative uploaded image setting (default: '0'). | |
| 38 | - * - 'c2i_font': Custom font setting (default: null). | |
| 39 | - * - 'c2i_fontSize': Font size for configuration (default: 10). | |
| 40 | - * - 'c2i_fontRGB': Font color in RGB format (default: '#000000'). | |
| 41 | - * - 'echo': Flag to enable output directly to the browser (default: 1). | |
| 42 | - * - 'whiteList': Comma-separated string of allowed file extensions (default: 'jpeg,jpg,png,gif'). | |
| 43 | - * - 'disable_rss': Flag to disable CryptX in RSS feeds by default (default: 1). | |
| 44 | - * - 'encryption_mode': Encryption mode setting (default: 'secure'). | |
| 45 | - * - 'encryption_password': Password for encryption; a random secret is generated | |
| 46 | - * on first use if null and then kept forever (default: null). | |
| 47 | - * - 'use_secure_encryption': Flag to enable secure encryption by default (default: 1). | |
| 48 | - * - 'iterations': PBKDF2 iteration count for the secure mode (default: 10000). | |
| 49 | - * - 'link_mode': How the encrypted link is delivered -- 'data' puts the payload | |
| 50 | - * into data attributes and lets a delegated click handler take | |
| 51 | - * over (survives a Content-Security-Policy), 'js' is the historical | |
| 52 | - * "javascript:" URI (default: 'data'). | |
| 53 | - */ | |
| 54 | 6 | private const DEFAULT_OPTIONS = [ |
| 55 | 7 | 'version' => null, |
| 56 | 8 | 'at' => ' [at] ', |
| 57 | 9 | 'dot' => ' [dot] ', |
| @@ -76,24 +28,16 @@ | ||
| 76 | 28 | 'c2i_font' => null, |
| 77 | 29 | 'c2i_fontSize' => 10, |
| 78 | 30 | 'c2i_fontRGB' => '#000000', |
| 79 | 31 | 'echo' => 1, |
| 32 | + 'filter' => ['the_content', 'the_meta_key', 'the_excerpt', 'comment_text', 'widget_text'], | |
| 80 | 33 | 'whiteList' => 'jpeg,jpg,png,gif', |
| 81 | - 'disable_rss' => 1, | |
| 82 | - 'encryption_mode' => 'secure', | |
| 83 | - 'encryption_password' => null, | |
| 84 | - 'use_secure_encryption' => 1, | |
| 85 | - 'iterations' => 10000, | |
| 86 | - 'link_mode' => 'data', | |
| 34 | + 'disable_rss' => 1, // Disable CryptX in RSS feeds by default | |
| 35 | + 'encryption_mode' => 'secure', // Changed to 'secure' by default | |
| 36 | + 'encryption_password' => null, // Will be auto-generated if null | |
| 37 | + 'use_secure_encryption' => 1, // Enable secure encryption by default | |
| 87 | 38 | ]; |
| 88 | 39 | |
| 89 | - /** | |
| 90 | - * An array of filter names used within the application. | |
| 91 | - * These filters are commonly applied to various types of content, | |
| 92 | - * including posts, comments, and widgets. | |
| 93 | - */ | |
| 94 | - private const FILTERS = ['the_content', 'the_meta_key', 'the_excerpt', 'comment_text', 'widget_text']; | |
| 95 | - | |
| 96 | 40 | // Define the actual widget filters that will be used when widget_text is enabled |
| 97 | 41 | private const WIDGET_FILTERS = [ |
| 98 | 42 | 'widget_text', // Legacy text widget (pre-4.9) |
| 99 | 43 | 'widget_text_content', // Modern text widget (4.9+) |
| @@ -108,9 +52,9 @@ | ||
| 108 | 52 | $this->originalOptions = $this->options; |
| 109 | 53 | } |
| 110 | 54 | |
| 111 | 55 | public function getActiveFilters(): array { |
| 112 | - return array_filter(self::FILTERS, fn($filter) => | |
| 56 | + return array_filter($this->options['filter'], fn($filter) => | |
| 113 | 57 | isset($this->options[$filter]) && $this->options[$filter] |
| 114 | 58 | ); |
| 115 | 59 | } |
| 116 | 60 | |
| @@ -219,19 +163,10 @@ | ||
| 219 | 163 | return $this->options; |
| 220 | 164 | } |
| 221 | 165 | |
| 222 | 166 | /** |
| 223 | - * Resets all options to their default values. | |
| 167 | + * Resets all options to their default values | |
| 224 | 168 | * |
| 225 | - * Careful before wiring this up again: it has had no caller since 4.1.0, | |
| 226 | - * because the settings screen resets through SettingsSchema instead. This | |
| 227 | - * method sets the whole array to DEFAULT_OPTIONS, in which | |
| 228 | - * encryption_password is null -- and then saves. That discards the secret | |
| 229 | - * every already delivered link was encrypted with, so those links stop | |
| 230 | - * resolving until the pages are regenerated. SettingsSchema::defaults() | |
| 231 | - * covers only the editable options and leaves the secret alone, which is | |
| 232 | - * why the REST route uses it. | |
| 233 | - * | |
| 234 | 169 | * @return void |
| 235 | 170 | */ |
| 236 | 171 | public function reset(): void |
| 237 | 172 | { |
| @@ -275,37 +210,16 @@ | ||
| 275 | 210 | * @return string Returns the encryption password as a string. |
| 276 | 211 | */ |
| 277 | 212 | public function getEncryptionPassword(): string |
| 278 | 213 | { |
| 279 | - // A stored password is returned untouched and is NEVER regenerated. | |
| 280 | - // The password is baked into every link this plugin has ever emitted, | |
| 281 | - // so a new one would turn all already delivered and cached pages into | |
| 282 | - // undecryptable garbage. Only a missing (or empty) value is filled in. | |
| 283 | 214 | if (empty($this->options['encryption_password'])) { |
| 284 | - // Random secret instead of a value derived from the WordPress keys. | |
| 285 | - // Rationale: this password is published. It is handed to the browser | |
| 286 | - // as the second argument of the generated | |
| 287 | - // javascript:secureDecryptAndNavigate(...) link and therefore sits | |
| 288 | - // in the HTML of every page in clear text. Deriving it from AUTH_KEY | |
| 289 | - // and SECURE_AUTH_KEY was not reversible, but there is no reason to | |
| 290 | - // publish anything at all that is a function of the site's secrets. | |
| 291 | - // | |
| 292 | - // bin2hex(random_bytes(32)) is the choice because random_bytes() is | |
| 293 | - // the platform CSPRNG (always available on the required PHP 8.1+, | |
| 294 | - // not filterable by other plugins) and hex output is pure [0-9a-f]: | |
| 295 | - // it survives every escaping stage on the way into the JavaScript | |
| 296 | - // string literal and into the option row unchanged. 32 bytes = 256 | |
| 297 | - // bits, matching the AES-256 key later derived from it via PBKDF2. | |
| 298 | - try { | |
| 299 | - $this->options['encryption_password'] = bin2hex(random_bytes(32)); | |
| 300 | - } catch (\Throwable $e) { | |
| 301 | - // random_bytes() throws when the system has no usable source of | |
| 302 | - // randomness. wp_generate_password() then provides the fallback; | |
| 303 | - // 64 chars without special characters keeps the value safe to | |
| 304 | - // embed unescaped. | |
| 305 | - $this->options['encryption_password'] = wp_generate_password(64, false, false); | |
| 306 | - } | |
| 215 | + // Generate a secure password based on WordPress keys | |
| 216 | + $this->options['encryption_password'] = hash('sha256', | |
| 217 | + (defined('AUTH_KEY') ? AUTH_KEY : '') . | |
| 218 | + (defined('SECURE_AUTH_KEY') ? SECURE_AUTH_KEY : '') . | |
| 219 | + get_site_url() | |
| 220 | + ); | |
| 307 | 221 | $this->save(); |
| 308 | 222 | } |
| 309 | 223 | return $this->options['encryption_password']; |
| 310 | 224 | } |
| 311 | 225 | } |