New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure Storage support #2229

Merged
merged 7 commits into from Jan 27, 2017
@@ -345,6 +345,12 @@ private HttpWebRequest PrepareWebRequest(HttpMethod method, string url, NameValu
headers.Remove("Accept");
}
if (headers["Content-Length"] != null)
{
request.ContentLength = Convert.ToInt32(headers["Content-Length"]);
headers.Remove("Content-Length");
}
request.Headers.Add(headers);
}
@@ -105,6 +105,8 @@ public enum FileDestination
Mega,
[Description("Amazon S3")]
AmazonS3,
[Description("Azure Storage")]
AzureStorage,
[Description("ownCloud")]
OwnCloud,
[Description("MediaFire")]
Binary file not shown.
@@ -0,0 +1,186 @@
using ShareX.UploadersLib.Properties;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
namespace ShareX.UploadersLib.FileUploaders
{
public sealed class AzureStorage : FileUploader
{
private string azureStorageAccountName;
private string azureStorageAccountAccessKey;
private string azureStorageContainer;
private const string apiVersion = "2016-05-31";
public AzureStorage(string asAccountName, string asAccessKey, string asContainer)
{
azureStorageAccountName = asAccountName;
azureStorageAccountAccessKey = asAccessKey;
azureStorageContainer = asContainer;
}
public override UploadResult Upload(Stream stream, string fileName)
{
if (string.IsNullOrEmpty(azureStorageAccountName)) { Errors.Add("'Account Name' must not be empty"); }
if (string.IsNullOrEmpty(azureStorageAccountAccessKey)) { Errors.Add("'Access key' must not be empty"); }
if (string.IsNullOrEmpty(azureStorageContainer)) { Errors.Add("'Container' must not be empty"); }
if (IsError)
{
return null;
}
CreateContainerIfNotExists();
var date = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
var uri = string.Format("https://{0}.blob.core.windows.net/{1}/{2}", azureStorageAccountName, azureStorageContainer, fileName);
NameValueCollection requestHeaders = new NameValueCollection();
requestHeaders["x-ms-date"] = date;
requestHeaders["x-ms-version"] = apiVersion;
requestHeaders["x-ms-blob-type"] = "BlockBlob";
var canonicalizedHeaders = string.Format("x-ms-blob-type:BlockBlob\nx-ms-date:{0}\nx-ms-version:{1}\n", date, apiVersion);
var canonicalizedResource = string.Format("/{0}/{1}/{2}", azureStorageAccountName, azureStorageContainer, fileName);
var StringToSign = GenerateStringToSign(canonicalizedHeaders, canonicalizedResource, stream.Length.ToString());
requestHeaders["Authorization"] = string.Format("SharedKey {0}:{1}", azureStorageAccountName, HashRequest(StringToSign));
NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, uri, stream, null, null, requestHeaders, null);
if (responseHeaders != null)
{
return new UploadResult { IsSuccess = true, URL = uri };
}
else
{
Errors.Add("Upload failed.");
return null;
}
}
private void CreateContainerIfNotExists()
{
var date = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
var uri = string.Format("https://{0}.blob.core.windows.net/{1}?restype=container", azureStorageAccountName, azureStorageContainer);
NameValueCollection requestHeaders = new NameValueCollection();
requestHeaders["Content-Length"] = "0";
requestHeaders["x-ms-date"] = date;
requestHeaders["x-ms-version"] = apiVersion;
var canonicalizedHeaders = string.Format("x-ms-date:{0}\nx-ms-version:{1}\n", date, apiVersion);
var canonicalizedResource = string.Format("/{0}/{1}\nrestype:container", azureStorageAccountName, azureStorageContainer);
var StringToSign = GenerateStringToSign(canonicalizedHeaders, canonicalizedResource);
requestHeaders["Authorization"] = string.Format("SharedKey {0}:{1}", azureStorageAccountName, HashRequest(StringToSign));
NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, uri, null, null, null, requestHeaders, null);
if (responseHeaders != null)
{
SetContainerACL();
}
else
{
if (Errors.Count != 0)
{
if (Errors[0].Contains("409"))
SetContainerACL();
else
{
Errors.Add("Upload to Azure storage failed.");
}
}
}
}
private void SetContainerACL()
{
var date = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
var uri = string.Format("https://{0}.blob.core.windows.net/{1}?restype=container&comp=acl", azureStorageAccountName, azureStorageContainer);
NameValueCollection requestHeaders = new NameValueCollection();
requestHeaders["Content-Length"] = "0";
requestHeaders["x-ms-date"] = date;
requestHeaders["x-ms-version"] = apiVersion;
requestHeaders["x-ms-blob-public-access"] = "container";
var canonicalizedHeaders = string.Format("x-ms-blob-public-access:container\nx-ms-date:{0}\nx-ms-version:{1}\n", date, apiVersion);
var canonicalizedResource = string.Format("/{0}/{1}\ncomp:acl\nrestype:container", azureStorageAccountName, azureStorageContainer);
var StringToSign = GenerateStringToSign(canonicalizedHeaders, canonicalizedResource);
requestHeaders["Authorization"] = string.Format("SharedKey {0}:{1}", azureStorageAccountName, HashRequest(StringToSign));
NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, uri, null, null, null, requestHeaders, null);
if (responseHeaders == null)
Errors.Add("There was an issue with setting ACL on the container.");
}
private string HashRequest(string stringToSign)
{
string hashedString;
using (HashAlgorithm hashAlgorithm = new HMACSHA256(Convert.FromBase64String(azureStorageAccountAccessKey)))
{
byte[] messageBuffer = Encoding.UTF8.GetBytes(stringToSign);
hashedString = Convert.ToBase64String(hashAlgorithm.ComputeHash(messageBuffer));
}
return hashedString;
}
private string GenerateStringToSign(string canonicalizedHeaders, string canonicalizedResource, string contentLength = "")
{
var stringToSign = "PUT" + "\n" +
"\n" +
"\n" +
(string.IsNullOrEmpty(contentLength) ? string.Empty : contentLength) + "\n" +
"\n" +
"\n" +
"\n" +
"\n" +
"\n" +
"\n" +
"\n" +
"\n" +
canonicalizedHeaders +
canonicalizedResource;
return stringToSign;
}
}
public class AzureStorageUploaderService : FileUploaderService
{
public override FileDestination EnumValue { get; } = FileDestination.AzureStorage;
public override Image ServiceImage => Resources.AzureStorage;
public override bool CheckConfig(UploadersConfig config)
{
return !string.IsNullOrEmpty(config.AzureStorageAccountName) &&
!string.IsNullOrEmpty(config.AzureStorageAccountAccessKey) &&
!string.IsNullOrEmpty(config.AzureStorageContainer);
}
public override GenericUploader CreateUploader(UploadersConfig config, TaskReferenceHelper taskInfo)
{
return new AzureStorage(config.AzureStorageAccountName, config.AzureStorageAccountAccessKey, config.AzureStorageContainer);
}
public override TabPage GetUploadersConfigTabPage(UploadersConfigForm form) => form.tpAzureStorage;
}
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ShareX.UploadersLib.FileUploaders
{
public class AzureStorageSettings
{
public string AccountName { get; set; }
public string AccessKey { get; set; }
public string Container { get; set; }
}
}
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.