mirror of
https://github.com/Leseratte10/acsm-calibre-plugin.git
synced 2024-12-22 17:29:56 +06:00
Support anonymous auth and other auth providers
This commit is contained in:
parent
f9fbc4172a
commit
cc37506762
26
README.md
26
README.md
@ -5,19 +5,25 @@ It is a full Python reimplementation of libgourou by Grégory Soutadé (http://i
|
||||
|
||||
## Setup
|
||||
|
||||
1. Download the plugin and import it into Calibre
|
||||
2. Open the plugin settings, it should say "Not authorized for any ADE ID"
|
||||
3. If you have ADE installed on your machine, 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
|
||||
Download the plugin and import it into Calibre, then open the plugin settings. The plugin should display "Not authorized for any ADE ID". You now have multiple options to authorize the plugin:
|
||||
|
||||
- You can click on "Link to ADE account" and enter your AdobeID credentials to link your Calibre installation to your AdobeID account. This uses up one of your available activations.
|
||||
- You can click on "Create anonymous authorization" to create an anonymous authorization. Make sure to create backups of that authorization. Also, if you do end up emulating ADE3+ and you receive a file with the new Adobe DRM, you might not be able to access it ...
|
||||
- If you have ADE installed and activated on your machine, you can click "Import activation from ADE" to clone the existing activation from your ADE installation.
|
||||
- If you have used this plugin before, you can click on "Import existing activation backup" to import a previously created activation backup (ZIP) file to restore an activation. This functionality can also be used to clone one activation to multiple computers.
|
||||
|
||||
During authorization, the plugin may ask you for the ADE version to emulate. Usually you can leave this setting as it is (ADE 2.0.1).
|
||||
|
||||
After you've activated the plugin, make a backup of the activation using the "Export account activation data". Then click "Export account encryption key" and import the resulting file into the DeDRM plugin for DRM removal. If you're using noDRM's fork of the DeDRM plugin, this step will happen automatically.
|
||||
|
||||
Once that's done, 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
|
||||
|
||||
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.
|
||||
- If you use an anonymous authorization, make sure you make backups of the activation data.
|
||||
- If you use an anonymous authorization and you end up getting an eBook with the new Adobe DRM (version 3 or higher), there might be no way for you to access that book at all, as right now there's no way to export an existing authorization from the plugin into ADE.
|
||||
- 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
|
||||
@ -41,10 +47,6 @@ Though, generally it's recommended to use the Calibre plugin instead of these st
|
||||
|
||||
## To-Do list for the future?
|
||||
|
||||
There's a bunch of features that could still be added, but most of them aren't implemented in libgourou either, so I don't know if or when I'll be able to add these:
|
||||
|
||||
- Support for anonymous Adobe IDs
|
||||
- Support for un-authorizing a machine
|
||||
- Support to copy an authorization from the plugin to an ADE install
|
||||
- Support for Adobe's "auth" download method instead of the "simple" method.
|
||||
- ...
|
@ -29,6 +29,9 @@
|
||||
# fix authorization failing with certain non-ASCII characters in username,
|
||||
# add detailed logging toggle setting, add auto-delete ACSM setting,
|
||||
# add useful error message for ACSMs with nonstandard download type.
|
||||
# Currently in development:
|
||||
# Add support for anonymous authorizations, add support for other ID providers,
|
||||
# fix ACSM files from Google Play books (no metadata node).
|
||||
|
||||
PLUGIN_NAME = "DeACSM"
|
||||
PLUGIN_VERSION_TUPLE = (0, 0, 14)
|
||||
|
@ -22,7 +22,8 @@ from PyQt5 import Qt as QtGui
|
||||
from zipfile import ZipFile
|
||||
|
||||
# calibre modules and constants.
|
||||
from calibre.gui2 import (question_dialog, error_dialog, info_dialog, choose_save_file, choose_files) # type: ignore
|
||||
from calibre.gui2 import (question_dialog, error_dialog, info_dialog, # type: ignore
|
||||
warning_dialog, choose_save_file, choose_files)
|
||||
# modules from this plugin's zipfile.
|
||||
from calibre_plugins.deacsm.__init__ import PLUGIN_NAME, PLUGIN_VERSION # type: ignore
|
||||
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
||||
@ -72,6 +73,11 @@ class ConfigWidget(QWidget):
|
||||
self.button_link_account.clicked.connect(self.link_account)
|
||||
ua_group_box_layout.addWidget(self.button_link_account)
|
||||
|
||||
self.button_anon_auth = QtGui.QPushButton(self)
|
||||
self.button_anon_auth.setText(_("Create anonymous authorization"))
|
||||
self.button_anon_auth.clicked.connect(self.create_anon_auth)
|
||||
ua_group_box_layout.addWidget(self.button_anon_auth)
|
||||
|
||||
if isosx:
|
||||
self.button_import_MacADE = QtGui.QPushButton(self)
|
||||
self.button_import_MacADE.setText(_("Import activation from ADE (MacOS)"))
|
||||
@ -169,6 +175,7 @@ class ConfigWidget(QWidget):
|
||||
# Internal error, this should never happen
|
||||
if not activated:
|
||||
self.button_link_account.setEnabled(False)
|
||||
self.button_anon_auth.setEnabled(False)
|
||||
self.button_import_activation.setEnabled(False)
|
||||
if isosx:
|
||||
self.button_import_MacADE.setEnabled(activated)
|
||||
@ -196,7 +203,7 @@ class ConfigWidget(QWidget):
|
||||
msg += "This will cause various data to be included in the logfiles, like encryption keys, account keys and other confidential data.\n"
|
||||
msg += "With this setting enabled, only share log files privately with the developer and don't make them publicly available."
|
||||
|
||||
info_dialog(None, "Warning", msg, show=True, show_copy_button=False)
|
||||
warning_dialog(None, "Warning", msg, show=True, show_copy_button=False)
|
||||
|
||||
def toggle_acsm_delete(self):
|
||||
if not self.chkDeleteAfterFulfill.isChecked():
|
||||
@ -207,7 +214,7 @@ class ConfigWidget(QWidget):
|
||||
msg += "As this feature is experimental, it's possible that ACSMs will also sometimes get deleted even when the import failed.\n\n"
|
||||
msg += "If you're importing an ACSM that you cannot re-download in case of issues, do not enable this option!"
|
||||
|
||||
info_dialog(None, "Warning", msg, show=True, show_copy_button=False)
|
||||
warning_dialog(None, "Warning", msg, show=True, show_copy_button=False)
|
||||
|
||||
|
||||
|
||||
@ -453,6 +460,7 @@ class ConfigWidget(QWidget):
|
||||
self.lblAccInfo.setText(info_string)
|
||||
|
||||
self.button_link_account.setEnabled(not activated)
|
||||
self.button_anon_auth.setEnabled(not activated)
|
||||
self.button_import_activation.setEnabled(not activated)
|
||||
self.button_import_LinuxWineADE.setEnabled(not activated)
|
||||
self.button_export_key.setEnabled(activated)
|
||||
@ -485,6 +493,7 @@ class ConfigWidget(QWidget):
|
||||
self.lblAccInfo.setText(info_string)
|
||||
|
||||
self.button_link_account.setEnabled(not activated)
|
||||
self.button_anon_auth.setEnabled(not activated)
|
||||
self.button_import_activation.setEnabled(not activated)
|
||||
self.button_import_WinADE.setEnabled(not activated)
|
||||
self.button_export_key.setEnabled(activated)
|
||||
@ -522,6 +531,7 @@ class ConfigWidget(QWidget):
|
||||
self.lblAccInfo.setText(info_string)
|
||||
|
||||
self.button_link_account.setEnabled(not activated)
|
||||
self.button_anon_auth.setEnabled(not activated)
|
||||
self.button_import_activation.setEnabled(not activated)
|
||||
self.button_import_MacADE.setEnabled(not activated)
|
||||
self.button_export_key.setEnabled(activated)
|
||||
@ -586,6 +596,7 @@ class ConfigWidget(QWidget):
|
||||
self.lblAccInfo.setText(info_string)
|
||||
|
||||
self.button_link_account.setEnabled(not activated)
|
||||
self.button_anon_auth.setEnabled(not activated)
|
||||
self.button_import_activation.setEnabled(not activated)
|
||||
self.button_export_key.setEnabled(activated)
|
||||
self.button_export_activation.setEnabled(activated)
|
||||
@ -705,8 +716,7 @@ class ConfigWidget(QWidget):
|
||||
return error_dialog(None, "Failed", "Error while changing ADE version.", show=True, det_msg=traceback.format_exc(), show_copy_button=False)
|
||||
|
||||
|
||||
def link_account(self):
|
||||
|
||||
def create_anon_auth(self):
|
||||
try:
|
||||
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
|
||||
@ -721,6 +731,116 @@ class ConfigWidget(QWidget):
|
||||
traceback.print_exc()
|
||||
|
||||
update_account_path(self.deacsmprefs["path_to_account_data"])
|
||||
|
||||
msg = "You are about to create an anonymous authorization.\n"
|
||||
msg += "If you lose access to this authorization, all books linked to it will be lost / inaccessible. "
|
||||
msg += "Make sure to create backups of the authorization data! "
|
||||
msg += "Also, if you do end up emulating ADE3 or newer, and you receive an eBook with the new DRM, "
|
||||
msg += "you might not be able to read / access that book at all."
|
||||
|
||||
warning_dialog(None, "Warning", msg, show=True, show_copy_button=False)
|
||||
|
||||
# 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(False, idx)
|
||||
success, resp = createUser(idx, None)
|
||||
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)
|
||||
|
||||
success, resp = signIn("anonymous", "", "")
|
||||
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(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)
|
||||
|
||||
print("Authorized to anonymous account")
|
||||
|
||||
|
||||
# update display
|
||||
info_string, activated, mail = self.get_account_info()
|
||||
self.lblAccInfo.setText(info_string)
|
||||
|
||||
self.button_link_account.setEnabled(not activated)
|
||||
self.button_anon_auth.setEnabled(not activated)
|
||||
self.button_import_activation.setEnabled(not activated)
|
||||
self.button_export_key.setEnabled(activated)
|
||||
self.button_export_activation.setEnabled(activated)
|
||||
if isosx:
|
||||
self.button_import_MacADE.setEnabled(not activated)
|
||||
if iswindows:
|
||||
self.button_import_WinADE.setEnabled(not activated)
|
||||
if islinux:
|
||||
self.button_import_LinuxWineADE.setEnabled(not activated)
|
||||
|
||||
self.resize(self.sizeHint())
|
||||
|
||||
info_dialog(None, "Done", "Authorized to anonymous account.", show=True, show_copy_button=False)
|
||||
|
||||
def link_account(self):
|
||||
|
||||
try:
|
||||
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, getAuthMethodsAndCert, createUser, signIn, activateDevice
|
||||
except:
|
||||
try:
|
||||
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, 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"])
|
||||
|
||||
|
||||
# Get account types
|
||||
types, authCert = getAuthMethodsAndCert()
|
||||
|
||||
msg = "Please select your AdobeID provider. Usually, \"Adobe ID\" is the correct choice."
|
||||
|
||||
acc_item, ok = QInputDialog.getItem(self, "Authorizing ADE account", msg, types[1], 0, False)
|
||||
acc_type = "AdobeID"
|
||||
try:
|
||||
acc_idx = types[1].index(acc_item)
|
||||
acc_type = types[0][acc_idx]
|
||||
print("User has selected account type " + acc_type)
|
||||
except ValueError:
|
||||
return error_dialog(None, "ADE activation failed", "Invalid provider", show=True, show_copy_button=True)
|
||||
|
||||
|
||||
|
||||
mail, ok = QInputDialog.getText(self, "Authorizing ADE account", "Please enter mail address")
|
||||
|
||||
@ -755,49 +875,50 @@ class ConfigWidget(QWidget):
|
||||
if (not ok):
|
||||
return
|
||||
|
||||
idx = 0
|
||||
vers_idx = 0
|
||||
try:
|
||||
idx = VAR_VER_SUPP_CONFIG_NAMES.index(item)
|
||||
print("User selected ({0}) -> {1}".format(idx, VAR_VER_SUPP_CONFIG_NAMES[idx]))
|
||||
vers_idx = VAR_VER_SUPP_CONFIG_NAMES.index(item)
|
||||
print("User selected ({0}) -> {1}".format(vers_idx, VAR_VER_SUPP_CONFIG_NAMES[vers_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(False, idx)
|
||||
success, resp = createUser(idx)
|
||||
createDeviceFile(False, vers_idx)
|
||||
success, resp = createUser(vers_idx, authCert)
|
||||
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)
|
||||
|
||||
success, resp = signIn(mail, passwd)
|
||||
success, resp = signIn(acc_type, mail, passwd)
|
||||
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(idx)
|
||||
success, resp = activateDevice(vers_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)
|
||||
|
||||
print("Authorized to account " + mail)
|
||||
print("Authorized to '" + acc_type + "' account " + mail)
|
||||
|
||||
|
||||
# update display
|
||||
info_string, activated, mail = self.get_account_info()
|
||||
self.lblAccInfo.setText(info_string)
|
||||
|
||||
self.button_link_account.setEnabled(False)
|
||||
self.button_import_activation.setEnabled(False)
|
||||
self.button_export_key.setEnabled(True)
|
||||
self.button_export_activation.setEnabled(True)
|
||||
self.button_link_account.setEnabled(not activated)
|
||||
self.button_anon_auth.setEnabled(not activated)
|
||||
self.button_import_activation.setEnabled(not activated)
|
||||
self.button_export_key.setEnabled(activated)
|
||||
self.button_export_activation.setEnabled(activated)
|
||||
if isosx:
|
||||
self.button_import_MacADE.setEnabled(False)
|
||||
self.button_import_MacADE.setEnabled(not activated)
|
||||
if iswindows:
|
||||
self.button_import_WinADE.setEnabled(False)
|
||||
self.button_import_WinADE.setEnabled(not activated)
|
||||
if islinux:
|
||||
self.button_import_LinuxWineADE.setEnabled(False)
|
||||
self.button_import_LinuxWineADE.setEnabled(not activated)
|
||||
|
||||
self.resize(self.sizeHint())
|
||||
|
||||
info_dialog(None, "Done", "Authorized to account " + mail, show=True, show_copy_button=False)
|
||||
info_dialog(None, "Done", "Authorized to '" + acc_item + "' account " + mail, show=True, show_copy_button=False)
|
||||
|
||||
|
||||
|
||||
|
@ -68,14 +68,14 @@ def main():
|
||||
exit(1)
|
||||
|
||||
|
||||
success, resp = createUser(VAR_VER)
|
||||
success, resp = createUser(VAR_VER, None)
|
||||
if (success is False):
|
||||
print("Error, couldn't create user: %s" % resp)
|
||||
exit(1)
|
||||
|
||||
print("Logging in ...")
|
||||
|
||||
success, resp = signIn(VAR_MAIL, VAR_PASS)
|
||||
success, resp = signIn("AdobeID", VAR_MAIL, VAR_PASS)
|
||||
if (success is False):
|
||||
print("Login unsuccessful: " + resp)
|
||||
exit(1)
|
||||
|
@ -350,6 +350,11 @@ def decrypt_with_device_key(data):
|
||||
|
||||
def addNonce():
|
||||
|
||||
# TODO: Update nonce calculation
|
||||
# Currently, the plugin always uses the current time, and the counter (tmp) is always 0.
|
||||
# What Adobe does instead is save the current time on program start, then increase tmp
|
||||
# every time a Nonce is needed.
|
||||
|
||||
dt = datetime.utcnow()
|
||||
usec = dt.microsecond
|
||||
sec = (dt - datetime(1970,1,1)).total_seconds()
|
||||
|
@ -95,11 +95,57 @@ def createDeviceFile(randomSerial: bool, useVersionIndex: int = 0):
|
||||
|
||||
return True
|
||||
|
||||
def getAuthMethodsAndCert():
|
||||
# Queries the /AuthenticationServiceInfo endpoint to get a list
|
||||
# of available ID providers.
|
||||
# Returns a list of providers, and the login certificate.
|
||||
|
||||
def createUser(useVersionIndex: int = 0):
|
||||
# The login certificate stuff would usually be handled elsewhere,
|
||||
# but that would require another request to Adobe's servers
|
||||
# which is not what we want (as ADE only performs one request, too),
|
||||
# so we need to store this cert.
|
||||
|
||||
# If you DO call this method before calling createUser,
|
||||
# it is your responsibility to pass the authCert returned by this function
|
||||
# to the createUser function call.
|
||||
# Otherwise the plugin will not look 100% like ADE to Adobe.
|
||||
|
||||
authenticationURL = VAR_ACS_SERVER_HTTP + "/AuthenticationServiceInfo"
|
||||
response2 = sendHTTPRequest(authenticationURL)
|
||||
|
||||
adobe_response_xml2 = etree.fromstring(response2)
|
||||
|
||||
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
||||
|
||||
try:
|
||||
authCert = None
|
||||
authCert = adobe_response_xml2.find("./%s" % (adNS("certificate"))).text
|
||||
except:
|
||||
pass
|
||||
|
||||
# Get sign-in methods.
|
||||
sign_in_methods = adobe_response_xml2.findall("./%s/%s" % (adNS("signInMethods"), adNS("signInMethod")))
|
||||
|
||||
aid_ids = []
|
||||
aid_names = []
|
||||
|
||||
for method in sign_in_methods:
|
||||
mid = method.get("method", None)
|
||||
txt = method.text
|
||||
|
||||
if mid != "anonymous":
|
||||
aid_ids.append(mid)
|
||||
aid_names.append(txt)
|
||||
|
||||
return [aid_ids, aid_names], authCert
|
||||
|
||||
|
||||
|
||||
|
||||
def createUser(useVersionIndex: int = 0, authCert = None):
|
||||
|
||||
if useVersionIndex >= len(VAR_VER_SUPP_CONFIG_NAMES):
|
||||
return False, "Invalid Version index"
|
||||
return False, "Invalid Version index", [[], []]
|
||||
|
||||
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
||||
|
||||
@ -138,7 +184,7 @@ def createUser(useVersionIndex: int = 0):
|
||||
certificate = adobe_response_xml.find("./%s" % (adNS("certificate"))).text
|
||||
|
||||
if (authURL is None or userInfoURL is None or certificate is None):
|
||||
return False, "Error: Unexpected reply from Adobe."
|
||||
return False, "Error: Unexpected reply from Adobe.", [[], []]
|
||||
|
||||
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "authURL")).text = authURL
|
||||
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "userInfoURL")).text = userInfoURL
|
||||
@ -150,17 +196,15 @@ def createUser(useVersionIndex: int = 0):
|
||||
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "certificate")).text = certificate
|
||||
|
||||
|
||||
authenticationURL = authURL + "/AuthenticationServiceInfo"
|
||||
response2 = sendHTTPRequest(authenticationURL)
|
||||
if authCert is None:
|
||||
# This is not supposed to happen, but if it does, then just query it again from Adobe.
|
||||
authenticationURL = authURL + "/AuthenticationServiceInfo"
|
||||
response2 = sendHTTPRequest(authenticationURL)
|
||||
|
||||
adobe_response_xml2 = etree.fromstring(response2)
|
||||
authCert = adobe_response_xml2.find("./%s" % (adNS("certificate"))).text
|
||||
|
||||
#print("======================================================")
|
||||
#print("Sending request to " + authenticationURL)
|
||||
#print("got response:")
|
||||
#print(response2)
|
||||
#print("======================================================")
|
||||
|
||||
adobe_response_xml2 = etree.fromstring(response2)
|
||||
authCert = adobe_response_xml2.find("./%s" % (adNS("certificate"))).text
|
||||
etree.SubElement(activationServiceInfo, etree.QName(NSMAP["adept"], "authenticationCertificate")).text = authCert
|
||||
|
||||
|
||||
@ -168,17 +212,16 @@ def createUser(useVersionIndex: int = 0):
|
||||
f.write("<?xml version=\"1.0\"?>\n")
|
||||
f.write(etree.tostring(root, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("latin-1"))
|
||||
f.close()
|
||||
|
||||
return True, "Done"
|
||||
|
||||
|
||||
|
||||
|
||||
def buildSignInRequest(adobeID: str, adobePassword: str, authenticationCertificate: str):
|
||||
def buildSignInRequest(type: str, username: str, password: str, authenticationCertificate: str):
|
||||
NSMAP = { "adept" : "http://ns.adobe.com/adept" }
|
||||
etree.register_namespace("adept", NSMAP["adept"])
|
||||
|
||||
root = etree.Element(etree.QName(NSMAP["adept"], "signIn"))
|
||||
root.set("method", "AdobeID")
|
||||
root.set("method", type)
|
||||
|
||||
f = open(get_devkey_path(), "rb")
|
||||
devkey_bytes = f.read()
|
||||
@ -189,10 +232,10 @@ def buildSignInRequest(adobeID: str, adobePassword: str, authenticationCertifica
|
||||
# Build buffer <devkey_bytes> <len username> <username> <len password> <password>
|
||||
|
||||
ar = bytearray(devkey_bytes)
|
||||
ar.extend(bytearray(len(adobeID).to_bytes(1, 'big')))
|
||||
ar.extend(bytearray(adobeID.encode("latin-1")))
|
||||
ar.extend(bytearray(len(adobePassword).to_bytes(1, 'big')))
|
||||
ar.extend(bytearray(adobePassword.encode("latin-1")))
|
||||
ar.extend(bytearray(len(username).to_bytes(1, 'big')))
|
||||
ar.extend(bytearray(username.encode("latin-1")))
|
||||
ar.extend(bytearray(len(password).to_bytes(1, 'big')))
|
||||
ar.extend(bytearray(password.encode("latin-1")))
|
||||
|
||||
# Crypt code from https://stackoverflow.com/a/12921889/4991648
|
||||
cert = DerSequence()
|
||||
@ -230,7 +273,7 @@ def buildSignInRequest(adobeID: str, adobePassword: str, authenticationCertifica
|
||||
|
||||
|
||||
|
||||
def signIn(username: str, passwd: str):
|
||||
def signIn(account_type: str, username: str, passwd: str):
|
||||
|
||||
|
||||
# Get authenticationCertificate
|
||||
@ -238,7 +281,9 @@ def signIn(username: str, passwd: str):
|
||||
adNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
|
||||
authenticationCertificate = activationxml.find("./%s/%s" % (adNS("activationServiceInfo"), adNS("authenticationCertificate"))).text
|
||||
|
||||
signInRequest = buildSignInRequest(username, passwd, authenticationCertificate)
|
||||
|
||||
# Type = "AdobeID" or "anonymous". For "anonymous", username and passwd need to be the empty string.
|
||||
signInRequest = buildSignInRequest(account_type, username, passwd, authenticationCertificate)
|
||||
|
||||
signInURL = activationxml.find("./%s/%s" % (adNS("activationServiceInfo"), adNS("authURL"))).text + "/SignInDirect"
|
||||
|
||||
@ -294,7 +339,8 @@ def signIn(username: str, passwd: str):
|
||||
|
||||
f.write("<adept:credentials xmlns:adept=\"http://ns.adobe.com/adept\">\n")
|
||||
f.write("<adept:user>%s</adept:user>\n" % (credentialsXML.find("./%s" % (adNS("user"))).text))
|
||||
f.write("<adept:username method=\"%s\">%s</adept:username>\n" % (credentialsXML.find("./%s" % (adNS("username"))).get("method", "AdobeID"), credentialsXML.find("./%s" % (adNS("username"))).text))
|
||||
if account_type != "anonymous":
|
||||
f.write("<adept:username method=\"%s\">%s</adept:username>\n" % (credentialsXML.find("./%s" % (adNS("username"))).get("method", account_type), credentialsXML.find("./%s" % (adNS("username"))).text))
|
||||
f.write("<adept:pkcs12>%s</adept:pkcs12>\n" % (credentialsXML.find("./%s" % (adNS("pkcs12"))).text))
|
||||
f.write("<adept:licenseCertificate>%s</adept:licenseCertificate>\n" % (credentialsXML.find("./%s" % (adNS("licenseCertificate"))).text))
|
||||
f.write("<adept:privateLicenseKey>%s</adept:privateLicenseKey>\n" % (base64.b64encode(private_key_data).decode("latin-1")))
|
||||
|
@ -56,12 +56,12 @@ def main():
|
||||
print("Error, couldn't create device file.")
|
||||
exit(1)
|
||||
|
||||
success, resp = createUser(VAR_VER)
|
||||
success, resp = createUser(VAR_VER, None)
|
||||
if (success is False):
|
||||
print("Error, couldn't create user: %s" % resp)
|
||||
exit(1)
|
||||
|
||||
success, resp = signIn(VAR_MAIL, VAR_PASS)
|
||||
success, resp = signIn("AdobeID", VAR_MAIL, VAR_PASS)
|
||||
if (success is False):
|
||||
print("Login unsuccessful: " + resp)
|
||||
exit(1)
|
||||
|
Loading…
Reference in New Issue
Block a user