mirror of
https://github.com/Leseratte10/acsm-calibre-plugin.git
synced 2024-12-22 17:29:56 +06:00
Begin work on Python2 support
This commit is contained in:
parent
cec56cb9a2
commit
6d72506fad
12
.github/workflows/main.yml
vendored
12
.github/workflows/main.yml
vendored
@ -34,8 +34,16 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
# Require cryptography >= 3.1 because in 3.0 and below, the backend param in load_key_and_certificates was still required.
|
# Require cryptography >= 3.1 because in 3.0 and below, the backend param in load_key_and_certificates was still required.
|
||||||
pip3 install freezegun lxml pycryptodome rsa oscrypto "cryptography>=3.1"
|
pip3 install freezegun lxml pycryptodome rsa oscrypto "cryptography>=3.1"
|
||||||
|
# Install Python2 stuff
|
||||||
|
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
|
||||||
|
python2 get-pip.py
|
||||||
|
pip2 install freezegun mock lxml pycryptodome "rsa<=4.3" oscrypto cryptography==3.1
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests (Python 3)
|
||||||
run: |
|
run: |
|
||||||
cd tests && ./main.py
|
cd tests && python3 ./main.py && cd ..
|
||||||
|
|
||||||
|
- name: Run tests (Python 2)
|
||||||
|
run: |
|
||||||
|
cd tests && PYTHONWARNINGS=ignore python2 ./main.py && cd ..
|
||||||
|
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
[ ! -f calibre-plugin/asn1crypto.zip ] && ./package_modules.sh
|
[ ! -f calibre-plugin/asn1crypto.zip ] && ./package_modules.sh
|
||||||
[ ! -f calibre-plugin/oscrypto.zip ] && ./package_modules.sh
|
[ ! -f calibre-plugin/oscrypto.zip ] && ./package_modules.sh
|
||||||
|
|
||||||
pushd calibre-plugin
|
rm -rf calibre-plugin-tmp || /bin/true
|
||||||
|
|
||||||
|
cp -r calibre-plugin calibre-plugin-tmp
|
||||||
|
|
||||||
|
pushd calibre-plugin-tmp
|
||||||
pushd keyextract
|
pushd keyextract
|
||||||
|
|
||||||
# Compile C programs:
|
# Compile C programs:
|
||||||
@ -21,8 +25,24 @@ echo -n "2021-12-19-03" > module_id.txt
|
|||||||
cp ../LICENSE LICENSE
|
cp ../LICENSE LICENSE
|
||||||
cp ../README.md README.md
|
cp ../README.md README.md
|
||||||
|
|
||||||
|
shopt -s globstar
|
||||||
|
echo "Injecting Python2 compat code ..."
|
||||||
|
for file in **/*.py;
|
||||||
|
do
|
||||||
|
#echo $file
|
||||||
|
# Inject Python2 compat code:
|
||||||
|
sed '/#@@CALIBRE_COMPAT_CODE@@/ {
|
||||||
|
r __calibre_compat_code.py
|
||||||
|
d
|
||||||
|
}' -i $file
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create ZIP file from calibre-plugin folder.
|
# Create ZIP file from calibre-plugin folder.
|
||||||
zip -r ../calibre-plugin.zip *
|
zip -r ../calibre-plugin.zip *
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
rm -rf calibre-plugin-tmp
|
||||||
|
|
||||||
|
21
calibre-plugin/__calibre_compat_code.py
Normal file
21
calibre-plugin/__calibre_compat_code.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE_START@@
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
# Compatibility code taken from noDRM's DeDRM fork.
|
||||||
|
# This fixes the weird import issues with Calibre 2,
|
||||||
|
# and it allows me to get rid of a ton of try-except blocks.
|
||||||
|
|
||||||
|
if "calibre" in sys.modules:
|
||||||
|
|
||||||
|
# Explicitly allow importing everything ...
|
||||||
|
if os.path.dirname(os.path.abspath(__file__)) not in sys.path:
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
# Bugfix for Calibre < 5:
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
from calibre.utils.config import config_dir
|
||||||
|
if os.path.join(config_dir, "plugins", "DeACSM.zip") not in sys.path:
|
||||||
|
sys.path.insert(0, os.path.join(config_dir, "plugins", "DeACSM.zip"))
|
||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE_END@@
|
@ -54,13 +54,15 @@ import os, shutil, traceback, sys, time, io, random
|
|||||||
import zipfile
|
import zipfile
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
|
|
||||||
class DeACSM(FileTypePlugin):
|
class DeACSM(FileTypePlugin):
|
||||||
name = PLUGIN_NAME
|
name = PLUGIN_NAME
|
||||||
description = "ACSM Input Plugin - Takes an Adobe ACSM file and converts that into a useable EPUB or PDF file. Python reimplementation of libgourou by Grégory Soutadé"
|
description = "ACSM Input Plugin - Takes an Adobe ACSM file and converts that into a useable EPUB or PDF file. Python reimplementation of libgourou by Grégory Soutadé"
|
||||||
supported_platforms = ['linux', 'osx', 'windows']
|
supported_platforms = ['linux', 'osx', 'windows']
|
||||||
author = "Leseratte10"
|
author = "Leseratte10"
|
||||||
version = PLUGIN_VERSION_TUPLE
|
version = PLUGIN_VERSION_TUPLE
|
||||||
minimum_calibre_version = (5, 0, 0)
|
minimum_calibre_version = (4, 0, 0)
|
||||||
file_types = set(['acsm'])
|
file_types = set(['acsm'])
|
||||||
on_import = True
|
on_import = True
|
||||||
on_preprocess = True
|
on_preprocess = True
|
||||||
@ -184,21 +186,9 @@ class DeACSM(FileTypePlugin):
|
|||||||
|
|
||||||
# Okay, now all the modules are available, import the Adobe modules.
|
# Okay, now all the modules are available, import the Adobe modules.
|
||||||
|
|
||||||
# Account:
|
from libadobe import createDeviceKeyFile, update_account_path, sendHTTPRequest
|
||||||
try:
|
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
||||||
from calibre_plugins.deacsm.libadobe import createDeviceKeyFile, update_account_path
|
from libadobeFulfill import buildRights, fulfill
|
||||||
from calibre_plugins.deacsm.libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
|
||||||
except:
|
|
||||||
from libadobe import createDeviceKeyFile, update_account_path
|
|
||||||
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
|
||||||
|
|
||||||
# Fulfill:
|
|
||||||
try:
|
|
||||||
from calibre_plugins.deacsm.libadobe import sendHTTPRequest
|
|
||||||
from calibre_plugins.deacsm.libadobeFulfill import buildRights, fulfill
|
|
||||||
except:
|
|
||||||
from libadobe import sendHTTPRequest
|
|
||||||
from libadobeFulfill import buildRights, fulfill
|
|
||||||
|
|
||||||
|
|
||||||
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
||||||
@ -245,20 +235,13 @@ class DeACSM(FileTypePlugin):
|
|||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def download(self, replyData: str):
|
def download(self, replyData):
|
||||||
|
# type: (str) -> str
|
||||||
|
|
||||||
|
|
||||||
try:
|
from libadobe import sendHTTPRequest_DL2FILE
|
||||||
from calibre_plugins.deacsm.libadobe import sendHTTPRequest_DL2FILE
|
from libadobeFulfill import buildRights, fulfill
|
||||||
from calibre_plugins.deacsm.libadobeFulfill import buildRights, fulfill
|
from libpdf import patch_drm_into_pdf
|
||||||
except:
|
|
||||||
from libadobe import sendHTTPRequest_DL2FILE
|
|
||||||
from libadobeFulfill import buildRights, fulfill
|
|
||||||
|
|
||||||
try:
|
|
||||||
from calibre_plugins.deacsm.libpdf import patch_drm_into_pdf
|
|
||||||
except:
|
|
||||||
from libpdf import patch_drm_into_pdf
|
|
||||||
|
|
||||||
|
|
||||||
adobe_fulfill_response = etree.fromstring(replyData)
|
adobe_fulfill_response = etree.fromstring(replyData)
|
||||||
@ -344,7 +327,9 @@ class DeACSM(FileTypePlugin):
|
|||||||
print("{0} v{1}: Error: Unsupported file type ...".format(PLUGIN_NAME, PLUGIN_VERSION))
|
print("{0} v{1}: Error: Unsupported file type ...".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def run(self, path_to_ebook: str):
|
def run(self, path_to_ebook):
|
||||||
|
# type: (str) -> str
|
||||||
|
|
||||||
# This code gets called by Calibre with a path to the new book file.
|
# This code gets called by Calibre with a path to the new book file.
|
||||||
# We need to check if it's an ACSM file
|
# We need to check if it's an ACSM file
|
||||||
|
|
||||||
@ -363,12 +348,9 @@ class DeACSM(FileTypePlugin):
|
|||||||
print("{0} v{1}: ADE auth is missing or broken ".format(PLUGIN_NAME, PLUGIN_VERSION))
|
print("{0} v{1}: ADE auth is missing or broken ".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
return path_to_ebook
|
return path_to_ebook
|
||||||
|
|
||||||
try:
|
|
||||||
from calibre_plugins.deacsm.libadobe import are_ade_version_lists_valid
|
from libadobe import are_ade_version_lists_valid
|
||||||
from calibre_plugins.deacsm.libadobeFulfill import fulfill
|
from libadobeFulfill import fulfill
|
||||||
except:
|
|
||||||
from libadobe import are_ade_version_lists_valid
|
|
||||||
from libadobeFulfill import fulfill
|
|
||||||
|
|
||||||
if not are_ade_version_lists_valid():
|
if not are_ade_version_lists_valid():
|
||||||
print("{0} v{1}: ADE version list mismatch, please open a bug report.".format(PLUGIN_NAME, PLUGIN_VERSION))
|
print("{0} v{1}: ADE version list mismatch, please open a bug report.".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
|
@ -32,6 +32,13 @@ from calibre.utils.config import config_dir # type: ignore
|
|||||||
from calibre.constants import isosx, iswindows, islinux # type: ignore
|
from calibre.constants import isosx, iswindows, islinux # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
|
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
class FileNotFoundError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ConfigWidget(QWidget):
|
class ConfigWidget(QWidget):
|
||||||
def __init__(self, plugin_path):
|
def __init__(self, plugin_path):
|
||||||
QWidget.__init__(self)
|
QWidget.__init__(self)
|
||||||
@ -171,15 +178,11 @@ class ConfigWidget(QWidget):
|
|||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobe import createDeviceKeyFile, update_account_path, are_ade_version_lists_valid
|
from libadobe import createDeviceKeyFile, update_account_path, are_ade_version_lists_valid
|
||||||
from calibre_plugins.deacsm.libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobe import createDeviceKeyFile, update_account_path, are_ade_version_lists_valid
|
traceback.print_exc()
|
||||||
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
|
|
||||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||||
@ -242,15 +245,11 @@ class ConfigWidget(QWidget):
|
|||||||
# So just open up a folder picker dialog and have the user select the eReader's root folder.
|
# So just open up a folder picker dialog and have the user select the eReader's root folder.
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobe import update_account_path, VAR_VER_HOBBES_VERSIONS
|
from libadobe import update_account_path, VAR_VER_HOBBES_VERSIONS
|
||||||
from calibre_plugins.deacsm.libadobeAccount import activateDevice, exportProxyAuth
|
from libadobeAccount import activateDevice, exportProxyAuth
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobe import update_account_path, VAR_VER_HOBBES_VERSIONS
|
traceback.print_exc()
|
||||||
from libadobeAccount import activateDevice, exportProxyAuth
|
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
|
|
||||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||||
@ -402,7 +401,7 @@ class ConfigWidget(QWidget):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
containerdev = etree.parse(device_xml_path)
|
containerdev = etree.parse(device_xml_path)
|
||||||
except (FileNotFoundError, OSError) as e:
|
except (IOError, FileNotFoundError, OSError) as e:
|
||||||
return error_dialog(None, "Failed", "Error while reading device.xml", show=True, show_copy_button=False)
|
return error_dialog(None, "Failed", "Error while reading device.xml", show=True, show_copy_button=False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -509,14 +508,12 @@ class ConfigWidget(QWidget):
|
|||||||
|
|
||||||
def get_account_info(self):
|
def get_account_info(self):
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS
|
from libadobe import VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobe import VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS
|
traceback.print_exc()
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
activation_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "activation.xml")
|
activation_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "activation.xml")
|
||||||
device_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "device.xml")
|
device_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "device.xml")
|
||||||
@ -525,7 +522,7 @@ class ConfigWidget(QWidget):
|
|||||||
try:
|
try:
|
||||||
container = etree.parse(activation_xml_path)
|
container = etree.parse(activation_xml_path)
|
||||||
containerdev = etree.parse(device_xml_path)
|
containerdev = etree.parse(device_xml_path)
|
||||||
except (FileNotFoundError, OSError) as e:
|
except (IOError, FileNotFoundError, OSError) as e:
|
||||||
return "Not authorized for any ADE ID", False, None
|
return "Not authorized for any ADE ID", False, None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -579,16 +576,12 @@ class ConfigWidget(QWidget):
|
|||||||
def export_activation(self):
|
def export_activation(self):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobe import update_account_path
|
from libadobe import update_account_path
|
||||||
from calibre_plugins.deacsm.libadobeAccount import getAccountUUID
|
from libadobeAccount import getAccountUUID
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobe import update_account_path
|
traceback.print_exc()
|
||||||
from libadobeAccount import getAccountUUID
|
return False
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||||
@ -678,7 +671,7 @@ class ConfigWidget(QWidget):
|
|||||||
return error_dialog(None, "Import failed", "The WINEPREFIX you entered doesn't seem to contain an authorized ADE.", show=True, show_copy_button=False)
|
return error_dialog(None, "Import failed", "The WINEPREFIX you entered doesn't seem to contain an authorized ADE.", show=True, show_copy_button=False)
|
||||||
|
|
||||||
|
|
||||||
from calibre_plugins.deacsm.libadobeImportAccount import importADEactivationLinuxWine
|
from libadobeImportAccount import importADEactivationLinuxWine
|
||||||
|
|
||||||
ret, msg = importADEactivationLinuxWine(text)
|
ret, msg = importADEactivationLinuxWine(text)
|
||||||
|
|
||||||
@ -715,7 +708,7 @@ class ConfigWidget(QWidget):
|
|||||||
def import_activation_from_Win(self):
|
def import_activation_from_Win(self):
|
||||||
# This will try to import the activation from Adobe Digital Editions on Windows ...
|
# This will try to import the activation from Adobe Digital Editions on Windows ...
|
||||||
|
|
||||||
from calibre_plugins.deacsm.libadobeImportAccount import importADEactivationWindows
|
from libadobeImportAccount import importADEactivationWindows
|
||||||
|
|
||||||
ret, msg = importADEactivationWindows()
|
ret, msg = importADEactivationWindows()
|
||||||
|
|
||||||
@ -757,7 +750,7 @@ class ConfigWidget(QWidget):
|
|||||||
|
|
||||||
info_dialog(None, "Importing from ADE", msg, show=True, show_copy_button=False)
|
info_dialog(None, "Importing from ADE", msg, show=True, show_copy_button=False)
|
||||||
|
|
||||||
from calibre_plugins.deacsm.libadobeImportAccount import importADEactivationMac
|
from libadobeImportAccount import importADEactivationMac
|
||||||
|
|
||||||
ret, msg = importADEactivationMac()
|
ret, msg = importADEactivationMac()
|
||||||
|
|
||||||
@ -862,24 +855,19 @@ class ConfigWidget(QWidget):
|
|||||||
|
|
||||||
def switch_ade_version(self):
|
def switch_ade_version(self):
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_HOBBES_VERSIONS, VAR_VER_SUPP_CONFIG_NAMES
|
from libadobe import VAR_VER_HOBBES_VERSIONS, VAR_VER_SUPP_CONFIG_NAMES
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_BUILD_IDS, VAR_VER_ALLOWED_BUILD_IDS_SWITCH_TO
|
from libadobe import VAR_VER_BUILD_IDS, VAR_VER_ALLOWED_BUILD_IDS_SWITCH_TO
|
||||||
from calibre_plugins.deacsm.libadobeAccount import changeDeviceVersion
|
from libadobeAccount import changeDeviceVersion
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobe import VAR_VER_HOBBES_VERSIONS, VAR_VER_SUPP_CONFIG_NAMES
|
traceback.print_exc()
|
||||||
from libadobe import VAR_VER_BUILD_IDS, VAR_VER_ALLOWED_BUILD_IDS_SWITCH_TO
|
|
||||||
from libadobeAccount import changeDeviceVersion
|
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
|
|
||||||
device_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "device.xml")
|
device_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "device.xml")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
containerdev = etree.parse(device_xml_path)
|
containerdev = etree.parse(device_xml_path)
|
||||||
except (FileNotFoundError, OSError) as e:
|
except (IOError, FileNotFoundError, OSError) as e:
|
||||||
return error_dialog(None, "Failed", "Error while reading file", show=True, show_copy_button=False)
|
return error_dialog(None, "Failed", "Error while reading file", show=True, show_copy_button=False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -961,18 +949,14 @@ class ConfigWidget(QWidget):
|
|||||||
|
|
||||||
|
|
||||||
def create_anon_auth(self):
|
def create_anon_auth(self):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobe import createDeviceKeyFile, update_account_path, VAR_VER_SUPP_CONFIG_NAMES
|
from libadobe import createDeviceKeyFile, update_account_path, VAR_VER_SUPP_CONFIG_NAMES
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE, VAR_VER_BUILD_IDS, VAR_VER_DEFAULT_BUILD_ID
|
from libadobe import VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE, VAR_VER_BUILD_IDS, VAR_VER_DEFAULT_BUILD_ID
|
||||||
from calibre_plugins.deacsm.libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobe import createDeviceKeyFile, update_account_path, VAR_VER_SUPP_CONFIG_NAMES
|
traceback.print_exc()
|
||||||
from libadobe import VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE, VAR_VER_BUILD_IDS, VAR_VER_DEFAULT_BUILD_ID
|
|
||||||
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
|
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||||
|
|
||||||
@ -1059,15 +1043,11 @@ class ConfigWidget(QWidget):
|
|||||||
|
|
||||||
def convert_anon_to_account(self):
|
def convert_anon_to_account(self):
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobe import createDeviceKeyFile, update_account_path
|
from libadobe import createDeviceKeyFile, update_account_path
|
||||||
from calibre_plugins.deacsm.libadobeAccount import convertAnonAuthToAccount
|
from libadobeAccount import convertAnonAuthToAccount
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobe import createDeviceKeyFile, update_account_path
|
traceback.print_exc()
|
||||||
from libadobeAccount import convertAnonAuthToAccount
|
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||||
|
|
||||||
@ -1128,17 +1108,12 @@ class ConfigWidget(QWidget):
|
|||||||
def link_account(self):
|
def link_account(self):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobe import createDeviceKeyFile, update_account_path, VAR_VER_SUPP_CONFIG_NAMES
|
from libadobe import createDeviceKeyFile, update_account_path, VAR_VER_SUPP_CONFIG_NAMES
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE, VAR_VER_BUILD_IDS, VAR_VER_DEFAULT_BUILD_ID
|
from libadobe import VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE, VAR_VER_BUILD_IDS, VAR_VER_DEFAULT_BUILD_ID
|
||||||
from calibre_plugins.deacsm.libadobeAccount import createDeviceFile, getAuthMethodsAndCert, createUser, signIn, activateDevice
|
from libadobeAccount import createDeviceFile, getAuthMethodsAndCert, createUser, signIn, activateDevice
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobe import createDeviceKeyFile, update_account_path, VAR_VER_SUPP_CONFIG_NAMES
|
traceback.print_exc()
|
||||||
from libadobe import VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE, VAR_VER_BUILD_IDS, VAR_VER_DEFAULT_BUILD_ID
|
|
||||||
from libadobeAccount import createDeviceFile, getAuthMethodsAndCert, createUser, signIn, activateDevice
|
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||||
|
|
||||||
@ -1247,15 +1222,11 @@ class ConfigWidget(QWidget):
|
|||||||
def export_key(self):
|
def export_key(self):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobe import update_account_path
|
from libadobe import update_account_path
|
||||||
from calibre_plugins.deacsm.libadobeAccount import exportAccountEncryptionKeyDER, getAccountUUID
|
from libadobeAccount import exportAccountEncryptionKeyDER, getAccountUUID
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobe import update_account_path
|
traceback.print_exc()
|
||||||
from libadobeAccount import exportAccountEncryptionKeyDER, getAccountUUID
|
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
|
|
||||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||||
@ -1421,13 +1392,10 @@ class RentedBooksDialog(QDialog):
|
|||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from calibre_plugins.deacsm.libadobeFulfill import tryReturnBook
|
from libadobeFulfill import tryReturnBook
|
||||||
except:
|
except:
|
||||||
try:
|
print("{0} v{1}: Error while importing book return stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
from libadobeFulfill import tryReturnBook
|
traceback.print_exc()
|
||||||
except:
|
|
||||||
print("{0} v{1}: Error while importing book return stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
Ret_book = None
|
Ret_book = None
|
||||||
for book in self.parent.deacsmprefs["list_of_rented_books"]:
|
for book in self.parent.deacsmprefs["list_of_rented_books"]:
|
||||||
|
@ -8,6 +8,8 @@ The original code used blinding and this one doesn't,
|
|||||||
but we don't really care about side-channel attacks ...
|
but we don't really care about side-channel attacks ...
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from Cryptodome.PublicKey import RSA
|
from Cryptodome.PublicKey import RSA
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -16,6 +18,7 @@ except ImportError:
|
|||||||
|
|
||||||
class CustomRSA:
|
class CustomRSA:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def encrypt_for_adobe_signature(signing_key, message):
|
def encrypt_for_adobe_signature(signing_key, message):
|
||||||
key = RSA.importKey(signing_key)
|
key = RSA.importKey(signing_key)
|
||||||
keylen = CustomRSA.byte_size(key.n)
|
keylen = CustomRSA.byte_size(key.n)
|
||||||
@ -23,12 +26,17 @@ class CustomRSA:
|
|||||||
payload = CustomRSA.transform_bytes2int(padded)
|
payload = CustomRSA.transform_bytes2int(padded)
|
||||||
encrypted = CustomRSA.normal_encrypt(key, payload)
|
encrypted = CustomRSA.normal_encrypt(key, payload)
|
||||||
block = CustomRSA.transform_int2bytes(encrypted, keylen)
|
block = CustomRSA.transform_int2bytes(encrypted, keylen)
|
||||||
return block
|
return bytearray(block)
|
||||||
|
|
||||||
def byte_size(number: int):
|
@staticmethod
|
||||||
|
def byte_size(number):
|
||||||
|
# type: (int) -> int
|
||||||
return (number.bit_length() + 7) // 8
|
return (number.bit_length() + 7) // 8
|
||||||
|
|
||||||
def pad_message(message: bytes, target_len: int) -> bytes:
|
@staticmethod
|
||||||
|
def pad_message(message, target_len):
|
||||||
|
# type: (bytes, int) -> bytes
|
||||||
|
|
||||||
# Padding always uses 0xFF
|
# Padding always uses 0xFF
|
||||||
# Returns: 00 01 PADDING 00 MESSAGE
|
# Returns: 00 01 PADDING 00 MESSAGE
|
||||||
|
|
||||||
@ -40,9 +48,13 @@ class CustomRSA:
|
|||||||
|
|
||||||
padding_len = target_len - message_length - 3
|
padding_len = target_len - message_length - 3
|
||||||
|
|
||||||
return b"".join([b"\x00\x01", padding_len * b"\xff", b"\x00", message])
|
ret = bytearray(b"".join([b"\x00\x01", padding_len * b"\xff", b"\x00"]))
|
||||||
|
ret.extend(bytes(message))
|
||||||
|
|
||||||
def normal_encrypt(key, message: int):
|
return ret
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def normal_encrypt(key, message):
|
||||||
|
|
||||||
if message < 0 or message > key.n:
|
if message < 0 or message > key.n:
|
||||||
raise ValueError("Invalid message")
|
raise ValueError("Invalid message")
|
||||||
@ -50,15 +62,57 @@ class CustomRSA:
|
|||||||
encrypted = pow(message, key.d, key.n)
|
encrypted = pow(message, key.d, key.n)
|
||||||
return encrypted
|
return encrypted
|
||||||
|
|
||||||
def transform_bytes2int(raw_bytes: bytes):
|
@staticmethod
|
||||||
return int.from_bytes(raw_bytes, "big", signed=False)
|
def py2_int_to_bytes(value, length, big_endian = True):
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for i in range(0, length):
|
||||||
|
result.append(value >> (i * 8) & 0xff)
|
||||||
|
|
||||||
|
if big_endian:
|
||||||
|
result.reverse()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def py2_bytes_to_int(bytes, big_endian = True):
|
||||||
|
# type: (bytes, bool) -> int
|
||||||
|
|
||||||
|
my_bytes = bytes
|
||||||
|
if not big_endian:
|
||||||
|
my_bytes.reverse()
|
||||||
|
|
||||||
|
result = 0
|
||||||
|
for b in my_bytes:
|
||||||
|
result = result * 256 + int(b)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def transform_bytes2int(raw_bytes):
|
||||||
|
# type: (bytes) -> int
|
||||||
|
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
return int.from_bytes(raw_bytes, "big", signed=False)
|
||||||
|
|
||||||
|
return CustomRSA.py2_bytes_to_int(raw_bytes, True)
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def transform_int2bytes(number, fill_size = 0):
|
||||||
|
# type: (int, int) -> bytes
|
||||||
|
|
||||||
def transform_int2bytes(number: int, fill_size: int = 0):
|
|
||||||
if number < 0:
|
if number < 0:
|
||||||
raise ValueError("Negative number")
|
raise ValueError("Negative number")
|
||||||
|
|
||||||
|
size = None
|
||||||
|
|
||||||
if fill_size > 0:
|
if fill_size > 0:
|
||||||
return number.to_bytes(fill_size, "big")
|
size = fill_size
|
||||||
|
else:
|
||||||
|
size = max(1, CustomRSA.byte_size(number))
|
||||||
|
|
||||||
bytes_needed = max(1, CustomRSA.byte_size(number))
|
if sys.version_info[0] >= 3:
|
||||||
return number.to_bytes(bytes_needed, "big")
|
return number.to_bytes(size, "big")
|
||||||
|
|
||||||
|
return CustomRSA.py2_int_to_bytes(number, size, True)
|
@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
|
|
||||||
from re import VERBOSE
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def unfuck(user):
|
def unfuck(user):
|
||||||
# Wine uses a pretty nonstandard encoding in their registry file.
|
# Wine uses a pretty nonstandard encoding in their registry file.
|
||||||
@ -22,10 +22,16 @@ def unfuck(user):
|
|||||||
while i < len(user):
|
while i < len(user):
|
||||||
# Convert string of len 1 to a byte
|
# Convert string of len 1 to a byte
|
||||||
char = user[i][0].encode("latin-1")[0]
|
char = user[i][0].encode("latin-1")[0]
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
char = ord(char)
|
||||||
|
|
||||||
if char == ord('\\'):
|
if char == ord('\\'):
|
||||||
# Get next char:
|
# Get next char:
|
||||||
i += 1
|
i += 1
|
||||||
char = user[i][0].encode("latin-1")[0]
|
char = user[i][0].encode("latin-1")[0]
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
char = ord(char)
|
||||||
|
|
||||||
if (char == ord('a')):
|
if (char == ord('a')):
|
||||||
user_new.append(0x07)
|
user_new.append(0x07)
|
||||||
elif (char == ord('b')):
|
elif (char == ord('b')):
|
||||||
@ -46,6 +52,8 @@ def unfuck(user):
|
|||||||
# Get next char
|
# Get next char
|
||||||
i += 1
|
i += 1
|
||||||
char = user[i][0].encode("latin-1")[0]
|
char = user[i][0].encode("latin-1")[0]
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
char = ord(char)
|
||||||
if char not in hex_char_list:
|
if char not in hex_char_list:
|
||||||
user_new.append(ord('x'))
|
user_new.append(ord('x'))
|
||||||
# This seems to be fallback code.
|
# This seems to be fallback code.
|
||||||
@ -57,16 +65,25 @@ def unfuck(user):
|
|||||||
|
|
||||||
# Read up to 3 more chars
|
# Read up to 3 more chars
|
||||||
next = user[i + 1][0].encode("latin-1")[0]
|
next = user[i + 1][0].encode("latin-1")[0]
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
next = ord(next)
|
||||||
|
|
||||||
if next in hex_char_list:
|
if next in hex_char_list:
|
||||||
ival += chr(next)
|
ival += chr(next)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
next = user[i + 1][0].encode("latin-1")[0]
|
next = user[i + 1][0].encode("latin-1")[0]
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
next = ord(next)
|
||||||
|
|
||||||
if next in hex_char_list:
|
if next in hex_char_list:
|
||||||
ival += chr(next)
|
ival += chr(next)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
next = user[i + 1][0].encode("latin-1")[0]
|
next = user[i + 1][0].encode("latin-1")[0]
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
next = ord(next)
|
||||||
|
|
||||||
if next in hex_char_list:
|
if next in hex_char_list:
|
||||||
ival += chr(next)
|
ival += chr(next)
|
||||||
i += 1
|
i += 1
|
||||||
@ -83,11 +100,17 @@ def unfuck(user):
|
|||||||
|
|
||||||
# Read up to 2 more chars
|
# Read up to 2 more chars
|
||||||
next = user[i + 1][0].encode("latin-1")[0]
|
next = user[i + 1][0].encode("latin-1")[0]
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
next = ord(next)
|
||||||
|
|
||||||
if next >= ord('0') and next <= ord('9'):
|
if next >= ord('0') and next <= ord('9'):
|
||||||
octal = (octal * 8) + (next - ord('0'))
|
octal = (octal * 8) + (next - ord('0'))
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
next = user[i + 1][0].encode("latin-1")[0]
|
next = user[i + 1][0].encode("latin-1")[0]
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
next = ord(next)
|
||||||
|
|
||||||
if next >= ord('0') and next <= ord('9'):
|
if next >= ord('0') and next <= ord('9'):
|
||||||
octal = (octal * 8) + (next - ord('0'))
|
octal = (octal * 8) + (next - ord('0'))
|
||||||
i += 1
|
i += 1
|
||||||
@ -122,11 +145,8 @@ def GetMasterKey(path_to_wine_prefix):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
|
||||||
import cpuid
|
import cpuid
|
||||||
except:
|
|
||||||
import calibre_plugins.deacsm.cpuid as cpuid
|
|
||||||
|
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -17,6 +17,8 @@ except ImportError:
|
|||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
|
|
||||||
def GetSystemDirectory():
|
def GetSystemDirectory():
|
||||||
from ctypes import windll, c_wchar_p, c_uint, create_unicode_buffer
|
from ctypes import windll, c_wchar_p, c_uint, create_unicode_buffer
|
||||||
MAX_PATH = 255
|
MAX_PATH = 255
|
||||||
@ -126,11 +128,8 @@ def GetMasterKey():
|
|||||||
|
|
||||||
|
|
||||||
# Get CPU vendor:
|
# Get CPU vendor:
|
||||||
try:
|
|
||||||
import cpuid
|
|
||||||
except:
|
|
||||||
import calibre_plugins.deacsm.cpuid as cpuid
|
|
||||||
|
|
||||||
|
import cpuid
|
||||||
import struct
|
import struct
|
||||||
cpu = cpuid.CPUID()
|
cpu = cpuid.CPUID()
|
||||||
_, b, c, d = cpu(0)
|
_, b, c, d = cpu(0)
|
||||||
|
@ -6,8 +6,15 @@ Helper library with code needed for Adobe stuff.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
from uuid import getnode
|
from uuid import getnode
|
||||||
import os, hashlib, base64
|
import sys, os, hashlib, base64
|
||||||
import urllib.request, ssl
|
import ssl
|
||||||
|
try:
|
||||||
|
import urllib.request as ulib
|
||||||
|
import urllib.error as uliberror
|
||||||
|
except:
|
||||||
|
import urllib2 as ulib
|
||||||
|
import urllib2 as uliberror
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
@ -23,10 +30,11 @@ except ImportError:
|
|||||||
from Crypto.Cipher import AES
|
from Crypto.Cipher import AES
|
||||||
from Crypto.Hash import SHA
|
from Crypto.Hash import SHA
|
||||||
|
|
||||||
try:
|
|
||||||
from customRSA import CustomRSA
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
except:
|
|
||||||
from calibre_plugins.deacsm.customRSA import CustomRSA
|
|
||||||
|
from customRSA import CustomRSA
|
||||||
|
|
||||||
from oscrypto import keys
|
from oscrypto import keys
|
||||||
from oscrypto.asymmetric import dump_certificate, dump_private_key
|
from oscrypto.asymmetric import dump_certificate, dump_private_key
|
||||||
@ -115,7 +123,9 @@ def get_activation_xml_path():
|
|||||||
return FILE_ACTIVATIONXML
|
return FILE_ACTIVATIONXML
|
||||||
|
|
||||||
|
|
||||||
def update_account_path(folder_path: str):
|
def update_account_path(folder_path):
|
||||||
|
# type: (str) -> None
|
||||||
|
|
||||||
global FILE_DEVICEKEY, FILE_DEVICEXML, FILE_ACTIVATIONXML
|
global FILE_DEVICEKEY, FILE_DEVICEXML, FILE_ACTIVATIONXML
|
||||||
|
|
||||||
FILE_DEVICEKEY = os.path.join(folder_path, "devicesalt")
|
FILE_DEVICEKEY = os.path.join(folder_path, "devicesalt")
|
||||||
@ -134,17 +144,40 @@ def createDeviceKeyFile():
|
|||||||
f.write(devkey_bytes)
|
f.write(devkey_bytes)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
def int_to_bytes(value, length, big_endian = True):
|
||||||
|
# Helper function for Python2 only (big endian)
|
||||||
|
# Python3 uses int.to_bytes()
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for i in range(0, length):
|
||||||
|
result.append(value >> (i * 8) & 0xff)
|
||||||
|
|
||||||
|
if big_endian:
|
||||||
|
result.reverse()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def get_mac_address():
|
def get_mac_address():
|
||||||
mac1 = getnode()
|
mac1 = getnode()
|
||||||
mac2 = getnode()
|
mac2 = getnode()
|
||||||
if (mac1 != mac2) or ((mac1 >> 40) % 2):
|
if (mac1 != mac2) or ((mac1 >> 40) % 2):
|
||||||
return bytes([1, 2, 3, 4, 5, 0])
|
if sys.version_info[0] >= 3:
|
||||||
|
return bytes([1, 2, 3, 4, 5, 0])
|
||||||
|
else:
|
||||||
|
return bytearray([1, 2, 3, 4, 5, 0])
|
||||||
|
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
return mac1.to_bytes(6, byteorder='big')
|
||||||
|
|
||||||
|
return int_to_bytes(mac1, 6)
|
||||||
|
|
||||||
return mac1.to_bytes(6, byteorder='big')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def makeSerial(random: bool):
|
|
||||||
|
def makeSerial(random):
|
||||||
|
# type: (bool) -> str
|
||||||
|
|
||||||
# Original implementation: std::string Device::makeSerial(bool random)
|
# Original implementation: std::string Device::makeSerial(bool random)
|
||||||
|
|
||||||
# It doesn't look like this implementation results in the same fingerprint Adobe is using in ADE.
|
# It doesn't look like this implementation results in the same fingerprint Adobe is using in ADE.
|
||||||
@ -165,17 +198,26 @@ def makeSerial(random: bool):
|
|||||||
|
|
||||||
mac_address = get_mac_address()
|
mac_address = get_mac_address()
|
||||||
|
|
||||||
dataToHash = "%d:%s:%02x:%02x:%02x:%02x:%02x:%02x\x00" % (uid, username,
|
if sys.version_info[0] >= 3:
|
||||||
mac_address[0], mac_address[1], mac_address[2],
|
dataToHash = "%d:%s:%02x:%02x:%02x:%02x:%02x:%02x\x00" % (uid, username,
|
||||||
mac_address[3], mac_address[4], mac_address[5])
|
mac_address[0], mac_address[1], mac_address[2],
|
||||||
|
mac_address[3], mac_address[4], mac_address[5])
|
||||||
|
|
||||||
|
else:
|
||||||
|
dataToHash = "%d:%s:%02x:%02x:%02x:%02x:%02x:%02x\x00" % (uid, username,
|
||||||
|
mac_address[0], mac_address[1], mac_address[2],
|
||||||
|
mac_address[3], mac_address[4], mac_address[5])
|
||||||
|
|
||||||
sha_out = hashlib.sha1(dataToHash.encode('latin-1')).hexdigest().lower()
|
sha_out = hashlib.sha1(dataToHash.encode('latin-1')).hexdigest().lower()
|
||||||
else:
|
else:
|
||||||
sha_out = Random.get_random_bytes(20).hex().lower()
|
import binascii
|
||||||
|
sha_out = binascii.hexlify(Random.get_random_bytes(20)).lower()
|
||||||
|
|
||||||
return sha_out
|
return sha_out
|
||||||
|
|
||||||
def makeFingerprint(serial: str):
|
def makeFingerprint(serial):
|
||||||
|
# type: (str) -> str
|
||||||
|
|
||||||
# Original implementation: std::string Device::makeFingerprint(const std::string& serial)
|
# Original implementation: std::string Device::makeFingerprint(const std::string& serial)
|
||||||
# base64(sha1(serial + privateKey))
|
# base64(sha1(serial + privateKey))
|
||||||
# Fingerprint must be 20 bytes or less.
|
# Fingerprint must be 20 bytes or less.
|
||||||
@ -195,14 +237,16 @@ def makeFingerprint(serial: str):
|
|||||||
|
|
||||||
############################################## HTTP stuff:
|
############################################## HTTP stuff:
|
||||||
|
|
||||||
def sendHTTPRequest_DL2FILE(URL: str, outputfile: str):
|
def sendHTTPRequest_DL2FILE(URL, outputfile):
|
||||||
|
# type: (str, str) -> int
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"Accept": "*/*",
|
"Accept": "*/*",
|
||||||
"User-Agent": "book2png",
|
"User-Agent": "book2png",
|
||||||
# MacOS uses different User-Agent. Good thing we're emulating a Windows client.
|
# MacOS uses different User-Agent. Good thing we're emulating a Windows client.
|
||||||
}
|
}
|
||||||
req = urllib.request.Request(url=URL, headers=headers)
|
req = ulib.Request(url=URL, headers=headers)
|
||||||
handler = urllib.request.urlopen(req)
|
handler = ulib.urlopen(req)
|
||||||
|
|
||||||
chunksize = 16 * 1024
|
chunksize = 16 * 1024
|
||||||
|
|
||||||
@ -230,7 +274,8 @@ def sendHTTPRequest_DL2FILE(URL: str, outputfile: str):
|
|||||||
|
|
||||||
return 200
|
return 200
|
||||||
|
|
||||||
def sendHTTPRequest_getSimple(URL: str):
|
def sendHTTPRequest_getSimple(URL):
|
||||||
|
# type: (str) -> str
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"Accept": "*/*",
|
"Accept": "*/*",
|
||||||
@ -246,8 +291,8 @@ def sendHTTPRequest_getSimple(URL: str):
|
|||||||
ctx.check_hostname = False
|
ctx.check_hostname = False
|
||||||
ctx.verify_mode = ssl.CERT_NONE
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
req = urllib.request.Request(url=URL, headers=headers)
|
req = ulib.Request(url=URL, headers=headers)
|
||||||
handler = urllib.request.urlopen(req, context=ctx)
|
handler = ulib.urlopen(req, context=ctx)
|
||||||
|
|
||||||
content = handler.read()
|
content = handler.read()
|
||||||
|
|
||||||
@ -262,7 +307,8 @@ def sendHTTPRequest_getSimple(URL: str):
|
|||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
def sendPOSTHTTPRequest(URL: str, document: bytes, type: str, returnRC = False):
|
def sendPOSTHTTPRequest(URL, document, type, returnRC = False):
|
||||||
|
# type: (str, bytes, str, bool) -> str
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"Accept": "*/*",
|
"Accept": "*/*",
|
||||||
@ -279,10 +325,10 @@ def sendPOSTHTTPRequest(URL: str, document: bytes, type: str, returnRC = False):
|
|||||||
ctx.check_hostname = False
|
ctx.check_hostname = False
|
||||||
ctx.verify_mode = ssl.CERT_NONE
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
req = urllib.request.Request(url=URL, headers=headers, data=document)
|
req = ulib.Request(url=URL, headers=headers, data=document)
|
||||||
try:
|
try:
|
||||||
handler = urllib.request.urlopen(req, context=ctx)
|
handler = ulib.urlopen(req, context=ctx)
|
||||||
except urllib.error.HTTPError as err:
|
except uliberror.HTTPError as err:
|
||||||
# This happens with HTTP 500 and related errors.
|
# This happens with HTTP 500 and related errors.
|
||||||
print("Post request caused HTTPError %d" % (err.code))
|
print("Post request caused HTTPError %d" % (err.code))
|
||||||
return err.code, "Post request caused HTTPException"
|
return err.code, "Post request caused HTTPException"
|
||||||
@ -311,14 +357,17 @@ def sendPOSTHTTPRequest(URL: str, document: bytes, type: str, returnRC = False):
|
|||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
def sendHTTPRequest(URL: str):
|
def sendHTTPRequest(URL):
|
||||||
|
# type: (str) -> str
|
||||||
return sendHTTPRequest_getSimple(URL)
|
return sendHTTPRequest_getSimple(URL)
|
||||||
|
|
||||||
|
|
||||||
def sendRequestDocu(document: str, URL: str):
|
def sendRequestDocu(document, URL):
|
||||||
|
# type: (str, str) -> str
|
||||||
return sendPOSTHTTPRequest(URL, document.encode("utf-8"), "application/vnd.adobe.adept+xml", False)
|
return sendPOSTHTTPRequest(URL, document.encode("utf-8"), "application/vnd.adobe.adept+xml", False)
|
||||||
|
|
||||||
def sendRequestDocuRC(document: str, URL: str):
|
def sendRequestDocuRC(document, URL):
|
||||||
|
# type: (str, str) -> str
|
||||||
return sendPOSTHTTPRequest(URL, document.encode("utf-8"), "application/vnd.adobe.adept+xml", True)
|
return sendPOSTHTTPRequest(URL, document.encode("utf-8"), "application/vnd.adobe.adept+xml", True)
|
||||||
|
|
||||||
|
|
||||||
@ -328,6 +377,8 @@ def sendRequestDocuRC(document: str, URL: str):
|
|||||||
|
|
||||||
def encrypt_with_device_key(data):
|
def encrypt_with_device_key(data):
|
||||||
|
|
||||||
|
data = bytearray(data)
|
||||||
|
|
||||||
global devkey_bytes
|
global devkey_bytes
|
||||||
if devkey_bytes is None:
|
if devkey_bytes is None:
|
||||||
f = open(FILE_DEVICEKEY, "rb")
|
f = open(FILE_DEVICEKEY, "rb")
|
||||||
@ -338,7 +389,9 @@ def encrypt_with_device_key(data):
|
|||||||
if (len(data) % 16):
|
if (len(data) % 16):
|
||||||
remain = 16 - (len(data) % 16)
|
remain = 16 - (len(data) % 16)
|
||||||
|
|
||||||
data += bytes([remain])*remain
|
for _ in range(remain):
|
||||||
|
data.append(remain)
|
||||||
|
|
||||||
|
|
||||||
iv = Random.get_random_bytes(16)
|
iv = Random.get_random_bytes(16)
|
||||||
cip = AES.new(devkey_bytes, AES.MODE_CBC, iv)
|
cip = AES.new(devkey_bytes, AES.MODE_CBC, iv)
|
||||||
@ -348,6 +401,11 @@ def encrypt_with_device_key(data):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def decrypt_with_device_key(data):
|
def decrypt_with_device_key(data):
|
||||||
|
|
||||||
|
if isinstance(data, str):
|
||||||
|
# Python2
|
||||||
|
data = bytes(data)
|
||||||
|
|
||||||
global devkey_bytes
|
global devkey_bytes
|
||||||
if devkey_bytes is None:
|
if devkey_bytes is None:
|
||||||
f = open(FILE_DEVICEKEY, "rb")
|
f = open(FILE_DEVICEKEY, "rb")
|
||||||
@ -355,7 +413,7 @@ def decrypt_with_device_key(data):
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
cip = AES.new(devkey_bytes, AES.MODE_CBC, data[:16])
|
cip = AES.new(devkey_bytes, AES.MODE_CBC, data[:16])
|
||||||
decrypted = cip.decrypt(data[16:])
|
decrypted = bytearray(cip.decrypt(data[16:]))
|
||||||
|
|
||||||
# Remove padding
|
# Remove padding
|
||||||
decrypted = decrypted[:-decrypted[-1]]
|
decrypted = decrypted[:-decrypted[-1]]
|
||||||
@ -380,12 +438,17 @@ def addNonce():
|
|||||||
# Unixtime to gregorian timestamp
|
# Unixtime to gregorian timestamp
|
||||||
Ntime += 62167219200000
|
Ntime += 62167219200000
|
||||||
|
|
||||||
final = bytearray(Ntime.to_bytes(8, 'little'))
|
|
||||||
|
|
||||||
# Something is fishy with this tmp value. It usually is 0 in ADE, but not always.
|
# Something is fishy with this tmp value. It usually is 0 in ADE, but not always.
|
||||||
# I haven't yet figured out what it means ...
|
# I haven't yet figured out what it means ...
|
||||||
tmp = 0
|
tmp = 0
|
||||||
final.extend(tmp.to_bytes(4, 'little'))
|
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
final = bytearray(Ntime.to_bytes(8, 'little'))
|
||||||
|
final.extend(tmp.to_bytes(4, 'little'))
|
||||||
|
else:
|
||||||
|
final = bytearray(int_to_bytes(Ntime, 8, False))
|
||||||
|
final.extend(int_to_bytes(tmp, 4, True))
|
||||||
|
|
||||||
|
|
||||||
ret = ""
|
ret = ""
|
||||||
|
|
||||||
@ -552,9 +615,13 @@ def hash_node_ctx(node, hash_ctx):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def hash_do_append_string(hash_ctx, string: str):
|
def hash_do_append_string(hash_ctx, string):
|
||||||
|
# type: (SHA.SHA1Hash, str) -> None
|
||||||
|
|
||||||
str_bytes = bytes(string, encoding="utf-8")
|
if sys.version_info[0] >= 3:
|
||||||
|
str_bytes = bytes(string, encoding="utf-8")
|
||||||
|
else:
|
||||||
|
str_bytes = bytes(string)
|
||||||
|
|
||||||
length = len(str_bytes)
|
length = len(str_bytes)
|
||||||
len_upper = int(length / 256)
|
len_upper = int(length / 256)
|
||||||
@ -563,12 +630,14 @@ def hash_do_append_string(hash_ctx, string: str):
|
|||||||
hash_do_append_raw_bytes(hash_ctx, [len_upper, len_lower])
|
hash_do_append_raw_bytes(hash_ctx, [len_upper, len_lower])
|
||||||
hash_do_append_raw_bytes(hash_ctx, str_bytes)
|
hash_do_append_raw_bytes(hash_ctx, str_bytes)
|
||||||
|
|
||||||
def hash_do_append_tag(hash_ctx, tag: int):
|
def hash_do_append_tag(hash_ctx, tag):
|
||||||
|
# type: (SHA.SHA1Hash, int) -> None
|
||||||
|
|
||||||
if (tag > 5):
|
if (tag > 5):
|
||||||
return
|
return
|
||||||
|
|
||||||
hash_do_append_raw_bytes(hash_ctx, [tag])
|
hash_do_append_raw_bytes(hash_ctx, [tag])
|
||||||
|
|
||||||
def hash_do_append_raw_bytes(hash_ctx, data: bytes):
|
def hash_do_append_raw_bytes(hash_ctx, data):
|
||||||
|
# type: (SHA.SHA1Hash, bytes) -> None
|
||||||
hash_ctx.update(bytearray(data))
|
hash_ctx.update(bytearray(data))
|
||||||
|
@ -12,25 +12,20 @@ except ImportError:
|
|||||||
from Crypto.Util.asn1 import DerSequence
|
from Crypto.Util.asn1 import DerSequence
|
||||||
from Crypto.Cipher import PKCS1_v1_5
|
from Crypto.Cipher import PKCS1_v1_5
|
||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
try:
|
|
||||||
from libadobe import addNonce, sign_node, sendRequestDocu, sendHTTPRequest
|
|
||||||
from libadobe import makeFingerprint, makeSerial, encrypt_with_device_key, decrypt_with_device_key
|
|
||||||
from libadobe import get_devkey_path, get_device_path, get_activation_xml_path
|
|
||||||
from libadobe import VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS, VAR_VER_OS_IDENTIFIERS
|
|
||||||
from libadobe import VAR_VER_ALLOWED_BUILD_IDS_SWITCH_TO, VAR_VER_SUPP_VERSIONS, VAR_ACS_SERVER_HTTP
|
|
||||||
from libadobe import VAR_ACS_SERVER_HTTPS, VAR_VER_BUILD_IDS, VAR_VER_NEED_HTTPS_BUILD_ID_LIMIT, VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE
|
|
||||||
except:
|
|
||||||
from calibre_plugins.deacsm.libadobe import addNonce, sign_node, sendRequestDocu, sendHTTPRequest
|
|
||||||
from calibre_plugins.deacsm.libadobe import makeFingerprint, makeSerial, encrypt_with_device_key, decrypt_with_device_key
|
|
||||||
from calibre_plugins.deacsm.libadobe import get_devkey_path, get_device_path, get_activation_xml_path
|
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS, VAR_VER_OS_IDENTIFIERS
|
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_ALLOWED_BUILD_IDS_SWITCH_TO, VAR_VER_SUPP_VERSIONS, VAR_ACS_SERVER_HTTP
|
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_ACS_SERVER_HTTPS, VAR_VER_BUILD_IDS, VAR_VER_NEED_HTTPS_BUILD_ID_LIMIT, VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE
|
|
||||||
|
|
||||||
|
|
||||||
|
from libadobe import addNonce, sign_node, sendRequestDocu, sendHTTPRequest
|
||||||
|
from libadobe import makeFingerprint, makeSerial, encrypt_with_device_key, decrypt_with_device_key
|
||||||
|
from libadobe import get_devkey_path, get_device_path, get_activation_xml_path
|
||||||
|
from libadobe import VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS, VAR_VER_OS_IDENTIFIERS
|
||||||
|
from libadobe import VAR_VER_ALLOWED_BUILD_IDS_SWITCH_TO, VAR_VER_SUPP_VERSIONS, VAR_ACS_SERVER_HTTP
|
||||||
|
from libadobe import VAR_ACS_SERVER_HTTPS, VAR_VER_BUILD_IDS, VAR_VER_NEED_HTTPS_BUILD_ID_LIMIT, VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE
|
||||||
|
|
||||||
|
|
||||||
|
def createDeviceFile(randomSerial, useVersionIndex = 0):
|
||||||
|
# type: (bool, int) -> bool
|
||||||
|
|
||||||
def createDeviceFile(randomSerial: bool, useVersionIndex: int = 0):
|
|
||||||
# Original implementation: Device::createDeviceFile(const std::string& hobbes, bool randomSerial)
|
# Original implementation: Device::createDeviceFile(const std::string& hobbes, bool randomSerial)
|
||||||
|
|
||||||
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
||||||
@ -142,7 +137,7 @@ def getAuthMethodsAndCert():
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def createUser(useVersionIndex: int = 0, authCert = None):
|
def createUser(useVersionIndex = 0, authCert = None):
|
||||||
|
|
||||||
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
||||||
return False, "Invalid Version index", [[], []]
|
return False, "Invalid Version index", [[], []]
|
||||||
@ -215,12 +210,11 @@ def createUser(useVersionIndex: int = 0, authCert = None):
|
|||||||
|
|
||||||
return True, "Done"
|
return True, "Done"
|
||||||
|
|
||||||
def encryptLoginCredentials(username: str, password: str, authenticationCertificate: str):
|
def encryptLoginCredentials(username, password, authenticationCertificate):
|
||||||
|
# type: (str, str, str) -> bytes
|
||||||
|
|
||||||
try:
|
from libadobe import devkey_bytes as devkey_adobe
|
||||||
from calibre_plugins.deacsm.libadobe import devkey_bytes as devkey_adobe
|
import struct
|
||||||
except:
|
|
||||||
from libadobe import devkey_bytes as devkey_adobe
|
|
||||||
|
|
||||||
if devkey_adobe is not None:
|
if devkey_adobe is not None:
|
||||||
devkey_bytes = devkey_adobe
|
devkey_bytes = devkey_adobe
|
||||||
@ -234,9 +228,9 @@ def encryptLoginCredentials(username: str, password: str, authenticationCertific
|
|||||||
# Build buffer <devkey_bytes> <len username> <username> <len password> <password>
|
# Build buffer <devkey_bytes> <len username> <username> <len password> <password>
|
||||||
|
|
||||||
ar = bytearray(devkey_bytes)
|
ar = bytearray(devkey_bytes)
|
||||||
ar.extend(bytearray(len(username).to_bytes(1, 'big')))
|
ar.extend(bytearray(struct.pack("B", len(username))))
|
||||||
ar.extend(bytearray(username.encode("latin-1")))
|
ar.extend(bytearray(username.encode("latin-1")))
|
||||||
ar.extend(bytearray(len(password).to_bytes(1, 'big')))
|
ar.extend(bytearray(struct.pack("B", len(password))))
|
||||||
ar.extend(bytearray(password.encode("latin-1")))
|
ar.extend(bytearray(password.encode("latin-1")))
|
||||||
|
|
||||||
# Crypt code from https://stackoverflow.com/a/12921889/4991648
|
# Crypt code from https://stackoverflow.com/a/12921889/4991648
|
||||||
@ -253,7 +247,9 @@ def encryptLoginCredentials(username: str, password: str, authenticationCertific
|
|||||||
return crypted_msg
|
return crypted_msg
|
||||||
|
|
||||||
|
|
||||||
def buildSignInRequestForAnonAuthConvert(username: str, password: str, authenticationCertificate: str):
|
def buildSignInRequestForAnonAuthConvert(username, password, authenticationCertificate):
|
||||||
|
# type: (str, str, str) -> str
|
||||||
|
|
||||||
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
||||||
etree.register_namespace("adept", NSMAP["adept"])
|
etree.register_namespace("adept", NSMAP["adept"])
|
||||||
|
|
||||||
@ -283,7 +279,9 @@ def buildSignInRequestForAnonAuthConvert(username: str, password: str, authentic
|
|||||||
return "<?xml version=\"1.0\"?>\n" + etree.tostring(root, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("latin-1")
|
return "<?xml version=\"1.0\"?>\n" + etree.tostring(root, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("latin-1")
|
||||||
|
|
||||||
|
|
||||||
def buildSignInRequest(type: str, username: str, password: str, authenticationCertificate: str):
|
def buildSignInRequest(type, username, password, authenticationCertificate):
|
||||||
|
# type: (str, str, str, str) -> str
|
||||||
|
|
||||||
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
||||||
etree.register_namespace("adept", NSMAP["adept"])
|
etree.register_namespace("adept", NSMAP["adept"])
|
||||||
|
|
||||||
@ -316,7 +314,8 @@ def buildSignInRequest(type: str, username: str, password: str, authenticationCe
|
|||||||
return "<?xml version=\"1.0\"?>\n" + etree.tostring(root, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("latin-1")
|
return "<?xml version=\"1.0\"?>\n" + etree.tostring(root, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("latin-1")
|
||||||
|
|
||||||
|
|
||||||
def convertAnonAuthToAccount(username: str, passwd: str):
|
def convertAnonAuthToAccount(username, passwd):
|
||||||
|
|
||||||
# If you have an anonymous authorization, you can convert that to an AdobeID.
|
# If you have an anonymous authorization, you can convert that to an AdobeID.
|
||||||
# Important: You can only do this ONCE for each AdobeID.
|
# Important: You can only do this ONCE for each AdobeID.
|
||||||
# The AdobeID you are using for this must not be connected to any ADE install.
|
# The AdobeID you are using for this must not be connected to any ADE install.
|
||||||
@ -402,7 +401,7 @@ def convertAnonAuthToAccount(username: str, passwd: str):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def signIn(account_type: str, username: str, passwd: str):
|
def signIn(account_type, username, passwd):
|
||||||
|
|
||||||
|
|
||||||
# Get authenticationCertificate
|
# Get authenticationCertificate
|
||||||
@ -556,7 +555,7 @@ def exportProxyAuth(act_xml_path, activationToken):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def buildActivateReqProxy(useVersionIndex: int = 0, proxyData = None):
|
def buildActivateReqProxy(useVersionIndex = 0, proxyData = None):
|
||||||
|
|
||||||
if proxyData is None:
|
if proxyData is None:
|
||||||
return False
|
return False
|
||||||
@ -652,7 +651,7 @@ def buildActivateReqProxy(useVersionIndex: int = 0, proxyData = None):
|
|||||||
return True, ret
|
return True, ret
|
||||||
|
|
||||||
|
|
||||||
def buildActivateReq(useVersionIndex: int = 0):
|
def buildActivateReq(useVersionIndex = 0):
|
||||||
|
|
||||||
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
||||||
return False
|
return False
|
||||||
@ -727,7 +726,7 @@ def buildActivateReq(useVersionIndex: int = 0):
|
|||||||
|
|
||||||
|
|
||||||
# Call this function to change from ADE2 to ADE3 and vice versa.
|
# Call this function to change from ADE2 to ADE3 and vice versa.
|
||||||
def changeDeviceVersion(useVersionIndex: int = 0):
|
def changeDeviceVersion(useVersionIndex = 0):
|
||||||
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
||||||
return False, "Invalid Version index"
|
return False, "Invalid Version index"
|
||||||
|
|
||||||
@ -771,7 +770,7 @@ def changeDeviceVersion(useVersionIndex: int = 0):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def activateDevice(useVersionIndex: int = 0, proxyData = None):
|
def activateDevice(useVersionIndex = 0, proxyData = None):
|
||||||
|
|
||||||
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
||||||
return False, "Invalid Version index"
|
return False, "Invalid Version index"
|
||||||
@ -881,7 +880,8 @@ def getAccountUUID():
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def exportAccountEncryptionKeyDER(output_file: str):
|
def exportAccountEncryptionKeyDER(output_file):
|
||||||
|
# type: (str) -> bool
|
||||||
try:
|
try:
|
||||||
activationxml = etree.parse(get_activation_xml_path())
|
activationxml = etree.parse(get_activation_xml_path())
|
||||||
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
try:
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
from libadobe import addNonce, sign_node, get_cert_from_pkcs12, sendRequestDocu, sendRequestDocuRC, sendHTTPRequest
|
|
||||||
from libadobe import get_devkey_path, get_device_path, get_activation_xml_path
|
from libadobe import addNonce, sign_node, get_cert_from_pkcs12, sendRequestDocu, sendRequestDocuRC, sendHTTPRequest
|
||||||
from libadobe import VAR_VER_SUPP_VERSIONS, VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS
|
from libadobe import get_devkey_path, get_device_path, get_activation_xml_path
|
||||||
from libadobe import VAR_VER_BUILD_IDS, VAR_VER_USE_DIFFERENT_NOTIFICATION_XML_ORDER
|
from libadobe import VAR_VER_SUPP_VERSIONS, VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS
|
||||||
except:
|
from libadobe import VAR_VER_BUILD_IDS, VAR_VER_USE_DIFFERENT_NOTIFICATION_XML_ORDER
|
||||||
from calibre_plugins.deacsm.libadobe import addNonce, sign_node, get_cert_from_pkcs12, sendRequestDocu, sendRequestDocuRC, sendHTTPRequest
|
|
||||||
from calibre_plugins.deacsm.libadobe import get_devkey_path, get_device_path, get_activation_xml_path
|
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_SUPP_VERSIONS, VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS
|
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_BUILD_IDS, VAR_VER_USE_DIFFERENT_NOTIFICATION_XML_ORDER
|
|
||||||
|
|
||||||
|
|
||||||
def buildFulfillRequest(acsm):
|
def buildFulfillRequest(acsm):
|
||||||
@ -108,7 +105,8 @@ def buildFulfillRequest(acsm):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def buildInitLicenseServiceRequest(authURL: str):
|
def buildInitLicenseServiceRequest(authURL):
|
||||||
|
# type: (str) -> str
|
||||||
|
|
||||||
|
|
||||||
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
||||||
@ -175,7 +173,9 @@ def buildAuthRequest():
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def doOperatorAuth(operatorURL: str):
|
def doOperatorAuth(operatorURL):
|
||||||
|
# type: (str) -> str
|
||||||
|
|
||||||
auth_req = buildAuthRequest()
|
auth_req = buildAuthRequest()
|
||||||
|
|
||||||
authURL = operatorURL
|
authURL = operatorURL
|
||||||
@ -212,7 +212,8 @@ def doOperatorAuth(operatorURL: str):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def operatorAuth(operatorURL: str):
|
def operatorAuth(operatorURL):
|
||||||
|
# type: (str) -> str
|
||||||
|
|
||||||
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
||||||
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
||||||
@ -749,7 +750,8 @@ def performFulfillmentNotification(fulfillmentResultToken, forceOptional = False
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def fetchLicenseServiceCertificate(licenseURL: str, operatorURL: str):
|
def fetchLicenseServiceCertificate(licenseURL, operatorURL):
|
||||||
|
|
||||||
# Check if we already have a cert for this URL:
|
# Check if we already have a cert for this URL:
|
||||||
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
||||||
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
||||||
|
@ -8,6 +8,10 @@ except ImportError:
|
|||||||
# Some distros still ship this as Crypto
|
# Some distros still ship this as Crypto
|
||||||
from Crypto.Cipher import AES as _AES
|
from Crypto.Cipher import AES as _AES
|
||||||
|
|
||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
|
|
||||||
|
|
||||||
class AES(object):
|
class AES(object):
|
||||||
def __init__(self, key, iv):
|
def __init__(self, key, iv):
|
||||||
self._aes = _AES.new(key, _AES.MODE_CBC, iv)
|
self._aes = _AES.new(key, _AES.MODE_CBC, iv)
|
||||||
@ -15,12 +19,8 @@ class AES(object):
|
|||||||
return self._aes.decrypt(data)
|
return self._aes.decrypt(data)
|
||||||
|
|
||||||
|
|
||||||
try:
|
from libadobe import makeSerial, get_devkey_path, get_device_path, get_activation_xml_path
|
||||||
from libadobe import makeSerial, get_devkey_path, get_device_path, get_activation_xml_path
|
from libadobe import VAR_VER_HOBBES_VERSIONS, VAR_VER_OS_IDENTIFIERS, VAR_VER_DEFAULT_BUILD_ID, VAR_VER_BUILD_IDS
|
||||||
from libadobe import VAR_VER_HOBBES_VERSIONS, VAR_VER_OS_IDENTIFIERS, VAR_VER_DEFAULT_BUILD_ID, VAR_VER_BUILD_IDS
|
|
||||||
except:
|
|
||||||
from calibre_plugins.deacsm.libadobe import makeSerial, get_devkey_path, get_device_path, get_activation_xml_path
|
|
||||||
from calibre_plugins.deacsm.libadobe import VAR_VER_HOBBES_VERSIONS, VAR_VER_OS_IDENTIFIERS, VAR_VER_DEFAULT_BUILD_ID, VAR_VER_BUILD_IDS
|
|
||||||
|
|
||||||
|
|
||||||
def importADEactivationLinuxWine(wine_prefix_path, buildIDtoEmulate=VAR_VER_DEFAULT_BUILD_ID):
|
def importADEactivationLinuxWine(wine_prefix_path, buildIDtoEmulate=VAR_VER_DEFAULT_BUILD_ID):
|
||||||
|
@ -7,7 +7,10 @@ sys.path.append("../calibre-plugin")
|
|||||||
import unittest
|
import unittest
|
||||||
import base64
|
import base64
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
from unittest.mock import patch
|
if sys.version_info[0] >= 3:
|
||||||
|
from unittest.mock import patch
|
||||||
|
else:
|
||||||
|
from mock import patch
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
|
|
||||||
@ -38,9 +41,9 @@ class TestAdobe(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
def test_checkIfVersionListsAreValid(self):
|
def test_checkIfVersionListsAreValid(self):
|
||||||
'''
|
'''Check if version lists are sane'''
|
||||||
Check if version lists are sane
|
|
||||||
|
|
||||||
|
'''
|
||||||
These four lists must all have the same amount of elements.
|
These four lists must all have the same amount of elements.
|
||||||
Also, the default build ID must be valid, and all the IDs
|
Also, the default build ID must be valid, and all the IDs
|
||||||
available for authorization or switching must be valid, too.
|
available for authorization or switching must be valid, too.
|
||||||
@ -67,7 +70,7 @@ class TestAdobe(unittest.TestCase):
|
|||||||
|
|
||||||
def test_fingerprintGeneration(self):
|
def test_fingerprintGeneration(self):
|
||||||
'''Check if fingerprint generation works'''
|
'''Check if fingerprint generation works'''
|
||||||
libadobe.devkey_bytes = bytes([0xf8, 0x7a, 0xfc, 0x8c, 0x75, 0x25, 0xdc, 0x4b, 0x83, 0xec, 0x0c, 0xe2, 0xab, 0x4b, 0xef, 0x51])
|
libadobe.devkey_bytes = bytearray([0xf8, 0x7a, 0xfc, 0x8c, 0x75, 0x25, 0xdc, 0x4b, 0x83, 0xec, 0x0c, 0xe2, 0xab, 0x4b, 0xef, 0x51])
|
||||||
|
|
||||||
self.assertEqual(libadobe.makeFingerprint("f0081bce3f771bdeeb26fcb4b2011fed77edff7b"), b"FgLMNXxv1BZPqMOM6IUnfaG4Qj8=", "Wrong fingerprint")
|
self.assertEqual(libadobe.makeFingerprint("f0081bce3f771bdeeb26fcb4b2011fed77edff7b"), b"FgLMNXxv1BZPqMOM6IUnfaG4Qj8=", "Wrong fingerprint")
|
||||||
self.assertEqual(libadobe.makeFingerprint("HelloWorld123"), b"hpp223C1kfLDOoyxo8WR7KhcXB8=", "Wrong fingerprint")
|
self.assertEqual(libadobe.makeFingerprint("HelloWorld123"), b"hpp223C1kfLDOoyxo8WR7KhcXB8=", "Wrong fingerprint")
|
||||||
@ -79,14 +82,14 @@ class TestAdobe(unittest.TestCase):
|
|||||||
|
|
||||||
# Overwrite the get_random_bytes function that's used to get a random IV
|
# Overwrite the get_random_bytes function that's used to get a random IV
|
||||||
# Forcing hard-coded IV ...
|
# Forcing hard-coded IV ...
|
||||||
random.get_random_bytes._mock_side_effect = lambda rndlen: bytes([0xc2, 0x3b, 0x0f, 0xde, 0xf2, 0x4a, 0xc3, 0x03,
|
random.get_random_bytes._mock_side_effect = lambda rndlen: bytearray([0xc2, 0x3b, 0x0f, 0xde, 0xf2, 0x4a, 0xc3, 0x03,
|
||||||
0xae, 0xc8, 0x70, 0xd4, 0x46, 0x6c, 0x8b, 0xb0])
|
0xae, 0xc8, 0x70, 0xd4, 0x46, 0x6c, 0x8b, 0xb0])
|
||||||
|
|
||||||
|
|
||||||
libadobe.devkey_bytes = bytes([0xf8, 0x7a, 0xfc, 0x8c, 0x75, 0x25, 0xdc, 0x4b, 0x83, 0xec, 0x0c, 0xe2, 0xab, 0x4b, 0xef, 0x51])
|
libadobe.devkey_bytes = bytearray([0xf8, 0x7a, 0xfc, 0x8c, 0x75, 0x25, 0xdc, 0x4b, 0x83, 0xec, 0x0c, 0xe2, 0xab, 0x4b, 0xef, 0x51])
|
||||||
mock_data = b"Test message"
|
mock_data = b"Test message"
|
||||||
mock_result = libadobe.encrypt_with_device_key(mock_data)
|
mock_result = libadobe.encrypt_with_device_key(mock_data)
|
||||||
expected_result = bytes([0xc2, 0x3b, 0x0f, 0xde, 0xf2, 0x4a, 0xc3, 0x03, 0xae, 0xc8, 0x70, 0xd4,
|
expected_result = bytearray([0xc2, 0x3b, 0x0f, 0xde, 0xf2, 0x4a, 0xc3, 0x03, 0xae, 0xc8, 0x70, 0xd4,
|
||||||
0x46, 0x6c, 0x8b, 0xb0, 0x23, 0x5a, 0xd3, 0x1b, 0x4e, 0x2b, 0x12, 0x79,
|
0x46, 0x6c, 0x8b, 0xb0, 0x23, 0x5a, 0xd3, 0x1b, 0x4e, 0x2b, 0x12, 0x79,
|
||||||
0x85, 0x63, 0x2d, 0x01, 0xa4, 0xe8, 0x29, 0x22])
|
0x85, 0x63, 0x2d, 0x01, 0xa4, 0xe8, 0x29, 0x22])
|
||||||
|
|
||||||
@ -95,9 +98,9 @@ class TestAdobe(unittest.TestCase):
|
|||||||
def test_deviceKeyDecryption(self):
|
def test_deviceKeyDecryption(self):
|
||||||
'''Check if decryption with the device key works'''
|
'''Check if decryption with the device key works'''
|
||||||
|
|
||||||
libadobe.devkey_bytes = bytes([0xf8, 0x7a, 0xfc, 0x8c, 0x75, 0x25, 0xdc, 0x4b, 0x83, 0xec, 0x0c, 0xe2, 0xab, 0x4b, 0xef, 0x51])
|
libadobe.devkey_bytes = bytearray([0xf8, 0x7a, 0xfc, 0x8c, 0x75, 0x25, 0xdc, 0x4b, 0x83, 0xec, 0x0c, 0xe2, 0xab, 0x4b, 0xef, 0x51])
|
||||||
|
|
||||||
mock_data = bytes([0xc2, 0x3b, 0x0f, 0xde, 0xf2, 0x4a, 0xc3, 0x03, 0xae, 0xc8, 0x70, 0xd4,
|
mock_data = bytearray([0xc2, 0x3b, 0x0f, 0xde, 0xf2, 0x4a, 0xc3, 0x03, 0xae, 0xc8, 0x70, 0xd4,
|
||||||
0x46, 0x6c, 0x8b, 0xb0, 0x23, 0x5a, 0xd3, 0x1b, 0x4e, 0x2b, 0x12, 0x79,
|
0x46, 0x6c, 0x8b, 0xb0, 0x23, 0x5a, 0xd3, 0x1b, 0x4e, 0x2b, 0x12, 0x79,
|
||||||
0x85, 0x63, 0x2d, 0x01, 0xa4, 0xe8, 0x29, 0x22])
|
0x85, 0x63, 0x2d, 0x01, 0xa4, 0xe8, 0x29, 0x22])
|
||||||
|
|
||||||
@ -175,7 +178,7 @@ class TestAdobe(unittest.TestCase):
|
|||||||
# in case we need to go back to the old method.
|
# in case we need to go back to the old method.
|
||||||
|
|
||||||
mock_signing_key = "MIICdAIBADANBgkqhkiG9w0BAQEFAASCAl4wggJaAgEAAoGBALluuPvdDpr4L0j3eIGy3VxhgRcEKU3++qwbdvLXI99/izW9kfELFFJtq5d4ktIIUIvHsWkW0jblGi+bQ4sQXCeIvtOgqVHMSvRpW78lnGEkdD4Y1qhbcVGw7OGpWlhp8qCJKVCGbrkML7BSwFvQqqvg4vMU8O1uALfJvicKN3YfAgMBAAECf3uEg+Hr+DrstHhZF40zJPHKG3FkFd3HerXbOawMH5Q6CKTuKDGmOYQD+StFIlMArQJh8fxTVM3gSqgPkyyiesw0OuECU985FaLbUWxuCQzBcitnhl+VSv19oEPHTJWu0nYabasfT4oPjf8eiWR/ymJ9DZrjMWWy4Xf/S+/nFYUCQQDIZ1pc9nZsCB4QiBl5agTXoMcKavxFHPKxI/mHfRCHYjNyirziBJ+Dc/N40zKvldNBjO43KjLhUZs/BxdAJo09AkEA7OAdsg6SmviVV8xk0vuTmgLxhD7aZ9vpV4KF5+TH2DbximFoOP3YRObXV862wAjCpa84v43ok7Imtsu3NKQ+iwJAc0mx3GUU/1U0JoKFVSm+m2Ws27tsYT4kB/AQLvetuJSv0CcsPkI2meLsoAev0v84Ry+SIz4tgx31V672mzsSaQJBAJET1rw2Vq5Zr8Y9ZkceVFGQmfGAOW5A71Jsm6zin0+anyc874NwXaQdqiiab61/8A9gGSahOKA1DacJcCTqr28CQGm4mn3rOQFf+nniajIobATjNHaZJ76Xnc6rtoreK6+ZjO9wYF+797X/bhiV11Fpakvyrz6+t7bAd0PPQ2taTDg="
|
mock_signing_key = "MIICdAIBADANBgkqhkiG9w0BAQEFAASCAl4wggJaAgEAAoGBALluuPvdDpr4L0j3eIGy3VxhgRcEKU3++qwbdvLXI99/izW9kfELFFJtq5d4ktIIUIvHsWkW0jblGi+bQ4sQXCeIvtOgqVHMSvRpW78lnGEkdD4Y1qhbcVGw7OGpWlhp8qCJKVCGbrkML7BSwFvQqqvg4vMU8O1uALfJvicKN3YfAgMBAAECf3uEg+Hr+DrstHhZF40zJPHKG3FkFd3HerXbOawMH5Q6CKTuKDGmOYQD+StFIlMArQJh8fxTVM3gSqgPkyyiesw0OuECU985FaLbUWxuCQzBcitnhl+VSv19oEPHTJWu0nYabasfT4oPjf8eiWR/ymJ9DZrjMWWy4Xf/S+/nFYUCQQDIZ1pc9nZsCB4QiBl5agTXoMcKavxFHPKxI/mHfRCHYjNyirziBJ+Dc/N40zKvldNBjO43KjLhUZs/BxdAJo09AkEA7OAdsg6SmviVV8xk0vuTmgLxhD7aZ9vpV4KF5+TH2DbximFoOP3YRObXV862wAjCpa84v43ok7Imtsu3NKQ+iwJAc0mx3GUU/1U0JoKFVSm+m2Ws27tsYT4kB/AQLvetuJSv0CcsPkI2meLsoAev0v84Ry+SIz4tgx31V672mzsSaQJBAJET1rw2Vq5Zr8Y9ZkceVFGQmfGAOW5A71Jsm6zin0+anyc874NwXaQdqiiab61/8A9gGSahOKA1DacJcCTqr28CQGm4mn3rOQFf+nniajIobATjNHaZJ76Xnc6rtoreK6+ZjO9wYF+797X/bhiV11Fpakvyrz6+t7bAd0PPQ2taTDg="
|
||||||
payload_bytes = bytes([0x34, 0x52, 0xe3, 0xd1, 0x1c, 0xdd, 0x70, 0xeb, 0x90, 0x32, 0x3f, 0x29, 0x1c, 0x06, 0xaf, 0xaf, 0xe1, 0x0e, 0x09, 0x8a])
|
payload_bytes = bytearray([0x34, 0x52, 0xe3, 0xd1, 0x1c, 0xdd, 0x70, 0xeb, 0x90, 0x32, 0x3f, 0x29, 0x1c, 0x06, 0xaf, 0xaf, 0xe1, 0x0e, 0x09, 0x8a])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import rsa
|
import rsa
|
||||||
@ -184,7 +187,10 @@ class TestAdobe(unittest.TestCase):
|
|||||||
|
|
||||||
key = rsa.PrivateKey.load_pkcs1(RSA.importKey(base64.b64decode(mock_signing_key)).exportKey())
|
key = rsa.PrivateKey.load_pkcs1(RSA.importKey(base64.b64decode(mock_signing_key)).exportKey())
|
||||||
keylen = rsa.pkcs1.common.byte_size(key.n)
|
keylen = rsa.pkcs1.common.byte_size(key.n)
|
||||||
padded = rsa.pkcs1._pad_for_signing(payload_bytes, keylen)
|
if sys.version_info[0] >= 3:
|
||||||
|
padded = rsa.pkcs1._pad_for_signing(bytes(payload_bytes), keylen)
|
||||||
|
else:
|
||||||
|
padded = rsa.pkcs1._pad_for_signing(bytes(payload_bytes), keylen)
|
||||||
payload = rsa.pkcs1.transform.bytes2int(padded)
|
payload = rsa.pkcs1.transform.bytes2int(padded)
|
||||||
encrypted = key.blinded_encrypt(payload)
|
encrypted = key.blinded_encrypt(payload)
|
||||||
block = rsa.pkcs1.transform.int2bytes(encrypted, keylen)
|
block = rsa.pkcs1.transform.int2bytes(encrypted, keylen)
|
||||||
@ -200,7 +206,7 @@ class TestAdobe(unittest.TestCase):
|
|||||||
'''Check if the builtin CustomRSA library signs correctly'''
|
'''Check if the builtin CustomRSA library signs correctly'''
|
||||||
|
|
||||||
mock_signing_key = "MIICdAIBADANBgkqhkiG9w0BAQEFAASCAl4wggJaAgEAAoGBALluuPvdDpr4L0j3eIGy3VxhgRcEKU3++qwbdvLXI99/izW9kfELFFJtq5d4ktIIUIvHsWkW0jblGi+bQ4sQXCeIvtOgqVHMSvRpW78lnGEkdD4Y1qhbcVGw7OGpWlhp8qCJKVCGbrkML7BSwFvQqqvg4vMU8O1uALfJvicKN3YfAgMBAAECf3uEg+Hr+DrstHhZF40zJPHKG3FkFd3HerXbOawMH5Q6CKTuKDGmOYQD+StFIlMArQJh8fxTVM3gSqgPkyyiesw0OuECU985FaLbUWxuCQzBcitnhl+VSv19oEPHTJWu0nYabasfT4oPjf8eiWR/ymJ9DZrjMWWy4Xf/S+/nFYUCQQDIZ1pc9nZsCB4QiBl5agTXoMcKavxFHPKxI/mHfRCHYjNyirziBJ+Dc/N40zKvldNBjO43KjLhUZs/BxdAJo09AkEA7OAdsg6SmviVV8xk0vuTmgLxhD7aZ9vpV4KF5+TH2DbximFoOP3YRObXV862wAjCpa84v43ok7Imtsu3NKQ+iwJAc0mx3GUU/1U0JoKFVSm+m2Ws27tsYT4kB/AQLvetuJSv0CcsPkI2meLsoAev0v84Ry+SIz4tgx31V672mzsSaQJBAJET1rw2Vq5Zr8Y9ZkceVFGQmfGAOW5A71Jsm6zin0+anyc874NwXaQdqiiab61/8A9gGSahOKA1DacJcCTqr28CQGm4mn3rOQFf+nniajIobATjNHaZJ76Xnc6rtoreK6+ZjO9wYF+797X/bhiV11Fpakvyrz6+t7bAd0PPQ2taTDg="
|
mock_signing_key = "MIICdAIBADANBgkqhkiG9w0BAQEFAASCAl4wggJaAgEAAoGBALluuPvdDpr4L0j3eIGy3VxhgRcEKU3++qwbdvLXI99/izW9kfELFFJtq5d4ktIIUIvHsWkW0jblGi+bQ4sQXCeIvtOgqVHMSvRpW78lnGEkdD4Y1qhbcVGw7OGpWlhp8qCJKVCGbrkML7BSwFvQqqvg4vMU8O1uALfJvicKN3YfAgMBAAECf3uEg+Hr+DrstHhZF40zJPHKG3FkFd3HerXbOawMH5Q6CKTuKDGmOYQD+StFIlMArQJh8fxTVM3gSqgPkyyiesw0OuECU985FaLbUWxuCQzBcitnhl+VSv19oEPHTJWu0nYabasfT4oPjf8eiWR/ymJ9DZrjMWWy4Xf/S+/nFYUCQQDIZ1pc9nZsCB4QiBl5agTXoMcKavxFHPKxI/mHfRCHYjNyirziBJ+Dc/N40zKvldNBjO43KjLhUZs/BxdAJo09AkEA7OAdsg6SmviVV8xk0vuTmgLxhD7aZ9vpV4KF5+TH2DbximFoOP3YRObXV862wAjCpa84v43ok7Imtsu3NKQ+iwJAc0mx3GUU/1U0JoKFVSm+m2Ws27tsYT4kB/AQLvetuJSv0CcsPkI2meLsoAev0v84Ry+SIz4tgx31V672mzsSaQJBAJET1rw2Vq5Zr8Y9ZkceVFGQmfGAOW5A71Jsm6zin0+anyc874NwXaQdqiiab61/8A9gGSahOKA1DacJcCTqr28CQGm4mn3rOQFf+nniajIobATjNHaZJ76Xnc6rtoreK6+ZjO9wYF+797X/bhiV11Fpakvyrz6+t7bAd0PPQ2taTDg="
|
||||||
payload_bytes = bytes([0x34, 0x52, 0xe3, 0xd1, 0x1c, 0xdd, 0x70, 0xeb, 0x90, 0x32, 0x3f, 0x29, 0x1c, 0x06, 0xaf, 0xaf, 0xe1, 0x0e, 0x09, 0x8a])
|
payload_bytes = bytearray([0x34, 0x52, 0xe3, 0xd1, 0x1c, 0xdd, 0x70, 0xeb, 0x90, 0x32, 0x3f, 0x29, 0x1c, 0x06, 0xaf, 0xaf, 0xe1, 0x0e, 0x09, 0x8a])
|
||||||
|
|
||||||
block = CustomRSA.encrypt_for_adobe_signature(base64.b64decode(mock_signing_key), payload_bytes)
|
block = CustomRSA.encrypt_for_adobe_signature(base64.b64decode(mock_signing_key), payload_bytes)
|
||||||
signature = base64.b64encode(block).decode()
|
signature = base64.b64encode(block).decode()
|
||||||
@ -287,7 +293,7 @@ class TestAdobe(unittest.TestCase):
|
|||||||
user = "username"
|
user = "username"
|
||||||
passwd = "unit-test-password"
|
passwd = "unit-test-password"
|
||||||
|
|
||||||
libadobe.devkey_bytes = bytes([0xf8, 0x7a, 0xfc, 0x8c, 0x75, 0x25, 0xdc, 0x4b, 0x83, 0xec, 0x0c, 0xe2, 0xab, 0x4b, 0xef, 0x51])
|
libadobe.devkey_bytes = bytearray([0xf8, 0x7a, 0xfc, 0x8c, 0x75, 0x25, 0xdc, 0x4b, 0x83, 0xec, 0x0c, 0xe2, 0xab, 0x4b, 0xef, 0x51])
|
||||||
encrypted = libadobeAccount.encryptLoginCredentials(user, passwd, mock_auth_certificate)
|
encrypted = libadobeAccount.encryptLoginCredentials(user, passwd, mock_auth_certificate)
|
||||||
|
|
||||||
# Okay, now try to decrypt this again:
|
# Okay, now try to decrypt this again:
|
||||||
@ -296,13 +302,18 @@ class TestAdobe(unittest.TestCase):
|
|||||||
cipher_engine = PKCS1_v1_5.new(pkey)
|
cipher_engine = PKCS1_v1_5.new(pkey)
|
||||||
msg = cipher_engine.decrypt(encrypted, bytes([0x00] * 16))
|
msg = cipher_engine.decrypt(encrypted, bytes([0x00] * 16))
|
||||||
|
|
||||||
|
import struct
|
||||||
|
|
||||||
expected_msg = bytearray(libadobe.devkey_bytes)
|
expected_msg = bytearray(libadobe.devkey_bytes)
|
||||||
expected_msg.extend(bytearray(len(user).to_bytes(1, 'big')))
|
expected_msg.extend(bytearray(struct.pack("B", len(user))))
|
||||||
expected_msg.extend(bytearray(user.encode("latin-1")))
|
expected_msg.extend(bytearray(user.encode("latin-1")))
|
||||||
expected_msg.extend(bytearray(len(passwd).to_bytes(1, 'big')))
|
expected_msg.extend(bytearray(struct.pack("B", len(passwd))))
|
||||||
expected_msg.extend(bytearray(passwd.encode("latin-1")))
|
expected_msg.extend(bytearray(passwd.encode("latin-1")))
|
||||||
|
|
||||||
self.assertEqual(msg.hex(), expected_msg.hex(), "devkey encryption returned invalid result")
|
if sys.version_info[0] >= 3:
|
||||||
|
self.assertEqual(msg.hex(), expected_msg.hex(), "devkey encryption returned invalid result")
|
||||||
|
else:
|
||||||
|
self.assertEqual(msg, expected_msg, "devkey encryption returned invalid result")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -322,7 +333,7 @@ class TestOther(unittest.TestCase):
|
|||||||
'''Check if Wine username decoder is working properly'''
|
'''Check if Wine username decoder is working properly'''
|
||||||
|
|
||||||
self.assertEqual(fix_wine_username(r'"1234"'), b'1234', "Wine username mismatch")
|
self.assertEqual(fix_wine_username(r'"1234"'), b'1234', "Wine username mismatch")
|
||||||
self.assertEqual(fix_wine_username(r'"a\x00e931"'), b'a\xe931', "Wine username mismatch")
|
self.assertEqual(fix_wine_username(r'"a\x00e931"'), b'a\xe931', "Wine username mismatch with UTF-8")
|
||||||
|
|
||||||
def test_pdf_trimEncrypt(self):
|
def test_pdf_trimEncrypt(self):
|
||||||
'''Check if PDF encryption string trimming code is working properly'''
|
'''Check if PDF encryption string trimming code is working properly'''
|
||||||
|
Loading…
Reference in New Issue
Block a user