From 2686500d6538058680e0ec1dfbf1c013f82acd2d Mon Sep 17 00:00:00 2001 From: Athanasius Date: Mon, 12 Apr 2021 11:05:11 +0100 Subject: [PATCH 1/5] companion: Split Frontier Auth URL string over lines This way a change to one part is an easier to read diff. --- companion.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/companion.py b/companion.py index d1aca078..068d1c40 100644 --- a/companion.py +++ b/companion.py @@ -295,7 +295,14 @@ class Auth(object): logger.info(f'Trying auth from scratch for Commander "{self.cmdr}"') challenge = self.base64_url_encode(hashlib.sha256(self.verifier).digest()) webbrowser.open( - f'{SERVER_AUTH}{URL_AUTH}?response_type=code&audience=frontier,steam,epic&scope=capi&client_id={CLIENT_ID}&code_challenge={challenge}&code_challenge_method=S256&state={self.state}&redirect_uri={protocolhandler.redirect}' # noqa: E501 # I cant make this any shorter + f'{SERVER_AUTH}{URL_AUTH}?response_type=code' + f'&audience=frontier,steam,epic' + f'&scope=auth capi' + f'&client_id={CLIENT_ID}' + f'&code_challenge={challenge}' + f'&code_challenge_method=S256' + f'&state={self.state}' + f'&redirect_uri={protocolhandler.redirect}' ) return None From 5c7aa4dfa97a46a58f842a05ef9fb1dbfd8f6956 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Mon, 12 Apr 2021 12:03:11 +0100 Subject: [PATCH 2/5] companion: commented-out example of requests/http debug logging --- companion.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/companion.py b/companion.py index 068d1c40..1a0fad67 100644 --- a/companion.py +++ b/companion.py @@ -341,6 +341,13 @@ class Auth(object): 'redirect_uri': protocolhandler.redirect, } + # import http.client as http_client + # http_client.HTTPConnection.debuglevel = 1 + # import logging + # requests_log = logging.getLogger("requests.packages.urllib3") + # requests_log.setLevel(logging.DEBUG) + # requests_log.propagate = True + r = self.session.post(SERVER_AUTH + URL_TOKEN, data=request_data, timeout=auth_timeout) data = r.json() if r.status_code == requests.codes.ok: From ca08339dfe85921078ccb93e48183a9482132455 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Mon, 12 Apr 2021 12:37:17 +0100 Subject: [PATCH 3/5] companion: /decode access token and check customer_id matches FID --- companion.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/companion.py b/companion.py index 1a0fad67..0aa2bc20 100644 --- a/companion.py +++ b/companion.py @@ -56,6 +56,7 @@ CLIENT_ID = os.getenv('CLIENT_ID') or 'fb88d428-9110-475f-a3d2-dc151c2b9c7a' SERVER_AUTH = 'https://auth.frontierstore.net' URL_AUTH = '/auth' URL_TOKEN = '/token' +URL_DECODE = '/decode' USER_AGENT = f'EDCD-{appname}-{appversion()}' @@ -307,7 +308,7 @@ class Auth(object): return None - def authorize(self, payload: str) -> str: + def authorize(self, payload: str) -> str: # noqa: CCR001 """Handle oAuth authorization callback. :return: access token if successful, otherwise raises CredentialsError. @@ -349,18 +350,42 @@ class Auth(object): # requests_log.propagate = True r = self.session.post(SERVER_AUTH + URL_TOKEN, data=request_data, timeout=auth_timeout) - data = r.json() + data_token = r.json() if r.status_code == requests.codes.ok: + # Now we need to /decode the token to check the customer_id against FID + r = self.session.get( + SERVER_AUTH + URL_DECODE, + headers={ + 'Authorization': f'Bearer {data_token.get("access_token", "")}', + 'Content-Type': 'application/json', + }, + timeout=auth_timeout + ) + data_decode = r.json() + if r.status_code != requests.codes.ok: + r.raise_for_status() + + if (usr := data_decode.get('usr')) is None: + logger.error('No "usr" in /decode data') + raise CredentialsError("Error: Couldn't check token customer_id") + + if (customer_id := usr.get('customer_id')) is None: + logger.error('No "usr"->"customer_id" in /decode data') + raise CredentialsError("Error: Couldn't check token customer_id") + + if f'F{customer_id}' != monitor.state.get('FID'): + raise CredentialsError("Error: customer_id doesn't match!") + logger.info(f'Frontier CAPI Auth: New token for \"{self.cmdr}\"') cmdrs = config.get_list('cmdrs', default=[]) idx = cmdrs.index(self.cmdr) tokens = config.get_list('fdev_apikeys', default=[]) tokens = tokens + [''] * (len(cmdrs) - len(tokens)) - tokens[idx] = data.get('refresh_token', '') + tokens[idx] = data_token.get('refresh_token', '') config.set('fdev_apikeys', tokens) config.save() # Save settings now for use by command-line app - return str(data.get('access_token')) + return str(data_token.get('access_token')) except Exception as e: logger.exception(f"Frontier CAPI Auth: Can't get token for \"{self.cmdr}\"") From 0575c3ff437fb1fd4f72e503464b3d2715175e66 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Mon, 12 Apr 2021 12:38:23 +0100 Subject: [PATCH 4/5] companion: Don't over-write all CredentialsError with generic one --- companion.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/companion.py b/companion.py index 0aa2bc20..a061a74f 100644 --- a/companion.py +++ b/companion.py @@ -387,6 +387,9 @@ class Auth(object): return str(data_token.get('access_token')) + except CredentialsError: + raise + except Exception as e: logger.exception(f"Frontier CAPI Auth: Can't get token for \"{self.cmdr}\"") if r: From ffc8d2fcb8627a4cbf4010516588c5b99d7fd8d5 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Mon, 12 Apr 2021 12:52:05 +0100 Subject: [PATCH 5/5] Add comment about assuming FID always starts 'F'. --- companion.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/companion.py b/companion.py index a061a74f..f827aa9f 100644 --- a/companion.py +++ b/companion.py @@ -373,6 +373,8 @@ class Auth(object): logger.error('No "usr"->"customer_id" in /decode data') raise CredentialsError("Error: Couldn't check token customer_id") + # All 'FID' seen in Journals so far have been 'F' + # Frontier, Steam and Epic if f'F{customer_id}' != monitor.state.get('FID'): raise CredentialsError("Error: customer_id doesn't match!")