1+ import re
12from typing import Any
23from typing import Dict
34from typing import List
45from typing import Optional
6+ from typing import Tuple
7+ from urllib .parse import urlparse
58
69import requests
710
@@ -16,26 +19,59 @@ class ShellHub:
1619 _username : str
1720 _password : str
1821 _endpoint : str
22+ _url : str
1923 _access_token : Optional [str ]
24+ _use_ssl : bool
2025
21- def __init__ (self , username : str , password : str , endpoint : str ) -> None :
22- self ._username : str = username
23- self ._password : str = password
24- self ._endpoint : str = endpoint
25- self ._access_token : Optional [str ] = None
26+ def __init__ (self , username : str , password : str , endpoint_or_url : str , use_ssl : bool = True ) -> None :
27+ self ._username = username
28+ self ._password = password
29+ self ._use_ssl = use_ssl
30+ self ._url , self ._endpoint = self ._format_and_validate_url (endpoint_or_url )
31+ self ._access_token = None
2632
2733 self ._login ()
2834
35+ def _format_and_validate_url (self , endpoint : str ) -> Tuple [str , str ]:
36+ # Adjust the endpoint based on the _use_ssl flag
37+ if not endpoint .startswith (("http://" , "https://" )):
38+ protocol = "https://" if self ._use_ssl else "http://"
39+ endpoint = protocol + endpoint
40+
41+ # Validate the URL (basic check)
42+ if not self ._is_valid_url (endpoint ):
43+ raise ShellHubBaseException ("Invalid URL provided." )
44+
45+ # Use urlparse to extract the base endpoint without the scheme
46+ parsed_url = urlparse (endpoint )
47+ base_endpoint = parsed_url .netloc
48+
49+ return endpoint , base_endpoint # Return both full URL and base endpoint
50+
51+ @staticmethod
52+ def _is_valid_url (url : str ) -> bool :
53+ # Simple pattern to check if the URL is well-formed
54+ pattern = re .compile (
55+ r"^https?:\/\/" # http:// or https://
56+ r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|" # domain...
57+ r"localhost|" # localhost...
58+ r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" # ...or ip
59+ r"(?::\d+)?" # optional port
60+ r"(?:\/[^\s]*)?$" ,
61+ re .IGNORECASE ,
62+ ) # optional path
63+ return re .match (pattern , url ) is not None
64+
2965 def __repr__ (self ) -> str :
30- return f"<ShellHub username={ self ._username } endpoint ={ self ._endpoint } >"
66+ return f"<ShellHub username={ self ._username } url ={ self ._url } >"
3167
3268 def __str__ (self ) -> str :
33- return self ._endpoint
69+ return self ._url
3470
3571 def _login (self ) -> None :
3672 try :
3773 response = requests .post (
38- f"{ self ._endpoint } /api/login" ,
74+ f"{ self ._url } /api/login" ,
3975 json = {
4076 "username" : self ._username ,
4177 "password" : self ._password ,
@@ -69,7 +105,7 @@ def make_request(
69105 params = params [:- 1 ]
70106
71107 response : requests .Response = getattr (requests , method .lower ())(
72- f"{ self ._endpoint } { endpoint } { params if params else '' } " ,
108+ f"{ self ._url } { endpoint } { params if params else '' } " ,
73109 headers = {
74110 "Authorization" : f"Bearer { self ._access_token } " ,
75111 },
@@ -79,7 +115,7 @@ def make_request(
79115 if response .status_code == 401 :
80116 self ._login ()
81117 response = getattr (requests , method .lower ())(
82- f"{ self ._endpoint } { endpoint } { params if params else '' } " ,
118+ f"{ self ._url } { endpoint } { params if params else '' } " ,
83119 headers = {
84120 "Authorization" : f"Bearer { self ._access_token } " ,
85121 },
0 commit comments