public B2StorageProvider(IConfiguration config, ILogger <B2StorageProvider> logger) { _b2Options = new B2Options() { AccountId = config["Auth:B2:AccountId"], KeyId = config["Auth:B2:KeyId"], ApplicationKey = config["Auth:B2:AppKey"], BucketId = config["Auth:B2:BucketId"], PersistBucket = true }; // if backblaze isn't fully configured if (string.IsNullOrEmpty(_b2Options.AccountId) || string.IsNullOrEmpty(_b2Options.KeyId) || string.IsNullOrEmpty(_b2Options.ApplicationKey) || string.IsNullOrEmpty(_b2Options.BucketId)) { throw new InvalidOperationException("Backblaze not fully configured."); } _client = new B2Client(B2Client.Authorize(_b2Options)); _logger = logger; _bucketName = _client.Buckets.GetList().Result .Single(b => b.BucketId == _b2Options.BucketId) .BucketName; }
public static HttpRequestMessage GetDownloadAuthorization(B2Options options, string fileNamePrefix, int validDurationInSeconds, string bucketId, string b2ContentDisposition = "") { var uri = new Uri(options.ApiUrl + "/b2api/" + Constants.Version + "/" + Endpoints.GetDownloadAuthorization); var body = "{\"bucketId\":" + JsonConvert.ToString(bucketId) + ", \"fileNamePrefix\":" + JsonConvert.ToString(fileNamePrefix) + ", \"validDurationInSeconds\":" + JsonConvert.ToString(validDurationInSeconds); if (!string.IsNullOrEmpty(b2ContentDisposition)) { body += ", \"b2ContentDisposition\":" + JsonConvert.ToString(b2ContentDisposition); } body += "}"; var request = new HttpRequestMessage() { Method = HttpMethod.Post, RequestUri = uri, Content = new StringContent(body) }; request.Headers.TryAddWithoutValidation("Authorization", options.AuthorizationToken); return(request); }
public static HttpRequestMessage CopyPart(B2Options options, string sourceFileId, string destinationLargeFileId, int destinationPartNumber, string range = "") { var uri = new Uri(options.ApiUrl + "/b2api/" + Constants.Version + "/" + Endpoints.CopyPart); var payload = new Dictionary <string, string>() { { "sourceFileId", sourceFileId }, { "largeFileId", destinationLargeFileId }, { "partNumber", destinationPartNumber.ToString() }, }; if (!string.IsNullOrWhiteSpace(range)) { payload.Add("range", range); } var content = JsonConvert.SerializeObject(payload); var request = new HttpRequestMessage() { Method = HttpMethod.Post, RequestUri = uri, Content = new StringContent(content), }; request.Headers.TryAddWithoutValidation("Authorization", options.AuthorizationToken); request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); request.Content.Headers.ContentLength = content.Length; return(request); }
/// <summary> /// Upload a file to B2. This method will calculate the SHA1 checksum before sending any data. /// </summary> /// <param name="options"></param> /// <param name="uploadUrl"></param> /// <param name="fileData"></param> /// <param name="fileName"></param> /// <param name="fileInfo"></param> /// <returns></returns> public static HttpRequestMessage Upload(B2Options options, byte[] fileData, int partNumber, B2UploadPartUrl uploadPartUrl) { if (partNumber < 1 || partNumber > 10000) { throw new Exception("Part number must be between 1 and 10,000"); } var uri = new Uri(uploadPartUrl.UploadUrl); var request = new HttpRequestMessage() { Method = HttpMethod.Post, RequestUri = uri, Content = new ByteArrayContent(fileData) }; // Get the file checksum string hash = Utilities.GetSHA1Hash(fileData); // Add headers request.Headers.Add("Authorization", uploadPartUrl.AuthorizationToken); request.Headers.Add("X-Bz-Part-Number", partNumber.ToString()); request.Headers.Add("X-Bz-Content-Sha1", hash); request.Content.Headers.ContentLength = fileData.Length; return(request); }
/// <summary> /// Upload a file to B2. This method will calculate the SHA1 checksum before sending any data. /// </summary> /// <param name="options"></param> /// <param name="uploadUrl"></param> /// <param name="fileData"></param> /// <param name="fileName"></param> /// <param name="fileInfo"></param> /// <returns></returns> public static HttpRequestMessage Upload(B2Options options, string uploadUrl, byte[] fileData, string fileName, Dictionary <string, string> fileInfo) { var uri = new Uri(uploadUrl); var request = new HttpRequestMessage() { Method = HttpMethod.Post, RequestUri = uri, Content = new ByteArrayContent(fileData) }; // Get the file checksum string hash = Utilities.GetSHA1Hash(fileData); // Add headers request.Headers.Add("Authorization", options.UploadAuthorizationToken); request.Headers.Add("X-Bz-File-Name", fileName.b2UrlEncode()); request.Headers.Add("X-Bz-Content-Sha1", hash); // File Info headers if (fileInfo != null && fileInfo.Count > 0) { foreach (var info in fileInfo.Take(10)) { request.Headers.Add($"X-Bz-Info-{info.Key}", info.Value); } } // TODO last modified //request.Headers.Add("X-Bz-src_last_modified_millis", hash); request.Content.Headers.ContentType = new MediaTypeHeaderValue("b2/x-auto"); request.Content.Headers.ContentLength = fileData.Length; return(request); }
/// <summary> /// Used to modify the bucket type of the provided bucket. /// </summary> /// <param name="options"></param> /// <returns></returns> public static HttpRequestMessage UpdateBucket(B2Options options, string bucketId, string bucketType) { var body = "{\"accountId\":\"" + options.AccountId + "\", \"bucketId\":\"" + bucketId + "\", \"bucketType\":\"" + bucketType + "\"}"; return(BaseRequestGenerator.PostRequest(Endpoints.Update, body, options)); }
/// <summary> /// Upload a file to B2 using a stream. NOTE: You MUST provide the SHA1 at the end of your stream. This method will NOT do it for you. /// </summary> /// <param name="options"></param> /// <param name="uploadUrl"></param> /// <param name="fileData"></param> /// <param name="fileName"></param> /// <param name="fileInfo"></param> /// <returns></returns> public static HttpRequestMessage Upload(B2Options options, string uploadUrl, Stream fileDataWithSHA, string fileName, Dictionary <string, string> fileInfo, string contentType = "", bool dontSHA = false) { var uri = new Uri(uploadUrl); var request = new HttpRequestMessage() { Method = HttpMethod.Post, RequestUri = uri, Content = new StreamContent(fileDataWithSHA) }; // Add headers request.Headers.TryAddWithoutValidation("Authorization", options.UploadAuthorizationToken); request.Headers.Add("X-Bz-File-Name", fileName.b2UrlEncode()); // Stream puts the SHA1 at the end of the content request.Headers.Add("X-Bz-Content-Sha1", dontSHA ? "do_not_verify" : "hex_digits_at_end"); // File Info headers if (fileInfo != null && fileInfo.Count > 0) { foreach (var info in fileInfo.Take(10)) { request.Headers.Add($"X-Bz-Info-{info.Key}", info.Value); } } // TODO last modified //request.Headers.Add("X-Bz-src_last_modified_millis", hash); request.Content.Headers.ContentType = new MediaTypeHeaderValue(string.IsNullOrWhiteSpace(contentType) ? "b2/x-auto" : contentType); // SHA will be in Stream already request.Content.Headers.ContentLength = fileDataWithSHA.Length; return(request); }
public static HttpRequestMessage ListVersions(B2Options options, string bucketId, string startFileName = "", string startFileId = "", int?maxFileCount = null, string prefix = "", string delimiter = "") { var body = "{\"bucketId\":\"" + bucketId + "\""; if (!string.IsNullOrEmpty(startFileName)) { body += ", \"startFileName\":" + JsonConvert.ToString(startFileName); } if (!string.IsNullOrEmpty(startFileId)) { body += ", \"startFileId\":\"" + startFileId + "\""; } if (maxFileCount.HasValue) { body += ", \"maxFileCount\":" + maxFileCount.Value.ToString(); } if (!string.IsNullOrEmpty(prefix)) { body += ", \"prefix\":" + JsonConvert.ToString(prefix); } if (!string.IsNullOrEmpty(delimiter)) { body += ", \"delimiter\":" + JsonConvert.ToString(delimiter); } body += "}"; return(BaseRequestGenerator.PostRequest(Endpoints.Versions, body, options)); }
public static HttpRequestMessage Cancel(B2Options options, string fileId) { var content = JsonConvert.SerializeObject(new { fileId }); var request = BaseRequestGenerator.PostRequestJson(Endpoints.Cancel, content, options); return(request); }
public static HttpRequestMessage Finish(B2Options options, string fileId, string[] partSHA1Array) { var content = JsonConvert.SerializeObject(new { fileId, partSha1Array = partSHA1Array }); var request = BaseRequestGenerator.PostRequestJson(Endpoints.Finish, content, options); return(request); }
public B2Client(B2Options options) { _options = options; Buckets = new Buckets(options); Files = new Files(options); LargeFiles = new LargeFiles(options); }
public static HttpRequestMessage Start(B2Options options, string bucketId, string fileName, string contentType, Dictionary <string, string> fileInfo = null) { var uri = new Uri(options.ApiUrl + "/b2api/" + Constants.Version + "/" + Endpoints.Start); var content = "{\"bucketId\":\"" + bucketId + "\",\"fileName\":\"" + fileName + "\",\"contentType\":\"" + (string.IsNullOrEmpty(contentType) ? "b2/x-auto" : contentType) + "\"}"; var request = new HttpRequestMessage() { Method = HttpMethod.Post, RequestUri = uri, Content = new StringContent(content), }; request.Headers.Add("Authorization", options.AuthorizationToken); // File Info headers if (fileInfo != null && fileInfo.Count > 0) { foreach (var info in fileInfo.Take(10)) { request.Headers.Add($"X-Bz-Info-{info.Key}", info.Value); } } request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); request.Content.Headers.ContentLength = content.Length; return(request); }
/// <summary> /// Requires that AccountId and ApplicationKey on the options object be set. If you are using an application key you must specify the accountId, the keyId, and the applicationKey. /// </summary> /// <param name="options"></param> /// <returns></returns> public static B2Options Authorize(B2Options options) { // Return if already authenticated. if (options.Authenticated) { return(options); } var client = HttpClientFactory.CreateHttpClient(options.RequestTimeout); var requestMessage = AuthRequestGenerator.Authorize(options); var response = client.SendAsync(requestMessage).Result; var jsonResponse = response.Content.ReadAsStringAsync().Result; if (response.IsSuccessStatusCode) { var authResponse = JsonConvert.DeserializeObject <B2AuthResponse>(jsonResponse); options.SetState(authResponse); } else if (response.StatusCode == HttpStatusCode.Unauthorized) { // Return a better exception because of confusing Keys api. throw new AuthorizationException("If you are using an Application key and not a Master key, make sure that you are supplying the Key ID and Key Value for that Application Key. Do not mix your Account ID with your Application Key."); } else { throw new AuthorizationException(jsonResponse); } return(options); }
/// <summary> /// Create a bucket. Defaults to allPrivate. /// </summary> /// <param name="options"></param> /// <param name="bucketName"></param> /// <param name="bucketType"></param> /// <returns></returns> public static HttpRequestMessage CreateBucket(B2Options options, string bucketName, B2BucketOptions bucketOptions) { // Check lifecycle rules var hasLifecycleRules = bucketOptions.LifecycleRules != null && bucketOptions.LifecycleRules.Count > 0; if (hasLifecycleRules) { foreach (var rule in bucketOptions.LifecycleRules) { if (rule.DaysFromHidingToDeleting < 1 || rule.DaysFromUploadingToHiding < 1) { throw new System.Exception("The smallest number of days you can set in a lifecycle rule is 1."); } if (rule.DaysFromHidingToDeleting == null && rule.DaysFromUploadingToHiding == null) { throw new System.Exception("You must set either DaysFromHidingToDeleting or DaysFromUploadingToHiding. Both cannot be null."); } } } var allowed = new Regex("^[a-zA-Z0-9-]+$"); if (bucketName.Length < 6 || bucketName.Length > 50 || !allowed.IsMatch(bucketName) || bucketName.StartsWith("b2-")) { throw new Exception(@"The bucket name specified does not match the requirements. Bucket Name can consist of upper-case letters, lower-case letters, numbers, and "" - "", must be at least 6 characters long, and can be at most 50 characters long"); } var body = new B2BucketCreateModel() { accountId = options.AccountId, bucketName = bucketName, bucketType = bucketOptions.BucketType.ToString() }; // Add optional options if (bucketOptions.CacheControl != 0) { body.bucketInfo = new Dictionary <string, string>() { { "Cache-Control", "max-age=" + bucketOptions.CacheControl } }; } if (hasLifecycleRules) { body.lifecycleRules = bucketOptions.LifecycleRules; } // Has cors rules if (bucketOptions.CORSRules != null && bucketOptions.CORSRules.Count > 0) { body.corsRules = bucketOptions.CORSRules; } var json = JsonSerialize(body); return(BaseRequestGenerator.PostRequest(Endpoints.Create, json, options)); }
/// <summary> /// Only call this method if you created a B2Client with authorizeOnInitalize = false. This method of using B2.NET is considered in Beta, as it has not been extensively tested. /// </summary> /// <returns></returns> public async Task Initialize() { _options = Authorize(_options); Buckets = new Buckets(_options); Files = new Files(_options); LargeFiles = new LargeFiles(_options); _capabilities = _options.Capabilities; }
/// <summary> /// Create a bucket. Defaults to allPrivate. /// </summary> /// <param name="options"></param> /// <param name="bucketName"></param> /// <param name="bucketType"></param> /// <returns></returns> public static HttpRequestMessage CreateBucket(B2Options options, string bucketName, string bucketType = "allPrivate") { // TODO: Handle naming conventions, check name for invalid characters. var body = "{\"accountId\":\"" + options.AccountId + "\", \"bucketName\":\"" + bucketName + "\", \"bucketType\":\"" + bucketType + "\"}"; return(BaseRequestGenerator.PostRequest(Endpoints.Create, body, options)); }
public B2Client(B2Options options) { _options = Authorize(options); Buckets = new Buckets(options); Files = new Files(options); LargeFiles = new LargeFiles(options); _capabilities = options.Capabilities; }
public BaseTest() { Options = new B2Options() { KeyId = TestConstants.KeyId, ApplicationKey = TestConstants.ApplicationKey }; }
public BaseTest() { Options = new B2Options() { AccountId = TestConstants.AccountId, ApplicationKey = TestConstants.ApplicationKey, BucketId = TestConstants.BucketId }; }
public static string DetermineBucketId(B2Options options, string bucketId) { // Check for a persistant bucket if (!options.PersistBucket && string.IsNullOrEmpty(bucketId)) { throw new ArgumentNullException(nameof(bucketId)); } // Are we persisting buckets? If so use the one from settings return(options.PersistBucket ? options.BucketId : bucketId); }
public static HttpRequestMessage ListParts(B2Options options, string fileId, int startPartNumber, int maxPartCount) { if (startPartNumber < 1 || startPartNumber > 10000) { throw new Exception("Start part number must be between 1 and 10,000"); } var content = JsonConvert.SerializeObject(new { fileId, startPartNumber, maxPartCount }); var request = BaseRequestGenerator.PostRequestJson(Endpoints.ListParts, content, options); return(request); }
public static HttpRequestMessage DownloadByName(B2Options options, string bucketName, string fileName) { var uri = new Uri(options.DownloadUrl + "/" + Endpoints.DownloadByName + "/" + bucketName + "/" + fileName.b2UrlEncode()); var request = new HttpRequestMessage() { Method = HttpMethod.Get, RequestUri = uri }; request.Headers.Add("Authorization", options.AuthorizationToken); return(request); }
public static HttpRequestMessage Authorize(B2Options options) { var uri = new Uri(Constants.ApiBaseUrl + "/" + Constants.Version + "/" + Endpoints.Auth); var request = new HttpRequestMessage() { Method = HttpMethod.Get, RequestUri = uri }; request.Headers.Add("Authorization", Utilities.CreateAuthorizationHeader(options.AccountId, options.ApplicationKey)); return(request); }
public static HttpRequestMessage DownloadById(B2Options options, string fileId) { var uri = new Uri(options.DownloadUrl + "/b2api/" + Constants.Version + "/" + Endpoints.DownloadById); var request = new HttpRequestMessage() { Method = HttpMethod.Post, RequestUri = uri, Content = new StringContent("{\"fileId\":\"" + fileId + "\"}") }; request.Headers.Add("Authorization", options.AuthorizationToken); return(request); }
public static HttpRequestMessage PostRequest(string endpoint, string body, B2Options options) { var uri = new Uri(options.ApiUrl + "/b2api/" + Constants.Version + "/" + endpoint); var request = new HttpRequestMessage() { Method = HttpMethod.Post, RequestUri = uri, Content = new StringContent(body) }; request.Headers.Add("Authorization", options.AuthorizationToken); return(request); }
/// <summary> /// Simple method for instantiating the B2Client. Does auth for you. /// </summary> /// <param name="accountId"></param> /// <param name="applicationkey"></param> /// <param name="requestTimeout"></param> public B2Client(string accountId, string applicationkey, int requestTimeout = 100) { _options = new B2Options() { AccountId = accountId, ApplicationKey = applicationkey, RequestTimeout = requestTimeout }; _options = Authorize(_options); Buckets = new Buckets(_options); Files = new Files(_options); LargeFiles = new LargeFiles(_options); }
public static HttpRequestMessage Copy(B2Options options, string sourceFileId, string fileName, B2MetadataDirective metadataDirective, string contentType = "", Dictionary <string, string> fileInfo = null, string range = "", string destinationBucketId = "") { var uri = new Uri(options.ApiUrl + "/b2api/" + Constants.Version + "/" + Endpoints.Copy); var payload = new Dictionary <string, object>() { { "sourceFileId", sourceFileId }, { "fileName", fileName }, { "metadataDirective", metadataDirective.ToString() }, }; if (!string.IsNullOrWhiteSpace(range)) { payload.Add("range", range); } if (!string.IsNullOrWhiteSpace(destinationBucketId)) { payload.Add("destinationBucketId", destinationBucketId); } if (metadataDirective == B2MetadataDirective.REPLACE) { if (string.IsNullOrWhiteSpace(contentType)) { payload.Add("contentType", "b2/x-auto"); } else { payload.Add("contentType", contentType); } } // File Info if (metadataDirective == B2MetadataDirective.REPLACE && fileInfo != null && fileInfo.Count > 0) { payload.Add("fileInfo", fileInfo); } var json = JsonConvert.SerializeObject(payload); var request = new HttpRequestMessage() { Method = HttpMethod.Post, RequestUri = uri, Content = new StringContent(json) }; request.Headers.TryAddWithoutValidation("Authorization", options.AuthorizationToken); return(request); }
public static HttpRequestMessage HideFile(B2Options options, string bucketId, string fileName = "", string fileId = "") { var body = "{\"bucketId\":\"" + bucketId + "\""; if (!string.IsNullOrEmpty(fileName) && string.IsNullOrEmpty(fileId)) { body += ", \"fileName\":" + JsonConvert.ToString(fileName); } if (!string.IsNullOrEmpty(fileId)) { body += ", \"fileId\":\"" + fileId + "\""; } body += "}"; return(BaseRequestGenerator.PostRequest(Endpoints.Hide, body, options)); }
public static HttpRequestMessage GetList(B2Options options, string bucketId, string startFileName = "", int?maxFileCount = null) { var body = "{\"bucketId\":\"" + bucketId + "\""; if (!string.IsNullOrEmpty(startFileName)) { body += ", \"startFileName\":" + JsonConvert.ToString(startFileName); } if (maxFileCount.HasValue) { body += ", \"maxFileCount\":" + maxFileCount.Value.ToString(); } body += "}"; return(BaseRequestGenerator.PostRequest(Endpoints.List, body, options)); }
/// <summary> /// Create a bucket. Defaults to allPrivate. /// </summary> /// <param name="options"></param> /// <param name="bucketName"></param> /// <param name="bucketType"></param> /// <returns></returns> public static HttpRequestMessage CreateBucket(B2Options options, string bucketName, string bucketType = "allPrivate") { var allowed = new Regex("^[a-zA-Z0-9-]+$"); if (bucketName.Length < 6 || bucketName.Length > 50 || !allowed.IsMatch(bucketName) || bucketName.StartsWith("b2-")) { throw new Exception(@"The bucket name specified does not match the requirements. Bucket Name can consist of upper-case letters, lower-case letters, numbers, and "" - "", must be at least 6 characters long, and can be at most 50 characters long"); } var json = JsonConvert.SerializeObject(new { accountId = options.AccountId, bucketName, bucketType }); return(BaseRequestGenerator.PostRequest(Endpoints.Create, json, options)); }