From 51d0b1c9dff380d523cf69142b15b01f5520e689 Mon Sep 17 00:00:00 2001 From: Lorenzo Di Fuccia Date: Thu, 6 Jun 2019 19:02:21 +0200 Subject: [PATCH] Working on #94 --- safaribooks.py | 85 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/safaribooks.py b/safaribooks.py index d39beab..6cde6af 100644 --- a/safaribooks.py +++ b/safaribooks.py @@ -18,8 +18,14 @@ from urllib.parse import urljoin, urlsplit, urlparse PATH = os.path.dirname(os.path.realpath(__file__)) COOKIES_FILE = os.path.join(PATH, "cookies.json") -SAFARI_BASE_HOST = "learning.oreilly.com" +ORLY_BASE_HOST = "oreilly.com" # PLEASE INSERT URL HERE + +SAFARI_BASE_HOST = "learning." + ORLY_BASE_HOST +API_ORIGIN_HOST = "api." + ORLY_BASE_HOST + +ORLY_BASE_URL = "https://www." + ORLY_BASE_HOST SAFARI_BASE_URL = "https://" + SAFARI_BASE_HOST +API_ORIGIN_URL = "https://" + API_ORIGIN_HOST class Display: @@ -181,8 +187,9 @@ class WinQueue(list): # TODO: error while use `process` in Windows: can't pickl class SafariBooks: + LOGIN_URL = ORLY_BASE_URL + "/member/auth/login/" + LOGIN_ENTRY_URL = SAFARI_BASE_URL + "/login/unified/?next=/home/" - LOGIN_URL = SAFARI_BASE_URL + "/accounts/login/" API_TEMPLATE = SAFARI_BASE_URL + "/api/v1/book/{0}/" HEADERS = { @@ -193,7 +200,7 @@ class SafariBooks: "cookie": "", "pragma": "no-cache", "origin": SAFARI_BASE_URL, - "referer": LOGIN_URL, + "referer": LOGIN_ENTRY_URL, "upgrade-insecure-requests": "1", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/60.0.3112.113 Safari/537.36" @@ -274,6 +281,7 @@ class SafariBooks: self.display.intro() self.cookies = {} + self.jwt = {} if not args.cred: if not os.path.isfile(COOKIES_FILE): @@ -368,7 +376,7 @@ class SafariBooks: return " ".join(["{0}={1};".format(k, v) for k, v in self.cookies.items()]) def return_headers(self, url): - if SAFARI_BASE_HOST in urlsplit(url).netloc: + if ORLY_BASE_HOST in urlsplit(url).netloc: self.HEADERS["cookie"] = self.return_cookies() else: @@ -382,7 +390,7 @@ class SafariBooks: cookie.name: cookie.value }) - def requests_provider(self, url, post=False, data=None, update_cookies=True, **kwargs): + def requests_provider(self, url, post=False, data=None, update_cookies=True, update_referer=False, **kwargs): try: response = getattr(requests, "post" if post else "get")( url, @@ -404,6 +412,10 @@ class SafariBooks: if update_cookies: self.update_cookies(response.cookies) + if update_referer: + # TODO Update Referer HTTP Header + pass + return response @staticmethod @@ -421,41 +433,41 @@ class SafariBooks: return new_cred def do_login(self, email, password): - response = self.requests_provider(self.LOGIN_URL) + response = self.requests_provider(self.LOGIN_ENTRY_URL, allow_redirects=False) + if response == 0: + self.display.exit("Login: unable to reach Safari Books Online. Try again...") + elif not response.is_redirect: + self.display.exit("Login: error? LOGIN-UPDATE-01") + + response = self.requests_provider(response.next.url, allow_redirects=False) + if response == 0: + self.display.exit("Login: unable to reach Safari Books Online. Try again...") + elif not response.is_redirect: + self.display.error("Login: error? LOGIN-UPDATE-02") + + response = self.requests_provider(response.next.url, allow_redirects=False) if response == 0: self.display.exit("Login: unable to reach Safari Books Online. Try again...") - csrf = [] - try: - csrf = html.fromstring(response.text).xpath("//input[@name='csrfmiddlewaretoken'][@value]") + redirect_uri = response.request.path_url[response.request.path_url.index("redirect_uri"):] # TODO try...catch + redirect_uri = redirect_uri[:redirect_uri.index("&")] + redirect_uri = "https://api.oreilly.com%2Fapi%2Fv1%2Fauth%2Fopenid%2Fauthorize%3F" + redirect_uri - except (html.etree.ParseError, html.etree.ParserError) as parsing_error: - self.display.error(parsing_error) - self.display.exit( - "Login: error trying to parse the home of Safari Books Online." - ) - - if not len(csrf): - self.display.exit("Login: no CSRF Token found in the page." - " Unable to continue the login." - " Try again...") - - csrf = csrf[0].attrib["value"] response = self.requests_provider( self.LOGIN_URL, post=True, - data=( - ("csrfmiddlewaretoken", csrf), - ("email", email), ("password1", password), - ("login", "Sign In"), ("next", "") - ), + json={ + "email": email, + "password": password, + "redirect_uri": redirect_uri + }, allow_redirects=False ) if response == 0: self.display.exit("Login: unable to perform auth to Safari Books Online.\n Try again...") - if response.status_code != 302: + if response.status_code != 200: # TODO To be reviewed try: error_page = html.fromstring(response.text) errors_message = error_page.xpath("//ul[@class='errorlist']//li/text()") @@ -473,6 +485,25 @@ class SafariBooks: " trying to parse the login details of Safari Books Online. Try again..." ) + self.jwt = response.json() # TODO: save JWT Tokens and use the refresh_token to restore user session + response = self.requests_provider(self.jwt["redirect_uri"], allow_redirects=False) + if response == 0: + self.display.exit("Login: unable to reach Safari Books Online. Try again...") + elif not response.is_redirect: + self.display.exit("Login: error? LOGIN-UPDATE-03") + + response = self.requests_provider(response.next.url, allow_redirects=False) + if response == 0: + self.display.exit("Login: unable to reach Safari Books Online. Try again...") + elif not response.is_redirect: + self.display.exit("Login: error? LOGIN-UPDATE-04") + + response = self.requests_provider(response.next.url) + if response == 0: + self.display.exit("Login: unable to reach Safari Books Online. Try again...") + elif not response.ok: + self.display.exit("Login: error? LOGIN-UPDATE-05") + def get_book_info(self): response = self.requests_provider(self.api_url) if response == 0: