Skip to content

Commit debbb50

Browse files
committed
Handle multiple time formats for SSL cert expiry time. by: Conrad, Giles
1 parent a924ae7 commit debbb50

File tree

4 files changed

+39
-4
lines changed

4 files changed

+39
-4
lines changed

pythonanywhere/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import getpass
22
import os
3-
from datetime import datetime
43
from pathlib import Path
54
from textwrap import dedent
65

6+
from dateutil.parser import parse
77
import requests
88

99
from pythonanywhere.exceptions import SanityException
@@ -162,7 +162,7 @@ def get_ssl_info(self):
162162
)
163163

164164
result = response.json()
165-
result["not_after"] = datetime.strptime(result["not_after"], "%Y%m%dT%H%M%SZ")
165+
result["not_after"] = parse(result["not_after"])
166166
return result
167167

168168
def delete_log(self, log_type, index=0):

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ psutil==5.4.0
99
py==1.7.0
1010
pytest==3.2.3
1111
pytest-cov==2.6.0
12+
python-dateutil==2.7.5
1213
requests==2.18.4
1314
responses==0.8.1
1415
six==1.11.0

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
install_requires=[
3333
'docopt',
3434
'requests',
35+
'python-dateutil',
3536
],
3637
extras_require={},
3738
python_requires='>=3.5',

tests/test_api.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from unittest.mock import patch
55
from urllib.parse import urlencode
66

7+
from dateutil.tz import tzutc
78
import pytest
89
import responses
910
from pythonanywhere.api import PYTHON_VERSIONS, AuthenticationError, Webapp, call_api, get_api_endpoint
@@ -277,7 +278,9 @@ def test_raises_if_post_does_not_20x(self, api_responses, api_token):
277278

278279

279280
class TestGetWebappSSLInfo:
280-
def test_returns_json_from_server_having_parsed_expiry(self, api_responses, api_token):
281+
def test_returns_json_from_server_having_parsed_expiry_with_z_for_utc_and_no_separators(
282+
self, api_responses, api_token
283+
):
281284
expected_url = get_api_endpoint().format(username=getpass.getuser(), flavor="webapps") + "mydomain.com/ssl/"
282285
api_responses.add(
283286
responses.GET,
@@ -294,7 +297,37 @@ def test_returns_json_from_server_having_parsed_expiry(self, api_responses, api_
294297
)
295298

296299
assert Webapp("mydomain.com").get_ssl_info() == {
297-
"not_after": datetime(2018, 8, 24, 17, 16, 23),
300+
"not_after": datetime(2018, 8, 24, 17, 16, 23, tzinfo=tzutc()),
301+
"issuer_name": "PythonAnywhere test CA",
302+
"subject_name": "www.mycoolsite.com",
303+
"subject_alternate_names": ["www.mycoolsite.com", "mycoolsite.com"],
304+
}
305+
306+
get = api_responses.calls[0]
307+
assert get.request.method == "GET"
308+
assert get.request.url == expected_url
309+
assert get.request.headers["Authorization"] == "Token {api_token}".format(api_token=api_token)
310+
311+
def test_returns_json_from_server_having_parsed_expiry_with_timezone_offset_and_separators(
312+
self, api_responses, api_token
313+
):
314+
expected_url = get_api_endpoint().format(username=getpass.getuser(), flavor="webapps") + "mydomain.com/ssl/"
315+
api_responses.add(
316+
responses.GET,
317+
expected_url,
318+
status=200,
319+
body=json.dumps(
320+
{
321+
"not_after": "2018-08-24T17:16:23+00:00",
322+
"issuer_name": "PythonAnywhere test CA",
323+
"subject_name": "www.mycoolsite.com",
324+
"subject_alternate_names": ["www.mycoolsite.com", "mycoolsite.com"],
325+
}
326+
),
327+
)
328+
329+
assert Webapp("mydomain.com").get_ssl_info() == {
330+
"not_after": datetime(2018, 8, 24, 17, 16, 23, tzinfo=tzutc()),
298331
"issuer_name": "PythonAnywhere test CA",
299332
"subject_name": "www.mycoolsite.com",
300333
"subject_alternate_names": ["www.mycoolsite.com", "mycoolsite.com"],

0 commit comments

Comments
 (0)