tplinkrouterc6u 5.0.3__py3-none-any.whl → 5.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- test/test_client_ex.py +339 -0
- test/test_client_mr.py +185 -0
- tplinkrouterc6u/__init__.py +13 -12
- tplinkrouterc6u/client/__init__.py +1 -0
- tplinkrouterc6u/client/api_cgi_bin.py +435 -0
- tplinkrouterc6u/client/c1200.py +102 -0
- tplinkrouterc6u/client/c5400x.py +109 -0
- tplinkrouterc6u/client/c6v4.py +38 -0
- tplinkrouterc6u/client/deco.py +177 -0
- tplinkrouterc6u/client/ex.py +295 -0
- tplinkrouterc6u/client/mr.py +645 -0
- tplinkrouterc6u/client_abstract.py +48 -0
- tplinkrouterc6u/common/__init__.py +1 -0
- tplinkrouterc6u/{dataclass.py → common/dataclass.py} +12 -1
- tplinkrouterc6u/provider.py +37 -0
- {tplinkrouterc6u-5.0.3.dist-info → tplinkrouterc6u-5.1.0.dist-info}/METADATA +16 -1
- tplinkrouterc6u-5.1.0.dist-info/RECORD +28 -0
- {tplinkrouterc6u-5.0.3.dist-info → tplinkrouterc6u-5.1.0.dist-info}/WHEEL +1 -1
- tplinkrouterc6u/client.py +0 -1451
- tplinkrouterc6u-5.0.3.dist-info/RECORD +0 -17
- /tplinkrouterc6u/{encryption.py → common/encryption.py} +0 -0
- /tplinkrouterc6u/{exception.py → common/exception.py} +0 -0
- /tplinkrouterc6u/{helper.py → common/helper.py} +0 -0
- /tplinkrouterc6u/{package_enum.py → common/package_enum.py} +0 -0
- {tplinkrouterc6u-5.0.3.dist-info → tplinkrouterc6u-5.1.0.dist-info}/LICENSE +0 -0
- {tplinkrouterc6u-5.0.3.dist-info → tplinkrouterc6u-5.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
from base64 import b64decode
|
|
2
|
+
from json import dumps
|
|
3
|
+
from macaddress import EUI48
|
|
4
|
+
from ipaddress import IPv4Address
|
|
5
|
+
from logging import Logger
|
|
6
|
+
from tplinkrouterc6u.common.helper import get_ip, get_mac
|
|
7
|
+
from tplinkrouterc6u.common.package_enum import Connection
|
|
8
|
+
from tplinkrouterc6u.common.dataclass import Firmware, Status, Device, IPv4Status
|
|
9
|
+
from tplinkrouterc6u.client_abstract import AbstractRouter
|
|
10
|
+
from tplinkrouterc6u.client.api_cgi_bin import TplinkEncryption
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TPLinkDecoClient(TplinkEncryption, AbstractRouter):
|
|
14
|
+
def __init__(self, host: str, password: str, username: str = 'admin', logger: Logger = None,
|
|
15
|
+
verify_ssl: bool = True, timeout: int = 30) -> None:
|
|
16
|
+
super().__init__(host, password, username, logger, verify_ssl, timeout)
|
|
17
|
+
|
|
18
|
+
self._headers_request = {'Content-Type': 'application/json'}
|
|
19
|
+
self._headers_login = {'Content-Type': 'application/json'}
|
|
20
|
+
self._data_block = 'result'
|
|
21
|
+
self.devices = []
|
|
22
|
+
|
|
23
|
+
def logout(self) -> None:
|
|
24
|
+
self.request('admin/system?form=logout', dumps({'operation': 'logout'}), True)
|
|
25
|
+
self._stok = ''
|
|
26
|
+
self._sysauth = ''
|
|
27
|
+
self._logged = False
|
|
28
|
+
|
|
29
|
+
def set_wifi(self, wifi: Connection, enable: bool) -> None:
|
|
30
|
+
en = {'enable': enable}
|
|
31
|
+
if Connection.HOST_2G == wifi:
|
|
32
|
+
params = {'band2_4': {'host': en}}
|
|
33
|
+
elif Connection.HOST_5G == wifi:
|
|
34
|
+
params = {'band5_1': {'host': en}}
|
|
35
|
+
elif Connection.GUEST_5G == wifi:
|
|
36
|
+
params = {'band5_1': {'guest': en}}
|
|
37
|
+
elif Connection.HOST_6G == wifi:
|
|
38
|
+
params = {'band6': {'host': en}}
|
|
39
|
+
elif Connection.GUEST_6G == wifi:
|
|
40
|
+
params = {'band6': {'guest': en}}
|
|
41
|
+
else:
|
|
42
|
+
params = {'band2_4': {'guest': en}}
|
|
43
|
+
|
|
44
|
+
self.request('admin/wireless?form=wlan', dumps({'operation': 'write', 'params': params}))
|
|
45
|
+
|
|
46
|
+
def reboot(self) -> None:
|
|
47
|
+
if not self.devices:
|
|
48
|
+
self.get_firmware()
|
|
49
|
+
self.request('admin/device?form=system', dumps({
|
|
50
|
+
'operation': 'reboot',
|
|
51
|
+
'params': {'mac_list': [{"mac": item['mac']} for item in self.devices]}}))
|
|
52
|
+
|
|
53
|
+
def get_firmware(self) -> Firmware:
|
|
54
|
+
self.devices = self.request('admin/device?form=device_list', dumps({"operation": "read"})).get(
|
|
55
|
+
'device_list', [])
|
|
56
|
+
|
|
57
|
+
for item in self.devices:
|
|
58
|
+
if item.get('role') != 'master' and len(self.devices) != 1:
|
|
59
|
+
continue
|
|
60
|
+
firmware = Firmware(item.get('hardware_ver', ''),
|
|
61
|
+
item.get('device_model', ''),
|
|
62
|
+
item.get('software_ver', ''))
|
|
63
|
+
|
|
64
|
+
return firmware
|
|
65
|
+
|
|
66
|
+
def get_status(self) -> Status:
|
|
67
|
+
data = self.request('admin/network?form=wan_ipv4', dumps({'operation': 'read'}))
|
|
68
|
+
|
|
69
|
+
status = Status()
|
|
70
|
+
element = self._get_value(data, ['wan', 'ip_info', 'mac'])
|
|
71
|
+
status._wan_macaddr = EUI48(element) if element else None
|
|
72
|
+
status._lan_macaddr = EUI48(self._get_value(data, ['lan', 'ip_info', 'mac']))
|
|
73
|
+
element = self._get_value(data, ['wan', 'ip_info', 'ip'])
|
|
74
|
+
status._wan_ipv4_addr = IPv4Address(element) if element else None
|
|
75
|
+
element = self._get_value(data, ['lan', 'ip_info', 'ip'])
|
|
76
|
+
status._lan_ipv4_addr = IPv4Address(element) if element else None
|
|
77
|
+
element = self._get_value(data, ['wan', 'ip_info', 'gateway'])
|
|
78
|
+
status._wan_ipv4_gateway = IPv4Address(element) if element else None
|
|
79
|
+
|
|
80
|
+
data = self.request('admin/network?form=performance', dumps({"operation": "read"}))
|
|
81
|
+
status.mem_usage = data.get('mem_usage')
|
|
82
|
+
status.cpu_usage = data.get('cpu_usage')
|
|
83
|
+
|
|
84
|
+
data = self.request('admin/wireless?form=wlan', dumps({'operation': 'read'}))
|
|
85
|
+
status.wifi_2g_enable = self._get_value(data, ['band2_4', 'host', 'enable'])
|
|
86
|
+
status.guest_2g_enable = self._get_value(data, ['band2_4', 'guest', 'enable'])
|
|
87
|
+
status.wifi_5g_enable = self._get_value(data, ['band5_1', 'host', 'enable'])
|
|
88
|
+
status.guest_5g_enable = self._get_value(data, ['band5_1', 'guest', 'enable'])
|
|
89
|
+
status.wifi_6g_enable = self._get_value(data, ['band6', 'host', 'enable'])
|
|
90
|
+
status.guest_6g_enable = self._get_value(data, ['band6', 'guest', 'enable'])
|
|
91
|
+
|
|
92
|
+
devices = []
|
|
93
|
+
data = self.request('admin/client?form=client_list', dumps(
|
|
94
|
+
{"operation": "read", "params": {"device_mac": "default"}})).get('client_list', [])
|
|
95
|
+
|
|
96
|
+
for item in data:
|
|
97
|
+
if not item.get('online'):
|
|
98
|
+
continue
|
|
99
|
+
conn = self._map_wire_type(item)
|
|
100
|
+
if conn == Connection.WIRED:
|
|
101
|
+
status.wired_total += 1
|
|
102
|
+
elif conn.is_host_wifi():
|
|
103
|
+
status.wifi_clients_total += 1
|
|
104
|
+
elif conn.is_guest_wifi():
|
|
105
|
+
status.guest_clients_total += 1
|
|
106
|
+
elif conn.is_iot():
|
|
107
|
+
if status.iot_clients_total is None:
|
|
108
|
+
status.iot_clients_total = 0
|
|
109
|
+
status.iot_clients_total += 1
|
|
110
|
+
|
|
111
|
+
device = Device(conn,
|
|
112
|
+
get_mac(item.get('mac', '00:00:00:00:00:00')),
|
|
113
|
+
get_ip(item.get('ip', '0.0.0.0')),
|
|
114
|
+
b64decode(item['name']).decode())
|
|
115
|
+
device.down_speed = item.get('down_speed')
|
|
116
|
+
device.up_speed = item.get('up_speed')
|
|
117
|
+
devices.append(device)
|
|
118
|
+
|
|
119
|
+
status.clients_total = (status.wired_total + status.wifi_clients_total + status.guest_clients_total
|
|
120
|
+
+ (0 if status.iot_clients_total is None else status.iot_clients_total))
|
|
121
|
+
status.devices = devices
|
|
122
|
+
|
|
123
|
+
return status
|
|
124
|
+
|
|
125
|
+
def get_ipv4_status(self) -> IPv4Status:
|
|
126
|
+
ipv4_status = IPv4Status()
|
|
127
|
+
data = self.request('admin/network?form=wan_ipv4', dumps({'operation': 'read'}))
|
|
128
|
+
ipv4_status._wan_macaddr = EUI48(self._get_value(data, ['wan', 'ip_info', 'mac']))
|
|
129
|
+
element = self._get_value(data, ['wan', 'ip_info', 'ip'])
|
|
130
|
+
ipv4_status._wan_ipv4_ipaddr = IPv4Address(element) if element else None
|
|
131
|
+
element = self._get_value(data, ['wan', 'ip_info', 'gateway'])
|
|
132
|
+
ipv4_status._wan_ipv4_gateway = IPv4Address(element) if element else None
|
|
133
|
+
ipv4_status.wan_ipv4_conntype = self._get_value(data, ['wan', 'dial_type'])
|
|
134
|
+
element = self._get_value(data, ['wan', 'ip_info', 'mask'])
|
|
135
|
+
ipv4_status._wan_ipv4_netmask = IPv4Address(element) if element else None
|
|
136
|
+
ipv4_status._wan_ipv4_pridns = IPv4Address(self._get_value(data, ['wan', 'ip_info', 'dns1']))
|
|
137
|
+
ipv4_status._wan_ipv4_snddns = IPv4Address(self._get_value(data, ['wan', 'ip_info', 'dns2']))
|
|
138
|
+
ipv4_status._lan_macaddr = EUI48(self._get_value(data, ['lan', 'ip_info', 'mac']))
|
|
139
|
+
ipv4_status._lan_ipv4_ipaddr = IPv4Address(self._get_value(data, ['lan', 'ip_info', 'ip']))
|
|
140
|
+
ipv4_status.lan_ipv4_dhcp_enable = False
|
|
141
|
+
ipv4_status._lan_ipv4_netmask = IPv4Address(self._get_value(data, ['lan', 'ip_info', 'mask']))
|
|
142
|
+
|
|
143
|
+
return ipv4_status
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def _get_value(dictionary: dict, keys: list):
|
|
147
|
+
nested_dict = dictionary
|
|
148
|
+
|
|
149
|
+
for key in keys:
|
|
150
|
+
try:
|
|
151
|
+
nested_dict = nested_dict[key]
|
|
152
|
+
except Exception:
|
|
153
|
+
return None
|
|
154
|
+
return nested_dict
|
|
155
|
+
|
|
156
|
+
def _map_wire_type(self, data: dict) -> Connection:
|
|
157
|
+
if data.get('wire_type') == 'wired':
|
|
158
|
+
return Connection.WIRED
|
|
159
|
+
mapping = {'band2_4': {'main': Connection.HOST_2G, 'guest': Connection.GUEST_2G, 'iot': Connection.IOT_2G},
|
|
160
|
+
'band5': {'main': Connection.HOST_5G, 'guest': Connection.GUEST_5G, 'iot': Connection.IOT_5G},
|
|
161
|
+
'band6': {'main': Connection.HOST_6G, 'guest': Connection.GUEST_6G, 'iot': Connection.IOT_6G}
|
|
162
|
+
}
|
|
163
|
+
result = self._get_value(mapping, [data.get('connection_type'), data.get('interface')])
|
|
164
|
+
|
|
165
|
+
return result if result else Connection.UNKNOWN
|
|
166
|
+
|
|
167
|
+
@staticmethod
|
|
168
|
+
def _get_login_data(crypted_pwd: str) -> str:
|
|
169
|
+
data = {
|
|
170
|
+
"params": {"password": crypted_pwd},
|
|
171
|
+
"operation": "login",
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return dumps(data)
|
|
175
|
+
|
|
176
|
+
def _is_valid_response(self, data: dict) -> bool:
|
|
177
|
+
return 'error_code' in data and data['error_code'] == 0
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
from base64 import b64encode
|
|
2
|
+
from json import loads
|
|
3
|
+
from datetime import timedelta
|
|
4
|
+
from macaddress import EUI48
|
|
5
|
+
from ipaddress import IPv4Address
|
|
6
|
+
from logging import Logger
|
|
7
|
+
from tplinkrouterc6u.common.package_enum import Connection
|
|
8
|
+
from tplinkrouterc6u.common.dataclass import Firmware, Status, Device, IPv4Reservation, IPv4DHCPLease, IPv4Status
|
|
9
|
+
from tplinkrouterc6u.common.exception import ClientException, ClientError
|
|
10
|
+
from tplinkrouterc6u.client.mr import TPLinkMRClientBase
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TPLinkEXClient(TPLinkMRClientBase):
|
|
14
|
+
WIFI_SET = {
|
|
15
|
+
Connection.HOST_2G: '1,0,0,0,0,0',
|
|
16
|
+
Connection.HOST_5G: '2,0,0,0,0,0',
|
|
17
|
+
Connection.GUEST_2G: '1,0,0,0,0,0',
|
|
18
|
+
Connection.GUEST_5G: '2,0,0,0,0,0',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class ActItem:
|
|
22
|
+
GET = 'go'
|
|
23
|
+
GO = 'go'
|
|
24
|
+
SET = 'so'
|
|
25
|
+
ADD = 'add'
|
|
26
|
+
DEL = 'del'
|
|
27
|
+
GL = 'gl'
|
|
28
|
+
GS = 'gs'
|
|
29
|
+
OP = 'op'
|
|
30
|
+
CGI = 'cgi'
|
|
31
|
+
|
|
32
|
+
def __init__(self, type: str, oid: str, stack: str = '0,0,0,0,0,0', pstack: str = '0,0,0,0,0,0',
|
|
33
|
+
attrs: list = []):
|
|
34
|
+
self.type = type
|
|
35
|
+
self.oid = oid
|
|
36
|
+
self.stack = stack
|
|
37
|
+
self.pstack = pstack
|
|
38
|
+
self.attrs = attrs
|
|
39
|
+
|
|
40
|
+
def __init__(self, host: str, password: str, username: str = 'user', logger: Logger = None,
|
|
41
|
+
verify_ssl: bool = True, timeout: int = 30) -> None:
|
|
42
|
+
super().__init__(host, password, username, logger, verify_ssl, timeout)
|
|
43
|
+
|
|
44
|
+
self.username = 'user'
|
|
45
|
+
self._url_rsa_key = 'cgi/getGDPRParm'
|
|
46
|
+
|
|
47
|
+
def logout(self) -> None:
|
|
48
|
+
'''
|
|
49
|
+
Logs out from the host
|
|
50
|
+
'''
|
|
51
|
+
acts = [
|
|
52
|
+
self.ActItem(self.ActItem.CGI, '/cgi/logout')
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
response, _ = self.req_act(acts)
|
|
56
|
+
|
|
57
|
+
if response == '':
|
|
58
|
+
self._token = None
|
|
59
|
+
|
|
60
|
+
def get_firmware(self) -> Firmware:
|
|
61
|
+
acts = [
|
|
62
|
+
self.ActItem(self.ActItem.GET, 'DEV2_DEV_INFO', attrs=[
|
|
63
|
+
'hardwareVersion',
|
|
64
|
+
'modelName',
|
|
65
|
+
'softwareVersion'
|
|
66
|
+
])
|
|
67
|
+
]
|
|
68
|
+
_, values = self.req_act(acts)
|
|
69
|
+
|
|
70
|
+
if not values:
|
|
71
|
+
raise ValueError('No firmware information received.')
|
|
72
|
+
|
|
73
|
+
firmware = Firmware(
|
|
74
|
+
values[0].get('hardwareVersion', ''),
|
|
75
|
+
values[0].get('modelName', ''),
|
|
76
|
+
values[0].get('softwareVersion', '')
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return firmware
|
|
80
|
+
|
|
81
|
+
def get_status(self) -> Status:
|
|
82
|
+
status = Status()
|
|
83
|
+
acts = [
|
|
84
|
+
self.ActItem(self.ActItem.GL, 'DEV2_ADT_LAN', attrs=['MACAddress', 'IPAddress']),
|
|
85
|
+
self.ActItem(self.ActItem.GL, 'DEV2_ADT_WAN',
|
|
86
|
+
attrs=['enable', 'MACAddr', 'connIPv4Address', 'connIPv4Gateway']),
|
|
87
|
+
self.ActItem(self.ActItem.GL, 'DEV2_ADT_WIFI_COMMON', attrs=['primaryEnable', 'guestEnable']),
|
|
88
|
+
self.ActItem(self.ActItem.GL, 'DEV2_HOST_ENTRY',
|
|
89
|
+
attrs=['active', 'X_TP_LanConnType', 'physAddress', 'IPAddress', 'hostName']),
|
|
90
|
+
self.ActItem(self.ActItem.GO, 'DEV2_MEM_STATUS', attrs=['total', 'free']),
|
|
91
|
+
self.ActItem(self.ActItem.GO, 'DEV2_PROC_STATUS', attrs=['CPUUsage']),
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
_, values = self.req_act(acts)
|
|
95
|
+
|
|
96
|
+
if values[0].__class__ == list:
|
|
97
|
+
values[0] = values[0][0]
|
|
98
|
+
|
|
99
|
+
status._lan_macaddr = EUI48(values[0]['MACAddress'])
|
|
100
|
+
status._lan_ipv4_addr = IPv4Address(values[0]['IPAddress'])
|
|
101
|
+
|
|
102
|
+
for item in values[1]:
|
|
103
|
+
if int(item['enable']) == 0 and values[1].__class__ == list:
|
|
104
|
+
continue
|
|
105
|
+
status._wan_macaddr = EUI48(item['MACAddr']) if item['MACAddr'] else None
|
|
106
|
+
status._wan_ipv4_addr = IPv4Address(item['connIPv4Address'])
|
|
107
|
+
status._wan_ipv4_gateway = IPv4Address(item['connIPv4Gateway'])
|
|
108
|
+
|
|
109
|
+
if values[2].__class__ != list:
|
|
110
|
+
status.wifi_2g_enable = bool(int(values[2]['primaryEnable']))
|
|
111
|
+
else:
|
|
112
|
+
status.wifi_2g_enable = bool(int(values[2][0]['primaryEnable']))
|
|
113
|
+
status.wifi_5g_enable = bool(int(values[2][1]['primaryEnable']))
|
|
114
|
+
|
|
115
|
+
if values[2].__class__ != list:
|
|
116
|
+
status.guest_2g_enable = bool(int(values[2]['guestEnable']))
|
|
117
|
+
else:
|
|
118
|
+
status.guest_2g_enable = bool(int(values[2][0]['guestEnable']))
|
|
119
|
+
status.guest_5g_enable = bool(int(values[2][1]['guestEnable']))
|
|
120
|
+
|
|
121
|
+
devices = {}
|
|
122
|
+
for val in self._to_list(values[3]):
|
|
123
|
+
if int(val['active']) == 0:
|
|
124
|
+
continue
|
|
125
|
+
conn = self.CLIENT_TYPES.get(int(val['X_TP_LanConnType']))
|
|
126
|
+
if conn is None:
|
|
127
|
+
continue
|
|
128
|
+
elif conn == Connection.WIRED:
|
|
129
|
+
status.wired_total += 1
|
|
130
|
+
elif conn.is_guest_wifi():
|
|
131
|
+
status.guest_clients_total += 1
|
|
132
|
+
elif conn.is_host_wifi():
|
|
133
|
+
status.wifi_clients_total += 1
|
|
134
|
+
devices[val['physAddress']] = Device(conn,
|
|
135
|
+
EUI48(val['physAddress']),
|
|
136
|
+
IPv4Address(val['IPAddress']),
|
|
137
|
+
val['hostName'])
|
|
138
|
+
|
|
139
|
+
total = int(values[4]['total'])
|
|
140
|
+
free = int(values[4]["free"])
|
|
141
|
+
status.mem_usage = ((total - free) / total)
|
|
142
|
+
|
|
143
|
+
status.cpu_usage = int(values[5]['CPUUsage']) / 100
|
|
144
|
+
|
|
145
|
+
status.devices = list(devices.values())
|
|
146
|
+
status.clients_total = status.wired_total + status.wifi_clients_total + status.guest_clients_total
|
|
147
|
+
|
|
148
|
+
return status
|
|
149
|
+
|
|
150
|
+
def get_ipv4_reservations(self) -> [IPv4Reservation]:
|
|
151
|
+
acts = [
|
|
152
|
+
self.ActItem(self.ActItem.GL, 'DEV2_DHCPV4_POOL_STATICADDR', attrs=['enable', 'chaddr', 'yiaddr']),
|
|
153
|
+
]
|
|
154
|
+
_, values = self.req_act(acts)
|
|
155
|
+
|
|
156
|
+
ipv4_reservations = []
|
|
157
|
+
for item in values[0]:
|
|
158
|
+
ipv4_reservations.append(
|
|
159
|
+
IPv4Reservation(
|
|
160
|
+
EUI48(item['chaddr']),
|
|
161
|
+
IPv4Address(item['yiaddr']),
|
|
162
|
+
'',
|
|
163
|
+
bool(int(item['enable']))
|
|
164
|
+
))
|
|
165
|
+
|
|
166
|
+
return ipv4_reservations
|
|
167
|
+
|
|
168
|
+
def get_ipv4_dhcp_leases(self) -> [IPv4DHCPLease]:
|
|
169
|
+
acts = [
|
|
170
|
+
self.ActItem(self.ActItem.GL, 'DEV2_HOST_ENTRY',
|
|
171
|
+
attrs=['IPAddress', 'physAddress', 'hostName', 'leaseTimeRemaining']),
|
|
172
|
+
]
|
|
173
|
+
_, values = self.req_act(acts)
|
|
174
|
+
|
|
175
|
+
dhcp_leases = []
|
|
176
|
+
for item in values[0]:
|
|
177
|
+
lease_time = item['leaseTimeRemaining']
|
|
178
|
+
dhcp_leases.append(
|
|
179
|
+
IPv4DHCPLease(
|
|
180
|
+
EUI48(item['physAddress']),
|
|
181
|
+
IPv4Address(item['IPAddress']),
|
|
182
|
+
item['hostName'],
|
|
183
|
+
str(timedelta(seconds=int(lease_time))) if (lease_time.isdigit()
|
|
184
|
+
and int(lease_time)) > 0 else 'Permanent',
|
|
185
|
+
))
|
|
186
|
+
|
|
187
|
+
return dhcp_leases
|
|
188
|
+
|
|
189
|
+
def get_ipv4_status(self) -> IPv4Status:
|
|
190
|
+
acts = [
|
|
191
|
+
self.ActItem(self.ActItem.GL, 'DEV2_ADT_LAN',
|
|
192
|
+
attrs=['MACAddress', 'IPAddress', 'IPSubnetMask', 'DHCPv4Enable']),
|
|
193
|
+
self.ActItem(self.ActItem.GL, 'DEV2_ADT_WAN',
|
|
194
|
+
attrs=['enable', 'MACAddr', 'connIPv4Address', 'connIPv4Gateway', 'name', 'connIPv4SubnetMask',
|
|
195
|
+
'connIPv4DnsServer']),
|
|
196
|
+
]
|
|
197
|
+
_, values = self.req_act(acts)
|
|
198
|
+
|
|
199
|
+
if values[0].__class__ == list:
|
|
200
|
+
values[0] = values[0][0]
|
|
201
|
+
|
|
202
|
+
ipv4_status = IPv4Status()
|
|
203
|
+
ipv4_status._lan_macaddr = EUI48(values[0]['MACAddress'])
|
|
204
|
+
ipv4_status._lan_ipv4_ipaddr = IPv4Address(values[0]['IPAddress'])
|
|
205
|
+
ipv4_status._lan_ipv4_netmask = IPv4Address(values[0]['IPSubnetMask'])
|
|
206
|
+
ipv4_status.lan_ipv4_dhcp_enable = bool(int(values[0]['DHCPv4Enable']))
|
|
207
|
+
|
|
208
|
+
for item in values[1]:
|
|
209
|
+
if int(item['enable']) == 0 and values[1].__class__ == list:
|
|
210
|
+
continue
|
|
211
|
+
ipv4_status._wan_macaddr = EUI48(item['MACAddr'])
|
|
212
|
+
ipv4_status._wan_ipv4_ipaddr = IPv4Address(item['connIPv4Address'])
|
|
213
|
+
ipv4_status._wan_ipv4_gateway = IPv4Address(item['connIPv4Gateway'])
|
|
214
|
+
ipv4_status.wan_ipv4_conntype = item['name']
|
|
215
|
+
ipv4_status._wan_ipv4_netmask = IPv4Address(item['connIPv4SubnetMask'])
|
|
216
|
+
dns = item['connIPv4DnsServer'].split(',')
|
|
217
|
+
ipv4_status._wan_ipv4_pridns = IPv4Address(dns[0])
|
|
218
|
+
ipv4_status._wan_ipv4_snddns = IPv4Address(dns[1])
|
|
219
|
+
|
|
220
|
+
return ipv4_status
|
|
221
|
+
|
|
222
|
+
def set_wifi(self, wifi: Connection, enable: bool) -> None:
|
|
223
|
+
atr = [f'"primaryEnable":"{int(enable)}"' if 'GUEST' not in str(wifi) else f'"guestEnable":"{int(enable)}"']
|
|
224
|
+
acts = [
|
|
225
|
+
self.ActItem(
|
|
226
|
+
self.ActItem.SET,
|
|
227
|
+
'DEV2_ADT_WIFI_COMMON',
|
|
228
|
+
self.WIFI_SET[wifi],
|
|
229
|
+
attrs=atr),
|
|
230
|
+
]
|
|
231
|
+
self.req_act(acts)
|
|
232
|
+
|
|
233
|
+
def req_act(self, acts: list):
|
|
234
|
+
'''
|
|
235
|
+
Requests ACTs via the cgi_gdpr proxy
|
|
236
|
+
'''
|
|
237
|
+
|
|
238
|
+
all_responses = []
|
|
239
|
+
url = self._get_url('cgi_gdpr?9')
|
|
240
|
+
|
|
241
|
+
for act in acts:
|
|
242
|
+
attrs_str = ', '.join([attr if ':' in attr else f'"{attr}":""' for attr in act.attrs])
|
|
243
|
+
tp_data = \
|
|
244
|
+
(f'{{"data":{{"stack":"{act.stack}","pstack":"{act.pstack}"{"," + attrs_str if attrs_str else ""}}},'
|
|
245
|
+
f'"operation":"{act.type}","oid":"{act.oid}"}}')
|
|
246
|
+
|
|
247
|
+
code, response = self._request(url, data_str=tp_data, encrypt=True)
|
|
248
|
+
response = response.replace("\r", "").replace("\n", "").replace("\t", "")
|
|
249
|
+
|
|
250
|
+
if code != 200:
|
|
251
|
+
error = 'TplinkRouter - EX - Response with error; Request {} - Response {}'.format(tp_data, response)
|
|
252
|
+
if self._logger:
|
|
253
|
+
self._logger.debug(error)
|
|
254
|
+
raise ClientError(error)
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
if len(response):
|
|
258
|
+
json_data = loads(response)
|
|
259
|
+
if 'data' in json_data:
|
|
260
|
+
all_responses.append(json_data['data'])
|
|
261
|
+
except ValueError:
|
|
262
|
+
raise ClientError(f"Error trying to convert response to JSON: {response}")
|
|
263
|
+
|
|
264
|
+
return response, all_responses
|
|
265
|
+
|
|
266
|
+
def _req_login(self) -> None:
|
|
267
|
+
login_data = ('{"data":{"UserName":"%s","Passwd":"%s","Action": "1","stack":"0,0,0,0,0,0",'
|
|
268
|
+
'"pstack":"0,0,0,0,0,0"},"operation":"cgi","oid":"/cgi/login"}') % (
|
|
269
|
+
b64encode(bytes(self.username, "utf-8")).decode("utf-8"),
|
|
270
|
+
b64encode(bytes(self.password, "utf-8")).decode("utf-8")
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
sign, data = self._prepare_data(login_data, True)
|
|
274
|
+
assert len(sign) == 256
|
|
275
|
+
|
|
276
|
+
request_data = f"sign={sign}\r\ndata={data}\r\n"
|
|
277
|
+
|
|
278
|
+
url = f"{self.host}/cgi_gdpr?9"
|
|
279
|
+
(code, response) = self._request(url, data_str=request_data)
|
|
280
|
+
response = self._encryption.aes_decrypt(response)
|
|
281
|
+
|
|
282
|
+
# parse and match return code
|
|
283
|
+
ret_code = self._parse_ret_val(response)
|
|
284
|
+
error = ''
|
|
285
|
+
if ret_code == self.HTTP_ERR_USER_PWD_NOT_CORRECT:
|
|
286
|
+
error = 'TplinkRouter - EX - Login failed, wrong user or password.'
|
|
287
|
+
elif ret_code == self.HTTP_ERR_USER_BAD_REQUEST:
|
|
288
|
+
error = 'TplinkRouter - EX - Login failed. Generic error code: {}'.format(ret_code)
|
|
289
|
+
elif ret_code != self.HTTP_RET_OK:
|
|
290
|
+
error = 'TplinkRouter - EX - Login failed. Unknown error code: {}'.format(ret_code)
|
|
291
|
+
|
|
292
|
+
if error:
|
|
293
|
+
if self._logger:
|
|
294
|
+
self._logger.debug(error)
|
|
295
|
+
raise ClientException(error)
|