public override UploadResult Upload(Stream stream, string fileName) { Dictionary <string, string> args = new Dictionary <string, string>(); args.Add("api_key", API_Key); args.Add("auth_token", Auth.Token); if (!string.IsNullOrEmpty(Settings.Title)) { args.Add("title", Settings.Title); } if (!string.IsNullOrEmpty(Settings.Description)) { args.Add("description", Settings.Description); } if (!string.IsNullOrEmpty(Settings.Tags)) { args.Add("tags", Settings.Tags); } if (!string.IsNullOrEmpty(Settings.IsPublic)) { args.Add("is_public", Settings.IsPublic); } if (!string.IsNullOrEmpty(Settings.IsFriend)) { args.Add("is_friend", Settings.IsFriend); } if (!string.IsNullOrEmpty(Settings.IsFamily)) { args.Add("is_family", Settings.IsFamily); } if (!string.IsNullOrEmpty(Settings.SafetyLevel)) { args.Add("safety_level", Settings.SafetyLevel); } if (!string.IsNullOrEmpty(Settings.ContentType)) { args.Add("content_type", Settings.ContentType); } if (!string.IsNullOrEmpty(Settings.Hidden)) { args.Add("hidden", Settings.Hidden); } args.Add("api_sig", GetAPISig(args)); UploadResult result = UploadData(stream, "https://up.flickr.com/services/upload/", fileName, "photo", args); if (result.IsSuccess) { XElement xele = ParseResponse(result.Response, "photoid"); if (null != xele) { string photoid = xele.Value; string url = URLHelpers.CombineURL(GetPhotosLink(), photoid); result.URL = URLHelpers.CombineURL(url, "sizes/o"); } } return(result); }
public override UploadResult Upload(Stream stream, string fileName) { if (string.IsNullOrEmpty(Host)) { throw new Exception("ownCloud Host is empty."); } if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password)) { throw new Exception("ownCloud Username or Password is empty."); } if (string.IsNullOrEmpty(Path)) { Path = "/"; } // Original, unencoded path. Necessary for shared files string path = URLHelpers.CombineURL(Path, fileName); // Encoded path, necessary when sent in the URL string encodedPath = URLHelpers.CombineURL(Path, URLHelpers.URLEncode(fileName)); string url = URLHelpers.CombineURL(Host, "remote.php/webdav", encodedPath); url = URLHelpers.FixPrefix(url); NameValueCollection headers = CreateAuthenticationHeader(Username, Password); SSLBypassHelper sslBypassHelper = null; try { if (IgnoreInvalidCert) { sslBypassHelper = new SSLBypassHelper(); } string response = SendRequestStream(url, stream, Helpers.GetMimeType(fileName), headers, method: HttpMethod.PUT); UploadResult result = new UploadResult(response); if (!IsError) { if (CreateShare) { AllowReportProgress = false; result.URL = ShareFile(path); } else { result.IsURLExpected = false; } } return(result); } finally { if (sslBypassHelper != null) { sslBypassHelper.Dispose(); } } }
public string GetPhotosLink(string userID) { return(URLHelpers.CombineURL("https://www.flickr.com/photos", userID)); }
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(); string date = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture); string targetPath = GetUploadPath(fileName); string url; if (AzureStorageContainer == "$root") { url = $"https://{AzureStorageAccountName}.{AzureStorageEnvironment}/{targetPath}"; } else { url = $"https://{AzureStorageAccountName}.{AzureStorageEnvironment}/{AzureStorageContainer}/{targetPath}"; } string contentType = Helpers.GetMimeType(fileName); NameValueCollection requestHeaders = new NameValueCollection(); requestHeaders["x-ms-date"] = date; requestHeaders["x-ms-version"] = APIVersion; requestHeaders["x-ms-blob-type"] = "BlockBlob"; string canonicalizedHeaders = $"x-ms-blob-type:BlockBlob\nx-ms-date:{date}\nx-ms-version:{APIVersion}\n"; string canonicalizedResource; if (AzureStorageContainer == "$root") { canonicalizedResource = $"/{AzureStorageAccountName}/{targetPath}"; } else { canonicalizedResource = $"/{AzureStorageAccountName}/{AzureStorageContainer}/{targetPath}"; } string stringToSign = GenerateStringToSign(canonicalizedHeaders, canonicalizedResource, stream.Length.ToString(), contentType); requestHeaders["Authorization"] = $"SharedKey {AzureStorageAccountName}:{stringToSign}"; using (HttpWebResponse response = GetResponse(HttpMethod.PUT, url, stream, contentType, null, requestHeaders, null)) { if (response != null && response.Headers != null) { string result; if (!string.IsNullOrEmpty(AzureStorageCustomDomain)) { if (AzureStorageExcludeContainer) { result = URLHelpers.CombineURL(AzureStorageCustomDomain, targetPath); } else { result = URLHelpers.CombineURL(AzureStorageCustomDomain, AzureStorageContainer, targetPath); } result = URLHelpers.FixPrefix(result); } else { result = url; } return(new UploadResult { IsSuccess = true, URL = result }); } } Errors.Add("Upload failed."); return(null); }
public override UploadResult Upload(Stream stream, string fileName) { string host = $"{Settings.Bucket}.s3.{Settings.Endpoint}.amazonaws.com"; string algorithm = "AWS4-HMAC-SHA256"; string credentialDate = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture); string scope = $"{credentialDate}/{Settings.Endpoint}/s3/aws4_request"; string credential = $"{Settings.AccessKeyID}/{scope}"; string longDate = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture); string expiresTotalSeconds = ((long)TimeSpan.FromHours(1).TotalSeconds).ToString(); string contentType = Helpers.GetMimeType(fileName); NameValueCollection headers = new NameValueCollection(); headers["content-type"] = contentType; headers["host"] = host; headers["x-amz-acl"] = "public-read"; headers["x-amz-storage-class"] = Settings.UseReducedRedundancyStorage ? "REDUCED_REDUNDANCY" : "STANDARD"; string signedHeaders = GetSignedHeaders(headers); Dictionary <string, string> args = new Dictionary <string, string>(); args.Add("X-Amz-Algorithm", algorithm); args.Add("X-Amz-Credential", credential); args.Add("X-Amz-Date", longDate); args.Add("X-Amz-Expires", expiresTotalSeconds); args.Add("X-Amz-SignedHeaders", signedHeaders); string uploadPath = GetUploadPath(fileName); string canonicalURI = URLHelpers.AddSlash(uploadPath, SlashType.Prefix); canonicalURI = URLHelpers.URLPathEncode(canonicalURI); string canonicalQueryString = CreateQueryString(args); string canonicalHeaders = CreateCanonicalHeaders(headers); string canonicalRequest = "PUT" + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + "UNSIGNED-PAYLOAD"; string stringToSign = algorithm + "\n" + longDate + "\n" + scope + "\n" + BytesToHex(ComputeHash(canonicalRequest)); byte[] secretKey = Encoding.UTF8.GetBytes("AWS4" + Settings.SecretAccessKey); byte[] dateKey = ComputeHMAC(Encoding.UTF8.GetBytes(credentialDate), secretKey); byte[] dateRegionKey = ComputeHMAC(Encoding.UTF8.GetBytes(Settings.Endpoint), dateKey); byte[] dateRegionServiceKey = ComputeHMAC(Encoding.UTF8.GetBytes("s3"), dateRegionKey); byte[] signingKey = ComputeHMAC(Encoding.UTF8.GetBytes("aws4_request"), dateRegionServiceKey); string signature = BytesToHex(ComputeHMAC(Encoding.UTF8.GetBytes(stringToSign), signingKey)); args.Add("X-Amz-Signature", signature); headers.Remove("content-type"); headers.Remove("host"); string url = URLHelpers.CombineURL(host, canonicalURI) + "?" + CreateQueryString(args); url = URLHelpers.ForcePrefix(url, "https://"); NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, url, stream, contentType, null, headers); if (responseHeaders == null || responseHeaders.Count == 0) { Errors.Add("Upload to Amazon S3 failed. Check your access credentials."); return(null); } if (responseHeaders["ETag"] == null) { Errors.Add("Upload to Amazon S3 failed."); return(null); } return(new UploadResult { IsSuccess = true, URL = GenerateURL(fileName) }); }
private string GetUploadPath(string fileName) { string path = NameParser.Parse(NameParserType.FolderPath, Settings.ObjectPrefix.Trim('/')); return(URLHelpers.CombineURL(path, fileName)); }
// https://doc.owncloud.org/server/10.0/developer_manual/core/ocs-share-api.html#create-a-new-share public string ShareFile(string path) { Dictionary <string, string> args = new Dictionary <string, string>(); args.Add("path", path); // path to the file/folder which should be shared args.Add("shareType", "3"); // ‘0’ = user; ‘1’ = group; ‘3’ = public link // args.Add("shareWith", ""); // user / group id with which the file should be shared // args.Add("publicUpload", "false"); // allow public upload to a public shared folder (true/false) // args.Add("password", ""); // password to protect public link Share with args.Add("permissions", "1"); // 1 = read; 2 = update; 4 = create; 8 = delete; 16 = share; 31 = all (default: 31, for public shares: 1) if (AutoExpire) { if (AutoExpireTime == 0) { throw new Exception("ownCloud Auto Epxire Time is not valid."); } else { try { DateTime expireTime = DateTime.UtcNow.AddDays(AutoExpireTime); args.Add("expireDate", $"{expireTime.Year}-{expireTime.Month}-{expireTime.Day}"); } catch { throw new Exception("ownCloud Auto Expire time is invalid"); } } } string url = URLHelpers.CombineURL(Host, "ocs/v1.php/apps/files_sharing/api/v1/shares?format=json"); url = URLHelpers.FixPrefix(url); NameValueCollection headers = CreateAuthenticationHeader(Username, Password); headers["OCS-APIREQUEST"] = "true"; string response = SendRequestMultiPart(url, args, headers); if (!string.IsNullOrEmpty(response)) { OwnCloudShareResponse result = JsonConvert.DeserializeObject <OwnCloudShareResponse>(response); if (result != null && result.ocs != null && result.ocs.meta != null) { if (result.ocs.data != null && result.ocs.meta.statuscode == 100) { OwnCloudShareResponseData data = ((JObject)result.ocs.data).ToObject <OwnCloudShareResponseData>(); string link = data.url; if (PreviewLink) { link += Helpers.IsImageFile(path) ? "/preview" : "/download"; } else if (DirectLink) { link += (IsCompatibility81 ? "/" : "&") + "download"; } return(link); } else { Errors.Add(string.Format("Status: {0}\r\nStatus code: {1}\r\nMessage: {2}", result.ocs.meta.status, result.ocs.meta.statuscode, result.ocs.meta.message)); } } } return(null); }
public string GetSubFolderPath(string filename = null, NameParserType nameParserType = NameParserType.URL) { string path = NameParser.Parse(nameParserType, SubFolderPath.Replace("%host", Host)); return(URLHelpers.CombineURL(path, filename)); }
public string GetUriPath(string filename, string subFolderPath = null) { if (string.IsNullOrEmpty(Host)) { return(string.Empty); } if (HttpHomePathNoExtension) { filename = Path.GetFileNameWithoutExtension(filename); } filename = URLHelpers.URLEncode(filename); if (subFolderPath == null) { subFolderPath = GetSubFolderPath(); } UriBuilder httpHomeUri; var httpHomePath = GetHttpHomePath(); if (string.IsNullOrEmpty(httpHomePath)) { var host = Host; if (host.StartsWith("ftp.")) { host = host.Substring(4); } httpHomeUri = new UriBuilder(URLHelpers.CombineURL(host, subFolderPath, filename)); httpHomeUri.Port = -1; //Since httpHomePath is not set, it's safe to erase UriBuilder's assumed port number } else { //Parse HttpHomePath in to host, port, path and query components var firstSlash = httpHomePath.IndexOf('/'); var httpHome = firstSlash >= 0 ? httpHomePath.Substring(0, firstSlash) : httpHomePath; var portSpecifiedAt = httpHome.LastIndexOf(':'); var httpHomeHost = portSpecifiedAt >= 0 ? httpHome.Substring(0, portSpecifiedAt) : httpHome; var httpHomePort = -1; var httpHomePathAndQuery = firstSlash >= 0 ? httpHomePath.Substring(firstSlash + 1) : ""; var querySpecifiedAt = httpHomePathAndQuery.LastIndexOf('?'); var httpHomeDir = querySpecifiedAt >= 0 ? httpHomePathAndQuery.Substring(0, querySpecifiedAt) : httpHomePathAndQuery; var httpHomeQuery = querySpecifiedAt >= 0 ? httpHomePathAndQuery.Substring(querySpecifiedAt + 1) : ""; if (portSpecifiedAt >= 0) { int.TryParse(httpHome.Substring(portSpecifiedAt + 1), out httpHomePort); } //Build URI httpHomeUri = new UriBuilder { Host = httpHomeHost, Path = httpHomeDir, Query = httpHomeQuery }; if (portSpecifiedAt >= 0) { httpHomeUri.Port = httpHomePort; } if (httpHomeUri.Query.EndsWith("=")) { //Setting URIBuilder.Query automatically prepends a ? so we must trim it first. if (HttpHomePathAutoAddSubFolderPath) { httpHomeUri.Query = URLHelpers.CombineURL(httpHomeUri.Query.Substring(1), subFolderPath, filename); } else { httpHomeUri.Query = httpHomeUri.Query.Substring(1) + filename; } } else { if (HttpHomePathAutoAddSubFolderPath) { httpHomeUri.Path = URLHelpers.CombineURL(httpHomeUri.Path, subFolderPath); } httpHomeUri.Path = URLHelpers.CombineURL(httpHomeUri.Path, filename); } } httpHomeUri.Scheme = BrowserProtocol.GetDescription(); return(httpHomeUri.Uri.AbsoluteUri); }
private void TranscodeFile(UploadResult result) { StreamableTranscodeResponse transcodeResponse = JsonConvert.DeserializeObject <StreamableTranscodeResponse>(result.Response); if (!string.IsNullOrEmpty(transcodeResponse.Shortcode)) { ProgressManager progress = new ProgressManager(100); if (AllowReportProgress) { OnProgressChanged(progress); } while (!StopUploadRequested) { string statusJson = SendRequest(HttpMethod.GET, URLHelpers.CombineURL(Host, "videos", transcodeResponse.Shortcode)); StreamableStatusResponse response = JsonConvert.DeserializeObject <StreamableStatusResponse>(statusJson); if (response.status > 2) { Errors.Add(response.message); result.IsSuccess = false; break; } else if (response.status == 2) { if (AllowReportProgress) { long delta = 100 - progress.Position; progress.UpdateProgress(delta); OnProgressChanged(progress); } result.IsSuccess = true; if (UseDirectURL && response.files != null && response.files.mp4 != null && !string.IsNullOrEmpty(response.files.mp4.url)) { result.URL = URLHelpers.ForcePrefix(response.files.mp4.url); } else { result.URL = URLHelpers.ForcePrefix(response.url); } break; } if (AllowReportProgress) { long delta = response.percent - progress.Position; progress.UpdateProgress(delta); OnProgressChanged(progress); } Thread.Sleep(1000); } } else { Errors.Add("Could not create video"); result.IsSuccess = false; } }
public override UploadResult Upload(Stream stream, string fileName) { if (string.IsNullOrEmpty(APIURL)) { throw new Exception("Seafile API URL is empty."); } if (string.IsNullOrEmpty(AuthToken)) { throw new Exception("Seafile Authentication Token is empty."); } if (string.IsNullOrEmpty(Path)) { Path = "/"; } else { char pathLast = Path[Path.Length - 1]; if (pathLast != '/') { Path += "/"; } } string url = URLHelpers.FixPrefix(APIURL); url = URLHelpers.CombineURL(APIURL, "repos/" + RepoID + "/upload-link/?format=json"); NameValueCollection headers = new NameValueCollection(); headers.Add("Authorization", "Token " + AuthToken); SSLBypassHelper sslBypassHelper = null; try { if (IgnoreInvalidCert) { sslBypassHelper = new SSLBypassHelper(); } string response = SendRequest(HttpMethod.GET, url, null, headers); string responseURL = response.Trim('"'); Dictionary <string, string> args = new Dictionary <string, string>(); args.Add("filename", fileName); args.Add("parent_dir", Path); UploadResult result = UploadData(stream, responseURL, fileName, "file", args, headers); if (!IsError) { if (CreateShareableURL && !IsLibraryEncrypted) { AllowReportProgress = false; result.URL = ShareFile(Path + fileName); } else { result.IsURLExpected = false; } } return(result); } finally { if (sslBypassHelper != null) { sslBypassHelper.Dispose(); } } }
private string GetEndpoint() { return(URLHelpers.ForcePrefix(URLHelpers.CombineURL(GetCurrentRegion(s3Settings).Hostname, s3Settings.Bucket))); }
private string GetEndpoint() { return(URLHelpers.CombineURL("https://" + GetCurrentRegion(s3Settings).Hostname, s3Settings.Bucket)); }
public override UploadResult Upload(Stream stream, string fileName) { WebExceptionThrow = true; string hash = CreateHash(stream); UploadResult result = CheckExists(hash); if (result != null) { return(result); } try { result = SendRequestFile(URLHelpers.CombineURL(APIURL, "api/upload/file"), stream, fileName); } catch (WebException e) { HttpWebResponse response = e.Response as HttpWebResponse; if (response == null) { throw; } if (response.StatusCode == HttpStatusCode.Conflict) { return(HandleDuplicate(response)); } throw; } hash = JToken.Parse(result.Response)["hash"].Value <string>(); while (!StopUploadRequested) { result.Response = SendRequest(HttpMethod.GET, URLHelpers.CombineURL(APIURL, "api/" + hash + "/status")); JToken jsonResponse = JToken.Parse(result.Response); string status = jsonResponse["status"].Value <string>(); switch (status) { case "processing": case "pending": Thread.Sleep(500); break; case "done": case "ready": MediaCrushBlob blob = jsonResponse[hash].ToObject <MediaCrushBlob>(); return(UpdateResult(result, blob)); case "unrecognized": // Note: MediaCrush accepts just about _every_ kind of media file, // so the file itself is probably corrupted or just not actually a media file throw new Exception("This file is not an acceptable file type."); case "timeout": throw new Exception("This file took too long to process."); default: throw new Exception("This file failed to process."); } } return(result); }
private string GetObjectKey(string fileName) { string objectPrefix = NameParser.Parse(NameParserType.FolderPath, S3Settings.ObjectPrefix.Trim('/')); return(URLHelpers.CombineURL(objectPrefix, fileName)); }
private void lvFTPList_DragDrop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(typeof(string[]))) { Point point = lvFTPList.PointToClient(new Point(e.X, e.Y)); ListViewItem lvi = lvFTPList.GetItemAt(point.X, point.Y); if (lvi != null && e.AllowedEffect == DragDropEffects.Move) { if (tempSelected != null && tempSelected != lvi) { tempSelected.Selected = false; } FtpListItem file = lvi.Tag as FtpListItem; if (file != null && file.Type == FtpFileSystemObjectType.Directory) { string[] filenames = e.Data.GetData(typeof(string[])) as string[]; if (filenames != null) { int renameCount = 0; foreach (string filename in filenames) { if (file.Name != filename) { string path = URLHelpers.CombineURL(currentDirectory, filename); string movePath = ""; if (file.Type == FtpFileSystemObjectType.Link) { if (file.Name == ".") { movePath = URLHelpers.AddSlash(filename, SlashType.Prefix, 2); } else if (file.Name == "..") { movePath = URLHelpers.AddSlash(filename, SlashType.Prefix); } } else { movePath = URLHelpers.CombineURL(file.FullName, filename); } if (!string.IsNullOrEmpty(movePath)) { Client.Rename(path, movePath); renameCount++; } } } if (renameCount > 0) { RefreshDirectory(); } } } } tempSelected = null; } else if (e.Data.GetDataPresent(DataFormats.FileDrop)) { string[] files = e.Data.GetData(DataFormats.FileDrop) as string[]; if (files != null) { Client.UploadFiles(files, currentDirectory); RefreshDirectory(); } } }
public override UploadResult Upload(Stream stream, string fileName) { bool isPathStyleRequest = Settings.UsePathStyle; if (!isPathStyleRequest && Settings.Bucket.Contains(".")) { isPathStyleRequest = true; } string endpoint = URLHelpers.RemovePrefixes(Settings.Endpoint); string host = isPathStyleRequest ? endpoint : $"{Settings.Bucket}.{endpoint}"; string algorithm = "AWS4-HMAC-SHA256"; string credentialDate = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture); string region = GetRegion(); string scope = URLHelpers.CombineURL(credentialDate, region, "s3", "aws4_request"); string credential = URLHelpers.CombineURL(Settings.AccessKeyID, scope); string timeStamp = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture); string contentType = Helpers.GetMimeType(fileName); string uploadPath = GetUploadPath(fileName); string hashedPayload = "UNSIGNED-PAYLOAD"; NameValueCollection headers = new NameValueCollection(); headers["host"] = host; headers["content-type"] = contentType; headers["x-amz-date"] = timeStamp; headers["x-amz-content-sha256"] = hashedPayload; headers["x-amz-storage-class"] = Settings.StorageClass.ToString(); if (Settings.SetPublicACL) { headers["x-amz-acl"] = "public-read"; } string canonicalURI = uploadPath; if (isPathStyleRequest) { canonicalURI = URLHelpers.CombineURL(Settings.Bucket, canonicalURI); } canonicalURI = URLHelpers.AddSlash(canonicalURI, SlashType.Prefix); canonicalURI = URLHelpers.URLPathEncode(canonicalURI); string canonicalQueryString = ""; string canonicalHeaders = CreateCanonicalHeaders(headers); string signedHeaders = GetSignedHeaders(headers); string canonicalRequest = "PUT" + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedPayload; string stringToSign = algorithm + "\n" + timeStamp + "\n" + scope + "\n" + Helpers.BytesToHex(Helpers.ComputeSHA256(canonicalRequest)); byte[] dateKey = Helpers.ComputeHMACSHA256(credentialDate, "AWS4" + Settings.SecretAccessKey); byte[] dateRegionKey = Helpers.ComputeHMACSHA256(region, dateKey); byte[] dateRegionServiceKey = Helpers.ComputeHMACSHA256("s3", dateRegionKey); byte[] signingKey = Helpers.ComputeHMACSHA256("aws4_request", dateRegionServiceKey); string signature = Helpers.BytesToHex(Helpers.ComputeHMACSHA256(stringToSign, signingKey)); headers["Authorization"] = algorithm + " " + "Credential=" + credential + "," + "SignedHeaders=" + signedHeaders + "," + "Signature=" + signature; headers.Remove("host"); headers.Remove("content-type"); string url = URLHelpers.CombineURL(host, canonicalURI); url = URLHelpers.ForcePrefix(url, "https://"); NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, url, stream, contentType, null, headers); if (responseHeaders == null || responseHeaders.Count == 0 || responseHeaders["ETag"] == null) { Errors.Add("Upload to Amazon S3 failed."); return(null); } return(new UploadResult { IsSuccess = true, URL = GenerateURL(uploadPath) }); }
public override UploadResult Upload(Stream stream, string fileName) { bool isPathStyleRequest = Settings.UsePathStyle; if (!isPathStyleRequest && Settings.Bucket.Contains(".")) { isPathStyleRequest = true; } string endpoint = URLHelpers.RemovePrefixes(Settings.Endpoint); string host = isPathStyleRequest ? endpoint : $"{Settings.Bucket}.{endpoint}"; string algorithm = "AWS4-HMAC-SHA256"; string credentialDate = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture); string region = GetRegion(); string scope = URLHelpers.CombineURL(credentialDate, region, "s3", "aws4_request"); string credential = URLHelpers.CombineURL(Settings.AccessKeyID, scope); string timeStamp = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture); string contentType = RequestHelpers.GetMimeType(fileName); string hashedPayload; if (Settings.SignedPayload) { hashedPayload = Helpers.BytesToHex(Helpers.ComputeSHA256(stream)); } else { hashedPayload = "UNSIGNED-PAYLOAD"; } string uploadPath = GetUploadPath(fileName); string resultURL = GenerateURL(uploadPath); OnEarlyURLCopyRequested(resultURL); NameValueCollection headers = new NameValueCollection { ["Host"] = host, ["Content-Length"] = stream.Length.ToString(), ["Content-Type"] = contentType, ["x-amz-date"] = timeStamp, ["x-amz-content-sha256"] = hashedPayload, // If you don't specify, S3 Standard is the default storage class. Amazon S3 supports other storage classes. // Valid Values: STANDARD | REDUCED_REDUNDANCY | STANDARD_IA | ONEZONE_IA | INTELLIGENT_TIERING | GLACIER | DEEP_ARCHIVE // https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html ["x-amz-storage-class"] = Settings.StorageClass.ToString() }; if (Settings.SetPublicACL) { // The canned ACL to apply to the object. For more information, see Canned ACL. // https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl headers["x-amz-acl"] = "public-read"; } string canonicalURI = uploadPath; if (isPathStyleRequest) { canonicalURI = URLHelpers.CombineURL(Settings.Bucket, canonicalURI); } canonicalURI = URLHelpers.AddSlash(canonicalURI, SlashType.Prefix); canonicalURI = URLHelpers.URLEncode(canonicalURI, true); string canonicalQueryString = ""; string canonicalHeaders = CreateCanonicalHeaders(headers); string signedHeaders = GetSignedHeaders(headers); string canonicalRequest = "PUT" + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedPayload; string stringToSign = algorithm + "\n" + timeStamp + "\n" + scope + "\n" + Helpers.BytesToHex(Helpers.ComputeSHA256(canonicalRequest)); byte[] dateKey = Helpers.ComputeHMACSHA256(credentialDate, "AWS4" + Settings.SecretAccessKey); byte[] dateRegionKey = Helpers.ComputeHMACSHA256(region, dateKey); byte[] dateRegionServiceKey = Helpers.ComputeHMACSHA256("s3", dateRegionKey); byte[] signingKey = Helpers.ComputeHMACSHA256("aws4_request", dateRegionServiceKey); string signature = Helpers.BytesToHex(Helpers.ComputeHMACSHA256(stringToSign, signingKey)); headers["Authorization"] = algorithm + " " + "Credential=" + credential + "," + "SignedHeaders=" + signedHeaders + "," + "Signature=" + signature; headers.Remove("Host"); headers.Remove("Content-Type"); string url = URLHelpers.CombineURL(host, canonicalURI); url = URLHelpers.ForcePrefix(url, "https://"); SendRequest(HttpMethod.PUT, url, stream, contentType, null, headers); if (LastResponseInfo != null && LastResponseInfo.IsSuccess) { return(new UploadResult { IsSuccess = true, URL = resultURL }); } Errors.Add("Upload to Amazon S3 failed."); return(null); }
public override UploadResult Upload(Stream stream, string fileName) { string parsedUploadPath = NameParser.Parse(NameParserType.FolderPath, UploadPath); string destinationPath = URLHelpers.CombineURL(parsedUploadPath, fileName); // docs: https://www.backblaze.com/b2/docs/ // STEP 1: authorize, get auth token, api url, download url DebugHelper.WriteLine($"B2 uploader: Attempting to authorize as '{ApplicationKeyId}'."); B2Authorization auth = B2ApiAuthorize(ApplicationKeyId, ApplicationKey, out string authError); if (authError != null) { DebugHelper.WriteLine("B2 uploader: Failed to authorize."); Errors.Add($"Could not authenticate with B2: {authError}"); return(null); } DebugHelper.WriteLine($"B2 uploader: Authorized, using API server {auth.apiUrl}, download URL {auth.downloadUrl}"); // STEP 1.25: if we have an application key, there will be a bucketId present here, but if // not, we have an account key and need to find our bucket id ourselves string bucketId = auth.allowed?.bucketId; if (bucketId == null) { DebugHelper.WriteLine("B2 uploader: Key doesn't have a bucket ID set, so I'm looking for a bucket ID."); string newBucketId = B2ApiGetBucketId(auth, BucketName, out string getBucketError); if (getBucketError != null) { DebugHelper.WriteLine($"B2 uploader: It's {newBucketId}."); bucketId = newBucketId; } } // STEP 1.5: verify whether we can write to the bucket user wants to write to, with the given prefix DebugHelper.WriteLine("B2 uploader: Checking clientside whether we have permission to upload."); bool authCheckOk = IsAuthorizedForUpload(auth, bucketId, destinationPath, out string authCheckError); if (!authCheckOk) { DebugHelper.WriteLine("B2 uploader: Key is not suitable for this upload."); Errors.Add($"B2 upload failed: {authCheckError}"); return(null); } // STEP 1.75: start upload attempt loop const int maxTries = 5; B2UploadUrl url = null; for (int tries = 1; tries <= maxTries; tries++) { string newOrSameUrl = url == null ? "New URL." : "Same URL."; DebugHelper.WriteLine($"B2 uploader: Upload attempt {tries} of {maxTries}. {newOrSameUrl}"); // sloppy, but we need exponential backoff somehow and we are not in async code // since B2Uploader should have the thread to itself, and this just occurs on rare failures, // this should be OK if (tries > 1) { int delay = (int)Math.Pow(2, tries - 1) * 1000; DebugHelper.WriteLine($"Waiting ${delay} ms for backoff."); Thread.Sleep(delay); } // STEP 2: get upload url that we need to POST to in step 3 if (url == null) { DebugHelper.WriteLine("B2 uploader: Getting new upload URL."); url = B2ApiGetUploadUrl(auth, bucketId, out string getUrlError); if (getUrlError != null) { // this is guaranteed to be unrecoverable, so bail out DebugHelper.WriteLine("B2 uploader: Got error trying to get upload URL."); Errors.Add("Could not get B2 upload URL: " + getUrlError); return(null); } } // STEP 3: upload file and see if anything went wrong DebugHelper.WriteLine($"B2 uploader: Uploading to URL {url.uploadUrl}"); B2UploadResult uploadResult = B2ApiUploadFile(url, destinationPath, stream); HashSet <string> expiredTokenCodes = new HashSet <string>(new List <string> { "expired_auth_token", "bad_auth_token" }); if (uploadResult.RC == -1) { // magic number for "connection failed", should also happen when upload // caps are exceeded DebugHelper.WriteLine("B2 uploader: Connection failed, trying with new URL."); url = null; continue; } else if (uploadResult.RC == 401 && expiredTokenCodes.Contains(uploadResult.Error.code)) { // Unauthorized, our token expired DebugHelper.WriteLine("B2 uploader: Upload auth token expired, trying with new URL."); url = null; continue; } else if (uploadResult.RC == 408) { DebugHelper.WriteLine("B2 uploader: Request Timeout, trying with same URL."); continue; } else if (uploadResult.RC == 429) { DebugHelper.WriteLine("B2 uploader: Too Many Requests, trying with same URL."); continue; } else if (uploadResult.RC == 503) { DebugHelper.WriteLine("B2 uploader: Service Unavailable, trying with new URL."); url = null; continue; } else if (uploadResult.RC != 200) { // something else happened that wasn't a success, so bail out DebugHelper.WriteLine("B2 uploader: Unknown error, upload failure."); Errors.Add("B2 uploader: Unknown error occurred while calling b2_upload_file()."); return(null); } // success! // STEP 4: compose: // the download url (e.g. "https://f567.backblazeb2.com") // /file/$bucket/$uploadPath // or // $customUrl/$uploadPath string encodedFileName = URLHelpers.URLEncode(uploadResult.Upload.fileName, true); string remoteLocation = URLHelpers.CombineURL(auth.downloadUrl, "file", URLHelpers.URLEncode(BucketName), encodedFileName); DebugHelper.WriteLine($"B2 uploader: Successful upload! File should be at: {remoteLocation}"); if (UseCustomUrl) { string parsedCustomUrl = NameParser.Parse(NameParserType.FolderPath, CustomUrl); remoteLocation = URLHelpers.CombineURL(parsedCustomUrl, encodedFileName); remoteLocation = URLHelpers.FixPrefix(remoteLocation, "https://"); DebugHelper.WriteLine($"B2 uploader: But user requested custom URL, which will be: {remoteLocation}"); } return(new UploadResult() { IsSuccess = true, URL = remoteLocation }); } DebugHelper.WriteLine("B2 uploader: Ran out of attempts, aborting."); Errors.Add($"B2 upload failed: Could not upload file after {maxTries} attempts."); return(null); }
public string GenerateURL(string fileName) { string uploadPath = GetUploadPath(fileName); return(URLHelpers.CombineURL($"https://s3.{Settings.Endpoint}.amazonaws.com", Settings.Bucket, uploadPath)); }
public override UploadResult Upload(Stream stream, string fileName) { #region Calculating sizes long fileSize = stream.Length; int chunks = (int)Math.Ceiling((double)fileSize / BYTE_CHUNK_SIZE); long fullUploadSize = 16; // 16 bytes header List <long> uploadSizes = new List <long>(); uploadSizes.Add(0); LoopStartEnd((chunkStart, chunkEnd, i) => { int chunkLength = chunkEnd - chunkStart; fullUploadSize += chunkLength + 16 - (chunkLength % 16); uploadSizes.Add(fullUploadSize); }, chunks, fileSize); #endregion string randomKey = GenerateRandomKey(); byte[] randomKeyBytes = Encoding.UTF8.GetBytes(randomKey); Vault_oooCryptoData cryptoData = DeriveCryptoData(randomKeyBytes); #region Building filename byte[] fileNameBytes = Encoding.UTF8.GetBytes(fileName); string encryptedFileName; using (MemoryStream ms = new MemoryStream()) // Encrypting file name { ms.Write(cryptoData.Salt, 0, cryptoData.Salt.Length); byte[] encryptedFn = EncryptBytes(cryptoData, fileNameBytes); ms.Write(encryptedFn, 0, encryptedFn.Length); encryptedFileName = Helpers.BytesToHex(ms.ToArray()); } string bytesLengthHex = fullUploadSize.ToString("X4"); // To Hex DateTime expiryTime = DateTime.UtcNow.AddDays(30); // Defaults from the web client string expiryTimeHex = ((long)(expiryTime - ORIGIN_TIME).TotalSeconds).ToString("X4"); // Expiry date in UNIX seconds in hex string fullFileName = $"{expiryTimeHex}-b-{bytesLengthHex}-{encryptedFileName}".ToLower(); #endregion Dictionary <string, string> requestHeaders = new Dictionary <string, string>(); requestHeaders.Add("X-Get-Raw-File", "1"); Dictionary <string, long> postRequestJson = new Dictionary <string, long>(); postRequestJson.Add("chunks", chunks); postRequestJson.Add("fileLength", fullUploadSize); string postResult = SendRequest(HttpMethod.POST, URLHelpers.CombineURL(APIURL, fullFileName), JsonConvert.SerializeObject(postRequestJson), RequestHelpers.ContentTypeJSON, requestHeaders); Vault_oooMetaInfo metaInfo = JsonConvert.DeserializeObject <Vault_oooMetaInfo>(postResult); if (string.IsNullOrEmpty(metaInfo.UrlPathName)) { throw new InvalidOperationException("No correct metaInfo returned"); } #region Upload in chunks List <byte> dumpStash = new List <byte>(); LoopStartEnd((chunkStart, chunkEnd, i) => { int chunkLength = chunkEnd - chunkStart; byte[] plainBytes = new byte[chunkLength]; stream.Read(plainBytes, 0, chunkLength); byte[] encryptedBytes = EncryptBytes(cryptoData, plainBytes); int prependSize = 0; if (dumpStash.Count > 0) { using (MemoryStream ms = new MemoryStream()) { ms.Write(dumpStash.ToArray(), 0, dumpStash.Count); ms.Write(encryptedBytes, 0, encryptedBytes.Length); encryptedBytes = ms.ToArray(); } prependSize = dumpStash.Count; dumpStash.Clear(); } if (encryptedBytes.Length + (i == 0 ? 16 : 0) > BYTE_CHUNK_SIZE) // 16 bytes for the salt header { dumpStash.AddRange(encryptedBytes.Skip(BYTE_CHUNK_SIZE - (i == 0 ? 16 : 0))); encryptedBytes = encryptedBytes.Take(BYTE_CHUNK_SIZE - (i == 0 ? 16 : 0)).ToArray(); } using (MemoryStream ms = new MemoryStream()) { if (i == 0) { ms.Write(Encoding.UTF8.GetBytes("Salted__"), 0, 8); // Write header ms.Write(cryptoData.Salt, 0, cryptoData.Salt.Length); // 8 bytes ms.Write(encryptedBytes, 0, encryptedBytes.Length); } else { ms.Write(encryptedBytes, 0, encryptedBytes.Length); // Write encrypted bytes } NameValueCollection headers = new NameValueCollection(); headers.Add("X-Get-Raw-File", "1"); int uploadChunkStart = (int)(uploadSizes[i] - prependSize); headers.Add("X-Put-Chunk-Start", uploadChunkStart.ToString()); headers.Add("X-Put-Chunk-End", (uploadChunkStart + ms.Length).ToString()); headers.Add("X-Put-JWT", metaInfo.Token); SendRequest(HttpMethod.PUT, URLHelpers.CombineURL(APIURL, metaInfo.UrlPathName), ms, "application/octet-stream", null, headers); } }, chunks, fileSize); #endregion UploadResult res = new UploadResult(); res.IsURLExpected = true; res.URL = URLHelpers.CombineURL(APIURL, metaInfo.UrlPathName) + "#" + randomKey; // Full url with the encryption key return(res); }
public override UploadResult Upload(Stream stream, string fileName) { bool forcePathStyle = Settings.UsePathStyle; if (!forcePathStyle && Settings.Bucket.Contains(".")) { forcePathStyle = true; } string endpoint = URLHelpers.RemovePrefixes(Settings.Endpoint); string host = forcePathStyle ? endpoint : $"{Settings.Bucket}.{endpoint}"; string algorithm = "AWS4-HMAC-SHA256"; string credentialDate = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture); string region = GetRegion(); string scope = URLHelpers.CombineURL(credentialDate, region, "s3", "aws4_request"); string credential = URLHelpers.CombineURL(Settings.AccessKeyID, scope); string longDate = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture); string expiresTotalSeconds = ((long)TimeSpan.FromHours(1).TotalSeconds).ToString(); string contentType = Helpers.GetMimeType(fileName); NameValueCollection headers = new NameValueCollection(); headers["content-type"] = contentType; headers["host"] = host; headers["x-amz-acl"] = "public-read"; headers["x-amz-storage-class"] = Settings.StorageClass.ToString(); string signedHeaders = GetSignedHeaders(headers); Dictionary <string, string> args = new Dictionary <string, string>(); args.Add("X-Amz-Algorithm", algorithm); args.Add("X-Amz-Credential", credential); args.Add("X-Amz-Date", longDate); args.Add("X-Amz-Expires", expiresTotalSeconds); args.Add("X-Amz-SignedHeaders", signedHeaders); string uploadPath = GetUploadPath(fileName); string canonicalURI = uploadPath; if (forcePathStyle) { canonicalURI = URLHelpers.CombineURL(Settings.Bucket, canonicalURI); } canonicalURI = URLHelpers.AddSlash(canonicalURI, SlashType.Prefix); canonicalURI = URLHelpers.URLPathEncode(canonicalURI); string canonicalQueryString = URLHelpers.CreateQuery(args, true); string canonicalHeaders = CreateCanonicalHeaders(headers); string canonicalRequest = "PUT" + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + "UNSIGNED-PAYLOAD"; string stringToSign = algorithm + "\n" + longDate + "\n" + scope + "\n" + Helpers.BytesToHex(Helpers.ComputeSHA256(canonicalRequest)); byte[] dateKey = Helpers.ComputeHMACSHA256(credentialDate, "AWS4" + Settings.SecretAccessKey); byte[] dateRegionKey = Helpers.ComputeHMACSHA256(region, dateKey); byte[] dateRegionServiceKey = Helpers.ComputeHMACSHA256("s3", dateRegionKey); byte[] signingKey = Helpers.ComputeHMACSHA256("aws4_request", dateRegionServiceKey); string signature = Helpers.BytesToHex(Helpers.ComputeHMACSHA256(stringToSign, signingKey)); args.Add("X-Amz-Signature", signature); headers.Remove("content-type"); headers.Remove("host"); string url = URLHelpers.CombineURL(host, canonicalURI); url = URLHelpers.CreateQuery(url, args, true); url = URLHelpers.ForcePrefix(url, "https://"); NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, url, stream, contentType, null, headers); if (responseHeaders == null || responseHeaders.Count == 0) { Errors.Add("Upload to Amazon S3 failed. Check your access credentials."); return(null); } if (responseHeaders["ETag"] == null) { Errors.Add("Upload to Amazon S3 failed."); return(null); } return(new UploadResult { IsSuccess = true, URL = GenerateURL(uploadPath) }); }