tcllib.requests.downloadrequest.get_salt()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nop 0
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
"""Generic file download request."""
5
6
import binascii
7
import hashlib
8
import random
9
import time
10
import zlib
11
from collections import OrderedDict
12
from math import floor
13
14
from .. import devices
15
from .tclrequest import TclRequest
16
from .tclresult import DownloadResult
17
18
19
VDKEY_B64Z = b"eJwdjwEOwDAIAr8kKFr//7HhmqXp8AIIDrYAgg8byiUXrwRJRXja+d6iNxu0AhUooDCN9rd6rDLxmGIakUVWo3IGCTRWqCAt6X4jGEIUAxgN0eYWnp+LkpHQAg/PsO90ELsy0Npm/n2HbtPndFgGEV31R9OmT4O4nrddjc3Qt6nWscx7e+WRHq5UnOudtjw5skuV09pFhvmqnOEIs4ljPeel1wfLYUF4\n"
20
21
22
def get_salt():
23
    """Generate cryptographic salt."""
24
    millis = floor(time.time() * 1000)
25
    tail = "{:06d}".format(random.randint(0, 999999))
26
    return "{}{}".format(str(millis), tail)
27
28
29
def get_vk2(params_dict, cltp):
30
    """Generate salted hash of API parameters."""
31
    params_dict["cltp"] = cltp
32
    query = ""
33
    for key, val in params_dict.items():
34
        if query:
35
            query += "&"
36
        query += key + "=" + str(val)
37
    vdk = zlib.decompress(binascii.a2b_base64(VDKEY_B64Z))
38
    query += vdk.decode("utf-8")
39
    engine = hashlib.sha1()
40
    engine.update(bytes(query, "utf-8"))
41
    hexhash = engine.hexdigest()
42
    return hexhash
43
44
45
class DownloadRequest(TclRequest):
0 ignored issues
show
best-practice introduced by
Too many instance attributes (9/7)
Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
46
    """Generic file download request."""
47
48
    def __init__(self, device: devices.Device, tvver: str, fw_id: str):
49
        """Populate variables."""
50
        super().__init__()
51
        self.uri = "/download_request.php"
52
        self.method = "POST"
53
        self.device = device
54
        self.tvver = tvver
55
        self.fw_id = fw_id
56
57
    def get_headers(self):
58
        """Return request headers."""
59
        return {"User-Agent": self.device.uagent}
60
61
    def get_params(self):
62
        """Return request parameters."""
63
        params = OrderedDict()
64
        params["id"] = self.device.imei
65
        params["salt"] = get_salt()
66
        params["curef"] = self.device.curef
67
        params["fv"] = self.device.fwver
68
        params["tv"] = self.tvver
69
        params["type"] = self.device.type
70
        params["fw_id"] = self.fw_id
71
        params["mode"] = self.device.mode
72
        params["vk"] = get_vk2(params, self.device.cltp)
73
        params["cltp"] = self.device.cltp
74
        params["cktp"] = self.device.cktp
75
        params["rtd"] = self.device.rtd
76
        if self.device.mode == self.device.MODE_STATES["FULL"]:
77
            params["foot"] = 1
78
        params["chnl"] = self.device.chnl
79
        return params
80
81
    def is_done(self, http_status: int, contents: str) -> bool:
82
        """Handle request result."""
83
        if http_status == 200:
84
            self.response = contents
85
            self.result = DownloadResult(contents)
86
            self.success = True
87
            return True
88
        elif http_status not in [500, 502, 503]:
89
            # Errors OTHER than 500, 502 or 503 are probably
90
            # errors where we don't need to retry
91
            self.error = "HTTP {}".format(http_status)
92
            self.success = False
93
            return True
94
        return False
95