From 610f20310859f71ce00785152838e5cd875ecde7 Mon Sep 17 00:00:00 2001 From: Colin Frei Date: Mon, 22 Apr 2019 16:05:40 +0200 Subject: [PATCH] Update to v2 of Landroid API Some auth changes, based on https://github.com/MeisterTR/ioBroker.landroid-s/commit/5b61b2ac81896cb809358d82c07011902308f27c The ident code (step_one, ...) seems to also be from https://stackoverflow.com/questions/18279141/javascript-string-encryption-and-decryption --- pylandroidcloud/pylandroidcloud.py | 62 +++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/pylandroidcloud/pylandroidcloud.py b/pylandroidcloud/pylandroidcloud.py index e11ee8f..dfdbc60 100644 --- a/pylandroidcloud/pylandroidcloud.py +++ b/pylandroidcloud/pylandroidcloud.py @@ -36,9 +36,14 @@ def __init__(self, username, password, on_message): #API Calls def authenticate(self, username, password): auth_data = self.api.auth(username, password) - self.api.set_token(auth_data['api_token']) - self.mqtt_client_id = auth_data['mqtt_client_id'] - self.endpoint = auth_data['mqtt_endpoint'] + + self.api.set_token(auth_data['access_token']) + self.api.set_token_type(auth_data['token_type']) + + profile = self.api.get_profile() + self.endpoint = profile['mqtt_endpoint'] + + self.mqtt_client_id = 'android-' + self.api.uuid @contextlib.contextmanager def get_cert(self): @@ -108,35 +113,66 @@ def pfx_to_pem(pfx_data): yield t_pem.name class LandroidApi: - WORX_API_BASE = "https://api.worxlandroid.com/api/v1" + #TODO: make this nicer + WORX_API_HOST = "api.worxlandroid.com" + WORX_API_BASE = "https://api.worxlandroid.com/api/v2" def __init__(self): - self.token = 'qiJNz3waS4I99FPvTaPt2C2R46WXYdhw' + self.token = self.generate_identify_token('725f542f5d2c4b6a5145722a2a6a5b736e764f6e725b462e4568764d4b58755f6a767b2b76526457') + self.token_type = 'app' def set_token(self, token): self.token = token + def set_token_type(self, token_type): + self.token_type = token_type + + def generate_identify_token(self, input): + # split api url into letters and get ascii code for each + text_to_char = [ord(c) for c in self.WORX_API_HOST] + + import re + step_one = re.findall(r".{1,2}", input) + step_two = list(map((lambda hex: int(hex, 16)), step_one)) + + import functools + import operator + step_three = list(map((lambda foo: functools.reduce((lambda x, y: operator.xor(x, y)), text_to_char, foo)), step_two)) + step_four = list(map(chr, step_three)) + + final = ''.join(step_four) + return final + def get_headers(self): header_data = {} header_data['Content-Type'] = 'application/json' - header_data['X-Auth-Token'] = self.token + header_data['Authorization'] = self.token_type + ' ' + self.token return header_data - def auth(self, username, password, platform='android', type='app'): + def auth(self, username, password, type='app'): import uuid import json + self.uuid = str(uuid.uuid1()) + + payload_data = {} - payload_data['email'] = username + payload_data['username'] = username payload_data['password'] = password - payload_data['platform'] = platform + payload_data['grant_type'] = "password" + payload_data['client_id'] = 1 payload_data['type'] = type - payload_data['uuid'] = str(uuid.uuid1()) + payload_data['client_secret'] = self.token + payload_data['scope'] = "*" + payload_data['uuid'] = self.uuid payload = json.dumps(payload_data) - return self.call('/users/auth', payload) + return self.call('/oauth/token', payload) + + def get_profile(self): + return self.call('/users/me') def get_cert(self): return self.call('/users/certificate') @@ -154,7 +190,7 @@ def call(self, path, payload=None): if not req.ok: _LOGGER.error("Error when calling Worx Landroid API. Status Code %s", req.status_code) - + _LOGGER.error(req.text) return False - return req.json() \ No newline at end of file + return req.json()