Bunch of ADE-related changes

- Support for emulating multiple ADE versions
- Support for importing existing Win/Mac ADE activation
- Various small fixes and cleanup
This commit is contained in:
Florian Bach 2021-11-20 06:53:51 +01:00
parent a7290b536a
commit eebb523b6b
10 changed files with 1247 additions and 98 deletions

View File

@ -7,9 +7,9 @@ It is a full Python reimplementation of libgourou by Grégory Soutadé (http://i
1. Download the plugin and import it into Calibre
2. Open the plugin settings, it should say "Not authorized for any ADE ID"
3. Click the "Link to ADE account" button
4. Enter your AdobeID and password, then wait a couple seconds for the success message.
5. The settings window should now say "Authorized with ADE ID X on device Y".
3. If you have ADE installed on your machine (Windows+Mac only, no Linux/Wine), there will be a button "Import activation from ADE". Clicking that will automatically copy your account information from ADE over to the Calibre plugin without using up an activation.
4. If you don't have ADE installed, or you want to authorize a different account, or the automatic retrieval from ADE failed, click the "Link to ADE account" button to make a new clean authorization. You will then be asked to enter your AdobeID and password and to select an ADE version (ADE 2.0.1 recommended). A couple seconds later a success message should be displayed.
5. The settings window should now say "Authorized with ADE ID X on device Y, emulating ADE version Z".
6. Click the "Export account activation data" and "Export account encryption key" buttons to export / backup your keys. Do not skip this step. The first file (ZIP) can be used to re-authorize Calibre after a reset / reinstall without using up one of your Adobe authorizations. The second file (DER) can be imported into DeDRM.
7. If needed (new AdobeID), import the DER file into the DeDRM plugin.
8. Download an ACSM file from Adobe's test library and see if you can import it into Calibre: https://www.adobe.com/de/solutions/ebook/digital-editions/sample-ebook-library.html
@ -18,7 +18,6 @@ IMPORTANT:
- I would suggest creating a new dummy AdobeID to use for Calibre so just in case Adobe detects this and bans you, you don't lose your main AdobeID.
- Combined with that I suggest importing the DER file into the DeDRM plugin to make sure that losing your AdobeID doesn't also mean you'll lose access to all your eBooks.
- Support for PDFs might be unreliable. You will need to apply pull request #1689 (including my additional bugfix in the comments of that PR) to the DeDRM plugin in order to remove the DRM from PDF files. If you still encounter an issue with a PDF file created by this tool even with these bugfixes, please report a bug (in this repository, not in the DeDRM one) and attach the corrupted PDF.
- This software is not approved by Adobe. I am not responsible if Adobe detects that you're using nonstandard software and bans your account. Do not complain to me if Adobe bans your main ADE account - you have been warned.
## Returning books

View File

@ -19,9 +19,13 @@
# improve PassHash support, include UUID in key export filename,
# fix bug that would block other FileTypePlugins
# v0.0.12: Fix Calibre Plugin index / updater
# v0.0.13: Add support for emulating multiple ADE versions (1.7.2, 2.0.1, 3.0.1, 4.0.3, 4.5.11),
# add code to import existing activation from ADE (Windows+Mac only),
# fix race condition when importing multiple ACSMs simultaneously,
# fix authorization failing with certain non-ASCII characters in username.
PLUGIN_NAME = "DeACSM"
PLUGIN_VERSION_TUPLE = (0, 0, 12)
PLUGIN_VERSION_TUPLE = (0, 0, 13)
from calibre.customize import FileTypePlugin # type: ignore
__version__ = PLUGIN_VERSION = ".".join([str(x)for x in PLUGIN_VERSION_TUPLE])
@ -106,10 +110,10 @@ class DeACSM(FileTypePlugin):
# Account:
try:
from calibre_plugins.deacsm.libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
from calibre_plugins.deacsm.libadobe import createDeviceKeyFile, update_account_path
from calibre_plugins.deacsm.libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
except:
from libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
from libadobe import createDeviceKeyFile, update_account_path
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
# Fulfill:
@ -120,6 +124,7 @@ class DeACSM(FileTypePlugin):
from libadobe import sendHTTPRequest
from libadobeFulfill import buildRights, fulfill
import calibre_plugins.deacsm.prefs as prefs # type: ignore
deacsmprefs = prefs.DeACSM_Prefs()
update_account_path(deacsmprefs["path_to_account_data"])
@ -238,6 +243,7 @@ class DeACSM(FileTypePlugin):
elif filetype == ".pdf":
adobe_fulfill_response = etree.fromstring(rights_xml_str)
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
resource = adobe_fulfill_response.find("./%s/%s" % (adNS("licenseToken"), adNS("resource"))).text
@ -274,14 +280,18 @@ class DeACSM(FileTypePlugin):
print("{0} v{1}: ADE auth is missing or broken ".format(PLUGIN_NAME, PLUGIN_VERSION))
return path_to_ebook
print("{0} v{1}: Try to fulfill ...".format(PLUGIN_NAME, PLUGIN_VERSION))
try:
from calibre_plugins.deacsm.libadobe import sendHTTPRequest
from calibre_plugins.deacsm.libadobeFulfill import buildRights, fulfill
from calibre_plugins.deacsm.libadobe import are_ade_version_lists_valid
from calibre_plugins.deacsm.libadobeFulfill import fulfill
except:
from libadobe import sendHTTPRequest
from libadobeFulfill import buildRights, fulfill
from libadobe import are_ade_version_lists_valid
from libadobeFulfill import fulfill
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))
return path_to_ebook
print("{0} v{1}: Try to fulfill ...".format(PLUGIN_NAME, PLUGIN_VERSION))
import calibre_plugins.deacsm.prefs as prefs # type: ignore
deacsmprefs = prefs.DeACSM_Prefs()

View File

@ -25,6 +25,7 @@ from calibre.gui2 import (question_dialog, error_dialog, info_dialog, choose_sav
from calibre_plugins.deacsm.__init__ import PLUGIN_NAME, PLUGIN_VERSION # type: ignore
import calibre_plugins.deacsm.prefs as prefs # type: ignore
from calibre.utils.config import config_dir # type: ignore
from calibre.constants import isosx, iswindows # type: ignore
class ConfigWidget(QWidget):
@ -67,11 +68,30 @@ class ConfigWidget(QWidget):
self.button_link_account.clicked.connect(self.link_account)
ua_group_box_layout.addWidget(self.button_link_account)
if isosx:
self.button_import_MacADE = QtGui.QPushButton(self)
self.button_import_MacADE.setText(_("Import activation from ADE (MacOS)"))
self.button_import_MacADE.clicked.connect(self.import_activation_from_MAC)
ua_group_box_layout.addWidget(self.button_import_MacADE)
if iswindows:
self.button_import_WinADE = QtGui.QPushButton(self)
self.button_import_WinADE.setText(_("Import activation from ADE (Windows)"))
self.button_import_WinADE.clicked.connect(self.import_activation_from_Win)
ua_group_box_layout.addWidget(self.button_import_WinADE)
self.button_import_activation = QtGui.QPushButton(self)
self.button_import_activation.setText(_("Import existing activation data (ZIP)"))
self.button_import_activation.clicked.connect(self.import_activation)
self.button_import_activation.setText(_("Import existing activation backup (ZIP)"))
self.button_import_activation.clicked.connect(self.import_activation_from_ZIP)
ua_group_box_layout.addWidget(self.button_import_activation)
else:
self.button_switch_ade_version = QtGui.QPushButton(self)
self.button_switch_ade_version.setText(_("Change ADE version"))
self.button_switch_ade_version.clicked.connect(self.switch_ade_version)
ua_group_box_layout.addWidget(self.button_switch_ade_version)
self.button_export_key = QtGui.QPushButton(self)
self.button_export_key.setText(_("Export account encryption key"))
self.button_export_key.clicked.connect(self.export_key)
@ -101,11 +121,11 @@ class ConfigWidget(QWidget):
try:
from calibre_plugins.deacsm.libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
from calibre_plugins.deacsm.libadobe import createDeviceKeyFile, update_account_path, are_ade_version_lists_valid
from calibre_plugins.deacsm.libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
except:
try:
from libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
from libadobe import createDeviceKeyFile, update_account_path, are_ade_version_lists_valid
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
except:
print("{0} v{1}: Error while importing Account stuff".format(PLUGIN_NAME, PLUGIN_VERSION))
@ -113,11 +133,39 @@ class ConfigWidget(QWidget):
update_account_path(self.deacsmprefs["path_to_account_data"])
self.resize(self.sizeHint())
if not are_ade_version_lists_valid():
# Internal error, this should never happen
if not activated:
self.button_link_account.setEnabled(False)
self.button_import_activation.setEnabled(False)
if isosx:
self.button_import_MacADE.setEnabled(activated)
if iswindows:
self.button_import_WinADE.setEnabled(activated)
else:
self.button_switch_ade_version.setEnabled(False)
self.button_export_key.setEnabled(False)
self.button_export_activation.setEnabled(False)
self.button_rented_books.setEnabled(False)
self.chkNotifyFulfillment.setEnabled(False)
error_dialog(None, "Internal error", "Version list mismatch. Please open a bug report.", show=True, show_copy_button=False)
def get_account_info(self):
try:
from calibre_plugins.deacsm.libadobe import VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS
except:
try:
from libadobe import VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS
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")
device_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "device.xml")
@ -130,11 +178,36 @@ class ConfigWidget(QWidget):
try:
adeptNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
usernameXML = container.find(adeptNS("credentials")).find(adeptNS("username"))
devicenameXML = containerdev.find(adeptNS("deviceName"))
ade_type = usernameXML.get('method', "unknown")
ade_mail = usernameXML.text
ade_device_name = devicenameXML.text
anon = False
try:
usernameXML = container.find(adeptNS("credentials")).find(adeptNS("username"))
ade_type = usernameXML.get('method', "unknown")
ade_mail = usernameXML.text
except:
anon = True
# Determine the ADE version we're emulating:
ver = containerdev.findall("./%s" % (adeptNS("version")))
ADE_version = None
for f in ver:
if f.get("name") == "hobbes":
hobbes_version = f.get("value")
if hobbes_version is not None:
try:
v_idx = VAR_VER_HOBBES_VERSIONS.index(hobbes_version)
ADE_version = VAR_VER_SUPP_CONFIG_NAMES[v_idx] + " (" + hobbes_version + ")"
except:
# Version not present, probably the "old" 10.0.4 entry.
# As 10.X is in the 3.0 range, assume we're on ADE 3.0
ADE_version = "ADE 3.0.1 (" + hobbes_version + ")"
if container.find(adeptNS("activationToken")) == None:
return "ADE authorization seems to be corrupted (activationToken missing)", False, None
@ -142,8 +215,12 @@ class ConfigWidget(QWidget):
if container.find(adeptNS("credentials")).find(adeptNS("pkcs12")) == None:
return "ADE authorization seems to be corrupted (pkcs12 missing)", False, None
return "Authorized with ADE ID ("+ade_type+") " + ade_mail + "\non device " + ade_device_name, True, ade_mail
if not anon:
return "Authorized with ADE ID ("+ade_type+") " + ade_mail + "\non device " + ade_device_name + ", emulating " + ADE_version + ".", True, ade_mail
else:
return "Authorized with an anonymous ADE ID\non device " + ade_device_name + ", emulating " + ADE_version + ".", True, None
except:
traceback.print_exc()
return "ADE authorization seems to be corrupted", False, None
@ -188,7 +265,75 @@ class ConfigWidget(QWidget):
except:
return error_dialog(None, "Export failed", "Export failed.", show=True, show_copy_button=False)
def import_activation(self):
def import_activation_from_Win(self):
# This will try to import the activation from Adobe Digital Editions on Windows ...
from calibre_plugins.deacsm.libadobeImportAccount import importADEactivationWindows
ret, msg = importADEactivationWindows()
if (ret):
# update display
info_string, activated, ade_mail = self.get_account_info()
self.lblAccInfo.setText(info_string)
self.button_link_account.setEnabled(not activated)
self.button_import_activation.setEnabled(not activated)
self.button_export_key.setEnabled(activated)
self.button_export_activation.setEnabled(activated)
self.button_import_WinADE.setEnabled(activated)
self.resize(self.sizeHint())
if (activated):
if ade_mail is None:
info_dialog(None, "Done", "Successfully imported an anonymous authorization", show=True, show_copy_button=False)
else:
info_dialog(None, "Done", "Successfully imported authorization for " + ade_mail, show=True, show_copy_button=False)
else:
error_dialog(None, "Import failed", "Import looks like it worked, but the resulting files seem to be corrupted ...", show=True, show_copy_button=False)
else:
error_dialog(None, "Import failed", "That didn't work:\n" + msg, show=True, show_copy_button=False)
def import_activation_from_MAC(self):
# This will try to import the activation from Adobe Digital Editions on MacOS ...
msg = "Trying to import existing activation from Adobe Digital Editions ...\n"
msg += "You might get a prompt asking you to unlock your keychain / enter your keychain password.\n"
msg += "This is necessary to extract the ADE encryption keys. "
info_dialog(None, "Importing from ADE", msg, show=True, show_copy_button=False)
from calibre_plugins.deacsm.libadobeImportAccount import importADEactivationMac
ret, msg = importADEactivationMac()
if (ret):
# update display
info_string, activated, ade_mail = self.get_account_info()
self.lblAccInfo.setText(info_string)
self.button_link_account.setEnabled(not activated)
self.button_import_activation.setEnabled(not activated)
self.button_export_key.setEnabled(activated)
self.button_export_activation.setEnabled(activated)
self.button_import_MacADE.setEnabled(activated)
self.resize(self.sizeHint())
if (activated):
if ade_mail is None:
info_dialog(None, "Done", "Successfully imported an anonymous authorization", show=True, show_copy_button=False)
else:
info_dialog(None, "Done", "Successfully imported authorization for " + ade_mail, show=True, show_copy_button=False)
else:
error_dialog(None, "Import failed", "Import looks like it worked, but the resulting files seem to be corrupted ...", show=True, show_copy_button=False)
else:
error_dialog(None, "Import failed", "That didn't work:\n" + msg, show=True, show_copy_button=False)
def import_activation_from_ZIP(self):
filters = [("ZIP", ["zip"])]
filenames = choose_files(self, "Import ADE activation file (ZIP)", _("Import ADE activation file (ZIP)"),
@ -236,21 +381,134 @@ class ConfigWidget(QWidget):
self.button_import_activation.setEnabled(not activated)
self.button_export_key.setEnabled(activated)
self.button_export_activation.setEnabled(activated)
try:
self.button_import_MacADE.setEnabled(activated)
except:
pass
try:
self.button_import_WinADE.setEnabled(activated)
except:
pass
self.resize(self.sizeHint())
info_dialog(None, "Done", "Successfully imported authorization for " + ade_mail, show=True, show_copy_button=False)
if ade_mail is None:
info_dialog(None, "Done", "Successfully imported an anonymous authorization.", show=True, show_copy_button=False)
else:
info_dialog(None, "Done", "Successfully imported authorization for " + ade_mail, show=True, show_copy_button=False)
def switch_ade_version(self):
try:
from calibre_plugins.deacsm.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 calibre_plugins.deacsm.libadobeAccount import changeDeviceVersion
except:
try:
from libadobe import VAR_VER_HOBBES_VERSIONS, VAR_VER_SUPP_CONFIG_NAMES
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")
try:
containerdev = etree.parse(device_xml_path)
except (FileNotFoundError, OSError) as e:
return error_dialog(None, "Failed", "Error while reading file", show=True, show_copy_button=False)
try:
adeptNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
# Determine the ADE version we're emulating:
ver = containerdev.findall("./%s" % (adeptNS("version")))
# "Default" entry would be for the old 10.0.4 entry.
# As 10.X is in the 3.0 range, assume we're on ADE 3.0.1 with hobbes version 10.0.85385
v_idx = VAR_VER_HOBBES_VERSIONS.index("10.0.85385")
for f in ver:
if f.get("name") == "hobbes":
hobbes_version = f.get("value")
if hobbes_version is not None:
ADE_version = "ADE 3.0.X (RMSDK " + hobbes_version + ")"
try:
v_idx = VAR_VER_HOBBES_VERSIONS.index(hobbes_version)
ADE_version = VAR_VER_SUPP_CONFIG_NAMES[v_idx] + " (RMSDK " + hobbes_version + ")"
except:
pass
else:
ADE_version = "ADE 3.0.X"
except:
err = traceback.format_exc()
return error_dialog(None, "Failed", "Error while determining current ADE version.", show=True, det_msg=err, show_copy_button=False)
# Build a list of allowed strings:
allowed_strings = []
for allowed_id in VAR_VER_ALLOWED_BUILD_IDS_SWITCH_TO:
try:
idx = VAR_VER_BUILD_IDS.index(allowed_id)
except:
pass
try:
allowed_strings.append(VAR_VER_SUPP_CONFIG_NAMES[idx])
except:
pass
if len(allowed_strings) == 0:
return error_dialog(None, "Failed", "Error determining available versions", show=True, show_copy_button=True)
msg = "You are currently using " + ADE_version + "\n"
msg += "You can switch to a different ADE version by using the selection box below.\n"
msg += "- ADE 1.7.2 is for debugging only. Do not use this setting, it might get your account banned\n"
msg += "- ADE 2.0.1 works with most books, and will always get you the old, removable DRM. Select this if you're unsure\n"
msg += "- ADE 3.0.1 works with all books, but may give you unremovable DRM for some retailers\n"
msg += "- ADE 4.0.3 and ADE 4.5.11 are available, but aren't really needed for anything\n"
msg += "Select ADE 2.0.1 if you are unsure\n\n"
msg += "Which ADE version do you want to emulate?"
item, ok = QInputDialog.getItem(self, "Change ADE version", msg, VAR_VER_SUPP_CONFIG_NAMES, 1, False)
if (not ok):
return
idx = -1
try:
idx = VAR_VER_SUPP_CONFIG_NAMES.index(item)
ret, msg = changeDeviceVersion(idx)
if (ret):
# Update info display:
info_string, activated, mail = self.get_account_info()
self.lblAccInfo.setText(info_string)
return info_dialog(None, "Done", "Successfully switched to " + item, show=True, show_copy_button=False)
else:
return error_dialog(None, "Failed", "Error while changing ADE version: " + msg, show=True, show_copy_button=False)
except:
return error_dialog(None, "Failed", "Error while changing ADE version.", show=True, det_msg=err, show_copy_button=False)
def link_account(self):
try:
from calibre_plugins.deacsm.libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
from calibre_plugins.deacsm.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 calibre_plugins.deacsm.libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
except:
try:
from libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
from libadobe import createDeviceKeyFile, update_account_path, VAR_VER_SUPP_CONFIG_NAMES
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))
@ -267,10 +525,41 @@ class ConfigWidget(QWidget):
if (not ok or passwd is None or len(passwd) == 0):
return
# Build a list of allowed strings:
allowed_strings = []
for allowed_id in VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE:
idx = VAR_VER_BUILD_IDS.index(allowed_id)
allowed_strings.append(VAR_VER_SUPP_CONFIG_NAMES[idx])
if len(allowed_strings) == 0:
return error_dialog(None, "ADE activation failed", "Error determining available versions", show=True, show_copy_button=True)
msg = "Which ADE version do you want to emulate?\n"
msg += "- ADE 2.0.1 works with most but not all books, but will always give you the old, removable DRM.\n"
msg += "- ADE 3.0.1 works with all books, but may give you unremovable DRM for some retailers.\n"
msg += "- ADE 4.0.3 and 4.5.11 are only provided for completeness sake, but aren't usually needed.\n"
msg += "Select ADE 2.0 if you are unsure."
item, ok = QInputDialog.getItem(self, "Authorizing ADE account", msg, allowed_strings,
VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE.index(VAR_VER_DEFAULT_BUILD_ID), False)
if (not ok):
return
idx = 0
try:
idx = VAR_VER_SUPP_CONFIG_NAMES.index(item)
print("User selected ({0}) -> {1}".format(idx, VAR_VER_SUPP_CONFIG_NAMES[idx]))
except:
resp = traceback.format_exc()
return error_dialog(None, "ADE activation failed", "Error determining version", det_msg=str(resp), show=True, show_copy_button=True)
createDeviceKeyFile()
createDeviceFile(VAR_HOBBES_VERSION, False)
success, resp = createUser()
createDeviceFile(False, idx)
success, resp = createUser(idx)
if (success is False):
return error_dialog(None, "ADE activation failed", "Couldn't create user", det_msg=str(resp), show=True, show_copy_button=True)
@ -278,7 +567,7 @@ class ConfigWidget(QWidget):
if (success is False):
return error_dialog(None, "ADE activation failed", "Login unsuccessful", det_msg=str(resp), show=True, show_copy_button=True)
success, resp = activateDevice()
success, resp = activateDevice(idx)
if (success is False):
return error_dialog(None, "ADE activation failed", "Couldn't activate device", det_msg=str(resp), show=True, show_copy_button=True)
@ -293,6 +582,14 @@ class ConfigWidget(QWidget):
self.button_import_activation.setEnabled(False)
self.button_export_key.setEnabled(True)
self.button_export_activation.setEnabled(True)
try:
self.button_import_MacADE.setEnabled(False)
except:
pass
try:
self.button_import_WinADE.setEnabled(False)
except:
pass
self.resize(self.sizeHint())
@ -345,7 +642,6 @@ class ConfigWidget(QWidget):
def save_settings(self):
#self.deacsmprefs.set('path_to_account_data', self.txtboxUA.text())
self.deacsmprefs.set('notify_fulfillment', self.chkNotifyFulfillment.isChecked())
self.deacsmprefs.writeprefs()

View File

@ -20,7 +20,7 @@ if sys.version_info[0] < 3:
print("This script requires Python 3.")
exit(1)
from libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile, update_account_path
from libadobe import createDeviceKeyFile, update_account_path, VAR_VER_SUPP_CONFIG_NAMES
from libadobeAccount import createDeviceFile, createUser, signIn, exportAccountEncryptionKeyDER, getAccountUUID
# These are the only two variables you'll need to change
@ -28,12 +28,14 @@ from libadobeAccount import createDeviceFile, createUser, signIn, exportAccountE
VAR_MAIL = ""
VAR_PASS = ""
VAR_VER = None # 1 for ADE2.0.1, 2 for ADE3.0.1
#################################################################
def main():
global VAR_MAIL
global VAR_PASS
global VAR_VER
if (VAR_MAIL == ""):
VAR_MAIL = input("Please enter your AdobeID: ")
@ -41,6 +43,13 @@ def main():
if (VAR_PASS == ""):
VAR_PASS = getpass.getpass("Please enter the password for your AdobeID: ")
if (VAR_VER is None):
VAR_VER = int(input("Please enter '1' for ADE 2.0 or '2' for ADE 3.0: "))
if VAR_VER >= len(VAR_VER_SUPP_CONFIG_NAMES):
print("Invalid version")
exit(1)
if (VAR_MAIL == "" or VAR_PASS == ""):
print("Empty credential, aborting")
exit(1)
@ -53,8 +62,13 @@ def main():
print ("Preparing keys ...")
createDeviceKeyFile()
createDeviceFile(VAR_HOBBES_VERSION, True)
success, resp = createUser()
success = createDeviceFile(True, VAR_VER)
if (success is False):
print("Error, couldn't create device file.")
exit(1)
success, resp = createUser(VAR_VER)
if (success is False):
print("Error, couldn't create user: %s" % resp)
exit(1)

View File

@ -31,14 +31,62 @@ from oscrypto.asymmetric import dump_certificate, dump_private_key, dump_public_
VAR_AUTH_SERVER = "adeactivate.adobe.com"
VAR_ACS_SERVER = "http://adeactivate.adobe.com/adept"
VAR_HOBBES_VERSION = "10.0.4"
VAR_ACS_SERVER_HTTP = "http://adeactivate.adobe.com/adept"
VAR_ACS_SERVER_HTTPS = "https://adeactivate.adobe.com/adept"
FILE_DEVICEKEY = "devicesalt"
FILE_DEVICEXML = "device.xml"
FILE_ACTIVATIONXML = "activation.xml"
# Lists of different ADE "versions" we know about
VAR_VER_SUPP_CONFIG_NAMES = [ "ADE 1.7.2", "ADE 2.0.1", "ADE 3.0.1", "ADE 4.0.3", "ADE 4.5.10", "ADE 4.5.11" ]
VAR_VER_SUPP_VERSIONS = [ "ADE WIN 9,0,1131,27", "2.0.1.78765", "3.0.1.91394", "4.0.3.123281",
"com.adobe.adobedigitaleditions.exe v4.5.10.186048",
"com.adobe.adobedigitaleditions.exe v4.5.11.187303" ]
VAR_VER_HOBBES_VERSIONS = [ "9.0.1131.27", "9.3.58046", "10.0.85385", "12.0.123217", "12.5.4.186049", "12.5.4.187298" ]
VAR_VER_OS_IDENTIFIERS = [ "Windows Vista", "Windows Vista", "Windows 8", "Windows 8", "Windows 8", "Windows 8" ]
# This is a list of ALL versions we know (and can potentially use if present in a config file).
# Must have the same length / size as the four lists above.
VAR_VER_BUILD_IDS = [ 1131, 78765, 91394, 123281, 186048, 187303 ]
# This is a list of versions that can be used for new authorizations:
VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE = [ 78765, 91394, 123281, 187303 ]
# This is a list of versions to be displayed in the version changer.
VAR_VER_ALLOWED_BUILD_IDS_SWITCH_TO = [ 1131, 78765, 91394, 123281, 187303 ]
# Versions >= this one are using HTTPS
VAR_VER_NEED_HTTPS_BUILD_ID_LIMIT = 123281
# Default build ID to use - ADE 2.0.1
VAR_VER_DEFAULT_BUILD_ID = 78765
def are_ade_version_lists_valid():
# These five lists MUST all have the same amount of elements.
# Otherwise that will cause all kinds of issues.
fail = False
if len(VAR_VER_SUPP_CONFIG_NAMES) != len(VAR_VER_SUPP_VERSIONS):
fail = True
if len(VAR_VER_SUPP_CONFIG_NAMES) != len(VAR_VER_HOBBES_VERSIONS):
fail = True
if len(VAR_VER_SUPP_CONFIG_NAMES) != len(VAR_VER_OS_IDENTIFIERS):
fail = True
if len(VAR_VER_SUPP_CONFIG_NAMES) != len(VAR_VER_BUILD_IDS):
fail = True
if fail:
print("Internal error in DeACSM: Mismatched version list lenghts.")
print("This should never happen, please open a bug report.")
return False
return True
devkey_bytes = None
@ -93,11 +141,11 @@ def makeSerial(random: bool):
# Linux
uid = os.getuid()
import pwd
username = pwd.getpwuid(uid).pw_name
username = pwd.getpwuid(uid).pw_name.encode("utf-8").decode("latin-1")
except:
# Windows
uid = 1000
username = os.getlogin()
username = os.getlogin().encode("utf-8").decode("latin-1")
mac_address = get_mac_address()

View File

@ -17,19 +17,34 @@ 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
VAR_AUTH_SERVER = "adeactivate.adobe.com"
VAR_ACS_SERVER = "http://adeactivate.adobe.com/adept"
VAR_HOBBES_VERSION = "10.0.4"
def createDeviceFile(hobbes: str, randomSerial: bool):
def createDeviceFile(randomSerial: bool, useVersionIndex: int = 0):
# Original implementation: Device::createDeviceFile(const std::string& hobbes, bool randomSerial)
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
return False
try:
build_id = VAR_VER_BUILD_IDS.index(useVersionIndex)
except:
return False
if build_id not in VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE:
# ADE 1.7.2 or another version that authorization is disabled for
return False
serial = makeSerial(randomSerial)
fingerprint = makeFingerprint(serial)
@ -37,27 +52,37 @@ def createDeviceFile(hobbes: str, randomSerial: bool):
etree.register_namespace("adept", NSMAP["adept"])
root = etree.Element(etree.QName(NSMAP["adept"], "deviceInfo"))
etree.SubElement(root, etree.QName(NSMAP["adept"], "deviceType")).text = "standalone"
# These three elements are not supposed to be sent to Adobe:
etree.SubElement(root, etree.QName(NSMAP["adept"], "deviceClass")).text = "Desktop"
etree.SubElement(root, etree.QName(NSMAP["adept"], "deviceSerial")).text = serial
etree.SubElement(root, etree.QName(NSMAP["adept"], "deviceName")).text = platform.uname()[1]
etree.SubElement(root, etree.QName(NSMAP["adept"], "deviceType")).text = "standalone"
# ##
atr_ver = etree.SubElement(root, etree.QName(NSMAP["adept"], "version"))
atr_ver.set("name", "hobbes")
atr_ver.set("value", hobbes)
atr_ver.set("value", VAR_VER_HOBBES_VERSIONS[useVersionIndex])
atr_ver2 = etree.SubElement(root, etree.QName(NSMAP["adept"], "version"))
atr_ver2.set("name", "clientOS")
atr_ver2.set("value", platform.system() + " " + platform.release())
# "Windows Vista"
# This used to contain code to actually read the user's operating system.
# That's probably not a good idea because then Adobe sees a bunch of requests from "Linux"
#atr_ver2.set("value", platform.system() + " " + platform.release())
atr_ver2.set("value", VAR_VER_OS_IDENTIFIERS[useVersionIndex])
atr_ver3 = etree.SubElement(root, etree.QName(NSMAP["adept"], "version"))
atr_ver3.set("name", "clientLocale")
language = locale.getdefaultlocale()[0]
language = None
try:
language = locale.getdefaultlocale()[0].split('_')[0]
except:
pass
if language is None or language == "":
# Can sometimes happen on MacOS with default English language
language = "en_US"
language = "en"
atr_ver3.set("value", language)
@ -68,8 +93,13 @@ def createDeviceFile(hobbes: str, randomSerial: bool):
f.write(etree.tostring(root, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("latin-1"))
f.close()
return True
def createUser():
def createUser(useVersionIndex: int = 0):
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
return False, "Invalid Version index"
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
@ -80,8 +110,17 @@ def createUser():
activationServiceInfo = etree.SubElement(root, etree.QName(NSMAP["adept"], "activationServiceInfo"))
activationURL = VAR_ACS_SERVER + "/ActivationServiceInfo"
useHTTPS = False
if VAR_VER_BUILD_IDS[useVersionIndex] >= VAR_VER_NEED_HTTPS_BUILD_ID_LIMIT:
useHTTPS = True
if useHTTPS:
# ADE 4.X uses HTTPS
activationURL = VAR_ACS_SERVER_HTTPS + "/ActivationServiceInfo"
else:
activationURL = VAR_ACS_SERVER_HTTP + "/ActivationServiceInfo"
response = sendHTTPRequest(activationURL)
#print("======================================================")
@ -103,7 +142,11 @@ def createUser():
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "authURL")).text = authURL
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "userInfoURL")).text = userInfoURL
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "activationURL")).text = VAR_ACS_SERVER
if useHTTPS:
# ADE 4.X uses HTTPS
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "activationURL")).text = VAR_ACS_SERVER_HTTPS
else:
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "activationURL")).text = VAR_ACS_SERVER_HTTP
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "certificate")).text = certificate
@ -265,7 +308,19 @@ def signIn(username: str, passwd: str):
def buildActivateReq():
def buildActivateReq(useVersionIndex: int = 0):
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
return False
try:
build_id = VAR_VER_BUILD_IDS.index(useVersionIndex)
except:
return False
if build_id not in VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE:
# ADE 1.7.2 or another version that authorization is disabled for
return False
devicexml = etree.parse(get_device_path())
activationxml = etree.parse(get_activation_xml_path())
@ -288,7 +343,7 @@ def buildActivateReq():
clientLocale = f.get("value")
if (version is None or clientOS is None or clientLocale is None):
return False, "err"
return False, "Required version information missing"
ret = ""
@ -298,15 +353,18 @@ def buildActivateReq():
ret += "<adept:deviceType>%s</adept:deviceType>" % (devicexml.find("./%s" % (adNS("deviceType"))).text)
ret += "<adept:clientOS>%s</adept:clientOS>" % (clientOS)
ret += "<adept:clientLocale>%s</adept:clientLocale>" % (clientLocale)
ret += "<adept:clientVersion>%s</adept:clientVersion>" % (devicexml.find("./%s" % (adNS("deviceClass"))).text)
ret += "<adept:clientVersion>%s</adept:clientVersion>" % (VAR_VER_SUPP_VERSIONS[useVersionIndex])
ret += "<adept:targetDevice>"
ret += "<adept:softwareVersion>%s</adept:softwareVersion>" % (version)
ret += "<adept:clientOS>%s</adept:clientOS>" % (clientOS)
ret += "<adept:clientLocale>%s</adept:clientLocale>" % (clientLocale)
ret += "<adept:clientVersion>%s</adept:clientVersion>" % (devicexml.find("./%s" % (adNS("deviceClass"))).text)
ret += "<adept:clientVersion>%s</adept:clientVersion>" % (VAR_VER_SUPP_VERSIONS[useVersionIndex])
ret += "<adept:deviceType>%s</adept:deviceType>" % (devicexml.find("./%s" % (adNS("deviceType"))).text)
ret += "<adept:productName>%s</adept:productName>" % ("ADOBE Digitial Editions")
# YES, this typo ("Digitial" instead of "Digital") IS present in ADE!!
ret += "<adept:fingerprint>%s</adept:fingerprint>" % (devicexml.find("./%s" % (adNS("fingerprint"))).text)
ret += "</adept:targetDevice>"
@ -320,9 +378,67 @@ def buildActivateReq():
return True, ret
def activateDevice():
# Call this function to change from ADE2 to ADE3 and vice versa.
def changeDeviceVersion(useVersionIndex: int = 0):
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
return False, "Invalid Version index"
result, activate_req = buildActivateReq()
try:
build_id = VAR_VER_BUILD_IDS.index(useVersionIndex)
except:
return False, "Unknown build ID"
if build_id not in VAR_VER_ALLOWED_BUILD_IDS_SWITCH_TO:
# A version that we no longer want to allow switching to
return False, "BuildID not supported"
try:
devicexml = etree.parse(get_device_path())
new_hobbes = VAR_VER_HOBBES_VERSIONS[useVersionIndex]
new_os = VAR_VER_OS_IDENTIFIERS[useVersionIndex]
except:
return False, "Error preparing version change"
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
ver = devicexml.findall("./%s" % (adNS("version")))
for f in ver:
if f.get("name") == "hobbes":
#print("Changing hobbes from {0} to {1}".format(f.attrib["value"], new_hobbes))
f.attrib["value"] = new_hobbes
if f.get("name") == "clientOS":
#print("Changing OS from {0} to {1}".format(f.attrib["value"], new_os))
f.attrib["value"] = new_os
try:
f = open(get_device_path(), "w")
f.write("<?xml version=\"1.0\"?>\n")
f.write(etree.tostring(devicexml, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("latin-1"))
f.close()
except:
return False, "Failed to update device file."
return True, ""
def activateDevice(useVersionIndex: int = 0):
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
return False, "Invalid Version index"
try:
build_id = VAR_VER_BUILD_IDS.index(useVersionIndex)
except:
return False, "error checking build ID"
if build_id not in VAR_VER_ALLOWED_BUILD_IDS_AUTHORIZE:
# ADE 1.7.2 or another version that authorization is disabled for
return False, "Authorization not supported for this build ID"
result, activate_req = buildActivateReq(useVersionIndex)
if (result is False):
return False, "Building activation request failed: " + activate_req
@ -344,7 +460,15 @@ def activateDevice():
data = "<?xml version=\"1.0\"?>\n" + etree.tostring(req_xml, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("latin-1")
ret = sendRequestDocu(data, VAR_ACS_SERVER + "/Activate")
useHTTPS = False
if VAR_VER_BUILD_IDS[useVersionIndex] >= VAR_VER_NEED_HTTPS_BUILD_ID_LIMIT:
useHTTPS = True
if useHTTPS:
# ADE 4.X uses HTTPS
ret = sendRequestDocu(data, VAR_ACS_SERVER_HTTPS + "/Activate")
else:
ret = sendRequestDocu(data, VAR_ACS_SERVER_HTTP + "/Activate")
try:
credentialsXML = etree.fromstring(ret)
@ -409,3 +533,14 @@ def exportAccountEncryptionKeyDER(output_file: str):
return True
except:
return False
def exportAccountEncryptionKeyBytes():
try:
activationxml = etree.parse(get_activation_xml_path())
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
privatekey = activationxml.find("./%s/%s" % (adNS("credentials"), adNS("privateLicenseKey"))).text
privatekey = base64.b64decode(privatekey)
privatekey = privatekey[26:]
return privatekey
except:
return None

View File

@ -0,0 +1,225 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Most of the code in this file has been taken from adobekey.pyw written by i♥cabbages
# adobekey.pyw, version 7.0
# Copyright © 2009-2020 i♥cabbages, Apprentice Harper et al.
# Released under the terms of the GNU General Public Licence, version 3
# <http://www.gnu.org/licenses/>
from ctypes import windll, c_char_p, c_wchar_p, c_uint, POINTER, byref, \
create_unicode_buffer, create_string_buffer, CFUNCTYPE, \
string_at, Structure, c_void_p, cast, c_size_t, memmove
from ctypes.wintypes import LPVOID, DWORD, BOOL
import struct
try:
import winreg
except ImportError:
import _winreg as winreg
MAX_PATH = 255
kernel32 = windll.kernel32
advapi32 = windll.advapi32
crypt32 = windll.crypt32
def GetSystemDirectory():
GetSystemDirectoryW = kernel32.GetSystemDirectoryW
GetSystemDirectoryW.argtypes = [c_wchar_p, c_uint]
GetSystemDirectoryW.restype = c_uint
def GetSystemDirectory():
buffer = create_unicode_buffer(MAX_PATH + 1)
GetSystemDirectoryW(buffer, len(buffer))
return buffer.value
return GetSystemDirectory
GetSystemDirectory = GetSystemDirectory()
def GetVolumeSerialNumber():
GetVolumeInformationW = kernel32.GetVolumeInformationW
GetVolumeInformationW.argtypes = [c_wchar_p, c_wchar_p, c_uint,
POINTER(c_uint), POINTER(c_uint),
POINTER(c_uint), c_wchar_p, c_uint]
GetVolumeInformationW.restype = c_uint
def GetVolumeSerialNumber(path):
vsn = c_uint(0)
GetVolumeInformationW(
path, None, 0, byref(vsn), None, None, None, 0)
return vsn.value
return GetVolumeSerialNumber
GetVolumeSerialNumber = GetVolumeSerialNumber()
def GetUserName():
GetUserNameW = advapi32.GetUserNameW
GetUserNameW.argtypes = [c_wchar_p, POINTER(c_uint)]
GetUserNameW.restype = c_uint
def GetUserName():
buffer = create_unicode_buffer(32)
size = c_uint(len(buffer))
while not GetUserNameW(buffer, byref(size)):
buffer = create_unicode_buffer(len(buffer) * 2)
size.value = len(buffer)
return buffer.value.encode('utf-16-le')[::2]
return GetUserName
GetUserName = GetUserName()
PAGE_EXECUTE_READWRITE = 0x40
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
def VirtualAlloc():
_VirtualAlloc = kernel32.VirtualAlloc
_VirtualAlloc.argtypes = [LPVOID, c_size_t, DWORD, DWORD]
_VirtualAlloc.restype = LPVOID
def VirtualAlloc(addr, size, alloctype=(MEM_COMMIT | MEM_RESERVE),
protect=PAGE_EXECUTE_READWRITE):
return _VirtualAlloc(addr, size, alloctype, protect)
return VirtualAlloc
VirtualAlloc = VirtualAlloc()
MEM_RELEASE = 0x8000
def VirtualFree():
_VirtualFree = kernel32.VirtualFree
_VirtualFree.argtypes = [LPVOID, c_size_t, DWORD]
_VirtualFree.restype = BOOL
def VirtualFree(addr, size=0, freetype=MEM_RELEASE):
return _VirtualFree(addr, size, freetype)
return VirtualFree
VirtualFree = VirtualFree()
class NativeFunction(object):
def __init__(self, restype, argtypes, insns):
self._buf = buf = VirtualAlloc(None, len(insns))
memmove(buf, insns, len(insns))
ftype = CFUNCTYPE(restype, *argtypes)
self._native = ftype(buf)
def __call__(self, *args):
return self._native(*args)
def __del__(self):
if self._buf is not None:
VirtualFree(self._buf)
self._buf = None
if struct.calcsize("P") == 4:
CPUID0_INSNS = (
b"\x53" # push %ebx
b"\x31\xc0" # xor %eax,%eax
b"\x0f\xa2" # cpuid
b"\x8b\x44\x24\x08" # mov 0x8(%esp),%eax
b"\x89\x18" # mov %ebx,0x0(%eax)
b"\x89\x50\x04" # mov %edx,0x4(%eax)
b"\x89\x48\x08" # mov %ecx,0x8(%eax)
b"\x5b" # pop %ebx
b"\xc3" # ret
)
CPUID1_INSNS = (
b"\x53" # push %ebx
b"\x31\xc0" # xor %eax,%eax
b"\x40" # inc %eax
b"\x0f\xa2" # cpuid
b"\x5b" # pop %ebx
b"\xc3" # ret
)
else:
CPUID0_INSNS = (
b"\x49\x89\xd8" # mov %rbx,%r8
b"\x49\x89\xc9" # mov %rcx,%r9
b"\x48\x31\xc0" # xor %rax,%rax
b"\x0f\xa2" # cpuid
b"\x4c\x89\xc8" # mov %r9,%rax
b"\x89\x18" # mov %ebx,0x0(%rax)
b"\x89\x50\x04" # mov %edx,0x4(%rax)
b"\x89\x48\x08" # mov %ecx,0x8(%rax)
b"\x4c\x89\xc3" # mov %r8,%rbx
b"\xc3" # retq
)
CPUID1_INSNS = (
b"\x53" # push %rbx
b"\x48\x31\xc0" # xor %rax,%rax
b"\x48\xff\xc0" # inc %rax
b"\x0f\xa2" # cpuid
b"\x5b" # pop %rbx
b"\xc3" # retq
)
def cpuid0():
_cpuid0 = NativeFunction(None, [c_char_p], CPUID0_INSNS)
buf = create_string_buffer(12)
def cpuid0():
_cpuid0(buf)
return buf.raw
return cpuid0
cpuid0 = cpuid0()
cpuid1 = NativeFunction(c_uint, [], CPUID1_INSNS)
class DataBlob(Structure):
_fields_ = [('cbData', c_uint),
('pbData', c_void_p)]
DataBlob_p = POINTER(DataBlob)
def CryptUnprotectData():
_CryptUnprotectData = crypt32.CryptUnprotectData
_CryptUnprotectData.argtypes = [DataBlob_p, c_wchar_p, DataBlob_p,
c_void_p, c_void_p, c_uint, DataBlob_p]
_CryptUnprotectData.restype = c_uint
def CryptUnprotectData(indata, entropy):
indatab = create_string_buffer(indata)
indata = DataBlob(len(indata), cast(indatab, c_void_p))
entropyb = create_string_buffer(entropy)
entropy = DataBlob(len(entropy), cast(entropyb, c_void_p))
outdata = DataBlob()
if not _CryptUnprotectData(byref(indata), None, byref(entropy),
None, None, 0, byref(outdata)):
raise Exception("Failed to decrypt user key key (sic)")
return string_at(outdata.pbData, outdata.cbData)
return CryptUnprotectData
CryptUnprotectData = CryptUnprotectData()
DEVICE_KEY_PATH = r'Software\Adobe\Adept\Device'
def GetMasterKey():
root = GetSystemDirectory().split('\\')[0] + '\\'
serial = GetVolumeSerialNumber(root)
vendor = cpuid0()
signature = struct.pack('>I', cpuid1())[1:]
try:
regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, DEVICE_KEY_PATH)
device = winreg.QueryValueEx(regkey, 'key')[0]
# ADE puts an "username" attribute into that key which was unused
# in previous versions of this script. This means that this key
# retrieval script would break / not work if the user had ever
# changed their Windows account user name after installing ADE.
# By reading the "username" registry entry if available we won't
# have that problem anymore.
try:
user = winreg.QueryValueEx(regkey, 'username')[0].encode('utf-16-le')[::2]
# Yes, this actually only uses the lowest byte of each character.
except:
# This value should always be available, but just in case
# it's not, use the old implementation.
user = GetUserName()
except WindowsError:
return None
entropy = struct.pack('>I12s3s13s', serial, vendor, signature, user)
try:
keykey = CryptUnprotectData(device, entropy)
except Exception:
# There was an exception, so this thing was unable to decrypt
# the key. Maybe this is due to the new user name handling, so
# let's retry with the old code.
user = GetUserName()
entropy = struct.pack('>I12s3s13s', serial, vendor, signature, user)
keykey = CryptUnprotectData(device, entropy)
return keykey

View File

@ -4,9 +4,11 @@ import base64
try:
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 VAR_VER_SUPP_VERSIONS, VAR_VER_SUPP_CONFIG_NAMES, VAR_VER_HOBBES_VERSIONS
except:
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
def buildFulfillRequest(acsm):
@ -20,9 +22,19 @@ def buildFulfillRequest(acsm):
user_uuid = activationxml.find("./%s/%s" % (adNS("credentials"), adNS("user"))).text
device_uuid = activationxml.find("./%s/%s" % (adNS("activationToken"), adNS("device"))).text
device_type = devicexml.find("./%s" % (adNS("deviceType"))).text
device_class = devicexml.find("./%s" % (adNS("deviceClass"))).text
fingerprint = devicexml.find("./%s" % (adNS("fingerprint"))).text
try:
fingerprint = None
device_type = None
fingerprint = activationxml.find("./%s/%s" % (adNS("activationToken"), adNS("fingerprint"))).text
fingerprint = activationxml.find("./%s/%s" % (adNS("activationToken"), adNS("deviceType"))).text
except:
pass
if (fingerprint is None or fingerprint == "" or device_type is None or device_type == ""):
# This should usually never happen with a proper activation, but just in case it does,
# I'll leave this code in - it loads the fingerprint from the device data instead.
fingerprint = devicexml.find("./%s" % (adNS("fingerprint"))).text
device_type = devicexml.find("./%s" % (adNS("deviceType"))).text
@ -41,31 +53,56 @@ def buildFulfillRequest(acsm):
elif f.get("name") == "clientLocale":
clientLocale = f.get("value")
# Find matching client version depending on the Hobbes version.
# This way we don't need to store and re-load it for each fulfillment.
request = ""
request += "<?xml version=\"1.0\"?>\n"
request += "<adept:fulfill xmlns:adept=\"http://ns.adobe.com/adept\">\n"
request += "<adept:user>%s</adept:user>\n" % (user_uuid)
request += "<adept:device>%s</adept:device>\n" % (device_uuid)
request += "<adept:deviceType>%s</adept:deviceType>\n" % (device_type)
request += etree.tostring(acsm, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("utf-8")
request += "<adept:targetDevice>\n"
try:
v_idx = VAR_VER_HOBBES_VERSIONS.index(version)
clientVersion = VAR_VER_SUPP_VERSIONS[v_idx]
request += "<adept:softwareVersion>%s</adept:softwareVersion>\n" % (version)
request += "<adept:clientOS>%s</adept:clientOS>\n" % (clientOS)
request += "<adept:clientLocale>%s</adept:clientLocale>\n" % (clientLocale)
request += "<adept:clientVersion>%s</adept:clientVersion>\n" % (device_class)
request += "<adept:deviceType>%s</adept:deviceType>\n" % (device_type)
request += "<adept:fingerprint>%s</adept:fingerprint>\n" % (fingerprint)
except:
# Version not present, probably the "old" 10.0.4 entry.
# As 10.X is in the 3.0 range, assume we're on ADE 3.0
clientVersion = "3.0.1.91394"
request += "<adept:activationToken>\n"
request += "<adept:user>%s</adept:user>\n" % (user_uuid)
request += "<adept:device>%s</adept:device>\n" % (device_uuid)
request += "</adept:activationToken>\n"
request += "</adept:targetDevice>\n"
request += "</adept:fulfill>\n"
if clientVersion == "ADE WIN 9,0,1131,27":
# Ancient ADE 1.7.2 does this request differently
request = "<fulfill xmlns=\"http://ns.adobe.com/adept\">\n"
request += "<user>%s</user>\n" % (user_uuid)
request += "<device>%s</device>\n" % (device_uuid)
request += "<deviceType>%s</deviceType>\n" % (device_type)
request += etree.tostring(acsm, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("utf-8")
request += "</fulfill>"
return request, False
return request
else:
request = ""
request += "<?xml version=\"1.0\"?>"
request += "<adept:fulfill xmlns:adept=\"http://ns.adobe.com/adept\">"
request += "<adept:user>%s</adept:user>" % (user_uuid)
request += "<adept:device>%s</adept:device>" % (device_uuid)
request += "<adept:deviceType>%s</adept:deviceType>" % (device_type)
request += etree.tostring(acsm, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("utf-8")
request += "<adept:targetDevice>"
request += "<adept:softwareVersion>%s</adept:softwareVersion>" % (version)
request += "<adept:clientOS>%s</adept:clientOS>" % (clientOS)
request += "<adept:clientLocale>%s</adept:clientLocale>" % (clientLocale)
request += "<adept:clientVersion>%s</adept:clientVersion>" % (clientVersion)
request += "<adept:deviceType>%s</adept:deviceType>" % (device_type)
request += "<adept:productName>%s</adept:productName>" % ("ADOBE Digitial Editions")
# YES, this typo ("Digitial" instead of "Digital") IS present in ADE!!
request += "<adept:fingerprint>%s</adept:fingerprint>" % (fingerprint)
request += "<adept:activationToken>"
request += "<adept:user>%s</adept:user>" % (user_uuid)
request += "<adept:device>%s</adept:device>" % (device_uuid)
request += "</adept:activationToken>"
request += "</adept:targetDevice>"
request += "</adept:fulfill>"
return request, True
@ -286,7 +323,7 @@ def fulfill(acsm_file, do_notify = False):
print("Continuing anyways ...")
fulfill_request = buildFulfillRequest(acsmxml)
fulfill_request, adept_ns = buildFulfillRequest(acsmxml)
#print(fulfill_request)
@ -298,7 +335,13 @@ def fulfill(acsm_file, do_notify = False):
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
etree.SubElement(fulfill_request_xml, etree.QName(NSMAP["adept"], "signature")).text = signature
if adept_ns:
# "new" ADE
etree.SubElement(fulfill_request_xml, etree.QName(NSMAP["adept"], "signature")).text = signature
else:
# ADE 1.7.2
etree.SubElement(fulfill_request_xml, etree.QName("signature")).text = signature
# Get operator URL:
operatorURL = None
@ -316,8 +359,12 @@ def fulfill(acsm_file, do_notify = False):
if (ret is not None):
return False, "operatorAuth error: %s" % ret
fulfill_req_signed = "<?xml version=\"1.0\"?>\n" + etree.tostring(fulfill_request_xml, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("utf-8")
if adept_ns:
# "new" ADE
fulfill_req_signed = "<?xml version=\"1.0\"?>\n" + etree.tostring(fulfill_request_xml, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("utf-8")
else:
# ADE 1.7.2
fulfill_req_signed = etree.tostring(fulfill_request_xml, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("utf-8")
#print("will send:\n %s" % fulfill_req_signed)
#print("Sending fulfill request to %s" % fulfillURL)
@ -350,11 +397,14 @@ def fulfill(acsm_file, do_notify = False):
licenseURL = adobe_fulfill_response.find("./%s/%s/%s/%s" % (adNS("fulfillmentResult"), adNS("resourceItemInfo"), adNS("licenseToken"), adNS("licenseURL"))).text
if do_notify:
print("Notifying server ...")
success, response = performFulfillmentNotification(adobe_fulfill_response)
else:
print("Not notifying any server since that was disabled.")
if adept_ns:
if do_notify:
print("Notifying server ...")
success, response = performFulfillmentNotification(adobe_fulfill_response)
else:
print("Not notifying any server since that was disabled.")
else:
print("Skipping notify, not supported properly with ADE 1.7.2")
is_returnable = False
@ -365,9 +415,10 @@ def fulfill(acsm_file, do_notify = False):
except:
pass
if (is_returnable and do_notify):
if (is_returnable and do_notify and adept_ns):
# Only support loan returning if we also notified ACS.
# Otherwise the server gets confused and we don't want that.
# Also, only do that for new-ish ADE and not for ADE 1.7.2
updateLoanReturnData(adobe_fulfill_response)
success, response = fetchLicenseServiceCertificate(licenseURL, operatorURL)

View File

@ -0,0 +1,356 @@
from lxml import etree
import base64
import os, locale, platform
from Crypto.Cipher import AES as _AES
class AES(object):
def __init__(self, key, iv):
self._aes = _AES.new(key, _AES.MODE_CBC, iv)
def decrypt(self, data):
return self._aes.decrypt(data)
try:
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
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 importADEactivationWindows(buildIDtoEmulate=VAR_VER_DEFAULT_BUILD_ID):
# Tries to import the system activation from Adobe Digital Editions on Windows into the plugin
# This can be used to "clone" the ADE activation so you don't need to waste an additional activation.
try:
from calibre.constants import iswindows
except:
import sys
iswindows = sys.platform.startswith('win')
if not iswindows:
print("This function is for Windows only!")
return False, "Windows only!"
# Get encryption key:
try:
from libadobeEncryptionWindows import GetMasterKey
except:
from calibre_plugins.deacsm.libadobeEncryptionWindows import GetMasterKey
master_key = GetMasterKey()
if master_key is None:
return False, "master_key is None ..."
PRIVATE_LICENCE_KEY_PATH = r'Software\Adobe\Adept\Activation'
# Dump data from registry:
try:
import winreg
except ImportError:
import _winreg as winreg
try:
activation_root = winreg.OpenKey(winreg.HKEY_CURRENT_USER, PRIVATE_LICENCE_KEY_PATH)
except:
return False, "Could not locate ADE activation"
i = 0
while True:
try:
activation_parent = winreg.OpenKey(activation_root, "%04d" % (i))
except:
break
ParentKeyType = winreg.QueryValueEx(activation_parent, None)[0]
j = 0
while True:
try:
activation_child = winreg.OpenKey(activation_parent, "%04d" % (j))
except:
break
SubKeyType = winreg.QueryValueEx(activation_child, None)[0]
try:
value = winreg.QueryValueEx(activation_child, 'value')[0]
try:
method = winreg.QueryValueEx(activation_child, 'method')[0]
except:
method = None
handle_subkey(ParentKeyType, SubKeyType, value, master_key, method, None)
except:
pass
j = j + 1
i = i + 1
return handle_subkey(None, None, None, master_key, None, buildIDtoEmulate)
persistent_data = dict()
account_method = None
def finalize_write_config_Windows(data, key, buildID):
# Okay, finally got all the data that's needed - recreate all the files.
# Create devicekey file:
f = open(get_devkey_path(), "wb")
f.write(key)
f.close()
# Create activation.xml
f = open(get_activation_xml_path(), "w")
content = '<?xml version="1.0"?>\n'
content += "<activationInfo xmlns=\"http://ns.adobe.com/adept\">\n"
content += '<adept:activationServiceInfo xmlns:adept="http://ns.adobe.com/adept">\n'
content += "<adept:authURL>%s</adept:authURL>" % (data["activationServiceInfo"]["authURL"])
content += "<adept:userInfoURL>%s</adept:userInfoURL>" % (data["activationServiceInfo"]["userInfoURL"])
content += "<adept:activationURL>%s</adept:activationURL>" % (data["activationServiceInfo"]["activationURL"])
content += "<adept:certificate>%s</adept:certificate>" % (data["activationServiceInfo"]["certificate"])
content += "<adept:authenticationCertificate>%s</adept:authenticationCertificate>" % (data["activationServiceInfo"]["authenticationCertificate"])
content += '</adept:activationServiceInfo>\n'
content += '<adept:credentials xmlns:adept="http://ns.adobe.com/adept">'
content += "<adept:user>%s</adept:user>" % (data["credentials"]["user"])
global account_method
if "username" in data["credentials"]:
if account_method is None:
account_method = "AdobeID"
content += "<adept:username method=\"%s\">%s</adept:username>" % (account_method, data["credentials"]["username"])
content += "<adept:pkcs12>%s</adept:pkcs12>" % (data["credentials"]["pkcs12"])
content += "<adept:licenseCertificate>%s</adept:licenseCertificate>" % (data["credentials"]["licenseCertificate"])
content += "<adept:privateLicenseKey>%s</adept:privateLicenseKey>" % (data["credentials"]["privateLicenseKey"])
content += "<adept:authenticationCertificate>%s</adept:authenticationCertificate>" % (data["credentials"]["authenticationCertificate"])
content += '</adept:credentials>\n'
content += '<activationToken xmlns="http://ns.adobe.com/adept">'
for x in ["device", "fingerprint", "deviceType", "activationURL", "user", "signature"]:
content += "<%s>%s</%s>" % (x, data["activationToken"][x], x)
content += '</activationToken>\n'
content += '</activationInfo>\n'
f.write(content)
f.close()
# Re-create device.xml from scratch:
content = '<?xml version="1.0"?>\n'
content += '<adept:deviceInfo xmlns:adept="http://ns.adobe.com/adept">\n'
content += "<adept:deviceType>%s</adept:deviceType>\n" % (data["activationToken"]["deviceType"])
content += "<adept:deviceClass>%s</adept:deviceClass>\n" % ("Desktop")
content += "<adept:deviceSerial>%s</adept:deviceSerial>\n" % (makeSerial(False))
content += "<adept:deviceName>%s</adept:deviceName>\n" % (platform.uname()[1])
version_idx = VAR_VER_BUILD_IDS.index(buildID)
hobbes_ver = VAR_VER_HOBBES_VERSIONS[version_idx]
clientOS = VAR_VER_OS_IDENTIFIERS[version_idx]
content += "<adept:version name=\"hobbes\" value=\"%s\"/>\n" % (hobbes_ver)
content += "<adept:version name=\"clientOS\" value=\"%s\"/>\n" % (clientOS)
language = None
try:
language = locale.getdefaultlocale()[0].split('_')[0]
except:
pass
if language is None or language == "":
# Can sometimes happen on MacOS with default English language
language = "en"
content += "<adept:version name=\"clientLocale\" value=\"%s\"/>\n" % (language)
content += "<adept:fingerprint>%s</adept:fingerprint>\n" % (data["activationToken"]["fingerprint"])
content += "</adept:deviceInfo>"
# Write device.xml
f = open(get_device_path(), "w")
f.write(content)
f.close()
return True, "Done"
def handle_subkey(parent, subkey, value, encryption_key, method, buildID):
if parent is None:
# We're done collecting sub keys - decrypt the private key, then finalize config.
# The first 16 bytes of the fingerprint are used as IV for the privateLicenseKey
# Older versions of this decryption code, like in the DeDRM plugin, didn't
# do that correctly. For DeDRM that doesn't matter as a wrong IV only causes
# the first 16 bytes to be corrupted, and these aren't used for decryption anyways.
# For this plugin I want the exact correct data, so lets use the fingerprint as IV.
# See jhowell's post: https://www.mobileread.com/forums/showpost.php?p=4173908
iv = persistent_data["activationToken"]["fingerprint"]
iv = base64.b64decode(iv)[:16]
aes = AES(encryption_key, iv)
value = base64.b64decode(persistent_data["credentials"]["privateLicenseKey"])
persistent_data["credentials"]["privateLicenseKey"] = base64.b64encode(aes.decrypt(value)).decode("latin-1")
return finalize_write_config_Windows(persistent_data, encryption_key, buildID)
else:
# collecting a single sub key by storing it in the global list "persistent_data"
global account_method
if method:
account_method = method
# Not encrypted
try:
persistent_data[parent][subkey] = value
except KeyError:
persistent_data[parent] = dict()
persistent_data[parent][subkey] = value
return None
def getMacCredential(type):
import os, re
# Just calling a native binary.
# The python modules were all A) pretty complicated and B) are only intended
# to read your own credentials, so they require the user to manually add
# Python to the list of applications allowed to read ADE credentials.
# By calling this "security" binary, it will instead pop up a password input
# dialog, having the user verify that they do want to export the ADE keys.
cmd = ' '.join([
"/usr/bin/security",
"find-generic-password",
"-g -s '%s' -a '%s'" % ("Digital Editions", type),
"2>&1 >/dev/null"
])
p = os.popen(cmd)
s = p.read()
p.close()
m = re.match(r"password: (?:0x([0-9A-F]+)\s*)?\"(.*)\"$", s)
if m:
hexform, stringform = m.groups()
if hexform:
return bytes.fromhex(hexform)
else:
return bytes(stringform, 'latin-1')
return None
def importADEactivationMac(buildIDtoEmulate=VAR_VER_DEFAULT_BUILD_ID):
# Tries to import the system activation from Adobe Digital Editions on a Mac into the plugin
# This can be used to "clone" the ADE activation so you don't need to waste an additional activation.
import sys
try:
from calibre.constants import isosx
except:
isosx = sys.platform.startswith('darwin')
if not isosx:
print("This function is for MacOS only!")
return False, "MacOS only!"
import subprocess
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
home = os.getenv('HOME')
cmdline = 'find "' + home + '/Library/Application Support/Adobe/Digital Editions" -name "activation.dat"'
cmdline = cmdline.encode(sys.getfilesystemencoding())
p2 = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False)
out1, out2 = p2.communicate()
reslst = out1.split(b'\n')
cnt = len(reslst)
ActDatPath = b"activation.dat"
for j in range(cnt):
resline = reslst[j]
pp = resline.find(b'activation.dat')
if pp >= 0:
ActDatPath = resline
break
if not os.path.exists(ActDatPath):
print("Activation file does not exist ...")
return False, "Activation file not found"
# activation.xml is at ActDatPath.
# Now get the password(s) ...
DeviceKey = getMacCredential("DeviceKey")
DeviceFingerprint = getMacCredential("DeviceFingerprint")
if (DeviceKey is None or DeviceFingerprint is None):
print("There was an error exporting the keys from the MacOS keychain.")
return False, "Error while exporting keys"
return recreateMacActivationFiles(ActDatPath, DeviceKey, DeviceFingerprint, buildIDtoEmulate)
def recreateMacActivationFiles(path_to_activation, deviceKey, deviceFingerprint, buildIDtoEmulate):
if (len(deviceKey) != 16):
print("Looks like the device key is invalid ...")
return False, "Invalid device key"
# Create activation.xml file:
import shutil
shutil.copyfile(path_to_activation, get_activation_xml_path())
# Create devicekey file:
f = open(get_devkey_path(), "wb")
f.write(deviceKey)
f.close()
# Read and parse activation.xml
activationxml = etree.parse(get_activation_xml_path())
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
devtype = activationxml.find("./%s/%s" % (adNS("activationToken"), adNS("deviceType"))).text
# Re-create device.xml from scratch:
content = '<?xml version="1.0"?>\n'
content += '<adept:deviceInfo xmlns:adept="http://ns.adobe.com/adept">\n'
content += "<adept:deviceType>%s</adept:deviceType>\n" % (devtype)
content += "<adept:deviceClass>%s</adept:deviceClass>\n" % ("Desktop")
content += "<adept:deviceSerial>%s</adept:deviceSerial>\n" % (makeSerial(False))
content += "<adept:deviceName>%s</adept:deviceName>\n" % (platform.uname()[1])
version_idx = VAR_VER_BUILD_IDS.index(buildIDtoEmulate)
hobbes_ver = VAR_VER_HOBBES_VERSIONS[version_idx]
clientOS = VAR_VER_OS_IDENTIFIERS[version_idx]
content += "<adept:version name=\"hobbes\" value=\"%s\"/>\n" % (hobbes_ver)
content += "<adept:version name=\"clientOS\" value=\"%s\"/>\n" % (clientOS)
language = None
try:
language = locale.getdefaultlocale()[0].split('_')[0]
except:
pass
if language is None or language == "":
# Can sometimes happen on MacOS with default English language
language = "en"
content += "<adept:version name=\"clientLocale\" value=\"%s\"/>\n" % (language)
content += "<adept:fingerprint>%s</adept:fingerprint>\n" % (base64.b64encode(deviceFingerprint))
content += "</adept:deviceInfo>"
# Write device.xml
f = open(get_device_path(), "w")
f.write(content)
f.close()
return True, "Success"

View File

@ -11,7 +11,7 @@ if sys.version_info[0] < 3:
print("This script requires Python 3.")
exit(1)
from libadobe import VAR_HOBBES_VERSION, createDeviceKeyFile
from libadobe import createDeviceKeyFile, VAR_VER_SUPP_CONFIG_NAMES
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
# These are the only two variables you'll need to change
@ -21,12 +21,15 @@ from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
VAR_MAIL = ""
VAR_PASS = ""
VAR_VER = None # 1 for ADE2.0, 2 for ADE3.0
#################################################################
def main():
global VAR_MAIL
global VAR_PASS
global VAR_VER
if (VAR_MAIL == ""):
VAR_MAIL = input("Please enter your AdobeID: ")
@ -34,14 +37,26 @@ def main():
if (VAR_PASS == ""):
VAR_PASS = getpass.getpass("Please enter the password for your AdobeID: ")
if (VAR_VER is None):
VAR_VER = int(input("Please enter '1' for ADE 2.0 or '2' for ADE 3.0: "))
if VAR_VER >= len(VAR_VER_SUPP_CONFIG_NAMES):
print("Invalid version")
exit(1)
if (VAR_MAIL == "" or VAR_PASS == ""):
print("Empty credential, aborting")
exit(1)
createDeviceKeyFile()
createDeviceFile(VAR_HOBBES_VERSION, False)
success, resp = createUser()
success = createDeviceFile(True, VAR_VER)
if (success is False):
print("Error, couldn't create device file.")
exit(1)
success, resp = createUser(VAR_VER)
if (success is False):
print("Error, couldn't create user: %s" % resp)
exit(1)
@ -51,7 +66,7 @@ def main():
print("Login unsuccessful: " + resp)
exit(1)
success, resp = activateDevice()
success, resp = activateDevice(VAR_VER)
if (success is False):
print("Couldn't activate device: " + resp)
exit(1)