Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinfaux committed Oct 30, 2018
1 parent eadd7f2 commit 2714021
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 19 deletions.
133 changes: 114 additions & 19 deletions src/UmbracoFileSystemProviders.Azure/AzureBlobFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ public class AzureBlobFileSystem : IFileSystem
/// </summary>
private const string UsePrivateContainerKey = Constants.Configuration.UsePrivateContainer;

/// <summary>
/// The configuration key for determining the container name for Umbraco Forms uploads.
/// </summary>
private const string ContainerNameKeyForUmbracoFormsUploads = Constants.Configuration.ContainerNameKeyForUmbracoFormsUploads;

/// <summary>
/// The configuration key for determining whether the container for Umbraco Forms uploads should be private.
/// </summary>
private const string UsePrivateContainerKeyForUmbracoFormsUploads = Constants.Configuration.UsePrivateContainerForUmbracoFormsUploads;

/// <summary>
/// Initializes a new instance of the <see cref="AzureBlobFileSystem"/> class.
/// </summary>
Expand Down Expand Up @@ -93,8 +103,45 @@ public AzureBlobFileSystem(string containerName, string rootUrl, string connecti
/// <param name="useDefaultRoute">Whether to use the default "media" route in the url independent of the blob container.</param>
/// <param name="usePrivateContainer">blob container can be private (no direct access) or public (direct access possible, default)</param>
public AzureBlobFileSystem(string containerName, string rootUrl, string connectionString, string maxDays, string useDefaultRoute, string usePrivateContainer)
: this(containerName, rootUrl, connectionString, maxDays, useDefaultRoute, usePrivateContainer, string.Empty, "true")
{
}

/// <summary>
/// Initializes a new instance of the <see cref="AzureBlobFileSystem" /> class.
/// </summary>
/// <param name="containerName">The container name.</param>
/// <param name="rootUrl">The root url.</param>
/// <param name="connectionString">The connection string.</param>
/// <param name="maxDays">The maximum number of days to cache blob items for in the browser.</param>
/// <param name="useDefaultRoute">Whether to use the default "media" route in the url independent of the blob container.</param>
/// <param name="usePrivateContainer">blob container can be private (no direct access) or public (direct access possible, default)</param>
/// <param name="containerNameForUmbracoFormsUploads">The container name for Umbraco Forms uploads.</param>
public AzureBlobFileSystem(string containerName, string rootUrl, string connectionString, string maxDays, string useDefaultRoute, string usePrivateContainer, string containerNameForUmbracoFormsUploads)
: this(containerName, rootUrl, connectionString, maxDays, useDefaultRoute, usePrivateContainer, containerNameForUmbracoFormsUploads, "true")
{
}

/// <summary>
/// Initializes a new instance of the <see cref="AzureBlobFileSystem" /> class.
/// </summary>
/// <param name="containerName">The container name.</param>
/// <param name="rootUrl">The root url.</param>
/// <param name="connectionString">The connection string.</param>
/// <param name="maxDays">The maximum number of days to cache blob items for in the browser.</param>
/// <param name="useDefaultRoute">Whether to use the default "media" route in the url independent of the blob container.</param>
/// <param name="usePrivateContainer">blob container can be private (no direct access) or public (direct access possible, default)</param>
/// <param name="containerNameForUmbracoFormsUploads">The container name for Umbraco Forms uploads.</param>
/// <param name="usePrivateContainerForUmbracoFormsUploads">blob container for Umbraco Forms uploads can be private (no direct access, default) or public (direct access possible)</param>
public AzureBlobFileSystem(string containerName, string rootUrl, string connectionString, string maxDays, string useDefaultRoute, string usePrivateContainer, string containerNameForUmbracoFormsUploads, string usePrivateContainerForUmbracoFormsUploads)
{
this.ConnectionString = connectionString;
this.FileSystem = AzureFileSystem.GetInstance(containerName, rootUrl, connectionString, maxDays, useDefaultRoute, usePrivateContainer);
if (!string.IsNullOrEmpty(containerNameForUmbracoFormsUploads))
{
this.ContainerNameForUmbracoFormsUploads = containerNameForUmbracoFormsUploads;
this.FileSystemForUmbracoFormsUploads = AzureFileSystem.GetInstance(containerNameForUmbracoFormsUploads, rootUrl, connectionString, maxDays, useDefaultRoute, usePrivateContainerForUmbracoFormsUploads);
}
}

/// <summary>
Expand All @@ -104,8 +151,8 @@ public AzureBlobFileSystem(string containerName, string rootUrl, string connecti
/// <param name="alias">The alias of the provider</param>
public AzureBlobFileSystem(string alias)
{
string connectionString = ConfigurationManager.AppSettings[$"{ConnectionStringKey}:{alias}"];
if (!string.IsNullOrWhiteSpace(connectionString))
this.ConnectionString = ConfigurationManager.AppSettings[$"{ConnectionStringKey}:{alias}"];
if (!string.IsNullOrWhiteSpace(this.ConnectionString))
{
string rootUrl = ConfigurationManager.AppSettings[$"{RootUrlKey}:{alias}"];
if (string.IsNullOrWhiteSpace(rootUrl))
Expand Down Expand Up @@ -137,19 +184,52 @@ public AzureBlobFileSystem(string alias)
accessType = "true";
}

this.FileSystem = AzureFileSystem.GetInstance(containerName, rootUrl, connectionString, maxDays, useDefaultRoute, accessType);
this.ContainerNameForUmbracoFormsUploads = ConfigurationManager.AppSettings[$"{ContainerNameKeyForUmbracoFormsUploads}:{alias}"];
if (string.IsNullOrWhiteSpace(this.ContainerNameForUmbracoFormsUploads))
{
containerName = string.Empty;
}

string accessTypeForUmbracoFormsUploads = ConfigurationManager.AppSettings[$"{UsePrivateContainerKeyForUmbracoFormsUploads}:{alias}"];
if (string.IsNullOrWhiteSpace(accessTypeForUmbracoFormsUploads))
{
accessType = "true";
}

this.FileSystem = AzureFileSystem.GetInstance(containerName, rootUrl, this.ConnectionString, maxDays, useDefaultRoute, accessType);
if (!string.IsNullOrEmpty(this.ContainerNameForUmbracoFormsUploads))
{
this.FileSystemForUmbracoFormsUploads = AzureFileSystem.GetInstance(this.ContainerNameForUmbracoFormsUploads, rootUrl, this.ConnectionString, maxDays, useDefaultRoute, accessTypeForUmbracoFormsUploads);
}

}
else
{
throw new InvalidOperationException("Unable to retrieve the Azure Storage configuration from the application settings. " + ConnectionStringKey + " was not defined or is empty.");
}
}

/// <summary>
/// Gets the Azure blob storage connection string.
/// </summary>
public string ConnectionString { get; private set; }

/// <summary>
/// Gets the container name for Umbraco Forms uploads, if configured.
/// </summary>
public string ContainerNameForUmbracoFormsUploads { get; private set; }

/// <summary>
/// Gets a singleton instance of the <see cref="AzureFileSystem"/> class.
/// </summary>
internal AzureFileSystem FileSystem { get; }

/// <summary>
/// Gets a singleton instance of the <see cref="AzureFileSystem"/> class.
/// </summary>
internal AzureFileSystem FileSystemForUmbracoFormsUploads { get; }


/// <summary>
/// Adds a file to the file system.
/// </summary>
Expand All @@ -164,7 +244,7 @@ public AzureBlobFileSystem(string alias)
/// </param>
public void AddFile(string path, Stream stream, bool overrideIfExists)
{
this.FileSystem.AddFile(path, stream, overrideIfExists);
this.SelectFileSystemForPath(path).AddFile(path, stream, overrideIfExists);
}

/// <summary>
Expand All @@ -178,7 +258,7 @@ public void AddFile(string path, Stream stream, bool overrideIfExists)
/// </param>
public void AddFile(string path, Stream stream)
{
this.FileSystem.AddFile(path, stream);
this.SelectFileSystemForPath(path).AddFile(path, stream);
}

/// <summary>
Expand All @@ -191,7 +271,7 @@ public void AddFile(string path, Stream stream)
/// </param>
public void DeleteDirectory(string path, bool recursive)
{
this.FileSystem.DeleteDirectory(path, recursive);
this.SelectFileSystemForPath(path).DeleteDirectory(path, recursive);
}

/// <summary>
Expand All @@ -200,7 +280,7 @@ public void DeleteDirectory(string path, bool recursive)
/// <param name="path">The name of the directory to remove.</param>
public void DeleteDirectory(string path)
{
this.FileSystem.DeleteDirectory(path, false);
this.SelectFileSystemForPath(path).DeleteDirectory(path, false);
}

/// <summary>
Expand All @@ -209,7 +289,7 @@ public void DeleteDirectory(string path)
/// <param name="path">The name of the file to remove.</param>
public void DeleteFile(string path)
{
this.FileSystem.DeleteFile(path);
this.SelectFileSystemForPath(path).DeleteFile(path);
}

/// <summary>
Expand All @@ -221,7 +301,7 @@ public void DeleteFile(string path)
/// </returns>
public bool DirectoryExists(string path)
{
return this.FileSystem.DirectoryExists(path);
return this.SelectFileSystemForPath(path).DirectoryExists(path);
}

/// <summary>
Expand All @@ -233,7 +313,7 @@ public bool DirectoryExists(string path)
/// </returns>
public bool FileExists(string path)
{
return this.FileSystem.FileExists(path);
return this.SelectFileSystemForPath(path).FileExists(path);
}

/// <summary>
Expand All @@ -245,7 +325,7 @@ public bool FileExists(string path)
/// </returns>
public DateTimeOffset GetCreated(string path)
{
return this.FileSystem.GetCreated(path);
return this.SelectFileSystemForPath(path).GetCreated(path);
}

/// <summary>
Expand All @@ -257,7 +337,7 @@ public DateTimeOffset GetCreated(string path)
/// </returns>
public IEnumerable<string> GetDirectories(string path)
{
return this.FileSystem.GetDirectories(path);
return this.SelectFileSystemForPath(path).GetDirectories(path);
}

/// <summary>
Expand All @@ -270,7 +350,7 @@ public IEnumerable<string> GetDirectories(string path)
/// </returns>
public IEnumerable<string> GetFiles(string path, string filter)
{
return this.FileSystem.GetFiles(path, filter);
return this.SelectFileSystemForPath(path).GetFiles(path, filter);
}

/// <summary>
Expand All @@ -282,7 +362,7 @@ public IEnumerable<string> GetFiles(string path, string filter)
/// </returns>
public IEnumerable<string> GetFiles(string path)
{
return this.FileSystem.GetFiles(path);
return this.SelectFileSystemForPath(path).GetFiles(path);
}

/// <summary>
Expand All @@ -294,7 +374,7 @@ public IEnumerable<string> GetFiles(string path)
/// </returns>
public string GetFullPath(string path)
{
return this.FileSystem.GetFullPath(path);
return this.SelectFileSystemForPath(path).GetFullPath(path);
}

/// <summary>
Expand All @@ -306,7 +386,7 @@ public string GetFullPath(string path)
/// </returns>
public DateTimeOffset GetLastModified(string path)
{
return this.FileSystem.GetLastModified(path);
return this.SelectFileSystemForPath(path).GetLastModified(path);
}

/// <summary>
Expand All @@ -318,7 +398,7 @@ public DateTimeOffset GetLastModified(string path)
/// </returns>
public string GetRelativePath(string fullPathOrUrl)
{
return this.FileSystem.GetRelativePath(fullPathOrUrl);
return this.SelectFileSystemForPath(fullPathOrUrl).GetRelativePath(fullPathOrUrl);
}

/// <summary>
Expand All @@ -331,7 +411,7 @@ public string GetRelativePath(string fullPathOrUrl)
/// </returns>
public string GetUrl(string path)
{
return this.FileSystem.GetUrl(path);
return this.SelectFileSystemForPath(path).GetUrl(path);
}

/// <summary>
Expand All @@ -343,7 +423,22 @@ public string GetUrl(string path)
/// </returns>
public Stream OpenFile(string path)
{
return this.FileSystem.OpenFile(path);
return this.SelectFileSystemForPath(path).OpenFile(path);
}

/// <summary>
/// Selects the correct file system depending on whether the media is an Umbraco Forms upload or not
/// </summary>
/// <param name="path">The path.</param>
/// <returns>The appropriate <see cref="AzureFileSystem"/> for the path</returns>
private AzureFileSystem SelectFileSystemForPath(string path)
{
if (this.FileSystemForUmbracoFormsUploads != null && this.FileSystemForUmbracoFormsUploads.IsUmbracoFormsUpload(path))
{
return this.FileSystemForUmbracoFormsUploads;
}

return this.FileSystem;
}
}
}
23 changes: 23 additions & 0 deletions src/UmbracoFileSystemProviders.Azure/AzureFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,17 @@ public Stream OpenFile(string path)
return null;
}

// If the path is for an Umbraco forms upload, just return an empty result.
// We don't want them downloaded via this provider because it's unauthenticated
// (or authenticated against Members), and forms uploads need to check that the
// current back office user has permission to the form. Sites will need to
// implement a separate secure way to download forms uploads.
// This is part of a workaround for http://issues.umbraco.org/issue/CON-1454
if (this.IsUmbracoFormsUpload(path))
{
return null;
}

MemoryStream stream = new MemoryStream();
blockBlob.DownloadToStream(stream);

Expand All @@ -654,6 +665,18 @@ public Stream OpenFile(string path)
return null;
}

/// <summary>
/// Determines whether a file path represents an Umbraco Forms upload.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>
/// <c>true</c> if it is an Umbraco Forms upload; otherwise, <c>false</c>.
/// </returns>
public bool IsUmbracoFormsUpload(string path)
{
return !string.IsNullOrEmpty(path) && this.FixPath(path).StartsWith("forms/upload/");
}

/// <summary>
/// Returns the media container, creating a new one if none exists.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/UmbracoFileSystemProviders.Azure/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ public static class Configuration
/// The configuration key for providing the Use Private Container value via the web.config
/// </summary>
public const string UsePrivateContainer = "AzureBlobFileSystem.UsePrivateContainer";

/// <summary>
/// The configuration key for providing the Azure Blob Container Name for Umbraco Forms uploads via the web.config
/// </summary>
public const string ContainerNameKeyForUmbracoFormsUploads = "AzureBlobFileSystem.ContainerNameForUmbracoFormsUploads";

/// <summary>
/// The configuration key for providing the Use Private Container value for Umbraco Forms uploads via the web.config
/// </summary>
public const string UsePrivateContainerForUmbracoFormsUploads = "AzureBlobFileSystem.UsePrivateContainerForUmbracoFormsUploads";
}
}
}

0 comments on commit 2714021

Please sign in to comment.