diff --git a/tcllib/__init__.py b/tcllib/__init__.py index 53e1b21..cfe25ce 100644 --- a/tcllib/__init__.py +++ b/tcllib/__init__.py @@ -27,7 +27,7 @@ class FotaCheck( dumpmgr.DumpMgrMixin ): """Main API handler class.""" - VDKEY = b"eJwdjwEOwDAIAr8kKFr//7HhmqXp8AIIDrYAgg8byiUXrwRJRXja+d6iNxu0AhUooDCN9rd6rDLxmGIakUVWo3IGCTRWqCAt6X4jGEIUAxgN0eYWnp+LkpHQAg/PsO90ELsy0Npm/n2HbtPndFgGEV31R9OmT4O4nrddjc3Qt6nWscx7e+WRHq5UnOudtjw5skuV09pFhvmqnOEIs4ljPeel1wfLYUF4\n" + CKTP = default_enum("CKTP", ["AUTO", "MANUAL"]) MODE = default_enum("MODE", {"OTA": 2, "FULL": 4}) RTD = default_enum("RTD", ["UNROOTED", "ROOTED"]) diff --git a/tcllib/dumpmgr.py b/tcllib/dumpmgr.py index c16ce65..18ea392 100644 --- a/tcllib/dumpmgr.py +++ b/tcllib/dumpmgr.py @@ -8,6 +8,9 @@ import errno import glob import os +import random +import time +from math import floor from . import ansi @@ -18,9 +21,16 @@ class DumpMgrMixin: """Populate dump file name.""" self.last_dump_filename = None + @staticmethod + def get_timestamp_random(): + """Generate timestamp + random part to avoid collisions.""" + millis = floor(time.time() * 1000) + tail = "{:06d}".format(random.randint(0, 999999)) + return "{}_{}".format(str(millis), tail) + def write_dump(self, data): """Write dump to file.""" - outfile = os.path.normpath("logs/{}.xml".format(self.get_salt())) + outfile = os.path.normpath("logs/{}.xml".format(self.get_timestamp_random())) if not os.path.exists(os.path.dirname(outfile)): try: os.makedirs(os.path.dirname(outfile)) diff --git a/tcllib/tclrequest.py b/tcllib/tclrequest.py index 06b631c..1014c52 100644 --- a/tcllib/tclrequest.py +++ b/tcllib/tclrequest.py @@ -38,44 +38,45 @@ from defusedxml import ElementTree } ''' +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(str(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") + engine = hashlib.sha1() + engine.update(bytes(query, "utf-8")) + hexhash = engine.hexdigest() + return hexhash class TclRequestMixin: """A mixin component for TCL's download request API.""" - @staticmethod - def get_salt(): - """Generate cryptographic salt.""" - millis = floor(time.time() * 1000) - tail = "{:06d}".format(random.randint(0, 999999)) - return "{}{}".format(str(millis), tail) - - def get_vk2(self, 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(self.VDKEY)) - query += vdk.decode("utf-8") - engine = hashlib.sha1() - engine.update(bytes(query, "utf-8")) - hexhash = engine.hexdigest() - return hexhash def do_request(self, curef, fvver, tvver, fw_id): """Perform download request with given parameters.""" url = "https://" + self.g2master + "/download_request.php" params = OrderedDict() params["id"] = self.serid - params["salt"] = self.get_salt() + params["salt"] = get_salt() params["curef"] = curef params["fv"] = fvver params["tv"] = tvver params["type"] = self.ftype params["fw_id"] = fw_id params["mode"] = self.mode.value - params["vk"] = self.get_vk2(params, self.cltp.value) + params["vk"] = get_vk2(params, self.cltp.value) params["cltp"] = self.cltp.value params["cktp"] = self.cktp.value params["rtd"] = self.rtd.value