From f9a1951ec5039f03b94eb5ba749bdc312d73ff5b Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Fri, 13 Oct 2017 10:53:02 -0600
Subject: [PATCH 1/3] Enable running multiple upgrades at once
---
app.js | 9 ++++-----
src/upgrade.js | 18 +++++++-----------
2 files changed, 11 insertions(+), 16 deletions(-)
diff --git a/app.js b/app.js
index 686b355602..4ce28da224 100644
--- a/app.js
+++ b/app.js
@@ -219,14 +219,13 @@ function upgrade() {
var meta = require('./src/meta');
var upgrade = require('./src/upgrade');
var build = require('./src/meta/build');
- var tasks = [db.init, meta.configs.init, upgrade.run, build.buildAll];
+ var tasks = [db.init, meta.configs.init];
if (nconf.get('upgrade') !== true) {
// Likely an upgrade script name passed in
- tasks[2] = async.apply(upgrade.runSingle, nconf.get('upgrade'));
-
- // Skip build
- tasks.pop();
+ tasks.push(async.apply(upgrade.runParticular, nconf.get('upgrade').split(',')));
+ } else {
+ tasks.push(upgrade.run, build.buildAll);
}
// disable mongo timeouts during upgrade
nconf.set('mongo:options:socketTimeoutMS', 0);
diff --git a/src/upgrade.js b/src/upgrade.js
index f1f5a016ad..97f5287bc6 100644
--- a/src/upgrade.js
+++ b/src/upgrade.js
@@ -87,23 +87,19 @@ Upgrade.run = function (callback) {
});
};
-Upgrade.runSingle = function (query, callback) {
+Upgrade.runParticular = function (names, callback) {
process.stdout.write('\nParsing upgrade scripts... ');
async.waterfall([
async.apply(file.walk, path.join(__dirname, './upgrades')),
function (files, next) {
- next(null, files.filter(function (file) {
- return path.basename(file, '.js') === query;
- }));
- },
- ], function (err, files) {
- if (err) {
- return callback(err);
- }
+ var upgrades = files.filter(function (file) {
+ return names.indexOf(path.basename(file, '.js')) !== -1;
+ });
- Upgrade.process(files, 0, callback);
- });
+ Upgrade.process(upgrades, 0, next);
+ },
+ ], callback);
};
Upgrade.process = function (files, skipCount, callback) {
From 46fafb20b9079e68155db3e0f233a8df8003c47c Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Fri, 13 Oct 2017 21:02:41 -0600
Subject: [PATCH 2/3] Remove string.js dependency
---
package.json | 1 -
public/src/modules/helpers.js | 10 +-
public/src/modules/string.js | 3 -
public/src/modules/translator.js | 35 ++--
public/src/utils.js | 313 +++++++++++++++++++++++++++-
src/controllers/accounts/profile.js | 4 +-
src/controllers/topics.js | 3 +-
src/flags.js | 3 +-
src/messaging.js | 3 +-
src/messaging/data.js | 3 +-
src/meta/js.js | 1 -
src/notifications.js | 5 +-
src/posts/parse.js | 5 +-
src/posts/summary.js | 4 +-
src/socket.io/helpers.js | 6 +-
src/socket.io/posts/edit.js | 4 +-
src/topics/create.js | 4 +-
src/topics/follow.js | 4 +-
src/topics/teaser.js | 4 +-
src/user/notifications.js | 4 +-
src/user/profile.js | 3 +-
test/build.js | 1 -
test/utils.js | 22 ++
23 files changed, 383 insertions(+), 62 deletions(-)
delete mode 100644 public/src/modules/string.js
diff --git a/package.json b/package.json
index 89456f495d..2d1318e5d2 100644
--- a/package.json
+++ b/package.json
@@ -90,7 +90,6 @@
"socket.io-redis": "5.2.0",
"socketio-wildcard": "2.0.0",
"spdx-license-list": "^3.0.1",
- "string": "^3.3.3",
"toobusy-js": "^0.5.1",
"uglify-js": "^3.1.3",
"validator": "9.0.0",
diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js
index 736926101d..77a060ed7a 100644
--- a/public/src/modules/helpers.js
+++ b/public/src/modules/helpers.js
@@ -3,13 +3,13 @@
(function (factory) {
if (typeof module === 'object' && module.exports) {
var relative_path = require('nconf').get('relative_path');
- module.exports = factory(require('../utils'), require('benchpressjs'), require('string'), relative_path);
+ module.exports = factory(require('../utils'), require('benchpressjs'), relative_path);
} else if (typeof define === 'function' && define.amd) {
- define('helpers', ['benchpress', 'string'], function (Benchpress, string) {
- return factory(utils, Benchpress, string, config.relative_path);
+ define('helpers', ['benchpress'], function (Benchpress) {
+ return factory(utils, Benchpress, config.relative_path);
});
}
-}(function (utils, Benchpress, S, relative_path) {
+}(function (utils, Benchpress, relative_path) {
var helpers = {
displayMenuItem: displayMenuItem,
buildMetaTag: buildMetaTag,
@@ -92,7 +92,7 @@
}
function stripTags(str) {
- return S(String(str)).stripTags().s;
+ return utils.stripHTMLTags(str);
}
function generateCategoryBackground(category) {
diff --git a/public/src/modules/string.js b/public/src/modules/string.js
deleted file mode 100644
index a06e1862f9..0000000000
--- a/public/src/modules/string.js
+++ /dev/null
@@ -1,3 +0,0 @@
-/*
-string.js - Copyright (C) 2012-2013, JP Richardson
-*/!function(){"use strict";function n(e,t){t!==null&&t!==undefined?typeof t=="string"?e.s=t:e.s=t.toString():e.s=t,e.orig=t,t!==null&&t!==undefined?e.__defineGetter__?e.__defineGetter__("length",function(){return e.s.length}):e.length=t.length:e.length=-1}function r(e){n(this,e)}function u(){for(var e in s)(function(e){var t=s[e];i.hasOwnProperty(e)||(o.push(e),i[e]=function(){return String.prototype.s=this,t.apply(this,arguments)})})(e)}function a(){for(var e=0;er?n.slice(s,i):"")},camelize:function(){var e=this.trim().s.replace(/(\-|_|\s)+(.)?/g,function(e,t,n){return n?n.toUpperCase():""});return new this.constructor(e)},capitalize:function(){return new this.constructor(this.s.substr(0,1).toUpperCase()+this.s.substring(1).toLowerCase())},charAt:function(e){return this.s.charAt(e)},chompLeft:function(e){var t=this.s;return t.indexOf(e)===0?(t=t.slice(e.length),new this.constructor(t)):this},chompRight:function(e){if(this.endsWith(e)){var t=this.s;return t=t.slice(0,t.length-e.length),new this.constructor(t)}return this},collapseWhitespace:function(){var e=this.s.replace(/[\s\xa0]+/g," ").replace(/^\s+|\s+$/g,"");return new this.constructor(e)},contains:function(e){return this.s.indexOf(e)>=0},count:function(e){var t=0,n=this.s.indexOf(e);while(n>=0)t+=1,n=this.s.indexOf(e,n+1);return t},dasherize:function(){var e=this.trim().s.replace(/[_\s]+/g,"-").replace(/([A-Z])/g,"-$1").replace(/-+/g,"-").toLowerCase();return new this.constructor(e)},decodeHtmlEntities:function(){var e=this.s;return e=e.replace(/(\d+);?/g,function(e,t){return String.fromCharCode(t)}).replace(/[xX]([A-Fa-f0-9]+);?/g,function(e,t){return String.fromCharCode(parseInt(t,16))}).replace(/&([^;\W]+;?)/g,function(e,n){var r=n.replace(/;$/,""),i=t[n]||n.match(/;$/)&&t[r];return typeof i=="number"?String.fromCharCode(i):typeof i=="string"?i:e}),new this.constructor(e)},endsWith:function(e){var t=this.s.length-e.length;return t>=0&&this.s.indexOf(e,t)===t},escapeHTML:function(){return new this.constructor(this.s.replace(/[&<>"']/g,function(e){return"&"+m[e]+";"}))},ensureLeft:function(e){var t=this.s;return t.indexOf(e)===0?this:new this.constructor(e+t)},ensureRight:function(e){var t=this.s;return this.endsWith(e)?this:new this.constructor(t+e)},humanize:function(){if(this.s===null||this.s===undefined)return new this.constructor("");var e=this.underscore().replace(/_id$/,"").replace(/_/g," ").trim().capitalize();return new this.constructor(e)},isAlpha:function(){return!/[^a-z\xC0-\xFF]/.test(this.s.toLowerCase())},isAlphaNumeric:function(){return!/[^0-9a-z\xC0-\xFF]/.test(this.s.toLowerCase())},isEmpty:function(){return this.s===null||this.s===undefined?!0:/^[\s\xa0]*$/.test(this.s)},isLower:function(){return this.isAlpha()&&this.s.toLowerCase()===this.s},isNumeric:function(){return!/[^0-9]/.test(this.s)},isUpper:function(){return this.isAlpha()&&this.s.toUpperCase()===this.s},left:function(e){if(e>=0){var t=this.s.substr(0,e);return new this.constructor(t)}return this.right(-e)},lines:function(){return this.replaceAll("\r\n","\n").s.split("\n")},pad:function(e,t){t==null&&(t=" ");if(this.s.length>=e)return new this.constructor(this.s);e-=this.s.length;var n=Array(Math.ceil(e/2)+1).join(t),r=Array(Math.floor(e/2)+1).join(t);return new this.constructor(n+this.s+r)},padLeft:function(e,t){return t==null&&(t=" "),this.s.length>=e?new this.constructor(this.s):new this.constructor(Array(e-this.s.length+1).join(t)+this.s)},padRight:function(e,t){return t==null&&(t=" "),this.s.length>=e?new this.constructor(this.s):new this.constructor(this.s+Array(e-this.s.length+1).join(t))},parseCSV:function(e,t,n,r){e=e||",",n=n||"\\",typeof t=="undefined"&&(t='"');var i=0,s=[],o=[],u=this.s.length,a=!1,f=this,l=function(e){return f.s.charAt(e)};if(typeof r!="undefined")var c=[];t||(a=!0);while(i=0){var t=this.s.substr(this.s.length-e,e);return new this.constructor(t)}return this.left(-e)},setValue:function(e){return n(this,e),this},slugify:function(){var e=(new r(this.s.replace(/[^\w\s-]/g,"").toLowerCase())).dasherize().s;return e.charAt(0)==="-"&&(e=e.substr(1)),new this.constructor(e)},startsWith:function(e){return this.s.lastIndexOf(e,0)===0},stripPunctuation:function(){return new this.constructor(this.s.replace(/[^\w\s]|_/g,"").replace(/\s+/g," "))},stripTags:function(){var e=this.s,t=arguments.length>0?arguments:[""];return d(t,function(t){e=e.replace(RegExp("?"+t+"[^<>]*>","gi"),"")}),new this.constructor(e)},template:function(e,t,n){var r=this.s,t=t||p.TMPL_OPEN,n=n||p.TMPL_CLOSE,i=t.replace(/[-[\]()*\s]/g,"\\$&").replace(/\$/g,"\\$"),s=n.replace(/[-[\]()*\s]/g,"\\$&").replace(/\$/g,"\\$"),o=new RegExp(i+"(.+?)"+s,"g"),u=r.match(o)||[];return u.forEach(function(i){var s=i.substring(t.length,i.length-n.length);typeof e[s]!="undefined"&&(r=r.replace(i,e[s]))}),new this.constructor(r)},times:function(e){return new this.constructor((new Array(e+1)).join(this.s))},toBoolean:function(){if(typeof this.orig=="string"){var e=this.s.toLowerCase();return e==="true"||e==="yes"||e==="on"}return this.orig===!0||this.orig===1},toFloat:function(e){var t=parseFloat(this.s);return e?parseFloat(t.toFixed(e)):t},toInt:function(){return/^\s*-?0x/i.test(this.s)?parseInt(this.s,16):parseInt(this.s,10)},trim:function(){var e;return typeof i.trim=="undefined"?e=this.s.replace(/(^\s*|\s*$)/g,""):e=this.s.trim(),new this.constructor(e)},trimLeft:function(){var e;return i.trimLeft?e=this.s.trimLeft():e=this.s.replace(/(^\s*)/g,""),new this.constructor(e)},trimRight:function(){var e;return i.trimRight?e=this.s.trimRight():e=this.s.replace(/\s+$/,""),new this.constructor(e)},truncate:function(e,t){var n=this.s;e=~~e,t=t||"...";if(n.length<=e)return new this.constructor(n);var i=function(e){return e.toUpperCase()!==e.toLowerCase()?"A":" "},s=n.slice(0,e+1).replace(/.(?=\W*\w*$)/g,i);return s.slice(s.length-2).match(/\w\w/)?s=s.replace(/\s*\S+$/,""):s=(new r(s.slice(0,s.length-1))).trimRight().s,(s+t).length>n.length?new r(n):new r(n.slice(0,s.length)+t)},toCSV:function(){function u(e){return e!==null&&e!==""}var e=",",t='"',n="\\",i=!0,s=!1,o=[];typeof arguments[0]=="object"?(e=arguments[0].delimiter||e,e=arguments[0].separator||e,t=arguments[0].qualifier||t,i=!!arguments[0].encloseNumbers,n=arguments[0].escape||n,s=!!arguments[0].keys):typeof arguments[0]=="string"&&(e=arguments[0]),typeof arguments[1]=="string"&&(t=arguments[1]),arguments[1]===null&&(t=null);if(this.orig instanceof Array)o=this.orig;else for(var a in this.orig)this.orig.hasOwnProperty(a)&&(s?o.push(a):o.push(this.orig[a]));var f=n+t,l=[];for(var c=0;c",quot:'"',apos:"'",amp:"&"},m={};for(var g in v)m[v[g]]=g;t={amp:"&",gt:">",lt:"<",quot:'"',apos:"'",AElig:198,Aacute:193,Acirc:194,Agrave:192,Aring:197,Atilde:195,Auml:196,Ccedil:199,ETH:208,Eacute:201,Ecirc:202,Egrave:200,Euml:203,Iacute:205,Icirc:206,Igrave:204,Iuml:207,Ntilde:209,Oacute:211,Ocirc:212,Ograve:210,Oslash:216,Otilde:213,Ouml:214,THORN:222,Uacute:218,Ucirc:219,Ugrave:217,Uuml:220,Yacute:221,aacute:225,acirc:226,aelig:230,agrave:224,aring:229,atilde:227,auml:228,ccedil:231,eacute:233,ecirc:234,egrave:232,eth:240,euml:235,iacute:237,icirc:238,igrave:236,iuml:239,ntilde:241,oacute:243,ocirc:244,ograve:242,oslash:248,otilde:245,ouml:246,szlig:223,thorn:254,uacute:250,ucirc:251,ugrave:249,uuml:252,yacute:253,yuml:255,copy:169,reg:174,nbsp:160,iexcl:161,cent:162,pound:163,curren:164,yen:165,brvbar:166,sect:167,uml:168,ordf:170,laquo:171,not:172,shy:173,macr:175,deg:176,plusmn:177,sup1:185,sup2:178,sup3:179,acute:180,micro:181,para:182,middot:183,cedil:184,ordm:186,raquo:187,frac14:188,frac12:189,frac34:190,iquest:191,times:215,divide:247,"OElig;":338,"oelig;":339,"Scaron;":352,"scaron;":353,"Yuml;":376,"fnof;":402,"circ;":710,"tilde;":732,"Alpha;":913,"Beta;":914,"Gamma;":915,"Delta;":916,"Epsilon;":917,"Zeta;":918,"Eta;":919,"Theta;":920,"Iota;":921,"Kappa;":922,"Lambda;":923,"Mu;":924,"Nu;":925,"Xi;":926,"Omicron;":927,"Pi;":928,"Rho;":929,"Sigma;":931,"Tau;":932,"Upsilon;":933,"Phi;":934,"Chi;":935,"Psi;":936,"Omega;":937,"alpha;":945,"beta;":946,"gamma;":947,"delta;":948,"epsilon;":949,"zeta;":950,"eta;":951,"theta;":952,"iota;":953,"kappa;":954,"lambda;":955,"mu;":956,"nu;":957,"xi;":958,"omicron;":959,"pi;":960,"rho;":961,"sigmaf;":962,"sigma;":963,"tau;":964,"upsilon;":965,"phi;":966,"chi;":967,"psi;":968,"omega;":969,"thetasym;":977,"upsih;":978,"piv;":982,"ensp;":8194,"emsp;":8195,"thinsp;":8201,"zwnj;":8204,"zwj;":8205,"lrm;":8206,"rlm;":8207,"ndash;":8211,"mdash;":8212,"lsquo;":8216,"rsquo;":8217,"sbquo;":8218,"ldquo;":8220,"rdquo;":8221,"bdquo;":8222,"dagger;":8224,"Dagger;":8225,"bull;":8226,"hellip;":8230,"permil;":8240,"prime;":8242,"Prime;":8243,"lsaquo;":8249,"rsaquo;":8250,"oline;":8254,"frasl;":8260,"euro;":8364,"image;":8465,"weierp;":8472,"real;":8476,"trade;":8482,"alefsym;":8501,"larr;":8592,"uarr;":8593,"rarr;":8594,"darr;":8595,"harr;":8596,"crarr;":8629,"lArr;":8656,"uArr;":8657,"rArr;":8658,"dArr;":8659,"hArr;":8660,"forall;":8704,"part;":8706,"exist;":8707,"empty;":8709,"nabla;":8711,"isin;":8712,"notin;":8713,"ni;":8715,"prod;":8719,"sum;":8721,"minus;":8722,"lowast;":8727,"radic;":8730,"prop;":8733,"infin;":8734,"ang;":8736,"and;":8743,"or;":8744,"cap;":8745,"cup;":8746,"int;":8747,"there4;":8756,"sim;":8764,"cong;":8773,"asymp;":8776,"ne;":8800,"equiv;":8801,"le;":8804,"ge;":8805,"sub;":8834,"sup;":8835,"nsub;":8836,"sube;":8838,"supe;":8839,"oplus;":8853,"otimes;":8855,"perp;":8869,"sdot;":8901,"lceil;":8968,"rceil;":8969,"lfloor;":8970,"rfloor;":8971,"lang;":9001,"rang;":9002,"loz;":9674,"spades;":9824,"clubs;":9827,"hearts;":9829,"diams;":9830}}.call(this);
diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js
index 465a240e4e..cd0d3c75c1 100644
--- a/public/src/modules/translator.js
+++ b/public/src/modules/translator.js
@@ -10,8 +10,8 @@
}
if (typeof define === 'function' && define.amd) {
// AMD. Register as a named module
- define('translator', ['string'], function (string) {
- return factory(string, loadClient, warn);
+ define('translator', [], function () {
+ return factory(utils, loadClient, warn);
});
} else if (typeof module === 'object' && module.exports) {
// Node
@@ -37,15 +37,23 @@
});
}
- module.exports = factory(require('string'), loadServer, warn);
+ module.exports = factory(require('../utils'), loadServer, warn);
}());
- } else {
- window.translator = factory(window.string, loadClient, warn);
}
-}(function (string, load, warn) {
+}(function (utils, load, warn) {
var assign = Object.assign || jQuery.extend;
function classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+ function escapeHTML(str) {
+ return utils.decodeHTMLEntities(
+ String(str)
+ .replace(/[\s\xa0]+/g, ' ')
+ .replace(/^\s+|\s+$/g, '')
+ ).replace(/[<>]/g, function (c) {
+ return c === '<' ? '<' : '>';
+ });
+ }
+
var Translator = (function () {
/**
* Construct a new Translator object
@@ -284,9 +292,7 @@
}
var argsToTranslate = args.map(function (arg) {
- return string(arg).collapseWhitespace().decodeHTMLEntities().escapeHTML().s.replace(/&/g, '&');
- }).map(function (arg) {
- return self.translate(arg);
+ return self.translate(escapeHTML(arg));
});
return Promise.all(argsToTranslate).then(function (translatedArgs) {
@@ -539,12 +545,13 @@
return cb('');
}
- Translator.create(lang).translate(text).catch(function (err) {
+ return Translator.create(lang).translate(text).then(function (output) {
+ if (cb) {
+ setTimeout(cb, 0, output);
+ }
+ return output;
+ }, function (err) {
warn('Translation failed: ' + err.stack);
- }).then(function (output) {
- cb(output);
- }).catch(function (err) {
- console.error(err);
});
},
diff --git a/public/src/utils.js b/public/src/utils.js
index 910082a430..328c73ebe0 100644
--- a/public/src/utils.js
+++ b/public/src/utils.js
@@ -25,6 +25,279 @@
window.utils = factory(window.XRegExp);
}
}(function (XRegExp) {
+ var freeze = Object.freeze || function (obj) { return obj; };
+
+ // add default escape function for escaping HTML entities
+ var escapeCharMap = freeze({
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`',
+ '=': '=',
+ });
+ function replaceChar(c) {
+ return escapeCharMap[c];
+ }
+ var escapeChars = /[&<>"'`=]/g;
+
+ var HTMLEntities = freeze({
+ amp: '&',
+ gt: '>',
+ lt: '<',
+ quot: '"',
+ apos: "'",
+ AElig: 198,
+ Aacute: 193,
+ Acirc: 194,
+ Agrave: 192,
+ Aring: 197,
+ Atilde: 195,
+ Auml: 196,
+ Ccedil: 199,
+ ETH: 208,
+ Eacute: 201,
+ Ecirc: 202,
+ Egrave: 200,
+ Euml: 203,
+ Iacute: 205,
+ Icirc: 206,
+ Igrave: 204,
+ Iuml: 207,
+ Ntilde: 209,
+ Oacute: 211,
+ Ocirc: 212,
+ Ograve: 210,
+ Oslash: 216,
+ Otilde: 213,
+ Ouml: 214,
+ THORN: 222,
+ Uacute: 218,
+ Ucirc: 219,
+ Ugrave: 217,
+ Uuml: 220,
+ Yacute: 221,
+ aacute: 225,
+ acirc: 226,
+ aelig: 230,
+ agrave: 224,
+ aring: 229,
+ atilde: 227,
+ auml: 228,
+ ccedil: 231,
+ eacute: 233,
+ ecirc: 234,
+ egrave: 232,
+ eth: 240,
+ euml: 235,
+ iacute: 237,
+ icirc: 238,
+ igrave: 236,
+ iuml: 239,
+ ntilde: 241,
+ oacute: 243,
+ ocirc: 244,
+ ograve: 242,
+ oslash: 248,
+ otilde: 245,
+ ouml: 246,
+ szlig: 223,
+ thorn: 254,
+ uacute: 250,
+ ucirc: 251,
+ ugrave: 249,
+ uuml: 252,
+ yacute: 253,
+ yuml: 255,
+ copy: 169,
+ reg: 174,
+ nbsp: 160,
+ iexcl: 161,
+ cent: 162,
+ pound: 163,
+ curren: 164,
+ yen: 165,
+ brvbar: 166,
+ sect: 167,
+ uml: 168,
+ ordf: 170,
+ laquo: 171,
+ not: 172,
+ shy: 173,
+ macr: 175,
+ deg: 176,
+ plusmn: 177,
+ sup1: 185,
+ sup2: 178,
+ sup3: 179,
+ acute: 180,
+ micro: 181,
+ para: 182,
+ middot: 183,
+ cedil: 184,
+ ordm: 186,
+ raquo: 187,
+ frac14: 188,
+ frac12: 189,
+ frac34: 190,
+ iquest: 191,
+ times: 215,
+ divide: 247,
+ 'OElig;': 338,
+ 'oelig;': 339,
+ 'Scaron;': 352,
+ 'scaron;': 353,
+ 'Yuml;': 376,
+ 'fnof;': 402,
+ 'circ;': 710,
+ 'tilde;': 732,
+ 'Alpha;': 913,
+ 'Beta;': 914,
+ 'Gamma;': 915,
+ 'Delta;': 916,
+ 'Epsilon;': 917,
+ 'Zeta;': 918,
+ 'Eta;': 919,
+ 'Theta;': 920,
+ 'Iota;': 921,
+ 'Kappa;': 922,
+ 'Lambda;': 923,
+ 'Mu;': 924,
+ 'Nu;': 925,
+ 'Xi;': 926,
+ 'Omicron;': 927,
+ 'Pi;': 928,
+ 'Rho;': 929,
+ 'Sigma;': 931,
+ 'Tau;': 932,
+ 'Upsilon;': 933,
+ 'Phi;': 934,
+ 'Chi;': 935,
+ 'Psi;': 936,
+ 'Omega;': 937,
+ 'alpha;': 945,
+ 'beta;': 946,
+ 'gamma;': 947,
+ 'delta;': 948,
+ 'epsilon;': 949,
+ 'zeta;': 950,
+ 'eta;': 951,
+ 'theta;': 952,
+ 'iota;': 953,
+ 'kappa;': 954,
+ 'lambda;': 955,
+ 'mu;': 956,
+ 'nu;': 957,
+ 'xi;': 958,
+ 'omicron;': 959,
+ 'pi;': 960,
+ 'rho;': 961,
+ 'sigmaf;': 962,
+ 'sigma;': 963,
+ 'tau;': 964,
+ 'upsilon;': 965,
+ 'phi;': 966,
+ 'chi;': 967,
+ 'psi;': 968,
+ 'omega;': 969,
+ 'thetasym;': 977,
+ 'upsih;': 978,
+ 'piv;': 982,
+ 'ensp;': 8194,
+ 'emsp;': 8195,
+ 'thinsp;': 8201,
+ 'zwnj;': 8204,
+ 'zwj;': 8205,
+ 'lrm;': 8206,
+ 'rlm;': 8207,
+ 'ndash;': 8211,
+ 'mdash;': 8212,
+ 'lsquo;': 8216,
+ 'rsquo;': 8217,
+ 'sbquo;': 8218,
+ 'ldquo;': 8220,
+ 'rdquo;': 8221,
+ 'bdquo;': 8222,
+ 'dagger;': 8224,
+ 'Dagger;': 8225,
+ 'bull;': 8226,
+ 'hellip;': 8230,
+ 'permil;': 8240,
+ 'prime;': 8242,
+ 'Prime;': 8243,
+ 'lsaquo;': 8249,
+ 'rsaquo;': 8250,
+ 'oline;': 8254,
+ 'frasl;': 8260,
+ 'euro;': 8364,
+ 'image;': 8465,
+ 'weierp;': 8472,
+ 'real;': 8476,
+ 'trade;': 8482,
+ 'alefsym;': 8501,
+ 'larr;': 8592,
+ 'uarr;': 8593,
+ 'rarr;': 8594,
+ 'darr;': 8595,
+ 'harr;': 8596,
+ 'crarr;': 8629,
+ 'lArr;': 8656,
+ 'uArr;': 8657,
+ 'rArr;': 8658,
+ 'dArr;': 8659,
+ 'hArr;': 8660,
+ 'forall;': 8704,
+ 'part;': 8706,
+ 'exist;': 8707,
+ 'empty;': 8709,
+ 'nabla;': 8711,
+ 'isin;': 8712,
+ 'notin;': 8713,
+ 'ni;': 8715,
+ 'prod;': 8719,
+ 'sum;': 8721,
+ 'minus;': 8722,
+ 'lowast;': 8727,
+ 'radic;': 8730,
+ 'prop;': 8733,
+ 'infin;': 8734,
+ 'ang;': 8736,
+ 'and;': 8743,
+ 'or;': 8744,
+ 'cap;': 8745,
+ 'cup;': 8746,
+ 'int;': 8747,
+ 'there4;': 8756,
+ 'sim;': 8764,
+ 'cong;': 8773,
+ 'asymp;': 8776,
+ 'ne;': 8800,
+ 'equiv;': 8801,
+ 'le;': 8804,
+ 'ge;': 8805,
+ 'sub;': 8834,
+ 'sup;': 8835,
+ 'nsub;': 8836,
+ 'sube;': 8838,
+ 'supe;': 8839,
+ 'oplus;': 8853,
+ 'otimes;': 8855,
+ 'perp;': 8869,
+ 'sdot;': 8901,
+ 'lceil;': 8968,
+ 'rceil;': 8969,
+ 'lfloor;': 8970,
+ 'rfloor;': 8971,
+ 'lang;': 9001,
+ 'rang;': 9002,
+ 'loz;': 9674,
+ 'spades;': 9824,
+ 'clubs;': 9827,
+ 'hearts;': 9829,
+ 'diams;': 9830,
+ });
+
var utils = {
generateUUID: function () {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
@@ -33,6 +306,35 @@
return v.toString(16);
});
},
+ // https://github.com/substack/node-ent/blob/master/index.js
+ decodeHTMLEntities: function (html) {
+ return String(html)
+ .replace(/(\d+);?/g, function (_, code) {
+ return String.fromCharCode(code);
+ })
+ .replace(/[xX]([A-Fa-f0-9]+);?/g, function (_, hex) {
+ return String.fromCharCode(parseInt(hex, 16));
+ })
+ .replace(/&([^;\W]+;?)/g, function (m, e) {
+ var ee = e.replace(/;$/, '');
+ var target = HTMLEntities[e] || (e.match(/;$/) && HTMLEntities[ee]);
+
+ if (typeof target === 'number') {
+ return String.fromCharCode(target);
+ } else if (typeof target === 'string') {
+ return target;
+ }
+
+ return m;
+ });
+ },
+ // https://github.com/jprichardson/string.js/blob/master/lib/string.js
+ stripHTMLTags: function (str, tags) {
+ var pattern = (tags || ['']).map(function (tag) {
+ return utils.escapeRegexChars(tag);
+ }).join('|');
+ return String(str).replace(new RegExp('?(?:' + pattern + ')[^<>]*>', 'gi'), '');
+ },
invalidUnicodeChars: XRegExp('[^\\p{L}\\s\\d\\-_]', 'g'),
invalidLatinChars: /[^\w\s\d\-_]/g,
@@ -232,8 +534,15 @@
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
},
- escapeHTML: function (raw) {
- return raw.replace(/&/gm, '&').replace(//gm, '>');
+ escapeHTML: function (str) {
+ if (str == null) {
+ return '';
+ }
+ if (!str) {
+ return String(str);
+ }
+
+ return str.toString().replace(escapeChars, replaceChar);
},
isAndroidBrowser: function () {
diff --git a/src/controllers/accounts/profile.js b/src/controllers/accounts/profile.js
index e067ed3ef5..fc9f9cb5b4 100644
--- a/src/controllers/accounts/profile.js
+++ b/src/controllers/accounts/profile.js
@@ -2,7 +2,6 @@
var nconf = require('nconf');
var async = require('async');
-var S = require('string');
var user = require('../../user');
var posts = require('../../posts');
@@ -13,6 +12,7 @@ var helpers = require('../helpers');
var pagination = require('../../pagination');
var messaging = require('../../messaging');
var translator = require('../../translator');
+var utils = require('../../utils');
var profileController = module.exports;
@@ -87,7 +87,7 @@ profileController.get = function (req, res, callback) {
userData.profileviews = 1;
}
- var plainAboutMe = userData.aboutme ? S(userData.aboutme).decodeHTMLEntities().stripTags().s : '';
+ var plainAboutMe = userData.aboutme ? utils.stripHTMLTags(utils.decodeHTMLEntities(userData.aboutme)) : '';
res.locals.metaTags = [
{
diff --git a/src/controllers/topics.js b/src/controllers/topics.js
index d3a4846390..c75f5c3602 100644
--- a/src/controllers/topics.js
+++ b/src/controllers/topics.js
@@ -2,7 +2,6 @@
var async = require('async');
-var S = require('string');
var nconf = require('nconf');
var user = require('../user');
@@ -217,7 +216,7 @@ function addTags(topicData, req, res) {
var postAtIndex = findPost(Math.max(0, req.params.post_index - 1));
if (postAtIndex && postAtIndex.content) {
- description = S(postAtIndex.content).decodeHTMLEntities().stripTags().s;
+ description = utils.stripHTMLTags(utils.decodeHTMLEntities(postAtIndex.content));
}
if (description.length > 255) {
diff --git a/src/flags.js b/src/flags.js
index 749878db33..a578accf18 100644
--- a/src/flags.js
+++ b/src/flags.js
@@ -2,7 +2,6 @@
var async = require('async');
var _ = require('lodash');
-var S = require('string');
var winston = require('winston');
var validator = require('validator');
@@ -660,7 +659,7 @@ Flags.notify = function (flagObj, uid, callback) {
return callback(err);
}
- var title = S(results.title).decodeHTMLEntities().s;
+ var title = utils.decodeHTMLEntities(results.title);
var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
notifications.create({
diff --git a/src/messaging.js b/src/messaging.js
index 9a53f327ce..a90c36c2c5 100644
--- a/src/messaging.js
+++ b/src/messaging.js
@@ -2,7 +2,6 @@
var async = require('async');
-var S = require('string');
var validator = require('validator');
var db = require('./database');
@@ -215,7 +214,7 @@ Messaging.getTeaser = function (uid, roomId, callback) {
return callback();
}
if (teaser.content) {
- teaser.content = S(teaser.content).stripTags().decodeHTMLEntities().s;
+ teaser.content = utils.stripHTMLTags(utils.decodeHTMLEntities(teaser.content));
teaser.content = validator.escape(String(teaser.content));
}
diff --git a/src/messaging/data.js b/src/messaging/data.js
index b3a2ba58dd..88b6683a11 100644
--- a/src/messaging/data.js
+++ b/src/messaging/data.js
@@ -1,7 +1,6 @@
'use strict';
var async = require('async');
-var S = require('string');
var db = require('../database');
var user = require('../user');
@@ -73,7 +72,7 @@ module.exports = function (Messaging) {
return next(err);
}
message.content = result;
- message.cleanedContent = S(result).stripTags().decodeHTMLEntities().s;
+ message.cleanedContent = utils.stripHTMLTags(utils.decodeHTMLEntities(result));
next(null, message);
});
}, next);
diff --git a/src/meta/js.js b/src/meta/js.js
index 8082be2412..28c5255db0 100644
--- a/src/meta/js.js
+++ b/src/meta/js.js
@@ -72,7 +72,6 @@ JS.scripts = {
'public/src/modules/alerts.js',
'public/src/modules/taskbar.js',
'public/src/modules/helpers.js',
- 'public/src/modules/string.js',
'public/src/modules/flags.js',
'public/src/modules/storage.js',
],
diff --git a/src/notifications.js b/src/notifications.js
index 098efe5d9f..919d5a22e4 100644
--- a/src/notifications.js
+++ b/src/notifications.js
@@ -4,7 +4,6 @@ var async = require('async');
var winston = require('winston');
var cron = require('cron').CronJob;
var nconf = require('nconf');
-var S = require('string');
var _ = require('lodash');
var db = require('./database');
@@ -56,7 +55,7 @@ Notifications.getMultiple = function (nids, callback) {
notification.datetimeISO = utils.toISOString(notification.datetime);
if (notification.bodyLong) {
- notification.bodyLong = S(notification.bodyLong).escapeHTML().s;
+ notification.bodyLong = utils.escapeHTML(notification.bodyLong);
}
notification.user = usersData[index];
@@ -470,7 +469,7 @@ Notifications.merge = function (notifications, callback) {
});
var numUsers = usernames.length;
- var title = S(notifications[modifyIndex].topicTitle || '').decodeHTMLEntities().s;
+ var title = utils.decodeHTMLEntities(notifications[modifyIndex].topicTitle || '');
var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
titleEscaped = titleEscaped ? (', ' + titleEscaped) : '';
diff --git a/src/posts/parse.js b/src/posts/parse.js
index d46eaa800d..d6f7165f19 100644
--- a/src/posts/parse.js
+++ b/src/posts/parse.js
@@ -4,12 +4,12 @@ var async = require('async');
var nconf = require('nconf');
var url = require('url');
var winston = require('winston');
-var S = require('string');
var meta = require('../meta');
var cache = require('./cache');
var plugins = require('../plugins');
var translator = require('../translator');
+var utils = require('../utils');
module.exports = function (Posts) {
Posts.urlRegex = {
@@ -82,7 +82,6 @@ module.exports = function (Posts) {
function sanitizeSignature(signature) {
signature = translator.escape(signature);
- var string = S(signature);
var tagsToStrip = [];
if (parseInt(meta.config['signatures:disableLinks'], 10) === 1) {
@@ -93,6 +92,6 @@ module.exports = function (Posts) {
tagsToStrip.push('img');
}
- return tagsToStrip.length ? string.stripTags.apply(string, tagsToStrip).s : signature;
+ return utils.stripHTMLTags(signature, tagsToStrip);
}
};
diff --git a/src/posts/summary.js b/src/posts/summary.js
index 6c1b6d1958..902a003445 100644
--- a/src/posts/summary.js
+++ b/src/posts/summary.js
@@ -3,7 +3,6 @@
var async = require('async');
var validator = require('validator');
-var S = require('string');
var _ = require('lodash');
var topics = require('../topics');
@@ -144,8 +143,7 @@ module.exports = function (Posts) {
function stripTags(content) {
if (content) {
- var s = S(content);
- return s.stripTags.apply(s, utils.stripTags).s;
+ return utils.stripHTMLTags(content, utils.stripTags);
}
return content;
}
diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js
index 0f158cd080..cbc01aff60 100644
--- a/src/socket.io/helpers.js
+++ b/src/socket.io/helpers.js
@@ -2,7 +2,6 @@
var async = require('async');
var winston = require('winston');
-var S = require('string');
var db = require('../database');
var websockets = require('./index');
@@ -12,6 +11,7 @@ var topics = require('../topics');
var privileges = require('../privileges');
var notifications = require('../notifications');
var plugins = require('../plugins');
+var utils = require('../utils');
var SocketHelpers = {};
@@ -105,7 +105,7 @@ SocketHelpers.sendNotificationToPostOwner = function (pid, fromuid, command, not
}, next);
},
function (results, next) {
- var title = S(results.topicTitle).decodeHTMLEntities().s;
+ var title = utils.decodeHTMLEntities(results.topicTitle);
var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
notifications.create({
@@ -151,7 +151,7 @@ SocketHelpers.sendNotificationToTopicOwner = function (tid, fromuid, command, no
return;
}
ownerUid = results.topicData.uid;
- var title = S(results.topicData.title).decodeHTMLEntities().s;
+ var title = utils.decodeHTMLEntities(results.topicData.title);
var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
notifications.create({
diff --git a/src/socket.io/posts/edit.js b/src/socket.io/posts/edit.js
index 00ae540496..48f750c2ce 100644
--- a/src/socket.io/posts/edit.js
+++ b/src/socket.io/posts/edit.js
@@ -3,12 +3,12 @@
var async = require('async');
var validator = require('validator');
var _ = require('lodash');
-var S = require('string');
var posts = require('../../posts');
var groups = require('../../groups');
var events = require('../../events');
var meta = require('../../meta');
+var utils = require('../../utils');
var websockets = require('../index');
module.exports = function (SocketPosts) {
@@ -20,7 +20,7 @@ module.exports = function (SocketPosts) {
}
// Trim and remove HTML (latter for composers that send in HTML, like redactor)
- var contentLen = S(data.content).stripTags().s.trim().length;
+ var contentLen = utils.stripHTMLTags(data.content).trim().length;
if (data.title && data.title.length < parseInt(meta.config.minimumTitleLength, 10)) {
return callback(new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]'));
diff --git a/src/topics/create.js b/src/topics/create.js
index f5a51e7e77..edb1f1b84d 100644
--- a/src/topics/create.js
+++ b/src/topics/create.js
@@ -4,7 +4,7 @@
var async = require('async');
var _ = require('lodash');
var validator = require('validator');
-var S = require('string');
+
var db = require('../database');
var utils = require('../utils');
var plugins = require('../plugins');
@@ -343,7 +343,7 @@ module.exports = function (Topics) {
function check(item, min, max, minError, maxError, callback) {
// Trim and remove HTML (latter for composers that send in HTML, like redactor)
if (typeof item === 'string') {
- item = S(item).stripTags().s.trim();
+ item = utils.stripHTMLTags(item).trim();
}
if (item === null || item === undefined || item.length < parseInt(min, 10)) {
diff --git a/src/topics/follow.js b/src/topics/follow.js
index f1981766a2..f1bad3ccf3 100644
--- a/src/topics/follow.js
+++ b/src/topics/follow.js
@@ -2,7 +2,6 @@
'use strict';
var async = require('async');
-var S = require('string');
var winston = require('winston');
var db = require('../database');
@@ -13,6 +12,7 @@ var privileges = require('../privileges');
var meta = require('../meta');
var emailer = require('../emailer');
var plugins = require('../plugins');
+var utils = require('../utils');
module.exports = function (Topics) {
Topics.toggleFollow = function (tid, uid, callback) {
@@ -214,7 +214,7 @@ module.exports = function (Topics) {
title = postData.topic.title;
if (title) {
- title = S(title).decodeHTMLEntities().s;
+ title = utils.decodeHTMLEntities(title);
titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
}
diff --git a/src/topics/teaser.js b/src/topics/teaser.js
index 09d4d048ae..2827e74d41 100644
--- a/src/topics/teaser.js
+++ b/src/topics/teaser.js
@@ -3,7 +3,6 @@
var async = require('async');
var _ = require('lodash');
-var S = require('string');
var winston = require('winston');
var meta = require('../meta');
@@ -91,8 +90,7 @@ module.exports = function (Topics) {
if (tidToPost[topic.tid]) {
tidToPost[topic.tid].index = meta.config.teaserPost === 'first' ? 1 : counts[index];
if (tidToPost[topic.tid].content) {
- var s = S(tidToPost[topic.tid].content);
- tidToPost[topic.tid].content = s.stripTags.apply(s, utils.stripTags).s;
+ tidToPost[topic.tid].content = utils.stripHTMLTags(tidToPost[topic.tid].content, utils.stripTags);
}
}
return tidToPost[topic.tid];
diff --git a/src/user/notifications.js b/src/user/notifications.js
index 4e2dcba7e8..a446a9a822 100644
--- a/src/user/notifications.js
+++ b/src/user/notifications.js
@@ -3,12 +3,12 @@
var async = require('async');
var winston = require('winston');
-var S = require('string');
var db = require('../database');
var meta = require('../meta');
var notifications = require('../notifications');
var privileges = require('../privileges');
+var utils = require('../utils');
var UserNotifications = module.exports;
@@ -281,7 +281,7 @@ UserNotifications.sendTopicNotificationToFollowers = function (uid, topicData, p
var title = topicData.title;
if (title) {
- title = S(title).decodeHTMLEntities().s;
+ title = utils.decodeHTMLEntities(title);
}
notifications.create({
diff --git a/src/user/profile.js b/src/user/profile.js
index dbdcbcba85..70dffeebe6 100644
--- a/src/user/profile.js
+++ b/src/user/profile.js
@@ -2,7 +2,6 @@
'use strict';
var async = require('async');
-var S = require('string');
var utils = require('../utils');
var meta = require('../meta');
@@ -61,7 +60,7 @@ module.exports = function (User) {
} else if (field === 'fullname') {
return updateFullname(updateUid, data.fullname, next);
} else if (field === 'signature') {
- data[field] = S(data[field]).stripTags().s;
+ data[field] = utils.stripHTMLTags(data[field]);
}
User.setUserField(updateUid, field, data[field], next);
diff --git a/test/build.js b/test/build.js
index 1c346ad621..35471d0fd6 100644
--- a/test/build.js
+++ b/test/build.js
@@ -1,6 +1,5 @@
'use strict';
-var string = require('string');
var path = require('path');
var fs = require('fs');
var assert = require('assert');
diff --git a/test/utils.js b/test/utils.js
index d6821d9d4b..e76c1b9bff 100644
--- a/test/utils.js
+++ b/test/utils.js
@@ -16,6 +16,28 @@ describe('Utility Methods', function () {
var $ = global.$;
global.window = window;
+ // https://github.com/jprichardson/string.js/blob/master/test/string.test.js
+ it('should decode HTML entities', function (done) {
+ assert.strictEqual(
+ utils.decodeHTMLEntities('Ken Thompson & Dennis Ritchie'),
+ 'Ken Thompson & Dennis Ritchie'
+ );
+ assert.strictEqual(
+ utils.decodeHTMLEntities('3 < 4'),
+ '3 < 4'
+ );
+ assert.strictEqual(
+ utils.decodeHTMLEntities('http://'),
+ 'http://'
+ );
+ done();
+ });
+ it('should strip HTML tags', function (done) {
+ assert.strictEqual(utils.stripHTMLTags('just some text
'), 'just some text');
+ assert.strictEqual(utils.stripHTMLTags('just some text
', ['p']), 'just some text');
+ done();
+ });
+
it('should preserve case if requested', function (done) {
var slug = utils.slugify('UPPER CASE', true);
assert.equal(slug, 'UPPER-CASE');
From 190eea5691ac5a4a8f89154d5ef7a1b77c7c32fa Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Fri, 13 Oct 2017 21:17:57 -0600
Subject: [PATCH 3/3] Remove this useless check
---
public/src/modules/translator.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js
index cd0d3c75c1..18a42e4e8f 100644
--- a/public/src/modules/translator.js
+++ b/public/src/modules/translator.js
@@ -42,7 +42,6 @@
}
}(function (utils, load, warn) {
var assign = Object.assign || jQuery.extend;
- function classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function escapeHTML(str) {
return utils.decodeHTMLEntities(
@@ -62,7 +61,6 @@
*/
function Translator(language) {
var self = this;
- classCallCheck(self, Translator);
if (!language) {
throw new TypeError('Parameter `language` must be a language string. Received ' + language + (language === '' ? '(empty string)' : ''));