tplinkrouterc6u 5.12.4__tar.gz → 5.13.0__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 (48) hide show
  1. {tplinkrouterc6u-5.12.4/tplinkrouterc6u.egg-info → tplinkrouterc6u-5.13.0}/PKG-INFO +10 -2
  2. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/README.md +9 -1
  3. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/setup.py +1 -1
  4. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_c6u.py +52 -19
  5. tplinkrouterc6u-5.13.0/test/test_client_c6u_v1_11.py +95 -0
  6. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_ex.py +80 -0
  7. tplinkrouterc6u-5.13.0/test/test_client_r.py +633 -0
  8. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_xdr.py +5 -0
  9. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/__init__.py +2 -1
  10. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/c6u.py +97 -0
  11. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/ex.py +9 -11
  12. tplinkrouterc6u-5.13.0/tplinkrouterc6u/client/r.py +198 -0
  13. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/xdr.py +10 -1
  14. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/provider.py +4 -1
  15. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0/tplinkrouterc6u.egg-info}/PKG-INFO +10 -2
  16. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u.egg-info/SOURCES.txt +3 -0
  17. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/LICENSE +0 -0
  18. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/setup.cfg +0 -0
  19. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/__init__.py +0 -0
  20. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_c1200.py +0 -0
  21. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_c80.py +0 -0
  22. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_deco.py +0 -0
  23. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_mr.py +0 -0
  24. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_mr_200.py +0 -0
  25. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_re330.py +0 -0
  26. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_vr400v2.py +0 -0
  27. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/test/test_client_wdr.py +0 -0
  28. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/__init__.py +0 -0
  29. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/c1200.py +0 -0
  30. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/c5400x.py +0 -0
  31. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/c80.py +0 -0
  32. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/deco.py +0 -0
  33. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/mr.py +0 -0
  34. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/mr200.py +0 -0
  35. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/re330.py +0 -0
  36. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/vr.py +0 -0
  37. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/vr400v2.py +0 -0
  38. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client/wdr.py +0 -0
  39. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/client_abstract.py +0 -0
  40. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/common/__init__.py +0 -0
  41. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/common/dataclass.py +0 -0
  42. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/common/encryption.py +0 -0
  43. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/common/exception.py +0 -0
  44. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/common/helper.py +0 -0
  45. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u/common/package_enum.py +0 -0
  46. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u.egg-info/dependency_links.txt +0 -0
  47. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/tplinkrouterc6u.egg-info/requires.txt +0 -0
  48. {tplinkrouterc6u-5.12.4 → tplinkrouterc6u-5.13.0}/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.4
3
+ Version: 5.13.0
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
@@ -56,6 +56,7 @@ Python package for API access and management for TP-Link and Mercusys Routers. S
56
56
  ```python
57
57
  from tplinkrouterc6u import (
58
58
  TplinkRouterProvider,
59
+ TplinkRouterV1_11,
59
60
  TplinkRouter,
60
61
  TplinkC1200Router,
61
62
  TplinkC5400XRouter,
@@ -66,6 +67,7 @@ from tplinkrouterc6u import (
66
67
  TPLinkVR400v2Client,
67
68
  TPLinkEXClient, # Class for EX series routers which supports old firmwares with AES cipher CBC mode
68
69
  TPLinkEXClientGCM, # Class for EX series routers which supports AES cipher GCM mode
70
+ TPLinkRClient,
69
71
  TPLinkXDRClient,
70
72
  TPLinkDecoClient,
71
73
  TplinkC80Router,
@@ -83,7 +85,7 @@ router = TplinkRouterProvider.get_client('http://192.168.0.1', 'password')
83
85
  # If you have the TP-link C5400X or similar, you can use the TplinkC5400XRouter class instead of the TplinkRouter class.
84
86
  # Remember that the password for this router is different, here you need to use the web encrypted password.
85
87
  # To get web encrypted password, read Web Encrypted Password section
86
- # router = TplinkC5400XRouter('http://192.168.0.1','WebEncryptedPassword', Logger('test'))
88
+ # router = TplinkC5400XRouter('http://192.168.0.1','WebEncryptedPassword', logger: Logger('test'))
87
89
 
88
90
  try:
89
91
  router.authorize() # authorizing
@@ -380,7 +382,10 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
380
382
  - Deco XE75PRO (v3.0)
381
383
  - EX511 v2.0
382
384
  - HX510 v1.0
385
+ - M8550 v1
386
+ - NE200-Outdoor v1.0
383
387
  - NX510v v1.0
388
+ - NX600 v2.0
384
389
  - TD-W9960 (v1, V1.20)
385
390
  - TL-MR100 v2.0
386
391
  - TL-MR105
@@ -389,10 +394,13 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
389
394
  - TL-MR150 v2
390
395
  - TL-MR6400 (v5, v5.3)
391
396
  - TL-MR6500v
397
+ - TL-R470GP-AC 4.0
398
+ - TL-R488GPM-AC 2.0
392
399
  - TL-WA1201 3.0
393
400
  - TL-WA3001 v1.0
394
401
  - TL-XDR3010 V2
395
402
  - TL-WDR3600 V1
403
+ - TL-XDR5410 1.0
396
404
  - TL-XDR6088 v1.0.30
397
405
  - VX420-G2h v1.1
398
406
  - VX800v v1
@@ -23,6 +23,7 @@ Python package for API access and management for TP-Link and Mercusys Routers. S
23
23
  ```python
24
24
  from tplinkrouterc6u import (
25
25
  TplinkRouterProvider,
26
+ TplinkRouterV1_11,
26
27
  TplinkRouter,
27
28
  TplinkC1200Router,
28
29
  TplinkC5400XRouter,
@@ -33,6 +34,7 @@ from tplinkrouterc6u import (
33
34
  TPLinkVR400v2Client,
34
35
  TPLinkEXClient, # Class for EX series routers which supports old firmwares with AES cipher CBC mode
35
36
  TPLinkEXClientGCM, # Class for EX series routers which supports AES cipher GCM mode
37
+ TPLinkRClient,
36
38
  TPLinkXDRClient,
37
39
  TPLinkDecoClient,
38
40
  TplinkC80Router,
@@ -50,7 +52,7 @@ router = TplinkRouterProvider.get_client('http://192.168.0.1', 'password')
50
52
  # If you have the TP-link C5400X or similar, you can use the TplinkC5400XRouter class instead of the TplinkRouter class.
51
53
  # Remember that the password for this router is different, here you need to use the web encrypted password.
52
54
  # To get web encrypted password, read Web Encrypted Password section
53
- # router = TplinkC5400XRouter('http://192.168.0.1','WebEncryptedPassword', Logger('test'))
55
+ # router = TplinkC5400XRouter('http://192.168.0.1','WebEncryptedPassword', logger: Logger('test'))
54
56
 
55
57
  try:
56
58
  router.authorize() # authorizing
@@ -347,7 +349,10 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
347
349
  - Deco XE75PRO (v3.0)
348
350
  - EX511 v2.0
349
351
  - HX510 v1.0
352
+ - M8550 v1
353
+ - NE200-Outdoor v1.0
350
354
  - NX510v v1.0
355
+ - NX600 v2.0
351
356
  - TD-W9960 (v1, V1.20)
352
357
  - TL-MR100 v2.0
353
358
  - TL-MR105
@@ -356,10 +361,13 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
356
361
  - TL-MR150 v2
357
362
  - TL-MR6400 (v5, v5.3)
358
363
  - TL-MR6500v
364
+ - TL-R470GP-AC 4.0
365
+ - TL-R488GPM-AC 2.0
359
366
  - TL-WA1201 3.0
360
367
  - TL-WA3001 v1.0
361
368
  - TL-XDR3010 V2
362
369
  - TL-WDR3600 V1
370
+ - TL-XDR5410 1.0
363
371
  - TL-XDR6088 v1.0.30
364
372
  - VX420-G2h v1.1
365
373
  - VX800v v1
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="tplinkrouterc6u",
8
- version="5.12.4",
8
+ version="5.13.0",
9
9
  author="Alex Erohin",
10
10
  author_email="alexanderErohin@yandex.ru",
11
11
  description="TP-Link Router API (supports also Mercusys Router)",
@@ -14,6 +14,12 @@ from tplinkrouterc6u import (
14
14
 
15
15
 
16
16
  class TestTPLinkClient(TestCase):
17
+ router_class = TplinkRouter
18
+ game_accelerator_path = 'admin/smart_network?form=game_accelerator'
19
+ openvpn_config_path = 'admin/openvpn?form=config'
20
+ pptpd_config_path = 'admin/pptpd?form=config'
21
+ vpn_uses_data_param = True
22
+
17
23
  def test_get_status(self) -> None:
18
24
  response_status = '''
19
25
  {
@@ -211,7 +217,9 @@ class TestTPLinkClient(TestCase):
211
217
  }
212
218
  '''
213
219
 
214
- class TPLinkRouterTest(TplinkRouter):
220
+ router_class = self.router_class
221
+
222
+ class TPLinkRouterTest(router_class):
215
223
  def request(self, path: str, data: str,
216
224
  ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
217
225
  if path == 'admin/status?form=all&operation=read':
@@ -339,7 +347,9 @@ class TestTPLinkClient(TestCase):
339
347
  }
340
348
  '''
341
349
 
342
- class TPLinkRouterTest(TplinkRouter):
350
+ router_class = self.router_class
351
+
352
+ class TPLinkRouterTest(router_class):
343
353
  def request(self, path: str, data: str,
344
354
  ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
345
355
  if path == 'admin/status?form=all&operation=read':
@@ -484,12 +494,15 @@ class TestTPLinkClient(TestCase):
484
494
  }
485
495
  '''
486
496
 
487
- class TPLinkRouterTest(TplinkRouter):
497
+ router_class = self.router_class
498
+ game_accelerator_path = self.game_accelerator_path
499
+
500
+ class TPLinkRouterTest(router_class):
488
501
  def request(self, path: str, data: str,
489
502
  ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
490
503
  if path == 'admin/status?form=all&operation=read':
491
504
  return loads(response_status)['data']
492
- elif path == 'admin/smart_network?form=game_accelerator':
505
+ elif path == game_accelerator_path:
493
506
  return loads(response_game_accelerator)['data']
494
507
  elif path == 'admin/wireless?form=statistics':
495
508
  return loads(response_stats)['data']
@@ -618,7 +631,9 @@ class TestTPLinkClient(TestCase):
618
631
  }
619
632
  '''
620
633
 
621
- class TPLinkRouterTest(TplinkRouter):
634
+ router_class = self.router_class
635
+
636
+ class TPLinkRouterTest(router_class):
622
637
  def request(self, path: str, data: str,
623
638
  ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
624
639
  if path == 'admin/status?form=all&operation=read':
@@ -661,8 +676,9 @@ class TestTPLinkClient(TestCase):
661
676
  def test_set_wifi(self) -> None:
662
677
  check_url = ''
663
678
  check_data = ''
679
+ router_class = self.router_class
664
680
 
665
- class TPLinkRouterTest(TplinkRouter):
681
+ class TPLinkRouterTest(router_class):
666
682
  def request(self, path: str, data: str,
667
683
  ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
668
684
  nonlocal check_url, check_data
@@ -705,8 +721,9 @@ class TestTPLinkClient(TestCase):
705
721
 
706
722
  def test_get_ipv4_status_empty(self) -> None:
707
723
  response_network = '{"result": {}, "error_code": 0}'
724
+ router_class = self.router_class
708
725
 
709
- class TPLinkRouterTest(TplinkRouter):
726
+ class TPLinkRouterTest(router_class):
710
727
  def request(self, path: str, data: str,
711
728
  ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
712
729
  if path == 'admin/network?form=status_ipv4&operation=read':
@@ -750,8 +767,9 @@ class TestTPLinkClient(TestCase):
750
767
  "operator": "load"
751
768
  }
752
769
  '''
770
+ router_class = self.router_class
753
771
 
754
- class TPLinkRouterTest(TplinkRouter):
772
+ class TPLinkRouterTest(router_class):
755
773
  def request(self, path: str, data: str,
756
774
  ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
757
775
  if path == 'admin/status?form=all&operation=read':
@@ -800,8 +818,9 @@ class TestTPLinkClient(TestCase):
800
818
  }
801
819
  }
802
820
  '''
821
+ router_class = self.router_class
803
822
 
804
- class TPLinkRouterTest(TplinkRouter):
823
+ class TPLinkRouterTest(router_class):
805
824
  def request(self, path: str, data: str,
806
825
  ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
807
826
  if path == 'admin/status?form=all&operation=read':
@@ -871,7 +890,12 @@ class TestTPLinkClient(TestCase):
871
890
  "extra": "7450", "vpntype": "pptp", "key": "7450"}
872
891
  ]"""
873
892
 
874
- class TPLinkRouterTest(TplinkRouter):
893
+ router_class = self.router_class
894
+ openvpn_config_path = self.openvpn_config_path
895
+ pptpd_config_path = self.pptpd_config_path
896
+ vpn_uses_data_param = self.vpn_uses_data_param
897
+
898
+ class TPLinkRouterTest(router_class):
875
899
  def request(
876
900
  self,
877
901
  path: str,
@@ -879,14 +903,20 @@ class TestTPLinkClient(TestCase):
879
903
  ignore_response: bool = False,
880
904
  ignore_errors: bool = False,
881
905
  ) -> dict | None:
882
- if path == "admin/openvpn?form=config":
906
+ if path == openvpn_config_path:
883
907
  return loads(response_openvpn_read)
884
- if path == "admin/pptpd?form=config":
908
+ if path == pptpd_config_path:
885
909
  return loads(response_pptp_read)
886
- if path == "admin/vpnconn?form=config" and data == "operation=list&vpntype=openvpn":
887
- return loads(respone_vpnconn_openvpn)
888
- if path == "admin/vpnconn?form=config" and data == "operation=list&vpntype=pptp":
889
- return loads(respone_vpnconn_pptpvpn)
910
+ if vpn_uses_data_param:
911
+ if path == "admin/vpnconn?form=config" and data == "operation=list&vpntype=openvpn":
912
+ return loads(respone_vpnconn_openvpn)
913
+ if path == "admin/vpnconn?form=config" and data == "operation=list&vpntype=pptp":
914
+ return loads(respone_vpnconn_pptpvpn)
915
+ else:
916
+ if path == "admin/vpnconn?form=config&operation=list&vpntype=openvpn":
917
+ return loads(respone_vpnconn_openvpn)
918
+ if path == "admin/vpnconn?form=config&operation=list&vpntype=pptp":
919
+ return loads(respone_vpnconn_pptpvpn)
890
920
  raise ClientException()
891
921
 
892
922
  client = TPLinkRouterTest("", "")
@@ -910,7 +940,10 @@ class TestTPLinkClient(TestCase):
910
940
  }
911
941
  """
912
942
 
913
- class TPLinkRouterTest(TplinkRouter):
943
+ router_class = self.router_class
944
+ openvpn_config_path = self.openvpn_config_path
945
+
946
+ class TPLinkRouterTest(router_class):
914
947
  def request(
915
948
  self,
916
949
  path: str,
@@ -918,7 +951,7 @@ class TestTPLinkClient(TestCase):
918
951
  ignore_response: bool = False,
919
952
  ignore_errors: bool = False,
920
953
  ) -> dict | None:
921
- if path == "admin/openvpn?form=config" and data == "operation=read":
954
+ if path == openvpn_config_path and data == "operation=read":
922
955
  return loads(response_openvpn_read)
923
956
  self.captured_path = path
924
957
  self.captured_data = data
@@ -930,7 +963,7 @@ class TestTPLinkClient(TestCase):
930
963
  "operation=write&enabled=on"
931
964
  "&proto=udp&access=home&cert_exist=True&mask=255.255.255.0&port=1194&serverip=10.8.0.0"
932
965
  )
933
- self.assertEqual(client.captured_path, 'admin/openvpn?form=config')
966
+ self.assertEqual(client.captured_path, self.openvpn_config_path)
934
967
  self.assertEqual(client.captured_data, expected_data)
935
968
 
936
969
 
@@ -0,0 +1,95 @@
1
+ from unittest import main
2
+ from unittest.mock import patch, Mock
3
+ from test_client_c6u import TestTPLinkClient
4
+ from tplinkrouterc6u import TplinkRouterV1_11, ClientException
5
+
6
+
7
+ class TestTPLinkClientV1_11(TestTPLinkClient):
8
+ """Inherits all tests from TestTPLinkClient, using TplinkRouterV1_11."""
9
+
10
+ router_class = TplinkRouterV1_11
11
+ game_accelerator_path = 'admin/smart_network?form=game_accelerator&operation=loadDevice'
12
+ openvpn_config_path = 'admin/openvpn?form=config&operation=read'
13
+ pptpd_config_path = 'admin/pptpd?form=config&operation=read'
14
+ vpn_uses_data_param = False
15
+
16
+ # V1_11-specific tests only
17
+
18
+ def test_supports_password_too_long(self) -> None:
19
+ long_password = 'a' * 126
20
+ client = TplinkRouterV1_11('http://192.168.0.1', long_password)
21
+ self.assertFalse(client.supports())
22
+
23
+ @patch('tplinkrouterc6u.client.c6u.EncryptionWrapper.rsa_encrypt')
24
+ @patch('tplinkrouterc6u.client.c6u.post')
25
+ def test_authorize_success(self, mock_post: Mock, mock_rsa: Mock) -> None:
26
+ mock_rsa.return_value = 'encrypted_password_hex'
27
+
28
+ keys_response = Mock()
29
+ keys_response.json.return_value = {
30
+ 'success': True,
31
+ 'data': {
32
+ 'password': ['mock_nn_value', '010001']
33
+ }
34
+ }
35
+
36
+ login_response = Mock()
37
+ login_response.json.return_value = {
38
+ 'success': True,
39
+ 'data': {
40
+ 'stok': 'test_stok_12345'
41
+ }
42
+ }
43
+ login_response.headers = {'set-cookie': 'sysauth=test_sysauth_cookie; path=/'}
44
+
45
+ mock_post.side_effect = [keys_response, login_response]
46
+
47
+ client = TplinkRouterV1_11('http://192.168.0.1', 'testpassword')
48
+ client.authorize()
49
+
50
+ self.assertTrue(client._logged)
51
+ self.assertEqual(client._stok, 'test_stok_12345')
52
+ self.assertEqual(client._sysauth, 'test_sysauth_cookie')
53
+ self.assertEqual(mock_post.call_count, 2)
54
+
55
+ first_call = mock_post.call_args_list[0]
56
+ self.assertIn('login?form=keys', first_call[0][0])
57
+
58
+ second_call = mock_post.call_args_list[1]
59
+ self.assertIn('login?form=login', second_call[0][0])
60
+ login_data = second_call[1]['data']
61
+ self.assertTrue(login_data.startswith('operation=login&password='))
62
+
63
+ @patch('tplinkrouterc6u.client.c6u.EncryptionWrapper.rsa_encrypt')
64
+ @patch('tplinkrouterc6u.client.c6u.post')
65
+ def test_authorize_failure(self, mock_post: Mock, mock_rsa: Mock) -> None:
66
+ mock_rsa.return_value = 'encrypted_password_hex'
67
+
68
+ keys_response = Mock()
69
+ keys_response.json.return_value = {
70
+ 'success': True,
71
+ 'data': {
72
+ 'password': ['mock_nn_value', '010001']
73
+ }
74
+ }
75
+
76
+ login_response = Mock()
77
+ login_response.json.return_value = {
78
+ 'success': False,
79
+ 'data': {'errorcode': 'invalid password'}
80
+ }
81
+ login_response.headers = {}
82
+
83
+ mock_post.side_effect = [keys_response, login_response]
84
+
85
+ client = TplinkRouterV1_11('http://192.168.0.1', 'wrongpassword')
86
+
87
+ with self.assertRaises(ClientException) as context:
88
+ client.authorize()
89
+
90
+ self.assertIn('Login failed', str(context.exception))
91
+ self.assertFalse(client._logged)
92
+
93
+
94
+ if __name__ == '__main__':
95
+ main()
@@ -204,6 +204,86 @@ class TestTPLinkEXClient(TestCase):
204
204
  self.assertEqual(status.devices[1].packets_sent, None) # TODO
205
205
  self.assertEqual(status.devices[1].packets_received, None) # TODO
206
206
 
207
+ def test_get_status_NE200(self) -> None:
208
+ DEV2_ADT_LAN = ('{"data":[{"MACAddress":"a0:28:84:de:dd:5c","IPAddress":"192.168.4.1","stack":"1,0,0,0,0,0"}],'
209
+ '"operation":"gl","oid":"DEV2_ADT_LAN","success":true}')
210
+ DEV2_ADT_WAN = ('{"data":[{"enable":"1","MACAddr":"","connIPv4Address":"","connIPv4Gateway":""'
211
+ ',"stack":"1,0,0,0,0,0"}],"operation":"gl","oid":"DEV2_ADT_WAN","success":true}')
212
+ DEV2_ADT_WIFI_COMMON = ('{"data":[],"operation":"gl",'
213
+ '"oid":"DEV2_ADT_WIFI_COMMON","success":true}')
214
+ DEV2_HOST_ENTRY = ('{"data":[{"active":"1","X_TP_LanConnType":"1","physAddress":"66-E2-02-BD-B5-1B",'
215
+ '"IPAddress":"192.168.30.10","hostName":"host1","stack":"1,0,0,0,0,0"},'
216
+ '{"active":"1","X_TP_LanConnType":"1","physAddress":"F4-A3-86-2D-41-B5",'
217
+ '"IPAddress":"192.168.30.11","hostName":"host2","stack":"2,0,0,0,0,0"}],"operation":"gl",'
218
+ '"oid":"DEV2_HOST_ENTRY","success":true}')
219
+ DEV2_MEM_STATUS = ('{"data":{"total":"192780","free":"78400","stack":"0,0,0,0,0,0"},"operation":"go",'
220
+ '"oid":"DEV2_MEM_STATUS","success":true}')
221
+ DEV2_PROC_STATUS = ('{"data":{"CPUUsage":"69","stack":"0,0,0,0,0,0"},"operation":"go",'
222
+ '"oid":"DEV2_PROC_STATUS","success":true}')
223
+
224
+ class TPLinkEXClientTest(TPLinkEXClient):
225
+ self._token = True
226
+
227
+ def _request(self, url, method='POST', data_str=None, encrypt=False):
228
+ if 'DEV2_ADT_LAN' in data_str:
229
+ return 200, DEV2_ADT_LAN
230
+ elif 'DEV2_ADT_WAN' in data_str:
231
+ return 200, DEV2_ADT_WAN
232
+ elif 'DEV2_ADT_WIFI_COMMON' in data_str:
233
+ return 200, DEV2_ADT_WIFI_COMMON
234
+ elif 'DEV2_HOST_ENTRY' in data_str:
235
+ return 200, DEV2_HOST_ENTRY
236
+ elif 'DEV2_MEM_STATUS' in data_str:
237
+ return 200, DEV2_MEM_STATUS
238
+ elif 'DEV2_PROC_STATUS' in data_str:
239
+ return 200, DEV2_PROC_STATUS
240
+ raise ClientException()
241
+
242
+ client = TPLinkEXClientTest('', '')
243
+ status = client.get_status()
244
+
245
+ self.assertIsInstance(status, Status)
246
+ self.assertEqual(status.wan_macaddr, None)
247
+ self.assertEqual(status.lan_macaddr, 'A0-28-84-DE-DD-5C')
248
+ self.assertIsInstance(status.lan_macaddress, EUI48)
249
+ self.assertEqual(status.wan_ipv4_addr, None)
250
+ self.assertEqual(status.lan_ipv4_addr, '192.168.4.1')
251
+ self.assertEqual(status.wan_ipv4_gateway, None)
252
+ self.assertEqual(status.wired_total, 0)
253
+ self.assertEqual(status.wifi_clients_total, 2)
254
+ self.assertEqual(status.guest_clients_total, 0)
255
+ self.assertEqual(status.clients_total, 2)
256
+ self.assertEqual(status.guest_2g_enable, None)
257
+ self.assertEqual(status.guest_5g_enable, None)
258
+ self.assertEqual(status.iot_2g_enable, None)
259
+ self.assertEqual(status.iot_5g_enable, None)
260
+ self.assertEqual(status.wifi_2g_enable, None)
261
+ self.assertEqual(status.wifi_5g_enable, None)
262
+ self.assertEqual(status.wan_ipv4_uptime, None)
263
+ self.assertGreaterEqual(status.mem_usage, 0)
264
+ self.assertLessEqual(status.mem_usage, 1)
265
+ self.assertGreaterEqual(status.cpu_usage, 0)
266
+ self.assertLessEqual(status.cpu_usage, 1)
267
+ self.assertEqual(len(status.devices), 2)
268
+ self.assertIsInstance(status.devices[0], Device)
269
+ self.assertEqual(status.devices[0].type, Connection.HOST_2G)
270
+ self.assertEqual(status.devices[0].macaddr, '66-E2-02-BD-B5-1B')
271
+ self.assertIsInstance(status.devices[0].macaddress, EUI48)
272
+ self.assertEqual(status.devices[0].ipaddr, '192.168.30.10')
273
+ self.assertIsInstance(status.devices[0].ipaddress, IPv4Address)
274
+ self.assertEqual(status.devices[0].hostname, 'host1')
275
+ self.assertEqual(status.devices[0].packets_sent, None)
276
+ self.assertEqual(status.devices[0].packets_received, None)
277
+ self.assertIsInstance(status.devices[1], Device)
278
+ self.assertEqual(status.devices[1].type, Connection.HOST_2G)
279
+ self.assertEqual(status.devices[1].macaddr, 'F4-A3-86-2D-41-B5')
280
+ self.assertIsInstance(status.devices[1].macaddress, EUI48)
281
+ self.assertEqual(status.devices[1].ipaddr, '192.168.30.11')
282
+ self.assertIsInstance(status.devices[1].ipaddress, IPv4Address)
283
+ self.assertEqual(status.devices[1].hostname, 'host2')
284
+ self.assertEqual(status.devices[1].packets_sent, None) # TODO
285
+ self.assertEqual(status.devices[1].packets_received, None) # TODO
286
+
207
287
  def test_get_ipv4_reservations(self) -> None:
208
288
 
209
289
  response = ('{"data":[{"enable":"1","chaddr":"bf:75:44:4c:dc:9e","yiaddr":"192.168.8.21",'