Beispiel #1
0
        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);
        }
Beispiel #2
0
        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();
                }
            }
        }
Beispiel #3
0
 public string GetPhotosLink(string userID)
 {
     return(URLHelpers.CombineURL("https://www.flickr.com/photos", userID));
 }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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)
            });
        }
Beispiel #6
0
        private string GetUploadPath(string fileName)
        {
            string path = NameParser.Parse(NameParserType.FolderPath, Settings.ObjectPrefix.Trim('/'));

            return(URLHelpers.CombineURL(path, fileName));
        }
Beispiel #7
0
        // 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);
        }
Beispiel #8
0
        public string GetSubFolderPath(string filename = null, NameParserType nameParserType = NameParserType.URL)
        {
            string path = NameParser.Parse(nameParserType, SubFolderPath.Replace("%host", Host));

            return(URLHelpers.CombineURL(path, filename));
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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;
            }
        }
Beispiel #11
0
        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();
                }
            }
        }
Beispiel #12
0
 private string GetEndpoint()
 {
     return(URLHelpers.ForcePrefix(URLHelpers.CombineURL(GetCurrentRegion(s3Settings).Hostname, s3Settings.Bucket)));
 }
Beispiel #13
0
 private string GetEndpoint()
 {
     return(URLHelpers.CombineURL("https://" + GetCurrentRegion(s3Settings).Hostname, s3Settings.Bucket));
 }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        private string GetObjectKey(string fileName)
        {
            string objectPrefix = NameParser.Parse(NameParserType.FolderPath, S3Settings.ObjectPrefix.Trim('/'));

            return(URLHelpers.CombineURL(objectPrefix, fileName));
        }
Beispiel #16
0
        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();
                }
            }
        }
Beispiel #17
0
        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)
            });
        }
Beispiel #18
0
        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);
        }
Beispiel #19
0
        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);
        }
Beispiel #20
0
        public string GenerateURL(string fileName)
        {
            string uploadPath = GetUploadPath(fileName);

            return(URLHelpers.CombineURL($"https://s3.{Settings.Endpoint}.amazonaws.com", Settings.Bucket, uploadPath));
        }
Beispiel #21
0
        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);
        }
Beispiel #22
0
        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)
            });
        }