diff --git a/.travis.yml b/.travis.yml index 81d607b..b15ac66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,6 @@ jobs: python: 3.8 - if: branch IN (master, develop) python: 3.6 - - if: branch IN (master, develop) - python: pypy - if: branch IN (master, develop) python: pypy3 diff --git a/README.rst b/README.rst index 61886c0..0c15bf2 100644 --- a/README.rst +++ b/README.rst @@ -19,8 +19,10 @@ Carson Living Python API Python Carson Living is a library written in Python that exposes the carson.live devices as Python objects. -Please note, that `Carson `_ does not provide an official API documentation, therefore this project -is solely based on reverse engineering. +Disclaimer +---------- +Please use this library at your own risk and make sure that you do not violate the +`Terms of Service of Carson `_. Getting started --------------- @@ -157,15 +159,6 @@ Checkout ``./scripts/carsoncli.py`` for further API implementation examples. Development Notes ----------------- -Request Headers -~~~~~~~~~~~~~~~ -The library currently works with the following base headers: - -.. code-block:: - - User-Agent: Carson/1.0.171 (live.carson.app; build:245; iOS 13.1.0) Alamofire/1.0.171 - X-Device-Type: ios - X-App-Version: 1.0.171(245) Code Documentation ~~~~~~~~~~~~~~~~~~ @@ -188,13 +181,6 @@ The following is not supported by the API yet and remains TODO. - Expand and extract EagleEye API (into separate project?). - -License -------- - -python-carson-living is released under the Apache License Version 2.0. See the LICENSE_ file for more -details. - Credits && Thanks ----------------- diff --git a/carson_living/auth.py b/carson_living/auth.py index 2a617a8..51fc5b3 100644 --- a/carson_living/auth.py +++ b/carson_living/auth.py @@ -10,7 +10,8 @@ from carson_living.const import (BASE_HEADERS, C_API_URI, - C_AUTH_ENDPOINT) + C_AUTH_ENDPOINT, + RETRY_TOKEN) from carson_living.util import default_carson_response_handler from carson_living.error import (CarsonAPIError, CarsonAuthenticationError, @@ -152,7 +153,7 @@ def valid_token(self): return self._token_expiration_time > int(time.time()) def authenticated_query(self, url, method='get', params=None, - json=None, retry_auth=1, + json=None, retry_auth=RETRY_TOKEN, response_handler=default_carson_response_handler): """Perform an authenticated Query against Carson Living diff --git a/carson_living/const.py b/carson_living/const.py index 7b4bd8d..a93daf3 100644 --- a/carson_living/const.py +++ b/carson_living/const.py @@ -8,34 +8,19 @@ 'MSG': 'msg' } -"""Pretend to be Carson iOS Installation v1.0.171""" BASE_HEADERS = { - 'User-Agent': 'Carson/1.0.200 (live.carson.app; build:315; iOS 13.3.0) ' - 'Alamofire/1.0.200', - 'X-App-Version': '1.0.200(315)', - 'X-Device-Type': 'ios' + 'User-Agent': 'okhttp/4.9.0', + 'X-App-Version': '2.1.5', + 'X-Device-Type': 'android' } # number of attempts to refresh token -# RETRY_TOKEN = 3 - -# default suffix for session cache file -# CACHE_ATTRS = {'account': None, 'alerts': None, 'token': None} -# -# try: -# CACHE_FILE = os.path.join(os.getenv("HOME"), -# '.carson_living-session.cache') -# except (AttributeError, TypeError): -# CACHE_FILE = os.path.join('.', '.carson_living-session.cache') - - -# code when item was not found -# NOT_FOUND = -1 +RETRY_TOKEN = 1 # Carson API endpoints # Beware URLs end in '/', otherwise it returns a # HTTP/1.1 301 Moved Permanently to the correct version. -C_API_VERSION = 'v1.4.3' +C_API_VERSION = 'v1.4.4' C_API_URI = 'https://api.carson.live/api/' + C_API_VERSION C_AUTH_ENDPOINT = '/auth/login/' diff --git a/requirements.txt b/requirements.txt index b126a46..4e1cb1e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -requests -pyjwt +requests==2.25.1 +PyJWT==2.4.0 diff --git a/setup.py b/setup.py index 57820b9..733de34 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ """Python Carson Living setup script.""" from setuptools import setup -_VERSION = '0.0.5' +_VERSION = '0.0.6' def readme(): diff --git a/tests/test_auth.py b/tests/test_auth.py index 005fb94..46958c1 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -67,7 +67,7 @@ def test_auth_valid_token_init(self): @requests_mock.Mocker() def test_update_token_success(self, mock): """Test token update""" - mock.post('https://api.carson.live/api/v1.4.3/auth/login/', + mock.post('https://api.carson.live/api/v1.4.4/auth/login/', text=load_fixture('carson.live', 'carson_login.json')) mock_token_update_cb = Mock() @@ -89,7 +89,7 @@ def test_update_token_success(self, mock): @requests_mock.Mocker() def test_update_token_fail(self, mock): """Test authentication failure in token update""" - mock.post('https://api.carson.live/api/v1.4.3/auth/login/', + mock.post('https://api.carson.live/api/v1.4.4/auth/login/', text=load_fixture('carson.live', 'carson_auth_failure.json'), status_code=401) @@ -110,9 +110,9 @@ def test_expired_token_is_invalid(self): @requests_mock.Mocker() def test_successful_query_without_initial_token(self, mock): """Test automatic authentication on query without initial token""" - mock.post('https://api.carson.live/api/v1.4.3/auth/login/', + mock.post('https://api.carson.live/api/v1.4.4/auth/login/', text=load_fixture('carson.live', 'carson_login.json')) - query_url = 'https://api.carson.live/api/v1.4.3/me/' + query_url = 'https://api.carson.live/api/v1.4.4/me/' mock.get(query_url, text=load_fixture('carson.live', 'carson_me.json')) @@ -129,7 +129,7 @@ def test_successful_query_without_initial_token(self, mock): @requests_mock.Mocker() def test_successful_query_with_initial_token(self, mock): """Test query with initial valid token""" - query_url = 'https://api.carson.live/api/v1.4.3/me/' + query_url = 'https://api.carson.live/api/v1.4.4/me/' mock.get(query_url, text=load_fixture('carson.live', 'carson_me.json')) @@ -148,9 +148,9 @@ def test_successful_query_with_initial_token(self, mock): @requests_mock.Mocker() def test_recursive_retry(self, mock): """"Test recursive query retry on Authentication Failure""" - mock.post('https://api.carson.live/api/v1.4.3/auth/login/', + mock.post('https://api.carson.live/api/v1.4.4/auth/login/', text=load_fixture('carson.live', 'carson_login.json')) - query_url = 'https://api.carson.live/api/v1.4.3/me/' + query_url = 'https://api.carson.live/api/v1.4.4/me/' mock.get(query_url, text=load_fixture('carson.live', 'carson_auth_failure.json'), status_code=401) @@ -169,7 +169,7 @@ def test_recursive_retry(self, mock): @requests_mock.Mocker() def test_raise_communication_error_on_empty(self, mock): """Test failure on empty response""" - query_url = 'https://api.carson.live/api/v1.4.3/me/' + query_url = 'https://api.carson.live/api/v1.4.4/me/' mock.get(query_url, status_code=500) @@ -185,7 +185,7 @@ def test_raise_communication_error_on_empty(self, mock): @requests_mock.Mocker() def test_raise_communication_error_wrong_json(self, mock): """Test failure on response with missing keys""" - query_url = 'https://api.carson.live/api/v1.4.3/me/' + query_url = 'https://api.carson.live/api/v1.4.4/me/' mock.get(query_url, text=load_fixture('carson.live', 'carson_missing_keys.json'))