Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions includes/class-withdrawal-path.php
Original file line number Diff line number Diff line change
Expand Up @@ -495,11 +495,25 @@ private static function strip_non_markup( $html ) {
continue;
}

$end = stripos( $html, '</' . $match[1][0], $after );
if ( false === $end ) {
// The end tag has to end where the name ends. A plain substring
// search closes the raw-text region at `</titlex>` or `</styles>`
// too, and everything after it is then treated as live markup — so
// a marker sitting in inert text passes verification, the footer
// route is believed, this plugin hides its own widget and the
// visitor is left with no way to withdraw consent. That is the
// fail-open this class documents itself as not doing. HTML5 ends a
// raw-text element only when the name is followed by tab, LF, FF,
// CR, space, `/` or `>`. The set is spelled out rather than written
// `\s`, because PCRE's `\s` also matches the vertical tab, which
// HTML does not treat as whitespace: `</title\x0B>` would close the
// region here while a browser keeps it as title text, which is the
// same fail-open with a less likely input.
$close_pattern = '#</' . preg_quote( $match[1][0], '#' ) . '(?=[\t\n\f\r />])#i';
if ( 1 !== preg_match( $close_pattern, $html, $close_match, PREG_OFFSET_CAPTURE, $after ) ) {
$offset = $length;
continue;
}
$end = $close_match[0][1];
$close = strpos( $html, '>', $end );
$offset = ( false === $close ) ? $length : $close + 1;
}
Expand Down
9 changes: 8 additions & 1 deletion tests/unit/test-mobile-compact-css-php.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,14 @@ function ( $value ) {
// their 40% bases leave it almost nothing to grow into: it collapsed to
// a few pixels wide.
faz_mcss_assert( false !== strpos( $dns_body, 'flex:1 1 100%' ), "{$type}: the Do-Not-Sell control takes a full row, not a share of the pair's" );
faz_mcss_assert( false !== strpos( $dns_body, 'width:100%' ), "{$type}: the Do-Not-Sell row spans the wrapper" );
// Anchored to a declaration boundary, not a substring: `width:100%`
// also matches `min-width:100%` and `max-width:100%`, and neither of
// those makes the row span the wrapper — so the plain substring check
// could not have caught that regression.
// Bounded on both sides: `width:100%junk` is an invalid value a browser
// discards, so without the trailing boundary the test could pass on a
// rule that sets no usable width at all.
faz_mcss_assert( 1 === preg_match( '/(?:^|;)width:100%(?=;|$)/', $dns_body ), "{$type}: the Do-Not-Sell row spans the wrapper" );
// "Do Not Sell or Share My Personal Information" is statutory wording
// that cannot be shortened, and it does not fit one line on a phone.
faz_mcss_assert( false !== strpos( $dns_body, 'white-space:normal' ), "{$type}: the statutory Do-Not-Sell label is allowed to wrap" );
Expand Down
33 changes: 33 additions & 0 deletions tests/unit/test-withdrawal-path-php.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,39 @@ function faz_page_without_link() {
faz_is( Withdrawal_Path::body_has_marker( '<body><!-- <a data-faz-open-preferences="1">Cookie</a> --><p>x</p></body>' ), false, 'marker solo in un commento HTML -> NON verificato' );
faz_is( Withdrawal_Path::body_has_marker( '<body><noscript><a href="#faz-consent" data-faz-open-preferences="1">Cookie</a></noscript></body>' ), false, 'marker solo in <noscript> -> NON verificato: senza script.js il link non fa nulla' );
faz_is( Withdrawal_Path::body_has_marker( '<body><template><button data-faz-open-preferences="1">Cookie</button></template></body>' ), false, 'marker solo in un <template> inerte -> NON verificato' );
// Raw-text regions must end where the element's name ends, not at the first
// string that merely starts with it. `</titlex>` does not close <title>, and
// a browser renders everything after it as the title's text — so a marker
// there is inert. Closing the region early would hand that inert text back
// as live markup, verify a footer route that does not exist, and leave the
// visitor with no way to withdraw consent: fail-open, in the one class whose
// contract is to fail closed.
// Each case puts a REAL element carrying the marker after the fake closing
// tag: that is what makes the assertion bite. With the marker only in loose
// text the DOM parser finds no attribute and the test would pass either way
// — green, and worthless. Confirmed by running all four against the old
// substring search: every one of them goes red.
$raw_text_boundaries = array(
'<title>Writing </titlex> more <a data-faz-open-preferences>fake</a></title><footer>none</footer>',
'<style>#a{color:red} /* </stylex> */ <a data-faz-open-preferences>fake</a></style><footer>none</footer>',
'<script>var s = "</scriptx>"; <a data-faz-open-preferences>fake</a></script><footer>none</footer>',
'<textarea>paste </textareax> here <a data-faz-open-preferences>fake</a></textarea><footer>none</footer>',
// Vertical tab. PCRE's \s matches it, HTML's whitespace set does not,
// so `</title\x0B>` must NOT close the region: a browser keeps reading
// title text, and anything after it has to stay inert here too.
"<title>t </title\x0B> <a data-faz-open-preferences>fake</a></title><footer>none</footer>",
);
foreach ( $raw_text_boundaries as $markup ) {
faz_is( Withdrawal_Path::body_has_marker( $markup ), false, 'marker oltre una finta chiusura di testo grezzo -> NON verificato' );
}
// E il tag di chiusura vero continua a chiudere: la correzione non deve
// rendere la regione infinita, o ogni marker reale dopo di essa sparirebbe.
faz_is(
Withdrawal_Path::body_has_marker( '<title>t</title><footer><a href="#faz-consent" data-faz-open-preferences>Cookie</a></footer>' ),
true,
'dopo la chiusura vera il markup torna a contare'
);

$unusable_controls = array(
'<button disabled data-faz-open-preferences>Preferences</button>',
'<button data-faz-open-preferences disabled="false">Preferences</button>',
Expand Down
Loading