From e0fcd99bcb44adb648d5999b886f4a486decd84d Mon Sep 17 00:00:00 2001 From: NoDRM Date: Wed, 29 Dec 2021 13:00:45 +0100 Subject: [PATCH] Add passhash interface to CLI --- DeDRM_plugin/adobekey_get_passhash.py | 2 +- DeDRM_plugin/ignoblekeyNookStudy.py | 18 ++--- DeDRM_plugin/standalone/__init__.py | 80 ++++++++++++++------ DeDRM_plugin/standalone/passhash.py | 102 ++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 33 deletions(-) create mode 100644 DeDRM_plugin/standalone/passhash.py diff --git a/DeDRM_plugin/adobekey_get_passhash.py b/DeDRM_plugin/adobekey_get_passhash.py index 5b4502a..adb0965 100644 --- a/DeDRM_plugin/adobekey_get_passhash.py +++ b/DeDRM_plugin/adobekey_get_passhash.py @@ -147,7 +147,7 @@ if iswindows: #print("Didn't find fingerprint for decryption ...") return [], [] - print("Found {0:d} passhashes".format(len(keys))) + print("Found {0:d} passhashes".format(len(keys)), file=sys.stderr) keys_decrypted = [] diff --git a/DeDRM_plugin/ignoblekeyNookStudy.py b/DeDRM_plugin/ignoblekeyNookStudy.py index 4152093..93c691b 100644 --- a/DeDRM_plugin/ignoblekeyNookStudy.py +++ b/DeDRM_plugin/ignoblekeyNookStudy.py @@ -157,7 +157,7 @@ def getNookLogFiles(): logpath = path +'\\Barnes & Noble\\NOOKstudy\\logs\\BNClientLog.txt' if os.path.isfile(logpath): found = True - print('Found nookStudy log file: ' + logpath.encode('ascii','ignore')) + print('Found nookStudy log file: ' + logpath.encode('ascii','ignore'), file=sys.stderr) logFiles.append(logpath) else: home = os.getenv('HOME') @@ -165,26 +165,26 @@ def getNookLogFiles(): testpath = home + '/Library/Application Support/Barnes & Noble/DesktopReader/logs/BNClientLog.txt' if os.path.isfile(testpath): logFiles.append(testpath) - print('Found nookStudy log file: ' + testpath) + print('Found nookStudy log file: ' + testpath, file=sys.stderr) found = True testpath = home + '/Library/Application Support/Barnes & Noble/DesktopReader/indices/BNClientLog.txt' if os.path.isfile(testpath): logFiles.append(testpath) - print('Found nookStudy log file: ' + testpath) + print('Found nookStudy log file: ' + testpath, file=sys.stderr) found = True testpath = home + '/Library/Application Support/Barnes & Noble/BNDesktopReader/logs/BNClientLog.txt' if os.path.isfile(testpath): logFiles.append(testpath) - print('Found nookStudy log file: ' + testpath) + print('Found nookStudy log file: ' + testpath, file=sys.stderr) found = True testpath = home + '/Library/Application Support/Barnes & Noble/BNDesktopReader/indices/BNClientLog.txt' if os.path.isfile(testpath): logFiles.append(testpath) - print('Found nookStudy log file: ' + testpath) + print('Found nookStudy log file: ' + testpath, file=sys.stderr) found = True if not found: - print('No nook Study log files have been found.') + print('No nook Study log files have been found.', file=sys.stderr) return logFiles @@ -205,7 +205,7 @@ def nookkeys(files = []): for file in files: fileKeys = getKeysFromLog(file) if fileKeys: - print("Found {0} keys in the Nook Study log files".format(len(fileKeys))) + print("Found {0} keys in the Nook Study log files".format(len(fileKeys)), file=sys.stderr) keys.extend(fileKeys) return list(set(keys)) @@ -218,7 +218,7 @@ def getkey(outpath, files=[]): outfile = outpath with open(outfile, 'w') as keyfileout: keyfileout.write(keys[-1]) - print("Saved a key to {0}".format(outfile)) + print("Saved a key to {0}".format(outfile), file=sys.stderr) else: keycount = 0 for key in keys: @@ -229,7 +229,7 @@ def getkey(outpath, files=[]): break with open(outfile, 'w') as keyfileout: keyfileout.write(key) - print("Saved a key to {0}".format(outfile)) + print("Saved a key to {0}".format(outfile), file=sys.stderr) return True return False diff --git a/DeDRM_plugin/standalone/__init__.py b/DeDRM_plugin/standalone/__init__.py index dbf0cab..fe74bb3 100644 --- a/DeDRM_plugin/standalone/__init__.py +++ b/DeDRM_plugin/standalone/__init__.py @@ -8,14 +8,16 @@ from __future__ import absolute_import, print_function # Copyright © 2021 NoDRM OPT_SHORT_TO_LONG = [ - ["h", "help"], - ["t", "test"], - ["v", "verbose"], - ["q", "quiet"], - ["u", "username"], - ["p", "password"], + ["c", "config"], ["d", "dest"], - ["f", "force"] + ["e", "extract"], + ["f", "force"], + ["h", "help"], + ["p", "password"], + ["q", "quiet"], + ["t", "test"], + ["u", "username"], + ["v", "verbose"], ] #@@CALIBRE_COMPAT_CODE@@ @@ -32,6 +34,29 @@ _additional_data = [] _additional_params = [] _function = None +def print_fname(f, info): + print(" " + f.ljust(15) + " " + info) + +def print_opt(short, long, info): + if short is None: + short = " " + else: + short = " -" + short + + if long is None: + long = " " + else: + long = "--" + long.ljust(16) + + print(short + " " + long + " " + info, file=sys.stderr) + +def print_std_usage(name, param_string): + print("Usage: ", file=sys.stderr) + if "calibre" in sys.modules: + print(" calibre-debug -r \"DeDRM\" -- "+name+" " + param_string, file=sys.stderr) + else: + print(" python3 DeDRM_plugin.zip "+name+" "+param_string, file=sys.stderr) + def print_err_header(): from __init__ import PLUGIN_NAME, PLUGIN_VERSION # type: ignore @@ -51,7 +76,11 @@ def print_help(): print("This plugin can either be imported into Calibre, or be executed directly") print("through Python like you are doing right now.") print() - print("TODO: Parameters here ...") + print("Available functions:") + print_fname("passhash", "Manage Adobe PassHashes") + print() + + # TODO: All parameters that are global should be listed here. def print_credits(): from __init__ import PLUGIN_NAME, PLUGIN_VERSION @@ -77,31 +106,23 @@ def handle_single_argument(arg, next): used_up = 0 global _additional_params - if arg == "--help": - print_help() - sys.exit(0) - - elif arg == "--credits": - print_credits() - sys.exit(0) - - elif arg in ["--username", "--password"]: + if arg in ["--username", "--password"]: used_up = 1 _additional_params.append(arg) if next is None: print_err_header() - print("Missing parameter for argument " + arg) + print("Missing parameter for argument " + arg, file=sys.stderr) sys.exit(1) else: _additional_params.append(next[0]) - elif arg in ["--verbose", "--quiet"]: + elif arg in ["--help", "--credits", "--verbose", "--quiet", "--extract"]: _additional_params.append(arg) else: print_err_header() - print("Unknown argument: " + arg) + print("Unknown argument: " + arg, file=sys.stderr) sys.exit(1) @@ -120,9 +141,14 @@ def handle_data(data): _additional_data.append(str(data)) def execute_action(action, filenames, params): - print("Executing '{0}' on file(s) {1} with parameters {2}".format(action, str(filenames), str(params))) + print("Executing '{0}' on file(s) {1} with parameters {2}".format(action, str(filenames), str(params)), file=sys.stderr) - print("ERROR: This feature is still in development. Right now it can't be used yet.") + if action == "passhash": + from standalone.passhash import perform_action + perform_action(params, filenames) + + else: + print("ERROR: This feature is still in development. Right now it can't be used yet.", file=sys.stderr) def main(argv): @@ -194,9 +220,17 @@ def main(argv): handle_data(arg) + if _function is None and "--credits" in _additional_params: + print_credits() + sys.exit(0) + + if _function is None and "--help" in _additional_params: + print_help() + sys.exit(0) + if _function is None: print_help() - return(1) + sys.exit(1) # Okay, now actually begin doing stuff. # This function gets told what to do and gets additional data (filenames). diff --git a/DeDRM_plugin/standalone/passhash.py b/DeDRM_plugin/standalone/passhash.py new file mode 100644 index 0000000..215f283 --- /dev/null +++ b/DeDRM_plugin/standalone/passhash.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# CLI interface for the DeDRM plugin (useable without Calibre, too) +# Adobe PassHash implementation + +from __future__ import absolute_import, print_function + +# Copyright © 2021 NoDRM + +#@@CALIBRE_COMPAT_CODE@@ + +import os, sys + +from standalone.__init__ import print_opt, print_std_usage + +iswindows = sys.platform.startswith('win') +isosx = sys.platform.startswith('darwin') + +def print_passhash_help(): + from __init__ import PLUGIN_NAME, PLUGIN_VERSION + print(PLUGIN_NAME + " v" + PLUGIN_VERSION + " - Calibre DRM removal plugin by noDRM") + print() + print("passhash: Manage Adobe PassHashes") + print() + print_std_usage("passhash", "[ -u username -p password | -e ]") + + print() + print("Options: ") + print_opt("u", "username", "Generate a PassHash with the given username") + print_opt("p", "password", "Generate a PassHash with the given username") + print_opt("e", "extract", "Extract PassHashes found on this machine") + +def perform_action(params, files): + user = None + pwd = None + + if len(params) == 0: + print_passhash_help() + return 0 + + extract = False + + while len(params) > 0: + p = params.pop(0) + if p == "--username": + user = params.pop(0) + elif p == "--password": + pwd = params.pop(0) + elif p == "--extract": + extract = True + elif p == "--help": + print_passhash_help() + return 0 + + if not extract: + if user is None: + print("Missing parameter: --username", file=sys.stderr) + if pwd is None: + print("Missing parameter: --password", file=sys.stderr) + if user is None or pwd is None: + return 1 + + if user is not None and pwd is not None: + from ignoblekeyGenPassHash import generate_key + key = generate_key(user, pwd) + print(key.decode("utf-8")) + + if extract: + if not iswindows and not isosx: + print("Extracting PassHash keys not supported on Linux.", file=sys.stderr) + return 1 + + keys = [] + + from ignoblekeyNookStudy import nookkeys + keys.extend(nookkeys()) + + if iswindows: + from ignoblekeyWindowsStore import dump_keys + keys.extend(dump_keys()) + + from adobekey_get_passhash import passhash_keys + ade_keys, ade_names = passhash_keys() + keys.extend(ade_keys) + + # Trim duplicates + newkeys = [] + for k in keys: + if not k in newkeys: + newkeys.append(k) + + # Print all found keys + for k in newkeys: + print(k) + + + return 0 + + +if __name__ == "__main__": + print("This code is not intended to be executed directly!") \ No newline at end of file