Commit | Line | Data |
---|---|---|
a91317a6 S |
1 | <?php |
2 | class speedport { | |
3 | /** | |
4 | * password-challenge | |
5 | * @var string | |
6 | */ | |
7 | private $challenge = ''; | |
8 | ||
9 | /** | |
10 | * hashed password | |
11 | * @var string | |
12 | */ | |
13 | private $hash = ''; | |
14 | ||
15 | /** | |
16 | * session cookie | |
17 | * @var string | |
18 | */ | |
19 | private $session = ''; | |
20 | ||
21 | /** | |
22 | * router url | |
23 | * @var string | |
24 | */ | |
25 | private $url = 'http://speedport.ip/'; | |
26 | ||
27 | public function __construct ($password) { | |
28 | $this->getChallenge(); | |
29 | ||
30 | if (empty($this->challenge)) { | |
31 | throw new Exception('unable to get the challenge from the router'); | |
32 | } | |
33 | ||
34 | $login = $this->login($password); | |
35 | ||
36 | if ($login === false) { | |
37 | throw new Exception('unable to login'); | |
38 | } | |
39 | } | |
40 | ||
41 | /** | |
42 | * Requests the password-challenge from the router. | |
43 | */ | |
44 | public function getChallenge () { | |
45 | $url = 'data/Login.json'; | |
46 | $fields = array('csrf_token' => 'nulltoken', 'showpw' => 0, 'challengev' => 'null'); | |
47 | $data = $this->sentRequest($url, $fields); | |
48 | $data = json_decode($data['body'], true); | |
49 | if ($data[1]['varid'] == 'challengev') { | |
50 | $this->challenge = $data[1]['varvalue']; | |
51 | } | |
52 | } | |
53 | ||
54 | /** | |
55 | * login into the router with the given password | |
56 | * | |
57 | * @param string $password | |
58 | * @return boolean | |
59 | */ | |
60 | public function login ($password) { | |
61 | $url = 'data/Login.json'; | |
62 | $this->hash = hash('sha256', $this->challenge.':'.$password); | |
63 | $fields = array('csrf_token' => 'nulltoken', 'showpw' => 0, 'password' => $this->hash); | |
64 | $data = $this->sentRequest($url, $fields); | |
65 | $json = json_decode($data['body'], true); | |
66 | if ($json[15]['varid'] == 'login' && $json[15]['varvalue'] == 'success') { | |
67 | if (isset($data['header']['Set-Cookie']) && !empty($data['header']['Set-Cookie'])) { | |
68 | preg_match('/^.*(SessionID_R3=[a-z0-9]*).*/i', $data['header']['Set-Cookie'], $match); | |
69 | if (isset($match[1]) && !empty($match[1])) { | |
70 | $this->session = $match[1]; | |
71 | } | |
72 | else { | |
73 | throw new Exception('unable to get the session cookie from the router'); | |
74 | } | |
75 | ||
76 | return true; | |
77 | } | |
78 | } | |
79 | ||
80 | return false; | |
81 | } | |
82 | ||
83 | /** | |
84 | * logout | |
85 | * | |
86 | * @return array | |
87 | */ | |
88 | public function logout () { | |
89 | $url = 'data/Login.json'; | |
90 | $fields = array('logout' => 'byby'); | |
91 | $data = $this->sentRequest($url, $fields); | |
92 | // reset challenge and session | |
93 | $this->challenge = ''; | |
94 | $this->session = ''; | |
95 | ||
96 | $json = json_decode($data['body'], true); | |
97 | ||
98 | return $json; | |
99 | } | |
100 | ||
101 | /** | |
102 | * reboot the router | |
103 | * | |
104 | * @return array | |
105 | */ | |
106 | public function reboot () { | |
107 | $url = 'data/Reboot.json'; | |
108 | $fields = array('csrf_token' => 'nulltoken', 'showpw' => 0, 'password' => $this->hash, 'reboot_device' => 'true'); | |
109 | $cookie = 'challengev='.$this->challenge.'; '.$this->session; | |
110 | $data = $this->sentRequest($url, $fields, $cookie); | |
111 | $json = json_decode($data['body'], true); | |
112 | ||
113 | return $json; | |
114 | } | |
115 | ||
116 | /** | |
117 | * return the given json as array | |
118 | * | |
119 | * the following paths are known to be valid: | |
120 | * /data/dsl.json | |
121 | * /data/interfaces.json | |
122 | * /data/arp.json | |
123 | * /data/session.json | |
124 | * /data/dhcp_client.json | |
125 | * /data/dhcp_server.json | |
126 | * /data/ipv6.json | |
127 | * /data/dns.json | |
128 | * /data/routing.json | |
129 | * /data/igmp_proxy.json | |
130 | * /data/igmp_snooping.json | |
131 | * /data/wlan.json | |
132 | * /data/module.json | |
133 | * /data/memory.json | |
134 | * /data/speed.json | |
135 | * /data/webdav.json | |
136 | * /data/bonding_client.json | |
137 | * /data/bonding_tunnel.json | |
138 | * /data/filterlist.json | |
139 | * /data/bonding_tr181.json | |
140 | * /data/letinfo.json | |
141 | * | |
142 | * /data/Status.json (No login needed) | |
143 | * | |
144 | * @param string $file | |
145 | * @return array | |
146 | */ | |
147 | public function getData ($file) { | |
148 | $url = 'data/'.$file.'.json'; | |
149 | $fields = array(); | |
150 | $cookie = 'challengev='.$this->challenge.'; '.$this->session; | |
151 | $data = $this->sentRequest($url, $fields, $cookie); | |
152 | ||
153 | if (empty($data['body'])) { | |
154 | throw new Exception('unable to get '.$file.' data'); | |
155 | } | |
156 | ||
157 | $json = json_decode($data['body'], true); | |
158 | ||
159 | return $json; | |
160 | } | |
161 | ||
162 | /** | |
163 | * sends the request to router | |
164 | * | |
165 | * @param string $url | |
166 | * @param array $fields | |
167 | * @param string $cookie | |
168 | * @return array | |
169 | */ | |
170 | private function sentRequest ($url, $fields = array(), $cookie = '') { | |
171 | $url = $this->url.$url; | |
172 | $ch = curl_init(); | |
173 | curl_setopt($ch, CURLOPT_URL, $url); | |
174 | ||
175 | if (!empty($fields)) { | |
176 | curl_setopt($ch, CURLOPT_POST, count($fields)); | |
177 | curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields)); | |
178 | } | |
179 | ||
180 | if (!empty($cookie)) { | |
181 | curl_setopt($ch, CURLOPT_COOKIE, $cookie); | |
182 | } | |
183 | ||
184 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
185 | curl_setopt($ch, CURLOPT_HEADER, true); | |
186 | ||
187 | ||
188 | if ($cookie) { | |
189 | ||
190 | } | |
191 | ||
192 | $result = curl_exec($ch); | |
193 | ||
194 | $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); | |
195 | $header = substr($result, 0, $header_size); | |
196 | $body = substr($result, $header_size); | |
197 | curl_close($ch); | |
198 | ||
199 | // fix invalid json | |
200 | $body = preg_replace("/(\r\n)|(\r)/", "\n", $body); | |
201 | $body = preg_replace('/\'/i', '"', $body); | |
202 | $body = preg_replace("/},\n\n]/", "}\n]", $body); | |
203 | $body = preg_replace('/\s+/', ' ', $body); | |
204 | $body = preg_replace("/\[ \]/i", '[ {} ]', $body); | |
205 | $body = preg_replace("/}, ]/", "} ]", $body); | |
206 | $body = preg_replace("/\n/", " ", $body); | |
207 | ||
208 | return array('header' => $this->parse_headers($header), 'body' => $body); | |
209 | } | |
210 | ||
211 | /** | |
212 | * parse the curl return header into an array | |
213 | * | |
214 | * @param string $response | |
215 | * @return array | |
216 | */ | |
217 | private function parse_headers($response) { | |
218 | $headers = array(); | |
219 | $header_text = substr($response, 0, strpos($response, "\r\n\r\n")); | |
220 | ||
221 | foreach (explode("\r\n", $header_text) as $i => $line) { | |
222 | if ($i === 0) { | |
223 | $headers['http_code'] = $line; | |
224 | } | |
225 | else { | |
226 | list ($key, $value) = explode(': ', $line); | |
227 | $headers[$key] = $value; | |
228 | } | |
229 | } | |
230 | ||
231 | return $headers; | |
232 | } | |
233 | } |