From 13c7373917aeefc41e54844a0531a927cbea0d41 Mon Sep 17 00:00:00 2001 From: ttrushin Date: Tue, 9 May 2017 14:47:31 -0400 Subject: [PATCH] Added auto-reauthorization (token refresh) when a request fails due to an expired token --- CHANGES.rst | 4 ++++ blinkpy.py | 51 +++++++++++++++++++++++++++----------------- helpers/constants.py | 2 +- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index cf9e38f..2a95b40 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,6 +3,10 @@ Changelog A list of changes between each release +0.6.0.dev1 (unreleased) +^^^^^^^^^^^^^^^^^^ +- Added auto-reauthorization (token refresh) when a request fails due to an expired token + 0.6.0.dev0 (unreleased) ^^^^^^^^^^^^^^^^^^ - Removed redundent properties that only called hidden variables diff --git a/blinkpy.py b/blinkpy.py index 4ec5a75..f63caf1 100644 --- a/blinkpy.py +++ b/blinkpy.py @@ -21,9 +21,14 @@ from helpers.constants import (BLINK_URL, LOGIN_URL, LOGIN_BACKUP_URL, DEFAULT_URL, ONLINE) +def _attempt_reauthorization(blink): + """Attempt to refresh auth token""" + headers = blink.get_auth_token() + blink.set_links() + return headers -def _request(url, data=None, headers=None, reqtype='get', - stream=False, json_resp=True): +def _request(blink, url=url, data=None, headers=None, reqtype='get', + stream=False, json_resp=True, is_retry=False): """Wrapper function for request.""" if reqtype == 'post': response = requests.post(url, headers=headers, @@ -35,8 +40,13 @@ def _request(url, data=None, headers=None, reqtype='get', raise BlinkException(ERROR.REQUEST) if json_resp and 'code' in response.json(): - raise BlinkAuthenticationException( - (response.json()['code'], response.json()['message'])) + if is_retry: + raise BlinkAuthenticationException( + (response.json()['code'], response.json()['message'])) + else: + headers = _attempt_reauthorization(blink) + _request(blink, url=url, data=data, headers=headers, reqtype=reqtype, + stream=stream, json_resp=json_resp, is_retry=True) if json_resp: return response.json() @@ -75,9 +85,10 @@ class BlinkURLHandler(object): class BlinkCamera(object): """Class to initialize individual camera.""" - def __init__(self, config, urls): + def __init__(self, config, blink): """Initiailize BlinkCamera.""" - self.urls = urls + self.blink = blink + self.urls = self.blink.urls self.id = str(config['device_id']) # pylint: disable=invalid-name self.name = config['name'] self._status = config['armed'] @@ -99,15 +110,15 @@ class BlinkCamera(object): def snap_picture(self): """Take a picture with camera to create a new thumbnail.""" - _request(self.image_link, headers=self.header, reqtype='post') + _request(self.blink, url=self.image_link, headers=self.header, reqtype='post') def set_motion_detect(self, enable): """Set motion detection.""" url = self.arm_link if enable: - _request(url + 'enable', headers=self.header, reqtype='post') + _request(self.blink, url=url + 'enable', headers=self.header, reqtype='post') else: - _request(url + 'disable', headers=self.header, reqtype='post') + _request(self.blink, url=url + 'disable', headers=self.header, reqtype='post') def update(self, values): """Update camera information.""" @@ -122,7 +133,7 @@ class BlinkCamera(object): def image_refresh(self): """Refresh current thumbnail.""" url = self.urls.home_url - response = _request(url, headers=self.header, + response = _request(self.blink, url=url, headers=self.header, reqtype='get')['devices'] for element in response: try: @@ -137,7 +148,7 @@ class BlinkCamera(object): def image_to_file(self, path): """Write image to file.""" thumb = self.image_refresh() - response = _request(thumb, headers=self.header, + response = _request(self.blink, url=thumb, headers=self.header, reqtype='get', stream=True, json_resp=False) if response.status_code == 200: with open(path, 'wb') as imgfile: @@ -183,7 +194,7 @@ class Blink(object): """Get all events on server.""" url = self.urls.event_url + self.network_id headers = self._auth_header - self._events = _request(url, headers=headers, + self._events = _request(self, url=url, headers=headers, reqtype='get')['event'] return self._events @@ -192,7 +203,7 @@ class Blink(object): """Return boolean system online status.""" url = self.urls.network_url + self.network_id + '/syncmodules' headers = self._auth_header - return ONLINE[_request(url, headers=headers, + return ONLINE[_request(self, url=url, headers=headers, reqtype='get')['syncmodule']['status']] def last_motion(self): @@ -224,7 +235,7 @@ class Blink(object): else: value_to_append = 'disarm' url = self.urls.network_url + self.network_id + '/' + value_to_append - _request(url, headers=self._auth_header, reqtype='post') + _request(self, url=url, headers=self._auth_header, reqtype='post') def refresh(self): """Get all blink cameras and pulls their most recent status.""" @@ -248,7 +259,7 @@ class Blink(object): if self._auth_header is None: raise BlinkException(ERROR.AUTH_TOKEN) - return _request(url, headers=headers, reqtype='get') + return _request(self, url=url, headers=headers, reqtype='get') def get_cameras(self): """Find and creates cameras.""" @@ -258,7 +269,7 @@ class Blink(object): element['device_type'] == 'camera'): # Add region to config element['region_id'] = self.region_id - device = BlinkCamera(element, self.urls) + device = BlinkCamera(element, self) self.cameras[device.name] = device self._idlookup[device.id] = device.name @@ -306,13 +317,13 @@ class Blink(object): "password": self._password, "client_specifier": "iPhone 9.2 | 2.2 | 222" }) - response = _request(LOGIN_URL, headers=headers, + response = _request(self, url=LOGIN_URL, headers=headers, data=data, json_resp=False, reqtype='post') if response.status_code is 200: response = response.json() (self.region_id, self.region), = response['region'].items() else: - response = _request(LOGIN_BACKUP_URL, headers=headers, + response = _request(self, url=LOGIN_BACKUP_URL, headers=headers, data=data, reqtype='post') self.region_id = 'rest.piri' self.region = "UNKNOWN" @@ -325,6 +336,8 @@ class Blink(object): self.urls = BlinkURLHandler(self.region_id) + return self._auth_header + def get_ids(self): """Set the network ID and Account ID.""" url = self.urls.networks_url @@ -333,6 +346,6 @@ class Blink(object): if self._auth_header is None: raise BlinkException(ERROR.AUTH_TOKEN) - response = _request(url, headers=headers, reqtype='get') + response = _request(self, url=url, headers=headers, reqtype='get') self.network_id = str(response['networks'][0]['id']) self.account_id = str(response['networks'][0]['account_id']) diff --git a/helpers/constants.py b/helpers/constants.py index b323e12..193d50b 100644 --- a/helpers/constants.py +++ b/helpers/constants.py @@ -6,7 +6,7 @@ import os MAJOR_VERSION = 0 MINOR_VERSION = 6 -PATCH_VERSION = '0.dev0' +PATCH_VERSION = '0.dev1' __version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)