check if apk changed

This commit is contained in:
Florian Bezannier
2021-12-01 20:41:28 +01:00
parent 21c2d7754f
commit acddabdf47
6 changed files with 150 additions and 68 deletions
+7 -1
View File
@@ -29,4 +29,10 @@ DEFAULT_PRECONDITIONING_PROGRAM = {
"program4": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0}
}
AUTHORIZE_SERVICE = "https://api.mpsa.com/api/connectedcar/v2/oauth/authorize"
REMOTE_URL = "https://api.groupe-psa.com/connectedcar/v4/virtualkey/remoteaccess/token?client_id="
REMOTE_URL = "https://api.groupe-psa.com/connectedcar/v4/virtualkey/remoteaccess/token?client_id="
BRAND = {"com.psa.mym.myopel": {"realm": "clientsB2COpel", "brand_code": "OP", "app_name": "MyOpel"},
"com.psa.mym.mypeugeot": {"realm": "clientsB2CPeugeot", "brand_code": "AP", "app_name": "MyPeugeot"},
"com.psa.mym.mycitroen": {"realm": "clientsB2CCitroen", "brand_code": "AC", "app_name": "MyCitroen"},
"com.psa.mym.myds": {"realm": "clientsB2CDS", "brand_code": "DS", "app_name": "MyDS"},
"com.psa.mym.myvauxhall": {"realm": "clientsB2CVauxhall", "brand_code": "VX", "app_name": "MyVauxhall"}
}
+54
View File
@@ -0,0 +1,54 @@
import json
import os
from androguard.core.bytecodes.apk import APK
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.serialization import pkcs12
from libs.psa.constants import BRAND
class ApkParser:
def __init__(self, filename, country_code):
self.country_code = country_code
self.filename = filename
self.host_brandid_prod = None
self.site_code = None
self.culture = None
self.client_id = None
self.client_secret = None
@staticmethod
def __get_cultures_code(file, country_code):
cultures = json.loads(file)
return cultures[country_code]["languages"][0]
def retrieve_content_from_apk(self):
a = APK(self.filename)
package_name = a.get_package()
resources = a.get_android_resources() # .get_strings_resources()
self.client_id = resources.get_string(package_name, "PSA_API_CLIENT_ID_PROD")[1]
self.client_secret = resources.get_string(package_name, "PSA_API_CLIENT_SECRET_PROD")[1]
self.host_brandid_prod = resources.get_string(package_name, "HOST_BRANDID_PROD")[1]
self.culture = self.__get_cultures_code(a.get_file("res/raw/cultures.json"), self.country_code)
## Get Customer id
self.site_code = BRAND[package_name]["brand_code"] + "_" + self.country_code + "_ESP"
pfx_cert = a.get_file("assets/MWPMYMA1.pfx")
save_key_to_pem(pfx_cert, b"y5Y2my5B")
def save_key_to_pem(pfx_data, pfx_password):
private_key, certificate = pkcs12.load_key_and_certificates(pfx_data,
pfx_password, default_backend())[:2]
try:
os.mkdir("certs")
except FileExistsError:
pass
with open("certs/public.pem", "wb") as f:
f.write(certificate.public_bytes(encoding=serialization.Encoding.PEM))
with open("certs/private.pem", "wb") as f:
f.write(private_key.private_bytes(encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()))
+111
View File
@@ -0,0 +1,111 @@
#!/usr/bin/env python3
import json
import traceback
import requests
from charge_control import ChargeControl, ChargeControls
from libs.psa.constants import BRAND
from libs.psa.setup.apk_parser import ApkParser
from libs.psa.setup.github import urlretrieve_from_github
from my_psacc import MyPSACC
from mylogger import logger
APP_VERSION = "1.33.0"
GITHUB_USER = "flobz"
GITHUB_REPO = "psa_apk"
def get_content_from_apk(filename: str, country_code: str) -> ApkParser:
apk_parser = ApkParser(filename, country_code)
urlretrieve_from_github(GITHUB_USER, GITHUB_REPO, "", apk_parser.filename)
apk_parser.retrieve_content_from_apk()
return apk_parser
def firstLaunchConfig(package_name, client_email, client_password, country_code, # pylint: disable=too-many-locals
config_prefix=""):
filename = package_name.split(".")[-1] + ".apk"
apk_parser = get_content_from_apk(filename, country_code)
try:
res = requests.post(apk_parser.host_brandid_prod + "/GetAccessToken",
headers={
"Connection": "Keep-Alive",
"Content-Type": "application/json",
"User-Agent": "okhttp/2.3.0"
},
params={"jsonRequest": json.dumps(
{"siteCode": apk_parser.site_code, "culture": "fr-FR", "action": "authenticate",
"fields": {"USR_EMAIL": {"value": client_email},
"USR_PASSWORD": {"value": client_password}}
}
)}
)
token = res.json()["accessToken"]
except Exception as ex:
msg = traceback.format_exc() + f"\nHOST_BRANDID : {apk_parser.host_brandid_prod} " \
f"sitecode: {apk_parser.site_code}"
try:
msg += res.text
except: # pylint: disable=bare-except
pass
logger.error(msg)
raise Exception(msg) from ex
try:
res2 = requests.post(
f"https://mw-{BRAND[package_name]['brand_code'].lower()}-m2c.mym.awsmpsa.com/api/v1/user",
params={
"culture": apk_parser.culture,
"width": 1080,
"version": APP_VERSION
},
data=json.dumps({"site_code": apk_parser.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": APP_VERSION
},
cert=("certs/public.pem", "certs/private.pem"),
)
res_dict = res2.json()["success"]
customer_id = BRAND[package_name]["brand_code"] + "-" + res_dict["id"]
except Exception as ex:
msg = traceback.format_exc()
try:
msg += res2.text
except: # pylint: disable=bare-except
pass
logger.error(msg)
raise Exception(msg) from ex
# Psacc
psacc = MyPSACC(None, apk_parser.client_id, apk_parser.client_secret,
None, customer_id, BRAND[package_name]["realm"],
country_code)
psacc.connect(client_email, client_password)
psacc.save_config(name=config_prefix + "config.json")
res = psacc.get_vehicles()
if len(res) == 0:
Exception("No vehicle in your account is compatible with this API, you vehicle is probably too old...")
for vehicle in res_dict["vehicles"]:
car = psacc.vehicles_list.get_car_by_vin(vehicle["vin"])
if car is not None and "short_label" in vehicle and car.label == "unknown":
car.label = vehicle["short_label"].split(" ")[-1] # remove new, nouvelle, neu word....
psacc.vehicles_list.save_cars()
logger.info("\nYour vehicles: %s", res)
# Charge control
charge_controls = ChargeControls(config_prefix + "charge_config.json")
for vehicle in res:
chc = ChargeControl(psacc, vehicle.vin, 100, [0, 0])
charge_controls[vehicle.vin] = chc
charge_controls.save_config()
return "Success !!!"
+43
View File
@@ -0,0 +1,43 @@
from hashlib import sha1
import requests
from mylogger import logger
def get_github_sha_from_file(user, repo, directory, filename):
res = requests.get("https://api.github.com/repos/{}/{}/git/trees/main:{}".format(user, repo, directory)).json()
file_info = next((file for file in res["tree"] if file['path'] == filename))
return file_info["sha"]
def github_file_need_to_be_downloaded(user, repo, directory, filename):
try:
with open(filename, 'rb') as file_for_hash:
data = file_for_hash.read()
filesize = len(data)
prefix = "blob " + str(filesize) + "\0"
sha_of_downloaded_file = sha1(prefix.encode("utf-8") + data).hexdigest()
sha_of_git_file = get_github_sha_from_file(user, repo, directory, filename)
if sha_of_downloaded_file == sha_of_git_file:
logger.debug("locale file is the latest version")
return False
logger.debug("download last version of file")
except FileNotFoundError:
logger.debug("File not found, download file")
return True
def urlretrieve_from_github(user, repo, directory, filename, branch="main"):
if github_file_need_to_be_downloaded(user, repo, directory, filename):
with open(filename, 'wb') as f:
r = requests.get("https://github.com/{}/{}/raw/{}/{}{}".format(user, repo, branch, directory, filename),
headers={
"Accept": "application/vnd.github.VERSION.raw"
},
stream=True
)
r.raise_for_status()
for chunk in r.iter_content(1024):
f.write(chunk)