Skip to content

Commit d8c449b

Browse files
committed
added host check for binary download url
1 parent 2172ec1 commit d8c449b

1 file changed

Lines changed: 25 additions & 1 deletion

File tree

browserstack/local_binary.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,33 @@
55

66
try:
77
from urllib.request import urlopen, Request
8+
from urllib.parse import urlparse
89
except ImportError:
910
from urllib2 import urlopen, Request
11+
from urlparse import urlparse
1012

1113
class LocalBinary:
1214
_version = None
15+
ALLOWED_DOWNLOAD_HOSTS = ("browserstack.com",)
16+
ALLOWED_DOWNLOAD_HOST_SUFFIXES = (".browserstack.com",)
17+
18+
@staticmethod
19+
def _validate_source_url(url):
20+
parsed = urlparse(url or "")
21+
if parsed.scheme != "https":
22+
raise BrowserStackLocalError(
23+
"Refusing binary download from non-HTTPS source URL")
24+
host = (parsed.hostname or "").lower()
25+
if not host:
26+
raise BrowserStackLocalError(
27+
"Refusing binary download: source URL has no host")
28+
if host in LocalBinary.ALLOWED_DOWNLOAD_HOSTS:
29+
return url
30+
for suffix in LocalBinary.ALLOWED_DOWNLOAD_HOST_SUFFIXES:
31+
if host.endswith(suffix):
32+
return url
33+
raise BrowserStackLocalError(
34+
"Refusing binary download: host '{}' is not in the allowed host list".format(host))
1335

1436
def __init__(self, key, error_object=None):
1537
self.key = key
@@ -64,7 +86,9 @@ def fetch_source_url(self):
6486
resp_bytes = response.read()
6587
resp_str = resp_bytes.decode('utf-8')
6688
resp_json = json.loads(resp_str)
67-
return resp_json["data"]["endpoint"]
89+
return self._validate_source_url(resp_json["data"]["endpoint"])
90+
except BrowserStackLocalError:
91+
raise
6892
except Exception as e:
6993
raise BrowserStackLocalError('Error trying to fetch the source url for downloading the binary: {}'.format(e))
7094

0 commit comments

Comments
 (0)