From 53a35e6e06ec5cfaa8a33d2b5b0d45f48eb8e0da Mon Sep 17 00:00:00 2001 From: Kenneth Hsu Date: Sun, 1 Dec 2019 10:33:54 -0800 Subject: [PATCH] Remove support for Amazon Cloud Drive. Amazon discontinued access to the Cloud Drive API. See https://forum.duplicati.com/t/amazon-cloud-drive-discontinued/7391. --- Duplicati CommandLine Only.sln | 6 - Duplicati.sln | 6 - ...Duplicati.CommandLine.BackendTester.csproj | 6 +- .../Duplicati.CommandLine.BackendTool.csproj | 6 +- .../CommandLine/Duplicati.CommandLine.csproj | 6 +- .../Duplicati.CommandLine.RecoveryTool.csproj | 6 +- .../Duplicati.GUI.TrayIcon.csproj | 6 +- .../Library/Backend/AmazonCloudDrive/AmzCD.cs | 678 ------------------ ...ti.Library.Backend.AmazonCloudDrive.csproj | 70 -- .../Backend/AmazonCloudDrive/Duplicati.snk | Bin 596 -> 0 bytes .../Properties/AssemblyInfo.cs | 43 -- .../Backend/AmazonCloudDrive/Strings.cs | 34 - .../Backend/AmazonCloudDrive/packages.config | 4 - Duplicati/Library/Main/Controller.cs | 4 - Duplicati/Server/Duplicati.Server.csproj | 6 +- .../directives/advancedOptionsEditor.js | 1 - .../ngax/scripts/services/EditUriBuiltins.js | 5 - .../ngax/scripts/services/SystemInfo.js | 1 - .../ngax/templates/backends/amzcd.html | 15 - Installer/Docker/README.md | 2 +- README.md | 2 +- 21 files changed, 8 insertions(+), 899 deletions(-) delete mode 100644 Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs delete mode 100644 Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.Library.Backend.AmazonCloudDrive.csproj delete mode 100644 Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.snk delete mode 100644 Duplicati/Library/Backend/AmazonCloudDrive/Properties/AssemblyInfo.cs delete mode 100644 Duplicati/Library/Backend/AmazonCloudDrive/Strings.cs delete mode 100644 Duplicati/Library/Backend/AmazonCloudDrive/packages.config delete mode 100644 Duplicati/Server/webroot/ngax/templates/backends/amzcd.html diff --git a/Duplicati CommandLine Only.sln b/Duplicati CommandLine Only.sln index 8d217c713..60f91ed27 100644 --- a/Duplicati CommandLine Only.sln +++ b/Duplicati CommandLine Only.sln @@ -45,8 +45,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.A EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Localization", "Duplicati\Library\Localization\Duplicati.Library.Localization.csproj", "{B68F2214-951F-4F78-8488-66E1ED3F50BF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.AmazonCloudDrive", "Duplicati\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj", "{08D7E42D-285C-4010-9881-986125FE2F3E}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.AutoUpdater", "Duplicati\Library\AutoUpdater\Duplicati.Library.AutoUpdater.csproj", "{7E119745-1F62-43F0-936C-F312A1912C0B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.SQLiteHelper", "Duplicati\Library\SQLiteHelper\Duplicati.Library.SQLiteHelper.csproj", "{2C838169-B187-4B09-8768-1C24C2521C8D}" @@ -179,10 +177,6 @@ Global {B68F2214-951F-4F78-8488-66E1ED3F50BF}.Debug|Any CPU.Build.0 = Debug|Any CPU {B68F2214-951F-4F78-8488-66E1ED3F50BF}.Release|Any CPU.ActiveCfg = Release|Any CPU {B68F2214-951F-4F78-8488-66E1ED3F50BF}.Release|Any CPU.Build.0 = Release|Any CPU - {08D7E42D-285C-4010-9881-986125FE2F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {08D7E42D-285C-4010-9881-986125FE2F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {08D7E42D-285C-4010-9881-986125FE2F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {08D7E42D-285C-4010-9881-986125FE2F3E}.Release|Any CPU.Build.0 = Release|Any CPU {7E119745-1F62-43F0-936C-F312A1912C0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7E119745-1F62-43F0-936C-F312A1912C0B}.Debug|Any CPU.Build.0 = Debug|Any CPU {7E119745-1F62-43F0-936C-F312A1912C0B}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/Duplicati.sln b/Duplicati.sln index 35e1e1594..5066303ef 100644 --- a/Duplicati.sln +++ b/Duplicati.sln @@ -71,8 +71,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.H EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.CommandLine.RecoveryTool", "Duplicati\CommandLine\RecoveryTool\Duplicati.CommandLine.RecoveryTool.csproj", "{4A010589-76E6-4F05-A5C4-4598D5DF11F8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.AmazonCloudDrive", "Duplicati\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj", "{08D7E42D-285C-4010-9881-986125FE2F3E}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Backblaze", "Duplicati\Library\Backend\Backblaze\Duplicati.Library.Backend.Backblaze.csproj", "{61C43D61-4368-4942-84A3-1EB623F4EF2A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Mega", "Duplicati\Library\Backend\Mega\Duplicati.Library.Backend.Mega.csproj", "{6643A5AE-AB38-453F-ADCE-408E35A81A83}" @@ -245,10 +243,6 @@ Global {4A010589-76E6-4F05-A5C4-4598D5DF11F8}.Debug|Any CPU.Build.0 = Debug|Any CPU {4A010589-76E6-4F05-A5C4-4598D5DF11F8}.Release|Any CPU.ActiveCfg = Release|Any CPU {4A010589-76E6-4F05-A5C4-4598D5DF11F8}.Release|Any CPU.Build.0 = Release|Any CPU - {08D7E42D-285C-4010-9881-986125FE2F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {08D7E42D-285C-4010-9881-986125FE2F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {08D7E42D-285C-4010-9881-986125FE2F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {08D7E42D-285C-4010-9881-986125FE2F3E}.Release|Any CPU.Build.0 = Release|Any CPU {61C43D61-4368-4942-84A3-1EB623F4EF2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {61C43D61-4368-4942-84A3-1EB623F4EF2A}.Debug|Any CPU.Build.0 = Debug|Any CPU {61C43D61-4368-4942-84A3-1EB623F4EF2A}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/Duplicati/CommandLine/BackendTester/Duplicati.CommandLine.BackendTester.csproj b/Duplicati/CommandLine/BackendTester/Duplicati.CommandLine.BackendTester.csproj index 47f42addf..9f61b68fe 100644 --- a/Duplicati/CommandLine/BackendTester/Duplicati.CommandLine.BackendTester.csproj +++ b/Duplicati/CommandLine/BackendTester/Duplicati.CommandLine.BackendTester.csproj @@ -126,10 +126,6 @@ {D60AD540-0E7D-40CE-83AE-D26E01FFE9B8} Duplicati.Library.Backend.HubiC - - {08D7E42D-285C-4010-9881-986125FE2F3E} - Duplicati.Library.Backend.AmazonCloudDrive - {1BFAE226-8364-4086-825C-BB83F6F3EE4C} Duplicati.Library.Backend.CloudFiles @@ -195,4 +191,4 @@ --> - \ No newline at end of file + diff --git a/Duplicati/CommandLine/BackendTool/Duplicati.CommandLine.BackendTool.csproj b/Duplicati/CommandLine/BackendTool/Duplicati.CommandLine.BackendTool.csproj index af3ca4d8b..81425bcd4 100644 --- a/Duplicati/CommandLine/BackendTool/Duplicati.CommandLine.BackendTool.csproj +++ b/Duplicati/CommandLine/BackendTool/Duplicati.CommandLine.BackendTool.csproj @@ -132,10 +132,6 @@ {D60AD540-0E7D-40CE-83AE-D26E01FFE9B8} Duplicati.Library.Backend.HubiC - - {08D7E42D-285C-4010-9881-986125FE2F3E} - Duplicati.Library.Backend.AmazonCloudDrive - {61C43D61-4368-4942-84A3-1EB623F4EF2A} Duplicati.Library.Backend.Backblaze @@ -160,4 +156,4 @@ - \ No newline at end of file + diff --git a/Duplicati/CommandLine/Duplicati.CommandLine.csproj b/Duplicati/CommandLine/Duplicati.CommandLine.csproj index 621485f26..54f616323 100644 --- a/Duplicati/CommandLine/Duplicati.CommandLine.csproj +++ b/Duplicati/CommandLine/Duplicati.CommandLine.csproj @@ -203,10 +203,6 @@ {4A010589-76E6-4F05-A5C4-4598D5DF11F8} Duplicati.CommandLine.RecoveryTool - - {08D7E42D-285C-4010-9881-986125FE2F3E} - Duplicati.Library.Backend.AmazonCloudDrive - {61C43D61-4368-4942-84A3-1EB623F4EF2A} Duplicati.Library.Backend.Backblaze @@ -256,4 +252,4 @@ --> - \ No newline at end of file + diff --git a/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj b/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj index eecbcc15e..5bbf41b2b 100644 --- a/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj +++ b/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj @@ -157,10 +157,6 @@ {10D2D1B7-C664-41D8-9B3A-00040C3D421B} Duplicati.Library.Main - - {08D7E42D-285C-4010-9881-986125FE2F3E} - Duplicati.Library.Backend.AmazonCloudDrive - {61C43D61-4368-4942-84A3-1EB623F4EF2A} Duplicati.Library.Backend.Backblaze @@ -193,4 +189,4 @@ - \ No newline at end of file + diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj index bf7f60013..d5ad3ea1a 100644 --- a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj @@ -313,10 +313,6 @@ {4A010589-76E6-4F05-A5C4-4598D5DF11F8} Duplicati.CommandLine.RecoveryTool - - {08D7E42D-285C-4010-9881-986125FE2F3E} - Duplicati.Library.Backend.AmazonCloudDrive - {61C43D61-4368-4942-84A3-1EB623F4EF2A} Duplicati.Library.Backend.Backblaze @@ -467,4 +463,4 @@ copy /Y '%USERPROFILE%\.nuget\packages\alphavss\1.4.0\lib\net45\AlphaVSS.*.dll' - \ No newline at end of file + diff --git a/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs b/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs deleted file mode 100644 index b0c4e1d4a..000000000 --- a/Duplicati/Library/Backend/AmazonCloudDrive/AmzCD.cs +++ /dev/null @@ -1,678 +0,0 @@ -// Copyright (C) 2015, The Duplicati Team -// http://www.duplicati.com, info@duplicati.com -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation; either version 2.1 of the -// License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -using Duplicati.Library.Common.IO; -using Duplicati.Library.Interface; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Threading; -using System.Threading.Tasks; - -namespace Duplicati.Library.Backend.AmazonCloudDrive -{ - // ReSharper disable once ClassNeverInstantiated.Global - // This class is instantiated dynamically in the BackendLoader. - public class AmzCD : IBackend, IStreamingBackend, IRenameEnabledBackend - { - private const string AUTHID_OPTION = "authid"; - private const string LABELS_OPTION = "amzcd-labels"; - private const string DELAY_OPTION = "amzcd-consistency-delay"; - - private const string DEFAULT_LABELS = "duplicati,backup"; - private const string DEFAULT_DELAY = "30s"; - - private const int PAGE_SIZE = 200; - - private const string CLOUDRIVE_MASTER_URL = "https://drive.amazonaws.com/drive/v1/account/endpoint"; - private const string CACHE_FILE_NAME_TEMPLATE = "dupl-amzcd-endp-{0}-cache.txt"; - private static readonly TimeSpan KEEP_CACHE_FILE_TIME = TimeSpan.FromDays(5); - - private const string CONTENT_KIND_FOLDER = "FOLDER"; - private const string CONTENT_KIND_FILE = "FILE"; - - private EndpointInfo m_endPointInfo; - private ResourceModel m_curdir; - - private readonly string m_path; - private readonly string[] m_labels; - - private readonly string m_authid; - private readonly OAuthHelper m_oauth; - private Dictionary m_filecache; - private readonly string m_userid; - private readonly TimeSpan m_delayTimeSpan; - - private static readonly object m_waitUntilLock; - private static readonly Dictionary m_waitUntilAuthId; - private static Dictionary m_waitUntilRemotename; - - static AmzCD() - { - m_waitUntilLock = new object(); - m_waitUntilAuthId = new Dictionary(); - m_waitUntilRemotename = new Dictionary(); - } - - // ReSharper disable once UnusedMember.Global - // This constructor is needed by the BackendLoader. - public AmzCD() - { - } - - // ReSharper disable once UnusedMember.Global - // This constructor is needed by the BackendLoader. - public AmzCD(string url, Dictionary options) - { - var uri = new Utility.Uri(url); - m_path = Util.AppendDirSeparator(uri.HostAndPath, "/"); - - if (options.ContainsKey(AUTHID_OPTION)) - m_authid = options[AUTHID_OPTION]; - - string labels = DEFAULT_LABELS; - if (options.ContainsKey(LABELS_OPTION)) - labels = options[LABELS_OPTION]; - - string delay = DEFAULT_DELAY; - if (options.ContainsKey(DELAY_OPTION)) - delay = options[DELAY_OPTION]; - - if (!string.IsNullOrWhiteSpace(labels)) - m_labels = labels.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries); - - if (string.IsNullOrWhiteSpace(delay)) - m_delayTimeSpan = new TimeSpan(0); - else - m_delayTimeSpan = Library.Utility.Timeparser.ParseTimeSpan(delay); - - m_oauth = new OAuthHelper(m_authid, this.ProtocolKey) { AutoAuthHeader = true }; - m_userid = m_authid.Split(new [] {":"}, StringSplitOptions.RemoveEmptyEntries).First(); - } - - private static void CleanWaitUntil() - { - lock (m_waitUntilLock) - { - DateTime now = DateTime.Now; - m_waitUntilRemotename = m_waitUntilRemotename.Where(pair => pair.Value > now) - .ToDictionary(pair => pair.Key, pair => pair.Value); - } - } - - private DateTime GetWaitUntil(string remotename) - { - lock (m_waitUntilLock) - { - CleanWaitUntil(); - - DateTime result; - if (string.IsNullOrEmpty(remotename)) - { - if (m_waitUntilAuthId.TryGetValue(m_authid, out result)) - return result; - } - else - { - if (m_waitUntilRemotename.TryGetValue(remotename, out result)) - return result; - } - - return DateTime.MinValue; - } - } - - private void SetWaitUntil(string remotename, DateTime value) - { - lock (m_waitUntilLock) - { - DateTime oldValue; - - if (!string.IsNullOrEmpty(remotename)) - { - if (!m_waitUntilRemotename.TryGetValue(remotename, out oldValue) || value > oldValue) - m_waitUntilRemotename[remotename] = value; - } - - if (!m_waitUntilAuthId.TryGetValue(m_authid, out oldValue) || value > oldValue) - m_waitUntilAuthId[m_authid] = value; - } - } - - private void EnforceConsistencyDelay(string remotename) - { - var wait = GetWaitUntil(remotename) - DateTime.Now; - - if (wait.Ticks > 0) - Thread.Sleep(wait); - } - - private string CacheFilePath { get { return SystemIO.IO_OS.PathCombine(Utility.TempFolder.SystemTempPath, string.Format(CACHE_FILE_NAME_TEMPLATE, m_userid)); } } - - private void RefreshMetadataAndContentUrl() - { - try - { - if (File.Exists(CacheFilePath) && (DateTime.Now - File.GetLastWriteTime(CacheFilePath)) < KEEP_CACHE_FILE_TIME) - { - m_endPointInfo = JsonConvert.DeserializeObject(File.ReadAllText(CacheFilePath)); - return; - } - } - catch - { - } - - m_endPointInfo = m_oauth.GetJSONData(CLOUDRIVE_MASTER_URL); - - try - { - if (m_endPointInfo.CustomerExists && m_endPointInfo.ContentUrl != null && m_endPointInfo.MetadataUrl != null) - File.WriteAllText(CacheFilePath, JsonConvert.SerializeObject(m_endPointInfo)); - } - catch - { - } - } - - public string ContentUrl - { - get - { - if (m_endPointInfo == null) - RefreshMetadataAndContentUrl(); - while (m_endPointInfo.ContentUrl.EndsWith("/", StringComparison.Ordinal)) - m_endPointInfo.ContentUrl = m_endPointInfo.ContentUrl.Substring(0, m_endPointInfo.ContentUrl.Length - 1); - return m_endPointInfo.ContentUrl; - } - } - - public string MetadataUrl - { - get - { - if (m_endPointInfo == null) - RefreshMetadataAndContentUrl(); - while (m_endPointInfo.MetadataUrl.EndsWith("/", StringComparison.Ordinal)) - m_endPointInfo.MetadataUrl = m_endPointInfo.MetadataUrl.Substring(0, m_endPointInfo.MetadataUrl.Length - 1); - return m_endPointInfo.MetadataUrl; - } - } - - private Dictionary FileCache - { - get - { - if (m_filecache == null) - List(); - - return m_filecache; - } - } - - private ResourceModel GetCurrentDirectory(bool createMissing, string altpath = null) - { - var rootResponse = m_oauth.GetJSONData(string.Format("{0}/nodes?filters=isRoot:true", MetadataUrl)); - var parent = rootResponse.Data.First(); - var curpath = new List(); - foreach(var p in (altpath ?? m_path).Split(new string[] {"/"}, StringSplitOptions.RemoveEmptyEntries)) - { - var requestUrl = string.Format("{0}/nodes?filters=kind:{1}%20and%20parents:{2}%20and%20name:{3}", MetadataUrl, CONTENT_KIND_FOLDER, Utility.Uri.UrlEncode(parent.ID), Utility.Uri.UrlPathEncode(EscapeFiltersValue(p))); - var self = m_oauth.GetJSONData(requestUrl); - if (self == null || self.Count == 0 || self.Data == null || self.Data.Length == 0) - { - if (!createMissing) - throw new FolderMissingException(string.Format("Unable to find folder {0} in {1}", p, "/" + string.Join("/", curpath))); - - // Create the folder - var data = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new CreateItemRequest() { - Name = p, - Parents = new string[] { parent.ID }, - Kind = CONTENT_KIND_FOLDER, - Labels = m_labels - })); - - parent = m_oauth.GetJSONData( - string.Format("{0}/nodes", MetadataUrl), - - // Setup - req => - { - req.Method = "POST"; - req.ContentLength = data.Length; - req.ContentType = "application/json"; - }, - - // Post the folder entry - req => - { - using(var rs = req.GetRequestStream()) - rs.Write(data, 0, data.Length); - } - ); - SetWaitUntil(null, DateTime.Now + m_delayTimeSpan); - } - else if (self.Count > 1) - throw new UserInformationException(Strings.AmzCD.MultipleEntries(p, "/" + string.Join("/", curpath)), "AmzCDMultipleEntries"); - else - parent = self.Data.First(); - } - - return parent; - } - - private ResourceModel CurrentDirectory - { - get - { - if (m_curdir == null) - m_curdir = GetCurrentDirectory(false); - - return m_curdir; - } - } - - private string GetFileID(string name) - { - var recent = m_filecache == null; - - string id; - FileCache.TryGetValue(name, out id); - if (!string.IsNullOrWhiteSpace(id)) - return id; - - // Reset to make sure it is actually missing - if (!recent) - { - List(); - - FileCache.TryGetValue(name, out id); - if (!string.IsNullOrWhiteSpace(id)) - return id; - } - - throw new FileMissingException(); - } - - private static readonly System.Text.RegularExpressions.Regex FILTERS_VALUE_ESCAPECHAR = new System.Text.RegularExpressions.Regex(@"[+\-&|!(){}\[\]^'""~*?:\\ ]", System.Text.RegularExpressions.RegexOptions.Compiled); - - public static string EscapeFiltersValue(string value) - { - return FILTERS_VALUE_ESCAPECHAR.Replace(value, (m) => { - return @"\" + m.Value; - }); - } - - #region IStreamingBackend implementation - - public async Task PutAsync(string remotename, Stream stream, CancellationToken cancelToken) - { - EnforceConsistencyDelay(remotename); - - var overwrite = FileCache.ContainsKey(remotename); - var fileid = overwrite ? m_filecache[remotename] : null; - - var url = string.Format(overwrite ? "{0}/nodes/{1}/content?suppress=deduplication" : "{0}/nodes?suppress=deduplication", ContentUrl, fileid); - - var createreq = new CreateItemRequest() { - Name = remotename, - Kind = CONTENT_KIND_FILE, - Labels = m_labels, - Parents = new string[] { CurrentDirectory.ID } - }; - - try - { - var item = await m_oauth.PostMultipartAndGetJSONDataAsync( - url, - req => - { - req.Method = overwrite ? "PUT" : "POST"; - }, - cancelToken, - new MultipartItem(createreq, "metadata"), - new MultipartItem(stream, "content", remotename) - ).ConfigureAwait(false); - - if (m_filecache != null) - m_filecache[item.Name] = item.ID; - } - catch(Exception ex) - { - #if DEBUG - if (ex is WebException exception) - using(var sr = new StreamReader(exception.Response.GetResponseStream())) - Console.WriteLine(sr.ReadToEnd()); - #endif - - m_filecache = null; - throw; - } - finally - { - SetWaitUntil(remotename, DateTime.Now + m_delayTimeSpan); - } - } - - public void Get(string remotename, Stream stream) - { - EnforceConsistencyDelay(remotename); - - using (var resp = m_oauth.GetResponse(string.Format("{0}/nodes/{1}/content", ContentUrl, GetFileID(remotename)))) - using(var rs = Library.Utility.AsyncHttpRequest.TrySetTimeout(resp.GetResponseStream())) - Utility.Utility.CopyStream(rs, stream); - } - - #endregion - - #region IBackend implementation - - public IEnumerable List() - { - EnforceConsistencyDelay(null); - - var query = string.Format("{0}/nodes?filters=parents:{1}&limit={2}", MetadataUrl, Utility.Uri.UrlEncode(CurrentDirectory.ID), PAGE_SIZE); - var res = new List(); - string nextToken = null; - m_filecache = null; - var cache = new Dictionary(); - - do - { - var lst = m_oauth.GetJSONData(query + (string.IsNullOrWhiteSpace(nextToken) ? "" : ("&startToken=" + nextToken))); - if (lst.Data != null) - { - foreach(var n in lst.Data) - { - - if (string.Equals(CONTENT_KIND_FOLDER, n.Kind, StringComparison.OrdinalIgnoreCase)) - res.Add(new FileEntry(n.Name) { IsFolder = true }); - else if (string.Equals(CONTENT_KIND_FILE, n.Kind, StringComparison.OrdinalIgnoreCase)) - { - cache[n.Name] = n.ID; - - if (n.ContentProperties == null) - res.Add(new FileEntry(n.Name) { - LastAccess = n.LastModified, - LastModification = n.LastModified - }); - else - res.Add(new FileEntry(n.Name, n.ContentProperties.Size, n.LastModified, n.LastModified)); - } - } - } - - nextToken = lst.NextToken; - - // Contrary to the documentation, nextToken is null when the set is done - if (lst.Count == 0) - break; - - // Docs say to check for empty response ... - //if (lst.Count < PAGE_SIZE) - // break; - } while(nextToken != null); - - m_filecache = cache; - return res; - - } - - public Task PutAsync(string remotename, string filename, CancellationToken cancelToken) - { - using (FileStream fs = File.OpenRead(filename)) - return PutAsync(remotename, fs, cancelToken); - } - - public void Get(string remotename, string filename) - { - using (FileStream fs = File.Create(filename)) - Get(remotename, fs); - } - - public void Delete(string remotename) - { - EnforceConsistencyDelay(remotename); - - try - { - using (m_oauth.GetResponse(string.Format("{0}/trash/{1}", MetadataUrl, GetFileID(remotename)), null, "PUT")) - { - } - - m_filecache.Remove(remotename); - } - catch - { - m_filecache = null; - } - SetWaitUntil(remotename, DateTime.Now + m_delayTimeSpan); - } - - public void Test() - { - this.TestList(); - } - - public void CreateFolder() - { - EnforceConsistencyDelay(null); - GetCurrentDirectory(true); - } - - public string DisplayName - { - get - { - return Strings.AmzCD.DisplayName; - } - } - - public string ProtocolKey - { - get - { - return "amzcd"; - } - } - - public IList SupportedCommands - { - get { - return new List(new ICommandLineArgument[] { - new CommandLineArgument(AUTHID_OPTION, CommandLineArgument.ArgumentType.Password, Strings.AmzCD.AuthidShort, Strings.AmzCD.AuthidLong(OAuthHelper.OAUTH_LOGIN_URL("amzcd"))), - new CommandLineArgument(LABELS_OPTION, CommandLineArgument.ArgumentType.String, Strings.AmzCD.LabelsShort, Strings.AmzCD.LabelsLong, DEFAULT_LABELS), - new CommandLineArgument(DELAY_OPTION, CommandLineArgument.ArgumentType.Timespan, Strings.AmzCD.DelayShort, Strings.AmzCD.DelayLong, DEFAULT_DELAY), - }); - } - } - - public string Description - { - get - { - return Strings.AmzCD.Description; - } - } - - public string[] DNSName - { - get - { - var contentUrl = string.Empty; - var metdataUrl = string.Empty; - - if (m_endPointInfo != null) - { - if (!string.IsNullOrWhiteSpace(m_endPointInfo.ContentUrl)) - contentUrl = new Uri(m_endPointInfo.ContentUrl).Host; - if (!string.IsNullOrWhiteSpace(m_endPointInfo.MetadataUrl)) - metdataUrl = new Uri(m_endPointInfo.MetadataUrl).Host; - } - - return new string[] { - new Uri(CLOUDRIVE_MASTER_URL).Host, - contentUrl, - metdataUrl - }; - } - } - - #endregion - - #region IDisposable implementation - - public void Dispose() - { - } - - #endregion - - #region IRenameEnabledBackend - - public void Rename(string oldname, string newname) - { - EnforceConsistencyDelay(oldname); - - var id = GetFileID(oldname); - - var data = System.Text.Encoding.UTF8.GetBytes( - JsonConvert.SerializeObject(new CreateItemRequest() { Name = newname }) - ); - - try - { - var resp = m_oauth.GetJSONData( - string.Format("{0}/nodes/{1}", MetadataUrl, id), - req => - { - req.Method = "PATCH"; - req.ContentType = "application/json"; - req.ContentLength = data.Length; - }, - - req => - { - using (var rs = req.GetRequestStream()) - rs.Write(data, 0, data.Length); - } - ); - - m_filecache.Remove(oldname); - m_filecache[newname] = resp.ID; - } - catch - { - m_filecache = null; - throw; - } - finally - { - SetWaitUntil(oldname, DateTime.Now + m_delayTimeSpan); - SetWaitUntil(newname, DateTime.Now + m_delayTimeSpan); - } - } - - #endregion - - #region JSON Classes - - private class ListResponse - { - [JsonProperty("count")] - public long Count { get; set; } - [JsonProperty("nextToken")] - public string NextToken { get; set; } - [JsonProperty("data")] - public ResourceModel[] Data { get; set; } - } - - private class ResourceModel - { - [JsonProperty("id")] - public string ID { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("kind")] - public string Kind { get; set; } - [JsonProperty("version")] - public long Version { get; set; } - [JsonProperty("modifiedDate")] - public DateTime LastModified { get; set; } - [JsonProperty("createdDate")] - public DateTime CreatedDate { get; set; } - [JsonProperty("labels")] - public string[] Labels { get; set; } - [JsonProperty("description")] - public string Description { get; set; } - [JsonProperty("createdBy")] - public string CreatedBy { get; set; } - [JsonProperty("parents")] - public string[] Parents { get; set; } - [JsonProperty("status")] - public string Status { get; set; } - [JsonProperty("contentProperties")] - public ContentProperties ContentProperties { get; set; } - } - - private class ContentProperties - { - [JsonProperty("version")] - public long Version { get; set; } - [JsonProperty("md5")] - public string MD5 { get; set; } - [JsonProperty("size")] - public long Size { get; set; } - - [JsonProperty("contentType")] - public string ContentType { get; set; } - [JsonProperty("extension")] - public string Extension { get; set; } - [JsonProperty("contentDate")] - public DateTime ContentDate { get; set; } - } - - private class EndpointInfo - { - [JsonProperty("customerExists")] - public bool CustomerExists { get; set; } - [JsonProperty("contentUrl")] - public string ContentUrl { get; set; } - [JsonProperty("metadataUrl")] - public string MetadataUrl { get; set; } - } - - private class CreateItemRequest - { - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("kind")] - public string Kind { get; set; } - [JsonProperty("labels", NullValueHandling = NullValueHandling.Ignore)] - public string[] Labels { get; set; } - [JsonProperty("properties", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary Properties { get; set; } - [JsonProperty("parents")] - public string[] Parents { get; set; } - } - - #endregion - } -} - diff --git a/Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.Library.Backend.AmazonCloudDrive.csproj b/Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.Library.Backend.AmazonCloudDrive.csproj deleted file mode 100644 index 52413aaed..000000000 --- a/Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.Library.Backend.AmazonCloudDrive.csproj +++ /dev/null @@ -1,70 +0,0 @@ - - - - Debug - AnyCPU - {08D7E42D-285C-4010-9881-986125FE2F3E} - Library - Duplicati.Library.Backend.AmazonCloudDrive - Duplicati.Library.Backend.AmazonCloudDrive - Duplicati.snk - v4.6.2 - false - - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - full - true - bin\Release - prompt - 4 - false - - - - ..\..\..\..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - {B68F2214-951F-4F78-8488-66E1ED3F50BF} - Duplicati.Library.Localization - - - {D4C37C33-5E73-4B56-B2C3-DC4A6BAA36BB} - Duplicati.Library.OAuthHelper - - - {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65} - Duplicati.Library.Utility - - - {C5899F45-B0FF-483C-9D38-24A9FCAAB237} - Duplicati.Library.Interface - - - {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.Common - - - - - - \ No newline at end of file diff --git a/Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.snk b/Duplicati/Library/Backend/AmazonCloudDrive/Duplicati.snk deleted file mode 100644 index e0c1e2dd86119728adaeefc5f14f2e597dabceeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmZQ)VqjoUVPFUfb~IvOVPIfnU}U&>ZqBFG;TL!xbC@f=sW??FHp%RuD04u?d|@dM zp47GKm!Hl%dFaei`<5*qzAgXqbzUyVi_n}?OMO*3eH|OE?krr| zFEl@9)L*-L?Q8KJPtTajTTV9l{O!|eX~_>-AD#yZ=6m07=(;Lz?67b_fmBH7>6XPy zU(fsaYt6=H^BbXYGcsePe{{ZI&XLwz9=grGu+&OTZN+`>n#aL@H_qHKNL{x|{OX?< z|2?cWgj<|a*&Wn5qtR68+v$gad`lNSIGSM4$`K*nE_8`M(8%hLo?+%X^GU{qHtmys zKah1))%qg*H$8)~{Blp<;-4#gv3~y3w(VO5op^Nq_Qo%mz;QX`zXzj&$<=3DJ8QK~doHe9_tNXtnN&4~oeV$j z^o2{LFP>08&A&p7*^IG!Mnm`8x8Lq$er`8lWi+;b>yXC%XWDAv$p-_y)7-T(lU$#a z#IstS7OnePcICwJ+w3(l+=qQ0gsr@P>rWc{j)4B;9b4MXBe*rpp6LBh{}W&Ed`G$N IQKi@%02MtM!T - - - \ No newline at end of file diff --git a/Duplicati/Library/Main/Controller.cs b/Duplicati/Library/Main/Controller.cs index 684f19a67..e4c2b9273 100644 --- a/Duplicati/Library/Main/Controller.cs +++ b/Duplicati/Library/Main/Controller.cs @@ -803,10 +803,6 @@ namespace Duplicati.Library.Main if (string.Equals(m_options.CompressionModule, "7z", StringComparison.OrdinalIgnoreCase)) Logging.Log.WriteWarningMessage(LOGTAG, "7zModuleHasIssues", null, "The 7z compression module has known issues and should only be used for experimental purposes"); - // Amazon CD is closing August 16th 2019 - if (string.Equals(new Library.Utility.Uri(m_backend).Scheme, "amzcd", StringComparison.OrdinalIgnoreCase)) - Logging.Log.WriteWarningMessage(LOGTAG, "AmzCDClosingApi", null, "The Amazon Cloud Drive API is closing down on August 16th 2019, please migrate your backups before this date"); - //TODO: Based on the action, see if all options are relevant } diff --git a/Duplicati/Server/Duplicati.Server.csproj b/Duplicati/Server/Duplicati.Server.csproj index 78f92106d..d0887dc34 100644 --- a/Duplicati/Server/Duplicati.Server.csproj +++ b/Duplicati/Server/Duplicati.Server.csproj @@ -291,10 +291,6 @@ {4A010589-76E6-4F05-A5C4-4598D5DF11F8} Duplicati.CommandLine.RecoveryTool - - {08D7E42D-285C-4010-9881-986125FE2F3E} - Duplicati.Library.Backend.AmazonCloudDrive - {61C43D61-4368-4942-84A3-1EB623F4EF2A} Duplicati.Library.Backend.Backblaze @@ -338,4 +334,4 @@ --> - \ No newline at end of file + diff --git a/Duplicati/Server/webroot/ngax/scripts/directives/advancedOptionsEditor.js b/Duplicati/Server/webroot/ngax/scripts/directives/advancedOptionsEditor.js index 176468929..22de2a242 100644 --- a/Duplicati/Server/webroot/ngax/scripts/directives/advancedOptionsEditor.js +++ b/Duplicati/Server/webroot/ngax/scripts/directives/advancedOptionsEditor.js @@ -26,7 +26,6 @@ backupApp.directive('advancedOptionsEditor', function() { 'throttle-download': 'speed', 'retry-delay': 'shorttimespan', - 'amzcd-consistency-delay': 'shorttimespan', 'web-timeout': 'shorttimespan', 'run-script-timeout': 'shorttimespan' }; diff --git a/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js b/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js index 5ac789943..e428780f3 100644 --- a/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js +++ b/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js @@ -20,7 +20,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo, EditUriBackendConfig.templates['onedrivev2'] = 'templates/backends/oauth.html'; EditUriBackendConfig.templates['sharepoint'] = 'templates/backends/sharepoint.html'; EditUriBackendConfig.templates['msgroup'] = 'templates/backends/msgroup.html'; - EditUriBackendConfig.templates['amzcd'] = 'templates/backends/amzcd.html'; EditUriBackendConfig.templates['openstack'] = 'templates/backends/openstack.html'; EditUriBackendConfig.templates['azure'] = 'templates/backends/azure.html'; EditUriBackendConfig.templates['gcs'] = 'templates/backends/gcs.html'; @@ -199,7 +198,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo, EditUriBackendConfig.loaders['onedrivev2'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.loaders['sharepoint'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.loaders['msgroup'] = function() { return this['oauth-base'].apply(this, arguments); }; - EditUriBackendConfig.loaders['amzcd'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.loaders['box'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.loaders['dropbox'] = function() { return this['oauth-base'].apply(this, arguments); }; @@ -322,7 +320,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo, EditUriBackendConfig.parsers['onedrive'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.parsers['onedrivev2'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.parsers['sharepoint'] = function() { return this['oauth-base'].apply(this, arguments); }; - EditUriBackendConfig.parsers['amzcd'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.parsers['box'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.parsers['dropbox'] = function() { return this['oauth-base'].apply(this, arguments); }; @@ -474,7 +471,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo, EditUriBackendConfig.builders['onedrivev2'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.builders['sharepoint'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.builders['msgroup'] = function() { return this['oauth-base'].apply(this, arguments); }; - EditUriBackendConfig.builders['amzcd'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.builders['box'] = function() { return this['oauth-base'].apply(this, arguments); }; EditUriBackendConfig.builders['dropbox'] = function() { return this['oauth-base'].apply(this, arguments); }; @@ -718,7 +714,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo, EditUriBackendConfig.validaters['googledrive'] = EditUriBackendConfig.validaters['authid-base']; EditUriBackendConfig.validaters['gcs'] = EditUriBackendConfig.validaters['authid-base']; - EditUriBackendConfig.validaters['amzcd'] = EditUriBackendConfig.validaters['authid-base']; EditUriBackendConfig.validaters['box'] = EditUriBackendConfig.validaters['authid-base']; EditUriBackendConfig.validaters['dropbox'] = EditUriBackendConfig.validaters['authid-base']; EditUriBackendConfig.validaters['onedrive'] = EditUriBackendConfig.validaters['authid-base']; diff --git a/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js b/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js index 8ec89f270..b83792e88 100644 --- a/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js +++ b/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js @@ -64,7 +64,6 @@ backupApp.service('SystemInfo', function($rootScope, $timeout, $cookies, AppServ 'gcs': null, 'openstack': null, 'hubic': null, - 'amzcd': null, 'b2': null, 'mega': null, 'box': null, diff --git a/Duplicati/Server/webroot/ngax/templates/backends/amzcd.html b/Duplicati/Server/webroot/ngax/templates/backends/amzcd.html deleted file mode 100644 index 4104fde5c..000000000 --- a/Duplicati/Server/webroot/ngax/templates/backends/amzcd.html +++ /dev/null @@ -1,15 +0,0 @@ -

WARNING: Amazon Cloud Drive API is closing August 16th 2019

-

Do not use this destination for new backups, and migrate any existing backups away before this date

- -
- - -
- -
- - -
diff --git a/Installer/Docker/README.md b/Installer/Docker/README.md index ffcf4527e..8d42e54e6 100644 --- a/Installer/Docker/README.md +++ b/Installer/Docker/README.md @@ -1,7 +1,7 @@ # [Duplicati](https://www.duplicati.com) Duplicati is a free, open source, backup client that securely stores encrypted, incremental, compressed backups on cloud storage services and remote file servers. It works with: -*Amazon S3, OneDrive, Google Drive, Rackspace Cloud Files, HubiC, Backblaze (B2), Amazon Cloud Drive (AmzCD), Swift / OpenStack, WebDAV, SSH (SFTP), FTP, and more!* +*Amazon S3, OneDrive, Google Drive, Rackspace Cloud Files, HubiC, Backblaze (B2), Swift / OpenStack, WebDAV, SSH (SFTP), FTP, and more!* Duplicati is licensed under LGPL and available for Windows, OSX and Linux (.NET 4.6.2+ or Mono 4.8.0+ required). diff --git a/README.md b/README.md index 5b4182704..3f1a6b0d2 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Removed Gitter Duplicati is a free, open source, backup client that securely stores encrypted, incremental, compressed backups on cloud storage services and remote file servers. It works with: -   *Amazon Cloud Drive and S3, [Backblaze (B2)](https://www.backblaze.com/blog/duplicati-backups-cloud-storage/ "Duplicati with Backblaze B2 Cloud Storage"), Box, Dropbox, FTP, Google Cloud and Drive, HubiC, MEGA, Microsoft Azure and OneDrive, Rackspace Cloud Files, OpenStack Storage (Swift), Sia, SSH (SFTP), WebDAV, [and more!](https://duplicati.readthedocs.io/en/latest/01-introduction/#supported-backends)* +   *Amazon S3, [Backblaze (B2)](https://www.backblaze.com/blog/duplicati-backups-cloud-storage/ "Duplicati with Backblaze B2 Cloud Storage"), Box, Dropbox, FTP, Google Cloud and Drive, HubiC, MEGA, Microsoft Azure and OneDrive, Rackspace Cloud Files, OpenStack Storage (Swift), Sia, SSH (SFTP), WebDAV, [and more!](https://duplicati.readthedocs.io/en/latest/01-introduction/#supported-backends)* Duplicati is licensed under LGPL and available for Windows, OSX and Linux (.NET 4.6.2+ or Mono 4.8.0+ required).