This repository has been archived on 2024-08-27. You can view files and clone it, but cannot push or open issues or pull requests.
redstoner-utils/loginsecurity.py
Dico fd368a8aac Patch buggy movement blocking when logging in
Added a separate event handler for PlayerMoveEvent which instead of cancelling the event, sets the new position to the old one.
This should fix the buggy, flashy screen you get when you move your cursor while not yet logged in.
2016-06-23 05:21:24 +02:00

283 lines
8.3 KiB
Python

from helpers import *
from passlib.hash import pbkdf2_sha256 as crypt
from basecommands import simplecommand
import time
import threading
from login_secrets import * #Don't forget to make login_secrets aswell
import mysqlhack
from com.ziclix.python.sql import zxJDBC
from java.lang import Runnable
from player import get_py_player, py_players
wait_time = 30 #seconds
admin_perm = "utils.loginsecurity.admin"
min_pass_length = 8
blocked_events = ["block.BlockBreakEvent", "block.BlockPlaceEvent", "player.AsyncPlayerChatEvent"]
def matches(password,user):
thread = threading.Thread(target=matches_thread, args = (password,user))
thread.start()
def matches_thread(password, user):
hashed = get_pass(uid(user))
py_player = get_py_player(user)
if crypt.verify(password, hashed):
if py_player.logging_in:
py_player.logging_in = False
msg(user, "&aLogged in successfully!")
else:
if py_player.logging_in:
msg(user, "&cInvalid password!")
@simplecommand("cgpass",
usage = "<password> <new password>",
description = "Changes your password",
senderLimit = 0,
helpNoargs = True)
def change_pass_command(sender, command, label, args):
py_player = get_py_player(sender)
if py_player.logging_in:
return "&cYou are not logged in"
if not len(args) == 2:
return "&cInvalid arguments"
password = args[0]
new_password = args[1]
uuid = uid(sender)
if is_registered(uuid):
change_pass(uuid, crypt.encrypt(new_password, rounds=200000, salt_size=16))
return "&aPassword changed"
return "&cYou are not registered"
@simplecommand("login",
usage = "<password>",
description = "Logs you in if <password> matches your password.",
senderLimit = 0,
helpNoargs = True)
def login_command(sender, command, label, args):
py_player = get_py_player(sender)
if not py_player.logging_in:
msg(sender,"&cAlready logged in!")
password = args[0]
matches(password, sender)
@simplecommand("register",
usage = "<password>",
description = "Registers you with <password>. Next time you join, log in with /login",
senderLimit = 0,
helpNoargs = True)
def register_command(sender, command, label, args):
py_player = get_py_player(sender)
if len(args) > 1:
return "&cPassword can only be one word!"
uuid = uid(sender)
if is_registered(uuid):
return "&cYou are already registered!"
password = args[0]
if len(password) < min_pass_length:
return "&cThe password has to be made up of at least %s characters!" % min_pass_length
create_pass(uuid, password)
return "&cPassword set. Use /login <password> upon join."
@simplecommand("rmpass",
description = "Removes your password if the password matches",
senderLimit = 0,
amax = 0,
helpNoargs = False)
def rmpass_command(sender, command, label, args):
py_player = get_py_player(sender)
if py_player.logging_in:
return "&cYou are not logged in"
if not is_registered(uid(sender)):
return "&cYou are not registered!"
if py_player.logging_in == False:
delete_pass(uid(sender))
return "&aPassword removed successfully. You will not be prompted anymore."
return "&cFailed to remove password, please contact a staff member"
@simplecommand("rmotherpass",
aliases = ["lacrmpass"],
usage = "<user>",
senderLimit = -1,
description = "Removes password of <user> and sends them a notification",
helpNoargs = True)
def rmotherpass_command(sender, command, label, args):
py_player = get_py_player(sender)
if py_player.logging_in:
return "&cYou are not logged in"
if not sender.hasPermission(admin_perm):
noperm(sender)
return
user = server.getOfflinePlayer(args[0])
if is_registered(uid(user)):
delete_pass(uid(user))
runas(server.getConsoleSender(), colorify("mail send %s &cYour password was reset by a staff member. Use &6/register&c to set a new one." % user.getName()))
return "&aPassword of %s reset successfully" % user.getName()
return "&cThat player could not be found (or is not registered)"
def change_pass(uuid, pw):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("UPDATE secret SET pass = ? WHERE uuid = ?", (pw,uuid,))
conn.commit()
curs.close()
conn.close()
def get_pass(uuid):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("SELECT pass FROM secret WHERE uuid = ?", (uuid,))
results = curs.fetchall()
curs.close()
conn.close()
return results[0][0]
def create_pass(uuid,pw):
thread = threading.Thread(target=create_pass_thread, args=(uuid,pw))
thread.start()
def create_pass_thread(uuid, pw):
pw = crypt.encrypt(pw, rounds=200000, salt_size=16)
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("INSERT INTO secret VALUES (?,?)", (uuid,pw,))
conn.commit()
curs.close()
conn.close()
def is_registered(uuid):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("SELECT EXISTS(SELECT * FROM secret WHERE uuid = ?)", (uuid,))
results = curs.fetchall()
curs.close()
conn.close()
if results[0][0] == 1:
return True
return False
def delete_pass(uuid):
conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
curs = conn.cursor()
curs.execute("DELETE FROM secret WHERE uuid = ?", (uuid,))
conn.commit()
curs.close()
conn.close()
@hook.event("player.PlayerJoinEvent", "highest")
def on_join(event):
user = event.getPlayer()
py_player = get_py_player(event.getPlayer())
if is_registered(uid(user)):
msg(event.getPlayer(), "&4You will be disconnected after 60 seconds if you don't &alogin")
msg(user, "&cUse /login <password>")
py_player.logging_in = True
py_player.login_time = time.time()
return
elif user.hasPermission(admin_perm):
pass #Do what? force them to make a password, lots of code, maybe just message us on slack?
#This shouldn't be needed anymore as py_player gets removed anyway.
"""
@hook.event("player.PlayerQuitEvent", "high")
def on_quit(event):
if event.getPlayer().getName() in logging_in:
del logging_in[event.getPlayer().getName()]
"""
##Threading start
class kick_class(Runnable):
def __init__(self, player):
self.player = player
def run(self):
if self.player.isOnline():
self.player.kickPlayer(colorify("&aLogin timed out"))
def kick_thread():
while True:
time.sleep(1)
now = time.time()
for py_player in py_players:
if py_player.logging_in:
if now - py_player.login_time > wait_time:
player = py_player.player
kick = kick_class(player)
server.getScheduler().runTask(server.getPluginManager().getPlugin("RedstonerUtils"), kick)
"""if name in logging_in:
del logging_in[name]
break
"""
thread = threading.Thread(target = kick_thread)
thread.daemon = True
thread.start()
##Threading end
for blocked_event in blocked_events:
@hook.event(blocked_event, "high")
def on_blocked_event(event):
user = get_py_player(event.getPlayer())
if user.logging_in:
event.setCancelled(True)
@hook.event("player.PlayerCommandPreprocessEvent","normal")
def pre_command_proccess(event):
player = get_py_player(event.getPlayer())
if player.logging_in:
args = event.getMessage().split(" ")
if not args[0].lower() == "/login":
msg(player.player, "&4You need to login before you do that!")
event.setCancelled(True)
@hook.event("player.PlayerMoveEvent","normal")
def player_move(event):
user = get_py_player(event.getPlayer())
if user.logging_in:
event.setTo(event.getFrom())