From 0c1f7ea252322ed63a871974f8f3327081441b28 Mon Sep 17 00:00:00 2001 From: Darksider3 Date: Wed, 16 Oct 2019 20:52:15 +0200 Subject: [PATCH] Validate even imported files and users Created a new file for the validation functions, should be soon(TM) used too in the userapplication-script but dont hurry --- private/Backup.py | 57 ++++++++++++++++++++++++----------- private/lib/UserExceptions.py | 27 ++++++++++++++++- private/lib/validator.py | 52 ++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 18 deletions(-) create mode 100644 private/lib/validator.py diff --git a/private/Backup.py b/private/Backup.py index e71599e..35f9bd6 100644 --- a/private/Backup.py +++ b/private/Backup.py @@ -4,6 +4,8 @@ import ListUsers import csv import io import lib.CFG as CFG +import lib.validator +import lib.UserExceptions import os @@ -52,6 +54,7 @@ class Backup: return None # @TODO maybe some better output here if userids: pass # empty tuple means everything + # noinspection PyBroadException try: with open(fname, 'r', newline='') as f: import lib.sqlitedb @@ -60,25 +63,45 @@ class Backup: sql = lib.sqlitedb.SQLitedb(CFG.REG_FILE) reader = csv.DictReader(f) # @TODO csv.Sniffer to compare? When yes, give force-accept option for row in reader: + # if any of this fails move on to the next user, just print a relatively helpful message lel + if not lib.validator.checkUsernameLength(row["username"]): + print(f"The username {row['username']} is either too long(>16) or short(<3).") + continue + if not lib.validator.checkUsernameCharacters(row["username"]): + print(f"The username contains unsupported characters or starts with a number: " + f"{row['username']}") + continue + if not lib.validator.checkSSHKey(row["pubkey"]): + print(f"Following SSH-Key isn't valid: {row['pubkey']}") + continue + if lib.validator.checkUserExists(row["username"]): + print(f"The user '{row['username']}' already exists.") + continue + if not lib.validator.checkEmail(row["email"]): + print(f"The E-Mail address {row['email']} is not valid.") + continue if row["status"] == "1": - sysctl.register(row["username"]) - sysctl.lock_user_pw(row["username"]) - sysctl.add_to_usergroup(row["username"]) - sysctl.make_ssh_usable(row["username"], row["pubkey"]) - print(row['id'], row['username'], row['email'], row['name'], row['pubkey'], row['timestamp'], - row['status'] + "====> Registered.") + try: + sysctl.register(row["username"]) # @TODO exception lib.UserExceptions.UserExistsAlready + sysctl.lock_user_pw(row["username"]) # @TODO exception lib.UserExceptions.UnknownReturnCode + sysctl.add_to_usergroup(row["username"]) # @TODO exception lib.UnknownReturnCode + sysctl.make_ssh_usable(row["username"], row["pubkey"]) # @TODO exception + print(row['username'], "====> Registered.") + except Exception as e: + print(e) + continue elif row["status"] == "0": - print(row['id'], row['username'], row['email'], row['name'], row['pubkey'], row['timestamp'], - row['status'] + "not approved, therefore not registered.") - else: - print(f"Uhm, ok. Type is {type(row['status'])}, and value is {row['status']}") - sql.safequery("INSERT INTO `applications` (username, name, timestamp, email, pubkey, status) " - "VALUES (?,?,?,?,?,?)", - tuple([row["username"], row["name"], row["timestamp"], - row["email"], row["pubkey"], row["status"]])) # @TODO: without IDs - pass # @TODO: Import with sqlitedb and system. Will be fun Kappa - except OSError as E: - print(f"UUFFF, something went WRONG with the file {fname}: {E}") + print(row['username'] + "not approved, therefore not registered.") + try: + sql.safequery( + "INSERT INTO `applications` (username, name, timestamp, email, pubkey, status) " + "VALUES (?,?,?,?,?,?)", tuple([row["username"], row["name"], row["timestamp"], + row["email"], row["pubkey"], row["status"]])) + except OSError as E: + pass + print(f"UUFFF, something went WRONG with the file {fname}: {E}") + except Exception as e: + print(f"Exception! UNCATCHED! {type(e)}") return True diff --git a/private/lib/UserExceptions.py b/private/lib/UserExceptions.py index 02e8f47..926c8e5 100644 --- a/private/lib/UserExceptions.py +++ b/private/lib/UserExceptions.py @@ -18,5 +18,30 @@ class ModifyFilesystem(General): pass -class HomeDirExistsAlready(ModifyFilesystem): +class SSHDirUncreatable(ModifyFilesystem): pass + + +class SQLiteDatabaseDoesntExistYet(General): + pass + + +class User(Exception): + pass + + +class UsernameLength(User): + pass + + +class UsernameTooShort(User): + pass + + +class UsernameTooLong(User): + pass + + +class UsernameInvalidCharacters(User): + pass + diff --git a/private/lib/validator.py b/private/lib/validator.py new file mode 100644 index 0000000..82283d0 --- /dev/null +++ b/private/lib/validator.py @@ -0,0 +1,52 @@ +import re +import pwd + + +def checkUsernameCharacters(username: str): + if re.match("[a-z]+[a-z0-9]", username): + return True + else: + return False + + +def checkUsernameLength(username: str): + if len(username) > 16: + return False + if len(username) < 3: + return False + return True + + +def checkUserExists(username: str): + try: + pwd.getpwnam(username) + except KeyError: + return True # User already exists + else: + return False # User doesnt exist + + +def checkSSHKey(key: str): + # taken from https://github.com/hashbang/provisor/blob/master/provisor/utils.py, all belongs to them! ;) + import base64 + if len(key) > 8192 or len(key) < 80: + return False + + key = key.replace("\"", "").replace("'", "").replace("\\\"", "") + key = key.split(' ') + types = ['ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', + 'ecdsa-sha2-nistp521', 'ssh-rsa', 'ssh-dss', 'ssh-ed25519'] + if key[0] not in types: + return False + try: + base64.decodebytes(bytes(key[1], "utf-8")) + except TypeError: + return False + return True + + +def checkEmail(mail: str): + if not re.match("(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", mail): + return False + else: + return True