mirror of
https://github.com/evennia/evennia.git
synced 2026-04-04 15:07:16 +02:00
Added the @ban and @unban commands to the default command sets, allowing an admin to filter access from users without outright deleting their accounts. The ban list is stored in the database, but the checking is not hard-coded in the server/portal, but done in the normal login command(s), meaning it can be customized easily. Also contrib/menu_login has been updated to check for banned connections.
This commit is contained in:
parent
e2b67b0ac4
commit
1d40f688e5
6 changed files with 196 additions and 6 deletions
|
|
@ -31,14 +31,11 @@ the initial splash screen.
|
|||
import re
|
||||
import traceback
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from src.server import sessionhandler
|
||||
from src.players.models import PlayerDB
|
||||
from src.objects.models import ObjectDB
|
||||
from src.server.models import ServerConfig
|
||||
from src.comms.models import Channel
|
||||
|
||||
from src.utils import create, logger, utils, ansi
|
||||
from src.utils import create, logger, utils
|
||||
from src.commands.command import Command
|
||||
from src.commands.cmdset import CmdSet
|
||||
from src.commands.cmdhandler import CMD_LOGINSTART
|
||||
|
|
@ -116,6 +113,18 @@ class CmdPasswordSelect(Command):
|
|||
self.menutree.goto("node1b")
|
||||
return
|
||||
|
||||
# before going on, check eventual bans
|
||||
bans = ServerConfig.objects.conf("server_bans")
|
||||
if bans and (any(tup[0]==player.name for tup in bans)
|
||||
or
|
||||
any(tup[2].match(player.sessions[0].address[0]) for tup in bans if tup[2])):
|
||||
# this is a banned IP or name!
|
||||
string = "{rYou have been banned and cannot continue from here."
|
||||
string += "\nIf you feel this ban is in error, please email an admin.{x"
|
||||
self.caller.msg(string)
|
||||
self.caller.session_disconnect()
|
||||
return
|
||||
|
||||
# we are ok, log us in.
|
||||
self.caller.msg("{gWelcome %s! Logging in ...{n" % player.key)
|
||||
self.caller.session_login(player)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@ Admin commands
|
|||
|
||||
"""
|
||||
|
||||
import time, re
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from src.players.models import PlayerDB
|
||||
from src.server.sessionhandler import SESSIONS
|
||||
from src.server.models import ServerConfig
|
||||
from src.utils import utils
|
||||
from src.commands.default.muxcommand import MuxCommand
|
||||
|
||||
|
|
@ -93,6 +95,170 @@ class CmdBoot(MuxCommand):
|
|||
caller.msg("You booted %s." % name)
|
||||
|
||||
|
||||
# regex matching IP addresses with wildcards, eg. 233.122.4.*
|
||||
IPREGEX = re.compile(r"[0-9*]{1,3}\.[0-9*]{1,3}\.[0-9*]{1,3}\.[0-9*]{1,3}")
|
||||
|
||||
def list_bans(banlist):
|
||||
"""
|
||||
Helper function to display a list of active bans. Input argument
|
||||
is the banlist read into the two commands @ban and @undban below.
|
||||
"""
|
||||
if not banlist:
|
||||
return "No active bans were found."
|
||||
|
||||
table = [["id"], ["name/ip"], ["date"], ["reason"]]
|
||||
table[0].extend([str(i+1) for i in range(len(banlist))])
|
||||
for ban in banlist:
|
||||
if ban[0]:
|
||||
table[1].append(ban[0])
|
||||
else:
|
||||
table[1].append(ban[1])
|
||||
table[2].extend([ban[3] for ban in banlist])
|
||||
table[3].extend([ban[4] for ban in banlist])
|
||||
ftable = utils.format_table(table, 4)
|
||||
string = "{wActive bans:{x"
|
||||
for irow, row in enumerate(ftable):
|
||||
if irow == 0:
|
||||
srow = "\n" + "".join(row)
|
||||
srow = "{w%s{n" % srow.rstrip()
|
||||
else:
|
||||
srow = "\n" + "{w%s{n" % row[0] + "".join(row[1:])
|
||||
string += srow.rstrip()
|
||||
return string
|
||||
|
||||
class CmdBan(MuxCommand):
|
||||
"""
|
||||
ban a player from the server
|
||||
|
||||
Usage:
|
||||
@ban [<name or ip> [: reason]]
|
||||
|
||||
Without any arguments, shows numbered list of active bans.
|
||||
|
||||
This command bans a user from accessing the game. Supply an
|
||||
optional reason to be able to later remember why the ban was put in
|
||||
place
|
||||
|
||||
It is often to
|
||||
prefer over deleting a player with @delplayer. If banned by name,
|
||||
that player account can no longer be logged into.
|
||||
|
||||
IP (Internet Protocol) address banning allows to block all access
|
||||
from a specific address or subnet. Use the asterisk (*) as a
|
||||
wildcard.
|
||||
|
||||
Examples:
|
||||
@ban thomas - ban account 'thomas'
|
||||
@ban/ip 134.233.2.111 - ban specific ip address
|
||||
@ban/ip 134.233.2.* - ban all in the 134.233.2 subnet
|
||||
@ban/ip 134.233.*.* - ban all in the 134.233 subnet
|
||||
|
||||
A single IP filter is easy to circumvent by changing the computer
|
||||
(also, some ISPs assign only temporary IPs to their users in the
|
||||
first placer. Widening the IP block filter with wildcards might be
|
||||
tempting, but remember that blocking too much may accidentally
|
||||
also block innocent users connecting from the same country and
|
||||
region.
|
||||
|
||||
"""
|
||||
key = "@ban"
|
||||
aliases = ["@bans"]
|
||||
locks = "cmd:perm(ban) or perm(Immortals)"
|
||||
help_category="Admin"
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
Bans are stored in a serverconf db object as a list of
|
||||
dictionaries:
|
||||
[ (name, ip, ipregex, date, reason),
|
||||
(name, ip, ipregex, date, reason),... ]
|
||||
where name and ip are set by the user and are shown in
|
||||
lists. ipregex is a converted form of ip where the * is
|
||||
replaced by an appropriate regex pattern for fast
|
||||
matching. date is the time stamp the ban was instigated and
|
||||
'reason' is any optional info given to the command. Unset
|
||||
values in each tuple is set to the empty string.
|
||||
"""
|
||||
banlist = ServerConfig.objects.conf('server_bans')
|
||||
if not banlist:
|
||||
banlist = []
|
||||
|
||||
if not self.args or (self.switches
|
||||
and not any(switch in ('ip', 'name') for switch in self.switches)):
|
||||
self.caller.msg(list_bans(banlist))
|
||||
return
|
||||
|
||||
now = time.ctime()
|
||||
reason = ""
|
||||
if ':' in self.args:
|
||||
ban, reason = self.args.rsplit(':',1)
|
||||
else:
|
||||
ban = self.args
|
||||
ban = ban.lower()
|
||||
ipban = IPREGEX.findall(ban)
|
||||
if not ipban:
|
||||
# store as name
|
||||
typ = "Name"
|
||||
bantup = (ban, "", "", now, reason)
|
||||
else:
|
||||
# an ip address.
|
||||
typ = "IP"
|
||||
ban = ipban[0]
|
||||
# replace * with regex form and compile it
|
||||
ipregex = ban.replace('.','\.')
|
||||
ipregex = ipregex.replace('*', '[0-9]{1,3}')
|
||||
print "regex:",ipregex
|
||||
ipregex = re.compile(r"%s" % ipregex)
|
||||
bantup = ("", ban, ipregex, now, reason)
|
||||
# save updated banlist
|
||||
banlist.append(bantup)
|
||||
ServerConfig.objects.conf('server_bans', banlist)
|
||||
self.caller.msg("%s-Ban {w%s{x was added." % (typ, ban))
|
||||
|
||||
class CmdUnban(MuxCommand):
|
||||
"""
|
||||
remove a ban
|
||||
|
||||
Usage:
|
||||
@unban <banid>
|
||||
|
||||
This will clear a player name/ip ban previously set with the @ban
|
||||
command. Use this command without an argument to view a numbered
|
||||
list of bans. Use the numbers in this list to select which one to
|
||||
unban.
|
||||
|
||||
"""
|
||||
key = "@unban"
|
||||
locks = "cmd:perm(unban) or perm(Immortals)"
|
||||
help_category="Admin"
|
||||
|
||||
def func(self):
|
||||
"Implement unbanning"
|
||||
|
||||
banlist = ServerConfig.objects.conf('server_bans')
|
||||
|
||||
if not self.args:
|
||||
self.caller.msg(list_bans(banlist))
|
||||
return
|
||||
|
||||
try:
|
||||
num = int(self.args)
|
||||
except Exception:
|
||||
self.caller.msg("You must supply a valid ban id to clear.")
|
||||
return
|
||||
|
||||
if not banlist:
|
||||
self.caller.msg("There are no bans to clear.")
|
||||
elif not (0 < num < len(banlist) + 1):
|
||||
self.caller.msg("Ban id {w%s{x was not found." % self.args)
|
||||
else:
|
||||
# all is ok, clear ban
|
||||
ban = banlist[num-1]
|
||||
del banlist[num-1]
|
||||
ServerConfig.objects.conf('server_bans', banlist)
|
||||
self.caller.msg("Cleared ban %s: %s" % (num, " ".join([s for s in ban[:2]])))
|
||||
|
||||
|
||||
class CmdDelPlayer(MuxCommand):
|
||||
"""
|
||||
delplayer - delete player from server
|
||||
|
|
@ -102,7 +268,7 @@ class CmdDelPlayer(MuxCommand):
|
|||
|
||||
Switch:
|
||||
delobj - also delete the player's currently
|
||||
assigned in-game object.
|
||||
assigned in-game object.
|
||||
|
||||
Completely deletes a user from the server database,
|
||||
making their nick and e-mail again available.
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ class DefaultCmdSet(CmdSet):
|
|||
|
||||
# Admin commands
|
||||
self.add(admin.CmdBoot())
|
||||
self.add(admin.CmdBan())
|
||||
self.add(admin.CmdUnban())
|
||||
self.add(admin.CmdDelPlayer())
|
||||
self.add(admin.CmdEmit())
|
||||
self.add(admin.CmdNewPassword())
|
||||
|
|
|
|||
|
|
@ -62,6 +62,18 @@ class CmdConnect(MuxCommand):
|
|||
session.msg("Incorrect password.")
|
||||
return
|
||||
|
||||
# Check IP and/or name bans
|
||||
bans = ServerConfig.objects.conf("server_bans")
|
||||
if bans and (any(tup[0]==player.name for tup in bans)
|
||||
or
|
||||
any(tup[2].match(session.address[0]) for tup in bans if tup[2])):
|
||||
# this is a banned IP or name!
|
||||
string = "{rYou have been banned and cannot continue from here."
|
||||
string += "\nIf you feel this ban is in error, please email an admin.{x"
|
||||
session.msg(string)
|
||||
session.execute_cmd("quit")
|
||||
return
|
||||
|
||||
# actually do the login. This will call all hooks.
|
||||
session.session_login(player)
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ class Session(object):
|
|||
self.protocol_key = protocol_key
|
||||
# Protocol address tied to this session
|
||||
self.address = address
|
||||
|
||||
# suid is used by some protocols, it's a hex key.
|
||||
self.suid = None
|
||||
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ def time_format(seconds, style=0):
|
|||
def datetime_format(dtobj):
|
||||
"""
|
||||
Takes a datetime object instance (e.g. from django's DateTimeField)
|
||||
and returns a string.
|
||||
and returns a string describing how long ago that date was.
|
||||
"""
|
||||
|
||||
year, month, day = dtobj.year, dtobj.month, dtobj.day
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue