tplinkrouterc6u 5.7.0__py3-none-any.whl → 5.9.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_c1200.py CHANGED
@@ -5,7 +5,6 @@ from tplinkrouterc6u import (
5
5
  Connection,
6
6
  ClientException,
7
7
  )
8
- from tplinkrouterc6u.common.package_enum import VPN
9
8
 
10
9
 
11
10
  class TestTPLinkC1200Client(TestCase):
@@ -201,13 +200,13 @@ class TestTPLinkC1200Client(TestCase):
201
200
  ignore_response: bool = False,
202
201
  ignore_errors: bool = False,
203
202
  ) -> dict | None:
204
- if path == "/admin/openvpn?form=config&operation=read":
203
+ if path == "admin/openvpn?form=config&operation=read":
205
204
  return loads(response_openvpn_read)
206
- if path == "/admin/pptpd?form=config&operation=read":
205
+ if path == "admin/pptpd?form=config&operation=read":
207
206
  return loads(response_pptp_read)
208
- if path == "/admin/vpnconn?form=config&operation=list&vpntype=openvpn":
207
+ if path == "admin/vpnconn?form=config&operation=list&vpntype=openvpn":
209
208
  return loads(respone_vpnconn_openvpn)
210
- if path == "/admin/vpnconn?form=config&operation=list&vpntype=pptp":
209
+ if path == "admin/vpnconn?form=config&operation=list&vpntype=pptp":
211
210
  return loads(respone_vpnconn_pptpvpn)
212
211
  raise ClientException()
213
212
 
@@ -219,41 +218,6 @@ class TestTPLinkC1200Client(TestCase):
219
218
  self.assertEqual(vpn_status.openvpn_clients_total, 2)
220
219
  self.assertEqual(vpn_status.pptpvpn_clients_total, 3)
221
220
 
222
- def test_set_vpn(self) -> None:
223
- response_openvpn_read = """
224
- {
225
- "enabled": "on",
226
- "proto": "udp",
227
- "access": "home",
228
- "cert_exist": true,
229
- "mask": "255.255.255.0",
230
- "port": "1194",
231
- "serverip": "10.8.0.0"
232
- }
233
- """
234
-
235
- class TPLinkRouterTest(TplinkC1200Router):
236
- def request(
237
- self,
238
- path: str,
239
- data: str,
240
- ignore_response: bool = False,
241
- ignore_errors: bool = False,
242
- ) -> dict | None:
243
- if path == "/admin/openvpn?form=config&operation=read":
244
- return loads(response_openvpn_read)
245
- self.captured_path = path
246
-
247
- client = TPLinkRouterTest("", "")
248
- client.set_vpn(VPN.OPEN_VPN, True)
249
-
250
- expected_path = (
251
- "/admin/openvpn?form=config&operation=write&enabled=on"
252
- "&proto=udp&access=home&cert_exist=True"
253
- "&mask=255.255.255.0&port=1194&serverip=10.8.0.0"
254
- )
255
- self.assertEqual(client.captured_path, expected_path)
256
-
257
221
 
258
222
  if __name__ == "__main__":
259
223
  main()
test/test_client_c6u.py CHANGED
@@ -9,6 +9,7 @@ from tplinkrouterc6u import (
9
9
  IPv4Status,
10
10
  Device,
11
11
  ClientException,
12
+ VPN,
12
13
  )
13
14
 
14
15
 
@@ -729,6 +730,146 @@ class TestTPLinkClient(TestCase):
729
730
  self.assertEqual(result.lan_ipv4_dhcp_enable, False)
730
731
  self.assertEqual(result.remote, None)
731
732
 
733
+ def test_get_status_wan_macaddr_empty(self) -> None:
734
+ response_status = '''
735
+ {
736
+ "success": true,
737
+ "data": {
738
+ "lan_macaddr": "06:e6:97:9e:23:f5",
739
+ "wan_macaddr": "",
740
+ "wan_ipv4_ipaddr": "0.0.0.0",
741
+ "wan_ipv4_gateway": "0.0.0.0"
742
+ }
743
+ }
744
+ '''
745
+ response_stats = '''
746
+ {
747
+ "data": [],
748
+ "timeout": false,
749
+ "success": true,
750
+ "operator": "load"
751
+ }
752
+ '''
753
+
754
+ class TPLinkRouterTest(TplinkRouter):
755
+ def request(self, path: str, data: str,
756
+ ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
757
+ if path == 'admin/status?form=all&operation=read':
758
+ return loads(response_status)['data']
759
+ elif path == 'admin/wireless?form=statistics':
760
+ return loads(response_stats)['data']
761
+ raise ClientException()
762
+
763
+ client = TPLinkRouterTest('', '')
764
+ result = client.get_status()
765
+
766
+ self.assertIsInstance(result, Status)
767
+ self.assertEqual(result.wan_macaddr, None)
768
+ self.assertEqual(result.wan_ipv4_addr, '0.0.0.0')
769
+ self.assertEqual(result.wan_ipv4_gateway, '0.0.0.0')
770
+ self.assertEqual(result.lan_macaddr, '06-E6-97-9E-23-F5')
771
+
772
+ def test_vpn_status(self) -> None:
773
+ response_openvpn_read = """
774
+ {
775
+ "enabled": "on",
776
+ "proto": "udp",
777
+ "access": "home",
778
+ "cert_exist": true,
779
+ "mask": "255.255.255.0",
780
+ "port": "1194",
781
+ "serverip": "10.8.0.0"
782
+ }
783
+ """
784
+
785
+ response_pptp_read = """
786
+ {
787
+ "enabled": "off",
788
+ "unencrypted_access": "on",
789
+ "samba_access": "on",
790
+ "netbios_pass": "on",
791
+ "remoteip": "10.0.0.11-20"
792
+ }
793
+ """
794
+
795
+ respone_vpnconn_openvpn = """[
796
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
797
+ "extra": "7450", "vpntype": "openvpn", "key": "7450"},
798
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
799
+ "extra": "7450", "vpntype": "openvpn", "key": "7450"}
800
+ ]"""
801
+
802
+ respone_vpnconn_pptpvpn = """[
803
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
804
+ "extra": "7450", "vpntype": "pptp", "key": "7450"},
805
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
806
+ "extra": "7450", "vpntype": "pptp", "key": "7450"},
807
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
808
+ "extra": "7450", "vpntype": "pptp", "key": "7450"}
809
+ ]"""
810
+
811
+ class TPLinkRouterTest(TplinkRouter):
812
+ def request(
813
+ self,
814
+ path: str,
815
+ data: str,
816
+ ignore_response: bool = False,
817
+ ignore_errors: bool = False,
818
+ ) -> dict | None:
819
+ if path == "admin/openvpn?form=config":
820
+ return loads(response_openvpn_read)
821
+ if path == "admin/pptpd?form=config":
822
+ return loads(response_pptp_read)
823
+ if path == "admin/vpnconn?form=config" and data == "operation=list&vpntype=openvpn":
824
+ return loads(respone_vpnconn_openvpn)
825
+ if path == "admin/vpnconn?form=config" and data == "operation=list&vpntype=pptp":
826
+ return loads(respone_vpnconn_pptpvpn)
827
+ raise ClientException()
828
+
829
+ client = TPLinkRouterTest("", "")
830
+
831
+ vpn_status = client.get_vpn_status()
832
+ self.assertTrue(vpn_status.openvpn_enable)
833
+ self.assertFalse(vpn_status.pptpvpn_enable)
834
+ self.assertEqual(vpn_status.openvpn_clients_total, 2)
835
+ self.assertEqual(vpn_status.pptpvpn_clients_total, 3)
836
+
837
+ def test_set_vpn(self) -> None:
838
+ response_openvpn_read = """
839
+ {
840
+ "enabled": "on",
841
+ "proto": "udp",
842
+ "access": "home",
843
+ "cert_exist": true,
844
+ "mask": "255.255.255.0",
845
+ "port": "1194",
846
+ "serverip": "10.8.0.0"
847
+ }
848
+ """
849
+
850
+ class TPLinkRouterTest(TplinkRouter):
851
+ def request(
852
+ self,
853
+ path: str,
854
+ data: str,
855
+ ignore_response: bool = False,
856
+ ignore_errors: bool = False,
857
+ ) -> dict | None:
858
+ if path == "admin/openvpn?form=config" and data == "operation=read":
859
+ return loads(response_openvpn_read)
860
+ self.captured_path = path
861
+ self.captured_data = data
862
+
863
+ client = TPLinkRouterTest("", "")
864
+ client.set_vpn(VPN.OPEN_VPN, True)
865
+
866
+ expected_data = (
867
+ "operation=write&enabled=on"
868
+ "&proto=udp&access=home&cert_exist=True&mask=255.255.255.0&port=1194&serverip=10.8.0.0"
869
+ )
870
+ self.assertEqual(client.captured_path, 'admin/openvpn?form=config')
871
+ self.assertEqual(client.captured_data, expected_data)
872
+
732
873
 
733
874
  if __name__ == '__main__':
734
875
  main()
@@ -0,0 +1,292 @@
1
+ from unittest import main, TestCase
2
+ from ipaddress import IPv4Address
3
+ from macaddress import EUI48
4
+ from tplinkrouterc6u.common.dataclass import Firmware, Status
5
+ from tplinkrouterc6u.common.dataclass import IPv4Status, IPv4Reservation, IPv4DHCPLease
6
+ from tplinkrouterc6u import ClientError
7
+ from tplinkrouterc6u.client.wdr import TplinkWDRRouter
8
+
9
+ _NETWAN = (
10
+ '<SCRIPT language="javascript" type="text/javascript">\nvar wanTypeDetectInfoArray = '
11
+ + "new Array(\n1, 0, 4500, \n0,0 );\n</SCRIPT>\n"
12
+ + '<SCRIPT language="javascript" type="text/javascript">\nvar dhcpInf = new Array(\n1,\n'
13
+ + '0,\n1,\n0,\n0,\n0,\n0,\n0,\n"",\n"",\n0,\n0,\n"",\n"192.168.0.129",\n"255.255.255.0",\n'
14
+ + '"192.168.0.1",\n1,\n0,\n1500,\n0,\n"8.8.8.8",\n1,\n"8.8.4.4",\n0,\n0,\n0,\n"TL-WDR3600",\n0,0 );\n</SCRIPT>\n'
15
+ + '<SCRIPT language="javascript" type="text/javascript">\nvar wantypeinfo = new Array(\n6,\n0,\n'
16
+ + '"WanDynamicIpCfgRpm.htm",\n1,\n"WanStaticIpCfgRpm.htm",\n'
17
+ + '2,\n"PPPoECfgRpm.htm",\n5,\n"BPACfgRpm.htm",\n6,\n"L2TPCfgRpm.htm",\n7,\n"PPTPCfgRpm.htm",\n0,0 );\n</SCRIPT>'
18
+ )
19
+ _NETLAN = (
20
+ '<SCRIPT language="javascript" type="text/javascript">\nvar lanPara = new Array(\n"C4-6E-1F-41-67-C0",\n'
21
+ + '"192.168.1.254",\n2,\n"255.255.255.0",\n1,\n0,0 );\n</SCRIPT>'
22
+ )
23
+
24
+ _W24STA = (
25
+ '<SCRIPT language="javascript" type="text/javascript">\nvar wlanHostPara = new Array(\n1, 1, 8, 5000, 4,\n'
26
+ + '0,0);\n</SCRIPT>\n<SCRIPT language="javascript" type="text/javascript">\nvar hostList = new Array(\n'
27
+ + '"D0-BD-53-57-3E-4A", 1, 170893827, 0,\n"08-16-AC-03-E2-FA", 1, 873409583, 0,\n"F8-F1-E8-CD-0A-CF", 1, '
28
+ + '240958643, 0,\n"ED-49-92-1A-1D-D7", 1, 358743698, 0,\n"0E-50-99-5D-9A-D5", 1, 572346959, 0,\n0,0 );\n</SCRIPT>'
29
+ )
30
+ _W50STA = (
31
+ '<SCRIPT language="javascript" type="text/javascript">\nvar wlanHostPara = new Array(\n1, 1, 8, 5000, 4,\n'
32
+ + '0,0 );\n</SCRIPT>\n<SCRIPT language="javascript" type="text/javascript">\nvar hostList = new Array(\n'
33
+ + '"50-A6-FC-6D-EB-D3", 1, 708938274, 0,\n"6A-D0-5F-2A-FA-2D", 1, 287340958, 0,\n"DA-69-2D-59-B3-FA", 1'
34
+ + ", 540958641, 0,\n0,0 );\n</SCRIPT>"
35
+ )
36
+
37
+ _WLANGUEST = (
38
+ '<SCRIPT language="javascript" type="text/javascript">\nvar guestNetworkBandwidthInf = '
39
+ + "new Array(\n"
40
+ + '0,\n1000000,\n1000000,\n1024,\n1024,\n1,\n0,0);\n</SCRIPT>\n<SCRIPT language="javascript" '
41
+ + 'type="text/javascript">'
42
+ + '\nvar guestNetAccTime2gInf = new Array(\n1,\n1,\n0,\n0,\n0,\n1,\n0,\n0,\n0,\n0,\n0,\n0,\n0,\n1,\n"",\n"",\n'
43
+ + "0,0 );"
44
+ + '\n</SCRIPT>\n<SCRIPT language="javascript" type="text/javascript">\nvar guestNetAccTime5gInf = new Array(\n'
45
+ + '1,\n0,\n0,\n0,\n0,\n1,\n0,\n0,\n0,\n0,\n0,\n0,\n0,\n1,\n"",\n"",\n0,0 );\n</SCRIPT>\n'
46
+ + '<SCRIPT language="javascript" type="text/javascript">\nvar guestNetworkInf = '
47
+ + 'new Array(\n1, 1, 1, 0, "Pegasus", '
48
+ + '"Pegasus", 1, 1, 3, 3, "333", "333", 0, 0, "p4ssw0rd", "p4ssw0rd", '
49
+ + "0, 0, 0, 0, 3, 3, 1, 1, 5, 8, 0, \n0,0 );\n"
50
+ + "</SCRIPT>"
51
+ )
52
+
53
+ _DHCPCFG = (
54
+ '<SCRIPT language="javascript" type="text/javascript">\nvar DHCPPara = new Array(\n1,\n"192.168.1.129",\n'
55
+ + '"192.168.1.192",\n120,\n"192.168.1.254",\n"internal.lan",\n"8.8.8.8",\n"8.8.4.4",\n0,\n0,0 );\n</SCRIPT>'
56
+ )
57
+
58
+ _DHCPLEASES = (
59
+ '<SCRIPT language="javascript" type="text/javascript">var DHCPDynList = new Array(\n"aliquam",'
60
+ + '"A9-A8-2B-F7-9F-5D","192.168.1.123","Permanent",\n"pharetra","B3-A5-1E-C3-92-A9","192.168.1.163","Permanent",\n'
61
+ + '"ligula","71-34-47-FD-DE-84","192.168.1.165","Permanent",\n"vulputate","46-5F-5F-27-23-9F","192.168.1.103",'
62
+ + '"Permanent",\n"amet","86-9F-53-91-04-2B","192.168.1.72","Permanent",\n"volutpat","FA-5C-6F-87-A3-5A",'
63
+ + '"192.168.1.43",'
64
+ + '"Permanent",\n"eget","C4-ED-6C-B6-F6-B9","192.168.1.112","Permanent",\n"ante","FF-C1-A3-93-C8-E6",'
65
+ + '"192.168.1.38",'
66
+ + '"Permanent",\n"pellentesque","E3-5E-59-2E-CF-AD","192.168.1.148","Permanent",\n"metus","AE-15-51-37-0E-9E",'
67
+ + '"192.168.1.178","Permanent",\n0,0 );\n</SCRIPT>\n<SCRIPT language="javascript" type="text/javascript">\n'
68
+ + "var DHCPDynPara = new Array(\n10,\n4,\n0,0 );\n</SCRIPT>"
69
+ )
70
+
71
+ _DHCPRESERVES = (
72
+ '<SCRIPT language="javascript" type="text/javascript">\nvar dhcpList = new Array(\n"9B-FA-04-D8-AB-8D",'
73
+ + '"192.168.1.56",1,\n"EE-7C-6B-B6-05-2F","192.168.1.51",1,\n"09-51-B3-0B-92-01","192.168.1.21",1,\n'
74
+ + '"49-6F-72-CD-68-5D","192.168.1.25",1,\n"DF-24-38-C1-FE-BB","192.168.1.51",1,\n"1A-08-6C-52-31-3D",'
75
+ + '"192.168.1.22",1,\n"DE-E4-DF-9A-AD-0D","192.168.1.17",1,\n"DF-F2-CB-FE-46-15","192.168.1.26",1,\n'
76
+ + '0,0 )\n</SCRIPT>\n<SCRIPT language="javascript" type="text/javascript">var DHCPStaticPara = '
77
+ + "new Array(\n1,\n1,\n8,\n1,\n8,\n0,0 );\n</SCRIPT>"
78
+ )
79
+
80
+ ABSTRACT_STATUS = (
81
+ '<SCRIPT language="javascript" type="text/javascript">\nvar statusPara = new Array(\n1,\n1,\n1,\n'
82
+ + '22,\n20000,\n1468171,\n"3.13.34 Build 130909 Rel.53148n ",\n"WDR3600 v1 00000000",\n6732336,\n0, 0);\n'
83
+ + '</SCRIPT>\n'
84
+ + '<SCRIPT language="javascript" type="text/javascript">\nvar lanPara = new Array(\n"C4-6E-1F-41-67-C0", '
85
+ + '"192.168.1.254", "255.255.255.0",\n0, 0);\n</SCRIPT>\n<SCRIPT language="javascript" type="text/javascript">\n'
86
+ + 'var wlanPara = new Array(\n1,\n"testSSID24",\n15,\n5,\n"C4-6E-1F-41-67-BF",\n"192.168.1.254",\n2,\n8,\n71,\n6,\n'
87
+ + '6,\n0, 0);\n</SCRIPT>\n<SCRIPT language="javascript" type="text/javascript">\nvar wlan5GPara = new Array(\n1,\n'
88
+ + '"testSSID",\n15,\n8,\n"C4-6E-1F-41-67-C0",\n"192.168.1.254",\n2,\n8,\n83,\n36,\n6,\n0, 0);\n</SCRIPT>\n'
89
+ + '<SCRIPT language="javascript" type="text/javascript">\nvar statistList = '
90
+ + "new Array(\n1129349328, 3900411475, 200068023, 165562287,\n0, 0);\n</SCRIPT>\n"
91
+ + '<SCRIPT language="javascript" type="text/javascript">\nvar wanPara = new Array(\n4, '
92
+ + '"C4-6E-1F-41-67-C1", "192.168.0.129", 1, "255.255.255.0", 0, 0, "192.168.0.1", 1, 1, 0, '
93
+ + '"8.8.8.8 , 8.8.4.4", "", 0, 0, "0.0.0.0", "0.0.0.0", "0.0.0.0", "0.0.0.0 , 0.0.0.0", '
94
+ + "0, 0, 0, 0, 0,\n0, 0);\n</SCRIPT>"
95
+ )
96
+
97
+ ABSTRACT_NETWORK = {
98
+ "netWan": _NETWAN,
99
+ "netLan": _NETLAN,
100
+ "w24stations": _W24STA,
101
+ "w50stations": _W50STA,
102
+ "wgsettings": _WLANGUEST,
103
+ "dhcpconfig": _DHCPCFG,
104
+ "dhcplease": _DHCPLEASES,
105
+ "dhcpreserve": _DHCPRESERVES,
106
+ }
107
+
108
+
109
+ class ResponseMock:
110
+ def __init__(self, text: str, status_code=0):
111
+ self.content = text.encode("utf8")
112
+ self.status_code = status_code
113
+ self.headers: dict = {}
114
+
115
+
116
+ class TplinkWDRRouterTest(TplinkWDRRouter):
117
+ response = ""
118
+
119
+ def request(
120
+ self,
121
+ section: str,
122
+ data: str,
123
+ ignore_response: bool = False,
124
+ ignore_errors: bool = False,
125
+ ) -> str | dict | None:
126
+ # only a test, so no extra headers
127
+ # Responses
128
+ sections = "summary,status,"
129
+ sections += "netWan,netLan,dualBand,"
130
+ sections += "w24settings,w24wps,w24sec,w24adv,w24stations,"
131
+ sections += "w50settings,w50wps,w50sec,w50adv,w50stations,"
132
+ sections += "wgsettings,wgshare,dhcpconfig,dhcplease,dhcpreserve,"
133
+ sections += "portFwd,sysroute,upnpFwd"
134
+
135
+ section_list = sections.split(",")
136
+
137
+ if ignore_response:
138
+ return None
139
+ elif section == "check":
140
+ resp = ResponseMock("", 200)
141
+ resp.headers["www-authenticate"] = (
142
+ 'Basic realm="TP-LINK Wireless Dual Band Gigabit Router WDR3600"'
143
+ )
144
+ return resp
145
+ elif section in section_list:
146
+ if section in ["summary", "status"]:
147
+ return ResponseMock(ABSTRACT_STATUS).content
148
+ elif section in ["w24stations", "w50stations", "dhcpreserve"]:
149
+ return ResponseMock(ABSTRACT_NETWORK[section]).content
150
+ elif section in [
151
+ "netLan",
152
+ "netWan",
153
+ # 'w24stations',
154
+ # 'w50stations',
155
+ "wgsettings",
156
+ "dhcpconfig",
157
+ "dhcplease",
158
+ # 'dhcpreserve',
159
+ ]:
160
+ return ResponseMock(ABSTRACT_NETWORK[section]).content
161
+ else:
162
+ return ""
163
+ # raise ClientError (f'Section {section} not allowed')
164
+
165
+ else:
166
+ error = ""
167
+ error = (
168
+ (
169
+ "WDRRouter - {} - Response with error; Request {} - Response {}".format(
170
+ self.__class__.__name__, section, data
171
+ )
172
+ )
173
+ if not error
174
+ else error
175
+ )
176
+ if self._logger:
177
+ self._logger.debug(error)
178
+
179
+ raise ClientError(error)
180
+
181
+
182
+ class TestTPLinkWDRClient(TestCase):
183
+
184
+ def test_supports(self) -> None:
185
+ client = TplinkWDRRouterTest("", "")
186
+ # client.response = ResponseMock(ABSTRACT_STATUS)
187
+ supports = client.supports()
188
+ self.assertTrue(supports)
189
+
190
+ def test_get_firmware(self) -> None:
191
+
192
+ client = TplinkWDRRouterTest("", "")
193
+ client.response = ResponseMock(ABSTRACT_STATUS)
194
+ firmware = client.get_firmware()
195
+
196
+ self.assertIsInstance(firmware, Firmware)
197
+ self.assertEqual(firmware.hardware_version, "WDR3600 v1 00000000")
198
+ self.assertEqual(firmware.model, "WDR3600")
199
+ self.assertEqual(
200
+ firmware.firmware_version.strip(), "3.13.34 Build 130909 Rel.53148n"
201
+ )
202
+
203
+ def test_get_ipv4(self) -> None:
204
+
205
+ client = TplinkWDRRouterTest("", "")
206
+ ipv4status: IPv4Status = IPv4Status()
207
+ ipv4status = client.get_ipv4_status()
208
+
209
+ self.assertIsInstance(ipv4status, IPv4Status)
210
+ self.assertEqual(ipv4status._wan_macaddr, EUI48("C4-6E-1F-41-67-C1"))
211
+ self.assertEqual(
212
+ IPv4Address(ipv4status.wan_ipv4_ipaddr), IPv4Address("192.168.0.129")
213
+ )
214
+ self.assertEqual(
215
+ IPv4Address(ipv4status.wan_ipv4_gateway), IPv4Address("192.168.0.1")
216
+ )
217
+ self.assertEqual(ipv4status.wan_ipv4_conntype, "Dynamic IP")
218
+ self.assertEqual(
219
+ IPv4Address(ipv4status.wan_ipv4_netmask), IPv4Address("255.255.255.0")
220
+ )
221
+ self.assertEqual(
222
+ IPv4Address(ipv4status.wan_ipv4_pridns), IPv4Address("0.0.0.0")
223
+ )
224
+ self.assertEqual(
225
+ IPv4Address(ipv4status.wan_ipv4_snddns), IPv4Address("0.0.0.0")
226
+ )
227
+ self.assertEqual(ipv4status._lan_macaddr, EUI48("C4-6E-1F-41-67-C0"))
228
+ self.assertEqual(
229
+ IPv4Address(ipv4status.lan_ipv4_ipaddr), IPv4Address("192.168.1.254")
230
+ )
231
+ self.assertEqual(ipv4status.lan_ipv4_dhcp_enable, True)
232
+ self.assertEqual(
233
+ IPv4Address(ipv4status.lan_ipv4_netmask), IPv4Address("255.255.255.0")
234
+ )
235
+
236
+ def test_get_ipv4_reservations(self) -> None:
237
+ client = TplinkWDRRouterTest("", "")
238
+ ipv4_reservations: list[IPv4Reservation] = client.get_ipv4_reservations()
239
+ fRes: IPv4Reservation = ipv4_reservations[0]
240
+
241
+ self.assertIsInstance(fRes, IPv4Reservation)
242
+ self.assertEqual(EUI48(fRes.macaddress), EUI48("9B-FA-04-D8-AB-8D"))
243
+ self.assertEqual(IPv4Address(fRes.ipaddress), IPv4Address("192.168.1.56"))
244
+ self.assertEqual(fRes.enabled, True)
245
+
246
+ def test_get_ipv4_dhcp_leases(self) -> None:
247
+ client = TplinkWDRRouterTest("", "")
248
+ dhcp_leases: list[IPv4DHCPLease] = client.get_ipv4_dhcp_leases()
249
+
250
+ self.assertIsInstance(dhcp_leases[0], IPv4DHCPLease)
251
+ self.assertEqual(dhcp_leases[0].macaddress, EUI48("A9-A8-2B-F7-9F-5D"))
252
+ self.assertEqual(dhcp_leases[0].ipaddress, IPv4Address("192.168.1.123"))
253
+ self.assertEqual(dhcp_leases[0].hostname, "aliquam")
254
+ self.assertEqual(dhcp_leases[0].lease_time, "Permanent")
255
+
256
+ self.assertIsInstance(dhcp_leases[1], IPv4DHCPLease)
257
+ self.assertEqual(dhcp_leases[1].macaddress, EUI48("B3-A5-1E-C3-92-A9"))
258
+ self.assertEqual(dhcp_leases[1].ipaddress, IPv4Address("192.168.1.163"))
259
+ self.assertEqual(dhcp_leases[1].hostname, "pharetra")
260
+ self.assertEqual(dhcp_leases[1].lease_time, "Permanent")
261
+
262
+ def test_get_status(self) -> None:
263
+ client = TplinkWDRRouterTest("", "")
264
+ client.response = ResponseMock(ABSTRACT_STATUS)
265
+
266
+ status = client.get_status()
267
+
268
+ self.assertIsInstance(status, Status)
269
+ self.assertEqual(status.wan_macaddr, "C4-6E-1F-41-67-C1")
270
+ self.assertIsInstance(status.wan_macaddress, EUI48)
271
+ self.assertEqual(status.lan_macaddr, "C4-6E-1F-41-67-C0")
272
+ self.assertIsInstance(status.lan_macaddress, EUI48)
273
+ self.assertEqual(status.wan_ipv4_addr, "192.168.0.129")
274
+ self.assertIsInstance(status.lan_ipv4_address, IPv4Address)
275
+ self.assertEqual(status.lan_ipv4_addr, "192.168.1.254")
276
+ self.assertEqual(status.wan_ipv4_gateway, "192.168.0.1")
277
+ self.assertIsInstance(status.wan_ipv4_address, IPv4Address)
278
+
279
+ self.assertEqual(status.wired_total, 10)
280
+ self.assertEqual(status.wifi_clients_total, 8)
281
+ self.assertEqual(status.guest_clients_total, 0)
282
+ self.assertEqual(status.clients_total, 18)
283
+
284
+ self.assertTrue(status.guest_2g_enable)
285
+ self.assertFalse(status.guest_5g_enable)
286
+ self.assertTrue(status.wifi_2g_enable)
287
+ self.assertTrue(status.wifi_5g_enable)
288
+ self.assertEqual(status.wan_ipv4_uptime, 6732336)
289
+
290
+
291
+ if __name__ == "__main__":
292
+ main()
@@ -8,6 +8,7 @@ from tplinkrouterc6u.client.c80 import TplinkC80Router
8
8
  from tplinkrouterc6u.client.c5400x import TplinkC5400XRouter
9
9
  from tplinkrouterc6u.client.c1200 import TplinkC1200Router
10
10
  from tplinkrouterc6u.client.xdr import TPLinkXDRClient
11
+ from tplinkrouterc6u.client.wdr import TplinkWDRRouter
11
12
  from tplinkrouterc6u.provider import TplinkRouterProvider
12
13
  from tplinkrouterc6u.common.package_enum import Connection, VPN
13
14
  from tplinkrouterc6u.common.dataclass import (
@@ -1,11 +1,8 @@
1
1
  from re import search
2
2
  from requests import post, Response
3
- from urllib.parse import urlencode
4
3
  from tplinkrouterc6u.common.encryption import EncryptionWrapper
5
4
  from tplinkrouterc6u.common.exception import ClientException, AuthorizeError
6
5
  from tplinkrouterc6u.client.c5400x import TplinkC5400XRouter
7
- from tplinkrouterc6u.common.dataclass import VPNStatus
8
- from tplinkrouterc6u.common.package_enum import VPN
9
6
 
10
7
 
11
8
  class TplinkC1200Router(TplinkC5400XRouter):
@@ -103,36 +100,3 @@ class TplinkC1200Router(TplinkC5400XRouter):
103
100
  @staticmethod
104
101
  def _get_login_data(crypted_pwd: str) -> str:
105
102
  return 'operation=login&password={}'.format(crypted_pwd)
106
-
107
- def get_vpn_status(self) -> VPNStatus:
108
- status = VPNStatus()
109
-
110
- values = [
111
- self.request("/admin/openvpn?form=config&operation=read", "operation=read"),
112
- self.request("/admin/pptpd?form=config&operation=read", "operation=read"),
113
- self.request("/admin/vpnconn?form=config&operation=list&vpntype=openvpn",
114
- "operation=list&operation=list&vpntype=openvpn"),
115
- self.request("/admin/vpnconn?form=config&operation=list&vpntype=pptp",
116
- "operation=list&operation=list&vpntype=pptp"),
117
- ]
118
-
119
- status.openvpn_enable = values[0]['enabled'] == 'on'
120
- status.pptpvpn_enable = values[1]['enabled'] == 'on'
121
-
122
- if isinstance(values[2], list):
123
- status.openvpn_clients_total = len(values[2])
124
- status.pptpvpn_clients_total = len(values[3])
125
- else:
126
- status.openvpn_clients_total = 0
127
- status.pptpvpn_clients_total = 0
128
-
129
- return status
130
-
131
- def set_vpn(self, vpn: VPN, enable: bool) -> None:
132
- path = "/admin/{}?form=config&operation=read".format(vpn.lowercase)
133
- current_config = self.request(path, "operation=read")
134
- current_config['enabled'] = "on" if enable else "off"
135
- data = urlencode(current_config)
136
- data = "&operation=write&{}".format(data)
137
- path = "/admin/{}?form=config{}".format(vpn.lowercase, data)
138
- self.request(path, data)
@@ -1,14 +1,23 @@
1
1
  from hashlib import md5
2
2
  from re import search
3
3
  from json import loads
4
+ from urllib.parse import urlencode
4
5
  from requests import post, Response
5
6
  from macaddress import EUI48
6
7
  from ipaddress import IPv4Address
7
8
  from logging import Logger
8
9
  from tplinkrouterc6u.common.helper import get_ip, get_mac
9
10
  from tplinkrouterc6u.common.encryption import EncryptionWrapper
10
- from tplinkrouterc6u.common.package_enum import Connection
11
- from tplinkrouterc6u.common.dataclass import Firmware, Status, Device, IPv4Reservation, IPv4DHCPLease, IPv4Status
11
+ from tplinkrouterc6u.common.package_enum import Connection, VPN
12
+ from tplinkrouterc6u.common.dataclass import (
13
+ Firmware,
14
+ Status,
15
+ Device,
16
+ IPv4Reservation,
17
+ IPv4DHCPLease,
18
+ IPv4Status,
19
+ VPNStatus,
20
+ )
12
21
  from tplinkrouterc6u.common.exception import ClientException, ClientError
13
22
  from tplinkrouterc6u.client_abstract import AbstractRouter
14
23
  from abc import abstractmethod
@@ -231,6 +240,10 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
231
240
  self._url_firmware = 'admin/firmware?form=upgrade&operation=read'
232
241
  self._url_ipv4_reservations = 'admin/dhcps?form=reservation&operation=load'
233
242
  self._url_ipv4_dhcp_leases = 'admin/dhcps?form=client&operation=load'
243
+ self._url_openvpn = 'admin/openvpn?form=config&operation=read'
244
+ self._url_pptpd = 'admin/pptpd?form=config&operation=read'
245
+ self._url_vpnconn_openvpn = 'admin/vpnconn?form=config&operation=list&vpntype=openvpn'
246
+ self._url_vpnconn_pptpd = 'admin/vpnconn?form=config&operation=list&vpntype=pptp'
234
247
  referer = '{}/webpages/index.html'.format(self.host)
235
248
  self._headers_request = {'Referer': referer}
236
249
  self._headers_login = {'Referer': referer, 'Content-Type': 'application/x-www-form-urlencoded'}
@@ -275,7 +288,7 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
275
288
  data = self.request('admin/status?form=all&operation=read', 'operation=read')
276
289
 
277
290
  status = Status()
278
- status._wan_macaddr = EUI48(data['wan_macaddr']) if 'wan_macaddr' in data else None
291
+ status._wan_macaddr = EUI48(data['wan_macaddr']) if 'wan_macaddr' in data and data['wan_macaddr'] else None
279
292
  status._lan_macaddr = EUI48(data['lan_macaddr'])
280
293
  status._wan_ipv4_addr = IPv4Address(data['wan_ipv4_ipaddr']) if 'wan_ipv4_ipaddr' in data else None
281
294
  status._lan_ipv4_addr = IPv4Address(data['lan_ipv4_ipaddr']) if 'lan_ipv4_ipaddr' in data else None
@@ -401,6 +414,36 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
401
414
 
402
415
  return dhcp_leases
403
416
 
417
+ def get_vpn_status(self) -> VPNStatus:
418
+ status = VPNStatus()
419
+
420
+ values = [
421
+ self.request(self._url_openvpn, "operation=read"),
422
+ self.request(self._url_pptpd, "operation=read"),
423
+ self.request(self._url_vpnconn_openvpn, "operation=list&vpntype=openvpn"),
424
+ self.request(self._url_vpnconn_pptpd, "operation=list&vpntype=pptp"),
425
+ ]
426
+
427
+ status.openvpn_enable = values[0]['enabled'] == 'on'
428
+ status.pptpvpn_enable = values[1]['enabled'] == 'on'
429
+
430
+ if isinstance(values[2], list):
431
+ status.openvpn_clients_total = len(values[2])
432
+ status.pptpvpn_clients_total = len(values[3])
433
+ else:
434
+ status.openvpn_clients_total = 0
435
+ status.pptpvpn_clients_total = 0
436
+
437
+ return status
438
+
439
+ def set_vpn(self, vpn: VPN, enable: bool) -> None:
440
+ path = self._url_openvpn if VPN.OPEN_VPN == vpn else self._url_pptpd
441
+ current_config = self.request(path, "operation=read")
442
+ current_config['enabled'] = "on" if enable else "off"
443
+ data = urlencode(current_config)
444
+ data = "operation=write&{}".format(data)
445
+ self.request(path, data)
446
+
404
447
  @staticmethod
405
448
  def _str2bool(v) -> bool | None:
406
449
  return str(v).lower() in ("yes", "true", "on") if v is not None else None
@@ -435,3 +478,7 @@ class TplinkRouter(TplinkEncryption, TplinkBaseRouter):
435
478
  self._url_firmware = 'admin/firmware?form=upgrade'
436
479
  self._url_ipv4_reservations = 'admin/dhcps?form=reservation'
437
480
  self._url_ipv4_dhcp_leases = 'admin/dhcps?form=client'
481
+ self._url_openvpn = 'admin/openvpn?form=config'
482
+ self._url_pptpd = 'admin/pptpd?form=config'
483
+ self._url_vpnconn_openvpn = 'admin/vpnconn?form=config'
484
+ self._url_vpnconn_pptpd = 'admin/vpnconn?form=config'