From e111fa4af193eb28fe7420b5e897d2717fb8a2a3 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 30 Aug 2018 12:32:52 -0700 Subject: [PATCH 01/11] Update spec to file revision 720 (v1534879991178) * Add components for amp-image-slider, amp-viqeo-player, * Add when-ended=continue to amp-date-countdown. * Add [open] to amp-lightbox. * Add disable-double-tap to amp-pan-zoom. --- .../class-amp-allowed-tags-generated.php | 148 +++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) diff --git a/includes/sanitizers/class-amp-allowed-tags-generated.php b/includes/sanitizers/class-amp-allowed-tags-generated.php index c12d90067c7..aa17d521933 100644 --- a/includes/sanitizers/class-amp-allowed-tags-generated.php +++ b/includes/sanitizers/class-amp-allowed-tags-generated.php @@ -13,7 +13,7 @@ */ class AMP_Allowed_Tags_Generated { - private static $spec_file_revision = 712; + private static $spec_file_revision = 720; private static $minimum_validator_revision_required = 348; private static $allowed_tags = array( @@ -1284,6 +1284,7 @@ class AMP_Allowed_Tags_Generated { ), 'when-ended' => array( 'value_casei' => array( + 'continue', 'stop', ), ), @@ -2340,6 +2341,33 @@ class AMP_Allowed_Tags_Generated { ), ), ), + 'amp-image-slider' => array( + array( + 'attr_spec_list' => array( + 'disable-hint-reappear' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 2, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-image-slider', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-image-slider', + ), + ), + ), 'amp-img' => array( array( 'attr_spec_list' => array( @@ -2598,6 +2626,7 @@ class AMP_Allowed_Tags_Generated { 9, 1, 4, + 5, ), ), 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-layout', @@ -2607,6 +2636,7 @@ class AMP_Allowed_Tags_Generated { 'amp-lightbox' => array( array( 'attr_spec_list' => array( + '[open]' => array(), 'animate-in' => array( 'value_casei' => array( 'fade-in', @@ -2951,6 +2981,11 @@ class AMP_Allowed_Tags_Generated { 'amp-pan-zoom' => array( array( 'attr_spec_list' => array( + 'disable-double-tap' => array( + 'value' => array( + '', + ), + ), 'initial-scale' => array( 'value_regex' => '[0-9]+(\\.[0-9]+)?', ), @@ -4097,6 +4132,40 @@ class AMP_Allowed_Tags_Generated { ), ), ), + 'amp-viqeo-player' => array( + array( + 'attr_spec_list' => array( + 'autoplay' => array(), + 'data-profileid' => array( + 'mandatory' => true, + 'value_regex' => '[0-9a-f]*', + ), + 'data-videoid' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-viqeo-player', + ), + ), + ), + ), 'amp-vk' => array( array( 'attr_spec_list' => array( @@ -4961,6 +5030,30 @@ class AMP_Allowed_Tags_Generated { 'spec_name' => 'FORM DIV [submit-error][template]', ), ), + array( + 'attr_spec_list' => array( + 'first' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'amp-image-slider', + 'spec_name' => 'AMP-IMAGE-SLIDER > DIV [first]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-image-slider', + ), + ), + array( + 'attr_spec_list' => array( + 'second' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'amp-image-slider', + 'spec_name' => 'AMP-IMAGE-SLIDER > DIV [second]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-image-slider', + ), + ), ), 'dl' => array( array( @@ -10082,6 +10175,31 @@ class AMP_Allowed_Tags_Generated { ), ), ), + array( + 'attr_spec_list' => array( + 'async' => array( + 'mandatory' => true, + 'value' => array( + '', + ), + ), + 'nonce' => array(), + 'type' => array( + 'value_casei' => array( + 'text/javascript', + ), + ), + ), + 'tag_spec' => array( + 'extension_spec' => array( + 'name' => 'amp-image-slider', + 'version' => array( + '0.1', + 'latest', + ), + ), + ), + ), array( 'attr_spec_list' => array( 'async' => array( @@ -11247,6 +11365,31 @@ class AMP_Allowed_Tags_Generated { ), ), ), + array( + 'attr_spec_list' => array( + 'async' => array( + 'mandatory' => true, + 'value' => array( + '', + ), + ), + 'nonce' => array(), + 'type' => array( + 'value_casei' => array( + 'text/javascript', + ), + ), + ), + 'tag_spec' => array( + 'extension_spec' => array( + 'name' => 'amp-viqeo-player', + 'version' => array( + '0.1', + 'latest', + ), + ), + ), + ), array( 'attr_spec_list' => array( 'async' => array( @@ -11916,6 +12059,9 @@ class AMP_Allowed_Tags_Generated { 'stroke-miterlimit' => array(), 'stroke-opacity' => array(), 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), 'systemlanguage' => array(), 'text-anchor' => array(), 'text-decoration' => array(), From 549c7b03b013f82a09b53ad61a1d5e0f9d729797 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 30 Aug 2018 13:46:13 -0700 Subject: [PATCH 02/11] Improve ability to see differences in sanitized markup --- tests/test-tag-and-attribute-sanitizer.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test-tag-and-attribute-sanitizer.php b/tests/test-tag-and-attribute-sanitizer.php index 3eb250a3063..173a7e9c922 100644 --- a/tests/test-tag-and-attribute-sanitizer.php +++ b/tests/test-tag-and-attribute-sanitizer.php @@ -214,6 +214,12 @@ public function get_body_data() { array( 'amp-playbuzz' ), ), + 'amp-next-page' => array( + '

Keep reading

', + null, + array( 'amp-next-page' ), + ), + 'amp-position-observer' => array( '', null, // No change. @@ -917,6 +923,12 @@ public function test_body_sanitizer( $source, $expected = null, $scripts = array $sanitizer->sanitize(); $content = AMP_DOM_Utils::get_content_from_dom( $dom ); $content = preg_replace( '/(?<=>)\s+(?=<)/', '', $content ); + preg_match_all( '#<.+?>#', $expected, $expected_matches ); + preg_match_all( '#<.+?>#', $content, $content_matches ); + $this->assertEquals( + $expected_matches, + $content_matches + ); $this->assertEquals( $expected, $content ); $this->assertEqualSets( $scripts, array_keys( $sanitizer->get_scripts() ) ); } @@ -1017,6 +1029,12 @@ public function test_html_sanitizer( $source, $expected = null, $scripts = array $sanitizer->sanitize(); $content = AMP_DOM_Utils::get_content_from_dom_node( $dom, $dom->documentElement ); $content = preg_replace( '/(?<=>)\s+(?=<)/', '', $content ); + preg_match_all( '#<.+?>#', $expected, $expected_matches ); + preg_match_all( '#<.+?>#', $content, $content_matches ); + $this->assertEquals( + $expected_matches, + $content_matches + ); $this->assertEquals( $expected, $content ); $this->assertEqualSets( $scripts, array_keys( $sanitizer->get_scripts() ) ); } From e9ffbcb257c5a0b316c340fff48ffe36e4291a18 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 30 Aug 2018 13:54:04 -0700 Subject: [PATCH 03/11] Add tests that intentionally fail, showing reference point problems --- tests/test-tag-and-attribute-sanitizer.php | 65 +++++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/tests/test-tag-and-attribute-sanitizer.php b/tests/test-tag-and-attribute-sanitizer.php index 173a7e9c922..4f53b947e03 100644 --- a/tests/test-tag-and-attribute-sanitizer.php +++ b/tests/test-tag-and-attribute-sanitizer.php @@ -214,12 +214,71 @@ public function get_body_data() { array( 'amp-playbuzz' ), ), - 'amp-next-page' => array( + 'reference-point-amp-next-page-separator' => array( '

Keep reading

', null, array( 'amp-next-page' ), ), + /* + * @todo This is not in the deployed validator yet. + * 'reference-point-amp-carousel-lightbox-exclude' => array( + * '', + * null, + * array( 'amp-carousel' ), + * ), + */ + + 'reference-point-lightbox-thumbnail-id' => array( + '', + null, + array(), + ), + + 'reference-points-amp-live-list' => array( + '
', + null, + array( 'amp-live-list' ), + ), + + 'reference-points-amp-story' => array( + str_replace( + array( "\n", "\t" ), + '', + ' + + + + + + + +

Hello, amp-story!

+
+
+ + + + + + +

The End

+
+
+ +
+ ' + ), + null, + array( 'amp-story' ), + ), + + 'reference-points-bad' => array( + '
BAD REFERENCE POINTS
', + '
BAD REFERENCE POINTS
', + array(), + ), + 'amp-position-observer' => array( '', null, // No change. @@ -745,8 +804,8 @@ public function get_body_data() { ), // Adapted from . - 'amp_selector_and_carousel_with_boolean_attributes' => array( - '
  • None of the Above
', + 'reference-points-amp_selector_and_carousel_with_boolean_attributes' => array( + '
  • None of the Above
', null, // No change. array( 'amp-selector', 'amp-form', 'amp-carousel' ), ), From 2eb230d0e6b77be268fe59b88a72fa8534652d2d Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 30 Aug 2018 16:36:33 -0700 Subject: [PATCH 04/11] Eliminate whitelisted_attr_regex in favor of data-* attr check --- includes/sanitizers/class-amp-rule-spec.php | 12 ------------ .../class-amp-tag-and-attribute-sanitizer.php | 7 +------ ...and-attribute-sanitizer-private-methods-tests.php | 2 +- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/includes/sanitizers/class-amp-rule-spec.php b/includes/sanitizers/class-amp-rule-spec.php index b3b61181f21..9a96888a1bf 100644 --- a/includes/sanitizers/class-amp-rule-spec.php +++ b/includes/sanitizers/class-amp-rule-spec.php @@ -91,18 +91,6 @@ abstract class AMP_Rule_Spec { // Include 'script' here? ); - /** - * It is mentioned in the documentation in several places that data-* - * is generally allowed, but there is no specific rule for it in the - * protoascii file, so we include it here. - * - * @var array - */ - public static $whitelisted_attr_regex = array( - '@^data-[a-zA-Z][\\w:.-]*$@uis', - '(update|item|pagination|option|selected|disabled)', // Allowed for live reference points. - ); - /** * List of boolean attributes. * diff --git a/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php b/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php index b52e7dfcfb9..b5452fb0fc0 100644 --- a/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php +++ b/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php @@ -1508,14 +1508,9 @@ private function check_attr_spec_rule_value_properties( $node, $attr_name, $attr * @return bool Return true if attribute name is valid for this attr_spec_list, false otherwise. */ private function is_amp_allowed_attribute( $attr_name, $attr_spec_list ) { - if ( isset( $attr_spec_list[ $attr_name ] ) ) { + if ( isset( $attr_spec_list[ $attr_name ] ) || 'data-' === substr( $attr_name, 0, 5 ) ) { return true; } - foreach ( AMP_Rule_Spec::$whitelisted_attr_regex as $whitelisted_attr_regex ) { - if ( preg_match( $whitelisted_attr_regex, $attr_name ) ) { - return true; - } - } $is_allowed_alt_name_attr = ( isset( $this->rev_alternate_attr_name_lookup[ $attr_name ] ) diff --git a/tests/amp-tag-and-attribute-sanitizer-private-methods-tests.php b/tests/amp-tag-and-attribute-sanitizer-private-methods-tests.php index ecdb081538b..9b01444498c 100644 --- a/tests/amp-tag-and-attribute-sanitizer-private-methods-tests.php +++ b/tests/amp-tag-and-attribute-sanitizer-private-methods-tests.php @@ -548,7 +548,7 @@ public function test_is_allowed_attribute( $data, $expected ) { } $source = '<' . $data['tag_name'] . ' ' . $attribute . '>Some test content'; - $attr_spec_list = $this->allowed_tags[ $data['tag_name'] ][ $data['rule_spec_index'] ]['attr_spec_list']; + $attr_spec_list = array_merge( $this->globally_allowed_attrs, $this->allowed_tags[ $data['tag_name'] ][ $data['rule_spec_index'] ]['attr_spec_list'] ); if ( isset( $this->allowed_tags[ $data['tag_name'] ][ $data['rule_spec_index'] ]['tag_spec']['amp_layout'] ) ) { $attr_spec_list = array_merge( $attr_spec_list, $this->layout_allowed_attrs ); } From 596a0c7130f99bd21dd5773507e6d78ca27874d0 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 30 Aug 2018 16:47:59 -0700 Subject: [PATCH 05/11] Remove dead code: AMP_Rule_Spec::$node_types_to_remove_if_invalid --- includes/sanitizers/class-amp-rule-spec.php | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/includes/sanitizers/class-amp-rule-spec.php b/includes/sanitizers/class-amp-rule-spec.php index 9a96888a1bf..a09fb94eb5b 100644 --- a/includes/sanitizers/class-amp-rule-spec.php +++ b/includes/sanitizers/class-amp-rule-spec.php @@ -70,27 +70,6 @@ abstract class AMP_Rule_Spec { 9 => 'intrinsic', ); - /** - * If a node type listed here is invalid, it and it's subtree will be - * removed if it is invalid. This is mainly because any children will be - * non-functional without this parent. - * - * If a tag is not listed here, it will be replaced by its children if it - * is invalid. - * - * @todo There are other nodes that should probably be listed here as well. - * - * @var array - */ - public static $node_types_to_remove_if_invalid = array( - 'form', - 'input', - 'link', - 'meta', - 'style', - // Include 'script' here? - ); - /** * List of boolean attributes. * From 04ed6a7c689b9181e2c3584924f63c6f72e69561 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 30 Aug 2018 21:38:44 -0700 Subject: [PATCH 06/11] Extract reference points from spec and use attr_spec_list on direct element children --- bin/amphtml-update.py | 48 ++- .../class-amp-allowed-tags-generated.php | 389 ++++++++++++++++++ .../class-amp-tag-and-attribute-sanitizer.php | 26 +- tests/test-tag-and-attribute-sanitizer.php | 62 ++- 4 files changed, 509 insertions(+), 16 deletions(-) diff --git a/bin/amphtml-update.py b/bin/amphtml-update.py index 4c468fe9932..3a925ee703a 100644 --- a/bin/amphtml-update.py +++ b/bin/amphtml-update.py @@ -100,7 +100,7 @@ def GeneratePHP(out_dir): logging.info('entering ...') assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir - allowed_tags, attr_lists, versions = ParseRules(out_dir) + allowed_tags, attr_lists, reference_points, versions = ParseRules(out_dir) #Generate the output out = [] @@ -109,6 +109,7 @@ def GeneratePHP(out_dir): GenerateAllowedTagsPHP(out, allowed_tags) GenerateLayoutAttributesPHP(out, attr_lists) GenerateGlobalAttributesPHP(out, attr_lists) + GenerateReferencePointsPHP(out, reference_points) GenerateFooterPHP(out) # join out array into a single string and remove unneeded whitespace @@ -188,6 +189,15 @@ def GenerateGlobalAttributesPHP(out, attr_lists): out.append('') logging.info('... done') +def GenerateReferencePointsPHP(out, reference_points): + logging.info('entering ...') + + # Output the reference points. + out.append('') + out.append('\tprivate static $reference_points = %s;' % Phpize( reference_points, 1 ).lstrip() ) + out.append('') + logging.info('... done') + def GenerateFooterPHP(out): logging.info('entering ...') @@ -219,6 +229,20 @@ def GenerateFooterPHP(out): return null; } + /** + * Get reference point spec. + * + * @since 1.0 + * @param string $tag_spec_name Tag spec name. + * @return array|null Reference point spec, or null if does not exist. + */ + public static function get_reference_point_spec( $tag_spec_name ) { + if ( isset( self::$reference_points[ $tag_spec_name ] ) ) { + return self::$reference_points[ $tag_spec_name ]; + } + return null; + } + /** * Get list of globally-allowed attributes. * @@ -258,6 +282,7 @@ def ParseRules(out_dir): allowed_tags = {} attr_lists = {} + reference_points = {} versions = {} specfile='%s/validator.protoascii' % out_dir @@ -301,14 +326,15 @@ def ParseRules(out_dir): if tag_spec.HasField('mandatory_parent') and tag_spec.mandatory_parent in mandatory_parent_blacklist and tag_spec.tag_name != 'HTML': continue - # Ignore the special $REFERENCE_POINT tag - if '$REFERENCE_POINT' == tag_spec.tag_name: - continue - # Ignore deprecated tags if tag_spec.HasField('deprecation'): continue + # Ignore the special $REFERENCE_POINT tag + if '$REFERENCE_POINT' == tag_spec.tag_name: + reference_points[ tag_spec.spec_name ] = GetTagSpec(tag_spec, attr_lists) + continue + # If we made it here, then start adding the tag_spec if tag_spec.tag_name.lower() not in allowed_tags: tag_list = [] @@ -322,7 +348,7 @@ def ParseRules(out_dir): allowed_tags[UnicodeEscape(tag_spec.tag_name).lower()] = tag_list logging.info('... done') - return allowed_tags, attr_lists, versions + return allowed_tags, attr_lists, reference_points, versions def GetTagSpec(tag_spec, attr_lists): @@ -400,6 +426,16 @@ def GetTagRules(tag_spec): requires_extension_list.append(requires_extension) tag_rules['requires_extension'] = requires_extension_list + if hasattr(tag_spec, 'reference_points') and len( tag_spec.reference_points ) != 0: + tag_reference_points = {} + for reference_point_spec in tag_spec.reference_points: + tag_reference_points[ reference_point_spec.tag_spec_name ] = { + "mandatory": reference_point_spec.mandatory, + "unique": reference_point_spec.unique + } + if len( tag_reference_points ) > 0: + tag_rules['reference_points'] = tag_reference_points + if hasattr(tag_spec, 'also_requires_tag_warning') and len( tag_spec.also_requires_tag_warning ) != 0: also_requires_tag_warning_list = [] for also_requires_tag_warning in tag_spec.also_requires_tag_warning: diff --git a/includes/sanitizers/class-amp-allowed-tags-generated.php b/includes/sanitizers/class-amp-allowed-tags-generated.php index aa17d521933..5fce609f9d3 100644 --- a/includes/sanitizers/class-amp-allowed-tags-generated.php +++ b/includes/sanitizers/class-amp-allowed-tags-generated.php @@ -1133,6 +1133,16 @@ class AMP_Allowed_Tags_Generated { 4, ), ), + 'reference_points' => array( + 'AMP-CAROUSEL lightbox [child]' => array( + 'mandatory' => false, + 'unique' => false, + ), + 'AMP-CAROUSEL lightbox [lightbox-exclude]' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), 'requires_extension' => array( 'amp-carousel', 'amp-lightbox-gallery', @@ -2754,6 +2764,20 @@ class AMP_Allowed_Tags_Generated { 3, ), ), + 'reference_points' => array( + 'AMP-LIVE-LIST [items]' => array( + 'mandatory' => true, + 'unique' => true, + ), + 'AMP-LIVE-LIST [pagination]' => array( + 'mandatory' => false, + 'unique' => true, + ), + 'AMP-LIVE-LIST [update]' => array( + 'mandatory' => true, + 'unique' => true, + ), + ), 'requires_extension' => array( 'amp-live-list', ), @@ -2790,6 +2814,16 @@ class AMP_Allowed_Tags_Generated { array( 'attr_spec_list' => array(), 'tag_spec' => array( + 'reference_points' => array( + 'AMP-NEXT-PAGE > [separator]' => array( + 'mandatory' => false, + 'unique' => true, + ), + 'amp-next-page extension .json configuration' => array( + 'mandatory' => true, + 'unique' => true, + ), + ), 'requires_extension' => array( 'amp-next-page', ), @@ -2812,6 +2846,12 @@ class AMP_Allowed_Tags_Generated { ), ), 'tag_spec' => array( + 'reference_points' => array( + 'AMP-NEXT-PAGE > [separator]' => array( + 'mandatory' => false, + 'unique' => true, + ), + ), 'requires_extension' => array( 'amp-next-page', ), @@ -3327,6 +3367,16 @@ class AMP_Allowed_Tags_Generated { 'disallowed_ancestor' => array( 'amp-selector', ), + 'reference_points' => array( + 'AMP-SELECTOR child' => array( + 'mandatory' => false, + 'unique' => false, + ), + 'AMP-SELECTOR option' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), 'requires_extension' => array( 'amp-selector', ), @@ -3696,6 +3746,12 @@ class AMP_Allowed_Tags_Generated { 'attr_spec_list' => array(), 'tag_spec' => array( 'mandatory_ancestor' => 'amp-story-page', + 'reference_points' => array( + 'AMP-STORY-CTA-LAYER animate-in' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), ), ), ), @@ -3714,6 +3770,16 @@ class AMP_Allowed_Tags_Generated { ), 'tag_spec' => array( 'mandatory_ancestor' => 'amp-story-page', + 'reference_points' => array( + 'AMP-STORY-GRID-LAYER animate-in' => array( + 'mandatory' => false, + 'unique' => false, + ), + 'AMP-STORY-GRID-LAYER default' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), ), ), ), @@ -12376,6 +12442,16 @@ class AMP_Allowed_Tags_Generated { ), 'tag_spec' => array( 'mandatory_parent' => 'amp-story-auto-ads', + 'reference_points' => array( + 'AMP-STORY-GRID-LAYER animate-in' => array( + 'mandatory' => false, + 'unique' => false, + ), + 'AMP-STORY-GRID-LAYER default' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), 'requires_extension' => array( 'amp-mustache', ), @@ -13595,6 +13671,305 @@ class AMP_Allowed_Tags_Generated { ); + private static $reference_points = array( + 'AMP-CAROUSEL lightbox [child]' => array( + 'attr_spec_list' => array( + 'lightbox-thumbnail-id' => array( + 'value_regex_casei' => '^[a-z][a-z\\d_-]*', + ), + ), + 'tag_spec' => array( + 'spec_name' => 'AMP-CAROUSEL lightbox [child]', + ), + ), + 'AMP-CAROUSEL lightbox [lightbox-exclude]' => array( + 'attr_spec_list' => array( + 'lightbox-exclude' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'spec_name' => 'AMP-CAROUSEL lightbox [lightbox-exclude]', + ), + ), + 'AMP-LIVE-LIST [items]' => array( + 'attr_spec_list' => array( + 'items' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'reference_points' => array( + 'AMP-LIVE-LIST [items] item' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), + 'spec_name' => 'AMP-LIVE-LIST [items]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-live-list#items', + ), + ), + 'AMP-LIVE-LIST [items] item' => array( + 'attr_spec_list' => array( + 'data-sort-time' => array( + 'mandatory' => true, + ), + 'data-tombstone' => array(), + 'data-update-time' => array(), + 'id' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'spec_name' => 'AMP-LIVE-LIST [items] item', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-live-list#items', + ), + ), + 'AMP-LIVE-LIST [pagination]' => array( + 'attr_spec_list' => array( + 'pagination' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'spec_name' => 'AMP-LIVE-LIST [pagination]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-live-list#pagination', + ), + ), + 'AMP-LIVE-LIST [update]' => array( + 'attr_spec_list' => array( + 'update' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'spec_name' => 'AMP-LIVE-LIST [update]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-live-list#update', + ), + ), + 'AMP-NEXT-PAGE > [separator]' => array( + 'attr_spec_list' => array( + 'separator' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'amp-next-page', + 'spec_name' => 'AMP-NEXT-PAGE > [separator]', + ), + ), + 'AMP-SELECTOR child' => array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'reference_points' => array( + 'AMP-SELECTOR child' => array( + 'mandatory' => false, + 'unique' => false, + ), + 'AMP-SELECTOR option' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), + 'spec_name' => 'AMP-SELECTOR child', + ), + ), + 'AMP-SELECTOR option' => array( + 'attr_spec_list' => array( + 'disabled' => array( + 'value' => array( + '', + ), + ), + 'option' => array( + 'mandatory' => true, + ), + 'selected' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'spec_name' => 'AMP-SELECTOR option', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-selector', + ), + ), + 'AMP-STORY-CTA-LAYER animate-in' => array( + 'attr_spec_list' => array( + 'animate-in' => array( + 'value' => array( + 'drop', + 'fade-in', + 'fly-in-bottom', + 'fly-in-left', + 'fly-in-right', + 'fly-in-top', + 'pan-down', + 'pan-left', + 'pan-right', + 'pan-up', + 'pulse', + 'rotate-in-left', + 'rotate-in-right', + 'twirl-in', + 'whoosh-in-left', + 'whoosh-in-right', + 'zoom-in', + 'zoom-out', + ), + ), + 'animate-in-after' => array(), + 'animate-in-delay' => array(), + 'animate-in-duration' => array(), + ), + 'tag_spec' => array( + 'reference_points' => array( + 'AMP-STORY-CTA-LAYER animate-in' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), + 'spec_name' => 'AMP-STORY-CTA-LAYER animate-in', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-story', + ), + ), + 'AMP-STORY-GRID-LAYER animate-in' => array( + 'attr_spec_list' => array( + 'animate-in' => array( + 'value' => array( + 'drop', + 'fade-in', + 'fly-in-bottom', + 'fly-in-left', + 'fly-in-right', + 'fly-in-top', + 'pan-down', + 'pan-left', + 'pan-right', + 'pan-up', + 'pulse', + 'rotate-in-left', + 'rotate-in-right', + 'twirl-in', + 'whoosh-in-left', + 'whoosh-in-right', + 'zoom-in', + 'zoom-out', + ), + ), + 'animate-in-after' => array(), + 'animate-in-delay' => array(), + 'animate-in-duration' => array(), + ), + 'tag_spec' => array( + 'reference_points' => array( + 'AMP-STORY-GRID-LAYER animate-in' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), + 'spec_name' => 'AMP-STORY-GRID-LAYER animate-in', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-story', + ), + ), + 'AMP-STORY-GRID-LAYER default' => array( + 'attr_spec_list' => array( + 'align-content' => array( + 'value' => array( + 'center', + 'end', + 'space-around', + 'space-between', + 'space-evenly', + 'start', + 'stretch', + ), + ), + 'align-items' => array( + 'value' => array( + 'center', + 'end', + 'start', + 'stretch', + ), + ), + 'align-self' => array( + 'value' => array( + 'center', + 'end', + 'start', + 'stretch', + ), + ), + 'animate-in' => array( + 'value' => array( + 'drop', + 'fade-in', + 'fly-in-bottom', + 'fly-in-left', + 'fly-in-right', + 'fly-in-top', + 'pan-down', + 'pan-left', + 'pan-right', + 'pan-up', + 'pulse', + 'rotate-in-left', + 'rotate-in-right', + 'twirl-in', + 'whoosh-in-left', + 'whoosh-in-right', + 'zoom-in', + 'zoom-out', + ), + ), + 'animate-in-after' => array(), + 'animate-in-delay' => array(), + 'animate-in-duration' => array(), + 'grid-area' => array(), + 'justify-content' => array( + 'value' => array( + 'center', + 'end', + 'space-around', + 'space-between', + 'space-evenly', + 'start', + 'stretch', + ), + ), + 'justify-items' => array( + 'value' => array( + 'center', + 'end', + 'start', + 'stretch', + ), + ), + 'justify-self' => array( + 'value' => array( + 'center', + 'end', + 'start', + 'stretch', + ), + ), + ), + 'tag_spec' => array( + 'reference_points' => array( + 'AMP-STORY-GRID-LAYER animate-in' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), + 'spec_name' => 'AMP-STORY-GRID-LAYER default', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-story', + ), + ), + ); + + /** * Get allowed tags. * @@ -13621,6 +13996,20 @@ public static function get_allowed_tag( $node_name ) { return null; } + /** + * Get reference point spec. + * + * @since 1.0 + * @param string $tag_spec_name Tag spec name. + * @return array|null Reference point spec, or null if does not exist. + */ + public static function get_reference_point_spec( $tag_spec_name ) { + if ( isset( self::$reference_points[ $tag_spec_name ] ) ) { + return self::$reference_points[ $tag_spec_name ]; + } + return null; + } + /** * Get list of globally-allowed attributes. * diff --git a/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php b/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php index b5452fb0fc0..330df192a60 100644 --- a/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php +++ b/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php @@ -240,7 +240,7 @@ private function process_alternate_names( $attr_spec_list ) { } /** - * Sanitize the