from Crypto.Cipher import AES import base64 import json import argparse import sys import string import random import datetime import os windows = False if sys.platform == "win32": windows = True print("") print("####################################") print("Program does not run on Windows!") print("Falling back to Testing Mode!") print("####################################") print("") def encrypt_val(clear_text, master): enc_secret = AES.new(master[:32]) tag_string = (str(clear_text) + (AES.block_size - len(str(clear_text)) % AES.block_size) * "\0") cipher_text = base64.b64encode(enc_secret.encrypt(tag_string)) return cipher_text def decrypt_val(cipher_text, master): dec_secret = AES.new(master[:32]) raw_decrypted = dec_secret.decrypt(base64.b64decode(cipher_text)) clear_val = raw_decrypted.rstrip("\0".encode()) return clear_val parser = argparse.ArgumentParser(description="Backup Script") parser.add_argument("-c", "--config", help="config file", default="settings.json") parser.add_argument("-t", "--test", help="Start in testing mode", action='store_true', default=False) args = parser.parse_args() if args.test: print("") print("####################################") print("Program is now running in testing Mode!") print("####################################") print("") windows = True try: json_data=open(args.config).read() except Exception as e: sys.exit("Cant open Config File:\n{0}".format(e)) try: data = json.loads(json_data) except Exception as e: sys.exit("Parser Error in JSON File {0}:\n{1}".format(args.config, e)) def save_json(): global data global args with open(args.config, 'w') as outfile: json.dump(data, outfile, sort_keys=True, indent=4, separators=(',', ': ')) MASTER_KEY = "" if not "option" in data or not "masterpassword" in data["option"] or data["option"]["masterpassword"] == "": master_pw = ''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(16)) data["option"]["masterpassword"] = base64.b64encode(master_pw.encode()).decode("utf-8") print("MASTER PASSWORD automaticly generated. !!!DO NOT REMOVE IT FROM THE SETTINGS FILE!!!") save_json() MASTER_KEY = data["option"]["masterpassword"] ignore = ["option"] for server in data: if server in ignore: continue host = server print("") print("") print("") print("--- {0} --".format(host)) for type in data[server]["types"]: print("") user = "" authtype, password = ("", "") if not "auth" in type: sys.exit("Server {0} has no authentication".format(server)) if not "destination" in type: sys.exit("Server {0} has no destination directory".format(server)) if not os.path.isdir(type["destination"]): sys.exit("Destination {0} for Server {1} not found".format(type["destination"], server)) if not "user" in type["auth"] or type["auth"]["user"] == "": sys.exit("Server {0} has no user".format(server)) else: user = type["auth"]["user"] if not "password" in type["auth"] or type["auth"]["password"] == "": if not "key" in type["auth"] or type["auth"]["key"] == "": sys.exit("Server {0} has no password or key".format(server)) else: authtype, password = ("key", type["auth"]["key"]) else: if type["auth"]["password"].endswith(".==="): authtype, password = ("password", decrypt_val((str(type["auth"]["password"])[:-2]).encode(), MASTER_KEY).decode("utf-8")) else: authtype, password = ("password", type["auth"]["password"]) encrypted = encrypt_val(type["auth"]["password"], MASTER_KEY).decode("utf-8") print("Encrypted {0}") type["auth"]["password"] = "{0}.===".format(encrypted) save_json() print("{0} {1}@{2} using {3} destination is {4}".format(type["type"], user, host, authtype, type["destination"])) if type["type"] == "sftp": if not "backup" in type or type["backup"] == "": sys.exit("Server {0} has backup paths".format(server)) rsync_base = ["rsync", "-zavx", "--ignore-errors", "--delete", "--delete-excluded"] bpaths = [] expaths = [] bpaths.extend(type["backup"]) if "exclude" in type: for exclude in type["exclude"]: rsync_base.extend(["--exclude", exclude]) for bpath in bpaths: bpath = bpath.strip() full_path = bpath.strip() rsync_cmd = rsync_base[:] if authtype == "key": rsync_cmd.append("-e") rsync_cmd.append("'ssh -i {0} -p22'".format(password)) bpath = user + "@" + host + ":" + bpath rsync_cmd.append(bpath) rsync_cmd.append(type["destination"] + os.sep + full_path.replace("/", "_").replace("\\", "_")) print("Running Rsync for {0}".format(bpath)) if not windows: os.system(" ".join(rsync_cmd)) else: print(" ".join(rsync_cmd)) elif type["type"] == "mysql": if not "database" in type or type["database"] == "": sys.exit("Server {0} has database info".format(server)) tstamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S") skip = ["information_schema", "performance_schema"] for db in type["database"]: if db in skip: continue if db == "all": db = "--all-databases" dbbackup_name = "{0}_{1}.{2}".format(tstamp, ("all" if db == "--all-databases" else db), "sql") dbbackup_path = type["destination"] + os.sep + dbbackup_name dump_cmd = "mysqldump -u " + user if host != None: dump_cmd += " -h " + "'" + host + "'" if authtype == "password" and password != "": dump_cmd += " -p" + password dump_cmd += " -e --opt -c " + db + " | gzip > " + dbbackup_path + ".gz" print("Dump db, %s to %s." % (db, dbbackup_path)) if not windows: os.system(dump_cmd) else: print(dump_cmd)