From e681e5d8c974914f957e24fd29de5caf160152fb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bartosz=20Dziewo=C5=84ski?= Date: Mon, 14 Nov 2016 16:14:37 +0100 Subject: [PATCH] mw.Message: Match behavior when key does not exist to PHP See 184658eb32f6c5561cd3789716bd98c1e9f0ba04. Change-Id: I3dba16bcb137ca2f52203bce95f8c044870af3fd --- includes/Message.php | 1 + resources/src/mediawiki/mediawiki.js | 15 +++++++++------ .../suites/resources/mediawiki/mediawiki.test.js | 6 ++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/includes/Message.php b/includes/Message.php index c1a12aa912..3272aff6a1 100644 --- a/includes/Message.php +++ b/includes/Message.php @@ -808,6 +808,7 @@ class Message implements MessageSpecifier, Serializable { // message key is user-controlled. // '⧼' is used instead of '<' to side-step any // double-escaping issues. + // (Keep synchronised with mw.Message#toString in JS.) return '⧼' . htmlspecialchars( $this->key ) . '⧽'; } diff --git a/resources/src/mediawiki/mediawiki.js b/resources/src/mediawiki/mediawiki.js index 9c8fe70bde..d5258131ae 100644 --- a/resources/src/mediawiki/mediawiki.js +++ b/resources/src/mediawiki/mediawiki.js @@ -325,12 +325,15 @@ var text; if ( !this.exists() ) { - // Use as text if key does not exist - if ( this.format === 'escaped' || this.format === 'parse' ) { - // format 'escaped' and 'parse' need to have the brackets and key html escaped - return mw.html.escape( '<' + this.key + '>' ); - } - return '<' + this.key + '>'; + // Use ⧼key⧽ as text if key does not exist + // Err on the side of safety, ensure that the output + // is always html safe in the event the message key is + // missing, since in that case its highly likely the + // message key is user-controlled. + // '⧼' is used instead of '<' to side-step any + // double-escaping issues. + // (Keep synchronised with Message::toString() in PHP.) + return '⧼' + mw.html.escape( this.key ) + '⧽'; } if ( this.format === 'plain' || this.format === 'text' || this.format === 'parse' ) { diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js index 1518a80cad..6ee49013c6 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js @@ -239,9 +239,7 @@ goodbye = mw.message( 'goodbye' ); assert.strictEqual( goodbye.exists(), false, 'Message.exists returns false for nonexistent messages' ); - assertMultipleFormats( [ 'goodbye' ], [ 'plain', 'text' ], '', 'Message.toString returns if key does not exist' ); - // bug 30684 - assertMultipleFormats( [ 'goodbye' ], [ 'parse', 'escaped' ], '<goodbye>', 'Message.toString returns properly escaped <key> if key does not exist' ); + assertMultipleFormats( [ 'good<>bye' ], [ 'plain', 'text', 'parse', 'escaped' ], '⧼good<>bye⧽', 'Message.toString returns ⧽key⧽ if key does not exist' ); assert.ok( mw.messages.set( 'plural-test-msg', 'There {{PLURAL:$1|is|are}} $1 {{PLURAL:$1|result|results}}' ), 'mw.messages.set: Register' ); assertMultipleFormats( [ 'plural-test-msg', 6 ], [ 'text', 'parse', 'escaped' ], 'There are 6 results', 'plural get resolved' ); @@ -320,7 +318,7 @@ QUnit.test( 'mw.msg', 14, function ( assert ) { assert.ok( mw.messages.set( 'hello', 'Hello awesome world' ), 'mw.messages.set: Register' ); assert.equal( mw.msg( 'hello' ), 'Hello awesome world', 'Gets message with default options (existing message)' ); - assert.equal( mw.msg( 'goodbye' ), '', 'Gets message with default options (nonexistent message)' ); + assert.equal( mw.msg( 'goodbye' ), '⧼goodbye⧽', 'Gets message with default options (nonexistent message)' ); assert.ok( mw.messages.set( 'plural-item', 'Found $1 {{PLURAL:$1|item|items}}' ), 'mw.messages.set: Register' ); assert.equal( mw.msg( 'plural-item', 5 ), 'Found 5 items', 'Apply plural for count 5' ); -- 2.20.1