tplinkrouterc6u 4.2.3__tar.gz → 5.0.1__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.
Files changed (22) hide show
  1. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/PKG-INFO +9 -7
  2. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/README.md +8 -6
  3. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/setup.py +1 -1
  4. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u/__init__.py +1 -0
  5. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u/client.py +121 -15
  6. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u/encryption.py +18 -0
  7. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u/exception.py +4 -0
  8. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u.egg-info/PKG-INFO +9 -7
  9. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/LICENSE +0 -0
  10. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/setup.cfg +0 -0
  11. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/test/__init__.py +0 -0
  12. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/test/test_client.py +0 -0
  13. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/test/test_client_c1200.py +0 -0
  14. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/test/test_client_deco.py +0 -0
  15. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/test/test_client_mr.py +0 -0
  16. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u/dataclass.py +0 -0
  17. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u/helper.py +0 -0
  18. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u/package_enum.py +0 -0
  19. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u.egg-info/SOURCES.txt +0 -0
  20. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u.egg-info/dependency_links.txt +0 -0
  21. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u.egg-info/requires.txt +0 -0
  22. {tplinkrouterc6u-4.2.3 → tplinkrouterc6u-5.0.1}/tplinkrouterc6u.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tplinkrouterc6u
3
- Version: 4.2.3
3
+ Version: 5.0.1
4
4
  Summary: TP-Link Router API
5
5
  Home-page: https://github.com/AlexandrErohin/TP-Link-Archer-C6U
6
6
  Author: Alex Erohin
@@ -42,6 +42,7 @@ from tplinkrouterc6u import (
42
42
  TplinkRouterProvider,
43
43
  TplinkRouter,
44
44
  TplinkC1200Router,
45
+ TplinkC5400XRouter,
45
46
  TPLinkMRClient,
46
47
  TPLinkDecoClient,
47
48
  Connection
@@ -53,10 +54,10 @@ router = TplinkRouterProvider.get_client('http://192.168.0.1', 'password')
53
54
  # router = TplinkRouter('http://192.168.0.1', 'password')
54
55
  # You may also pass username if it is different and a logger to log errors as
55
56
  # router = TplinkRouter('http://192.168.0.1','password','admin2', Logger('test'))
56
- # If you have the TP-link C1200 V2 or similar, you can use the TplinkC1200Router class instead of the TplinkRouter class.
57
+ # If you have the TP-link C5400X or similar, you can use the TplinkC5400XRouter class instead of the TplinkRouter class.
57
58
  # Remember that the password for this router is different, here you need to use the web encrypted password.
58
59
  # To get web encrypted password, read Web Encrypted Password section
59
- # router = TplinkC1200Router('http://192.168.0.1','WebEncryptedPassword', Logger('test'))
60
+ # router = TplinkC5400XRouter('http://192.168.0.1','WebEncryptedPassword', Logger('test'))
60
61
 
61
62
  try:
62
63
  router.authorize() # authorizing
@@ -87,8 +88,8 @@ The TP-Link Web Interface only supports upto 1 user logged in at a time (for sec
87
88
  So before action you need to authorize and after logout
88
89
 
89
90
  ### <a id="encrypted_pass">Web Encrypted Password</a>
90
- If you got exception - `You need to use web encrypted password instead. Check the documentation!`
91
- or you have TP-link C1200 V2 or similar router you need to get web encrypted password by these actions:
91
+ If you got exception - `use web encrypted password instead. Check the documentation!`
92
+ or you have TP-link C5400X or similar router you need to get web encrypted password by these actions:
92
93
  1. Go to the login page of your router. (default: 192.168.0.1).
93
94
  2. Type in the password you use to login into the password field.
94
95
  3. Click somewhere else on the page so that the password field is not selected anymore.
@@ -246,8 +247,9 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
246
247
  - Archer AX11000 V1
247
248
  - Archer BE800 v1.0
248
249
  - Archer BE805 v1.0
249
- - Archer C1200 (v1.0, v2.0) (You need to use [web encrypted password](#encrypted_pass))
250
- - Archer C2300 v1.0 (You need to use [web encrypted password](#encrypted_pass))
250
+ - Archer BE3600 1.6
251
+ - Archer C1200 (v1.0, v2.0)
252
+ - Archer C2300 (v1.0, v2.0)
251
253
  - Archer C6 (v2.0, v3.0)
252
254
  - Archer C6U v1.0
253
255
  - Archer C7 (v4.0, v5.0)
@@ -20,6 +20,7 @@ from tplinkrouterc6u import (
20
20
  TplinkRouterProvider,
21
21
  TplinkRouter,
22
22
  TplinkC1200Router,
23
+ TplinkC5400XRouter,
23
24
  TPLinkMRClient,
24
25
  TPLinkDecoClient,
25
26
  Connection
@@ -31,10 +32,10 @@ router = TplinkRouterProvider.get_client('http://192.168.0.1', 'password')
31
32
  # router = TplinkRouter('http://192.168.0.1', 'password')
32
33
  # You may also pass username if it is different and a logger to log errors as
33
34
  # router = TplinkRouter('http://192.168.0.1','password','admin2', Logger('test'))
34
- # If you have the TP-link C1200 V2 or similar, you can use the TplinkC1200Router class instead of the TplinkRouter class.
35
+ # If you have the TP-link C5400X or similar, you can use the TplinkC5400XRouter class instead of the TplinkRouter class.
35
36
  # Remember that the password for this router is different, here you need to use the web encrypted password.
36
37
  # To get web encrypted password, read Web Encrypted Password section
37
- # router = TplinkC1200Router('http://192.168.0.1','WebEncryptedPassword', Logger('test'))
38
+ # router = TplinkC5400XRouter('http://192.168.0.1','WebEncryptedPassword', Logger('test'))
38
39
 
39
40
  try:
40
41
  router.authorize() # authorizing
@@ -65,8 +66,8 @@ The TP-Link Web Interface only supports upto 1 user logged in at a time (for sec
65
66
  So before action you need to authorize and after logout
66
67
 
67
68
  ### <a id="encrypted_pass">Web Encrypted Password</a>
68
- If you got exception - `You need to use web encrypted password instead. Check the documentation!`
69
- or you have TP-link C1200 V2 or similar router you need to get web encrypted password by these actions:
69
+ If you got exception - `use web encrypted password instead. Check the documentation!`
70
+ or you have TP-link C5400X or similar router you need to get web encrypted password by these actions:
70
71
  1. Go to the login page of your router. (default: 192.168.0.1).
71
72
  2. Type in the password you use to login into the password field.
72
73
  3. Click somewhere else on the page so that the password field is not selected anymore.
@@ -224,8 +225,9 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
224
225
  - Archer AX11000 V1
225
226
  - Archer BE800 v1.0
226
227
  - Archer BE805 v1.0
227
- - Archer C1200 (v1.0, v2.0) (You need to use [web encrypted password](#encrypted_pass))
228
- - Archer C2300 v1.0 (You need to use [web encrypted password](#encrypted_pass))
228
+ - Archer BE3600 1.6
229
+ - Archer C1200 (v1.0, v2.0)
230
+ - Archer C2300 (v1.0, v2.0)
229
231
  - Archer C6 (v2.0, v3.0)
230
232
  - Archer C6U v1.0
231
233
  - Archer C7 (v4.0, v5.0)
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="tplinkrouterc6u",
8
- version="4.2.3",
8
+ version="5.0.1",
9
9
  author="Alex Erohin",
10
10
  author_email="alexanderErohin@yandex.ru",
11
11
  description="TP-Link Router API",
@@ -2,6 +2,7 @@ from tplinkrouterc6u.client import (
2
2
  TplinkRouter,
3
3
  TplinkRouterProvider,
4
4
  TplinkC1200Router,
5
+ TplinkC5400XRouter,
5
6
  TPLinkMRClient,
6
7
  AbstractRouter,
7
8
  TPLinkDecoClient,
@@ -14,7 +14,7 @@ from tplinkrouterc6u.helper import get_ip
14
14
  from tplinkrouterc6u.encryption import EncryptionWrapper, EncryptionWrapperMR
15
15
  from tplinkrouterc6u.package_enum import Connection
16
16
  from tplinkrouterc6u.dataclass import Firmware, Status, Device, IPv4Reservation, IPv4DHCPLease, IPv4Status
17
- from tplinkrouterc6u.exception import ClientException, ClientError
17
+ from tplinkrouterc6u.exception import ClientException, ClientError, AuthorizeError
18
18
  from abc import ABC, abstractmethod
19
19
 
20
20
 
@@ -108,7 +108,7 @@ class TplinkRequest:
108
108
  error = ('TplinkRouter - {} - Response with error; Request {} - Response {}'
109
109
  .format(self.__class__.__name__, path, data)) if not error else error
110
110
  if self._logger:
111
- self._logger.error(error)
111
+ self._logger.debug(error)
112
112
  raise ClientError(error)
113
113
 
114
114
  def _is_valid_response(self, data: dict) -> bool:
@@ -178,7 +178,7 @@ class TplinkEncryption(TplinkRequest):
178
178
  error = ("TplinkRouter - {} - Cannot authorize! Error - {}; Response - {}"
179
179
  .format(self.__class__.__name__, e, data))
180
180
  if self._logger:
181
- self._logger.error(error)
181
+ self._logger.debug(error)
182
182
  raise ClientException(error)
183
183
 
184
184
  def _request_pwd(self) -> None:
@@ -203,7 +203,7 @@ class TplinkEncryption(TplinkRequest):
203
203
  error = ('TplinkRouter - {} - Unknown error for pwd! Error - {}; Response - {}'
204
204
  .format(self.__class__.__name__, e, response.text))
205
205
  if self._logger:
206
- self._logger.error(error)
206
+ self._logger.debug(error)
207
207
  raise ClientException(error)
208
208
 
209
209
  def _request_seq(self) -> None:
@@ -230,7 +230,7 @@ class TplinkEncryption(TplinkRequest):
230
230
  error = ('TplinkRouter - {} - Unknown error for seq! Error - {}; Response - {}'
231
231
  .format(self.__class__.__name__, e, response.text))
232
232
  if self._logger:
233
- self._logger.error(error)
233
+ self._logger.debug(error)
234
234
  raise ClientException(error)
235
235
 
236
236
  def _try_login(self) -> Response:
@@ -658,7 +658,7 @@ class TplinkC6V4Router(AbstractRouter):
658
658
  return False
659
659
  if response.status_code == 401 and response.text.startswith('00'):
660
660
  raise ClientException(('Your router is not supported. Please add your router support to '
661
- 'https://github.com/AlexandrErohin/TP-Link-Archer-C6U'
661
+ 'https://github.com/AlexandrErohin/TP-Link-Archer-C6U '
662
662
  'by implementing methods for TplinkC6V4Router class'
663
663
  ))
664
664
  return False
@@ -682,9 +682,9 @@ class TplinkC6V4Router(AbstractRouter):
682
682
  raise ClientException('Not Implemented')
683
683
 
684
684
 
685
- class TplinkC1200Router(TplinkBaseRouter):
685
+ class TplinkC5400XRouter(TplinkBaseRouter):
686
686
  def supports(self) -> bool:
687
- return True
687
+ return len(self.password) >= 200
688
688
 
689
689
  def authorize(self) -> None:
690
690
  if len(self.password) < 200:
@@ -708,9 +708,9 @@ class TplinkC1200Router(TplinkBaseRouter):
708
708
  self._smart_network = False
709
709
 
710
710
  except Exception as e:
711
- error = "TplinkRouter - C1200 - Cannot authorize! Error - {}; Response - {}".format(e, response.text)
711
+ error = "TplinkRouter - C5400X - Cannot authorize! Error - {}; Response - {}".format(e, response.text)
712
712
  if self._logger:
713
- self._logger.error(error)
713
+ self._logger.debug(error)
714
714
  raise ClientException(error)
715
715
 
716
716
  def set_led(self, enable: bool) -> None:
@@ -786,6 +786,103 @@ class TplinkC1200Router(TplinkBaseRouter):
786
786
  self.request(path, data)
787
787
 
788
788
 
789
+ class TplinkC1200Router(TplinkC5400XRouter):
790
+ username = ''
791
+ password = ''
792
+ _pwdNN = ''
793
+ _pwdEE = ''
794
+ _encryption = EncryptionWrapper()
795
+
796
+ def supports(self) -> bool:
797
+ if len(self.password) > 125:
798
+ return False
799
+
800
+ try:
801
+ self._request_pwd()
802
+ return True
803
+ except ClientException:
804
+ return False
805
+
806
+ def authorize(self) -> None:
807
+ if self._pwdNN == '':
808
+ self._request_pwd()
809
+
810
+ response = self._try_login()
811
+
812
+ is_valid_json = False
813
+ try:
814
+ response.json()
815
+ is_valid_json = True
816
+ except BaseException:
817
+ """Ignore"""
818
+
819
+ if is_valid_json is False or response.status_code == 403:
820
+ self._logged = False
821
+ self._request_pwd()
822
+ response = self._try_login()
823
+
824
+ data = response.text
825
+ try:
826
+ data = response.json()
827
+ data = self._decrypt_response(data)
828
+
829
+ self._stok = data[self._data_block]['stok']
830
+ regex_result = search(
831
+ 'sysauth=(.*);', response.headers['set-cookie'])
832
+ self._sysauth = regex_result.group(1)
833
+ self._logged = True
834
+
835
+ except Exception as e:
836
+ error = ("TplinkRouter - C1200 - Cannot authorize! Error - {}; Response - {}".format(e, data))
837
+ if self._logger:
838
+ self._logger.debug(error)
839
+ if 'data' in vars() and data.get('errorcode') == 'login failed':
840
+ raise AuthorizeError(error)
841
+ raise ClientException(error)
842
+
843
+ def _request_pwd(self) -> None:
844
+ url = '{}/cgi-bin/luci/;stok=/login?form=login'.format(self.host)
845
+ response = post(
846
+ url, params={'operation': 'read'},
847
+ timeout=self.timeout,
848
+ verify=self._verify_ssl,
849
+ )
850
+
851
+ try:
852
+ data = response.json()
853
+
854
+ args = data[self._data_block]['password']
855
+
856
+ self._pwdNN = args[0]
857
+ self._pwdEE = args[1]
858
+
859
+ except Exception as e:
860
+ error = ('TplinkRouter - C1200 - {} - Unknown error for pwd! Error - {}; Response - {}'
861
+ .format(self.__class__.__name__, e, response.text))
862
+ if self._logger:
863
+ self._logger.debug(error)
864
+ raise ClientException(error)
865
+
866
+ def _try_login(self) -> Response:
867
+ url = '{}/cgi-bin/luci/;stok=/login?form=login'.format(self.host)
868
+
869
+ crypted_pwd = self._encryption.encrypt_password_C1200(self.password, self._pwdNN, self._pwdEE)
870
+
871
+ body = self._get_login_data(crypted_pwd)
872
+
873
+ return post(
874
+ url,
875
+ data=body,
876
+ headers=self._headers_login,
877
+ timeout=self.timeout,
878
+ verify=self._verify_ssl,
879
+ )
880
+
881
+ @staticmethod
882
+ def _get_login_data(crypted_pwd: str) -> str:
883
+ return 'operation=login&password={}'.format(crypted_pwd)
884
+
885
+
789
886
  class TPLinkMRClient(AbstractRouter):
790
887
  REQUEST_RETRIES = 3
791
888
 
@@ -1104,7 +1201,7 @@ class TPLinkMRClient(AbstractRouter):
1104
1201
  if code != 200:
1105
1202
  error = 'TplinkRouter - MR - Response with error; Request {} - Response {}'.format(data, response)
1106
1203
  if self._logger:
1107
- self._logger.error(error)
1204
+ self._logger.debug(error)
1108
1205
  raise ClientError(error)
1109
1206
 
1110
1207
  result = self._merge_response(response)
@@ -1255,7 +1352,7 @@ class TPLinkMRClient(AbstractRouter):
1255
1352
 
1256
1353
  if error:
1257
1354
  if self._logger:
1258
- self._logger.error(error)
1355
+ self._logger.debug(error)
1259
1356
  raise ClientException(error)
1260
1357
 
1261
1358
  def _request(self, url, method='POST', data_str=None, encrypt=False):
@@ -1334,10 +1431,19 @@ class TPLinkMRClient(AbstractRouter):
1334
1431
  class TplinkRouterProvider:
1335
1432
  @staticmethod
1336
1433
  def get_client(host: str, password: str, username: str = 'admin', logger: Logger = None,
1337
- verify_ssl: bool = True, timeout: int = 30) -> AbstractRouter | None:
1338
- for client in [TPLinkMRClient, TplinkC6V4Router, TPLinkDecoClient, TplinkRouter, TplinkC1200Router]:
1434
+ verify_ssl: bool = True, timeout: int = 30) -> AbstractRouter:
1435
+ for client in [TplinkC5400XRouter, TPLinkMRClient, TplinkC6V4Router, TPLinkDecoClient, TplinkRouter]:
1339
1436
  router = client(host, password, username, logger, verify_ssl, timeout)
1340
1437
  if router.supports():
1341
1438
  return router
1342
1439
 
1343
- return None
1440
+ router = TplinkC1200Router(host, password, username, logger, verify_ssl, timeout)
1441
+ try:
1442
+ router.authorize()
1443
+ except AuthorizeError as e:
1444
+ logger.error(e.__str__())
1445
+ raise ClientException(('Login failed! Please check if your router local password is correct or '
1446
+ 'try to use web encrypted password instead. Check the documentation!'
1447
+ ))
1448
+
1449
+ raise ClientException('You need to use web encrypted password instead. Check the documentation!')
@@ -64,6 +64,24 @@ class EncryptionWrapper:
64
64
  def _get_aes_string(self) -> str:
65
65
  return 'k={}&i={}'.format(self._key.decode(), self._iv.decode())
66
66
 
67
+ @staticmethod
68
+ def encrypt_password_C1200(password: str, nn: str, ee: str) -> str:
69
+ n = int(nn, 16)
70
+ e = int(ee, 16)
71
+ key = RSA.construct((n, e))
72
+
73
+ modulus_byte_length = (key.size_in_bits() + 7) // 8
74
+ password_bytes = password.encode('utf-8')
75
+ if len(password_bytes) > modulus_byte_length:
76
+ raise ValueError("Password too long for the RSA key size.")
77
+
78
+ padded_password = password_bytes.ljust(modulus_byte_length, b'\x00')
79
+ message_int = bytes_to_long(padded_password)
80
+ encrypted_int = pow(message_int, e, n)
81
+ encrypted_hex = format(encrypted_int, 'x').zfill(256)
82
+
83
+ return encrypted_hex
84
+
67
85
 
68
86
  class EncryptionWrapperMR:
69
87
  RSA_USE_PKCS_V1_5 = False
@@ -4,3 +4,7 @@ class ClientException(Exception):
4
4
 
5
5
  class ClientError(ClientException):
6
6
  pass
7
+
8
+
9
+ class AuthorizeError(ClientException):
10
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tplinkrouterc6u
3
- Version: 4.2.3
3
+ Version: 5.0.1
4
4
  Summary: TP-Link Router API
5
5
  Home-page: https://github.com/AlexandrErohin/TP-Link-Archer-C6U
6
6
  Author: Alex Erohin
@@ -42,6 +42,7 @@ from tplinkrouterc6u import (
42
42
  TplinkRouterProvider,
43
43
  TplinkRouter,
44
44
  TplinkC1200Router,
45
+ TplinkC5400XRouter,
45
46
  TPLinkMRClient,
46
47
  TPLinkDecoClient,
47
48
  Connection
@@ -53,10 +54,10 @@ router = TplinkRouterProvider.get_client('http://192.168.0.1', 'password')
53
54
  # router = TplinkRouter('http://192.168.0.1', 'password')
54
55
  # You may also pass username if it is different and a logger to log errors as
55
56
  # router = TplinkRouter('http://192.168.0.1','password','admin2', Logger('test'))
56
- # If you have the TP-link C1200 V2 or similar, you can use the TplinkC1200Router class instead of the TplinkRouter class.
57
+ # If you have the TP-link C5400X or similar, you can use the TplinkC5400XRouter class instead of the TplinkRouter class.
57
58
  # Remember that the password for this router is different, here you need to use the web encrypted password.
58
59
  # To get web encrypted password, read Web Encrypted Password section
59
- # router = TplinkC1200Router('http://192.168.0.1','WebEncryptedPassword', Logger('test'))
60
+ # router = TplinkC5400XRouter('http://192.168.0.1','WebEncryptedPassword', Logger('test'))
60
61
 
61
62
  try:
62
63
  router.authorize() # authorizing
@@ -87,8 +88,8 @@ The TP-Link Web Interface only supports upto 1 user logged in at a time (for sec
87
88
  So before action you need to authorize and after logout
88
89
 
89
90
  ### <a id="encrypted_pass">Web Encrypted Password</a>
90
- If you got exception - `You need to use web encrypted password instead. Check the documentation!`
91
- or you have TP-link C1200 V2 or similar router you need to get web encrypted password by these actions:
91
+ If you got exception - `use web encrypted password instead. Check the documentation!`
92
+ or you have TP-link C5400X or similar router you need to get web encrypted password by these actions:
92
93
  1. Go to the login page of your router. (default: 192.168.0.1).
93
94
  2. Type in the password you use to login into the password field.
94
95
  3. Click somewhere else on the page so that the password field is not selected anymore.
@@ -246,8 +247,9 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
246
247
  - Archer AX11000 V1
247
248
  - Archer BE800 v1.0
248
249
  - Archer BE805 v1.0
249
- - Archer C1200 (v1.0, v2.0) (You need to use [web encrypted password](#encrypted_pass))
250
- - Archer C2300 v1.0 (You need to use [web encrypted password](#encrypted_pass))
250
+ - Archer BE3600 1.6
251
+ - Archer C1200 (v1.0, v2.0)
252
+ - Archer C2300 (v1.0, v2.0)
251
253
  - Archer C6 (v2.0, v3.0)
252
254
  - Archer C6U v1.0
253
255
  - Archer C7 (v4.0, v5.0)
File without changes