diff --git a/MyPSACC.py b/MyPSACC.py index 8fa54f8..9abc1f0 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -19,6 +19,7 @@ from typing import List import psa_connectedcar as psac from Trip import Trip from ecomix import Ecomix +from otp.Otp import load_otp, new_otp_session, save_otp from psa_connectedcar import ApiClient from psa_connectedcar.rest import ApiException from MyLogger import logger @@ -167,6 +168,7 @@ class MyPSACC: } self.remote_token_last_update = None self._record_enabled = False + self.otp = None self.weather_api = weather_api def refresh_token(self): @@ -218,6 +220,28 @@ class MyPSACC: self.get_vehicles() return list(self.vehicles_list.keys()) + def load_otp(self): + otp_session = load_otp() + if otp_session is None: + self.get_sms_otp_code() + otp_session = new_otp_session() + return otp_session + + def get_sms_otp_code(self): + res = self.manager.post( + "https://api.groupe-psa.com/applications/cvs/v4/mobile/smsCode?client_id=" + self.client_id, + headers={ + "Connection": "Keep-Alive", + "User-Agent": "okhttp/4.8.0", + "x-introspect-realm": "clientsB2CPeugeot" + }) + return res + + def getOtpCode(self): + otp_code = self.otp.getOtpCode() + save_otp(self.otp) + return otp_code + def get_remote_access_token(self, password): res = self.manager.post(remote_url + self.client_id, json={"grant_type": "password", "password": password}, @@ -242,9 +266,12 @@ class MyPSACC: self.remote_access_token = data["access_token"] self.remote_refresh_token = data["refresh_token"] self.remote_token_last_update = datetime.now() - return data["access_token"], data["refresh_token"] + return res else: - logger.error(f"can't refresh_remote_token: {data}") + logger.error(f"can't refresh_remote_token: {data}\n Create a new one") + self.remote_token_last_update = datetime.now() + otp_code = self.getOtpCode() + self.get_remote_access_token(otp_code) def on_mqtt_connect(self, client, userdata, rc, a): try: @@ -293,6 +320,7 @@ class MyPSACC: logger.error(traceback.format_exc()) def start_mqtt(self): + self.otp = self.load_otp() self.refresh_remote_token() self.mqtt_client = mqtt.Client(clean_session=True, protocol=mqtt.MQTTv311) self.mqtt_client.tls_set_context() diff --git a/abe-all.jar b/abe-all.jar deleted file mode 100644 index 3175577..0000000 Binary files a/abe-all.jar and /dev/null differ diff --git a/app_decoder.py b/app_decoder.py index 779d01f..10ebd5e 100755 --- a/app_decoder.py +++ b/app_decoder.py @@ -1,15 +1,16 @@ #!/usr/bin/env python3 import json import os -import shutil -import xml.etree.ElementTree as ET -import base64 +from androguard.core.bytecodes.apk import APK + +import requests +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.serialization import pkcs12 + from ChargeControl import ChargeControl, ChargeControls from MyPSACC import MyPSACC from sys import argv -import tarfile import sys -import traceback import re @@ -40,91 +41,99 @@ def find_preferences_xml(): return None + +def save_key_to_pem(pfx_data, pfx_password): + private_key, certificate, additional_certificates = pkcs12.load_key_and_certificates(pfx_data, bytes.fromhex(pfx_password)) + with open("public.pem", "wb") as f: + f.write(certificate.public_bytes(encoding=serialization.Encoding.PEM)) + + with open("private.pem", "wb") as f: + f.write(private_key.private_bytes(encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption())) + + current_dir = os.getcwd() script_dir = dir_path = os.path.dirname(os.path.realpath(__file__)) if sys.version_info < (3, 6): raise RuntimeError("This application requres Python 3.6+") -if argv[1].endswith(".apk"): - from androguard.core.bytecodes.apk import APK - a = APK(argv[1]) - package_name = "com.psa.mym.mypeugeot" - resources = a.get_android_resources() # .get_strings_resources() - client_id = resources.get_string(package_name, "PSA_API_CLIENT_ID_PROD")[1] - client_secret = resources.get_string(package_name, "PSA_API_CLIENT_SECRET_PROD")[1] - remote_refresh_token = None - customer_id = None - -else: - if len(argv) > 2: - password = argv[2] - else: - password = "" - res = os.system("java --version") - if res != 0: - print("You need to install java on your computer : https://www.java.com/fr/download/") - exit(1) - os.system(f"java -jar {script_dir}/abe-all.jar unpack {argv[1]} backup.tar {password}") - my_tar = tarfile.open('backup.tar') - my_tar.extractall() - dir = find_app_path() - os.chdir(dir + "/sp") - # get client id/secret - psa_pref = find_preferences_xml() - root = ET.parse(psa_pref).getroot() - client_secret = getxmlvalue(root, "CEA_CLIENT_SECRET") - client_id = getxmlvalue(root, "CEA_CLIENT_ID") - #get customer id - remote_info_file = "BASIC_AUTH_CVS.xml" - root = ET.parse(remote_info_file).getroot() - customer_id_enc = getxmlvalue(root, "CRYPTED_CUSTOMER_ID") - customer_id = base64.b64decode(customer_id_enc).decode('utf-8') - #get remote token - try: - root = ET.parse("HUTokenManager.xml").getroot() - except FileNotFoundError: - traceback.print_exc() - print("Do a remote request (start preconditioning for example) to generate a remote refresh token, " - "make a new backup and relaunch this script") - exit(1) - remote_enc = root[0].text - remote_dec = json.loads(base64.b64decode(remote_enc)) - try: - if "refresh_token" in remote_dec: - remote_refresh_token = remote_dec["refresh_token"] - # Mypeugeot >= 1.26 - else: - remote_refresh_token = next(iter(remote_dec.values()))["refresh_token"] - except: - traceback.print_exc() - print(remote_dec) - +if not argv[1].endswith(".apk"): + print("No apk given") + exit(1) +print("APK loading...") +a = APK(argv[1]) +package_name = a.get_package() +resources = a.get_android_resources() # .get_strings_resources() +client_id = resources.get_string(package_name, "PSA_API_CLIENT_ID_PROD")[1] +client_secret = resources.get_string(package_name, "PSA_API_CLIENT_SECRET_PROD")[1] +HOST_BRANDID_PROD = resources.get_string(package_name, "HOST_BRANDID_PROD")[1] +pfx_cert = a.get_file("assets/MWPMYMA1.pfx") +remote_refresh_token = None +print("APK loaded !") client_email = input("mypeugeot email: ") -client_paswword = input("mypeugeot password: ") -client_realm = input("What is the car api realm : clientsB2CPeugeot, clientsB2CCitroen, clientsB2CDS, clientsB2COpel, clientsB2CVauxhall\n") +client_password = input("mypeugeot password: ") +client_realm = input("What is the car api realm : clientsB2CPeugeot, clientsB2CCitroen, clientsB2CDS, clientsB2COpel, " + "clientsB2CVauxhall\n") +country_code = input("What is your country code ? (ex: FR, GB, DE, ES...)\n") + +## Customer id +site_code="AP_"+country_code+"_ESP" +res=requests.post(HOST_BRANDID_PROD+"/GetAccessToken", + headers={ + "Connection": "Keep-Alive", + "Content-Type": "application/json", + "Host": "id-dcr.peugeot.com", + "User-Agent": "okhttp/2.3.0" + }, + params={"jsonRequest": json.dumps({"siteCode": site_code, "culture": "fr-FR", "action": "authenticate", + "fields": {"USR_EMAIL": {"value": client_email}, + "USR_PASSWORD": {"value": client_password}}}) + } + ) + +token = res.json()["accessToken"] +save_key_to_pem(pfx_cert,"") + +res2 = requests.post("https://mw-ap-m2c.mym.awsmpsa.com/api/v1/user?culture=fr_FR&width=1080&cgu=1611656517&v=1.27.0", + data=json.dumps({"site_code":site_code, "ticket":token}), + headers={ + "Connection": "Keep-Alive", + "Content-Type": "application/json;charset=UTF-8", + "Source-Agent": "App-Android", + "Token": token, + "User-Agent": "okhttp/4.8.0", + "Version": "1.27.0" + }, + cert=("public.pem","private.pem"), +) +res_dict = res2.json()["success"] +customer_id = res_dict["dealers"]["apv"]["data"]["Brand"] + "-" + res_dict["id"] + + +# Psacc + psacc = MyPSACC(None, client_id, client_secret, remote_refresh_token, customer_id, client_realm) -psacc.connect(client_email, client_paswword) +psacc.connect(client_email, client_password) os.chdir(current_dir) psacc.save_config(name="test.json") res = psacc.get_vehicles() print(f"\nYour vehicles: {res}") +## Charge control +charge_controls = ChargeControls() +for vin, vehicle in res.items(): + chc = ChargeControl(None, vin, 100, [0, 0]) + charge_controls.list[vin] = chc +charge_controls.save_config(name="charge_config1.json") +try: + os.remove("private.pem") + os.remove("public.pem") +except: + print("Error when deleting temp files") -if not argv[1].endswith(".apk"): - try: - os.remove("backup.tar") - shutil.rmtree('apps') - except: - print("Error when deleting temp files") - charge_controls = ChargeControls() - for vin,vehicle in res.items(): - chc = ChargeControl(None,vin,100,[0,0]) - charge_controls.list[vin] = chc - charge_controls.save_config(name="charge_config1.json") - - - +print("Success !!!") \ No newline at end of file diff --git a/otp/Otp.py b/otp/Otp.py new file mode 100644 index 0000000..dd731cc --- /dev/null +++ b/otp/Otp.py @@ -0,0 +1,305 @@ +import hashlib +import random +import traceback + +import requests +from Crypto.Cipher import AES + +from math import ceil + +import Crypto + +from Crypto.PublicKey import RSA + +from collections import defaultdict +from xml.etree import cElementTree as ET + +from otp import oaep +from otp.load import IWData +import pickle +from MyLogger import logger +proxies = None + + +def etree_to_dict(t): + d = {t.tag: {} if t.attrib else None} + children = list(t) + if children: + dd = defaultdict(list) + for dc in map(etree_to_dict, children): + for k, v in dc.items(): + dd[k].append(v) + d = {t.tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}} + if t.attrib: + d[t.tag].update(('@' + k, v) for k, v in t.attrib.items()) + if t.text: + text = t.text.strip() + if children or t.attrib: + if text: + d[t.tag]['#text'] = text + else: + d[t.tag] = text + return d + + +base36 = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", + "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] + + +def numberToBase36(n): + b = 36 + if n == 0: + return [0] + digits = "" + while n: + digits += base36[int(n % b)] + n //= b + return digits + + +class Otp: + OTP_TWICE = 10 + OK=0 + kPub = "11" + exponent = int(kPub, 16) + ACTIVATE_MODE = "activate" + OTP_MODE = "otp" + MS_MODE = "ms" + iw_host = "https://otp.mpsa.com" + def __init__(self, inweboAccessId): + self.Kiw = None + self.pinmode = None + self.Kfact = None + self.Kiw = None + self.pinmode = None + self.needsync = None + self.serviceid = None + self.alias = None + self.iwalea = random.randbytes(16).hex() + self.device_id = random.randbytes(8).hex() + self.codepin = None + self.challenge = "" + self.action = "" + self.s_id = None + self.version = "0.2.11" + self.isMac = True + self.data = IWData(self) + self.cipher = None + self.macid = inweboAccessId + self.smsCode = None + self.mode = Otp.ACTIVATE_MODE + self.defi = 0 + self.otp_count = 0 + + def init(self, Kfact=None, Kiw=None, pinmode=None): + self.Kfact = Kfact + self.pinmode = pinmode + self.Kiw = self.decode_oeap(Kiw, self.Kfact) + key = RSA.construct((int(self.Kiw, 16), Otp.exponent)) + self.cipher = oaep.new(key, hashAlgo=Crypto.Hash.SHA256) + + def getSerial(self): + return self.device_id + "/_/" + self.iwalea + + def generateKMA(self, codepin): + serial = self.getSerial() + kma_str = codepin + ";" + serial + kma = hashlib.sha256(kma_str.encode("utf-8")).hexdigest()[:32] + return kma + + def getR(self): + if self.action == "upgrade": + iw = self.data.iwK1 + # not correctly implemented + else: + iw = self.data.iwK0 + if self.action == "synchro": + R2 = self.challenge + ";" + iw + ";" + self.codepin + else: + R2 = self.challenge + ";" + iw + ";" + + R0 = self.challenge + ";" + iw + ";" + self.getSerial() + R1 = self.challenge + ";" + iw + ";" + self.data.iwK1 + logger.debug(f"{R0}\n{R1}\n{R2}") + return {"R0": hashlib.sha256(R0.encode("utf-8")).hexdigest(), + "R1": hashlib.sha256(R1.encode("utf-8")).hexdigest(), + "R2": hashlib.sha256(R2.encode("utf-8")).hexdigest()} + + def decode_oeap(self, enc, key): + modulus = int(key, 16) + key = RSA.construct((modulus, Otp.exponent)) + cipher = oaep.new(key, hashAlgo=Crypto.Hash.SHA256) + block_size = 128 + dec_string = "" + enc_b = bytes.fromhex(enc) + nb_block = ceil(len(enc_b) / block_size) + + for x in range(0, nb_block): + if x == nb_block - 1: + max = len(enc_b) + else: + max = (1 + x) * 128 + min = x * 128 + ciphertext = cipher.decrypt(enc_b[min:max]) + dec_string += ciphertext.hex() + logger.debug(dec_string) + return dec_string + + def request(self, param, setup=False): + raw_xml = requests.get( + f"{self.iw_host}/iwws/MAC", + headers={ + "Connection": "Keep-Alive", + "Host": "otp.mpsa.com", + "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 8.0.0; Android SDK built for x86_64 Build/OSR1.180418.004)" + }, + params=param, + proxies=proxies, + verify=False + ).text + try: + raw_xml = raw_xml[raw_xml.index("?>") + 2:] + if setup: + return etree_to_dict(ET.XML(raw_xml))["ActionSetup"] + else: + return etree_to_dict(ET.XML(raw_xml))["ActionFinalize"] + + except: + logger.debug(raw_xml) + raise Exception("Bad return from server") + + def activation_start(self): + param = {"action": "ActionSetup", "mode": self.mode, "id": self.data.iwid, "lastsync": self.data.iwTsync, + "version": "Generator-1.0/0.2.11", "macid": self.macid} + if self.mode == Otp.OTP_MODE: + param.update({"sid": self.data.iwsecid}) + if self.mode == Otp.ACTIVATE_MODE: + param.update({"code": self.smsCode}) + + xml = self.request(param, setup=True) + if xml["err"] == "OK": + if self.mode == Otp.ACTIVATE_MODE: + xml_filtred = {key: xml[key] for key in ["Kiw", "Kfact", "pinmode"]} + self.init(**xml_filtred) + elif self.mode == Otp.OTP_MODE: + self.challenge = xml["challenge"] + return True + else: + return False + + def activation_finalyze(self, random_bytes=None): + + R = self.getR() + params = {"action": "ActionFinalize", "mode": self.mode, "id": self.data.iwid, "lastsync": self.data.iwTsync, + "version": "Generator-1.0/0.2.11", + "lang": "fr", "ack": "", "macid": self.macid} + if self.mode == Otp.OTP_MODE: + params.update({"keytype": '0', "sid": self.data.iwsecid}) + + elif self.mode == Otp.ACTIVATE_MODE: + kma_crypt = self.cipher.encrypt(bytes.fromhex(self.generateKMA(self.codepin))).hex() + pin_crypt = self.cipher.encrypt(self.codepin.encode("utf-8")).hex() + params.update({"serial": self.getSerial(), "code": self.smsCode, + "Kma": kma_crypt, "pin": pin_crypt, "name": "Android SDK built for x86_64 / UNKNOWN", }) + + params.update(R) + xml = self.request(params) + + self.data.synchro(xml, self.generateKMA(self.codepin)) + + if self.mode == Otp.OTP_MODE: + self.defi = str(xml["defi"]) + if "J" in xml: + logger.debug("Need another otp request") + return Otp.OTP_TWICE + else: + return Otp.OK + + if "ms_n" not in xml or xml["ms_n"] == 0: + logger.debug("no ms_n request needed") + return Otp.OK + + if int(xml["ms_n"]) > 1: + raise NotImplementedError + else: + ms_n = "0" + + self.challenge = xml["challenge"] + self.action = "synchro" + res = self.decode_oeap(xml["ms_key"], self.Kfact) + temp_key = RSA.construct((int(res, 16), self.exponent)) + temp_cipher = oaep.new(temp_key, hashAlgo=Crypto.Hash.SHA256) + if random_bytes is None: + random_bytes = random.randbytes(16) + KpubEncode = temp_cipher.encrypt(random_bytes) + + aes_cipher = AES.new(bytes.fromhex(self.generateKMA(self.codepin)), AES.MODE_ECB) + encodeAesFromHex = aes_cipher.encrypt(random_bytes).hex() + self.data.iwsecval = encodeAesFromHex + self.data.iwsecid = xml["s_id"] + self.data.iwsecn = 1 + + req_param = {"action": "ActionFinalize", "mode": Otp.MS_MODE, "ms_id" + ms_n: xml["ms_id"], + "ms_val" + ms_n: KpubEncode.hex(), "macid": self.macid} + req_param.update({"id": self.data.iwid, "lastsync": self.data.iwTsync, "ms_n": 1}) + req_param.update(self.getR()) + xml = self.request(req_param) + self.data.synchro(xml, self.generateKMA(self.codepin)) + return Otp.OK + + def _getOtpCode(self): + password = self.data.iwK1 + ":" + self.defi + ":" + self.data.iwsecval + res = bytes(hashlib.sha256(password.encode("utf-8")).digest()) + nb = ((int.from_bytes(res[:4], byteorder="big") & 0xfffffff) * 1024) + ( + int.from_bytes(res[4:8], byteorder="big") & 1023) + otp = numberToBase36(nb) + return otp + + def getOtpCode(self): + self.mode = Otp.OTP_MODE + self.activation_start() + res = self.activation_finalyze() + if res == Otp.OTP_TWICE: + self.mode = Otp.OTP_MODE + self.activation_start() + self.activation_finalyze() + otp_code = self._getOtpCode() + logger.debug(f"otp code: {otp_code}") + return otp_code + + def __getstate__(self): + odict = self.__dict__.copy() + del odict['cipher'] # don't pickle this + return odict + + def __setstate__(self, dict): + self.__dict__.update(dict) + if self.Kiw is not None: + key = RSA.construct((int(self.Kiw, 16), Otp.exponent)) + self.cipher = oaep.new(key, hashAlgo=Crypto.Hash.SHA256) + + +def encode_oeap(text, key): + cipher = oaep.new(bytes.fromhex(key), hashAlgo=Crypto.Hash.SHA256) + return cipher.encrypt(text) + +def save_otp(obj): + with open("otp.bin", 'wb') as output: + pickle.dump(obj, output) + +def load_otp(): + try: + with open("otp.bin", 'rb') as input: + return pickle.load(input) + except: + logger.debug(traceback.format_exc()) + return None + +def new_otp_session(): + otp = Otp("bb8e981582b0f31353108fb020bead1c") + otp.smsCode = input("What is the code you just received by SMS ?") + otp.codepin = input("What is your app pin code ?") + otp.activation_start() + otp.activation_finalyze() + save_otp(otp) + return otp \ No newline at end of file diff --git a/otp/Tokenizer.py b/otp/Tokenizer.py new file mode 100644 index 0000000..4ab35bf --- /dev/null +++ b/otp/Tokenizer.py @@ -0,0 +1,41 @@ +from locale import atoi + + +class Tokenizer(object): + def __init__(self, str, delimiter="&&"): + self.s:str = str + self.delimiter = delimiter + self.currentIndex = 0 + + def nextToken(self): + if self.currentIndex >= len(self.s): + return "" + indexOf = self.currentIndex+self.s[self.currentIndex:].index(self.delimiter) + if indexOf == -1: + substring = self.s[self.currentIndex:] + self.currentIndex = self.s.length() + return substring + + substring2 = self.s[self.currentIndex:indexOf] + self.currentIndex = indexOf + len(self.delimiter) + #print(f"{substring2} index:{self.currentIndex}") + return substring2 + + def nextTokenI(self): + token = self.nextToken() + if token == "": + return 0 + else: + return int(token, 16) + + def hasMoreTokens(self): + return self.currentIndex < len(self.s) + +# a="0.2.11&&&&&&0&&0&&0&&9f13ba238fbabba08e85d93638e98ef5e48682a9d3e5bc325c3dd6fac8199a6ce09e9b4f373aa6a75a905c3d690f6e3335d1e8e5b748ecec3020a794149033f6ada6896db6d73b8d43b8365bbe15b9ac66f49d4e684a3628f1e9f3deda0c4e24aba771946e6085b92c5ad312477152acf8db01e6aea4b409d5ac1a05c2fd4e95&&0&&&&&&&&&&&&0&&0&&0&&0&&0&&0&&0&&&&&&&&0&&0&&0&&0&&0&&2.0.0&&http://m.inwebo.com/&&" +# t=Tokenizer(a) +# self = t +# t.nextToken() +# t.nextToken() +# t.currentIndex +# t.nextTokenI() +# atoi("") \ No newline at end of file diff --git a/otp/load.py b/otp/load.py new file mode 100644 index 0000000..ff50258 --- /dev/null +++ b/otp/load.py @@ -0,0 +1,175 @@ +import hashlib +from locale import atoi +from time import time + +from Crypto.Cipher import AES + +from otp.Tokenizer import Tokenizer + +default_token="0.2.11&&&&&&0&&0&&0&&9f13ba238fbabba08e85d93638e98ef5e48682a9d3e5bc325c3dd6fac8199a6ce09e9b4f373aa6a75a905c3d690f6e3335d1e8e5b748ecec3020a794149033f6ada6896db6d73b8d43b8365bbe15b9ac66f49d4e684a3628f1e9f3deda0c4e24aba771946e6085b92c5ad312477152acf8db01e6aea4b409d5ac1a05c2fd4e95&&0&&&&&&&&&&&&0&&0&&0&&0&&0&&0&&0&&&&&&&&0&&0&&0&&0&&0&&2.0.0&&http://m.inwebo.com/&&" +default_version="529" + +def filterLoad(string:str): + return string.replace("&", "&") + +class IWData(object): + def __init__(self,IW): + self.IW=IW + self.tokenizer = Tokenizer(default_token) + self.tokenizer.nextToken() + self.load1xx(int(default_version), self.tokenizer) + + def load1xx(self, j, tokenizer): + self.iwid = tokenizer.nextToken() + self.iwalea = tokenizer.nextToken() + self.iwblocked = tokenizer.nextTokenI() + if j >= 519: + self.iwhasnopin = tokenizer.nextTokenI() + self.iwTsync = tokenizer.nextTokenI() + self.kfact = tokenizer.nextToken() + if self.IW.isMac: + self.iwconnected = tokenizer.nextTokenI() + self.iwserver = tokenizer.nextToken() + self.iwJ = tokenizer.nextToken() + self.iwK = tokenizer.nextToken() + self.iwK0 = tokenizer.nextToken() + self.iwK1 = tokenizer.nextToken() + self.iwTref = tokenizer.nextTokenI() + self.iwcancelpin = tokenizer.nextTokenI() + self.iwnboka = tokenizer.nextTokenI() + self.iwlastt1 = tokenizer.nextTokenI() + self.iwlastt2 = tokenizer.nextTokenI() + self.iwlastt3 = tokenizer.nextTokenI() + self.iwlastbp = tokenizer.nextTokenI() + self.iwstackrand = tokenizer.nextToken() + self.iwstack = tokenizer.nextToken() + self.iwH = tokenizer.nextToken() + nextTokenI = tokenizer.nextTokenI() + self.iwsrvn = nextTokenI + self.iwsrvid = [None]*(nextTokenI) + self.iwsrvname = [None]*(nextTokenI) + self.iwsrvlogo = [None]*(nextTokenI) + self.iwsrvurl = [None]*(nextTokenI) + self.iwsrvonlineotp = [None]*(nextTokenI) + if self.IW.isMac: + self.iwsrvconnected = [None]*(self.iwsrvn) + j2 = self.iwsrvn + self.iwsrvsecure = [None]*(j2) + self.iwsrvksc = [None]*(j2) + i = 0 + while i < self.iwsrvn: + self.iwsrvid[i] = tokenizer.nextToken() + self.iwsrvname[i] = filterLoad(tokenizer.nextToken()) + self.iwsrvlogo[i] = filterLoad(tokenizer.nextToken()) + if self.IW.isMac: + self.iwsrvconnected[i] = tokenizer.nextTokenI() + if j>515: + i2 = 1 + elif j ==515: + i2=0 + else: + i2=-1 + if i2 < 0 or self.IW.isMac: + self.iwsrvurl[i] = "" + else: + self.iwsrvurl[i] = filterLoad(tokenizer.nextToken()) + if j < 520 or self.IW.isMac: + self.iwsrvonlineotp[i] = 0 + else: + self.iwsrvonlineotp[i] = tokenizer.nextTokenI() + self.iwsrvsecure[i] = tokenizer.nextToken() + if i2 < 0 or not self.IW.isMac: + self.iwsrvksc[i] = "" + else: + self.iwsrvksc[i] = tokenizer.nextToken() + i += 1 + nextTokenI2 = tokenizer.nextTokenI() + self.iwsecn = nextTokenI2 + self.iwsecid = [None]*(nextTokenI2) + self.iwsecval = [None]*(nextTokenI2) + i3 = 0 + while ((i3)) < self.iwsecn: + self.iwsecid[i3] = tokenizer.nextToken() + self.iwsecval[i3] = tokenizer.nextToken() + i3 += 1 + self.iwmsgn = tokenizer.nextTokenI() + self.iwmsgtime = tokenizer.nextTokenI() + self.iwmsgid ="" + self.iwmsgtitle ="" + self.iwmsgcontent = "" + self.iwmsgack = "" + i4 = 0 + while i4 < self.iwmsgn: + self.iwmsgid+= tokenizer.nextToken() + self.iwmsgtitle+= filterLoad(tokenizer.nextToken()) + self.iwmsgcontent+=filterLoad(tokenizer.nextToken()) + self.iwmsgack += tokenizer.nextTokenI() + i4 += 1 + self.iwmajorversion = tokenizer.nextTokenI() + self.iwnewversion = filterLoad(tokenizer.nextToken()) + self.iwnewversionurl = filterLoad(tokenizer.nextToken()) + self.mustupgrade = False + self.datatouch = 0 + + def synchro(self, ixml:dict, key): + aes_cipher = AES.new(bytes.fromhex(key), AES.MODE_ECB) + """ generated source for method synchro """ + value = ixml.get("id") + if value is not None and len(value) > 0: + self.iwid = value + value = ixml.get("server") + if value is not None and len(value) > 0: + self.iwserver = value + value = ixml.get("K0") + if value is not None and len(value) > 0: + self.iwK0 = aes_cipher.decrypt(bytes.fromhex(value)).hex() + value = ixml.get("K1") + if value is not None and len(value) > 0: + self.iwK1 = aes_cipher.decrypt(bytes.fromhex(value)).hex() + value = ixml.get("dK1") + if value is not None and len(value) > 0: + self.iwK1 = hashlib.sha256(("" + self.iwK1 + ";" + value).encode("utf-8")).hexdigest()[0:32] + value = ixml.get("J") + if value is not None and len(value) > 0: + self.iwJ = value + self.iwTref = int(time()) + self.IW.otpRetryService = -1 + value = ixml.get("K") + if value is not None and len(value) > 0: + self.iwK = value + value = ixml.get("H") + if value is not None and len(value) > 0: + self.iwH = aes_cipher.decrypt(bytes.fromhex(value)) + value = ixml.get("connected") + if value is not None and len(value) > 0: + self.iwconnected = atoi(value) + int(time()) + value = ixml.get("s_n") + if value is not None and len(value) > 0: + self.iwcancelpin = 0 + self.iwnboka = 0 + self.iwlastt1 = 0 + self.iwlastt2 = 0 + self.iwlastt3 = 0 + self.iwlastbp = 0 + self.iwstackrand = "" + self.iwstack = "" + self.iwTsync = ixml.get("Tsync") + self.iwsrvn = ixml.get("s_n") + self.iwsrvid = ixml.get("s_id") + self.iwsrvname = ixml.get("s_name") + self.iwsrvlogo = ixml.get("s_icon") + self.iwsrvconnected = ixml.get("s_connected") + self.iwsrvksc = ixml.get("s_ksc") + self.iwsrvsecure = ixml.get("s_secure") + self.iwsrvurl = ixml.get("s_url") + self.iwsrvonlineotp = ixml.get("s_onlineotp") + self.IW.synchroJustDone = 1 + value = ixml.get("m_n") + if value is not None and len(value) > 0: + self.iwmsgtime = int(time()) + self.iwmsgn = ixml.get("m_n") + self.iwmsgid = ixml.get("m_id") + self.iwmsgtitle = ixml.get("m_title") + self.iwmsgcontent = ixml.get("m_content") + self.iwmsgack = ixml.get("m_ack") + self.datatouch = 1 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 840c015..1190afa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,6 +12,7 @@ flask dash_bootstrap_components geojson reverse_geocode +androguard #swagger req certifi >= 14.05.14