Auto ban anonymous IP:
* New settings: "Ban anonymous user's IP when user is banned from a chatroom": * if enabled, every time a streamer bans an anonymous user, it will ban its IP on the chat server, * banned IPs are logged on disk, so server's admin can use them to feed fail2ban (for example), * option disabled by default, because could be used to create trapped-rooms on public servers
This commit is contained in:
parent
812eb89856
commit
d80cedfee5
@ -14,6 +14,10 @@
|
||||
* make it send pre-recorded messages every X minutes,
|
||||
* respond message to custom commands.
|
||||
* many other features will be available in future releases!
|
||||
* New settings: "Ban anonymous user's IP when user is banned from a chatroom":
|
||||
* if enabled, every time a streamer bans an anonymous user, it will ban its IP on the chat server,
|
||||
* banned IPs are logged on disk, so server's admin can use them to feed fail2ban (for example),
|
||||
* option disabled by default, because could be used to create trapped-rooms on public servers
|
||||
|
||||
### Minor changes and fixes
|
||||
|
||||
|
@ -240,6 +240,8 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
|
||||
return options.formValues['converse-theme'] !== 'peertube'
|
||||
case 'chat-per-live-video-warning':
|
||||
return !(options.formValues['chat-all-lives'] === true && options.formValues['chat-per-live-video'] === true)
|
||||
case 'auto-ban-anonymous-ip':
|
||||
return options.formValues['chat-no-anonymous'] !== false
|
||||
}
|
||||
|
||||
return false
|
||||
|
@ -122,6 +122,13 @@ no_anonymous_description: |
|
||||
If you enabled it, it is highly recommended to also check "Don't publish chat information".
|
||||
Otherwise, some third party tools could try to open the chat, and have unpredictable behaviours.
|
||||
|
||||
auto_ban_anonymous_ip_label: "Ban anonymous user's IP when user is banned from a chatroom"
|
||||
auto_ban_anonymous_ip_description: |
|
||||
By enabling this option, each time an anonymous user is banned from a chatroom, it's IP will also be banned from the chat server.
|
||||
Warning: if your instance is open to registration, any user could create a trapped-room, invite users to join, and automatically ban all anonymous user's IPs.
|
||||
The banned IP list is not stored, it will be cleared on server restart, or when you change some plugin's settings.
|
||||
The banned IP are logged in the Prosody server log files, so server's administrators can eventually use some external tools (like fail2ban) to ban IPs more widely.
|
||||
|
||||
theming_advanced_description: "<h3>Theming</h3>"
|
||||
|
||||
converse_theme_label: "ConverseJS theme"
|
||||
|
63
prosody-modules/mod_muc_ban_ip/README.markdown
Normal file
63
prosody-modules/mod_muc_ban_ip/README.markdown
Normal file
@ -0,0 +1,63 @@
|
||||
---
|
||||
labels:
|
||||
- 'Stage-Alpha'
|
||||
summary: Ban users from chatrooms by their IP address
|
||||
...
|
||||
|
||||
Note: this is a slightly modified version: the log level for IP bans is
|
||||
set to info, instead of debug.
|
||||
So we can use external tools (fail2ban for example) to block IPs more widely.
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
One frequent complaint about XMPP chatrooms (MUCs) compared to IRC is
|
||||
the inability for a room admin to ban a user based on their IP address.
|
||||
This is because an XMPP user is not identified on the network by their
|
||||
IP address, only their JID.
|
||||
|
||||
This means that it is possible to create a new account (usually quite
|
||||
easily), and rejoin the room that you were banned from.
|
||||
|
||||
This module allows the **user's** server to enforce bans by IP address,
|
||||
which is very desirable for server admins who want to prevent their
|
||||
server being used for spamming and abusive behaviour.
|
||||
|
||||
Details
|
||||
=======
|
||||
|
||||
An important point to note is that this module enforces the IP ban on
|
||||
the banned user's server, not on the MUC server. This means that:
|
||||
|
||||
- The user's server MUST have this module loaded, however -
|
||||
- The module works even when the MUC is on a different server to the
|
||||
user
|
||||
- The MUC server does not need this module (it only needs to support
|
||||
the [standard ban
|
||||
protocol](http://xmpp.org/extensions/xep-0045.html#ban))
|
||||
- The module works for effectively banning [anonymous
|
||||
users](http://prosody.im/doc/anonymous_logins)
|
||||
|
||||
Also note that IP bans are not saved permanently, and are reset upon a
|
||||
server restart.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
There is no extra configuration for this module except for loading it.
|
||||
Remember... do not load it on the MUC host, simply add it to your global
|
||||
`modules_enabled` list, or under a specific host like:
|
||||
|
||||
``` lua
|
||||
VirtualHost "anon.example.com"
|
||||
authentication = "anonymous"
|
||||
modules_enabled = { "muc_ban_ip" }
|
||||
```
|
||||
|
||||
Compatibility
|
||||
=============
|
||||
|
||||
----- --------------
|
||||
0.9 Works
|
||||
0.8 Doesn't work
|
||||
----- --------------
|
80
prosody-modules/mod_muc_ban_ip/mod_muc_ban_ip.lua
Normal file
80
prosody-modules/mod_muc_ban_ip/mod_muc_ban_ip.lua
Normal file
@ -0,0 +1,80 @@
|
||||
module:set_global();
|
||||
|
||||
local jid_bare, jid_host = require "util.jid".bare, require "util.jid".host;
|
||||
local st = require "util.stanza";
|
||||
local xmlns_muc_user = "http://jabber.org/protocol/muc#user";
|
||||
|
||||
local trusted_services = module:get_option_inherited_set("muc_ban_ip_trusted_services", {});
|
||||
local trust_local_restricted_services = module:get_option_boolean("muc_ban_ip_trust_local_restricted_services", true);
|
||||
|
||||
local ip_bans = module:shared("bans");
|
||||
local full_sessions = prosody.full_sessions;
|
||||
|
||||
local function is_local_restricted_service(host)
|
||||
local muc_service = prosody.hosts[host] and prosody.hosts[host].modules.muc;
|
||||
if muc_service and module:context(host):get_option("restrict_room_creation") ~= nil then -- COMPAT: May need updating post-0.12
|
||||
return true;
|
||||
end
|
||||
return false;
|
||||
end
|
||||
|
||||
local function ban_ip(session, from)
|
||||
local ip = session.ip;
|
||||
if not ip then
|
||||
module:log("warn", "Failed to ban IP (IP unknown) for %s", session.full_jid);
|
||||
return;
|
||||
end
|
||||
local from_host = jid_host(from);
|
||||
if trusted_services:contains(from_host) or (trust_local_restricted_services and is_local_restricted_service(from_host)) then
|
||||
from = from_host; -- Ban from entire host
|
||||
end
|
||||
local banned_from = ip_bans[ip];
|
||||
if not banned_from then
|
||||
banned_from = {};
|
||||
ip_bans[ip] = banned_from;
|
||||
end
|
||||
banned_from[from] = true;
|
||||
-- Specific to peertube-plugin-livechat: log level=info.
|
||||
module:log("info", "Added ban for IP address %s from %s", ip, from);
|
||||
end
|
||||
|
||||
local function check_for_incoming_ban(event)
|
||||
local stanza = event.stanza;
|
||||
local to_session = full_sessions[stanza.attr.to];
|
||||
if to_session then
|
||||
local directed = to_session.directed;
|
||||
local from = stanza.attr.from;
|
||||
if directed and directed[from] and stanza.attr.type == "unavailable" then
|
||||
-- This is a stanza from somewhere we sent directed presence to (may be a MUC)
|
||||
local x = stanza:get_child("x", xmlns_muc_user);
|
||||
if x then
|
||||
for status in x:childtags("status") do
|
||||
if status.attr.code == '301' then
|
||||
ban_ip(to_session, jid_bare(from));
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function check_for_ban(event)
|
||||
local origin, stanza = event.origin, event.stanza;
|
||||
local ip = origin.ip;
|
||||
local to, to_host = jid_bare(stanza.attr.to), jid_host(stanza.attr.to);
|
||||
if ip_bans[ip] and (ip_bans[ip][to] or ip_bans[ip][to_host]) then
|
||||
(origin.log or module._log)("debug", "IP banned: %s is banned from %s", ip, to)
|
||||
if stanza.attr.type ~= "error" then
|
||||
origin.send(st.error_reply(stanza, "auth", "forbidden")
|
||||
:tag("x", { xmlns = xmlns_muc_user })
|
||||
:tag("status", { code = '301' }));
|
||||
end
|
||||
return true;
|
||||
end
|
||||
(origin.log or module._log)("debug", "IP not banned: %s from %s", ip, to)
|
||||
end
|
||||
|
||||
function module.add_host(module)
|
||||
module:hook("presence/full", check_for_incoming_ban, 100);
|
||||
module:hook("pre-presence/full", check_for_ban, 100);
|
||||
end
|
@ -152,6 +152,7 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
||||
'prosody-components-interfaces',
|
||||
'prosody-components-list',
|
||||
'chat-no-anonymous',
|
||||
'auto-ban-anonymous-ip',
|
||||
'federation-dont-publish-remotely',
|
||||
'disable-channel-configuration'
|
||||
])
|
||||
@ -163,6 +164,7 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
||||
}
|
||||
const logByDefault = (settings['prosody-muc-log-by-default'] as boolean) ?? true
|
||||
const disableAnon = (settings['chat-no-anonymous'] as boolean) || false
|
||||
const autoBanIP = (settings['auto-ban-anonymous-ip'] as boolean) || false
|
||||
const logExpirationSetting = (settings['prosody-muc-expiration'] as string) ?? DEFAULTLOGEXPIRATION
|
||||
const enableC2S = (settings['prosody-c2s'] as boolean) || false
|
||||
// enableRoomS2S: room can be joined from remote XMPP servers (Peertube or not)
|
||||
@ -224,7 +226,7 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
||||
|
||||
const config = new ProsodyConfigContent(paths, prosodyDomain)
|
||||
if (!disableAnon) {
|
||||
config.useAnonymous()
|
||||
config.useAnonymous(autoBanIP)
|
||||
}
|
||||
config.useHttpAuthentication(authApiUrl)
|
||||
const useWS = !!options.registerWebSocketRoute // this comes with Peertube >=5.0.0, and is a prerequisite to websocket
|
||||
|
@ -207,10 +207,13 @@ class ProsodyConfigContent {
|
||||
this.muc.set('muc_room_default_history_length', 20)
|
||||
}
|
||||
|
||||
useAnonymous (): void {
|
||||
useAnonymous (autoBanIP: boolean): void {
|
||||
this.anon = new ProsodyConfigVirtualHost('anon.' + this.prosodyDomain)
|
||||
this.anon.set('authentication', 'anonymous')
|
||||
this.anon.set('modules_enabled', ['ping'])
|
||||
if (autoBanIP) {
|
||||
this.anon.add('modules_enabled', 'muc_ban_ip')
|
||||
}
|
||||
}
|
||||
|
||||
useHttpAuthentication (url: string): void {
|
||||
|
@ -83,7 +83,7 @@ Please read
|
||||
private: true
|
||||
})
|
||||
|
||||
// ********** Moderation and advances customization
|
||||
// ********** Advanced channel customization
|
||||
registerSetting({
|
||||
type: 'html',
|
||||
private: true,
|
||||
@ -197,6 +197,14 @@ Please read
|
||||
descriptionHTML: loc('no_anonymous_description'),
|
||||
private: false
|
||||
})
|
||||
registerSetting({
|
||||
name: 'auto-ban-anonymous-ip',
|
||||
label: loc('auto_ban_anonymous_ip_label'),
|
||||
type: 'input-checkbox',
|
||||
default: false,
|
||||
descriptionHTML: loc('auto_ban_anonymous_ip_description'),
|
||||
private: true
|
||||
})
|
||||
|
||||
// ********** Theming
|
||||
registerSetting({
|
||||
|
@ -82,6 +82,10 @@ Note: for now this feature simply hide the chat.
|
||||
In a future release, the chat will be replaced by a message saying «please log in to [...]».
|
||||
See [v5.7.0 Release Notes](https://github.com/JohnXLivingston/peertube-plugin-livechat/blob/main/CHANGELOG.md#570) for more information.
|
||||
|
||||
### {{% livechat_label auto_ban_anonymous_ip_label %}}
|
||||
|
||||
{{% livechat_label auto_ban_anonymous_ip_description %}}
|
||||
|
||||
## Theming
|
||||
|
||||
### {{% livechat_label converse_theme_label %}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user