Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix and streamline code for parsing URL and optional token from backend output #154

Merged
merged 2 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading