Skip to content

Commit

Permalink
Move function for parsing backend token from url from Protocol to Bac…
Browse files Browse the repository at this point in the history
…kendToken, and reuse it in Backend code instead of relying on fragile regex. (#154)
  • Loading branch information
confluence authored Jun 18, 2024
1 parent acf0044 commit 2f9dcb6
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 49 deletions.
14 changes: 5 additions & 9 deletions carta/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ class Backend:
A backend object with a process which has not been started.
"""
FRONTEND_URL = re.compile(r"CARTA is accessible at (http://.*?:\d+/\?token=(.*))")
FRONTEND_URL_NO_AUTH = re.compile(r"CARTA is accessible at (http://(.*?):\d+.*)")
FRONTEND_URL = re.compile(r"CARTA is accessible at (http://.*)")
SESSION_ID = re.compile(r"Session (\d+) \[[\d.]+\] Connected.")

def __init__(self, params, executable_path="carta", remote_host=None, token=None, frontend_url_timeout=10, session_creation_timeout=0):
Expand Down Expand Up @@ -96,9 +95,6 @@ def start(self):
self.proc = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, cwd=pathlib.Path.home(), preexec_fn=os.setpgrp)
os.set_blocking(self.proc.stdout.fileno(), False)

frontend_url_re = self.FRONTEND_URL if not self.debug_no_auth else self.FRONTEND_URL_NO_AUTH
token_string = None

start = time.time()

while self.frontend_url is None:
Expand All @@ -112,15 +108,15 @@ def start(self):
return False

for line in self.output:
m = frontend_url_re.search(line)
m = self.FRONTEND_URL.search(line)
if m:
self.frontend_url, token_string = m.groups()
self.frontend_url = m.group(1)
break

time.sleep(1)

if token_string is not None and self.token is None and not self.debug_no_auth:
self.token = BackendToken(token_string)
if self.frontend_url is not None and self.token is None and not self.debug_no_auth:
_, self.token = BackendToken.split_token_from_url(self.frontend_url)

# Only try to parse the session ID if it has been requested
if self.session_creation_timeout > 0:
Expand Down
40 changes: 1 addition & 39 deletions carta/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class Protocol:

def __init__(self, frontend_url, token=None, debug_no_auth=False):
self.frontend_url = frontend_url
self.base_url, token_from_url = self.split_token_from_url(frontend_url)
self.base_url, token_from_url = BackendToken.split_token_from_url(frontend_url)

if debug_no_auth:
self.auth = AuthType.NONE
Expand Down Expand Up @@ -145,44 +145,6 @@ def request_refresh_token(cls, frontend_url, username, path=None):

return token

@staticmethod
def split_token_from_url(url):
"""Extract a backend token from a frontend URL.
Parameters
----------
url : string
The URL of the frontend.
Returns
-------
string
The URL with the backend token removed.
:obj:`carta.token.BackendToken` object or None
The object representing the backend token.
Raises
------
CartaBadUrl
If an invalid URL was provided.
"""
parsed_url = urllib.parse.urlparse(url)

if not (parsed_url.scheme and parsed_url.netloc):
raise CartaBadUrl(f"Could not parse URL {url}.")

parsed_query = urllib.parse.parse_qs(parsed_url.query)

base_url = parsed_url._replace(query='').geturl().rstrip("/")

if "token" not in parsed_query:
token = None
else:
token = BackendToken(parsed_query["token"][0])

return base_url, token

@property
def domain(self):
"""The domain extracted from the frontend URL.
Expand Down
40 changes: 39 additions & 1 deletion carta/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import base64
import datetime
import json
import urllib

from .util import CartaBadToken
from .util import CartaBadToken, CartaBadUrl


class Token:
Expand Down Expand Up @@ -38,6 +39,43 @@ class BackendToken(Token):
def __init__(self, string):
super().__init__(string)

@staticmethod
def split_token_from_url(url):
"""Extract a backend token from a frontend URL.
Parameters
----------
url : string
The URL of the frontend.
Returns
-------
string
The URL with the backend token removed.
:obj:`carta.token.BackendToken` object or None
The object representing the backend token.
Raises
------
CartaBadUrl
If an invalid URL was provided.
"""
parsed_url = urllib.parse.urlparse(url)

if not (parsed_url.scheme and parsed_url.netloc):
raise CartaBadUrl(f"Could not parse URL {url}.")

parsed_query = urllib.parse.parse_qs(parsed_url.query)

base_url = parsed_url._replace(query='').geturl().rstrip("/")

if "token" not in parsed_query:
token = None
else:
token = BackendToken(parsed_query["token"][0])

return base_url, token


class ControllerToken(Token):
"""An object representing a security token used by the controller. These tokens are JWTs (JSON Web Tokens) which encode additional information such as an expiration date. The controller uses multiple types of tokens. This interface makes use of long-lived refresh tokens (used to log into the controller and to obtain scripting tokens) and short-lived scripting tokens (used to make scripting requests).
Expand Down

0 comments on commit 2f9dcb6

Please sign in to comment.