AMP for WordPress - Version 0.5.1

Version Description

(2017-08-17) =

  • Fix: issues with invalid tags not being stripped out (e.g. script tags) (h/t tmmbecker, fahmi182, pppdog, seejacobscott, RavanH, jenniejj, lkraav, simonrperry for the reports).
  • Fix: issues with dimension extraction for protocol-less and relative URLs (h/t ktmn for the report).
Download this release

Release Info

Developer batmoo
Plugin Icon 128x128 AMP for WordPress
Version 0.5.1
Comparing to
See all releases

Code changes from version 0.5 to 0.5.1

amp.php CHANGED
@@ -5,7 +5,7 @@
5
  * Plugin URI: https://github.com/automattic/amp-wp
6
  * Author: Automattic
7
  * Author URI: https://automattic.com
8
- * Version: 0.5
9
  * Text Domain: amp
10
  * Domain Path: /languages/
11
  * License: GPLv2 or later
@@ -13,7 +13,7 @@
13
 
14
  define( 'AMP__FILE__', __FILE__ );
15
  define( 'AMP__DIR__', dirname( __FILE__ ) );
16
- define( 'AMP__VERSION', '0.5' );
17
 
18
  require_once( AMP__DIR__ . '/back-compat/back-compat.php' );
19
  require_once( AMP__DIR__ . '/includes/amp-helper-functions.php' );
5
  * Plugin URI: https://github.com/automattic/amp-wp
6
  * Author: Automattic
7
  * Author URI: https://automattic.com
8
+ * Version: 0.5.1
9
  * Text Domain: amp
10
  * Domain Path: /languages/
11
  * License: GPLv2 or later
13
 
14
  define( 'AMP__FILE__', __FILE__ );
15
  define( 'AMP__DIR__', dirname( __FILE__ ) );
16
+ define( 'AMP__VERSION', '0.5.1' );
17
 
18
  require_once( AMP__DIR__ . '/back-compat/back-compat.php' );
19
  require_once( AMP__DIR__ . '/includes/amp-helper-functions.php' );
includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php CHANGED
@@ -83,7 +83,6 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
83
 
84
  // Remove nodes with non-whitelisted tags.
85
  if ( ! $this->is_amp_allowed_tag( $node ) ) {
86
-
87
  // If it's not an allowed tag, replace the node with it's children
88
  $this->replace_node_with_children( $node );
89
  // Return early since this node no longer exists.
@@ -109,52 +108,61 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
109
  }
110
 
111
  // The remaining validations all have to do with attributes.
112
- if ( $node->hasAttributes() ) {
113
- $attr_spec_list = array();
114
-
115
- // If we have exactly one rule_spec, use it's attr_spec_list to
116
- // validate the node's attributes.
117
- if ( 1 == count( $rule_spec_list_to_validate ) ) {
118
- $rule_spec = array_pop( $rule_spec_list_to_validate );
119
- $attr_spec_list = $rule_spec[AMP_Rule_Spec::ATTR_SPEC_LIST];
120
 
 
 
 
 
 
 
121
  // If there is more than one valid rule_spec for this node, then
122
  // try to deduce which one is intended by inspecting the node's
123
  // attributes.
124
- } else {
125
 
126
- // Get a score from each attr_spec_list by seeing how many
127
- // attributes and values match the node.
128
- $attr_spec_scores = array();
129
- foreach ( $rule_spec_list_to_validate as $spec_id => $rule_spec ) {
130
- $attr_spec_scores[ $spec_id ] = $this->validate_attr_spec_list_for_node( $node, $rule_spec[AMP_Rule_Spec::ATTR_SPEC_LIST] );
131
- }
132
-
133
- // Get the key(s) to the highest score(s).
134
- $spec_ids_sorted = array_keys( $attr_spec_scores, max( $attr_spec_scores ) );
135
 
136
- // If there is exactly one attr_spec with a max score, use that one.
137
- if ( 1 == count( $spec_ids_sorted ) ) {
138
- $attr_spec_list = $rule_spec_list_to_validate[ $spec_ids_sorted[0] ][AMP_Rule_Spec::ATTR_SPEC_LIST];
139
 
140
- // Otherwise...
141
- } else {
142
- // This shoud not happen very often, but...
143
- // If we're here, then we have no idea which spec should
144
- // be used. Try to merge the top scoring ones and cross
145
- // your fingers.
146
- foreach( $spec_ids_sorted as $id ) {
147
- $attr_spec_list = array_merge( $attr_spec_list, $rule_spec_list_to_validate[ $id ][AMP_Rule_Spec::ATTR_SPEC_LIST] );
148
- }
 
149
  }
150
  }
 
151
 
152
- // Remove any remaining disallowed attributes.
153
- $this->sanitize_disallowed_attributes_in_node( $node, $attr_spec_list );
 
 
 
 
 
154
 
155
- // Remove values that don't conform to the attr_spec.
156
- $this->sanitize_disallowed_attribute_values_in_node( $node, $attr_spec_list );
 
 
157
  }
 
 
 
 
 
 
158
  }
159
 
160
  /**
@@ -167,7 +175,6 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
167
  * return true.
168
  */
169
  private function validate_tag_spec_for_node( $node, $tag_spec ) {
170
-
171
  if ( ! empty( $tag_spec[AMP_Rule_Spec::MANDATORY_PARENT] ) &&
172
  ! $this->has_parent( $node, $tag_spec[AMP_Rule_Spec::MANDATORY_PARENT] ) ) {
173
  return false;
@@ -364,66 +371,58 @@ class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
364
  }
365
  }
366
 
 
 
367
  foreach( $node->attributes as $attr_name => $attr_node ) {
368
 
369
  if ( ! isset( $attr_spec_list[$attr_name] ) ) {
370
  continue;
371
  }
372
 
373
- $attr_spec_rule = $attr_spec_list[$attr_name];
 
374
 
375
  if ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE] ) &&
376
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_value( $node, $attr_name, $attr_spec_rule ) ) {
377
- $attrs_to_remove[] = $attr_name;
378
- continue;
379
- }
380
-
381
- if ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_CASEI] ) &&
382
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_value_casei( $node, $attr_name, $attr_spec_rule ) ) {
383
- $attrs_to_remove[] = $attr_name;
384
- continue;
385
- }
386
-
387
- if ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_REGEX] ) &&
388
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
389
- $attrs_to_remove[] = $attr_name;
390
- continue;
391
- }
392
-
393
- if ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_REGEX_CASEI] ) &&
394
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_value_regex_casei( $node, $attr_name, $attr_spec_rule ) ) {
395
- $attrs_to_remove[] = $attr_name;
396
- continue;
397
- }
398
-
399
- if ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOWED_PROTOCOL] ) &&
400
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_allowed_protocol( $node, $attr_name, $attr_spec_rule ) ) {
401
- $attrs_to_remove[] = $attr_name;
402
- continue;
403
- }
404
-
405
- if ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOW_RELATIVE] ) &&
406
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_disallowed_relative( $node, $attr_name, $attr_spec_rule ) ) {
407
- $attrs_to_remove[] = $attr_name;
408
- continue;
409
- }
410
-
411
- if ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOW_EMPTY] ) &&
412
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_disallowed_empty( $node, $attr_name, $attr_spec_rule ) ) {
413
- $attrs_to_remove[] = $attr_name;
414
- continue;
415
- }
416
-
417
- if ( isset( $attr_spec_rule[AMP_Rule_Spec::DISALLOWED_DOMAIN] ) &&
418
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_disallowed_domain( $node, $attr_name, $attr_spec_rule ) ) {
419
- $attrs_to_remove[] = $attr_name;
420
- continue;
 
 
421
  }
422
 
423
- if ( isset( $attr_spec_rule[AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX] ) &&
424
- AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_blacklisted_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
 
 
 
 
 
 
 
 
 
425
  $attrs_to_remove[] = $attr_name;
426
- continue;
427
  }
428
  }
429
 
83
 
84
  // Remove nodes with non-whitelisted tags.
85
  if ( ! $this->is_amp_allowed_tag( $node ) ) {
 
86
  // If it's not an allowed tag, replace the node with it's children
87
  $this->replace_node_with_children( $node );
88
  // Return early since this node no longer exists.
108
  }
109
 
110
  // The remaining validations all have to do with attributes.
111
+ $attr_spec_list = array();
 
 
 
 
 
 
 
112
 
113
+ // If we have exactly one rule_spec, use it's attr_spec_list to
114
+ // validate the node's attributes.
115
+ if ( 1 == count( $rule_spec_list_to_validate ) ) {
116
+ $rule_spec = array_pop( $rule_spec_list_to_validate );
117
+ $attr_spec_list = $rule_spec[AMP_Rule_Spec::ATTR_SPEC_LIST];
118
+ } else {
119
  // If there is more than one valid rule_spec for this node, then
120
  // try to deduce which one is intended by inspecting the node's
121
  // attributes.
 
122
 
123
+ // Get a score from each attr_spec_list by seeing how many
124
+ // attributes and values match the node.
125
+ $attr_spec_scores = array();
126
+ foreach ( $rule_spec_list_to_validate as $spec_id => $rule_spec ) {
127
+ $attr_spec_scores[ $spec_id ] = $this->validate_attr_spec_list_for_node( $node, $rule_spec[AMP_Rule_Spec::ATTR_SPEC_LIST] );
128
+ }
 
 
 
129
 
130
+ // Get the key(s) to the highest score(s).
131
+ $spec_ids_sorted = array_keys( $attr_spec_scores, max( $attr_spec_scores ) );
 
132
 
133
+ // If there is exactly one attr_spec with a max score, use that one.
134
+ if ( 1 == count( $spec_ids_sorted ) ) {
135
+ $attr_spec_list = $rule_spec_list_to_validate[ $spec_ids_sorted[0] ][AMP_Rule_Spec::ATTR_SPEC_LIST];
136
+ // Otherwise...
137
+ } else {
138
+ // This should not happen very often, but...
139
+ // If we're here, then we're not sure which spec should
140
+ // be used. Let's use the top scoring ones.
141
+ foreach( $spec_ids_sorted as $id ) {
142
+ $attr_spec_list = array_merge( $attr_spec_list, $rule_spec_list_to_validate[ $id ][AMP_Rule_Spec::ATTR_SPEC_LIST] );
143
  }
144
  }
145
+ }
146
 
147
+ // If an attribute is mandatory and we don't have it, just remove the node and move on.
148
+ foreach ( $attr_spec_list as $attr_name => $attr_spec_rule_value ) {
149
+ $is_mandatory =
150
+ isset( $attr_spec_rule_value[ AMP_Rule_Spec::MANDATORY ] )
151
+ ? (bool) $attr_spec_rule_value[ AMP_Rule_Spec::MANDATORY ]
152
+ : false;
153
+ $attribute_exists = $node->hasAttribute( $attr_name );
154
 
155
+ if ( $is_mandatory && ! $attribute_exists ) {
156
+ $this->remove_node( $node );
157
+ return;
158
+ }
159
  }
160
+
161
+ // Remove any remaining disallowed attributes.
162
+ $this->sanitize_disallowed_attributes_in_node( $node, $attr_spec_list );
163
+
164
+ // Remove values that don't conform to the attr_spec.
165
+ $this->sanitize_disallowed_attribute_values_in_node( $node, $attr_spec_list );
166
  }
167
 
168
  /**
175
  * return true.
176
  */
177
  private function validate_tag_spec_for_node( $node, $tag_spec ) {
 
178
  if ( ! empty( $tag_spec[AMP_Rule_Spec::MANDATORY_PARENT] ) &&
179
  ! $this->has_parent( $node, $tag_spec[AMP_Rule_Spec::MANDATORY_PARENT] ) ) {
180
  return false;
371
  }
372
  }
373
 
374
+ $mandatory_attributes = array();
375
+
376
  foreach( $node->attributes as $attr_name => $attr_node ) {
377
 
378
  if ( ! isset( $attr_spec_list[$attr_name] ) ) {
379
  continue;
380
  }
381
 
382
+ $should_remove_node = false;
383
+ $attr_spec_rule = $attr_spec_list[ $attr_name ];
384
 
385
  if ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE] ) &&
386
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_value( $node, $attr_name, $attr_spec_rule ) ) {
387
+ $should_remove_node = true;
388
+ } elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_CASEI] ) &&
 
 
 
389
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_value_casei( $node, $attr_name, $attr_spec_rule ) ) {
390
+ $should_remove_node = true;
391
+ } elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_REGEX] ) &&
 
 
 
392
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
393
+ $should_remove_node = true;
394
+ } elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::VALUE_REGEX_CASEI] ) &&
 
 
 
395
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_value_regex_casei( $node, $attr_name, $attr_spec_rule ) ) {
396
+ $should_remove_node = true;
397
+ } elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOWED_PROTOCOL] ) &&
 
 
 
398
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_allowed_protocol( $node, $attr_name, $attr_spec_rule ) ) {
399
+ $should_remove_node = true;
400
+ } elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOW_RELATIVE] ) &&
 
 
 
401
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_disallowed_relative( $node, $attr_name, $attr_spec_rule ) ) {
402
+ $should_remove_node = true;
403
+ } elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::ALLOW_EMPTY] ) &&
 
 
 
404
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_disallowed_empty( $node, $attr_name, $attr_spec_rule ) ) {
405
+ $should_remove_node = true;
406
+ } elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::DISALLOWED_DOMAIN] ) &&
 
 
 
407
  AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_disallowed_domain( $node, $attr_name, $attr_spec_rule ) ) {
408
+ $should_remove_node = true;
409
+ } elseif ( isset( $attr_spec_rule[AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX] ) &&
410
+ AMP_Rule_Spec::FAIL == $this->check_attr_spec_rule_blacklisted_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
411
+ $should_remove_node = true;
412
  }
413
 
414
+ if ( $should_remove_node ) {
415
+ $is_mandatory =
416
+ isset( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] )
417
+ ? (bool) $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ]
418
+ : false;
419
+
420
+ if ( $is_mandatory ) {
421
+ $this->remove_node( $node );
422
+ return;
423
+ }
424
+
425
  $attrs_to_remove[] = $attr_name;
 
426
  }
427
  }
428
 
includes/utils/class-amp-image-dimension-extractor.php CHANGED
@@ -10,18 +10,32 @@ class AMP_Image_Dimension_Extractor {
10
  self::register_callbacks();
11
  }
12
 
13
- $valid_urls = array();
14
- foreach ( $urls as $url ) {
15
- $url = self::normalize_url( $url );
16
- if ( false !== $url ) {
17
- $valid_urls[] = $url;
 
 
 
 
 
 
 
 
18
  }
19
  }
20
 
21
- $dimensions = array_fill_keys( $valid_urls, false );
22
- $dimensions = apply_filters( 'amp_extract_image_dimensions_batch', $dimensions );
23
 
24
- return $dimensions;
 
 
 
 
 
 
25
  }
26
 
27
  public static function normalize_url( $url ) {
10
  self::register_callbacks();
11
  }
12
 
13
+ $return_dimensions = array();
14
+
15
+ // Normalize URLs and also track a map of normalized-to-original as we'll need it to reformat things when returning the data.
16
+ $url_map = array();
17
+ $normalized_urls = array();
18
+ foreach ( $urls as $original_url ) {
19
+ $normalized_url = self::normalize_url( $original_url );
20
+ if ( false !== $normalized_url ) {
21
+ $url_map[ $normalized_url ] = $original_url;
22
+ $normalized_urls[] = $normalized_url;
23
+ } else {
24
+ // This is not a URL we can extract dimensions from, so default to false.
25
+ $return_dimensions[ $original_url ] = false;
26
  }
27
  }
28
 
29
+ $extracted_dimensions = array_fill_keys( $normalized_urls, false );
30
+ $extracted_dimensions = apply_filters( 'amp_extract_image_dimensions_batch', $extracted_dimensions );
31
 
32
+ // We need to return a map with the original (un-normalized URL) as we that to match nodes that need dimensions.
33
+ foreach ( $extracted_dimensions as $normalized_url => $dimension ) {
34
+ $original_url = $url_map[ $normalized_url ];
35
+ $return_dimensions[ $original_url ] = $dimension;
36
+ }
37
+
38
+ return $return_dimensions;
39
  }
40
 
41
  public static function normalize_url( $url ) {
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === AMP ===
2
- Contributors: batmoo, joen, automattic, potatomaster
3
  Tags: amp, mobile
4
  Requires at least: 4.7
5
  Tested up to: 4.8
6
- Stable tag: 0.5
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -53,6 +53,11 @@ A wise green Yoda once said, "Patience you must have, my young padawan." We're w
53
 
54
  == Changelog ==
55
 
 
 
 
 
 
56
  = 0.5 (2017-08-04) =
57
 
58
  - Whitelist Sanitizer: Replace Blacklist Sanitizer with a whitelist-based approach using the AMP spec (props delputnam)
1
  === AMP ===
2
+ Contributors: batmoo, joen, automattic, potatomaster, albertomedina
3
  Tags: amp, mobile
4
  Requires at least: 4.7
5
  Tested up to: 4.8
6
+ Stable tag: 0.5.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
53
 
54
  == Changelog ==
55
 
56
+ = 0.5.1 (2017-08-17) =
57
+
58
+ - Fix: issues with invalid tags not being stripped out (e.g. script tags) (h/t tmmbecker, fahmi182, pppdog, seejacobscott, RavanH, jenniejj, lkraav, simonrperry for the reports).
59
+ - Fix: issues with dimension extraction for protocol-less and relative URLs (h/t ktmn for the report).
60
+
61
  = 0.5 (2017-08-04) =
62
 
63
  - Whitelist Sanitizer: Replace Blacklist Sanitizer with a whitelist-based approach using the AMP spec (props delputnam)