Add XSS filter
This commit is contained in:
parent
feca68538e
commit
551d5b2c36
|
@ -8,6 +8,7 @@ var AsyncQueue = require("./asyncqueue");
|
|||
var MakeEmitter = require("./emitter");
|
||||
var InfoGetter = require("./get-info");
|
||||
var ChatCommand = require("./chatcommand");
|
||||
var XSS = require("./xss");
|
||||
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
@ -572,16 +573,6 @@ Channel.prototype.part = function (user) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the MOTD and broadcast it to connected users
|
||||
*/
|
||||
Channel.prototype.setMOTD = function (message) {
|
||||
this.motd.motd = message;
|
||||
// TODO XSS filter
|
||||
this.motd.html = message.replace(/\n/g, "<br>");
|
||||
this.sendMOTD(this.users);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send the MOTD to the given users
|
||||
*/
|
||||
|
@ -2194,9 +2185,9 @@ Channel.prototype.validateChatFilter = function (f) {
|
|||
}
|
||||
|
||||
f.replace = f.replace.substring(0, 1000);
|
||||
f.replace = XSS.sanitizeHTML(f.replace);
|
||||
f.flags = f.flags.substring(0, 4);
|
||||
|
||||
// TODO XSS prevention
|
||||
try {
|
||||
new RegExp(f.source, f.flags);
|
||||
} catch (e) {
|
||||
|
@ -2493,7 +2484,7 @@ Channel.prototype.handleSetJS = function (user, data) {
|
|||
* Sets the MOTD
|
||||
*/
|
||||
Channel.prototype.setMotd = function (motd) {
|
||||
// TODO XSS
|
||||
motd = XSS.sanitizeHTML(motd);
|
||||
var html = motd.replace(/\n/g, "<br>");
|
||||
this.motd = {
|
||||
motd: motd,
|
||||
|
@ -2557,7 +2548,7 @@ Channel.prototype.handleChat = function (user, data) {
|
|||
}
|
||||
|
||||
if (smuted) {
|
||||
// TODO XSS
|
||||
msg = XSS.sanitizeText(msg);
|
||||
msg = this.filterMessage(msg);
|
||||
var msgobj = {
|
||||
username: user.name,
|
||||
|
@ -2629,7 +2620,7 @@ Channel.prototype.filterMessage = function (msg) {
|
|||
* Sends a chat message
|
||||
*/
|
||||
Channel.prototype.sendMessage = function (user, msg, meta) {
|
||||
// TODO HTML escape
|
||||
msg = XSS.sanitizeText(msg);
|
||||
msg = this.filterMessage(msg);
|
||||
var msgobj = {
|
||||
username: user.name,
|
||||
|
@ -2645,7 +2636,7 @@ Channel.prototype.sendMessage = function (user, msg, meta) {
|
|||
}
|
||||
|
||||
this.logger.log("<" + user.name + (meta.addClass ? "." + meta.addClass : "") + "> " +
|
||||
msg);
|
||||
XSS.decodeText(msg));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
40
lib/xss.js
40
lib/xss.js
|
@ -46,6 +46,16 @@ TagParser.prototype.readLiteral = function (regexp) {
|
|||
str += this.text[this.i];
|
||||
this.i++;
|
||||
}
|
||||
|
||||
str = str.replace(/&#([0-9]{2,7});?/g, function (m, p1) {
|
||||
return String.fromCharCode(parseInt(p1));
|
||||
});
|
||||
|
||||
str = str.replace(/&#x([0-9a-fA-F]{2,7});?/g, function (m, p1) {
|
||||
return String.fromCharCode(parseInt(p1, 16));
|
||||
});
|
||||
|
||||
str = str.replace(/[\x00-\x1f]/g, "");
|
||||
return str;
|
||||
};
|
||||
|
||||
|
@ -53,7 +63,7 @@ TagParser.prototype.readLiteral = function (regexp) {
|
|||
a string. Otherwise, read a literal
|
||||
*/
|
||||
TagParser.prototype.readLiteralOrString = function (regexp) {
|
||||
if (this.text[this.i].match(/["']/)) {
|
||||
if (this.text[this.i].match(/["'`]/)) {
|
||||
return this.readString();
|
||||
}
|
||||
return this.readLiteral(regexp);
|
||||
|
@ -78,6 +88,16 @@ TagParser.prototype.readString = function () {
|
|||
this.i++;
|
||||
}
|
||||
this.i++;
|
||||
|
||||
str = str.replace(/&#([0-9]{2,7});?/g, function (m, p1) {
|
||||
return String.fromCharCode(parseInt(p1));
|
||||
});
|
||||
|
||||
str = str.replace(/&#x([0-9a-fA-F]{2,7});?/g, function (m, p1) {
|
||||
return String.fromCharCode(parseInt(p1, 16));
|
||||
});
|
||||
|
||||
str = str.replace(/[\x00-\x1f]/g, "");
|
||||
return str;
|
||||
};
|
||||
|
||||
|
@ -120,7 +140,7 @@ TagParser.prototype.parse = function () {
|
|||
}
|
||||
|
||||
this.i++;
|
||||
this.skipWhitespace();
|
||||
//this.skipWhitespace();
|
||||
var value = this.readLiteralOrString();
|
||||
if (key.trim().length > 0) {
|
||||
attrs[key] = value;
|
||||
|
@ -181,7 +201,8 @@ const badTags = new RegExp([
|
|||
*/
|
||||
const badAttrs = new RegExp([
|
||||
"\\bon\\S*",
|
||||
"\\bformaction"
|
||||
"\\bformaction",
|
||||
"\\baction"
|
||||
].join("|"), "i");
|
||||
|
||||
/* These are things commonly used in the values of HTML attributes of
|
||||
|
@ -240,7 +261,14 @@ function sanitizeHTML(str) {
|
|||
if (k.trim().length > 0) {
|
||||
fmt += " " + k;
|
||||
if (t.attributes[k].trim().length > 0) {
|
||||
fmt += '="' + t.attributes[k] + '"';
|
||||
var delim = '"';
|
||||
if (t.attributes[k].match(/[^\\]"/)) {
|
||||
delim = "'";
|
||||
if (t.attributes[k].match(/[^\\]'/)) {
|
||||
delim = "`";
|
||||
}
|
||||
}
|
||||
fmt += "=" + delim + t.attributes[k] + delim;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,10 +292,10 @@ function sanitizeText(str) {
|
|||
}
|
||||
|
||||
function decodeText(str) {
|
||||
str = str.replace(/&#([0-9]{2,4});?/g, function (m, p1) {
|
||||
str = str.replace(/&#([0-9]{2,7});?/g, function (m, p1) {
|
||||
return String.fromCharCode(parseInt(p1));
|
||||
});
|
||||
str = str.replace(/&#x([0-9a-f]{2,4});?/ig, function (m, p1) {
|
||||
str = str.replace(/&#x([0-9a-f]{2,7});?/ig, function (m, p1) {
|
||||
return String.fromCharCode(parseInt(p1, 16));
|
||||
});
|
||||
str = str.replace(/</g, "<")
|
||||
|
|
Loading…
Reference in a new issue