some stuff
[GitHub/Stricted/SpeedportHybridControl.git] / SpeedportHybridControl.Implementations / SpeedportHybridAPI.cs
1 using Newtonsoft.Json.Linq;
2 using System;
3 using System.Linq;
4 using System.IO;
5 using System.Net;
6 using System.Text;
7 using System.Text.RegularExpressions;
8 using System.Windows;
9 using System.Threading;
10 using System.Collections.Generic;
11
12 namespace SpeedportHybridControl.Implementations {
13 public class SpeedportHybridAPI : SingletonFactory<SpeedportHybridAPI> {
14 public string _ip = "speedport.ip";
15 private DateTime _lastReboot = DateTime.MinValue;
16 private bool _checkIsActive = false;
17 public string _password;
18 public string _challenge;
19 public string _hash;
20 public string _derivedk;
21 public CookieContainer _cookie = new CookieContainer();
22
23 public string ip {
24 get { return _ip; }
25 set { _ip = value; }
26 }
27
28 /**
29 * Requests the password-challenge from the router.
30 *
31 * @return string
32 */
33 public string getChallenge () {
34 string response = sendRequest("data/Login.json", "csrf_token=nulltoken&showpw=0&challengev=null");
35 if (response.IsNullOrEmpty())
36 return string.Empty;
37
38 string challenge = string.Empty;
39 try {
40 JToken jArray = JToken.Parse(response);
41
42 challenge = jArray.getVar("challengev");
43 jArray = null;
44 }
45 catch (Exception ex) {
46 LogManager.WriteToLog(ex.Message);
47 }
48
49 response = null;
50
51 return challenge;
52 }
53
54 /**
55 * calculate the derivedk
56 *
57 * @param string $password
58 * @return string
59 */
60 public string getDerviedk () {
61 return _password.sha256().pbkdf2(_challenge.Substring(0, 16));
62 }
63
64 /**
65 * login into the router with the given password
66 *
67 * @param string $password
68 * @return bool
69 */
70 public bool login (string passwort) {
71 if (passwort.IsNullOrEmpty()) {
72 return false;
73 }
74
75 _cookie = new CookieContainer();
76
77 _password = passwort;
78 _challenge = getChallenge();
79 _hash = string.Concat(_challenge, ":", _password).sha256();
80
81 string response = sendRequest("data/Login.json", string.Concat("csrf_token=nulltoken&showpw=0&password=", _hash));
82 if (response.IsNullOrEmpty())
83 return false;
84
85 _cookie.Add(new Cookie("challengev", _challenge) { Domain = "speedport.ip" });
86
87 bool login = false;
88 try {
89 JToken jArray = JToken.Parse(response);
90 if (jArray.getVar("login").Equals("success")) {
91 if (isLoggedin().Equals(false)) {
92 login = false;
93 }
94 else {
95 login = true;
96 _derivedk = getDerviedk();
97 _lastReboot = getLastReboot();
98 }
99 }
100 jArray = null;
101 }
102 catch (Exception ex) {
103 LogManager.WriteToLog(ex.Message);
104 }
105
106 response = null;
107
108 return login;
109 }
110
111 /**
112 * logout
113 *
114 * @return bool
115 */
116 public bool logout () {
117 string response = sendRequest("data/Login.json", string.Concat("csrf_token=", getToken(), "&logout=byby"));
118 if (response.IsNullOrEmpty())
119 return false;
120
121 bool logout = false;
122 try {
123 JToken jArray = JToken.Parse(response);
124 if (jArray.getVar("status").Equals("ok")) {
125 if (isLoggedin().Equals(true)) {
126 logout = false;
127 }
128 else {
129 logout = true;
130 _password = "";
131 _challenge = "";
132 _cookie = new CookieContainer();
133 _lastReboot = DateTime.MinValue;
134 _hash = "";
135 _derivedk = "";
136 }
137 }
138
139 jArray = null;
140 }
141 catch (Exception ex) {
142 LogManager.WriteToLog(ex.Message);
143 }
144
145 response = null;
146
147 return logout;
148 }
149
150 /**
151 * check if we are logged in
152 *
153 * @return bool
154 */
155 public bool checkLogin () {
156 // TODO:
157
158 /*
159 if (_checkIsActive.Equals(false)) {
160 _checkIsActive = true;
161 if (isLoggedin().Equals(false)) {
162 Console.WriteLine("Session expired, try to relogin");
163
164 Thread.Sleep(400);
165
166 if (login(_password).Equals(false)) {
167 // should we try to relogin? login(_password);...
168 new Thread(() => { LogManager.WriteToLog("Session expired."); }).Start();
169 _password = "";
170 _challenge = "";
171 _cookie = new CookieContainer();
172 _lastReboot = DateTime.MinValue;
173 _hash = "";
174 _derivedk = "";
175
176 util.logout();
177 new Thread(() => { MessageBox.Show("Session expired.", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
178 _checkIsActive = false;
179 return false;
180 }
181 }
182
183 _checkIsActive = false;
184 }
185 else {
186 Console.WriteLine("check allready in progress");
187 }
188 */
189
190 return true;
191 }
192
193 /**
194 * check if we are logged in
195 *
196 * @param bool ischeck
197 * @return bool
198 */
199 public bool isLoggedin () {
200 string response = sendRequest("data/SecureStatus.json");
201 if (response.IsNullOrEmpty())
202 return false;
203
204 bool login = false;
205 try {
206 JToken jArray = JToken.Parse(response);
207
208 if (jArray.getVar("loginstate").Equals("1")/* && jArray.getVar("login").Equals("true")*/) {
209 login = true;
210 }
211
212 jArray = null;
213 }
214
215 catch (Exception ex) {
216 LogManager.WriteToLog(ex.Message);
217 }
218
219 response = null;
220
221 return login;
222 }
223
224 /**
225 * reboot the router
226 */
227 public void reboot () {
228 // TODO:
229 /*
230 if (checkLogin().Equals(false))
231 return;
232
233 string response = sendRequest("data/Reboot.json", string.Concat("csrf_token=", Uri.EscapeUriString(getToken()), "&reboot_device=true"));
234 if (response.IsNullOrEmpty())
235 return;
236 try {
237 JToken jArray = JToken.Parse(response);
238 if (jArray.getVar("status").Equals("ok")) {
239 new Thread(() => { MessageBox.Show("Router Reboot.", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information); }).Start();
240 LogManager.WriteToLog("Router Reboot.");
241 _password = "";
242 _challenge = "";
243 _cookie = new CookieContainer();
244 _hash = "";
245 _derivedk = "";
246
247 util.logout();
248 }
249
250 jArray = null;
251 }
252 catch (Exception ex) {
253 LogManager.WriteToLog(ex.Message);
254 }
255
256 response = null;
257 */
258 }
259
260 /**
261 * reconnect LTE
262 *
263 * @return bool
264 */
265 public bool reconnectLte () {
266 if (checkLogin().Equals(false))
267 return false;
268
269 Thread.Sleep(400);
270
271 string response = sendEnryptedRequest("data/modules.json", string.Concat("lte_reconn=1&csrf_token=", Uri.EscapeUriString(getToken())));
272 if (response.IsNullOrEmpty())
273 return false;
274
275 try {
276 JToken jArray = JToken.Parse(response);
277
278 response = null;
279
280 if (jArray.getVar("status").Equals("ok")) {
281 jArray = null;
282 return true;
283 }
284
285 jArray = null;
286 }
287 catch (Exception ex) {
288 LogManager.WriteToLog(ex.Message);
289 }
290
291 response = null;
292
293 return false;
294 }
295
296 /**
297 * reconnect DSL
298 *
299 * @return bool
300 */
301 public bool reconnectDSL () {
302 if (checkLogin().Equals(false))
303 return false;
304
305 Thread.Sleep(400);
306
307 string response = sendEnryptedRequest("data/Connect.json", string.Concat("csrf_token=", Uri.EscapeUriString(getToken()), "&showpw=0&password=", _hash, "&req_connect=offline"));
308 if (response.IsNullOrEmpty())
309 return false;
310
311 bool offline = false;
312 try {
313 JToken jArray = JToken.Parse(response);
314
315 response = null;
316
317 if (jArray.getVar("status").Equals("ok")) {
318 offline = true;
319 }
320
321 jArray = null;
322
323 if (offline.Equals(true)) {
324 response = sendEnryptedRequest("data/Connect.json", string.Concat("csrf_token=", Uri.EscapeUriString(getToken()), "&showpw=0&password=", _hash, "&req_connect=online"));
325 jArray = JToken.Parse(response);
326 if (jArray.getVar("status").Equals("ok")) {
327 jArray = null;
328 return true;
329 }
330 }
331 }
332 catch (Exception ex) {
333 LogManager.WriteToLog(ex.Message);
334 }
335
336 response = null;
337
338 return false;
339 }
340
341 /**
342 * change dsl connection status
343 *
344 * @param string status
345 * @return bool
346 */
347 public bool changeDSLStatus (string status) {
348 if (checkLogin().Equals(false))
349 return false;
350
351 if (status.Equals("online") || status.Equals("offline")) {
352
353 string response = sendEnryptedRequest("data/Connect.json", string.Concat("req_connect=", status, "&csrf_token=", Uri.EscapeUriString(getToken())));
354 if (response.IsNullOrEmpty())
355 return false;
356 try {
357 JToken jArray = JToken.Parse(response);
358
359 response = null;
360
361 if (jArray.getVar("status").Equals("ok")) {
362 jArray = null;
363 return true;
364 }
365 }
366 catch (Exception ex) {
367 LogManager.WriteToLog(ex.Message);
368 }
369
370 response = null;
371 }
372
373 return false;
374 }
375
376 /**
377 * change lte connection status
378 *
379 * @param string status
380 * @return bool
381 */
382 public bool changeLTEStatus (string status) {
383 if (checkLogin().Equals(false))
384 return false;
385
386 if (status.Equals("online") || status.Equals("offline")) {
387 if (status.Equals("online"))
388 status = "1";
389
390 if (status.Equals("offline"))
391 status = "0";
392
393 string response = sendEnryptedRequest("data/Modules.json", string.Concat("use_lte=", status, "&csrf_token=", Uri.EscapeUriString(getToken())));
394 if (response.IsNullOrEmpty())
395 return false;
396 try {
397 JToken jArray = JToken.Parse(response);
398
399 response = null;
400
401 if (jArray.getVar("status").Equals("ok")) {
402 jArray = null;
403 return true;
404 }
405 }
406 catch (Exception ex) {
407 LogManager.WriteToLog(ex.Message);
408 }
409
410 response = null;
411 }
412
413 return false;
414 }
415
416 /**
417 * reset the router to Factory Default
418 * not tested
419 *
420 * @return bool
421 */
422 public bool resetToFactoryDefault () {
423 if (checkLogin().Equals(false))
424 return false;
425
426 Thread.Sleep(400);
427
428 string response = sendEnryptedRequest("data/resetAllSetting.json", string.Concat("csrf_token=nulltoken&showpw=0&password=", _hash, "&reset_all=true"));
429 if (response.IsNullOrEmpty())
430 return false;
431
432 try {
433 JToken jArray = JToken.Parse(response);
434 if (jArray.getVar("status").Equals("ok")) {
435 return true;
436 }
437
438 jArray = null;
439 }
440 catch (Exception ex) {
441 LogManager.WriteToLog(ex.Message);
442 }
443
444 response = null;
445
446 return false;
447 }
448
449 /**
450 * check for firmware update
451 */
452 public void checkFirmware () {
453 if (checkLogin().Equals(false))
454 return;
455
456 Thread.Sleep(400);
457
458 string response = sendRequest("data/checkfirm.json");
459 if (response.IsNullOrEmpty())
460 return;
461
462 try {
463 bool fw_isActual = false;
464 JToken jArray = JToken.Parse(response);
465
466 if (jArray.getVar("fw_isActual").Equals("1")) {
467 fw_isActual = true;
468 }
469
470 if (fw_isActual.Equals(true)) {
471 // Die Firmware ist aktuell.
472 MessageBox.Show("Die Firmware ist aktuell.", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information);
473 }
474 else {
475 // Es liegt eine neuere Firmware-Version vor. Möchten Sie diese Version jetzt installieren?
476 MessageBox.Show("Es liegt eine neuere Firmware-Version vor.\nMöchten Sie diese Version jetzt installieren?", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Warning);
477 }
478
479 jArray = null;
480 }
481 catch (Exception ex) {
482 LogManager.WriteToLog(ex.Message);
483 }
484
485 response = null;
486 }
487
488 /**
489 * flush dns cache
490 */
491 public void flushDNS () {
492 if (checkLogin().Equals(false))
493 return;
494
495 Thread.Sleep(400);
496
497 string response = sendEnryptedRequest("data/dns.json", "op_type=flush_dns_cache");
498 if (response.IsNullOrEmpty())
499 return;
500
501 try {
502 JToken jArray = JToken.Parse(response);
503
504 if (jArray["DCI"].Count().Equals(0)) {
505 new Thread(() => { MessageBox.Show("DNS cache geleert", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information); }).Start();
506 }
507 else {
508 new Thread(() => { MessageBox.Show("unable to flush dns cache", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
509 }
510
511
512 jArray = null;
513 }
514 catch (Exception ex) {
515 LogManager.WriteToLog(ex.Message);
516 }
517
518 response = null;
519 }
520
521 /**
522 * clear the Syslog
523 */
524 public void clearSyslog () {
525 if (checkLogin().Equals(false))
526 return;
527
528 Thread.Sleep(400);
529
530 string response = sendEnryptedRequest("data/SystemMessages.json", string.Concat("action_clearlist=true&clear_type=0&", "csrf_token=", getToken()));
531 if (response.IsNullOrEmpty())
532 return;
533
534 try {
535 JToken jArray = JToken.Parse(response);
536
537 if (jArray.getVar("status").Equals("ok")) {
538 // ok
539 new Thread(() => { MessageBox.Show("Syslog geleert", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information); }).Start();
540 }
541 else {
542 // fail
543 new Thread(() => { MessageBox.Show("Konnte Syslog nicht leeren.", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
544 }
545
546 jArray = null;
547 }
548 catch (Exception ex) {
549 LogManager.WriteToLog(ex.Message);
550 }
551
552 response = null;
553 }
554
555 /**
556 * set QueueSkbTimeOut
557 *
558 * @param string value
559 */
560 public void setQueueSkbTimeOut (string value) {
561 // TODO:
562 /*
563 if (checkLogin().Equals(false))
564 return;
565
566 string response = sendEnryptedRequest("data/bonding_tr181.json", string.Concat("bonding_QueueSkbTimeOut=", value));
567 if (response.IsNullOrEmpty())
568 return;
569 try {
570 TR181 obj = JsonConvert.DeserializeObject<TR181>(response);
571
572 if (obj.QueueSkbTimeOut.Equals(value)) {
573 new Thread(() => { MessageBox.Show("QueueSkbTimeOut geändert", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information); }).Start();
574 }
575 else {
576 new Thread(() => { MessageBox.Show("unable to change QueueSkbTimeOut", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
577 }
578
579 obj = null;
580 }
581 catch (Exception ex) {
582 LogManager.WriteToLog(ex.Message);
583 }
584
585 response = null;
586 */
587 }
588
589 /**
590 * set Antenna Mode
591 *
592 * @param string value
593 */
594 public void setAntennaMode (string value) {
595 // TODO:
596 /*
597 if (checkLogin().Equals(false))
598 return;
599
600 string response = sendEnryptedRequest("data/lteinfo.json", string.Concat("mode_select=", value));
601 if (response.IsNullOrEmpty())
602 return;
603 try {
604 LTE obj = JsonConvert.DeserializeObject<LTE>(response);
605
606 string antenna_mode;
607 if (obj.antenna_mode.Equals("Antennal set to internal")) {
608 antenna_mode = "Inner";
609 }
610 else if (obj.antenna_mode.Equals("Antennal set to external")) {
611 antenna_mode = "Outer";
612 }
613 else {
614 antenna_mode = "Auto";
615 }
616
617 if (antenna_mode.Equals(value)) {
618 new Thread(() => { MessageBox.Show("Antennen Modus geändert", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information); }).Start();
619 }
620 else {
621 new Thread(() => { MessageBox.Show("Antennen Modus ändern Fehlgeschlagen", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
622 }
623
624 antenna_mode = null;
625
626 obj = null;
627 }
628 catch (Exception ex) {
629 LogManager.WriteToLog(ex.Message);
630 }
631
632 response = null;
633 */
634 }
635
636 /**
637 * get Last Reboot time
638 *
639 * @return DateTime
640 */
641 public DateTime getLastReboot () {
642 if (_lastReboot.Equals(DateTime.MinValue).Equals(false)) {
643 return _lastReboot;
644 }
645
646 string response = sendRequest("data/Reboot.json");
647
648 if (response.IsNullOrEmpty())
649 return DateTime.Now;
650
651 JToken jArray = JToken.Parse(response);
652
653 DateTime lastReboot = DateTime.Parse(string.Concat(jArray.getVar("reboot_date"), " ", jArray.getVar("reboot_time")));
654
655 jArray = null;
656
657 return lastReboot;
658 }
659
660 /**
661 * get the csrf token from router
662 *
663 * @return string
664 */
665 public string getToken () {
666 string response = sendRequest("html/content/overview/index.html");
667 if (response.IsNullOrEmpty())
668 return string.Empty;
669
670 string a = "csrf_token = \"";
671 string b = "\";";
672 string token = response.Substring((response.IndexOf(a) + a.Length), (response.IndexOf(b) - response.IndexOf(a) - a.Length));
673
674 response = null;
675 a = null;
676 b = null;
677
678 Console.WriteLine("csrf_token: " + token);
679 return token;
680 }
681
682 /**
683 * send encrypted request to the router
684 *
685 * @param string path
686 * @param string post
687 * @param bool cookie
688 * @return string
689 */
690 public string sendEnryptedRequest (string path, string post = "", bool cookie = true) {
691 string response = string.Empty;
692
693 try {
694 sjcl sjcl = new sjcl();
695
696 string iv = _challenge.Substring(16, 16);
697 string adata = _challenge.Substring(32, 16);
698 string dKey = _derivedk;
699
700
701 // TODO: check if we need this really?
702 if (post.IsNullOrEmpty().Equals(false)) {
703 post = sjcl.encrypt(dKey, post, iv, adata);
704 }
705
706
707 response = sendRequest(path, post, cookie);
708 // check if the return value is hex (hex = enrypted)
709 if (Regex.IsMatch(response, @"\A\b[0-9a-fA-F]+\b\Z").Equals(true)) {
710 response = sjcl.decrypt(dKey, response, iv, adata);
711 }
712
713 post = null;
714 iv = null;
715 adata = null;
716 dKey = null;
717 sjcl = null;
718
719 }
720 catch (ArgumentOutOfRangeException ex) {
721 LogManager.WriteToLog(ex.Message);
722 }
723 catch (Exception ex) {
724 LogManager.WriteToLog(ex.Message);
725 }
726
727 return response;
728 }
729
730 /**
731 * send request to the router
732 *
733 * @param string path
734 * @param string post
735 * @param bool cookie
736 * @return string
737 */
738 public string sendRequest (string path, string post = "", bool cookie = true) {
739 string response = string.Empty;
740 try {
741 string url = string.Concat("http://", ip, "/", path, "?lang=de");
742
743 HttpWebRequest webRequest = WebRequest.Create(url) as HttpWebRequest;
744 /* set timeout to 10 seconds */
745 webRequest.Timeout = 10000;
746
747 if (cookie.Equals(true)) {
748 webRequest.CookieContainer = _cookie;
749 }
750
751 if (post.IsNullOrEmpty().Equals(false)) {
752 webRequest.Method = "POST";
753 byte[] dataStream = Encoding.UTF8.GetBytes(post);
754 webRequest.ContentLength = dataStream.Length;
755 Stream newStream = webRequest.GetRequestStream();
756 newStream.Write(dataStream, 0, dataStream.Length);
757 newStream.Close();
758 newStream.Dispose();
759 newStream = null;
760 dataStream = null;
761 }
762
763 WebResponse webResponse = webRequest.GetResponse();
764 StreamReader reader = new StreamReader(webResponse.GetResponseStream());
765 response = reader.ReadToEnd().ToString();
766
767 webResponse.Dispose();
768 reader.Dispose();
769 reader = null;
770 webRequest = null;
771 webResponse = null;
772 post = null;
773 }
774 catch (Exception ex) {
775 LogManager.WriteToLog(ex.Message);
776 }
777
778 return response;
779 }
780
781 public string sendRequest2 (string path, Dictionary<string, object> files, string post = "", bool cookie = true) {
782 string response = string.Empty;
783
784 try {
785 string url = string.Concat("http://", ip, "/", path, "?lang=de");
786
787 string boundary = string.Concat("---------------------------", DateTime.Now.Ticks.ToString("x"));
788 byte[] boundaryBytes = Encoding.ASCII.GetBytes(string.Concat("\r\n--", boundary, "\r\n"));
789
790 HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
791 request.ContentType = string.Concat("multipart/form-data; boundary=", boundary);
792 request.Method = "POST";
793 request.KeepAlive = true;
794
795 if (cookie.Equals(true)) {
796 request.CookieContainer = _cookie;
797 }
798
799 Stream requestStream = request.GetRequestStream();
800
801 if (string.IsNullOrEmpty(post).Equals(false)) {
802 byte[] dataStream = Encoding.UTF8.GetBytes(post);
803 requestStream.Write(dataStream, 0, dataStream.Length);
804 dataStream = null;
805 }
806
807 if (files != null && files.Count > 0) {
808 foreach (KeyValuePair<string, object> pair in files) {
809 requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
810 if (pair.Value is FormFile) {
811 FormFile file = pair.Value as FormFile;
812 string header = string.Concat("Content-Disposition: form-data; name=\"", pair.Key, "\"; filename=\"", file.Name, "\"\r\nContent-Type: ", file.ContentType, "\r\n\r\n");
813 byte[] bytes = Encoding.UTF8.GetBytes(header);
814 requestStream.Write(bytes, 0, bytes.Length);
815 byte[] buffer = new byte[32768];
816 int bytesRead;
817 if (file.Stream == null) {
818 // upload from file
819 FileStream fileStream = File.OpenRead(file.FilePath);
820 while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) {
821 requestStream.Write(buffer, 0, bytesRead);
822 }
823 fileStream.Close();
824 }
825 else {
826 // upload from given stream
827 while ((bytesRead = file.Stream.Read(buffer, 0, buffer.Length)) != 0)
828 requestStream.Write(buffer, 0, bytesRead);
829 }
830 }
831 else {
832 string data = string.Concat("Content-Disposition: form-data; name=\"", pair.Key, "\"\r\n\r\n", pair.Value);
833 byte[] bytes = Encoding.UTF8.GetBytes(data);
834 requestStream.Write(bytes, 0, bytes.Length);
835 }
836 }
837
838 byte[] trailer = Encoding.ASCII.GetBytes(string.Concat("\r\n--", boundary, "--\r\n"));
839 requestStream.Write(trailer, 0, trailer.Length);
840 requestStream.Close();
841
842 }
843
844 WebResponse webResponse = request.GetResponse();
845 Stream responseStream = webResponse.GetResponseStream();
846 StreamReader reader = new StreamReader(responseStream);
847 response = reader.ReadToEnd();
848
849 webResponse.Dispose();
850 reader.Dispose();
851 reader = null;
852 request = null;
853 webResponse = null;
854 }
855 catch (Exception ex) {
856 LogManager.WriteToLog(ex.Message);
857 }
858
859 return response;
860 }
861 }
862
863 public class FormFile {
864 public string Name { get; set; }
865
866 public string ContentType { get; set; }
867
868 public string FilePath { get; set; }
869
870 public Stream Stream { get; set; }
871 }
872 }