| @@ -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,31 +28,13 @@ | ||
| 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 | |
| 87 | 35 | ]; |
| 88 | 36 | |
| 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 | - // Define the actual widget filters that will be used when widget_text is enabled | |
| 97 | - private const WIDGET_FILTERS = [ | |
| 98 | - 'widget_text', // Legacy text widget (pre-4.9) | |
| 99 | - 'widget_text_content', // Modern text widget (4.9+) | |
| 100 | - 'widget_custom_html_content' // Custom HTML widget (4.8.1+) | |
| 101 | - ]; | |
| 102 | - | |
| 103 | 37 | private array $options; |
| 104 | 38 | private array $originalOptions; |
| 105 | 39 | |
| 106 | 40 | public function __construct(array $options = []) { |
| @@ -108,9 +42,9 @@ | ||
| 108 | 42 | $this->originalOptions = $this->options; |
| 109 | 43 | } |
| 110 | 44 | |
| 111 | 45 | public function getActiveFilters(): array { |
| 112 | - return array_filter(self::FILTERS, fn($filter) => | |
| 46 | + return array_filter($this->options['filter'], fn($filter) => | |
| 113 | 47 | isset($this->options[$filter]) && $this->options[$filter] |
| 114 | 48 | ); |
| 115 | 49 | } |
| 116 | 50 | |
| @@ -165,17 +99,8 @@ | ||
| 165 | 99 | public function getVersion(): ?string { |
| 166 | 100 | return $this->options['version']; |
| 167 | 101 | } |
| 168 | 102 | |
| 169 | - /** | |
| 170 | - * Get the actual widget filters to be applied | |
| 171 | - * | |
| 172 | - * @return array | |
| 173 | - */ | |
| 174 | - public function getWidgetFilters(): array { | |
| 175 | - return self::WIDGET_FILTERS; | |
| 176 | - } | |
| 177 | - | |
| 178 | 103 | public function updateFromShortcode(array $attributes, string $tag): void { |
| 179 | 104 | $this->originalOptions = $this->options; |
| 180 | 105 | $shortcodeOptions = shortcode_atts( |
| 181 | 106 | $this->options, |
| @@ -196,9 +121,9 @@ | ||
| 196 | 121 | public function update(array $newOptions): void |
| 197 | 122 | { |
| 198 | 123 | // Convert checkbox values to integers |
| 199 | 124 | foreach (['the_content', 'the_meta_key', 'the_excerpt', 'comment_text', |
| 200 | - 'widget_text', 'autolink', 'metaBox', 'disable_rss', 'use_secure_encryption'] as $key) { | |
| 125 | + 'widget_text', 'autolink', 'metaBox', 'disable_rss'] as $key) { | |
| 201 | 126 | if (isset($newOptions[$key])) { |
| 202 | 127 | $newOptions[$key] = (int)$newOptions[$key]; |
| 203 | 128 | } |
| 204 | 129 | } |
| @@ -219,19 +144,10 @@ | ||
| 219 | 144 | return $this->options; |
| 220 | 145 | } |
| 221 | 146 | |
| 222 | 147 | /** |
| 223 | - * Resets all options to their default values. | |
| 148 | + * Resets all options to their default values | |
| 224 | 149 | * |
| 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 | 150 | * @return void |
| 235 | 151 | */ |
| 236 | 152 | public function reset(): void |
| 237 | 153 | { |
| @@ -246,66 +162,6 @@ | ||
| 246 | 162 | $this->options['c2i_font'] = basename($fontFiles[0]); |
| 247 | 163 | } |
| 248 | 164 | |
| 249 | 165 | $this->save(); |
| 250 | - } | |
| 251 | - | |
| 252 | - /** | |
| 253 | - * Retrieves the encryption mode configured in the options. | |
| 254 | - * | |
| 255 | - * @return string Returns the encryption mode as a string. Defaults to 'secure' if not set. | |
| 256 | - */ | |
| 257 | - public function getEncryptionMode(): string | |
| 258 | - { | |
| 259 | - return $this->options['encryption_mode'] ?? 'secure'; | |
| 260 | - } | |
| 261 | - | |
| 262 | - /** | |
| 263 | - * Checks if secure encryption is enabled in the options. | |
| 264 | - * | |
| 265 | - * @return bool Returns true if secure encryption is enabled, false otherwise. | |
| 266 | - */ | |
| 267 | - public function isSecureEncryptionEnabled(): bool | |
| 268 | - { | |
| 269 | - return (bool) ($this->options['use_secure_encryption'] ?? true); | |
| 270 | - } | |
| 271 | - | |
| 272 | - /** | |
| 273 | - * Retrieves the encryption password configured in the options or generates a secure password if not set. | |
| 274 | - * | |
| 275 | - * @return string Returns the encryption password as a string. | |
| 276 | - */ | |
| 277 | - public function getEncryptionPassword(): string | |
| 278 | - { | |
| 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 | - 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 | - } | |
| 307 | - $this->save(); | |
| 308 | - } | |
| 309 | - return $this->options['encryption_password']; | |
| 310 | 166 | } |
| 311 | 167 | } |