| @@ -48,9 +48,9 @@ | ||
| 48 | 48 | |
| 49 | 49 | $defaults = Helper::defaults(); |
| 50 | 50 | $saved = []; |
| 51 | 51 | |
| 52 | - foreach ( [ 'enabled', 'buffer_gating', 'dry_run', 'consent_mode', 'record_enabled', 'record_ip', 'hide_for_admins' ] as $key ) { | |
| 52 | + foreach ( [ 'enabled', 'buffer_gating', 'embed_gating', 'dry_run', 'consent_mode', 'consent_mode_ads', 'record_enabled', 'record_ip', 'hide_for_admins' ] as $key ) { | |
| 53 | 53 | // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash |
| 54 | 54 | $saved[ $key ] = isset( $_POST[ $key ] ) ? \ABlocks\Helper::sanitize_checkbox_field( $_POST[ $key ] ) : $defaults[ $key ]; |
| 55 | 55 | } |
| 56 | 56 | |
| @@ -100,8 +100,15 @@ | ||
| 100 | 100 | : $current; |
| 101 | 101 | |
| 102 | 102 | $saved['categories'] = $this->sanitize_categories( $this->post_json( 'categories' ), $defaults['categories'] ); |
| 103 | 103 | $saved['rules'] = $this->sanitize_rules( $this->post_json( 'rules' ) ); |
| 104 | + | |
| 105 | + // Embeds carry no pattern: the shipped list is the whole list and only | |
| 106 | + // the two decisions the screen offers can come back from the browser. | |
| 107 | + // Anything else in the payload is dropped rather than merged, so a | |
| 108 | + // crafted request cannot introduce a matcher of its own. | |
| 109 | + $saved['embed_rules'] = $this->sanitize_provider_rules( $this->post_json( 'embed_rules' ) ); | |
| 110 | + $saved['pixel_rules'] = $this->sanitize_provider_rules( $this->post_json( 'pixel_rules' ) ); | |
| 104 | 111 | $saved['banner'] = $this->sanitize_banner( $this->post_json( 'banner' ), $defaults['banner'] ); |
| 105 | 112 | |
| 106 | 113 | Helper::save_settings( $saved ); |
| 107 | 114 | |
| @@ -258,8 +265,38 @@ | ||
| 258 | 265 | /** |
| 259 | 266 | * @param array $input Submitted rules. |
| 260 | 267 | * @return array |
| 261 | 268 | */ |
| 269 | + /** | |
| 270 | + * Embed and pixel overrides: an id, whether it is on, and which category. | |
| 271 | + * | |
| 272 | + * Nothing else survives. The pattern that decides what a rule matches is | |
| 273 | + * not editable and is never read from the request, which is the reason a | |
| 274 | + * mis-typed setting here cannot blank a payment iframe. | |
| 275 | + * | |
| 276 | + * @param array $rules Raw rules from the request. | |
| 277 | + * @return array | |
| 278 | + */ | |
| 279 | + private function sanitize_provider_rules( $rules ) { | |
| 280 | + if ( ! is_array( $rules ) ) { | |
| 281 | + return []; | |
| 282 | + } | |
| 283 | + | |
| 284 | + $clean = []; | |
| 285 | + foreach ( $rules as $rule ) { | |
| 286 | + if ( empty( $rule['id'] ) ) { | |
| 287 | + continue; | |
| 288 | + } | |
| 289 | + $clean[] = [ | |
| 290 | + 'id' => sanitize_key( $rule['id'] ), | |
| 291 | + 'enabled' => ! empty( $rule['enabled'] ), | |
| 292 | + 'category' => isset( $rule['category'] ) ? sanitize_key( $rule['category'] ) : '', | |
| 293 | + ]; | |
| 294 | + } | |
| 295 | + | |
| 296 | + return $clean; | |
| 297 | + } | |
| 298 | + | |
| 262 | 299 | private function sanitize_rules( $input ) { |
| 263 | 300 | $can_author = Helper::can( 'custom_rules' ); |
| 264 | 301 | $shipped = Helper::shipped_rule_ids(); |
| 265 | 302 | $defaults = []; |