1
0
This repository has been archived on 2025-06-26. You can view files and clone it, but cannot push or open issues or pull requests.
Files
tcl_ota_check/tcllib/requests/checknewrequest.py

105 lines
3.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Generic update check request."""
import binascii
import hashlib
import random
import time
import zlib
from collections import OrderedDict
from math import floor
from .. import devices
from .tclrequest import TclRequest
from .tclresult import CheckResult
VDKEY = "010010000110111101110111001000000110000101110010011001010010000001111001011011110111010100100000011001110110010101110100001000000111010001101000011010010111001100100000011010110110010101111001001000000111011101101111011100100110010000111111"
VDKEY_B64Z = b"eJwdjwEOwDAIAr8kKFr//7HhmqXp8AIIDrYAgg8byiUXrwRJRXja+d6iNxu0AhUooDCN9rd6rDLxmGIakUVWo3IGCTRWqCAt6X4jGEIUAxgN0eYWnp+LkpHQAg/PsO90ELsy0Npm/n2HbtPndFgGEV31R9OmT4O4nrddjc3Qt6nWscx7e+WRHq5UnOudtjw5skuV09pFhvmqnOEIs4ljPeel1wfLYUF4\n"
def get_salt():
"""Generate cryptographic salt."""
millis = floor(time.time() * 1000)
tail = "{:06d}".format(random.randint(0, 999999))
return "{}{}".format(millis, tail)
def get_vk2(params_dict, cltp):
"""Generate salted hash of API parameters."""
#params_dict["cltp"] = cltp
query = ""
for key, val in params_dict.items():
if query:
query += "&"
query += key + "=" + str(val)
#vdk = zlib.decompress(binascii.a2b_base64(VDKEY_B64Z))
#query += vdk.decode("utf-8")
query += VDKEY
engine = hashlib.sha1()
engine.update(bytes(query, "utf-8"))
hexhash = engine.hexdigest()
return hexhash
class CheckNewRequest(TclRequest):
"""Generic update check request."""
def __init__(self, device: devices.Device):
"""Populate variables.."""
super().__init__()
self.uri = "/check_new.php"
self.method = "GET"
self.device = device
def get_headers(self):
"""Return request headers."""
return {"User-Agent": "GOTU Client v10.1.1"}
def get_params(self):
"""Return request parameters."""
params = OrderedDict()
params["id"] = self.device.imei
params["salt"] = get_salt()
params["curef"] = self.device.curef
params["fv"] = self.device.fwver
params["type"] = self.device.type
params["mode"] = self.device.mode
params["cltp"] = self.device.cltp
params["vk"] = get_vk2(params, self.device.cltp)
#params["cktp"] = self.device.cktp
#params["rtd"] = self.device.rtd
#params["chnl"] = self.device.chnl
#params["osvs"] = self.device.osvs
#params["ckot"] = self.device.ckot
print(repr(params))
return params
def is_done(self, http_status: int, contents: str) -> bool:
"""Handle request result."""
ok_states = {
204: "No update available.",
404: "No data for requested CUREF/FV combination.",
}
if http_status == 200:
self.response = contents
self.result = CheckResult(contents)
self.success = True
return True
elif http_status in ok_states:
self.error = ok_states[http_status]
self.success = False
return True
elif http_status not in [500, 502, 503]:
# Errors OTHER than 500, 502 or 503 are probably
# errors where we don't need to retry
self.error = "HTTP {}.".format(http_status)
self.success = False
return True
return False
# Check requests have 4 possible outcomes:
# 1. HTTP 200 with XML data - our desired info
# 2. HTTP 204 - means: no newer update available
# 3. HTTP 404 - means: invalid device or firmware version
# 4. anything else: server problem (esp. 500, 502, 503)