Page MenuHomePhabricator
Authored By
MrStradivarius
Feb 6 2022, 7:55 AM
Size
6 KB
Referenced Files
None
Subscribers
None

T300743-enwiki3.patch

From 408b1e65a44596967f978ac7936bcf6fe9fd261c Mon Sep 17 00:00:00 2001
From: "Mr. Stradivarius" <misterstrad@gmail.com>
Date: Fri, 4 Feb 2022 11:33:14 +0900
Subject: [PATCH] Escape output in Import.toJs
We need to escape JavaScript strings, JavaScript comments, and URL
components. For the first two, we make our own custom functions based on
the js-string-escape library. For the last one, we can use
encodeURIComponent.
Also, unescape the input when reading from JavaScript files so that
round-tripping isn't broken.
---
MediaWiki:Gadget-script-installer-core.js | 100 +++++++++++++++++++---
1 file changed, 89 insertions(+), 11 deletions(-)
diff --git a/MediaWiki:Gadget-script-installer-core.js b/MediaWiki:Gadget-script-installer-core.js
index dc9de4b..4be1ab1 100644
--- a/MediaWiki:Gadget-script-installer-core.js
+++ b/MediaWiki:Gadget-script-installer-core.js
@@ -100,7 +100,7 @@
var match;
if( match = URL_RGX.exec( url ) ) {
var title = decodeURIComponent( match[2].replace( /&$/, "" ) ),
- wiki = match[1];
+ wiki = decodeURIComponent( match[1] );
return new Import( title, wiki, null, target, disabled );
}
return new Import( null, null, url, target, disabled );
@@ -110,12 +110,12 @@
var IMPORT_RGX = /^\s*(\/\/)?\s*importScript\s*\(\s*(?:"|')(.+?)(?:"|')\s*\)/;
var match;
if( match = IMPORT_RGX.exec( line ) ) {
- return Import.ofLocal( match[2], target, !!match[1] );
+ return Import.ofLocal( unescapeForJsString( match[2] ), target, !!match[1] );
}
var LOADER_RGX = /^\s*(\/\/)?\s*mw\.loader\.load\s*\(\s*(?:"|')(.+?)(?:"|')\s*\)/;
if( match = LOADER_RGX.exec( line ) ) {
- return Import.ofUrl( match[2], target, !!match[1] );
+ return Import.ofUrl( unescapeForJsString( match[2] ), target, !!match[1] );
}
}
@@ -142,11 +142,11 @@
var dis = this.disabled ? "//" : "",
url = this.url;
switch( this.type ) {
- case 0: return dis + "importScript('" + this.page + "'); // Backlink: [[" + this.page + "]]";
- case 1: url = "//" + this.wiki + ".org/w/index.php?title=" +
- this.page + "&action=raw&ctype=text/javascript";
+ case 0: return dis + "importScript('" + escapeForJsString( this.page ) + "'); // Backlink: [[" + escapeForJsComment( this.page ) + "]]";
+ case 1: url = "//" + encodeURIComponent( this.wiki ) + ".org/w/index.php?title=" +
+ encodeURIComponent( this.page ) + "&action=raw&ctype=text/javascript";
/* FALL THROUGH */
- case 2: return dis + "mw.loader.load('" + url + "');";
+ case 2: return dis + "mw.loader.load('" + escapeForJsString( url ) + "');";
}
}
@@ -172,10 +172,10 @@
}
var toFind;
switch( this.type ) {
- case 0: toFind = quoted( this.page ); break;
- case 1: toFind = new RegExp( escapeForRegex( this.wiki ) + ".*?" +
- escapeForRegex( this.page ) ); break;
- case 2: toFind = quoted( this.url ); break;
+ case 0: toFind = quoted( escapeForJsString( this.page ) ); break;
+ case 1: toFind = new RegExp( escapeForRegex( encodeURIComponent( this.wiki ) ) + ".*?" +
+ escapeForRegex( encodeURIComponent( this.page ) ) ); break;
+ case 2: toFind = quoted( escapeForJsString( this.url ) ); break;
}
var lineNums = [], lines = targetWikitext.split( "\n" );
for( var i = 0; i < lines.length; i++ ) {
@@ -677,6 +677,84 @@
return s.replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' );
}
+ /**
+ * Escape a string for use in a JavaScript string literal.
+ * This function is adapted from
+ * https://github.com/joliss/js-string-escape/blob/6887a69003555edf5c6caaa75f2592228558c595/index.js
+ * (released under the MIT licence).
+ */
+ function escapeForJsString( s ) {
+ return s.replace( /["'\\\n\r\u2028\u2029]/g, function ( character ) {
+ // Escape all characters not included in SingleStringCharacters and
+ // DoubleStringCharacters on
+ // http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
+ switch ( character ) {
+ case '"':
+ case "'":
+ case '\\':
+ return '\\' + character;
+ // Four possible LineTerminator characters need to be escaped:
+ case '\n':
+ return '\\n';
+ case '\r':
+ return '\\r';
+ case '\u2028':
+ return '\\u2028';
+ case '\u2029':
+ return '\\u2029';
+ }
+ } );
+ }
+
+ /**
+ * Escape a string for use in an inline JavaScript comment (comments that
+ * start with two slashes "//").
+ * This function is adapted from
+ * https://github.com/joliss/js-string-escape/blob/6887a69003555edf5c6caaa75f2592228558c595/index.js
+ * (released under the MIT licence).
+ */
+ function escapeForJsComment( s ) {
+ return s.replace( /[\n\r\u2028\u2029]/g, function ( character ) {
+ switch ( character ) {
+ // Escape possible LineTerminator characters
+ case '\n':
+ return '\\n';
+ case '\r':
+ return '\\r';
+ case '\u2028':
+ return '\\u2028';
+ case '\u2029':
+ return '\\u2029';
+ }
+ } );
+ }
+
+ /**
+ * Unescape a JavaScript string literal.
+ *
+ * This is the inverse of escapeForJsString.
+ */
+ function unescapeForJsString( s ) {
+ return s.replace( /\\"|\\'|\\\\|\\n|\\r|\\u2028|\\u2029/g, function ( substring ) {
+ switch ( substring ) {
+ case '\\"':
+ return '"';
+ case "\\'":
+ return "'";
+ case "\\\\":
+ return "\\";
+ case "\\r":
+ return "\r";
+ case "\\n":
+ return "\n";
+ case "\\u2028":
+ return "\u2028";
+ case "\\u2029":
+ return "\u2029";
+ }
+ } );
+ }
+
function getFullTarget ( target ) {
return USER_NAMESPACE_NAME + ":" + mw.config.get( "wgUserName" ) + "/" +
target + ".js";
--
2.25.1

File Metadata

Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
9341272
Default Alt Text
T300743-enwiki3.patch (6 KB)

Event Timeline