From 08cfa88249f12262d0f5d4d371e3d6a5a2cecf1b Mon Sep 17 00:00:00 2001 From: Jermolene Date: Thu, 4 Aug 2016 15:54:33 +0100 Subject: [PATCH] Fix problem with unsafe use of `String.prototype.replace()` We were using `String.prototype.replace()` without addressing the wrinkle that dollar signs in the replacement string have special handling. This caused problems in situations where the replacement string is derived from user input and contains dollar signs. Fixes #2517 --- core/modules/utils/utils.js | 9 +++++++++ core/modules/widgets/fields.js | 6 +++--- core/modules/widgets/link.js | 4 ++-- core/modules/widgets/widget.js | 2 +- plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/core/modules/utils/utils.js b/core/modules/utils/utils.js index e322811d9..2d599eac3 100644 --- a/core/modules/utils/utils.js +++ b/core/modules/utils/utils.js @@ -19,6 +19,15 @@ exports.warning = function(text) { console.log($tw.node ? "\x1b[1;33m" + text + "\x1b[0m" : text); }; +/* +Repeatedly replaces a substring within a string. Like String.prototype.replace, but without any of the default special handling of $ sequences in the replace string +*/ +exports.replaceString = function(text,search,replace) { + return text.replace(search,function() { + return replace; + }); +}; + /* Repeats a string */ diff --git a/core/modules/widgets/fields.js b/core/modules/widgets/fields.js index 511b6f7d5..d75a3b6e9 100755 --- a/core/modules/widgets/fields.js +++ b/core/modules/widgets/fields.js @@ -75,9 +75,9 @@ FieldsWidget.prototype.execute = function() { value = reMatch[1]; } } - row = row.replace("$name$",fieldName); - row = row.replace("$value$",value); - row = row.replace("$encoded_value$",$tw.utils.htmlEncode(value)); + row = $tw.utils.replaceString(row,"$name$",fieldName); + row = $tw.utils.replaceString(row,"$value$",value); + row = $tw.utils.replaceString(row,"$encoded_value$",$tw.utils.htmlEncode(value)); text.push(row); } } diff --git a/core/modules/widgets/link.js b/core/modules/widgets/link.js index b0deb4e51..e4596c72c 100755 --- a/core/modules/widgets/link.js +++ b/core/modules/widgets/link.js @@ -82,8 +82,8 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) { // Set an href var wikiLinkTemplateMacro = this.getVariable("tv-wikilink-template"), wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$", - wikiLinkText = wikiLinkTemplate.replace("$uri_encoded$",encodeURIComponent(this.to)); - wikiLinkText = wikiLinkText.replace("$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to))); + wikiLinkText = $tw.utils.replaceString(wikiLinkTemplate,"$uri_encoded$",encodeURIComponent(this.to)); + wikiLinkText = $tw.utils.replaceString(wikiLinkText,"$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to))); wikiLinkText = this.getVariable("tv-get-export-link",{params: [{name: "to",value: this.to}],defaultValue: wikiLinkText}); if(tag === "a") { domNode.setAttribute("href",wikiLinkText); diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index cf51fcbe4..f8a977eef 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -125,7 +125,7 @@ Widget.prototype.substituteVariableParameters = function(text,formalParams,actua // If we've still not got a value, use the default, if any paramValue = paramValue || paramInfo["default"] || ""; // Replace any instances of this parameter - text = text.replace(new RegExp("\\$" + $tw.utils.escapeRegExp(paramInfo.name) + "\\$","mg"),paramValue); + text = $tw.utils.replaceString(text,new RegExp("\\$" + $tw.utils.escapeRegExp(paramInfo.name) + "\\$","mg"),paramValue); } } return text; diff --git a/plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js b/plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js index 282c81dcc..9666ed0f8 100644 --- a/plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js +++ b/plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js @@ -35,7 +35,7 @@ TiddlyWebAdaptor.prototype.getHost = function() { ]; for(var t=0; t