/// <summary> /// This method must return true for the <see cref="XForwardedForHeader"/> and <see cref="XRealIPHeader"/> flags to be honored. This method should only return true if the provided remote IP address is trusted to provide the related headers. /// </summary> /// <param name="remoteIpAddress"></param> /// <returns></returns> public override bool IsTrustedProxyServer(IPAddress remoteIpAddress) { if (string.IsNullOrWhiteSpace(TimelapseWrapper.cfg.options.TrustedProxyServers)) { return(false); } return(IpWhitelist.IsWhitelisted(remoteIpAddress.ToString(), TimelapseWrapper.cfg.options.TrustedProxyServers)); }
public static string GetAllCamerasJavascriptArray(string ip) { List <string> camerasList = new List <string>(); foreach (CameraSpec cs in TimelapseWrapper.cfg.cameras) { if (!IpWhitelist.IsWhitelisted(ip, cs.ipWhitelist)) { continue; } if (cs.showOnAllPage) { string imgsrc = "", imglink = "", namelink = ""; long imgDate; if (cs.type == CameraType.ThirdPartyHosted) { imgsrc = cs.path_3rdpartyimg.Replace("%TIME%", DateTime.Now.ToJavaScriptMilliseconds().ToString()); imglink = cs.path_3rdpartyimglink; namelink = cs.path_3rdpartynamelink; imgDate = DateTime.UtcNow.ToJavaScriptMilliseconds(); } else { //imgsrc = cs.id + "/latest.jpg"; imglink = namelink = "Camera.html?cam=" + cs.id; string timeHtml; DateTime timeObj; try { Navigation.GetLatestImagePath(cs, out timeHtml, out timeObj); } catch (NavigationException) { timeObj = DateTime.Now; } imgsrc = cs.id + "/latest.jpg"; imgDate = timeObj.ToJavaScriptMilliseconds(); } string isPrivileged = string.IsNullOrWhiteSpace(cs.ipWhitelist) ? "false" : "true"; camerasList.Add("['" + HttpUtility.JavaScriptStringEncode(cs.id) + "', '" + HttpUtility.JavaScriptStringEncode(cs.name) + "', '" + HttpUtility.JavaScriptStringEncode(imgsrc) + "', '" + HttpUtility.JavaScriptStringEncode(imglink) + "', '" + HttpUtility.JavaScriptStringEncode(namelink) + "', '" + HttpUtility.JavaScriptStringEncode(cs.allPageOverlayMessage) + "', " + imgDate + ", " + isPrivileged + "]"); } } return("[" + string.Join(",", camerasList) + "]"); }
public override void handleGETRequest(HttpProcessor p) { try { string requestedPageLower = p.requestedPage.ToLower(); if (p.requestedPage == "errors") { string errors = File.ReadAllText(Globals.ErrorFilePath); p.writeSuccess(); p.outputStream.Write(HttpUtility.HtmlEncode(errors).Replace("\r\n", "<br/>").Replace("\r", "<br/>").Replace("\n", "<br/>")); return; } if (p.requestedPage == "error") { Logger.Debug("/error page loaded"); p.writeSuccess(); p.outputStream.Write("Error written to log"); return; } if (p.requestedPage == "admin") { p.writeRedirect("admin/main"); return; } if (p.requestedPage == "login") { LogOutUser(p, null); return; } if (p.requestedPage == "testip") { p.writeSuccess("text/plain; charset=utf-8"); p.outputStream.Write(p.RemoteIPAddressStr); return; } Session s = sm.GetSession(p.requestCookies.GetValue("tlsess"), p.requestCookies.GetValue("tlauth"), p.GetParam("rawauth")); if (s != null && s.sid != null && s.sid.Length == 16) { p.responseCookies.Add("tlsess", s.sid, TimeSpan.FromMinutes(s.sessionLengthMinutes)); } if (p.requestedPage == "logout") { LogOutUser(p, s); return; } if (p.requestedPage.StartsWith("admin/")) { string adminPage = p.requestedPage == "admin" ? "" : p.requestedPage.Substring("admin/".Length); if (string.IsNullOrWhiteSpace(adminPage)) { adminPage = "main"; } int idxQueryStringStart = adminPage.IndexOf('?'); if (idxQueryStringStart == -1) { idxQueryStringStart = adminPage.Length; } adminPage = adminPage.Substring(0, idxQueryStringStart); Pages.Admin.AdminPage.HandleRequest(adminPage, p, s); return; } else if (p.requestedPage == "Navigation" || p.requestedPage == "NavigationNextDay") { if (HandlePublicServiceDisabled(p)) { return; } CameraSpec cs = TimelapseWrapper.cfg.GetCameraSpec(p.GetParam("cam")); if (cs == null || cs.type != CameraType.FTP) { p.writeFailure("400 Bad Request"); } else if (cs != null && !IpWhitelist.IsWhitelisted(p.RemoteIPAddressStr, cs.ipWhitelist)) { p.writeFailure("403 Forbidden"); } else { string path = p.GetParam("path"); p.writeSuccess(); try { if (p.requestedPage == "Navigation") { p.outputStream.Write(Navigation.GetNavHtml(cs, path)); } else { p.outputStream.Write(Navigation.GetNavHtmlForNextDay(cs, path)); } } catch (NavigationException) { p.outputStream.Write("Server busy. Please reload this page later."); } } } else if (p.requestedPage == "TimeZoneList") { if (HandlePublicServiceDisabled(p)) { return; } p.writeSuccess(); p.outputStream.Write(Pages.TimeZoneList.GetHtml()); } else if (requestedPageLower.StartsWith(TimelapseGlobals.ImageArchiveFolderNameLower + "/")) { p.writeFailure(); } else if (p.requestedPage == "GetFileListUrls") { if (HandlePublicServiceDisabled(p)) { return; } CameraSpec cs = TimelapseWrapper.cfg.GetCameraSpec(p.GetParam("cam")); if (cs == null || cs.type != CameraType.FTP) { p.writeFailure("400 Bad Request"); } else if (cs != null && !IpWhitelist.IsWhitelisted(p.RemoteIPAddressStr, cs.ipWhitelist)) { p.writeFailure("403 Forbidden"); } else { string path = p.GetParam("path"); try { string response = Navigation.GetFileListUrls(cs, path); p.writeSuccess("text/plain"); p.outputStream.Write(response); } catch (NavigationException) { p.writeFailure("503 Service Unavailable"); p.outputStream.Write(""); } catch (Exception ex) { Logger.Debug(ex); p.writeFailure("500 Internal Server Error"); } } } else { if (p.requestedPage.StartsWith("TimelapseAPI/", StringComparison.OrdinalIgnoreCase)) { mvcApi.ProcessRequest(p, p.requestedPage.Substring("TimelapseAPI/".Length)); return; } CameraSpec cs = null; if (p.request_url.Segments.Length > 1) { cs = TimelapseWrapper.cfg.GetCameraSpec(p.request_url.Segments[1].Trim('/')); } if (cs != null) { if (HandlePublicServiceDisabled(p)) { return; } if (cs != null && !IpWhitelist.IsWhitelisted(p.RemoteIPAddressStr, cs.ipWhitelist)) { p.writeFailure("403 Forbidden"); } else { // This page is something involving a camera we have configured if (p.request_url.Segments.Length == 2) { if (cs.type == CameraType.ThirdPartyHosted) { p.writeFailure("400 Bad Request"); } else { p.writeRedirect("Camera.html?cam=" + cs.id); // Redirect to the camera page for this camera } } else if (p.request_url.Segments.Length >= 3) { if (p.request_url.Segments.Length == 3 && p.request_url.Segments[2] == "latest.jpg") { if (cs.type == CameraType.ThirdPartyHosted) { if (!string.IsNullOrWhiteSpace(cs.path_3rdpartyimgzippedURL)) { WebServerUtil.Handle3rdPartyZippedImage(p, cs); return; } else { p.writeFailure("400 Bad Request"); return; } } if (!CameraMaintenance.MaintainCamera(cs)) { p.writeFailure("500 Internal Server Error"); return; } string latestImgTime; DateTime dateTime; string latestImagePathPart; try { latestImagePathPart = Navigation.GetLatestImagePath(cs, out latestImgTime, out dateTime); } catch (NavigationException) { p.writeFailure("503 Service Unavailable"); return; } string path = cs.id + "/" + latestImagePathPart; List <KeyValuePair <string, string> > headers = WebServerUtil.GetCacheEtagHeaders(TimeSpan.Zero, path); FileInfo imgFile = new FileInfo(TimelapseGlobals.ImageArchiveDirectoryBase + path); headers.Add(new KeyValuePair <string, string>("Content-Disposition", "inline; filename=\"" + cs.name + " " + imgFile.Name.Substring(0, imgFile.Name.Length - imgFile.Extension.Length) + ".jpg\"")); if (path == p.GetHeaderValue("if-none-match")) { p.writeSuccess("image/jpeg", -1, "304 Not Modified"); return; } byte[] data = WebServerUtil.GetImageData(path); p.writeSuccess("image/jpeg", data.Length, additionalHeaders: headers); p.outputStream.Flush(); p.tcpStream.Write(data, 0, data.Length); } else { if (cs.type != CameraType.FTP) { p.writeFailure("400 Bad Request"); return; } List <KeyValuePair <string, string> > headers = WebServerUtil.GetCacheEtagHeaders(TimeSpan.FromDays(365), p.requestedPage); FileInfo imgFile = new FileInfo(TimelapseGlobals.ImageArchiveDirectoryBase + p.requestedPage); headers.Add(new KeyValuePair <string, string>("Content-Disposition", "inline; filename=\"" + cs.name + " " + imgFile.Name.Substring(0, imgFile.Name.Length - imgFile.Extension.Length) + ".jpg\"")); if (p.requestedPage == p.GetHeaderValue("if-none-match")) { p.writeSuccess("image/jpeg", -1, "304 Not Modified"); return; } byte[] data = WebServerUtil.GetImageData(p.requestedPage); p.writeSuccess("image/jpeg", data.Length, additionalHeaders: headers); p.outputStream.Flush(); p.tcpStream.Write(data, 0, data.Length); } } else { p.writeFailure(); } } } else { #region www DirectoryInfo WWWDirectory = new DirectoryInfo(TimelapseGlobals.WWWDirectoryBase); DirectoryInfo debugWWW = GetDebugWWW(); if (debugWWW != null) { WWWDirectory = debugWWW; } string wwwDirectoryBase = WWWDirectory.FullName.Replace('\\', '/').TrimEnd('/') + '/'; string reqPage = p.requestedPage; //if (reqPage == "") // reqPage = "Default.html"; FileInfo fi = new FileInfo(wwwDirectoryBase + reqPage); string targetFilePath = fi.FullName.Replace('\\', '/'); if (!targetFilePath.StartsWith(wwwDirectoryBase) || targetFilePath.Contains("../")) { if (WebServerUtil.HandleAdminConfiguredRedirect(p)) { return; } p.writeFailure("400 Bad Request"); return; } //if (webpackProxy != null) //{ // // Handle hot module reload provided by webpack dev server. // switch (fi.Extension.ToLower()) // { // case ".js": // case ".map": // case ".css": // case ".json": // webpackProxy.Proxy(p); // return; // } //} if (!fi.Exists) { if (WebServerUtil.HandleAdminConfiguredRedirect(p)) { return; } //fi = new FileInfo(wwwDirectoryBase + "Default.html"); //if (!fi.Exists) //{ p.writeFailure("404 Not Found"); return; //} } if ((fi.Extension == ".html" || fi.Extension == ".htm") && fi.Length < 256000) { string html = File.ReadAllText(fi.FullName); if (fi.Name.ToLower() == "camera.html") { // camera.html triggers special behavior if (HandlePublicServiceDisabled(p)) { return; } string camId = p.GetParam("cam"); cs = TimelapseWrapper.cfg.GetCameraSpec(camId); if (cs == null || cs.type == CameraType.ThirdPartyHosted || !CameraMaintenance.MaintainCamera(cs)) { p.writeFailure("400 Bad Request"); return; } if (cs != null && !IpWhitelist.IsWhitelisted(p.RemoteIPAddressStr, cs.ipWhitelist)) { p.writeFailure("403 Forbidden"); return; } string latestImgTime = ""; DateTime dateTime = DateTime.MinValue; string navMenu; string latestImagePathPart; try { navMenu = Navigation.GetNavHtml(cs, Navigation.GetLatestPath(cs, out latestImgTime, out dateTime)); latestImagePathPart = Navigation.GetLatestImagePath(cs, out latestImgTime, out dateTime); } catch (NavigationException) { navMenu = "Server busy. Please reload this page later."; latestImagePathPart = "latest"; } html = html.Replace("%NAVMENU%", navMenu); html = html.Replace("%TOPMENU%", cs.topMenuHtml); html = html.Replace("%CAMID%", cs.id); html = html.Replace("%CAMNAME%", cs.name); html = html.Replace("%CSS%", WebServerUtil.GetCameraPageStyleCSS(cs)); html = html.Replace("%CAMFRAME_GRADIENT%", cs.imgBackgroundGradient ? "true" : "false"); html = html.Replace("%CAMNAME_HTML%", WebServerUtil.GetCameraNameHtml(cs)); string latestImagePath = cs.id + "/" + latestImagePathPart + ".jpg"; html = html.Replace("%LATEST_IMAGE%", latestImagePath); html = html.Replace("%LATEST_IMAGE_TIME%", HttpUtility.JavaScriptStringEncode(latestImgTime)); } else if (fi.Name.ToLower() == "all.html") { // all.html triggers special macro strings html = html.Replace("%ALL_CAMERAS_JS_ARRAY%", WebServerUtil.GetAllCamerasJavascriptArray(p.RemoteIPAddressStr)); html = html.Replace("%ALL_PAGE_HEADER%", TimelapseWrapper.cfg.options.allPageHeading); } try { html = html.Replace("%REMOTEIP%", p.RemoteIPAddressStr); html = html.Replace("%SYSTEM_NAME%", TimelapseWrapper.cfg.options.systemName); html = html.Replace("%APP_VERSION%", TimelapseGlobals.Version); } catch (Exception ex) { Logger.Debug(ex); } p.writeSuccess(Mime.GetMimeType(fi.Extension)); p.outputStream.Write(html); p.outputStream.Flush(); } else { string mime = Mime.GetMimeType(fi.Extension); if (p.requestedPage.StartsWith(".well-known/acme-challenge/")) { mime = "text/plain"; } if (fi.LastWriteTimeUtc.ToString("R") == p.GetHeaderValue("if-modified-since")) { p.writeSuccess(mime, -1, "304 Not Modified"); return; } p.writeSuccess(mime, fi.Length, additionalHeaders: WebServerUtil.GetCacheLastModifiedHeaders(TimeSpan.FromHours(1), fi.LastWriteTimeUtc)); p.outputStream.Flush(); using (FileStream fs = fi.OpenRead()) { fs.CopyTo(p.tcpStream); } p.tcpStream.Flush(); } #endregion } } } catch (Exception ex) { if (!HttpProcessor.IsOrdinaryDisconnectException(ex)) { Logger.Debug(ex); } } }