1 using Newtonsoft.Json.Linq;
7 using System.Text.RegularExpressions;
9 using System.Threading;
10 using System.Collections.Generic;
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;
20 public string _derivedk;
21 public CookieContainer _cookie = new CookieContainer();
29 * Requests the password-challenge from the router.
33 public string getChallenge () {
34 string response = sendRequest("data/Login.json", "csrf_token=nulltoken&showpw=0&challengev=null");
35 if (response.IsNullOrEmpty())
38 string challenge = string.Empty;
40 JToken jArray = JToken.Parse(response);
42 challenge = jArray.getVar("challengev");
45 catch (Exception ex) {
46 LogManager.WriteToLog(ex.Message);
55 * calculate the derivedk
57 * @param string $password
60 public string getDerviedk () {
61 return _password.sha256().pbkdf2(_challenge.Substring(0, 16));
65 * login into the router with the given password
67 * @param string $password
70 public bool login (string passwort) {
71 if (passwort.IsNullOrEmpty()) {
75 _cookie = new CookieContainer();
78 _challenge = getChallenge();
79 _hash = string.Concat(_challenge, ":", _password).sha256();
81 string response = sendRequest("data/Login.json", string.Concat("csrf_token=nulltoken&showpw=0&password=", _hash));
82 if (response.IsNullOrEmpty())
85 _cookie.Add(new Cookie("challengev", _challenge) { Domain = "speedport.ip" });
89 JToken jArray = JToken.Parse(response);
90 if (jArray.getVar("login").Equals("success")) {
91 if (isLoggedin().Equals(false)) {
96 _derivedk = getDerviedk();
97 _lastReboot = getLastReboot();
102 catch (Exception ex) {
103 LogManager.WriteToLog(ex.Message);
116 public bool logout () {
117 string response = sendRequest("data/Login.json", string.Concat("csrf_token=", getToken(), "&logout=byby"));
118 if (response.IsNullOrEmpty())
123 JToken jArray = JToken.Parse(response);
124 if (jArray.getVar("status").Equals("ok")) {
125 if (isLoggedin().Equals(true)) {
132 _cookie = new CookieContainer();
133 _lastReboot = DateTime.MinValue;
141 catch (Exception ex) {
142 LogManager.WriteToLog(ex.Message);
151 * check if we are logged in
155 public bool checkLogin () {
159 if (_checkIsActive.Equals(false)) {
160 _checkIsActive = true;
161 if (isLoggedin().Equals(false)) {
162 Console.WriteLine("Session expired, try to relogin");
166 if (login(_password).Equals(false)) {
167 // should we try to relogin? login(_password);...
168 new Thread(() => { LogManager.WriteToLog("Session expired."); }).Start();
171 _cookie = new CookieContainer();
172 _lastReboot = DateTime.MinValue;
177 new Thread(() => { MessageBox.Show("Session expired.", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
178 _checkIsActive = false;
183 _checkIsActive = false;
186 Console.WriteLine("check allready in progress");
194 * check if we are logged in
196 * @param bool ischeck
199 public bool isLoggedin () {
200 string response = sendRequest("data/SecureStatus.json");
201 if (response.IsNullOrEmpty())
206 JToken jArray = JToken.Parse(response);
208 if (jArray.getVar("loginstate").Equals("1")/* && jArray.getVar("login").Equals("true")*/) {
215 catch (Exception ex) {
216 LogManager.WriteToLog(ex.Message);
227 public void reboot () {
230 if (checkLogin().Equals(false))
233 string response = sendRequest("data/Reboot.json", string.Concat("csrf_token=", Uri.EscapeUriString(getToken()), "&reboot_device=true"));
234 if (response.IsNullOrEmpty())
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.");
243 _cookie = new CookieContainer();
252 catch (Exception ex) {
253 LogManager.WriteToLog(ex.Message);
265 public bool reconnectLte () {
266 if (checkLogin().Equals(false))
271 string response = sendEnryptedRequest("data/modules.json", string.Concat("lte_reconn=1&csrf_token=", Uri.EscapeUriString(getToken())));
272 if (response.IsNullOrEmpty())
276 JToken jArray = JToken.Parse(response);
280 if (jArray.getVar("status").Equals("ok")) {
287 catch (Exception ex) {
288 LogManager.WriteToLog(ex.Message);
301 public bool reconnectDSL () {
302 if (checkLogin().Equals(false))
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())
311 bool offline = false;
313 JToken jArray = JToken.Parse(response);
317 if (jArray.getVar("status").Equals("ok")) {
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")) {
332 catch (Exception ex) {
333 LogManager.WriteToLog(ex.Message);
342 * change dsl connection status
344 * @param string status
347 public bool changeDSLStatus (string status) {
348 if (checkLogin().Equals(false))
351 if (status.Equals("online") || status.Equals("offline")) {
353 string response = sendEnryptedRequest("data/Connect.json", string.Concat("req_connect=", status, "&csrf_token=", Uri.EscapeUriString(getToken())));
354 if (response.IsNullOrEmpty())
357 JToken jArray = JToken.Parse(response);
361 if (jArray.getVar("status").Equals("ok")) {
366 catch (Exception ex) {
367 LogManager.WriteToLog(ex.Message);
377 * change lte connection status
379 * @param string status
382 public bool changeLTEStatus (string status) {
383 if (checkLogin().Equals(false))
386 if (status.Equals("online") || status.Equals("offline")) {
387 if (status.Equals("online"))
390 if (status.Equals("offline"))
393 string response = sendEnryptedRequest("data/Modules.json", string.Concat("use_lte=", status, "&csrf_token=", Uri.EscapeUriString(getToken())));
394 if (response.IsNullOrEmpty())
397 JToken jArray = JToken.Parse(response);
401 if (jArray.getVar("status").Equals("ok")) {
406 catch (Exception ex) {
407 LogManager.WriteToLog(ex.Message);
417 * reset the router to Factory Default
422 public bool resetToFactoryDefault () {
423 if (checkLogin().Equals(false))
428 string response = sendEnryptedRequest("data/resetAllSetting.json", string.Concat("csrf_token=nulltoken&showpw=0&password=", _hash, "&reset_all=true"));
429 if (response.IsNullOrEmpty())
433 JToken jArray = JToken.Parse(response);
434 if (jArray.getVar("status").Equals("ok")) {
440 catch (Exception ex) {
441 LogManager.WriteToLog(ex.Message);
450 * check for firmware update
452 public void checkFirmware () {
453 if (checkLogin().Equals(false))
458 string response = sendRequest("data/checkfirm.json");
459 if (response.IsNullOrEmpty())
463 bool fw_isActual = false;
464 JToken jArray = JToken.Parse(response);
466 if (jArray.getVar("fw_isActual").Equals("1")) {
470 if (fw_isActual.Equals(true)) {
471 // Die Firmware ist aktuell.
472 MessageBox.Show("Die Firmware ist aktuell.", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information);
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);
481 catch (Exception ex) {
482 LogManager.WriteToLog(ex.Message);
491 public void flushDNS () {
492 if (checkLogin().Equals(false))
497 string response = sendEnryptedRequest("data/dns.json", "op_type=flush_dns_cache");
498 if (response.IsNullOrEmpty())
502 JToken jArray = JToken.Parse(response);
504 if (jArray["DCI"].Count().Equals(0)) {
505 new Thread(() => { MessageBox.Show("DNS cache geleert", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information); }).Start();
508 new Thread(() => { MessageBox.Show("unable to flush dns cache", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
514 catch (Exception ex) {
515 LogManager.WriteToLog(ex.Message);
524 public void clearSyslog () {
525 if (checkLogin().Equals(false))
530 string response = sendEnryptedRequest("data/SystemMessages.json", string.Concat("action_clearlist=true&clear_type=0&", "csrf_token=", getToken()));
531 if (response.IsNullOrEmpty())
535 JToken jArray = JToken.Parse(response);
537 if (jArray.getVar("status").Equals("ok")) {
539 new Thread(() => { MessageBox.Show("Syslog geleert", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information); }).Start();
543 new Thread(() => { MessageBox.Show("Konnte Syslog nicht leeren.", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
548 catch (Exception ex) {
549 LogManager.WriteToLog(ex.Message);
556 * set QueueSkbTimeOut
558 * @param string value
560 public void setQueueSkbTimeOut (string value) {
563 if (checkLogin().Equals(false))
566 string response = sendEnryptedRequest("data/bonding_tr181.json", string.Concat("bonding_QueueSkbTimeOut=", value));
567 if (response.IsNullOrEmpty())
570 TR181 obj = JsonConvert.DeserializeObject<TR181>(response);
572 if (obj.QueueSkbTimeOut.Equals(value)) {
573 new Thread(() => { MessageBox.Show("QueueSkbTimeOut geändert", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information); }).Start();
576 new Thread(() => { MessageBox.Show("unable to change QueueSkbTimeOut", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
581 catch (Exception ex) {
582 LogManager.WriteToLog(ex.Message);
592 * @param string value
594 public void setAntennaMode (string value) {
597 if (checkLogin().Equals(false))
600 string response = sendEnryptedRequest("data/lteinfo.json", string.Concat("mode_select=", value));
601 if (response.IsNullOrEmpty())
604 LTE obj = JsonConvert.DeserializeObject<LTE>(response);
607 if (obj.antenna_mode.Equals("Antennal set to internal")) {
608 antenna_mode = "Inner";
610 else if (obj.antenna_mode.Equals("Antennal set to external")) {
611 antenna_mode = "Outer";
614 antenna_mode = "Auto";
617 if (antenna_mode.Equals(value)) {
618 new Thread(() => { MessageBox.Show("Antennen Modus geändert", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Information); }).Start();
621 new Thread(() => { MessageBox.Show("Antennen Modus ändern Fehlgeschlagen", "Confirmation", MessageBoxButton.OK, MessageBoxImage.Error); }).Start();
628 catch (Exception ex) {
629 LogManager.WriteToLog(ex.Message);
637 * get Last Reboot time
641 public DateTime getLastReboot () {
642 if (_lastReboot.Equals(DateTime.MinValue).Equals(false)) {
646 string response = sendRequest("data/Reboot.json");
648 if (response.IsNullOrEmpty())
651 JToken jArray = JToken.Parse(response);
653 DateTime lastReboot = DateTime.Parse(string.Concat(jArray.getVar("reboot_date"), " ", jArray.getVar("reboot_time")));
661 * get the csrf token from router
665 public string getToken () {
666 string response = sendRequest("html/content/overview/index.html");
667 if (response.IsNullOrEmpty())
670 string a = "csrf_token = \"";
672 string token = response.Substring((response.IndexOf(a) + a.Length), (response.IndexOf(b) - response.IndexOf(a) - a.Length));
678 Console.WriteLine("csrf_token: " + token);
683 * send encrypted request to the router
690 public string sendEnryptedRequest (string path, string post = "", bool cookie = true) {
691 string response = string.Empty;
694 sjcl sjcl = new sjcl();
696 string iv = _challenge.Substring(16, 16);
697 string adata = _challenge.Substring(32, 16);
698 string dKey = _derivedk;
701 // TODO: check if we need this really?
702 if (post.IsNullOrEmpty().Equals(false)) {
703 post = sjcl.encrypt(dKey, post, iv, adata);
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);
720 catch (ArgumentOutOfRangeException ex) {
721 LogManager.WriteToLog(ex.Message);
723 catch (Exception ex) {
724 LogManager.WriteToLog(ex.Message);
731 * send request to the router
738 public string sendRequest (string path, string post = "", bool cookie = true) {
739 string response = string.Empty;
741 string url = string.Concat("http://", ip, "/", path, "?lang=de");
743 HttpWebRequest webRequest = WebRequest.Create(url) as HttpWebRequest;
744 /* set timeout to 10 seconds */
745 webRequest.Timeout = 10000;
747 if (cookie.Equals(true)) {
748 webRequest.CookieContainer = _cookie;
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);
763 WebResponse webResponse = webRequest.GetResponse();
764 StreamReader reader = new StreamReader(webResponse.GetResponseStream());
765 response = reader.ReadToEnd().ToString();
767 webResponse.Dispose();
774 catch (Exception ex) {
775 LogManager.WriteToLog(ex.Message);
781 public string sendRequest2 (string path, Dictionary<string, object> files, string post = "", bool cookie = true) {
782 string response = string.Empty;
785 string url = string.Concat("http://", ip, "/", path, "?lang=de");
787 string boundary = string.Concat("---------------------------", DateTime.Now.Ticks.ToString("x"));
788 byte[] boundaryBytes = Encoding.ASCII.GetBytes(string.Concat("\r\n--", boundary, "\r\n"));
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;
795 if (cookie.Equals(true)) {
796 request.CookieContainer = _cookie;
799 Stream requestStream = request.GetRequestStream();
801 if (string.IsNullOrEmpty(post).Equals(false)) {
802 byte[] dataStream = Encoding.UTF8.GetBytes(post);
803 requestStream.Write(dataStream, 0, dataStream.Length);
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];
817 if (file.Stream == null) {
819 FileStream fileStream = File.OpenRead(file.FilePath);
820 while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) {
821 requestStream.Write(buffer, 0, bytesRead);
826 // upload from given stream
827 while ((bytesRead = file.Stream.Read(buffer, 0, buffer.Length)) != 0)
828 requestStream.Write(buffer, 0, bytesRead);
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);
838 byte[] trailer = Encoding.ASCII.GetBytes(string.Concat("\r\n--", boundary, "--\r\n"));
839 requestStream.Write(trailer, 0, trailer.Length);
840 requestStream.Close();
844 WebResponse webResponse = request.GetResponse();
845 Stream responseStream = webResponse.GetResponseStream();
846 StreamReader reader = new StreamReader(responseStream);
847 response = reader.ReadToEnd();
849 webResponse.Dispose();
855 catch (Exception ex) {
856 LogManager.WriteToLog(ex.Message);
863 public class FormFile {
864 public string Name { get; set; }
866 public string ContentType { get; set; }
868 public string FilePath { get; set; }
870 public Stream Stream { get; set; }