diff --git a/src/channel/chat.js b/src/channel/chat.js index da2117b7..83d252a7 100644 --- a/src/channel/chat.js +++ b/src/channel/chat.js @@ -121,6 +121,28 @@ ChatModule.prototype.shadowMutedUsers = function () { }); }; +ChatModule.prototype.restrictNewAccount = function restrictNewAccount(user, data) { + if (user.account.effectiveRank < 2 && this.channel.modules.options) { + const firstSeen = user.getFirstSeenTime(); + const opts = this.channel.modules.options; + // TODO: configurable times + if (firstSeen > Date.now() - opts.get("new_user_chat_delay")) { + user.socket.emit("spamFiltered", { + reason: "NEW_USER_CHAT" + }); + return true; + } else if ((firstSeen > Date.now() - opts.get("new_user_chat_link_delay")) + && data.msg.match(LINK)) { + user.socket.emit("spamFiltered", { + reason: "NEW_USER_CHAT_LINK" + }); + return true; + } + } + + return false; +}; + ChatModule.prototype.handleChatMsg = function (user, data) { var self = this; counters.add("chat:incoming"); @@ -132,17 +154,8 @@ ChatModule.prototype.handleChatMsg = function (user, data) { // Limit to 240 characters data.msg = data.msg.substring(0, 240); - const firstSeen = user.getFirstSeenTime(); - // TODO: configurable times - if (firstSeen > Date.now() - 5 * 60 * 1000) { - user.socket.emit("spamFiltered", { - reason: "NEW_USER_CHAT" - }); - return; - } else if ((firstSeen > Date.now() - 24 * 60 * 60 * 1000) && data.msg.match(LINK)) { - user.socket.emit("spamFiltered", { - reason: "NEW_USER_CHAT_LINK" - }); + // Restrict new accounts/IPs from chatting and posting links + if (this.restrictNewAccount(user, data)) { return; } @@ -188,6 +201,11 @@ ChatModule.prototype.handlePm = function (user, data) { msg: "You must be signed in to send PMs" }); } + + // Restrict new accounts/IPs from chatting and posting links + if (this.restrictNewAccount(user, data)) { + return; + } if (data.msg.match(Config.get("link-domain-blacklist-regex"))) { this.channel.logger.log(user.displayip + " (" + user.getName() + ") was kicked for " + diff --git a/src/channel/opts.js b/src/channel/opts.js index 45455324..14b37728 100644 --- a/src/channel/opts.js +++ b/src/channel/opts.js @@ -25,7 +25,9 @@ function OptionsModule(channel) { allow_dupes: false, // Allow duplicate videos on the playlist torbanned: false, // Block connections from Tor exit nodes allow_ascii_control: false,// Allow ASCII control characters (\x00-\x1f) - playlist_max_per_user: 0 // Maximum number of playlist items per user + playlist_max_per_user: 0, // Maximum number of playlist items per user + new_user_chat_delay: 10 * 60 * 1000, // Minimum account/IP age to chat + new_user_chat_link_delay: 60 * 60 * 1000 // Minimum account/IP age to post links }; } @@ -271,6 +273,20 @@ OptionsModule.prototype.handleSetOptions = function (user, data) { } } + if ("new_user_chat_delay" in data) { + var delay = parseInt(data.new_user_chat_delay); + if (!isNaN(delay) && delay >= 0) { + this.opts.new_user_chat_delay = delay; + } + } + + if ("new_user_chat_link_delay" in data) { + var delay = parseInt(data.new_user_chat_link_delay); + if (!isNaN(delay) && delay >= 0) { + this.opts.new_user_chat_link_delay = delay; + } + } + this.channel.logger.log("[mod] " + user.getName() + " updated channel options"); this.sendOpts(this.channel.users); }; diff --git a/templates/channeloptions.pug b/templates/channeloptions.pug index dfff94e1..6b7e69d8 100644 --- a/templates/channeloptions.pug +++ b/templates/channeloptions.pug @@ -46,6 +46,15 @@ mixin textbox-auto(id, label, placeholder) else input.form-control.cs-textbox(id=id, type="text") +mixin textbox-timeinput-auto(id, label, placeholder) + .form-group + label.control-label.col-sm-4(for=id)= label + .col-sm-8 + if placeholder + input.form-control.cs-textbox-timeinput(id=id, type="text", placeholder=placeholder) + else + input.form-control.cs-textbox-timeinput(id=id, type="text") + mixin miscoptions #cs-miscoptions.tab-pane.active h4 General Settings @@ -63,6 +72,11 @@ mixin miscoptions +rcheckbox-auto("cs-chat_antiflood", "Throttle chat") +textbox-auto("cs-chat_antiflood_burst", "# of messages allowed before throttling") +textbox-auto("cs-chat_antiflood_sustained", "# of messages (after burst) allowed per second") + +textbox-timeinput-auto("cs-new_user_chat_delay", "Delay before new accounts can chat", "0") + .form-group + .col-sm-8.col-sm-offset-4 + span.text-info Restrictions to new accounts can be disabled by setting the delay to 0. + +textbox-timeinput-auto("cs-new_user_chat_link_delay", "Delay before new accounts can post links in chat", "0") .form-group .col-sm-8.col-sm-offset-4 span.text-info Changes are automatically saved. diff --git a/www/js/util.js b/www/js/util.js index 98651b47..fb721348 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -930,6 +930,8 @@ function handleModPermissions() { $("#cs-torbanned").prop("checked", CHANNEL.opts.torbanned); $("#cs-allow_ascii_control").prop("checked", CHANNEL.opts.allow_ascii_control); $("#cs-playlist_max_per_user").val(CHANNEL.opts.playlist_max_per_user || 0); + $("#cs-new_user_chat_delay").val(CHANNEL.opts.new_user_chat_delay || 0); + $("#cs-new_user_chat_link_delay").val(CHANNEL.opts.new_user_chat_link_delay || 0); (function() { if(typeof CHANNEL.opts.maxlength != "number") { $("#cs-maxlength").val(""); @@ -1450,7 +1452,7 @@ function stripImages(msg){ return msg; } return msg.replace(IMAGE_MATCH, function(match,img){ - return CHANNEL.opts.enable_link_regex ? + return CHANNEL.opts.enable_link_regex ? ''+img+'' : img; }); }