tplinkrouterc6u 4.2.2__py3-none-any.whl → 5.0.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_deco.py CHANGED
@@ -71,7 +71,7 @@ class TestTPLinkDecoClient(TestCase):
71
71
  "online": true, "name": "d2lyZWxlc3M0", "enable_priority": false, "remain_time": 0, "owner_id": "",
72
72
  "client_type": "other", "interface": "guest"},
73
73
  {"mac": "56:32:c3:de:ce:f0", "up_speed": 3, "down_speed": 1, "wire_type": "wireless", "access_host": "1",
74
- "connection_type": "band2_4", "space_id": "1", "ip": "192.168.68.105", "client_mesh": true,
74
+ "connection_type": "band2_4", "space_id": "1", "ip": "UNKNOWN", "client_mesh": true,
75
75
  "online": true, "name": "d2lyZWxlc3M1", "enable_priority": false, "remain_time": 0, "owner_id": "",
76
76
  "client_type": "other", "interface": "guest"}
77
77
  ]}, "error_code": 0}
@@ -150,7 +150,7 @@ class TestTPLinkDecoClient(TestCase):
150
150
  self.assertIsInstance(status.devices[4], Device)
151
151
  self.assertEqual(status.devices[4].type, Connection.GUEST_2G)
152
152
  self.assertEqual(status.devices[4].macaddr, '56-32-C3-DE-CE-F0')
153
- self.assertEqual(status.devices[4].ipaddr, '192.168.68.105')
153
+ self.assertEqual(status.devices[4].ipaddr, '0.0.0.0')
154
154
  self.assertEqual(status.devices[4].hostname, 'wireless5')
155
155
  self.assertEqual(status.devices[4].packets_sent, None)
156
156
  self.assertEqual(status.devices[4].packets_received, None)
@@ -6,7 +6,7 @@ from tplinkrouterc6u.client import (
6
6
  AbstractRouter,
7
7
  TPLinkDecoClient,
8
8
  )
9
- from tplinkrouterc6u.enum import Connection
9
+ from tplinkrouterc6u.package_enum import Connection
10
10
  from tplinkrouterc6u.dataclass import (
11
11
  Firmware,
12
12
  Status,
tplinkrouterc6u/client.py CHANGED
@@ -10,8 +10,9 @@ from datetime import timedelta
10
10
  from macaddress import EUI48
11
11
  from ipaddress import IPv4Address
12
12
  from logging import Logger
13
+ from tplinkrouterc6u.helper import get_ip
13
14
  from tplinkrouterc6u.encryption import EncryptionWrapper, EncryptionWrapperMR
14
- from tplinkrouterc6u.enum import Connection
15
+ from tplinkrouterc6u.package_enum import Connection
15
16
  from tplinkrouterc6u.dataclass import Firmware, Status, Device, IPv4Reservation, IPv4DHCPLease, IPv4Status
16
17
  from tplinkrouterc6u.exception import ClientException, ClientError
17
18
  from abc import ABC, abstractmethod
@@ -353,15 +354,9 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
353
354
 
354
355
  devices = {}
355
356
 
356
- def _getIP(ip: str) -> IPv4Address:
357
- try:
358
- return IPv4Address(ip)
359
- except Exception:
360
- return IPv4Address('0.0.0.0')
361
-
362
357
  def _add_device(conn: Connection, item: dict) -> None:
363
358
  devices[item['macaddr']] = Device(conn, EUI48(item['macaddr']),
364
- _getIP(item['ipaddr']),
359
+ get_ip(item['ipaddr']),
365
360
  item['hostname'])
366
361
 
367
362
  for item in data.get('access_devices_wired', []):
@@ -387,7 +382,7 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
387
382
  for item in smart_network:
388
383
  if item['mac'] not in devices:
389
384
  conn = self._map_wire_type(item.get('deviceTag'), not item.get('isGuest'))
390
- devices[item['mac']] = Device(conn, EUI48(item['mac']), _getIP(item['ip']),
385
+ devices[item['mac']] = Device(conn, EUI48(item['mac']), get_ip(item['ip']),
391
386
  item['deviceName'])
392
387
  if conn.is_iot():
393
388
  if status.iot_clients_total is None:
@@ -585,10 +580,9 @@ class TPLinkDecoClient(TplinkEncryption, AbstractRouter):
585
580
  status.iot_clients_total = 0
586
581
  status.iot_clients_total += 1
587
582
 
588
- ip = item['ip'] if item.get('ip') else '0.0.0.0'
589
583
  device = Device(conn,
590
584
  EUI48(item['mac']),
591
- IPv4Address(ip),
585
+ get_ip(item.get('ip', '0.0.0.0')),
592
586
  b64decode(item['name']).decode())
593
587
  device.down_speed = item.get('down_speed')
594
588
  device.up_speed = item.get('up_speed')
@@ -689,36 +683,100 @@ class TplinkC6V4Router(AbstractRouter):
689
683
 
690
684
 
691
685
  class TplinkC1200Router(TplinkBaseRouter):
686
+ username = ''
687
+ password = ''
688
+ _pwdNN = ''
689
+ _pwdEE = ''
690
+ _encryption = EncryptionWrapper()
691
+
692
692
  def supports(self) -> bool:
693
- return True
693
+ if len(self.password) > 125:
694
+ return False
695
+
696
+ try:
697
+ self._request_pwd()
698
+ return True
699
+ except ClientException:
700
+ return False
694
701
 
695
702
  def authorize(self) -> None:
696
- if len(self.password) < 200:
697
- raise Exception('You need to use web encrypted password instead. Check the documentation!')
703
+ if self._pwdNN == '':
704
+ self._request_pwd()
698
705
 
699
- url = '{}/cgi-bin/luci/;stok=/login?form=login'.format(self.host)
706
+ response = self._try_login()
707
+
708
+ is_valid_json = False
709
+ try:
710
+ response.json()
711
+ is_valid_json = True
712
+ except BaseException:
713
+ """Ignore"""
714
+
715
+ if is_valid_json is False or response.status_code == 403:
716
+ self._logged = False
717
+ self._request_pwd()
718
+ response = self._try_login()
719
+
720
+ data = response.text
721
+ try:
722
+ data = response.json()
723
+ data = self._decrypt_response(data)
724
+
725
+ self._stok = data[self._data_block]['stok']
726
+ regex_result = search(
727
+ 'sysauth=(.*);', response.headers['set-cookie'])
728
+ self._sysauth = regex_result.group(1)
729
+ self._logged = True
730
+
731
+ except Exception as e:
732
+ error = ("TplinkRouter - C1200 - {} - Cannot authorize! Error - {}; Response - {}"
733
+ .format(self.__class__.__name__, e, data))
734
+ if self._logger:
735
+ self._logger.error(error)
736
+ raise ClientException(error)
700
737
 
738
+ def _request_pwd(self) -> None:
739
+ url = '{}/cgi-bin/luci/;stok=/login?form=login'.format(self.host)
701
740
  response = post(
702
- url,
703
- params={'operation': 'login', 'username': self.username, 'password': self.password},
704
- headers=self._headers_login,
741
+ url, params={'operation': 'read'},
705
742
  timeout=self.timeout,
706
743
  verify=self._verify_ssl,
707
744
  )
708
745
 
709
746
  try:
710
- self._stok = response.json().get('data').get('stok')
711
- regex_result = search('sysauth=(.*);', response.headers['set-cookie'])
712
- self._sysauth = regex_result.group(1)
713
- self._logged = True
714
- self._smart_network = False
747
+ data = response.json()
748
+
749
+ args = data[self._data_block]['password']
750
+
751
+ self._pwdNN = args[0]
752
+ self._pwdEE = args[1]
715
753
 
716
754
  except Exception as e:
717
- error = "TplinkRouter - C1200 - Cannot authorize! Error - {}; Response - {}".format(e, response.text)
755
+ error = ('TplinkRouter - C1200 - {} - Unknown error for pwd! Error - {}; Response - {}'
756
+ .format(self.__class__.__name__, e, response.text))
718
757
  if self._logger:
719
758
  self._logger.error(error)
720
759
  raise ClientException(error)
721
760
 
761
+ def _try_login(self) -> Response:
762
+ url = '{}/cgi-bin/luci/;stok=/login?form=login'.format(self.host)
763
+
764
+ crypted_pwd = self._encryption.encrypt_password_C1200(self.password, self._pwdNN, self._pwdEE)
765
+
766
+ body = self._get_login_data(crypted_pwd)
767
+
768
+ return post(
769
+ url,
770
+ data=body,
771
+ headers=self._headers_login,
772
+ timeout=self.timeout,
773
+ verify=self._verify_ssl,
774
+ )
775
+
776
+ @staticmethod
777
+ def _get_login_data(crypted_pwd: str) -> str:
778
+ return 'operation=login&password={}'.format(crypted_pwd)
779
+
722
780
  def set_led(self, enable: bool) -> None:
723
781
  current_state = (self.request('admin/ledgeneral?form=setting&operation=read', 'operation=read')
724
782
  .get('enable', 'off') == 'on')
@@ -1131,7 +1189,7 @@ class TPLinkMRClient(AbstractRouter):
1131
1189
  lines = response.split('\n')
1132
1190
  for line in lines:
1133
1191
  if line.startswith('['):
1134
- regexp = search('\[\d,\d,\d,\d,\d,\d\](\d)', line)
1192
+ regexp = search(r'\[\d,\d,\d,\d,\d,\d\](\d)', line)
1135
1193
  if regexp is not None:
1136
1194
  obj = {}
1137
1195
  index = regexp.group(1)
@@ -1321,7 +1379,7 @@ class TPLinkMRClient(AbstractRouter):
1321
1379
  Return value:
1322
1380
  return code (int)
1323
1381
  '''
1324
- result = search('\$\.ret=(.*);', response_text)
1382
+ result = search(r'\$\.ret=(.*);', response_text)
1325
1383
  assert result is not None
1326
1384
  assert result.group(1).isnumeric()
1327
1385
 
@@ -1346,4 +1404,7 @@ class TplinkRouterProvider:
1346
1404
  if router.supports():
1347
1405
  return router
1348
1406
 
1349
- return None
1407
+ raise ClientException(('Your router is not supported. Please add your router support to '
1408
+ 'https://github.com/AlexandrErohin/TP-Link-Archer-C6U'
1409
+ 'by implementing methods for AbstractRouter class'
1410
+ ))
@@ -1,7 +1,7 @@
1
1
  from macaddress import EUI48
2
2
  from ipaddress import IPv4Address
3
3
  from dataclasses import dataclass
4
- from tplinkrouterc6u.enum import Connection
4
+ from tplinkrouterc6u.package_enum import Connection
5
5
 
6
6
 
7
7
  @dataclass
@@ -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
@@ -0,0 +1,8 @@
1
+ from ipaddress import IPv4Address
2
+
3
+
4
+ def get_ip(ip: str) -> IPv4Address:
5
+ try:
6
+ return IPv4Address(ip)
7
+ except Exception:
8
+ return IPv4Address('0.0.0.0')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tplinkrouterc6u
3
- Version: 4.2.2
3
+ Version: 5.0.0
4
4
  Summary: TP-Link Router API
5
5
  Home-page: https://github.com/AlexandrErohin/TP-Link-Archer-C6U
6
6
  Author: Alex Erohin
@@ -53,10 +53,6 @@ router = TplinkRouterProvider.get_client('http://192.168.0.1', 'password')
53
53
  # router = TplinkRouter('http://192.168.0.1', 'password')
54
54
  # You may also pass username if it is different and a logger to log errors as
55
55
  # 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
- # Remember that the password for this router is different, here you need to use the web encrypted password.
58
- # To get web encrypted password, read Web Encrypted Password section
59
- # router = TplinkC1200Router('http://192.168.0.1','WebEncryptedPassword', Logger('test'))
60
56
 
61
57
  try:
62
58
  router.authorize() # authorizing
@@ -86,16 +82,6 @@ finally:
86
82
  The TP-Link Web Interface only supports upto 1 user logged in at a time (for security reasons, apparently).
87
83
  So before action you need to authorize and after logout
88
84
 
89
- ### <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:
92
- 1. Go to the login page of your router. (default: 192.168.0.1).
93
- 2. Type in the password you use to login into the password field.
94
- 3. Click somewhere else on the page so that the password field is not selected anymore.
95
- 4. Open the JavaScript console of your browser (usually by pressing F12 and then clicking on "Console").
96
- 5. Type `document.getElementById("login-password").value;`
97
- 6. Copy the returned value as password and use it.
98
-
99
85
  ## Functions
100
86
  | Function | Args | Description | Return |
101
87
  |---|---|---|---|
@@ -225,6 +211,7 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
225
211
  ## <a id="supports">Supported routers</a>
226
212
  ### Fully tested Hardware Versions
227
213
  - Archer A7 V5
214
+ - Archer A9 V6
228
215
  - Archer AX10 v1.0
229
216
  - Archer AX12 v1.0
230
217
  - Archer AX20 v1.0
@@ -237,6 +224,7 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
237
224
  - Archer AX72 V1
238
225
  - Archer AX73 V1
239
226
  - Archer AX75 V1
227
+ - Archer AX90 V1.20
240
228
  - Archer AXE75 V1
241
229
  - Archer AXE16000
242
230
  - Archer AX3000 V1
@@ -244,15 +232,15 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
244
232
  - Archer AX11000 V1
245
233
  - Archer BE800 v1.0
246
234
  - Archer BE805 v1.0
247
- - Archer C1200 (v1.0, v2.0) (You need to use [web encrypted password](#encrypted_pass))
248
- - Archer C2300 v1.0 (You need to use [web encrypted password](#encrypted_pass))
235
+ - Archer C1200 (v1.0, v2.0)
236
+ - Archer C2300 v1.0
249
237
  - Archer C6 (v2.0, v3.0)
250
238
  - Archer C6U v1.0
251
239
  - Archer C7 (v4.0, v5.0)
252
240
  - Archer C5400X V1
253
241
  - Archer GX90 v1.0
254
242
  - Archer MR200 (v5, v5.3)
255
- - Archer MR600 (v1, v3)
243
+ - Archer MR600 (v1, v2, v3)
256
244
  - Archer VR2100v v1
257
245
  - Archer VR900v
258
246
  - Deco M4 2.0
@@ -270,15 +258,14 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
270
258
  - TL-MR100 v2.0
271
259
  - TL-MR105
272
260
  - TL-MR6400 (v5, v5.3)
261
+ - TL-MR6500v
273
262
  - TL-WA3001 v1.0
274
263
 
275
264
  ### Not fully tested Hardware Versions
276
265
  - AD7200 V2
277
266
  - Archer A6 (V2 and V3)
278
- - Archer A9 V6
279
267
  - Archer A10 (V1 and V2)
280
268
  - Archer A20 (V1, V3)
281
- - Archer C7 V4
282
269
  - Archer C8 (V3 and V4)
283
270
  - Archer C9 (V4 and V5)
284
271
  - Archer C59 V2
@@ -0,0 +1,17 @@
1
+ test/__init__.py,sha256=McQmUjeN3AwmwdS6QNfwGXXE77OKoPK852I2BM9XsrU,210
2
+ test/test_client.py,sha256=8cK4qnheszu-zpUJqttKp5Z5WJXrQy1t_fMzMzNnmvw,30638
3
+ test/test_client_c1200.py,sha256=O6NK9uXIEb_vks6lI3g7j6q8TYJ9MSDFYzGA_wOBhOA,4620
4
+ test/test_client_deco.py,sha256=OqJ9e6_TcX60Ccqj_UH9AQ3Ty25hfdbtPvtzLnWpMn0,30464
5
+ test/test_client_mr.py,sha256=znDA8PBxHOGKbZHzsyERbEEWjkP0U5KpV8Z-kaRnXIM,23046
6
+ tplinkrouterc6u/__init__.py,sha256=EpcrPHORAk_m76WDHMLea_RzCPjqZYAs_774JZChLGs,410
7
+ tplinkrouterc6u/client.py,sha256=CWWU_IXA33PADfxA3XEWeXGyDEonhPDaTlc4f3iMLq8,53434
8
+ tplinkrouterc6u/dataclass.py,sha256=SuAOqKun_ThaeUEa8F9wi6qu4ucUatYMzebo39Kk10s,6617
9
+ tplinkrouterc6u/encryption.py,sha256=4HelTxzN6esMfDZRBt3m8bwB9Nj_biKijnCnrGWPWKg,6228
10
+ tplinkrouterc6u/exception.py,sha256=PUTPsadxiylQhIRUMfkN1RWXh07cHmdav9Pdgxs3Lmw,90
11
+ tplinkrouterc6u/helper.py,sha256=mbPkS_9GfOYMxEIx-q-xLlupR0-m_MDgCWQgx8xxOA8,172
12
+ tplinkrouterc6u/package_enum.py,sha256=bqmnu4gQMEntMCgsya2R7dRcrSJIDPWMj8vNN6JxeME,1382
13
+ tplinkrouterc6u-5.0.0.dist-info/LICENSE,sha256=YF6QR6Vjxcg5b_sYIyqkME7FZYau5TfEUGTG-0JeRK0,35129
14
+ tplinkrouterc6u-5.0.0.dist-info/METADATA,sha256=z8zgcEfcEO358npxVgWcDCDDuHsEoKtusw428SU_mt0,11859
15
+ tplinkrouterc6u-5.0.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
16
+ tplinkrouterc6u-5.0.0.dist-info/top_level.txt,sha256=1iSCCIueqgEkrTxtQ-jiHe99jAB10zqrVdBcwvNfe_M,21
17
+ tplinkrouterc6u-5.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,16 +0,0 @@
1
- test/__init__.py,sha256=McQmUjeN3AwmwdS6QNfwGXXE77OKoPK852I2BM9XsrU,210
2
- test/test_client.py,sha256=8cK4qnheszu-zpUJqttKp5Z5WJXrQy1t_fMzMzNnmvw,30638
3
- test/test_client_c1200.py,sha256=O6NK9uXIEb_vks6lI3g7j6q8TYJ9MSDFYzGA_wOBhOA,4620
4
- test/test_client_deco.py,sha256=8mo_9KEqVBsrazBHaGUdQTIsSvXcHtCT-l7MBxXSP3o,30478
5
- test/test_client_mr.py,sha256=znDA8PBxHOGKbZHzsyERbEEWjkP0U5KpV8Z-kaRnXIM,23046
6
- tplinkrouterc6u/__init__.py,sha256=CECjWGaoM8ABX3-95GUa4Xg9DCKzX2k8IprPg1fvnYw,402
7
- tplinkrouterc6u/client.py,sha256=7-S8FFD9ML5qHT0-7mzb-FQhmcmytNlB0J778235N4Q,51626
8
- tplinkrouterc6u/dataclass.py,sha256=VVLeWzH6_HYvjiw31aWisW5w8UTgiojWTgnQB7Tb5eM,6609
9
- tplinkrouterc6u/encryption.py,sha256=2InKlHLQSWkcI8yP8EIGSG-bGXft_KU-bplGjcoeE-k,5546
10
- tplinkrouterc6u/enum.py,sha256=bqmnu4gQMEntMCgsya2R7dRcrSJIDPWMj8vNN6JxeME,1382
11
- tplinkrouterc6u/exception.py,sha256=PUTPsadxiylQhIRUMfkN1RWXh07cHmdav9Pdgxs3Lmw,90
12
- tplinkrouterc6u-4.2.2.dist-info/LICENSE,sha256=YF6QR6Vjxcg5b_sYIyqkME7FZYau5TfEUGTG-0JeRK0,35129
13
- tplinkrouterc6u-4.2.2.dist-info/METADATA,sha256=50OdAco8AZW3sdxHol7OuMlVYU56h_cQiws-XjG6kFY,13036
14
- tplinkrouterc6u-4.2.2.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
15
- tplinkrouterc6u-4.2.2.dist-info/top_level.txt,sha256=1iSCCIueqgEkrTxtQ-jiHe99jAB10zqrVdBcwvNfe_M,21
16
- tplinkrouterc6u-4.2.2.dist-info/RECORD,,
File without changes