Made some minor updates to the evmenu_login contrib, including adding a max number of password retries before disconnecting as well as fixing how client-exhoes are handled. Also made empty string return rather than 'b'. Also fixed an inconsistency in the Session.msg.

This commit is contained in:
Griatch 2016-04-24 15:10:27 +02:00
parent bf50f5b94a
commit 8bf63885e2
5 changed files with 125 additions and 172 deletions

View file

@ -68,47 +68,48 @@ def start(caller):
""" """
text = random_string_from_module(CONNECTION_SCREEN_MODULE) text = random_string_from_module(CONNECTION_SCREEN_MODULE)
text += "\n\nEnter your username or |yNEW|n to create one." text += "\n\nEnter your username or |yNEW|n to create a new account."
options = ( options = (
{ "key": "",
"goto": "start",
},
{ {
"key": "new", "key": "new",
"desc": "Create a new character.",
"goto": "create_account", "goto": "create_account",
}, },
{ "key": "quit",
"goto": "quit"
},
{ {
"key": "_default", "key": "_default",
"desc": "Login to a valid username.",
"goto": "username", "goto": "username",
}, },
) )
return text, options return text, options
def username(caller, input): def username(caller, string_input):
"""Check that the username leads to an existing player. """Check that the username leads to an existing player.
Check that the specified username exists. If the username doesn't Check that the specified username exists. If the username doesn't
exist, display an error message and ask the user to either exist, display an error message and ask the user to try again. If
enter 'b' to go back, or to try again. entering an empty string, return to start node. If user exists,
If it does exist, move to the next node (enter password). move to the next node (enter password).
""" """
input = input.strip() string_input = string_input.strip()
player = managers.players.get_player_from_name(input) player = managers.players.get_player_from_name(string_input)
if player is None: if player is None:
text = dedent(""" text = dedent("""
|rThe username {} doesn't exist yet. Have you created it?|n |rThe username '{}' doesn't exist. Have you created it?|n
Type |yb|n to go back to the previous menu. Try another name or leave empty to go back.
Or try another name. """.strip("\n")).format(string_input)
""".strip("\n")).format(input)
options = ( options = (
{ {
"key": "b", "key": "",
"desc": "Back to the previous menu.",
"goto": "start", "goto": "start",
}, },
{ {
"key": "_default", "key": "_default",
"desc": "Try again.",
"goto": "username", "goto": "username",
}, },
) )
@ -116,19 +117,22 @@ def username(caller, input):
caller.ndb._menutree.player = player caller.ndb._menutree.player = player
text = "Enter the password for the {} account.".format(player.name) text = "Enter the password for the {} account.".format(player.name)
# Disables echo for the password # Disables echo for the password
caller.msg(echo=False) caller.msg("", options={"echo": False})
caller.msg(echo=False)
options = ( options = (
{
"key": "",
"exec": lambda caller: caller.msg("", options={"echo": True}),
"goto": "start",
},
{ {
"key": "_default", "key": "_default",
"desc": "Enter your account's password.",
"goto": "password", "goto": "password",
}, },
) )
return text, options return text, options
def password(caller, input): def password(caller, string_input):
"""Ask the user to enter the password to this player. """Ask the user to enter the password to this player.
This is assuming the user exists (see 'create_username' and This is assuming the user exists (see 'create_username' and
@ -139,53 +143,41 @@ def password(caller, input):
""" """
menutree = caller.ndb._menutree menutree = caller.ndb._menutree
caller.msg(echo=True) string_input = string_input.strip()
input = input.strip()
options = ( # Check the password and login is correct; also check for bans
{
"key": "_default",
"desc": "Enter your password.",
"goto": "password",
},
)
# Check the password and login if correct
if not hasattr(menutree, "player"):
text = dedent("""
|rSomething went wrong! The player was not remembered
from last step!|n
Press RETURN to continue.
""".strip("\n"))
# Redirects to the first node
options = (
{
"key": "_default",
"desc": "Press RETURN to continue.",
"goto": "start",
},
)
else:
player = menutree.player player = menutree.player
password_attempts = menutree.password_attempts \
if hasattr(menutree, "password_attempts") else 0
bans = ServerConfig.objects.conf("server_bans") bans = ServerConfig.objects.conf("server_bans")
banned = bans and (any(tup[0] == player.name.lower() for tup in bans) \ banned = bans and (any(tup[0] == player.name.lower() for tup in bans) \
or any(tup[2].match(caller.address) for tup in bans if tup[2])) or any(tup[2].match(caller.address) for tup in bans if tup[2]))
if not player.check_password(input):
caller.msg(echo=False) if not player.check_password(string_input):
# Didn't enter a correct password
password_attempts += 1
if password_attempts > 2:
# Too many tries
caller.sessionhandler.disconnect(
caller, "|rToo many failed attempts. Disconnecting.|n")
text = ""
options = {}
else:
menutree.password_attempts = password_attempts
text = dedent(""" text = dedent("""
|rIncorrect password.|n |rIncorrect password.|n
Type |yb|n to go back to the login screen. Try again or leave empty to go back.
Or enter your password again.
""".strip("\n")) """.strip("\n"))
# Loops on the same node # Loops on the same node
options = ( options = (
{ {
"key": "b", "key": "",
"desc": "Go back to the login screen.", "exec": lambda caller: caller.msg("", options={"echo": True}),
"goto": "start", "goto": "start",
}, },
{ {
"key": "_default", "key": "_default",
"desc": "Enter your password again.",
"goto": "password", "goto": "password",
}, },
) )
@ -193,24 +185,16 @@ def password(caller, input):
# This is a banned IP or name! # This is a banned IP or name!
string = dedent(""" string = dedent("""
|rYou have been banned and cannot continue from here. |rYou have been banned and cannot continue from here.
If you feel this ban is in error, please email an admin.|x If you feel this ban is in error, please email an admin.|n
Disconnecting.
""".strip("\n")) """.strip("\n"))
caller.msg(string) caller.sessionhandler.disconnect(caller, string)
caller.sessionhandler.disconnect(
caller, "Good bye! Disconnecting...")
# This is not necessary, since the player is disconnected,
# but it seems to raise an error if simply returning None, None
text = "" text = ""
options = ( options = {}
{
"key": "_default",
"desc": "Go back to the login screen.",
"goto": "start",
},
)
else: else:
# We are OK, log us in. # We are OK, log us in.
text = "" text = ""
options = {}
caller.sessionhandler.login(caller, player) caller.sessionhandler.login(caller, player)
return text, options return text, options
@ -222,91 +206,77 @@ def create_account(caller):
The input is redirected to 'create_username'. The input is redirected to 'create_username'.
""" """
text = "Enter your new account's name." text = "Enter your new account name."
options = ( options = (
{ {
"key": "_default", "key": "_default",
"desc": "Enter your new username.",
"goto": "create_username", "goto": "create_username",
}, },
) )
return text, options return text, options
def create_username(caller, input): def create_username(caller, string_input):
"""Prompt to enter a valid username (one that doesnt exist). """Prompt to enter a valid username (one that doesnt exist).
'input' contains the new username. If it exists, prompt 'string_input' contains the new username. If it exists, prompt
the username to retry or go back to the login screen. the username to retry or go back to the login screen.
""" """
menutree = caller.ndb._menutree menutree = caller.ndb._menutree
input = input.strip() string_input = string_input.strip()
player = managers.players.get_player_from_name(input) player = managers.players.get_player_from_name(string_input)
options = (
{
"key": "_default",
"desc": "Enter your new account's password.",
"goto": "create_password",
},
)
# If a player with that name exists, a new one will not be created # If a player with that name exists, a new one will not be created
if player: if player:
text = dedent(""" text = dedent("""
|rThe account {} already exists.|n |rThe account {} already exists.|n
Type |yb|n to go back to the login screen. Enter another username or leave blank to go back.
Or enter another username to create. """.strip("\n")).format(string_input)
""".strip("\n")).format(input)
# Loops on the same node # Loops on the same node
options = ( options = (
{ {
"key": "b", "key": "",
"desc": "Go back to the login screen.",
"goto": "start", "goto": "start",
}, },
{ {
"key": "_default", "key": "_default",
"desc": "Enter another username.",
"goto": "create_username", "goto": "create_username",
}, },
) )
elif not RE_VALID_USERNAME.search(input): elif not RE_VALID_USERNAME.search(string_input):
text = dedent(""" text = dedent("""
|rThis username isn't valid.|n |rThis username isn't valid.|n
Only letters are accepted, without special characters. Only letters are accepted, without special characters.
The username must be at least 3 characters long. The username must be at least 3 characters long.
Type |yb|n to go back to the login screen. Enter another username or leave blank to go back.
Or enter another username to be created.
""".strip("\n")) """.strip("\n"))
options = ( options = (
{ {
"key": "b", "key": "",
"desc": "Go back to the login screen.",
"goto": "start", "goto": "start",
}, },
{ {
"key": "_default", "key": "_default",
"desc": "Enter another username.",
"goto": "create_username", "goto": "create_username",
}, },
) )
else: else:
menutree.playername = input # a valid username - continue getting the password
menutree.playername = string_input
# Disables echo for entering password # Disables echo for entering password
caller.msg(echo=False) caller.msg("", options={"echo": False})
# Redirects to the creation of a password # Redirects to the creation of a password
text = "Enter this account's new password." text = "Enter this account's new password."
options = ( options = (
{ {
"key": "_default", "key": "_default",
"desc": "Enter this account's new password.",
"goto": "create_password", "goto": "create_password",
}, },
) )
return text, options return text, options
def create_password(caller, input): def create_password(caller, string_input):
"""Ask the user to create a password. """Ask the user to create a password.
This node is at the end of the menu for account creation. If This node is at the end of the menu for account creation. If
@ -318,43 +288,24 @@ def create_password(caller, input):
text = "" text = ""
options = ( options = (
{ {
"key": "b", "key": "",
"desc": "Go back to the login screen.", "exec": lambda caller: caller.msg("", options={"echo": True}),
"goto": "start", "goto": "start",
}, },
{ {
"key": "_default", "key": "_default",
"desc": "Enter your password.",
"goto": "create_password", "goto": "create_password",
}, },
) )
caller.msg(echo=True) password = string_input.strip()
password = input.strip()
if not hasattr(menutree, 'playername'):
text = dedent("""
|rSomething went wrong! Playername not remembered
from previous step!|n
Press RETURN to go back to the login screen.
""".strip("\n"))
# Redirects to the starting node
options = (
{
"key": "_default",
"desc": "Go back to the login screen.",
"goto": "start",
},
)
else:
playername = menutree.playername playername = menutree.playername
if len(password) < LEN_PASSWD: if len(password) < LEN_PASSWD:
caller.msg(echo=False)
# The password is too short # The password is too short
text = dedent(""" text = dedent("""
|rYour password must be at least {} characters long.|n |rYour password must be at least {} characters long.|n
Type |yb|n to return to the login screen. Enter another password or leave it empty to go back.
Or enter another password.
""".strip("\n")).format(LEN_PASSWD) """.strip("\n")).format(LEN_PASSWD)
else: else:
# Everything's OK. Create the new player account and # Everything's OK. Create the new player account and
@ -378,18 +329,21 @@ def create_password(caller, input):
# won't see any errors at all. # won't see any errors at all.
caller.msg(dedent(""" caller.msg(dedent("""
|rAn error occurred.|n Please e-mail an admin if |rAn error occurred.|n Please e-mail an admin if
the problem persists. the problem persists. Try another password or leave
Type |yb|n to go back to the login screen. it empty to go back to the login screen.
Or enter another password.
""".strip("\n"))) """.strip("\n")))
logger.log_trace() logger.log_trace()
else: else:
text = "" text = ""
caller.msg("Welcome, you're new account has been created!") caller.msg("|gWelcome, your new account has been created!|n")
caller.sessionhandler.login(caller, new_player) caller.sessionhandler.login(caller, new_player)
return text, options return text, options
def quit(caller):
caller.sessionhandler.disconnect(caller, "Goodbye! Logging off.")
return "", {}
## Other functions ## Other functions
def _formatter(nodetext, optionstext, caller=None): def _formatter(nodetext, optionstext, caller=None):
@ -426,5 +380,5 @@ class CmdUnloggedinLook(Command):
def func(self): def func(self):
"Execute the menu" "Execute the menu"
menu = EvMenu(self.caller, "evennia.contrib.evmenu_login", EvMenu(self.caller, "evennia.contrib.evmenu_login",
startnode="start", auto_quit=False, node_formatter=_formatter) startnode="start", auto_look=False, auto_quit=False, node_formatter=_formatter)

View file

@ -245,7 +245,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
reason (str): Reason for disconnecting. reason (str): Reason for disconnecting.
""" """
self.data_out(connection_close=((reason or "",), {})) self.data_out(text=((reason or "",), {}))
self.connectionLost(reason) self.connectionLost(reason)
def data_in(self, **kwargs): def data_in(self, **kwargs):
@ -294,7 +294,6 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
Note that it must be actively turned back on again! Note that it must be actively turned back on again!
""" """
#print "telnet.send_text", args,kwargs
text = args[0] if args else "" text = args[0] if args else ""
if text is None: if text is None:
return return

View file

@ -64,7 +64,7 @@ class WebSocketClient(Protocol, Session):
reason (str): Motivation for the disconnection. reason (str): Motivation for the disconnection.
""" """
self.data_out(connection_close=((reason or "",), {})) self.data_out(text=((reason or "",), {}))
self.connectionLost(reason) self.connectionLost(reason)
def connectionLost(self, reason): def connectionLost(self, reason):

View file

@ -376,7 +376,7 @@ class ServerSession(Session):
for the protocol(s). for the protocol(s).
""" """
if text: if text is not None:
self.data_out(text=text, **kwargs) self.data_out(text=text, **kwargs)
else: else:
self.data_out(**kwargs) self.data_out(**kwargs)
@ -409,6 +409,7 @@ class ServerSession(Session):
return u"%s" % str(self) return u"%s" % str(self)
# Dummy API hooks for use during non-loggedin operation # Dummy API hooks for use during non-loggedin operation
def at_cmdset_get(self, **kwargs): def at_cmdset_get(self, **kwargs):

View file

@ -205,7 +205,6 @@ class SessionHandler(dict):
else: else:
rkwargs[key] = [ [_validate(data)], {} ] rkwargs[key] = [ [_validate(data)], {} ]
rkwargs[key][1]["options"] = options rkwargs[key][1]["options"] = options
return rkwargs return rkwargs