From 37a2ce60e24d2f2875ee8ef00752bfafaa969ba4 Mon Sep 17 00:00:00 2001 From: aka Torgon Woodget Date: Sun, 13 Oct 2013 17:57:47 +0200 Subject: [PATCH] Extended remote file reader to handle extensionless image urls and querystring parameters for remote URLs New properties for whitelist: Sample URL for extensionless/paramter remote image: http://localhost:49788/remote.axd?http://maps.googleapis.com/maps/api/staticmap?center=52.341055,7.125435&zoom=13&sensor=false&size=600x300&key=AIzaSyCMKi4DyRB2N-j-Sm3LpZkl6rSXWP_G5ZE?width=600 A 3rd querystring part (here: width=600) if the remote image url has url parameters Former-commit-id: 7f4f18b44eec578b74e2b02647f5fb6bd54fe29c --- .../NET45/Config/ImageProcessorConfig.cs | 11 ++++ .../NET45/Config/ImageSecuritySection.cs | 16 ++++++ .../NET45/Helpers/RemoteFile.cs | 5 ++ .../HttpModules/ImageProcessingModule.cs | 50 +++++++++++++++++-- .../NET45/ImageProcessor.Web_NET45.csproj | 7 ++- src/ImageProcessor.Web/NET45/packages.config | 6 +-- 6 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs b/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs index 6160150d8..76082ab7d 100644 --- a/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs +++ b/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs @@ -121,6 +121,17 @@ namespace ImageProcessor.Web.Config } } + /// + /// + /// + public ImageSecuritySection.SafeUrl[] RemoteFileWhiteListExtensions + { + get + { + return GetImageSecuritySection().WhiteList.Cast().ToArray(); + } + } + /// /// Gets a value indicating whether the current application is allowed to download remote files. /// diff --git a/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs b/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs index ac20ff498..16ec62db7 100644 --- a/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs +++ b/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs @@ -178,6 +178,22 @@ namespace ImageProcessor.Web.Config set { this["url"] = value; } } + + [ConfigurationProperty("extensionLess", DefaultValue = false, IsRequired = false)] + public bool ExtensionLess + { + get { return (bool)this["extensionLess"]; } + + set { this["extensionLess"] = value; } + } + + [ConfigurationProperty("imageFormat", DefaultValue = "", IsRequired = false)] + public string ImageFormat + { + get { return (string)this["imageFormat"]; } + + set { this["imageFormat"] = value; } + } } } } diff --git a/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs b/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs index 211d8e1f2..bd6cdee9c 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs @@ -48,6 +48,11 @@ namespace ImageProcessor.Web.Helpers /// private static readonly Uri[] RemoteFileWhiteList = ImageProcessorConfig.Instance.RemoteFileWhiteList; + /// + /// The white-list of url[s] from which to download remote files. + /// + public static readonly ImageSecuritySection.SafeUrl[] RemoteFileWhiteListExtensions = ImageProcessorConfig.Instance.RemoteFileWhiteListExtensions; + /// /// The length of time, in milliseconds, that a remote file download attempt can last before timing out. /// diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index df1363b92..f6a8fb1aa 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -5,6 +5,11 @@ // // ----------------------------------------------------------------------- +using System.Linq; +using System.Security.Cryptography; +using System.Security.Policy; +using System.Text; + namespace ImageProcessor.Web.HttpModules { #region Using @@ -177,6 +182,10 @@ namespace ImageProcessor.Web.HttpModules string requestPath = string.Empty; string queryString = string.Empty; + bool validExtensionLessUrl = false; + string urlParameters = ""; + string extensionLessExtension = ""; + if (isRemote) { // We need to split the querystring to get the actual values we want. @@ -194,10 +203,25 @@ namespace ImageProcessor.Web.HttpModules requestPath = paths[0]; - if (paths.Length > 1) + if (paths.Count() > 2) + { + queryString = paths[2]; + urlParameters = paths[1]; + } + else if (paths.Length > 1) { queryString = paths[1]; } + + validExtensionLessUrl = RemoteFile.RemoteFileWhiteListExtensions.Any( + x => x.ExtensionLess == true && requestPath.StartsWith(x.Url.AbsoluteUri)); + + if (validExtensionLessUrl) + { + extensionLessExtension = RemoteFile.RemoteFileWhiteListExtensions.First( + x => x.ExtensionLess == true && requestPath.StartsWith(x.Url.AbsoluteUri)).ImageFormat; + + } } } else @@ -207,11 +231,31 @@ namespace ImageProcessor.Web.HttpModules } // Only process requests that pass our sanitizing filter. - if (ImageUtils.IsValidImageExtension(requestPath) && !string.IsNullOrWhiteSpace(queryString)) + if ((ImageUtils.IsValidImageExtension(requestPath) || validExtensionLessUrl ) && !string.IsNullOrWhiteSpace(queryString)) { string fullPath = string.Format("{0}?{1}", requestPath, queryString); string imageName = Path.GetFileName(requestPath); + if (validExtensionLessUrl && !string.IsNullOrWhiteSpace(extensionLessExtension)) + { + fullPath = requestPath; + + if (!string.IsNullOrWhiteSpace(urlParameters)) + { + //TODO: Add hash for querystring parameters + HashAlgorithm algorithm = MD5.Create(); // SHA1.Create() + var hashCode = algorithm.ComputeHash(Encoding.UTF8.GetBytes(urlParameters)); + StringBuilder sb = new StringBuilder(); + foreach (byte b in hashCode) + sb.Append(b.ToString("X2")); + imageName += sb.ToString(); + fullPath += sb.ToString(); + } + + imageName += "." + extensionLessExtension; + fullPath += extensionLessExtension + "?" + queryString; + } + // Create a new cache to help process and cache the request. DiskCache cache = new DiskCache(request, requestPath, fullPath, imageName, isRemote); @@ -251,7 +295,7 @@ namespace ImageProcessor.Web.HttpModules { if (isRemote) { - Uri uri = new Uri(requestPath); + Uri uri = new Uri(requestPath + "?" + urlParameters); RemoteFile remoteFile = new RemoteFile(uri, false); diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 7274ce547..4cadb0c9e 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -11,6 +11,8 @@ ImageProcessor.Web v4.5 512 + ..\..\..\..\..\..\..\..\TFS\ActiMeet\ActiMeet2\ + true true @@ -31,10 +33,10 @@ - ..\..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.dll + ..\..\..\..\..\..\..\..\TFS\ActiMeet\ActiMeet2\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.dll - ..\..\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.SQLiteClient.dll + ..\..\..\..\..\..\..\..\TFS\ActiMeet\ActiMeet2\packages\Csharp-Sqlite.3.7.7.1\lib\net40\Community.CsharpSqlite.SQLiteClient.dll @@ -75,6 +77,7 @@ +