#!/usr/bin/env python3 # -*- coding: utf-8 -*- __license__ = 'GPL v3' # Standard Python modules. import os, sys, re, hashlib, traceback #@@CALIBRE_COMPAT_CODE@@ from __init__ import PLUGIN_NAME, PLUGIN_VERSION class NoWinePython3Exception(Exception): pass class WinePythonCLI: py3_test = "import sys; sys.exit(0 if (sys.version_info.major==3) else 1)" def __init__(self, wineprefix=""): import subprocess if wineprefix != "": wineprefix = os.path.abspath(os.path.expanduser(os.path.expandvars(wineprefix))) if wineprefix != "" and os.path.exists(wineprefix): self.wineprefix = wineprefix else: self.wineprefix = None candidate_execs = [ ["wine", "py.exe", "-3"], ["wine", "python3.exe"], ["wine", "python.exe"], ["wine", "C:\\Python27\\python.exe"], # Should likely be removed ] for e in candidate_execs: self.python_exec = e try: self.check_call(["-c", self.py3_test]) print("{0} v{1}: Python3 exec found as {2}".format( PLUGIN_NAME, PLUGIN_VERSION, " ".join(self.python_exec) )) return None except subprocess.CalledProcessError as e: if e.returncode == 1: print("{0} v{1}: {2} is not python3".format( PLUGIN_NAME, PLUGIN_VERSION, " ".join(self.python_exec) )) elif e.returncode == 53: print("{0} v{1}: {2} does not exist".format( PLUGIN_NAME, PLUGIN_VERSION, " ".join(self.python_exec) )) raise NoWinePython3Exception("Could not find python3 executable on specified wine prefix") def check_call(self, cli_args): import subprocess env_dict = os.environ env_dict["PYTHONPATH"] = "" if self.wineprefix is not None: env_dict["WINEPREFIX"] = self.wineprefix subprocess.check_call(self.python_exec + cli_args, env=env_dict, stdin=None, stdout=sys.stdout, stderr=subprocess.STDOUT, close_fds=False, bufsize=1) def WineGetKeys(scriptpath, extension, wineprefix=""): if extension == ".k4i": import json try: pyexec = WinePythonCLI(wineprefix) except NoWinePython3Exception: print('{0} v{1}: Unable to find python3 executable in WINEPREFIX="{2}"'.format(PLUGIN_NAME, PLUGIN_VERSION, wineprefix)) return [], [] basepath, script = os.path.split(scriptpath) print("{0} v{1}: Running {2} under Wine".format(PLUGIN_NAME, PLUGIN_VERSION, script)) outdirpath = os.path.join(basepath, "winekeysdir") if not os.path.exists(outdirpath): os.makedirs(outdirpath) if wineprefix != "": wineprefix = os.path.abspath(os.path.expanduser(os.path.expandvars(wineprefix))) try: result = pyexec.check_call([scriptpath, outdirpath]) except Exception as e: print("{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0])) # try finding winekeys anyway, even if above code errored winekeys = [] winekey_names = [] # get any files with extension in the output dir files = [f for f in os.listdir(outdirpath) if f.endswith(extension)] for filename in files: try: fpath = os.path.join(outdirpath, filename) with open(fpath, 'rb') as keyfile: if extension == ".k4i": new_key_value = json.loads(keyfile.read()) else: new_key_value = keyfile.read() winekeys.append(new_key_value) winekey_names.append(filename) except: print("{0} v{1}: Error loading file {2}".format(PLUGIN_NAME, PLUGIN_VERSION, filename)) traceback.print_exc() os.remove(fpath) print("{0} v{1}: Found and decrypted {2} {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(winekeys), "key file" if len(winekeys) == 1 else "key files")) return winekeys, winekey_names