Only refresh token on unauthorized response from request

This commit is contained in:
Kevin Fronczak
2020-05-27 23:05:51 +00:00
parent 6a5256e9b1
commit 9e124ce5cc
5 changed files with 60 additions and 18 deletions
+32 -14
View File
@@ -5,7 +5,6 @@ from requests import Request, Session, exceptions
from blinkpy import api
from blinkpy.helpers import util
from blinkpy.helpers.constants import BLINK_URL, LOGIN_ENDPOINT
from blinkpy.helpers import errors as ERROR
_LOGGER = logging.getLogger(__name__)
@@ -95,7 +94,10 @@ class Auth:
self.token = self.login_response["authtoken"]["authtoken"]
self.client_id = self.login_response["client"]["id"]
self.account_id = self.login_response["account"]["id"]
except KeyError:
except LoginError:
_LOGGER.error("Login endpoint failed. Try again later.")
raise TokenRefreshFailed
except (TypeError, KeyError):
_LOGGER.error("Malformed login response: %s", self.login_response)
raise TokenRefreshFailed
return True
@@ -110,11 +112,12 @@ class Auth:
"""Check for valid response."""
if not json_resp:
return response
try:
json_data = response.json()
if json_data["code"] in ERROR.BLINK_ERRORS:
if response.status_code in [101, 401]:
raise UnauthorizedError
if response.status_code == 404:
raise exceptions.ConnectionError
json_data = response.json()
except KeyError:
pass
except (AttributeError, ValueError):
@@ -141,31 +144,42 @@ class Auth:
:param reqtype: Can be 'get' or 'post' (default: 'get')
:param stream: Stream response? True/FALSE
:param json_resp: Return JSON response? TRUE/False
:param is_retry: Is this a retry attempt? True/FALSE
:param is_retry: Is this part of a re-auth attempt? True/FALSE
"""
req = self.prepare_request(url, headers, data, reqtype)
try:
response = self.session.send(req, stream=stream)
return self.validate_response(response, json_resp)
except (exceptions.ConnectionError, exceptions.Timeout, TokenRefreshFailed):
except (exceptions.ConnectionError, exceptions.Timeout):
_LOGGER.error(
"Connection error. Endpoint %s possibly down or throttled. %s: %s",
url,
response.status_code,
response.reason,
)
except BlinkBadResponse:
_LOGGER.error(
"Expected json response from %s, but received: %s: %s",
url,
response.status_code,
response.reason,
)
except UnauthorizedError:
try:
if not is_retry:
self.refresh_token()
return self.query(
url=url,
data=data,
headers=headers,
headers=self.header,
reqtype=reqtype,
stream=stream,
json_resp=json_resp,
is_retry=True,
)
except (TokenRefreshFailed, LoginError):
_LOGGER.error("Endpoint %s failed. Unable to refresh login tokens", url)
except BlinkBadResponse:
_LOGGER.error("Expected json response, but received: %s", response)
_LOGGER.error("Endpoint %s failed", url)
_LOGGER.error("Unable to access %s after token refresh.", url)
except TokenRefreshFailed:
_LOGGER.error("Unable to refresh token.")
return None
def send_auth_key(self, blink, key):
@@ -200,3 +214,7 @@ class LoginError(Exception):
class BlinkBadResponse(Exception):
"""Class to throw bad json response exception."""
class UnauthorizedError(Exception):
"""Class to throw an unauthorized access error."""
-1
View File
@@ -78,7 +78,6 @@ class Blink:
"""
if self.check_if_ok_to_update() or force:
if not self.available:
self.auth.refresh_token()
self.setup_post_verify()
for sync_name, sync_module in self.sync.items():
+1 -1
View File
@@ -12,4 +12,4 @@ AUTH_TOKEN = (
)
REQUEST = (4, "Cannot perform request (get/post type incorrect)")
BLINK_ERRORS = [101, 400, 404]
BLINK_ERRORS = [400, 404]
+1
View File
@@ -9,6 +9,7 @@ class MockResponse:
self.json_data = json_data
self.status_code = status_code
self.raw_data = raw_data
self.reason = "foobar"
def json(self):
"""Return json data from get_request."""
+26 -2
View File
@@ -3,7 +3,13 @@
import unittest
from unittest import mock
from requests import exceptions
from blinkpy.auth import Auth, LoginError, TokenRefreshFailed, BlinkBadResponse
from blinkpy.auth import (
Auth,
LoginError,
TokenRefreshFailed,
BlinkBadResponse,
UnauthorizedError,
)
import blinkpy.helpers.constants as const
import tests.mock_responses as mresp
@@ -90,6 +96,10 @@ class TestAuth(unittest.TestCase):
with self.assertRaises(exceptions.ConnectionError):
self.auth.validate_response(fake_resp, True)
fake_resp = mresp.MockResponse({"code": 101}, 401)
with self.assertRaises(UnauthorizedError):
self.auth.validate_response(fake_resp, True)
def test_good_response_code(self):
"""Check good response code from server."""
fake_resp = mresp.MockResponse({"foo": "bar"}, 200)
@@ -133,6 +143,8 @@ class TestAuth(unittest.TestCase):
mock_req.return_value = fake_resp
with self.assertRaises(LoginError):
self.auth.login()
with self.assertRaises(TokenRefreshFailed):
self.auth.refresh_token()
@mock.patch("blinkpy.auth.Auth.login")
def test_refresh_token(self, mock_login):
@@ -197,10 +209,22 @@ class TestAuth(unittest.TestCase):
def test_query_retry(self, mock_refresh, mock_validate):
"""Check handling of request retry."""
self.auth.session = MockSession()
mock_validate.side_effect = [TokenRefreshFailed, "foobar"]
mock_validate.side_effect = [UnauthorizedError, "foobar"]
mock_refresh.return_value = True
self.assertEqual(self.auth.query(url="http://example.com"), "foobar")
@mock.patch("blinkpy.auth.Auth.validate_response")
@mock.patch("blinkpy.auth.Auth.refresh_token")
def test_query_retry_failed(self, mock_refresh, mock_validate):
"""Check handling of failed retry request."""
self.auth.seession = MockSession()
mock_validate.side_effect = [UnauthorizedError, BlinkBadResponse]
mock_refresh.return_value = True
self.assertEqual(self.auth.query(url="http://example.com"), None)
mock_validate.side_effect = [UnauthorizedError, TokenRefreshFailed]
self.assertEqual(self.auth.query(url="http://example.com"), None)
class MockSession:
"""Object to mock a session."""