Improve filter handling code
This commit is contained in:
parent
aa5e50f1d2
commit
25eba6ab2b
|
@ -1,26 +1,34 @@
|
||||||
var FilterList = require('cytubefilters');
|
var FilterList = require("cytubefilters");
|
||||||
var ChannelModule = require("./module");
|
var ChannelModule = require("./module");
|
||||||
var XSS = require("../xss");
|
var XSS = require("../xss");
|
||||||
var Logger = require("../logger");
|
var Logger = require("../logger");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Converts JavaScript-style replacements ($1, $2, etc.) with
|
||||||
|
* PCRE-style (\1, \2, etc.)
|
||||||
|
*/
|
||||||
|
function fixReplace(replace) {
|
||||||
|
return replace.replace(/\$(\d)/g, "\\$1");
|
||||||
|
}
|
||||||
|
|
||||||
function validateFilter(f) {
|
function validateFilter(f) {
|
||||||
if (typeof f.source !== "string" || typeof f.flags !== "string" ||
|
if (typeof f.source !== "string" || typeof f.flags !== "string" ||
|
||||||
typeof f.replace !== "string") {
|
typeof f.replace !== "string") {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof f.name !== "string") {
|
if (typeof f.name !== "string") {
|
||||||
f.name = f.source;
|
f.name = f.source;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.replace = f.replace.substring(0, 1000);
|
f.replace = fixReplace(f.replace.substring(0, 1000));
|
||||||
f.replace = XSS.sanitizeHTML(f.replace);
|
f.replace = XSS.sanitizeHTML(f.replace);
|
||||||
f.flags = f.flags.substring(0, 4);
|
f.flags = f.flags.substring(0, 4);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new RegExp(f.source, f.flags);
|
FilterList.checkValidRegex(f.source);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var filter = {
|
var filter = {
|
||||||
|
@ -35,58 +43,47 @@ function validateFilter(f) {
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fixReplace(replace) {
|
|
||||||
return replace.replace(/\$(\d)/g, '\\$1');
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeDefaultFilter(name, source, flags, replace) {
|
function makeDefaultFilter(name, source, flags, replace) {
|
||||||
return {
|
return {
|
||||||
name: name,
|
name: name,
|
||||||
source: source,
|
source: source,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
replace: fixReplace(replace),
|
replace: replace,
|
||||||
active: true,
|
active: true,
|
||||||
filterlinks: false
|
filterlinks: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_FILTERS = [
|
const DEFAULT_FILTERS = [
|
||||||
makeDefaultFilter("monospace", "`(.+?)`", "g", "<code>$1</code>"),
|
makeDefaultFilter("monospace", "`(.+?)`", "g", "<code>\\1</code>"),
|
||||||
makeDefaultFilter("bold", "\\*(.+?)\\*", "g", "<strong>$1</strong>"),
|
makeDefaultFilter("bold", "\\*(.+?)\\*", "g", "<strong>\\1</strong>"),
|
||||||
makeDefaultFilter("italic", "_(.+?)_", "g", "<em>$1</em>"),
|
makeDefaultFilter("italic", "_(.+?)_", "g", "<em>\\1</em>"),
|
||||||
makeDefaultFilter("strike", "~~(.+?)~~", "g", "<s>$1</s>"),
|
makeDefaultFilter("strike", "~~(.+?)~~", "g", "<s>\\1</s>"),
|
||||||
makeDefaultFilter("inline spoiler", "\\[sp\\](.*?)\\[\\/sp\\]", "ig", "<span class=\"spoiler\">$1</span>")
|
makeDefaultFilter("inline spoiler", "\\[sp\\](.*?)\\[\\/sp\\]", "ig",
|
||||||
|
"<span class=\"spoiler\">\\1</span>")
|
||||||
];
|
];
|
||||||
|
|
||||||
function ChatFilterModule(channel) {
|
function ChatFilterModule(channel) {
|
||||||
ChannelModule.apply(this, arguments);
|
ChannelModule.apply(this, arguments);
|
||||||
this.filters = new FilterList(DEFAULT_FILTERS);
|
this.filters = new FilterList();
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatFilterModule.prototype = Object.create(ChannelModule.prototype);
|
ChatFilterModule.prototype = Object.create(ChannelModule.prototype);
|
||||||
|
|
||||||
ChatFilterModule.prototype.load = function (data) {
|
ChatFilterModule.prototype.load = function (data) {
|
||||||
if ("filters" in data) {
|
if ("filters" in data) {
|
||||||
for (var i = 0; i < data.filters.length; i++) {
|
var filters = data.filters.map(validateFilter).filter(function (f) {
|
||||||
var f = validateFilter(data.filters[i]);
|
return f !== null;
|
||||||
if (f) {
|
});
|
||||||
try {
|
try {
|
||||||
this.filters.updateFilter(f);
|
this.filters = new FilterList(filters);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message.match(/does not exist/i)) {
|
Logger.errlog.log("Filter load failed: " + e + " (channel:" +
|
||||||
try {
|
this.channel.name);
|
||||||
this.filters.addFilter(f);
|
this.channel.logger.log("Failed to load filters: " + e);
|
||||||
} catch (e) {
|
|
||||||
Logger.errlog.log("Filter load failed: " +
|
|
||||||
JSON.stringify(f) + " c:" + this.channel.name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Logger.errlog.log("Filter load failed: " +
|
|
||||||
JSON.stringify(f) + " c:" + this.channel.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.filters = new FilterList(DEFAULT_FILTERS);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -128,6 +125,16 @@ ChatFilterModule.prototype.handleAddFilter = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
FilterList.checkValidRegex(data.source);
|
||||||
|
} catch (e) {
|
||||||
|
user.socket.emit("errorMsg", {
|
||||||
|
msg: "Invalid regex: " + e.message,
|
||||||
|
alert: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
data = validateFilter(data);
|
data = validateFilter(data);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
|
@ -142,6 +149,9 @@ ChatFilterModule.prototype.handleAddFilter = function (user, data) {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user.socket.emit("addFilterSuccess");
|
||||||
|
|
||||||
var chan = this.channel;
|
var chan = this.channel;
|
||||||
chan.users.forEach(function (u) {
|
chan.users.forEach(function (u) {
|
||||||
if (chan.modules.permissions.canEditFilters(u)) {
|
if (chan.modules.permissions.canEditFilters(u)) {
|
||||||
|
@ -150,8 +160,8 @@ ChatFilterModule.prototype.handleAddFilter = function (user, data) {
|
||||||
});
|
});
|
||||||
|
|
||||||
chan.logger.log("[mod] " + user.getName() + " added filter: " + data.name + " -> " +
|
chan.logger.log("[mod] " + user.getName() + " added filter: " + data.name + " -> " +
|
||||||
"s/" + data.source + "/" + data.replace + "/" + data.flags + " active: " +
|
"s/" + data.source + "/" + data.replace + "/" + data.flags +
|
||||||
data.active + ", filterlinks: " + data.filterlinks);
|
" active: " + data.active + ", filterlinks: " + data.filterlinks);
|
||||||
};
|
};
|
||||||
|
|
||||||
ChatFilterModule.prototype.handleUpdateFilter = function (user, data) {
|
ChatFilterModule.prototype.handleUpdateFilter = function (user, data) {
|
||||||
|
@ -163,6 +173,16 @@ ChatFilterModule.prototype.handleUpdateFilter = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
FilterList.checkValidRegex(data.source);
|
||||||
|
} catch (e) {
|
||||||
|
user.socket.emit("errorMsg", {
|
||||||
|
msg: "Invalid regex: " + e.message,
|
||||||
|
alert: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
data = validateFilter(data);
|
data = validateFilter(data);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
|
@ -171,14 +191,10 @@ ChatFilterModule.prototype.handleUpdateFilter = function (user, data) {
|
||||||
try {
|
try {
|
||||||
this.filters.updateFilter(data);
|
this.filters.updateFilter(data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message.match(/filter to be updated does not exist/i)) {
|
user.socket.emit("errorMsg", {
|
||||||
this.handleAddFilter(user, data);
|
msg: "Filter update failed: " + e.message,
|
||||||
} else {
|
alert: true
|
||||||
user.socket.emit("errorMsg", {
|
});
|
||||||
msg: "Filter update failed: " + e.message,
|
|
||||||
alert: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,8 +206,8 @@ ChatFilterModule.prototype.handleUpdateFilter = function (user, data) {
|
||||||
});
|
});
|
||||||
|
|
||||||
chan.logger.log("[mod] " + user.getName() + " updated filter: " + data.name + " -> " +
|
chan.logger.log("[mod] " + user.getName() + " updated filter: " + data.name + " -> " +
|
||||||
"s/" + data.source + "/" + data.replace + "/" + data.flags + " active: " +
|
"s/" + data.source + "/" + data.replace + "/" + data.flags +
|
||||||
data.active + ", filterlinks: " + data.filterlinks);
|
" active: " + data.active + ", filterlinks: " + data.filterlinks);
|
||||||
};
|
};
|
||||||
|
|
||||||
ChatFilterModule.prototype.handleImportFilters = function (user, data) {
|
ChatFilterModule.prototype.handleImportFilters = function (user, data) {
|
||||||
|
@ -207,7 +223,7 @@ ChatFilterModule.prototype.handleImportFilters = function (user, data) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.filters = new FilterList(data.map(validateFilter).filter(function (f) {
|
this.filters = new FilterList(data.map(validateFilter).filter(function (f) {
|
||||||
return f !== false;
|
return f !== null;
|
||||||
}));
|
}));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
user.socket.emit("errorMsg", {
|
user.socket.emit("errorMsg", {
|
||||||
|
@ -249,6 +265,7 @@ ChatFilterModule.prototype.handleRemoveFilter = function (user, data) {
|
||||||
u.socket.emit("deleteChatFilter", data);
|
u.socket.emit("deleteChatFilter", data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.channel.logger.log("[mod] " + user.getName() + " removed filter: " + data.name);
|
this.channel.logger.log("[mod] " + user.getName() + " removed filter: " + data.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
20
www/js/ui.js
20
www/js/ui.js
|
@ -621,14 +621,7 @@ $("#cs-chatfilters-newsubmit").click(function () {
|
||||||
"match.");
|
"match.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
socket.emit("addFilter", {
|
||||||
new RegExp(regex, flags);
|
|
||||||
} catch (e) {
|
|
||||||
alert("Regex error: " + e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.emit("updateFilter", {
|
|
||||||
name: name,
|
name: name,
|
||||||
source: regex,
|
source: regex,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
|
@ -636,10 +629,13 @@ $("#cs-chatfilters-newsubmit").click(function () {
|
||||||
active: true
|
active: true
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#cs-chatfilters-newname").val("");
|
socket.once("addFilterSuccess", function () {
|
||||||
$("#cs-chatfilters-newregex").val("");
|
console.log("addFilterSuccess");
|
||||||
$("#cs-chatfilters-newflags").val("");
|
$("#cs-chatfilters-newname").val("");
|
||||||
$("#cs-chatfilters-newreplace").val("");
|
$("#cs-chatfilters-newregex").val("");
|
||||||
|
$("#cs-chatfilters-newflags").val("");
|
||||||
|
$("#cs-chatfilters-newreplace").val("");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#cs-emotes-newsubmit").click(function () {
|
$("#cs-emotes-newsubmit").click(function () {
|
||||||
|
|
|
@ -2304,14 +2304,12 @@ function formatCSChatFilterList() {
|
||||||
f.flags = flags.val();
|
f.flags = flags.val();
|
||||||
f.replace = replace.val();
|
f.replace = replace.val();
|
||||||
f.filterlinks = filterlinks.prop("checked");
|
f.filterlinks = filterlinks.prop("checked");
|
||||||
try {
|
|
||||||
new RegExp(f.source, f.flags);
|
|
||||||
} catch (e) {
|
|
||||||
alert("Invalid regex: " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.emit("updateFilter", f);
|
socket.emit("updateFilter", f);
|
||||||
reset();
|
socket.once("updateFilterSuccess", function () {
|
||||||
|
console.log("updateFilterSuccess");
|
||||||
|
reset();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
control.data("editor", tr2);
|
control.data("editor", tr2);
|
||||||
|
|
Loading…
Reference in a new issue