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,
|
* make it send pre-recorded messages every X minutes,
|
||||||
* respond message to custom commands.
|
* respond message to custom commands.
|
||||||
* many other features will be available in future releases!
|
* 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
|
### Minor changes and fixes
|
||||||
|
|
||||||
|
@ -240,6 +240,8 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
|
|||||||
return options.formValues['converse-theme'] !== 'peertube'
|
return options.formValues['converse-theme'] !== 'peertube'
|
||||||
case 'chat-per-live-video-warning':
|
case 'chat-per-live-video-warning':
|
||||||
return !(options.formValues['chat-all-lives'] === true && options.formValues['chat-per-live-video'] === true)
|
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
|
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".
|
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.
|
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>"
|
theming_advanced_description: "<h3>Theming</h3>"
|
||||||
|
|
||||||
converse_theme_label: "ConverseJS theme"
|
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-interfaces',
|
||||||
'prosody-components-list',
|
'prosody-components-list',
|
||||||
'chat-no-anonymous',
|
'chat-no-anonymous',
|
||||||
|
'auto-ban-anonymous-ip',
|
||||||
'federation-dont-publish-remotely',
|
'federation-dont-publish-remotely',
|
||||||
'disable-channel-configuration'
|
'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 logByDefault = (settings['prosody-muc-log-by-default'] as boolean) ?? true
|
||||||
const disableAnon = (settings['chat-no-anonymous'] as boolean) || false
|
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 logExpirationSetting = (settings['prosody-muc-expiration'] as string) ?? DEFAULTLOGEXPIRATION
|
||||||
const enableC2S = (settings['prosody-c2s'] as boolean) || false
|
const enableC2S = (settings['prosody-c2s'] as boolean) || false
|
||||||
// enableRoomS2S: room can be joined from remote XMPP servers (Peertube or not)
|
// 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)
|
const config = new ProsodyConfigContent(paths, prosodyDomain)
|
||||||
if (!disableAnon) {
|
if (!disableAnon) {
|
||||||
config.useAnonymous()
|
config.useAnonymous(autoBanIP)
|
||||||
}
|
}
|
||||||
config.useHttpAuthentication(authApiUrl)
|
config.useHttpAuthentication(authApiUrl)
|
||||||
const useWS = !!options.registerWebSocketRoute // this comes with Peertube >=5.0.0, and is a prerequisite to websocket
|
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)
|
this.muc.set('muc_room_default_history_length', 20)
|
||||||
}
|
}
|
||||||
|
|
||||||
useAnonymous (): void {
|
useAnonymous (autoBanIP: boolean): void {
|
||||||
this.anon = new ProsodyConfigVirtualHost('anon.' + this.prosodyDomain)
|
this.anon = new ProsodyConfigVirtualHost('anon.' + this.prosodyDomain)
|
||||||
this.anon.set('authentication', 'anonymous')
|
this.anon.set('authentication', 'anonymous')
|
||||||
this.anon.set('modules_enabled', ['ping'])
|
this.anon.set('modules_enabled', ['ping'])
|
||||||
|
if (autoBanIP) {
|
||||||
|
this.anon.add('modules_enabled', 'muc_ban_ip')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useHttpAuthentication (url: string): void {
|
useHttpAuthentication (url: string): void {
|
||||||
|
@ -83,7 +83,7 @@ Please read
|
|||||||
private: true
|
private: true
|
||||||
})
|
})
|
||||||
|
|
||||||
// ********** Moderation and advances customization
|
// ********** Advanced channel customization
|
||||||
registerSetting({
|
registerSetting({
|
||||||
type: 'html',
|
type: 'html',
|
||||||
private: true,
|
private: true,
|
||||||
@ -197,6 +197,14 @@ Please read
|
|||||||
descriptionHTML: loc('no_anonymous_description'),
|
descriptionHTML: loc('no_anonymous_description'),
|
||||||
private: false
|
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
|
// ********** Theming
|
||||||
registerSetting({
|
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 [...]».
|
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.
|
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
|
## Theming
|
||||||
|
|
||||||
### {{% livechat_label converse_theme_label %}}
|
### {{% livechat_label converse_theme_label %}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user