diff --git a/Synology.py b/Synology.py index 98cadf6..c5144bd 100644 --- a/Synology.py +++ b/Synology.py @@ -83,7 +83,7 @@ def start(): def load_file(): fname = tkinter.filedialog.askopenfilename() - + if fname: try: pkfilebox.config(state='normal') @@ -105,7 +105,7 @@ def load_file(): def load_filepu(): fname = tkinter.filedialog.askopenfilename() - + if fname: try: pufilebox.config(state='normal') @@ -142,7 +142,7 @@ def load_decrypt_file(): fname = tkinter.filedialog.askopenfilename() else: fname = tkinter.filedialog.askdirectory() - + if fname: try: filebox.config(state='normal') @@ -164,7 +164,7 @@ def load_decrypt_file(): def load_output(): fname = tkinter.filedialog.askdirectory() - + if fname: try: outputbox.config(state='normal') @@ -198,7 +198,7 @@ def validate(): try: run_tool() except Exception as e: - elogger.error(e) + elogger.error(e, exc_info=e) tkinter.messagebox.showwarning("Decryption", "Failed to decrypt file(s), please raise an issue using the support button located in the about option of the application menu") else: tkinter.messagebox.showinfo("Decryption", "Files have successfully been decrypted and can be found in the destination folder") @@ -226,7 +226,7 @@ def validate(): try: run_tool() except Exception as e: - elogger.error(e) + elogger.error(e, exc_info=e) tkinter.messagebox.showwarning("Decryption", "Failed to decrypt file(s), please raise an issue using the support button located in the about option of the application menu") else: tkinter.messagebox.showinfo("Decryption", "Files have successfully been decrypted and can be found in the destination folder") @@ -317,7 +317,7 @@ def about_dialog(): win.title("About") win.configure(bg="#e7e7e7") win.resizable(0,0) - + img = ImageTk.PhotoImage(Image.open("app.gif").resize((128, 128), Image.ANTIALIAS)) icon = ttk.Label(win, image=img) icon.image = img @@ -331,7 +331,7 @@ def about_dialog(): license.config(state='disabled', highlightbackground='grey', highlightcolor='grey', borderwidth=1, highlightthickness=1) support = ttk.Button(win, text="Support", command=lambda: open_url("https://github.com/anojht/synology-cloud-sync-decrypt-tool/issues")) donate = ttk.Button(win, text="Donate", command=lambda: open_url("https://www.paypal.me/Anojh")) - + icon.grid(row=0, column=1, padx=10) name.grid(row=1, column=1, padx=10) author.grid(row=2, column=1) diff --git a/syndecrypt/__main__.py b/syndecrypt/__main__.py index 9d7f421..86aff77 100644 --- a/syndecrypt/__main__.py +++ b/syndecrypt/__main__.py @@ -23,19 +23,21 @@ import docopt import os import logging - +import sys +from multiprocessing import Pool + import syndecrypt.files as files #import files import syndecrypt.util as util #from syndecrypt import util def main(args): - + if args[0] == "-p": arguments = {"--password-file": args[1], "--private-key-file": None, "--public-key-file": None, "--output-directory": args[2], "": args[3]} elif args[0] == "-k": arguments = {"--password-file": None, "--private-key-file": args[1], "--public-key-file": args[2], "--output-directory": args[3], "": args[4]} - + password_file_name = arguments['--password-file'] if password_file_name != None: password = arguments['--password-file'] @@ -60,22 +62,36 @@ def main(args): f = arguments[''] ff = os.path.abspath(f) fp = os.path.basename(ff) - + if os.path.isdir(ff): if not os.path.isdir(os.path.join(output_dir, fp)): output_dir = os.path.join(output_dir, fp) os.mkdir(output_dir) else: print("Folder already exists!") - for root, subdirs, items in os.walk(ff): - structure = root.replace(ff, output_dir, 1) + + directories = list(os.walk(ff)) + + for input_dir, _, _ in directories: + structure = input_dir.replace(ff, output_dir, 1) if not os.path.isdir(structure): os.mkdir(structure) - - for filename in items: - file_path = os.path.join(root, filename) - if filename != ".DS_Store": - files.decrypt_file(file_path, os.path.join(structure, filename), password=password, private_key=private_key, public_key=public_key) + + decrypt_args = [] + + for input_dir, _, filenames in directories: + for filename in filenames: + decrypt_args.append(( + os.path.join(input_dir, filename), + os.path.join(input_dir.replace(ff, output_dir, 1), filename), + password, + private_key, + public_key, + )) + + with Pool() as p: + p.starmap(files.decrypt_file, decrypt_args) + else: files.decrypt_file(ff, os.path.join(output_dir, fp), password=password, private_key=private_key, public_key=public_key) diff --git a/syndecrypt/core.py b/syndecrypt/core.py index 12c3938..ad06b6e 100644 --- a/syndecrypt/core.py +++ b/syndecrypt/core.py @@ -31,7 +31,7 @@ # pwd and salt must be bytes objects def _openssl_kdf(algo, pwd, salt, key_size, iv_size, iteration): temp = b'' - + fd = temp while len(fd) < key_size + iv_size: try: @@ -173,14 +173,17 @@ def read_header(f): s = f.read(len(MAGIC)) if s != MAGIC: LOGGER.error('magic should not be ' + str(s) + ' but ' + str(MAGIC)) + return None s = f.read(32) magic_hash = hashlib.md5(MAGIC).hexdigest().encode('ascii') if s != magic_hash: LOGGER.error('magic hash should not be ' + str(s) + ' but ' + str(magic_hash)) + return None header = _read_object_from(f) if header['type'] != 'metadata': LOGGER.error('first object must have "metadata" type but found ' + header['type']) + return None return header def read_chunks(f): @@ -203,6 +206,9 @@ def outstream_writer_and_md5_digestor(decompressed_chunk): # create session key and decryptor header = read_header(instream) + if not header: + LOGGER.info('failed to parse header; skipping file...') + return # TODO: assert version and hash algo decrypt_stream.md5_digestor = hashlib.md5() if password != None: