tplinkrouterc6u 5.12.1__tar.gz → 5.12.3__tar.gz
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.
- {tplinkrouterc6u-5.12.1/tplinkrouterc6u.egg-info → tplinkrouterc6u-5.12.3}/PKG-INFO +7 -4
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/README.md +6 -3
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/setup.py +1 -1
- tplinkrouterc6u-5.12.3/test/test_client_vr400v2.py +60 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/__init__.py +1 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/c5400x.py +0 -1
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/c6u.py +3 -1
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/mr200.py +5 -5
- tplinkrouterc6u-5.12.3/tplinkrouterc6u/client/vr400v2.py +114 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/provider.py +17 -3
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3/tplinkrouterc6u.egg-info}/PKG-INFO +7 -4
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u.egg-info/SOURCES.txt +2 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/LICENSE +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/setup.cfg +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/__init__.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_c1200.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_c6u.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_c80.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_deco.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_ex.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_mr.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_mr_200.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_re330.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_wdr.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/test/test_client_xdr.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/__init__.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/c1200.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/c80.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/deco.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/ex.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/mr.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/re330.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/vr.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/wdr.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client/xdr.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/client_abstract.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/common/__init__.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/common/dataclass.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/common/encryption.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/common/exception.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/common/helper.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u/common/package_enum.py +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u.egg-info/dependency_links.txt +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u.egg-info/requires.txt +0 -0
- {tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tplinkrouterc6u
|
|
3
|
-
Version: 5.12.
|
|
3
|
+
Version: 5.12.3
|
|
4
4
|
Summary: TP-Link Router API (supports also Mercusys Router)
|
|
5
5
|
Home-page: https://github.com/AlexandrErohin/TP-Link-Archer-C6U
|
|
6
6
|
Author: Alex Erohin
|
|
@@ -49,7 +49,9 @@ Python package for API access and management for TP-Link and Mercusys Routers. S
|
|
|
49
49
|
- [pycryptodome](https://pypi.org/project/pycryptodome/)
|
|
50
50
|
|
|
51
51
|
## Usage
|
|
52
|
-
Enter the host & credentials used to log in to your router management page. Username is `admin` by default. But you may pass username as third parameter. Some routers have default username - `user`
|
|
52
|
+
- Enter the host & credentials used to log in to your router management page. Username is `admin` by default. But you may pass username as third parameter. Some routers have default username - `user`
|
|
53
|
+
- Use Local Password which is for Log In with Local Password. Login with TP-LINK ID doesnt work
|
|
54
|
+
- If you use `https` connection - You need to turn on "Local Management via HTTPS" (advanced->system->administration) in the router web UI
|
|
53
55
|
|
|
54
56
|
```python
|
|
55
57
|
from tplinkrouterc6u import (
|
|
@@ -61,6 +63,7 @@ from tplinkrouterc6u import (
|
|
|
61
63
|
TPLinkMRClientGCM, # Class for MR series routers which supports AES cipher GCM mode
|
|
62
64
|
TPLinkMR200Client,
|
|
63
65
|
TPLinkVRClient,
|
|
66
|
+
TPLinkVR400v2Client,
|
|
64
67
|
TPLinkEXClient, # Class for EX series routers which supports old firmwares with AES cipher CBC mode
|
|
65
68
|
TPLinkEXClientGCM, # Class for EX series routers which supports AES cipher GCM mode
|
|
66
69
|
TPLinkXDRClient,
|
|
@@ -304,7 +307,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
304
307
|
- [TP-LINK routers](#tplink)
|
|
305
308
|
- [MERCUSYS routers](#mercusys)
|
|
306
309
|
### <a id="tplink">TP-LINK routers</a>
|
|
307
|
-
- Archer A6
|
|
310
|
+
- Archer A6 (2.0, 4.0)
|
|
308
311
|
- Archer A7 V5
|
|
309
312
|
- Archer A8 (1.0, 2.20)
|
|
310
313
|
- Archer A9 V6
|
|
@@ -353,7 +356,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
353
356
|
- Archer MR550 v1
|
|
354
357
|
- Archer MR600 (v1, v2, v3)
|
|
355
358
|
- Archer NX200 v2.0
|
|
356
|
-
- Archer VR400 v3
|
|
359
|
+
- Archer VR400 (v2, v3)
|
|
357
360
|
- Archer VR600 v3
|
|
358
361
|
- Archer VR900v
|
|
359
362
|
- Archer VR1200v v1
|
|
@@ -16,7 +16,9 @@ Python package for API access and management for TP-Link and Mercusys Routers. S
|
|
|
16
16
|
- [pycryptodome](https://pypi.org/project/pycryptodome/)
|
|
17
17
|
|
|
18
18
|
## Usage
|
|
19
|
-
Enter the host & credentials used to log in to your router management page. Username is `admin` by default. But you may pass username as third parameter. Some routers have default username - `user`
|
|
19
|
+
- Enter the host & credentials used to log in to your router management page. Username is `admin` by default. But you may pass username as third parameter. Some routers have default username - `user`
|
|
20
|
+
- Use Local Password which is for Log In with Local Password. Login with TP-LINK ID doesnt work
|
|
21
|
+
- If you use `https` connection - You need to turn on "Local Management via HTTPS" (advanced->system->administration) in the router web UI
|
|
20
22
|
|
|
21
23
|
```python
|
|
22
24
|
from tplinkrouterc6u import (
|
|
@@ -28,6 +30,7 @@ from tplinkrouterc6u import (
|
|
|
28
30
|
TPLinkMRClientGCM, # Class for MR series routers which supports AES cipher GCM mode
|
|
29
31
|
TPLinkMR200Client,
|
|
30
32
|
TPLinkVRClient,
|
|
33
|
+
TPLinkVR400v2Client,
|
|
31
34
|
TPLinkEXClient, # Class for EX series routers which supports old firmwares with AES cipher CBC mode
|
|
32
35
|
TPLinkEXClientGCM, # Class for EX series routers which supports AES cipher GCM mode
|
|
33
36
|
TPLinkXDRClient,
|
|
@@ -271,7 +274,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
271
274
|
- [TP-LINK routers](#tplink)
|
|
272
275
|
- [MERCUSYS routers](#mercusys)
|
|
273
276
|
### <a id="tplink">TP-LINK routers</a>
|
|
274
|
-
- Archer A6
|
|
277
|
+
- Archer A6 (2.0, 4.0)
|
|
275
278
|
- Archer A7 V5
|
|
276
279
|
- Archer A8 (1.0, 2.20)
|
|
277
280
|
- Archer A9 V6
|
|
@@ -320,7 +323,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
320
323
|
- Archer MR550 v1
|
|
321
324
|
- Archer MR600 (v1, v2, v3)
|
|
322
325
|
- Archer NX200 v2.0
|
|
323
|
-
- Archer VR400 v3
|
|
326
|
+
- Archer VR400 (v2, v3)
|
|
324
327
|
- Archer VR600 v3
|
|
325
328
|
- Archer VR900v
|
|
326
329
|
- Archer VR1200v v1
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from unittest import main, TestCase
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
from requests import Session
|
|
4
|
+
from tplinkrouterc6u import TPLinkVR400v2Client
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestTPLinkVR400v2Client(TestCase):
|
|
8
|
+
def setUp(self):
|
|
9
|
+
self.obj = TPLinkVR400v2Client('', '')
|
|
10
|
+
|
|
11
|
+
def test_supports_false(self):
|
|
12
|
+
responses = [
|
|
13
|
+
'var param1="0x1A"\nvar param2="0x2B"\nignored line\n',
|
|
14
|
+
'404',
|
|
15
|
+
'var nn="dfgdfg"\nvar ee="0x2B"\n'
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
fake_responses = []
|
|
19
|
+
for text in responses:
|
|
20
|
+
r = MagicMock()
|
|
21
|
+
r.text = text
|
|
22
|
+
fake_responses.append(r)
|
|
23
|
+
|
|
24
|
+
with patch.object(Session, "get", side_effect=fake_responses):
|
|
25
|
+
for _ in range(len(fake_responses)):
|
|
26
|
+
result = self.obj.supports()
|
|
27
|
+
self.assertFalse(result)
|
|
28
|
+
|
|
29
|
+
def test_supports_false_standard_mr200(self):
|
|
30
|
+
# Scenario 1: Standard MR200 response (without userSetting)
|
|
31
|
+
# VR400v2 should return False to let MR200Client handle it
|
|
32
|
+
fake_response = MagicMock()
|
|
33
|
+
fake_response.text = (
|
|
34
|
+
'var nn="0x1A"\n'
|
|
35
|
+
'var ee="0x2B"\n'
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
with patch.object(Session, "get", return_value=fake_response):
|
|
39
|
+
result = self.obj.supports()
|
|
40
|
+
|
|
41
|
+
self.assertEqual(result, False)
|
|
42
|
+
|
|
43
|
+
def test_supports_true_vr400v2_style(self):
|
|
44
|
+
# Scenario 2: VR400v2 style response with extra lines
|
|
45
|
+
fake_response = MagicMock()
|
|
46
|
+
fake_response.text = (
|
|
47
|
+
'var userSetting=1;\n'
|
|
48
|
+
'var ee="010001";\n'
|
|
49
|
+
'var nn="0x123456";\n'
|
|
50
|
+
'$.ret=0;\n'
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
with patch.object(Session, "get", return_value=fake_response):
|
|
54
|
+
result = self.obj.supports()
|
|
55
|
+
|
|
56
|
+
self.assertEqual(result, True)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == '__main__':
|
|
60
|
+
main()
|
|
@@ -5,6 +5,7 @@ from tplinkrouterc6u.client.mr import TPLinkMRClient, TPLinkMRClientGCM
|
|
|
5
5
|
from tplinkrouterc6u.client.mr200 import TPLinkMR200Client
|
|
6
6
|
from tplinkrouterc6u.client.ex import TPLinkEXClient, TPLinkEXClientGCM
|
|
7
7
|
from tplinkrouterc6u.client.vr import TPLinkVRClient
|
|
8
|
+
from tplinkrouterc6u.client.vr400v2 import TPLinkVR400v2Client
|
|
8
9
|
from tplinkrouterc6u.client.c80 import TplinkC80Router
|
|
9
10
|
from tplinkrouterc6u.client.c5400x import TplinkC5400XRouter
|
|
10
11
|
from tplinkrouterc6u.client.c1200 import TplinkC1200Router
|
|
@@ -28,7 +28,6 @@ class TplinkC5400XRouter(TplinkBaseRouter):
|
|
|
28
28
|
regex_result = search('sysauth=(.*);', response.headers['set-cookie'])
|
|
29
29
|
self._sysauth = regex_result.group(1)
|
|
30
30
|
self._logged = True
|
|
31
|
-
self._smart_network = False
|
|
32
31
|
|
|
33
32
|
except Exception as e:
|
|
34
33
|
error = "TplinkRouter - C5400X - Cannot authorize! Error - {}; Response - {}".format(e, response.text)
|
|
@@ -240,6 +240,7 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
|
|
|
240
240
|
self._url_firmware = 'admin/firmware?form=upgrade&operation=read'
|
|
241
241
|
self._url_ipv4_reservations = 'admin/dhcps?form=reservation&operation=load'
|
|
242
242
|
self._url_ipv4_dhcp_leases = 'admin/dhcps?form=client&operation=load'
|
|
243
|
+
self._url_smart_network = 'admin/smart_network?form=game_accelerator&operation=loadDevice'
|
|
243
244
|
self._url_openvpn = 'admin/openvpn?form=config&operation=read'
|
|
244
245
|
self._url_pptpd = 'admin/pptpd?form=config&operation=read'
|
|
245
246
|
self._url_vpnconn_openvpn = 'admin/vpnconn?form=config&operation=list&vpntype=openvpn'
|
|
@@ -341,7 +342,7 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
|
|
|
341
342
|
smart_network = None
|
|
342
343
|
if self._smart_network:
|
|
343
344
|
try:
|
|
344
|
-
smart_network = self.request(
|
|
345
|
+
smart_network = self.request(self._url_smart_network, 'operation=loadDevice')
|
|
345
346
|
except Exception:
|
|
346
347
|
self._smart_network = False
|
|
347
348
|
|
|
@@ -483,6 +484,7 @@ class TplinkRouter(TplinkEncryption, TplinkBaseRouter):
|
|
|
483
484
|
self._url_firmware = 'admin/firmware?form=upgrade'
|
|
484
485
|
self._url_ipv4_reservations = 'admin/dhcps?form=reservation'
|
|
485
486
|
self._url_ipv4_dhcp_leases = 'admin/dhcps?form=client'
|
|
487
|
+
self._url_smart_network = 'admin/smart_network?form=game_accelerator'
|
|
486
488
|
self._url_openvpn = 'admin/openvpn?form=config'
|
|
487
489
|
self._url_pptpd = 'admin/pptpd?form=config'
|
|
488
490
|
self._url_vpnconn_openvpn = 'admin/vpnconn?form=config'
|
|
@@ -16,13 +16,13 @@ class TPLinkMR200Client(TPLinkMRClient):
|
|
|
16
16
|
|
|
17
17
|
def supports(self) -> bool:
|
|
18
18
|
try:
|
|
19
|
-
self.
|
|
19
|
+
self._get_params()
|
|
20
20
|
return True
|
|
21
21
|
except ClientException:
|
|
22
22
|
return False
|
|
23
23
|
|
|
24
24
|
def authorize(self) -> None:
|
|
25
|
-
self.
|
|
25
|
+
self._get_params()
|
|
26
26
|
|
|
27
27
|
# Construct the RSA public key manually using modulus (n) and exponent (e)
|
|
28
28
|
pub_key = RSA.construct((self._nn, self._ee))
|
|
@@ -79,7 +79,7 @@ class TPLinkMR200Client(TPLinkMRClient):
|
|
|
79
79
|
]
|
|
80
80
|
|
|
81
81
|
response, _ = self.req_act(acts)
|
|
82
|
-
ret_code = self._parse_ret_val(response)
|
|
82
|
+
ret_code = self._parse_ret_val(response.text)
|
|
83
83
|
|
|
84
84
|
if ret_code == self.HTTP_RET_OK:
|
|
85
85
|
del self.req.headers["TokenID"]
|
|
@@ -114,7 +114,7 @@ class TPLinkMR200Client(TPLinkMRClient):
|
|
|
114
114
|
|
|
115
115
|
return status
|
|
116
116
|
|
|
117
|
-
def
|
|
117
|
+
def _get_params(self, retry=False) -> None:
|
|
118
118
|
self.req.headers = {'referer': f'{self.host}/', 'origin': self.host}
|
|
119
119
|
try:
|
|
120
120
|
r = self.req.get(f"{self.host}/cgi/getParm", timeout=5)
|
|
@@ -127,7 +127,7 @@ class TPLinkMR200Client(TPLinkMRClient):
|
|
|
127
127
|
self._ee = int(result["ee"])
|
|
128
128
|
except Exception as e:
|
|
129
129
|
if not retry:
|
|
130
|
-
self.
|
|
130
|
+
self._get_params(True)
|
|
131
131
|
raise ClientException(str(e))
|
|
132
132
|
|
|
133
133
|
def req_act(self, acts: list):
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TP-Link Archer VR400 v2 Client
|
|
3
|
+
|
|
4
|
+
Based on reverse-engineering of network traffic.
|
|
5
|
+
Protocol is similar to MR series but with differences in:
|
|
6
|
+
1. Login: Uses RSA encryption (PKCS1 v1.5) for both Username and Password
|
|
7
|
+
2. Password must be Base64 encoded before encryption
|
|
8
|
+
3. Actions: Uses /cgi endpoint with types in query string and plain text body
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from re import search, findall
|
|
12
|
+
from logging import Logger
|
|
13
|
+
|
|
14
|
+
from tplinkrouterc6u.client.mr200 import TPLinkMR200Client
|
|
15
|
+
from tplinkrouterc6u.common.exception import ClientException
|
|
16
|
+
from tplinkrouterc6u.common.dataclass import VPNStatus
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TPLinkVR400v2Client(TPLinkMR200Client):
|
|
20
|
+
"""Client for TP-Link Archer VR400 v2"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, host: str, password: str, username: str = '', logger: Logger = None,
|
|
23
|
+
verify_ssl: bool = True, timeout: int = 30):
|
|
24
|
+
super().__init__(host, password, username, logger, verify_ssl, timeout)
|
|
25
|
+
self.req.headers['User-Agent'] = (
|
|
26
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
|
|
27
|
+
'(KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def supports(self) -> bool:
|
|
31
|
+
"""
|
|
32
|
+
Detect VR400 v2 by checking for 'userSetting' variable in /cgi/getParm response.
|
|
33
|
+
This distinguishes VR400v2 from standard MR200 routers.
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
self._get_params()
|
|
37
|
+
# After successful parameter fetch, check for VR400v2-specific signature
|
|
38
|
+
r = self.req.get(f"{self.host}/cgi/getParm", timeout=5)
|
|
39
|
+
if 'var userSetting' in r.text:
|
|
40
|
+
return True
|
|
41
|
+
except Exception:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
def _get_params(self, retry=False) -> None:
|
|
47
|
+
"""
|
|
48
|
+
Override to handle VR400v2's response format with extra variables and semicolons.
|
|
49
|
+
Uses findall to parse entire response instead of just first 2 lines.
|
|
50
|
+
"""
|
|
51
|
+
self.req.headers = {'referer': f'{self.host}/', 'origin': self.host}
|
|
52
|
+
try:
|
|
53
|
+
r = self.req.get(f"{self.host}/cgi/getParm", timeout=5)
|
|
54
|
+
matches = findall(r'var\s+(.*?)\s*=\s*"(.*?)"', r.text)
|
|
55
|
+
result = {}
|
|
56
|
+
for key, val in matches:
|
|
57
|
+
result[key] = int(val, 16)
|
|
58
|
+
|
|
59
|
+
self._nn = int(result["nn"])
|
|
60
|
+
self._ee = int(result["ee"])
|
|
61
|
+
except Exception as e:
|
|
62
|
+
if not retry:
|
|
63
|
+
self._get_params(True)
|
|
64
|
+
raise ClientException(str(e))
|
|
65
|
+
|
|
66
|
+
def _req_token(self):
|
|
67
|
+
"""Token extraction handled by parent's authorize() method."""
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
def _parse_ret_val(self, response_text):
|
|
71
|
+
"""Parse return code from VR400v2 response (supports multiple formats)."""
|
|
72
|
+
# Try $.ret=...; format
|
|
73
|
+
result = search(r'\$\.ret=([-]?\d+);', response_text)
|
|
74
|
+
if result:
|
|
75
|
+
return int(result.group(1))
|
|
76
|
+
|
|
77
|
+
# Try [error]... format
|
|
78
|
+
result = search(r'\[error\](\d+)', response_text)
|
|
79
|
+
if result:
|
|
80
|
+
return int(result.group(1))
|
|
81
|
+
|
|
82
|
+
# Try var errorcode=... format
|
|
83
|
+
result = search(r'var\s+errorcode\s*=\s*(\d+)', response_text)
|
|
84
|
+
if result:
|
|
85
|
+
return int(result.group(1))
|
|
86
|
+
|
|
87
|
+
if '[error]0' in response_text or 'errorcode=0' in response_text:
|
|
88
|
+
return 0
|
|
89
|
+
|
|
90
|
+
if self._logger:
|
|
91
|
+
self._logger.debug(f"Could not parse return code from: {response_text[:100]}...")
|
|
92
|
+
|
|
93
|
+
def get_vpn_status(self) -> VPNStatus:
|
|
94
|
+
status = VPNStatus()
|
|
95
|
+
acts = [
|
|
96
|
+
self.ActItem(self.ActItem.GET, 'OPENVPN', attrs=['enable']),
|
|
97
|
+
self.ActItem(self.ActItem.GET, 'PPTPVPN', attrs=['enable']),
|
|
98
|
+
self.ActItem(self.ActItem.GL, 'OVPN_CLIENT', attrs=['connAct']),
|
|
99
|
+
self.ActItem(self.ActItem.GL, 'PVPN_CLIENT', attrs=['connAct']),
|
|
100
|
+
]
|
|
101
|
+
_, values = self.req_act(acts)
|
|
102
|
+
|
|
103
|
+
status.openvpn_enable = values['0']['enable'] == '1'
|
|
104
|
+
status.pptpvpn_enable = values['1']['enable'] == '1'
|
|
105
|
+
|
|
106
|
+
for item in values['2']:
|
|
107
|
+
if item['connAct'] == '1':
|
|
108
|
+
status.openvpn_clients_total += 1
|
|
109
|
+
|
|
110
|
+
for item in values['3']:
|
|
111
|
+
if item['connAct'] == '1':
|
|
112
|
+
status.pptpvpn_clients_total += 1
|
|
113
|
+
|
|
114
|
+
return status
|
|
@@ -12,6 +12,7 @@ from tplinkrouterc6u.client.c5400x import TplinkC5400XRouter
|
|
|
12
12
|
from tplinkrouterc6u.client.c1200 import TplinkC1200Router
|
|
13
13
|
from tplinkrouterc6u.client.c80 import TplinkC80Router
|
|
14
14
|
from tplinkrouterc6u.client.vr import TPLinkVRClient
|
|
15
|
+
from tplinkrouterc6u.client.vr400v2 import TPLinkVR400v2Client
|
|
15
16
|
from tplinkrouterc6u.client.wdr import TplinkWDRRouter
|
|
16
17
|
from tplinkrouterc6u.client.re330 import TplinkRE330Router
|
|
17
18
|
|
|
@@ -20,9 +21,22 @@ class TplinkRouterProvider:
|
|
|
20
21
|
@staticmethod
|
|
21
22
|
def get_client(host: str, password: str, username: str = 'admin', logger: Logger = None,
|
|
22
23
|
verify_ssl: bool = True, timeout: int = 30) -> AbstractRouter:
|
|
23
|
-
for client in [
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
for client in [
|
|
25
|
+
TplinkC5400XRouter,
|
|
26
|
+
TPLinkVRClient,
|
|
27
|
+
TPLinkEXClientGCM,
|
|
28
|
+
TPLinkEXClient,
|
|
29
|
+
TPLinkMRClientGCM,
|
|
30
|
+
TPLinkMRClient,
|
|
31
|
+
TPLinkMR200Client,
|
|
32
|
+
TPLinkVR400v2Client,
|
|
33
|
+
TPLinkDecoClient,
|
|
34
|
+
TPLinkXDRClient,
|
|
35
|
+
TplinkRouter,
|
|
36
|
+
TplinkC80Router,
|
|
37
|
+
TplinkWDRRouter,
|
|
38
|
+
TplinkRE330Router,
|
|
39
|
+
]:
|
|
26
40
|
router = client(host, password, username, logger, verify_ssl, timeout)
|
|
27
41
|
if router.supports():
|
|
28
42
|
return router
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tplinkrouterc6u
|
|
3
|
-
Version: 5.12.
|
|
3
|
+
Version: 5.12.3
|
|
4
4
|
Summary: TP-Link Router API (supports also Mercusys Router)
|
|
5
5
|
Home-page: https://github.com/AlexandrErohin/TP-Link-Archer-C6U
|
|
6
6
|
Author: Alex Erohin
|
|
@@ -49,7 +49,9 @@ Python package for API access and management for TP-Link and Mercusys Routers. S
|
|
|
49
49
|
- [pycryptodome](https://pypi.org/project/pycryptodome/)
|
|
50
50
|
|
|
51
51
|
## Usage
|
|
52
|
-
Enter the host & credentials used to log in to your router management page. Username is `admin` by default. But you may pass username as third parameter. Some routers have default username - `user`
|
|
52
|
+
- Enter the host & credentials used to log in to your router management page. Username is `admin` by default. But you may pass username as third parameter. Some routers have default username - `user`
|
|
53
|
+
- Use Local Password which is for Log In with Local Password. Login with TP-LINK ID doesnt work
|
|
54
|
+
- If you use `https` connection - You need to turn on "Local Management via HTTPS" (advanced->system->administration) in the router web UI
|
|
53
55
|
|
|
54
56
|
```python
|
|
55
57
|
from tplinkrouterc6u import (
|
|
@@ -61,6 +63,7 @@ from tplinkrouterc6u import (
|
|
|
61
63
|
TPLinkMRClientGCM, # Class for MR series routers which supports AES cipher GCM mode
|
|
62
64
|
TPLinkMR200Client,
|
|
63
65
|
TPLinkVRClient,
|
|
66
|
+
TPLinkVR400v2Client,
|
|
64
67
|
TPLinkEXClient, # Class for EX series routers which supports old firmwares with AES cipher CBC mode
|
|
65
68
|
TPLinkEXClientGCM, # Class for EX series routers which supports AES cipher GCM mode
|
|
66
69
|
TPLinkXDRClient,
|
|
@@ -304,7 +307,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
304
307
|
- [TP-LINK routers](#tplink)
|
|
305
308
|
- [MERCUSYS routers](#mercusys)
|
|
306
309
|
### <a id="tplink">TP-LINK routers</a>
|
|
307
|
-
- Archer A6
|
|
310
|
+
- Archer A6 (2.0, 4.0)
|
|
308
311
|
- Archer A7 V5
|
|
309
312
|
- Archer A8 (1.0, 2.20)
|
|
310
313
|
- Archer A9 V6
|
|
@@ -353,7 +356,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
353
356
|
- Archer MR550 v1
|
|
354
357
|
- Archer MR600 (v1, v2, v3)
|
|
355
358
|
- Archer NX200 v2.0
|
|
356
|
-
- Archer VR400 v3
|
|
359
|
+
- Archer VR400 (v2, v3)
|
|
357
360
|
- Archer VR600 v3
|
|
358
361
|
- Archer VR900v
|
|
359
362
|
- Archer VR1200v v1
|
|
@@ -10,6 +10,7 @@ test/test_client_ex.py
|
|
|
10
10
|
test/test_client_mr.py
|
|
11
11
|
test/test_client_mr_200.py
|
|
12
12
|
test/test_client_re330.py
|
|
13
|
+
test/test_client_vr400v2.py
|
|
13
14
|
test/test_client_wdr.py
|
|
14
15
|
test/test_client_xdr.py
|
|
15
16
|
tplinkrouterc6u/__init__.py
|
|
@@ -31,6 +32,7 @@ tplinkrouterc6u/client/mr.py
|
|
|
31
32
|
tplinkrouterc6u/client/mr200.py
|
|
32
33
|
tplinkrouterc6u/client/re330.py
|
|
33
34
|
tplinkrouterc6u/client/vr.py
|
|
35
|
+
tplinkrouterc6u/client/vr400v2.py
|
|
34
36
|
tplinkrouterc6u/client/wdr.py
|
|
35
37
|
tplinkrouterc6u/client/xdr.py
|
|
36
38
|
tplinkrouterc6u/common/__init__.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tplinkrouterc6u-5.12.1 → tplinkrouterc6u-5.12.3}/tplinkrouterc6u.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|