mirror of
https://github.com/inAudible-NG/audible-activator.git
synced 2024-11-18 03:18:57 +01:00
841bee290b
Using the ./ at the beginning forces the program to look in the current directly for the driver. It's much more portable to simply rely on the PATH variable.
161 lines
6.2 KiB
Python
Executable File
161 lines
6.2 KiB
Python
Executable File
#!/usr/bin/env python2
|
|
|
|
from __future__ import print_function
|
|
from getpass import getpass
|
|
from optparse import OptionParser
|
|
import sys
|
|
import time
|
|
from selenium import webdriver
|
|
from urllib import urlencode
|
|
from urlparse import urlparse, parse_qsl
|
|
import hashlib
|
|
import base64
|
|
import requests
|
|
import os
|
|
import common
|
|
import binascii
|
|
|
|
|
|
def fetch_activation_bytes(username, password, options):
|
|
base_url = 'https://www.audible.com/'
|
|
base_url_license = 'https://www.audible.com/'
|
|
lang = options.lang
|
|
|
|
# Step 0
|
|
opts = webdriver.ChromeOptions()
|
|
opts.add_argument("user-agent=Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko")
|
|
|
|
# Step 1
|
|
if '@' in username: # Amazon login using email address
|
|
login_url = "https://www.amazon.com/ap/signin?"
|
|
else: # Audible member login using username (untested!)
|
|
login_url = "https://www.audible.com/sign-in/ref=ap_to_private?forcePrivateSignIn=true&rdPath=https%3A%2F%2Fwww.audible.com%2F%3F"
|
|
if lang == "uk":
|
|
login_url = login_url.replace('.com', ".co.uk")
|
|
base_url = base_url.replace('.com', ".co.uk")
|
|
elif lang != "us": # something more clever might be needed
|
|
login_url = login_url.replace('.com', "." + lang)
|
|
base_url = base_url.replace('.com', "." + lang)
|
|
|
|
player_id = base64.encodestring(hashlib.sha1("").digest()).rstrip() # keep this same to avoid hogging activation slots
|
|
if options.player_id:
|
|
player_id = base64.encodestring(binascii.unhexlify(options.player_id)).rstrip()
|
|
print("[*] Player ID is %s" % player_id)
|
|
|
|
payload = {
|
|
'openid.ns': 'http://specs.openid.net/auth/2.0',
|
|
'openid.identity': 'http://specs.openid.net/auth/2.0/identifier_select',
|
|
'openid.claimed_id': 'http://specs.openid.net/auth/2.0/identifier_select',
|
|
'openid.mode': 'logout',
|
|
'openid.assoc_handle': 'amzn_audible_' + lang,
|
|
'openid.return_to': base_url + 'player-auth-token?playerType=software&playerId=%s=&bp_ua=y&playerModel=Desktop&playerManufacturer=Audible' % (player_id)
|
|
}
|
|
|
|
if options.firefox:
|
|
driver = webdriver.Firefox()
|
|
else:
|
|
if sys.platform == 'win32':
|
|
chromedriver_path = "chromedriver.exe"
|
|
else:
|
|
chromedriver_path = "chromedriver"
|
|
|
|
driver = webdriver.Chrome(chrome_options=opts,
|
|
executable_path=chromedriver_path)
|
|
|
|
query_string = urlencode(payload)
|
|
url = login_url + query_string
|
|
driver.get(base_url + '?ipRedirectOverride=true')
|
|
driver.get(url)
|
|
if os.getenv("DEBUG") or options.debug: # enable if you hit CAPTCHA or 2FA or other "security" screens
|
|
print("[!] Running in DEBUG mode. You will need to login in a semi-automatic way, wait for the login screen to show up ;)")
|
|
time.sleep(32)
|
|
else:
|
|
search_box = driver.find_element_by_id('ap_email')
|
|
search_box.send_keys(username)
|
|
search_box = driver.find_element_by_id('ap_password')
|
|
search_box.send_keys(password)
|
|
search_box.submit()
|
|
time.sleep(2) # give the page some time to load
|
|
|
|
# Step 2
|
|
driver.get(base_url + 'player-auth-token?playerType=software&bp_ua=y&playerModel=Desktop&playerId=%s&playerManufacturer=Audible&serial=' % (player_id))
|
|
current_url = driver.current_url
|
|
o = urlparse(current_url)
|
|
data = dict(parse_qsl(o.query))
|
|
|
|
# Step 2.5, switch User-Agent to "Audible Download Manager"
|
|
headers = {
|
|
'User-Agent': "Audible Download Manager",
|
|
}
|
|
cookies = driver.get_cookies()
|
|
s = requests.Session()
|
|
for cookie in cookies:
|
|
s.cookies.set(cookie['name'], cookie['value'])
|
|
|
|
# Step 3, de-register first, in order to stop hogging all activation slots
|
|
# (there are 8 of them!)
|
|
durl = base_url_license + 'license/licenseForCustomerToken?' \
|
|
+ 'customer_token=' + data["playerToken"] + "&action=de-register"
|
|
s.get(durl, headers=headers)
|
|
|
|
# Step 4
|
|
url = base_url_license + 'license/licenseForCustomerToken?' \
|
|
+ 'customer_token=' + data["playerToken"]
|
|
response = s.get(url, headers=headers)
|
|
|
|
with open("activation.blob", "wb") as f:
|
|
f.write(response.content)
|
|
activation_bytes, _ = common.extract_activation_bytes(response.content)
|
|
print("activation_bytes: " + activation_bytes)
|
|
|
|
# Step 5 (de-register again to stop filling activation slots)
|
|
s.get(durl, headers=headers)
|
|
|
|
# driver.get(url)
|
|
time.sleep(8)
|
|
driver.quit()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = OptionParser(usage="Usage: %prog [options]", version="%prog 0.2")
|
|
parser.add_option("-d", "--debug",
|
|
action="store_true",
|
|
dest="debug",
|
|
default=False,
|
|
help="run program in debug mode, enable this for 2FA enabled accounts or for authentication debugging")
|
|
parser.add_option("-f", "--firefox",
|
|
action="store_true",
|
|
dest="firefox",
|
|
default=False,
|
|
help="use this option to use firefox instead of chrome",)
|
|
parser.add_option("-l", "--lang",
|
|
action="store",
|
|
dest="lang",
|
|
default="us",
|
|
help="us (default) / de / fr / uk (untested)",)
|
|
parser.add_option("-p",
|
|
action="store",
|
|
dest="player_id",
|
|
default=None,
|
|
help="Player ID in hex (for debugging, not for end users)",)
|
|
parser.add_option("--username",
|
|
action="store",
|
|
dest="username",
|
|
default=False,
|
|
help="Audible username, use along with the --password option")
|
|
parser.add_option("--password",
|
|
action="store",
|
|
dest="password",
|
|
default=False,
|
|
help="Audible password")
|
|
(options, args) = parser.parse_args()
|
|
|
|
if options.username and options.password:
|
|
username = options.username
|
|
password = options.password
|
|
else:
|
|
username = raw_input("Username: ")
|
|
password = getpass("Password: ")
|
|
|
|
fetch_activation_bytes(username, password, options)
|