From 14b6c6905ae0767596fe06b1c057db9416f0d8b2 Mon Sep 17 00:00:00 2001 From: PanFritz Date: Wed, 25 Nov 2015 18:22:08 +0100 Subject: Lots of fixes, added player loading/ unloading, login.py custom event system, mysql_utils.columns property --- loginsecurity.py | 275 ------------------------------------------------------ main.py | 2 +- mysql_utils.py | 12 +++ wrapper.py | 3 +- wrapper_event.py | 70 +++++++++----- wrapper_player.py | 113 +++++++++++++++++----- 6 files changed, 153 insertions(+), 322 deletions(-) delete mode 100644 loginsecurity.py diff --git a/loginsecurity.py b/loginsecurity.py deleted file mode 100644 index 89f9e47..0000000 --- a/loginsecurity.py +++ /dev/null @@ -1,275 +0,0 @@ -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 - -wait_time = 60 #seconds -admin_perm = "utils.loginsecurity.admin" -min_pass_length = 8 -blocked_events = ["block.BlockBreakEvent", "block.BlockPlaceEvent", "player.PlayerMoveEvent","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 = " ", - 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 = "", - description = "Logs you in if 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 = "", - description = "Registers you with . 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 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 = "", - senderLimit = -1, - description = "Removes password of 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 ") - 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) diff --git a/main.py b/main.py index 3e1319d..08ab182 100644 --- a/main.py +++ b/main.py @@ -34,7 +34,7 @@ info("Loading RedstonerUtils...") # Import all modules, in this order -shared["load_modules"] = ["test"] +shared["load_modules"] = ["test", "login"] shared["modules"] = {} for module in shared["load_modules"]: diff --git a/mysql_utils.py b/mysql_utils.py index e59c3d9..1edfe35 100644 --- a/mysql_utils.py +++ b/mysql_utils.py @@ -13,11 +13,23 @@ class mysql_connect: if args is None: return self.curs.execute(query) else: + print query + print args return self.curs.execute(query, args) def fetchall(self): return self.curs.fetchall() + @property + def columns(self): + self.execute("SHOW COLUMNS FROM utils_players") + fetched = self.fetchall() + columns = [] + + for row in fetched: + columns.append(row[0]) + return columns + def __enter__(self): return self diff --git a/wrapper.py b/wrapper.py index ddca5b5..b5b14ff 100644 --- a/wrapper.py +++ b/wrapper.py @@ -8,4 +8,5 @@ Before you run away from this if the class you need to use isn't here, please cr from helpers import * from wrapper_event import * from wrapper_player import * -from wrapper_command import * \ No newline at end of file +from wrapper_command import * +from util_events import utils_event, fire_event, utils_events \ No newline at end of file diff --git a/wrapper_event.py b/wrapper_event.py index c203cd3..8632c70 100644 --- a/wrapper_event.py +++ b/wrapper_event.py @@ -1,30 +1,56 @@ from wrapper import * +from util_events import utils_event, utils_events from wrapper_player import * from traceback import format_exc as print_traceback -class py_event: - def __init__(self,event): - self.event = event - try: - self.player = py_players[event.getPlayer()] - except: - warn("Player doesn't exist") +class py_event(object): + def __init__(self,event): + self.event = event + try: + self.player = py_players[event.getPlayer()] + except: + warn("Player doesn't exist") - @property - def cancelled(self): - return self.event.isCancelled() + @property + def cancelled(self): + return self.event.isCancelled() - @cancelled.setter - def cancelled(self, value): - self.event.setCancelled(value) + @cancelled.setter + def cancelled(self, value): + self.event.setCancelled(value) + + @property + def message(self): + try: + return self.event.getMessage() + except: + raise AttributeError + + @message.setter + def message(self, msg): + try: + self.event.setMessage(msg) + except: + raise AttributeError + +def event_handler(event_name = None, priority = "normal", utils = False): + if not utils: + def decorator(wrapped): + @hook.event(event_name, priority) + def wrapper(event): + try: + wrapped(py_event(event)) + except: + print(print_traceback()) + return decorator + elif utils: + def decorator(wrapped): + @utils_event(event_name, priority, create_event = utils_events) + def wrapper(*args): + try: + wrapped(*args) + except: + print(print_traceback()) + return decorator -def event_handler(event_name = None, priority = "normal"): - def decorator(wrapped): - @hook.event(event_name, priority) - def wrapper(event): - try: - wrapped(py_event(event)) - except: - print(print_traceback()) - return decorator diff --git a/wrapper_player.py b/wrapper_player.py index 4ca302a..5fb5c79 100644 --- a/wrapper_player.py +++ b/wrapper_player.py @@ -1,25 +1,75 @@ import time import mysqlhack from mysql_utils import * +from util_events import fire_event from thread_utils import * from players_secret import * from datetime import datetime from com.ziclix.python.sql import zxJDBC +from traceback import format_exc as print_traceback -class py_player: +class py_player(object): def __init__(self,player): self.player = player self.logging_in = True - + self.authenticated = False self.login_time = time.time() - self.nickname = self.name - self.registered = False - self.password = "None" - self.banned = False - self.banned_reason = "You have been banned!" - self.played_time = time.time() - self.login_time - self.last_login = datetime.now() - self.first_seen = datetime.now() + + self.props ={"uuid":self.uuid, + "name":self.name, + "nickname":self.name, + "registered":False, + "password":"None", + "banned":False, + "banned_reason":"You have been banned!", + "played_time":time.time() - self.login_time, + "last_login":datetime.now(), + "first_seen":datetime.now()} + + def __setattr__(self, attribute, value): + if not attribute in dir(self): + if not 'props' in self.__dict__: + self.__dict__[attribute] = value + else: + self.props[attribute] = value + else: + object.__setattr__(self, attribute, value) + + def __getattr__(self, attribute): + try: + return self.props[attribute] + except: + pass + + def save(self): + properties = [] + keys = [] + columns = [] + + with mysql_connect() as sql: + columns = sql.columns + + for key, value in self.props.items(): + if key not in columns: + with mysql_connect() as sql: + if isinstance(value, int): + sql.execute("ALTER TABLE utils_players ADD %s INT" % key) + elif isinstance(value, str): + sql.execute("ALTER TABLE utils_players ADD %s TEXT" % key) + elif isinstance(value, bool): + sql.execute("ALTER TABLE utils_players ADD %s TINYINT(1)" % key) + if key == "uuid": + continue + keys.append(key+"=?") + properties.append(value) + print value + properties.append(self.props["uuid"]) + keys = str(tuple(keys)).replace("\'","").replace("(","").replace(")","") + + + with mysql_connect() as sql: + sql.execute("UPDATE utils_players set %s WHERE uuid = ?" % keys, properties) + def kick(self, kick_message = "You have been kicked from the server!"): self.player.KickPlayer(kick_message) @@ -34,6 +84,7 @@ class py_player: @property def uuid(self): return str(self.player.getUniqueId()) + class Py_players: @@ -60,10 +111,12 @@ py_players = Py_players() @async(daemon=True) def fetch_player(player): - properties = (player.uuid, player.name, player.nickname, player.registered, - player.password, player.banned, - player.banned_reason, player.played_time, - player.last_login, player.first_seen) + + properties = [] + keys = [] + for key, value in player.props.iteritems(): + keys.append(key) + properties.append(value) with mysql_connect() as sql: sql.execute("SELECT * FROM utils_players WHERE uuid = ?", (player.uuid,)) @@ -71,24 +124,34 @@ def fetch_player(player): if len(result) is 0: with mysql_connect() as sql: - sql.execute("INSERT INTO utils_players \ - (uuid, name, nickname, registered, password, banned, \ - banned_reason, played_time, last_login, first_seen) \ - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - - args=properties) + sql.execute("INSERT INTO utils_players %s \ + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" % str(tuple(keys)).replace("\'","") + ,args=tuple(properties)) elif len(result) is 1: + keys = [] props = result[0] - print props + with mysql_connect() as sql: + sql.execute("SHOW COLUMNS FROM utils_players") + result = sql.fetchall() + for row in result: + keys.append(row[0]) + + for key in keys: + player.props[key] = props[keys.index(key)] + for prop in properties: - prop = props[properties.index(prop)] + print str(prop) else: player.kick("Something went wrong while loading your player data, please contact an admin") return + player.logging_in = False player.msg("You have succesfully logged into redstoner!") + fire_event("player_login", player) + + blocked_events = ["block.BlockBreakEvent", "block.BlockPlaceEvent", "player.PlayerMoveEvent", @@ -106,7 +169,11 @@ for event in blocked_events: @hook.event("player.PlayerJoinEvent","lowest") def on_join(event): - player = py_player(event.getPlayer()) + try: + player = py_player(event.getPlayer()) + except: + print(print_traceback()) + time.sleep(10) py_players.append(player) player.msg("Your input will be blocked for a short while") fetch_player(player) -- cgit v1.2.3