From 6723d6ce71afe353447290e4d440688c74841272 Mon Sep 17 00:00:00 2001 From: Jimmy Everling Date: Wed, 14 Jul 2021 12:48:06 +0200 Subject: [PATCH 1/2] Added automatic app version detection --- pcomfortcloud/constants.py | 2 ++ pcomfortcloud/session.py | 25 +++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/pcomfortcloud/constants.py b/pcomfortcloud/constants.py index 6e625d7..8e30419 100644 --- a/pcomfortcloud/constants.py +++ b/pcomfortcloud/constants.py @@ -58,3 +58,5 @@ class NanoeMode(Enum): On = 2 ModeG = 3 All = 4 + +DEFAULT_X_APP_VERSION = "1.12.0" \ No newline at end of file diff --git a/pcomfortcloud/session.py b/pcomfortcloud/session.py index 57bc3bf..886d4a3 100644 --- a/pcomfortcloud/session.py +++ b/pcomfortcloud/session.py @@ -52,16 +52,20 @@ class Session(object): """ - def __init__(self, username, password, tokenFileName='~/.panasonic-token', raw=False, verifySsl=True): + def __init__(self, username, password, tokenFileName='~/.panasonic-token', raw=False, verifySsl=True, appVersion='auto'): self._username = username self._password = password self._tokenFileName = os.path.expanduser(tokenFileName) self._vid = None + + self._appVersion = None self._groups = None self._devices = None self._deviceIndexer = {} self._raw = raw + self._setAppVersion(appVersion) + if verifySsl == False: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) self._verifySsl = verifySsl @@ -108,13 +112,30 @@ def logout(self): def _headers(self): return { "X-APP-TYPE": "1", - "X-APP-VERSION": "1.10.0", + "X-APP-VERSION": self._appVersion, "X-User-Authorization": self._vid, "User-Agent": "G-RAC", "Accept": "application/json", "Content-Type": "application/json" } + def _setAppVersion(self, version): + self._appVersion = constants.DEFAULT_X_APP_VERSION + if version.lower() != 'auto': + self._appVersion = version + return + if self._raw: print("--- auto detecting latest app version") + try: + data = requests.get("https://itunes.apple.com/lookup?id=1348640525").json() + version = data['results'][0]['version'] + if version is not None: + if self._raw: print("--- found version: {}".format(version)) + self._appVersion = version + return + except: + pass + if self._raw: print("--- failed to detect app version using default version: {}".format(constants.DEFAULT_X_APP_VERSION)) + def _create_token(self): response = None From 0b48f0a3ad17331b41aeae12d7dc553ec9d3f79b Mon Sep 17 00:00:00 2001 From: Jimmy Everling Date: Thu, 15 Jul 2021 21:40:32 +0200 Subject: [PATCH 2/2] Added new settings structure to store token and app version information --- pcomfortcloud/constants.py | 8 +++- pcomfortcloud/session.py | 34 ++++++++-------- pcomfortcloud/settings.py | 80 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 19 deletions(-) create mode 100644 pcomfortcloud/settings.py diff --git a/pcomfortcloud/constants.py b/pcomfortcloud/constants.py index 8e30419..2eb926a 100644 --- a/pcomfortcloud/constants.py +++ b/pcomfortcloud/constants.py @@ -59,4 +59,10 @@ class NanoeMode(Enum): ModeG = 3 All = 4 -DEFAULT_X_APP_VERSION = "1.12.0" \ No newline at end of file +DEFAULT_X_APP_VERSION = "1.12.0" + +MAX_VERSION_AGE = 5 + +SETTING_TOKEN = "token" +SETTING_VERSION = "version" +SETTING_VERSION_DATE = "versionDate" \ No newline at end of file diff --git a/pcomfortcloud/session.py b/pcomfortcloud/session.py index 886d4a3..85bb5bf 100644 --- a/pcomfortcloud/session.py +++ b/pcomfortcloud/session.py @@ -8,8 +8,10 @@ import urllib3 import hashlib + from . import urls from . import constants +from .settings import PanasonicSettings def _validate_response(response): """ Verify that response is OK """ @@ -52,20 +54,18 @@ class Session(object): """ - def __init__(self, username, password, tokenFileName='~/.panasonic-token', raw=False, verifySsl=True, appVersion='auto'): + def __init__(self, username, password, settingsFileName='~/.panasonic-settings', raw=False, verifySsl=True): self._username = username self._password = password - self._tokenFileName = os.path.expanduser(tokenFileName) + self._settings = PanasonicSettings(os.path.expanduser(settingsFileName)) self._vid = None - self._appVersion = None + self._appVersion = self._settings._version self._groups = None self._devices = None self._deviceIndexer = {} self._raw = raw - self._setAppVersion(appVersion) - if verifySsl == False: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) self._verifySsl = verifySsl @@ -73,6 +73,9 @@ def __init__(self, username, password, tokenFileName='~/.panasonic-token', raw=F self._verifySsl = os.path.join(os.path.dirname(__file__), "certificatechain.pem") + if self._settings.version_expired: + self._updateAppVersion() + def __enter__(self): self.login() return self @@ -83,10 +86,8 @@ def __exit__(self, exc_type, exc_val, exc_tb): def login(self): """ Login to verisure app api """ - if os.path.exists(self._tokenFileName): - with open(self._tokenFileName, 'r') as cookieFile: - self._vid = cookieFile.read().strip() - + if self._settings.token is not None: + self._vid = self._settings.token if self._raw: print("--- token found") try: @@ -97,12 +98,11 @@ def login(self): self._vid = None self._devices = None - os.remove(self._tokenFileName) + self._settings.token = None if self._vid is None: self._create_token() - with open(self._tokenFileName, 'w') as tokenFile: - tokenFile.write(self._vid) + self._settings.token = self._vid self._get_groups() @@ -119,11 +119,8 @@ def _headers(self): "Content-Type": "application/json" } - def _setAppVersion(self, version): - self._appVersion = constants.DEFAULT_X_APP_VERSION - if version.lower() != 'auto': - self._appVersion = version - return + def _updateAppVersion(self): + if self._raw: print("--- auto detecting latest app version") try: data = requests.get("https://itunes.apple.com/lookup?id=1348640525").json() @@ -131,10 +128,11 @@ def _setAppVersion(self, version): if version is not None: if self._raw: print("--- found version: {}".format(version)) self._appVersion = version + self._settings.version = version return except: pass - if self._raw: print("--- failed to detect app version using default version: {}".format(constants.DEFAULT_X_APP_VERSION)) + if self._raw: print("--- failed to detect app version using version: {}".format(self._appVersion)) def _create_token(self): response = None diff --git a/pcomfortcloud/settings.py b/pcomfortcloud/settings.py new file mode 100644 index 0000000..f4e44c5 --- /dev/null +++ b/pcomfortcloud/settings.py @@ -0,0 +1,80 @@ +import json +import os +from datetime import date +from packaging import version + +from .constants import ( + SETTING_TOKEN, + SETTING_VERSION, + SETTING_VERSION_DATE, + + DEFAULT_X_APP_VERSION, + MAX_VERSION_AGE +) + +class PanasonicSettings: + + def __init__(self, fileName): + self._fileName = fileName + self._token = None + self._version = None + self._versionDate = None + self._load() + + def _load(self): + if not os.path.exists(self._fileName): + return + try: + with open(self._fileName) as json_file: + data = json.load(json_file) + self._token = data[SETTING_TOKEN] + self._version = data[SETTING_VERSION] + self._versionDate = date.fromisoformat(data[SETTING_VERSION_DATE]) + except: + pass + + def _save(self): + data = {} + data[SETTING_TOKEN] = self._token + data[SETTING_VERSION] = self._version + data[SETTING_VERSION_DATE] = self._versionDate.isoformat() + with open(self._fileName, 'w') as outfile: + json.dump(data, outfile) + + @property + def token(self): + return self._token + + @token.setter + def token(self, value): + if self._token == value: + return + self._token = value + self._save() + + @property + def version(self): + if self._version is None: + return DEFAULT_X_APP_VERSION + return self._version + + @version.setter + def version(self,value): + if value is None: + return + if (self._version is None + or version.parse(self._version) < version.parse(value)): + self._version = value + self._versionDate = date.today() + self._save() + + @property + def version_expired(self): + if self._version is None: + return True + if self._versionDate is None: + return True + delta = date.today() - self._versionDate + if (delta.days < MAX_VERSION_AGE): + return False + return True