Skip to content

Commit 82c4ff2

Browse files
authored
Merge pull request #677 from Automattic/develop
2.3.1 Release
2 parents a2eef7f + 6f58318 commit 82c4ff2

File tree

5 files changed

+150
-37
lines changed

5 files changed

+150
-37
lines changed

.github/ISSUE_TEMPLATE/release-template.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
name: Release template
33
about: Internally used for new releases
4-
title: Release 2.x.y
4+
title: Release x.y.z
55
labels: 'Type: Maintenance'
66
assignees: GaryJones, rebeccahum
77

@@ -13,6 +13,7 @@ assignees: GaryJones, rebeccahum
1313

1414
PR for tracking changes for the X.Y.Z release. Target release date: DOW DD MMMM YYYY.
1515

16+
- [ ] Scan WordPress (or just wp-admin folder) with prior version and compare results against new release for potential new bugs.
1617
- [ ] Add change log for this release: PR #XXX
1718
- [ ] Double-check whether any dependencies need bumping.
1819
- [ ] Merge this PR.

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [2.3.1] - 2021-04-23
8+
9+
Props: jrfnl
10+
11+
### Fixed
12+
- [#668](https://github.com/Automattic/VIP-Coding-Standards/pull/668): ProperEscapingFunction: fix overreach of comma usage in non-echo expressions for notAttrEscAttr.
13+
- [#670](https://github.com/Automattic/VIP-Coding-Standards/pull/670): ProperEscapingFunction: improve "action" match precision for hrefSrcEscUrl.
14+
15+
## Deprecated
16+
- [#670](https://github.com/Automattic/VIP-Coding-Standards/pull/670): ProperEscapingFunction: private properties `$url_attrs` and `$attr_endings` are deprecated along with the public methods `is_html_attr()` and `attr_expects_url()`.
17+
718
## [2.3.0] - 2021-04-19
819

920
Props: jrfnl, rebeccahum, kevinfodness, GaryJones.
@@ -539,6 +550,7 @@ Initial release.
539550
Props: david-binda, pkevan.
540551

541552

553+
[2.3.1]: https://github.com/Automattic/VIP-Coding-Standards/compare/2.3.0...2.3.1
542554
[2.3.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/2.2.0...2.3.0
543555
[2.2.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/2.1.0...2.2.0
544556
[2.1.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/2.0.0...2.1.0

WordPressVIPMinimum/Sniffs/Security/ProperEscapingFunctionSniff.php

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
*/
1919
class ProperEscapingFunctionSniff extends Sniff {
2020

21+
/**
22+
* Regular expression to match the end of HTML attributes.
23+
*
24+
* @var string
25+
*/
26+
const ATTR_END_REGEX = '`(?<attrname>href|src|url|(^|\s+)action)?=(?:\\\\)?["\']*$`i';
27+
2128
/**
2229
* List of escaping functions which are being tested.
2330
*
@@ -46,13 +53,16 @@ class ProperEscapingFunctionSniff extends Sniff {
4653
T_OPEN_TAG => T_OPEN_TAG,
4754
T_OPEN_TAG_WITH_ECHO => T_OPEN_TAG_WITH_ECHO,
4855
T_STRING_CONCAT => T_STRING_CONCAT,
49-
T_COMMA => T_COMMA,
5056
T_NS_SEPARATOR => T_NS_SEPARATOR,
5157
];
5258

5359
/**
5460
* List of attributes associated with url outputs.
5561
*
62+
* @deprecated 2.3.1 Currently unused by the sniff, but needed for
63+
* for public methods which extending sniffs may be
64+
* relying on.
65+
*
5666
* @var array
5767
*/
5868
private $url_attrs = [
@@ -65,6 +75,10 @@ class ProperEscapingFunctionSniff extends Sniff {
6575
/**
6676
* List of syntaxes for inside attribute detection.
6777
*
78+
* @deprecated 2.3.1 Currently unused by the sniff, but needed for
79+
* for public methods which extending sniffs may be
80+
* relying on.
81+
*
6882
* @var array
6983
*/
7084
private $attr_endings = [
@@ -75,6 +89,14 @@ class ProperEscapingFunctionSniff extends Sniff {
7589
'=\\"',
7690
];
7791

92+
/**
93+
* Keep track of whether or not we're currently in the first statement of a short open echo tag.
94+
*
95+
* @var int|false Integer stack pointer to the end of the first statement in the current
96+
* short open echo tag or false when not in a short open echo tag.
97+
*/
98+
private $in_short_echo = false;
99+
78100
/**
79101
* Returns an array of tokens this test wants to listen for.
80102
*
@@ -83,7 +105,10 @@ class ProperEscapingFunctionSniff extends Sniff {
83105
public function register() {
84106
$this->echo_or_concat_tokens += Tokens::$emptyTokens;
85107

86-
return [ T_STRING ];
108+
return [
109+
T_STRING,
110+
T_OPEN_TAG_WITH_ECHO,
111+
];
87112
}
88113

89114
/**
@@ -94,6 +119,35 @@ public function register() {
94119
* @return void
95120
*/
96121
public function process_token( $stackPtr ) {
122+
/*
123+
* Short open echo tags will act as an echo for the first expression and
124+
* allow for passing multiple comma-separated parameters.
125+
* However, short open echo tags also allow for additional statements after, but
126+
* those have to be full PHP statements, not expressions.
127+
*
128+
* This snippet of code will keep track of whether or not we're in the first
129+
* expression in a short open echo tag.
130+
* $phpcsFile->findStartOfStatement() unfortunately is useless, as it will return
131+
* the first token in the statement, which can be anything - variable, text string -
132+
* without any indication of whether this is the start of a normal statement or
133+
* a short open echo expression.
134+
* So, if we used that, we'd need to walk back from every start of statement to
135+
* the previous non-empty to see if it is the short open echo tag.
136+
*/
137+
if ( $this->tokens[ $stackPtr ]['code'] === T_OPEN_TAG_WITH_ECHO ) {
138+
$end_of_echo = $this->phpcsFile->findNext( [ T_SEMICOLON, T_CLOSE_TAG ], ( $stackPtr + 1 ) );
139+
if ( $end_of_echo === false ) {
140+
$this->in_short_echo = $this->phpcsFile->numTokens;
141+
} else {
142+
$this->in_short_echo = $end_of_echo;
143+
}
144+
145+
return;
146+
}
147+
148+
if ( $this->in_short_echo !== false && $this->in_short_echo < $stackPtr ) {
149+
$this->in_short_echo = false;
150+
}
97151

98152
$function_name = strtolower( $this->tokens[ $stackPtr ]['content'] );
99153

@@ -107,7 +161,17 @@ public function process_token( $stackPtr ) {
107161
return;
108162
}
109163

110-
$html = $this->phpcsFile->findPrevious( $this->echo_or_concat_tokens, $stackPtr - 1, null, true );
164+
$ignore = $this->echo_or_concat_tokens;
165+
if ( $this->in_short_echo !== false ) {
166+
$ignore[ T_COMMA ] = T_COMMA;
167+
} else {
168+
$start_of_statement = $this->phpcsFile->findStartOfStatement( $stackPtr, T_COMMA );
169+
if ( $this->tokens[ $start_of_statement ]['code'] === T_ECHO ) {
170+
$ignore[ T_COMMA ] = T_COMMA;
171+
}
172+
}
173+
174+
$html = $this->phpcsFile->findPrevious( $ignore, $stackPtr - 1, null, true );
111175

112176
// Use $textStringTokens b/c heredoc and nowdoc tokens will never be encountered in this context anyways..
113177
if ( $html === false || isset( Tokens::$textStringTokens[ $this->tokens[ $html ]['code'] ] ) === false ) {
@@ -129,13 +193,17 @@ public function process_token( $stackPtr ) {
129193
return;
130194
}
131195

132-
if ( $escaping_type !== 'url' && $this->attr_expects_url( $content ) ) {
196+
if ( preg_match( self::ATTR_END_REGEX, $content, $matches ) !== 1 ) {
197+
return;
198+
}
199+
200+
if ( $escaping_type !== 'url' && empty( $matches['attrname'] ) === false ) {
133201
$message = 'Wrong escaping function. href, src, and action attributes should be escaped by `esc_url()`, not by `%s()`.';
134202
$this->phpcsFile->addError( $message, $stackPtr, 'hrefSrcEscUrl', $data );
135203
return;
136204
}
137205

138-
if ( $escaping_type === 'html' && $this->is_html_attr( $content ) ) {
206+
if ( $escaping_type === 'html' ) {
139207
$message = 'Wrong escaping function. HTML attributes should be escaped by `esc_attr()`, not by `%s()`.';
140208
$this->phpcsFile->addError( $message, $stackPtr, 'htmlAttrNotByEscHTML', $data );
141209
return;
@@ -145,6 +213,8 @@ public function process_token( $stackPtr ) {
145213
/**
146214
* Tests whether provided string ends with open attribute which expects a URL value.
147215
*
216+
* @deprecated 2.3.1
217+
*
148218
* @param string $content Haystack in which we look for an open attribute which exects a URL value.
149219
*
150220
* @return bool True if string ends with open attribute which expects a URL value.
@@ -165,6 +235,8 @@ public function attr_expects_url( $content ) {
165235
/**
166236
* Tests whether provided string ends with open HMTL attribute.
167237
*
238+
* @deprecated 2.3.1
239+
*
168240
* @param string $content Haystack in which we look for open HTML attribute.
169241
*
170242
* @return bool True if string ends with open HTML attribute.

WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.inc

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ echo 'data-param-url="' . Esc_HTML( $share_url ) . '"'; // Error.
3838

3939
?>
4040

41-
<form method="post" action="<?php echo esc_html(admin_url('admin.php?page='.$base_name.'&amp;mode=logs&amp;id='.$poll_id)); ?>">
42-
43-
41+
<form method="post" action="<?php echo esc_html(admin_url('admin.php?page='.$base_name.'&amp;mode=logs&amp;id='.$poll_id)); ?>"><!-- Error. -->
42+
<input data-action="<?php echo esc_attr( $my_var ); ?>"><!-- OK. -->
43+
<a href='https://demo.com?foo=bar&my-action=<?php echo esc_attr( $var ); ?>'>link</a><!-- OK. -->
4444

4545
<a href="#link"><?php echo esc_attr( 'testing' ); // Error.
4646
?> </a>
@@ -82,3 +82,27 @@ echo '<a href="', esc_html($url), '">'; // Error.
8282
echo '<a href=', esc_html($url), '>'; // Error.
8383

8484
echo 'data-param-url="' . Esc_HTML::static_method( $share_url ) . '"'; // OK.
85+
86+
// Not a target for this sniff (yet).
87+
printf( '<meta name="generator" content="%s">', esc_attr( $content ) ); // OK.
88+
?>
89+
90+
// Making sure tabs and new lines before "action" are handled correctly.
91+
<input class="something something-else something-more"
92+
action="<?php echo esc_attr( $my_var ); ?>"><!-- Error. -->
93+
<?php
94+
echo '<input class="something something-else something-more"
95+
action="', esc_url( $my_var ), '">'; // OK.
96+
echo '<input class="something something-else something-more"
97+
action="', esc_attr( $my_var ), '">'; // Error.
98+
99+
// Verify correct handling of comma's in short open echo tags, without affecting subsequent statements.
100+
?>
101+
<div>html</div>
102+
<?= '<h1>' , esc_attr( $test ) , '</h1>'; // Error.
103+
printf( '<meta name="generator" content="%s">', esc_attr( $content ) ); // OK.
104+
echo '<a href="', esc_html($url), '">'; // Error.
105+
?>
106+
<div>html</div>
107+
<?= '<h1 class="', esc_attr( $test ), '">'; ?><!-- OK -->
108+
<div>html</div>

WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.php

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,34 +25,38 @@ class ProperEscapingFunctionUnitTest extends AbstractSniffUnitTest {
2525
*/
2626
public function getErrorList() {
2727
return [
28-
3 => 1,
29-
5 => 1,
30-
15 => 1,
31-
17 => 1,
32-
21 => 1,
33-
23 => 1,
34-
33 => 1,
35-
37 => 1,
36-
41 => 1,
37-
45 => 1,
38-
48 => 1,
39-
62 => 1,
40-
63 => 1,
41-
64 => 1,
42-
65 => 1,
43-
67 => 1,
44-
68 => 1,
45-
69 => 1,
46-
72 => 1,
47-
73 => 1,
48-
74 => 1,
49-
75 => 1,
50-
76 => 1,
51-
77 => 1,
52-
78 => 1,
53-
79 => 1,
54-
80 => 1,
55-
82 => 1,
28+
3 => 1,
29+
5 => 1,
30+
15 => 1,
31+
17 => 1,
32+
21 => 1,
33+
23 => 1,
34+
33 => 1,
35+
37 => 1,
36+
41 => 1,
37+
45 => 1,
38+
48 => 1,
39+
62 => 1,
40+
63 => 1,
41+
64 => 1,
42+
65 => 1,
43+
67 => 1,
44+
68 => 1,
45+
69 => 1,
46+
72 => 1,
47+
73 => 1,
48+
74 => 1,
49+
75 => 1,
50+
76 => 1,
51+
77 => 1,
52+
78 => 1,
53+
79 => 1,
54+
80 => 1,
55+
82 => 1,
56+
92 => 1,
57+
97 => 1,
58+
102 => 1,
59+
104 => 1,
5660
];
5761
}
5862

0 commit comments

Comments
 (0)