Passed
Push — master ( 648e89...feb2f7 )
by Markus
02:11
created

tcllib.tclrequest.get_salt()   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nop 0
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
# pylint: disable=C0111,C0326,C0103
5
6
"""Tools to interface with TCL's download request API."""
7
8
import binascii
9
import hashlib
10
import random
11
import time
12
import zlib
13
from collections import OrderedDict
14
from math import floor
15
16
from defusedxml import ElementTree
17
18
19
'''
20
    private HashMap<String, String> buildDownloadUrisParams(UpdatePackageInfo updatePackageInfo) {
21
        FotaLog.m28v(TAG, "doAfterCheck");
22
        String salt = FotaUtil.salt();
23
        HashMap linkedHashMap = new LinkedHashMap();
24
        linkedHashMap.put("id", this.internalBuilder.getParam("id"));
25
        linkedHashMap.put("salt", salt);
26
        linkedHashMap.put("curef", updatePackageInfo.mCuref);
27
        linkedHashMap.put("fv", updatePackageInfo.mFv);
28
        linkedHashMap.put("tv", updatePackageInfo.mTv);
29
        linkedHashMap.put("type", "Firmware");
30
        linkedHashMap.put("fw_id", updatePackageInfo.mFirmwareId);
31
        linkedHashMap.put("mode", "2");
32
        linkedHashMap.put("vk", generateVk2((LinkedHashMap) linkedHashMap.clone()));
33
        linkedHashMap.put("cltp", "10");
34
        linkedHashMap.put("cktp", this.internalBuilder.getParam("cktp"));
35
        linkedHashMap.put("rtd", this.internalBuilder.getParam("rtd"));
36
        linkedHashMap.put("chnl", this.internalBuilder.getParam("chnl"));
37
        return linkedHashMap;
38
    }
39
'''
0 ignored issues
show
Unused Code introduced by
This string statement has no effect and could be removed.
Loading history...
40
41
VDKEY_B64Z = b"eJwdjwEOwDAIAr8kKFr//7HhmqXp8AIIDrYAgg8byiUXrwRJRXja+d6iNxu0AhUooDCN9rd6rDLxmGIakUVWo3IGCTRWqCAt6X4jGEIUAxgN0eYWnp+LkpHQAg/PsO90ELsy0Npm/n2HbtPndFgGEV31R9OmT4O4nrddjc3Qt6nWscx7e+WRHq5UnOudtjw5skuV09pFhvmqnOEIs4ljPeel1wfLYUF4\n"
42
43
def get_salt():
44
    """Generate cryptographic salt."""
45
    millis = floor(time.time() * 1000)
46
    tail = "{:06d}".format(random.randint(0, 999999))
47
    return "{}{}".format(str(millis), tail)
48
49
def get_vk2(params_dict, cltp):
50
    """Generate salted hash of API parameters."""
51
    params_dict["cltp"] = cltp
52
    query = ""
53
    for key, val in params_dict.items():
54
        if query:
55
            query += "&"
56
        query += key + "=" + str(val)
57
    vdk = zlib.decompress(binascii.a2b_base64(VDKEY_B64Z))
58
    query += vdk.decode("utf-8")
59
    engine = hashlib.sha1()
60
    engine.update(bytes(query, "utf-8"))
61
    hexhash = engine.hexdigest()
62
    return hexhash
63
64
class TclRequestMixin:
0 ignored issues
show
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
65
    """A mixin component for TCL's download request API."""
66
67
    def do_request(self, curef, fvver, tvver, fw_id):
68
        """Perform download request with given parameters."""
69
        url = "https://" + self.g2master + "/download_request.php"
70
        params = OrderedDict()
71
        params["id"] = self.serid
72
        params["salt"] = get_salt()
73
        params["curef"] = curef
74
        params["fv"] = fvver
75
        params["tv"] = tvver
76
        params["type"] = self.ftype
77
        params["fw_id"] = fw_id
78
        params["mode"] = self.mode.value
79
        params["vk"] = get_vk2(params, self.cltp.value)
80
        params["cltp"] = self.cltp.value
81
        params["cktp"] = self.cktp.value
82
        params["rtd"] = self.rtd.value
83
        if self.mode == self.MODE.FULL:
84
            params["foot"] = 1
85
        params["chnl"] = self.chnl.value
86
87
        # print(repr(dict(params)))
88
        req = self.sess.post(url, data=params)
89
        if req.status_code == 200:
90
            req.encoding = "utf-8"  # Force encoding as server doesn't give one
91
            self.write_dump(req.text)
92
            return req.text
93
        else:
94
            print("REQUEST: " + repr(req))
95
            print(repr(req.headers))
96
            print(repr(req.text))
97
            raise SystemExit
98
99
    @staticmethod
100
    def parse_request(xmlstr):
101
        """Parse output of ``do_request``."""
102
        root = ElementTree.fromstring(xmlstr)
103
        file = root.find("FILE_LIST").find("FILE")
104
        fileid = file.find("FILE_ID").text
105
        fileurl = file.find("DOWNLOAD_URL").text
106
        s3_fileurl_node = file.find("S3_DOWNLOAD_URL")
107
        s3_fileurl = ""
108
        if s3_fileurl_node:
109
            s3_fileurl = s3_fileurl_node.text
110
        slave_list = root.find("SLAVE_LIST").findall("SLAVE")
111
        enc_list = root.find("SLAVE_LIST").findall("ENCRYPT_SLAVE")
112
        s3_slave_list = root.find("SLAVE_LIST").findall("S3_SLAVE")
113
        slaves = [s.text for s in slave_list]
114
        encslaves = [s.text for s in enc_list]
115
        s3_slaves = [s.text for s in s3_slave_list]
116
        return fileid, fileurl, slaves, encslaves, s3_fileurl, s3_slaves
117