Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/duplicati/duplicati.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Skovhede <kenneth@hexad.dk>2022-06-15 00:07:24 +0300
committerKenneth Skovhede <kenneth@hexad.dk>2022-06-15 00:07:24 +0300
commitf1cdd63e3242bb85772b50ba94676951083a1b7d (patch)
tree519f28057d38cd56eec9edb67bddb50055c10bf3
parent81cbb05a8ec5989152712172621694fa10657d59 (diff)
Removed `IDrive` backend in favor of `IDrivee2` which is using the S3 API
-rw-r--r--Duplicati/Library/Backend/IDrive/Duplicati.Library.Backend.IDrive.csproj66
-rw-r--r--Duplicati/Library/Backend/IDrive/Duplicati.snkbin596 -> 0 bytes
-rw-r--r--Duplicati/Library/Backend/IDrive/IDriveApiClient.cs393
-rw-r--r--Duplicati/Library/Backend/IDrive/IDriveBackend.cs212
-rw-r--r--Duplicati/Library/Backend/IDrive/Properties/AssemblyInfo.cs43
-rw-r--r--Duplicati/Library/Backend/IDrive/Strings.cs18
-rw-r--r--Duplicati/Library/Backend/IDrive/app.config10
7 files changed, 0 insertions, 742 deletions
diff --git a/Duplicati/Library/Backend/IDrive/Duplicati.Library.Backend.IDrive.csproj b/Duplicati/Library/Backend/IDrive/Duplicati.Library.Backend.IDrive.csproj
deleted file mode 100644
index c49153699..000000000
--- a/Duplicati/Library/Backend/IDrive/Duplicati.Library.Backend.IDrive.csproj
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{C16639F6-DACC-4DD9-86CD-8B937516B340}</ProjectGuid>
- <OutputType>Library</OutputType>
- <RootNamespace>Duplicati.Library.Backend.IDrive</RootNamespace>
- <AssemblyName>Duplicati.Library.Backend.IDrive</AssemblyName>
- <AssemblyOriginatorKeyFile>Duplicati.snk</AssemblyOriginatorKeyFile>
- <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
- <UseMSBuildEngine>false</UseMSBuildEngine>
- <TargetFrameworkProfile />
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug</OutputPath>
- <DefineConstants>DEBUG;</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>full</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release</OutputPath>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <ConsolePause>false</ConsolePause>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Net.Http" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="IDriveApiClient.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="IDriveBackend.cs" />
- <Compile Include="Strings.cs" />
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <ItemGroup>
- <ProjectReference Include="..\..\Interface\Duplicati.Library.Interface.csproj">
- <Project>{C5899F45-B0FF-483C-9D38-24A9FCAAB237}</Project>
- <Name>Duplicati.Library.Interface</Name>
- </ProjectReference>
- <ProjectReference Include="..\..\Localization\Duplicati.Library.Localization.csproj">
- <Project>{B68F2214-951F-4F78-8488-66E1ED3F50BF}</Project>
- <Name>Duplicati.Library.Localization</Name>
- </ProjectReference>
- <ProjectReference Include="..\..\Utility\Duplicati.Library.Utility.csproj">
- <Project>{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}</Project>
- <Name>Duplicati.Library.Utility</Name>
- </ProjectReference>
- <ProjectReference Include="..\..\Common\Duplicati.Library.Common.csproj">
- <Project>{D63E53E4-A458-4C2F-914D-92F715F58ACF}</Project>
- <Name>Duplicati.Library.Common</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <None Include="app.config" />
- </ItemGroup>
-</Project> \ No newline at end of file
diff --git a/Duplicati/Library/Backend/IDrive/Duplicati.snk b/Duplicati/Library/Backend/IDrive/Duplicati.snk
deleted file mode 100644
index e0c1e2dd8..000000000
--- a/Duplicati/Library/Backend/IDrive/Duplicati.snk
+++ /dev/null
Binary files differ
diff --git a/Duplicati/Library/Backend/IDrive/IDriveApiClient.cs b/Duplicati/Library/Backend/IDrive/IDriveApiClient.cs
deleted file mode 100644
index b37af6677..000000000
--- a/Duplicati/Library/Backend/IDrive/IDriveApiClient.cs
+++ /dev/null
@@ -1,393 +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 System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.IO;
-using System.Linq;
-using System.Net.Http;
-using System.Reflection;
-using System.Security.Authentication;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-// Full IDrive Sync API documentation can be found here: https://www.idrivesync.com/evs/web-developers-guide.htm
-namespace Duplicati.Library.Backend.IDrive
-{
- /// <summary>
- /// Provides access to an IDrive Sync.
- /// </summary>
- public class IDriveApiClient
- {
- private const string IDRIVE_AUTH_CGI_URL = "https://www1.idrive.com/cgi-bin/v1/user-details.cgi";
- private const string IDRIVE_SYNC_GET_SERVER_ADDRESS_URL = "https://evs.idrivesync.com/evs/getServerAddress";
- private const string SUCCESS = "SUCCESS";
- private const string MESSAGE_ATTRIBUTE = "message";
- private const string XML_RESPONSE_TAG = "tree";
-
- private string _idriveUsername;
- private string _idrivePassword;
-
- private string _syncUsername;
- private string _syncPassword;
- private string _syncHostname;
-
- private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
- private static SemaphoreSlim UploadSemaphore = new SemaphoreSlim(10);
-
- public string UserAgent { get; set; } = "Duplicati-IDrive-API-Client/" + Assembly.GetExecutingAssembly().GetName().Version;
-
- public IDriveApiClient()
- {
- }
-
- public async Task LoginAsync(string username, string password)
- {
- _idriveUsername = username;
- _idrivePassword = password;
-
- await IDriveAuthAsync(_cancellationTokenSource.Token);
- await UpdateSyncHostnameAsync(_cancellationTokenSource.Token);
- }
-
- private async Task IDriveAuthAsync(CancellationToken cancellationToken)
- {
- // IDrive auth logic was reverse engineered from code found in the IDriveForLinux PERL scripts provided by IDrive. Download from: https://www.idrive.com/linux-backup-scripts
- // The auth response payload contains the login credentials for the associated IDrive Sync account.
- const string methodName = IDRIVE_AUTH_CGI_URL;
- using (var httpClient = GetHttpClient())
- {
- var parameters = new List<KeyValuePair<string, string>>() {
- new KeyValuePair<string, string> ( "username", _idriveUsername),
- new KeyValuePair<string, string> ( "password", _idrivePassword)
- };
- var content = new FormUrlEncodedContent(parameters);
- using (var response = await httpClient.PostAsync(IDRIVE_AUTH_CGI_URL, content))
- {
- if (response.StatusCode != System.Net.HttpStatusCode.OK)
- throw new AuthenticationException($"Failed IDrive authentication request. Server response: {response}");
-
- // Sample response (masked): "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<root>\n <login remote_manage_ip=\"173.255.13.30\" quota=\"5000000000000\" datacenter=\"evsvirginia.idrive.com\" enctype=\"DEFAULT\" pns_sync=\"notify2.idrive.com\" remote_manage_server_https=\"wsn16s.idrive.com\" jspsrvr=\"www.idrive.com\" plan_type=\"Regular\" dedup=\"on\" username_sync=\"abc12345678901234def\" password_sync=\"fed09887654321098cba\" dedup_enabled=\"no\" desc=\"Success\" evssrvrip=\"148.51.142.138\" plan=\"Personal\" acctype=\"IBSYNC\" cnfgstat=\"SET\" accstat=\"Y\" evswebsrvr=\"evsweb5114.idrive.com\" remote_manage_websock_server=\"yes\" evssrvr=\"evs5114.idrive.com\" message=\"SUCCESS\" remote_manage_ip_https=\"173.255.13.31\" cnfgstatus=\"Y\" remote_manage_server=\"wsn16.idrive.com\" evswebsrvrip=\"148.51.142.139\" quota_used=\"100000000000\"></login>\n</root>\n"
- string responseString = await response.Content.ReadAsStringAsync();
- var responseXml = new XmlDocument();
- responseXml.LoadXml(responseString);
- var nodes = responseXml.GetElementsByTagName("login");
- if (nodes.Count == 0)
- throw new AuthenticationException($"Failed '{methodName}' request. Unexpected authentication response data (no login element). Server response: {response}");
-
- var responseNode = nodes[0];
-
- if (responseNode.Attributes[MESSAGE_ATTRIBUTE]?.Value != SUCCESS)
- throw new AuthenticationException($"Failed IDrive authentication request. Non-{SUCCESS}. Description: {responseNode.Attributes["desc"]?.Value}");
-
- _syncUsername = responseNode.Attributes["username_sync"]?.Value;
- _syncPassword = responseNode.Attributes["password_sync"]?.Value;
-
- if (string.IsNullOrEmpty(_syncUsername) || string.IsNullOrEmpty(_syncPassword))
- throw new AuthenticationException($"Failed '{methodName}' request. IDrive Sync username and/or password were not provided. Server response: {response}");
- }
- }
- }
-
- private async Task UpdateSyncHostnameAsync(CancellationToken cancellationToken)
- {
- // The API docs state that the sync web API server may change over time and must be retrieved on each login.
- // The server may be different for different accounts, depending where the data is stored.
- var responseNode = await GetSimpleTreeResponseAsync(IDRIVE_SYNC_GET_SERVER_ADDRESS_URL, "getServerAddress", cancellationToken);
-
- _syncHostname = responseNode.Attributes["webApiServer"]?.Value;
-
- if (string.IsNullOrEmpty(_syncHostname))
- throw new AuthenticationException($"Failed 'getServerAddress' request. Empty hostname. Tree XML: {responseNode.OuterXml}");
- }
-
- public async Task<List<FileEntry>> GetFileEntryListAsync(string directoryPath, string searchCriteria = null)
- {
- string methodName = string.IsNullOrEmpty(searchCriteria) ? "browseFolder" : "searchFiles";
- // NOTE: The IDrive "searchFiles" API method has a bug that returns the name of the directory being listed as one of the items when searching for "*"
- string url = GetSyncServiceUrl(methodName);
- var list = new List<FileEntry>();
-
- using (var httpClient = GetHttpClient())
- using (var content = GetSyncPostContent(new NameValueCollection { { "p", directoryPath }, { "searchkey", searchCriteria } }))
- using (var response = await httpClient.PostAsync(url, content))
- {
- if (response.StatusCode != System.Net.HttpStatusCode.OK)
- throw new ApplicationException($"Failed '{methodName}' request. Server response: {response}");
-
- using (var responseStream = await response.Content.ReadAsStreamAsync())
- using (var xmlReader = XmlReader.Create(responseStream, new XmlReaderSettings() { Async = true }))
- {
- bool success = false;
- while (await xmlReader.ReadAsync())
- {
- if (xmlReader.Name != XML_RESPONSE_TAG)
- continue;
-
- success = xmlReader.GetAttribute(MESSAGE_ATTRIBUTE) == SUCCESS;
- break;
- }
-
- if (!success)
- throw new ApplicationException($"Failed '{methodName}' request. Non-{SUCCESS}. Description: {xmlReader.GetAttribute("desc")}");
-
- while (await xmlReader.ReadAsync())
- {
- // Item XML example: <item restype="1" resname="Myoffice.txt" size="9583" lmd="2010/05/26 01:58:57" ver="1" thumb="N"/>
- if (xmlReader.Name != "item")
- continue;
-
- string resname = xmlReader.GetAttribute("resname");
- if (string.IsNullOrEmpty(resname))
- continue;
-
- string restype = xmlReader.GetAttribute("restype");
- string size = xmlReader.GetAttribute("size");
- string lmd = xmlReader.GetAttribute("lmd");
-
- long.TryParse(size, out long parsedSize);
- DateTime.TryParse(lmd, out DateTime parsedModificationDate);
-
- var fileEntry = new FileEntry(resname)
- {
- IsFolder = restype != "1",
- Name = resname,
- Size = parsedSize,
- LastModification = parsedModificationDate
- };
-
- list.Add(fileEntry);
- }
- }
- }
-
- return list;
- }
-
- public async Task CreateDirectoryAsync(string directoryName, string baseDirectoryPath, CancellationToken cancellationToken)
- {
- const string methodName = "createFolder";
- string url = GetSyncServiceUrl(methodName);
- try
- {
- await GetSimpleTreeResponseAsync(url, methodName, cancellationToken, new NameValueCollection { { "p", baseDirectoryPath }, { "foldername", directoryName } });
- }
- catch (Exception ex)
- {
- if (ex.Message.Contains(@"FOLDER ALREADY EXISTS WITH THIS NAME."))
- return;
-
- throw;
- }
- }
-
- public async Task DeleteAsync(string filePath, CancellationToken cancellationToken, bool moveToTrash = true)
- {
- const string methodName = "deleteFile";
- string url = GetSyncServiceUrl(methodName);
- await GetSimpleTreeResponseAsync(url, methodName, cancellationToken, new NameValueCollection { { "p", filePath }, { "trash", moveToTrash ? "yes" : "no" } });
- }
-
- public async Task<FileEntry> UploadAsync(Stream stream, string filename, string directoryPath, CancellationToken cancellationToken)
- {
- const string methodName = "uploadFile";
- string url = GetSyncServiceUrl(methodName);
-
- await UploadSemaphore.WaitAsync(cancellationToken);
-
- try
- {
- if (cancellationToken.IsCancellationRequested)
- throw new OperationCanceledException();
-
- long? streamLength = null;
- try { streamLength = stream.Length; }
- catch { } // Fail gracefully is stream does not support Length
-
- using (var httpClient = GetHttpClient(TimeSpan.FromHours(24)))
- using (var content = GetSyncPostContent(new NameValueCollection { { "p", directoryPath } }, isMultiPart: true))
- using (var streamContent = new StreamContent(stream))
- {
- ((MultipartFormDataContent)content).Add(streamContent, filename, filename);
-
- using (var response = await httpClient.PostAsync(url, content, cancellationToken))
- {
- if (cancellationToken.IsCancellationRequested)
- throw new OperationCanceledException();
-
- if (response.StatusCode != System.Net.HttpStatusCode.OK)
- throw new ApplicationException($"Failed '{methodName}' request. Server response: {response}");
-
- string responseString = await response.Content.ReadAsStringAsync();
- var responseXml = new XmlDocument();
- responseXml.LoadXml(responseString);
- var nodes = responseXml.GetElementsByTagName(XML_RESPONSE_TAG);
- if (nodes.Count == 0)
- throw new ApplicationException($"Failed '{methodName}' request. Unexpected response. Server response: {response}");
-
- var responseNode = nodes[0];
- if (responseNode == null)
- throw new ApplicationException($"Failed '{methodName}' request. Missing {XML_RESPONSE_TAG} node. Server response: {response}");
-
- if (responseNode.Attributes[MESSAGE_ATTRIBUTE]?.Value != SUCCESS)
- throw new ApplicationException($"Failed '{methodName}' request. Non-{SUCCESS}. Description: {responseNode.Attributes["desc"]?.Value}");
- }
- }
-
- // Double check the upload by searching for the file on the server and validating the response
- var fileEntryList = await GetFileEntryListAsync(directoryPath, filename);
- if (fileEntryList.Count != 1)
- throw new FileMissingException($"Upload failed. File not found on server.");
-
- var fileEntry = fileEntryList[0];
-
- if (streamLength != null && fileEntry.Size != streamLength.Value)
- throw new FileMissingException($"Upload failed. File size on server does not match source.");
-
- if (fileEntry.Name != filename)
- throw new FileMissingException($"Upload failed. Wrong file not found on server."); // this should never happen
-
- return fileEntry;
- }
- finally
- {
- UploadSemaphore.Release();
- }
- }
-
- public async Task DownloadAsync(string filePath, Stream stream)
- {
- const string methodName = "downloadFile";
- string url = GetSyncServiceUrl(methodName);
-
- using (var httpClient = GetHttpClient())
- using (var content = GetSyncPostContent(new NameValueCollection { { "p", filePath } }))
- using (var response = await httpClient.PostAsync(url, content))
- {
- if (response.StatusCode != System.Net.HttpStatusCode.OK)
- throw new FileMissingException($"Failed '{methodName}' request. Server response: {response}");
-
- response.Headers.TryGetValues("RESTORE_STATUS", out var restoreStatus); // The download API uses RESTORE_STATUS to indicate success instead of body XML
-
- using (var responseStream = await response.Content.ReadAsStreamAsync())
- {
- if (restoreStatus.FirstOrDefault() == SUCCESS)
- {
- Library.Utility.Utility.CopyStream(responseStream, stream);
- return;
- }
-
- using (var xmlReader = XmlReader.Create(responseStream, new XmlReaderSettings() { Async = true }))
- {
- bool success = false;
- while (await xmlReader.ReadAsync())
- {
- if (xmlReader.Name != XML_RESPONSE_TAG)
- continue;
-
- success = xmlReader.GetAttribute(MESSAGE_ATTRIBUTE) == SUCCESS;
- break;
- }
-
- if (!success)
- throw new FileMissingException($"Failed '{methodName}' request. Non-{SUCCESS}. Description: {xmlReader.GetAttribute("desc")}");
-
- throw new FileMissingException($"Failed '{methodName}' request. Invalid RESTORE_STATUS result with invalid {SUCCESS} message."); // this should never happen
- }
- }
- }
- }
-
- private HttpClient GetHttpClient(TimeSpan? timeout = null)
- {
- var httpClient = new HttpClient()
- {
- Timeout = timeout ?? TimeSpan.FromMinutes(5) // more generous default timeout
- };
-
- if (!string.IsNullOrEmpty(UserAgent))
- httpClient.DefaultRequestHeaders.Add("User-Agent", UserAgent);
-
- return httpClient;
- }
-
- private string GetSyncServiceUrl(string serviceName)
- {
- return $"https://{_syncHostname}/evs/{serviceName}";
- }
-
- private async Task<XmlNode> GetSimpleTreeResponseAsync(string url, string methodName, CancellationToken cancellationToken, NameValueCollection parameters = null)
- {
- using (var httpClient = GetHttpClient())
- using (var content = GetSyncPostContent(parameters))
- using (var response = await httpClient.PostAsync(url, content, cancellationToken))
- {
- if (response.StatusCode != System.Net.HttpStatusCode.OK)
- throw new ApplicationException($"Failed '{methodName}' request. Server response: {response}");
-
- // Sample response: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<tree message=\"SUCCESS\" cmdUtilityServer=\"evs19.idrivesync.com\"\n cmdUtilityServerIP=\"4.71.135.136\"\n webApiServer=\"evsweb19.idrivesync.com\" webApiServerIP=\"4.71.135.137\"\n faceWebApiServer=\"\" faceWebApiServerIP=\"\" dedup=\"off\"/>\n"
- string responseString = await response.Content.ReadAsStringAsync();
- var responseXml = new XmlDocument();
- responseXml.LoadXml(responseString);
- var nodes = responseXml.GetElementsByTagName(XML_RESPONSE_TAG);
- if (nodes.Count == 0)
- throw new ApplicationException($"Failed '{methodName}' request. Unexpected response. Server response: {response}");
-
- var responseNode = nodes[0];
- if (responseNode == null)
- throw new ApplicationException($"Failed '{methodName}' request. Missing {XML_RESPONSE_TAG} node. Server response: {response}");
-
- if (responseNode.Attributes[MESSAGE_ATTRIBUTE]?.Value != SUCCESS)
- throw new ApplicationException($"Failed '{methodName}' request. Non-{SUCCESS}. Description: {responseNode.Attributes["desc"]?.Value}");
-
- return responseNode;
- }
- }
-
- private HttpContent GetSyncPostContent(NameValueCollection parameters = null, bool isMultiPart = false)
- {
- var allParameters = new List<KeyValuePair<string, string>>()
- {
- new KeyValuePair<string, string> ( "uid", _syncUsername),
- new KeyValuePair<string, string> ( "pwd", _syncPassword)
- };
-
- if (parameters != null)
- {
- foreach (string key in parameters.Keys)
- {
- allParameters.Add(new KeyValuePair<string, string>(key, parameters[key]));
- }
- }
-
- if (!isMultiPart)
- return new FormUrlEncodedContent(allParameters);
-
- var content = new MultipartFormDataContent(Guid.NewGuid().ToString());
- foreach (var parameter in allParameters)
- {
- content.Add(new StringContent(parameter.Value, Encoding.UTF8), parameter.Key);
- }
-
- return content;
- }
- }
-}
diff --git a/Duplicati/Library/Backend/IDrive/IDriveBackend.cs b/Duplicati/Library/Backend/IDrive/IDriveBackend.cs
deleted file mode 100644
index ba8561289..000000000
--- a/Duplicati/Library/Backend/IDrive/IDriveBackend.cs
+++ /dev/null
@@ -1,212 +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 System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Duplicati.Library.Backend.IDrive
-{
- // ReSharper disable once UnusedMember.Global
- // This class is instantiated dynamically in the BackendLoader.
- public class IDriveBackend : IBackend, IStreamingBackend
- {
- private readonly string _username = null;
- private readonly string _password = null;
- private readonly string _baseDirectoryPath = null;
- public string DisplayName => Strings.IDriveBackend.DisplayName;
- public string Description => Strings.IDriveBackend.Description;
- public string[] DNSName => null;
- public string ProtocolKey => "idrive";
- CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
-
- public IList<ICommandLineArgument> SupportedCommands
- {
- get
- {
- return new List<ICommandLineArgument>(new ICommandLineArgument[] {
- new CommandLineArgument("auth-password", CommandLineArgument.ArgumentType.Password, Strings.IDriveBackend.AuthPasswordDescriptionShort, Strings.IDriveBackend.AuthPasswordDescriptionLong),
- new CommandLineArgument("auth-username", CommandLineArgument.ArgumentType.String, Strings.IDriveBackend.AuthUsernameDescriptionShort, Strings.IDriveBackend.AuthUsernameDescriptionLong)
- });
- }
- }
-
- private Dictionary<string, FileEntry> _fileCache;
- protected Dictionary<string, FileEntry> FileCache
- {
- get
- {
- if (_fileCache == null)
- ResetFileCacheAsync().Wait();
-
- return _fileCache;
- }
- set
- {
- _fileCache = value;
- }
- }
-
- private IDriveApiClient _client;
- protected IDriveApiClient Client
- {
- get
- {
- if (_client == null)
- {
- var cl = new IDriveApiClient();
- cl.LoginAsync(_username, _password).Wait();
- _client = cl;
- }
-
- return _client;
- }
- }
-
- public IDriveBackend()
- {
- }
-
- public IDriveBackend(string url, Dictionary<string, string> options)
- {
- var uri = new Utility.Uri(url); // Sample url: idrive://Directory1/SubDirectory1?auth-username=MyUsername&auth-password=MyPassword
- _username = uri.Username;
- _password = uri.Password;
-
- if (string.IsNullOrEmpty(_username) && options.TryGetValue("auth-username", out string username))
- _username = username;
- if (string.IsNullOrEmpty(_password) && options.TryGetValue("auth-password", out string password))
- _password = password;
-
- if (string.IsNullOrEmpty(_username))
- throw new UserInformationException(Strings.IDriveBackend.NoUsernameError, "IDriveNoUsername");
- if (string.IsNullOrEmpty(_password))
- throw new UserInformationException(Strings.IDriveBackend.NoPasswordError, "IDriveNoPassword");
-
- _baseDirectoryPath = ("/" + (uri.HostAndPath ?? "").Trim('/') + "/").Replace("//", "/");
- }
-
- private async Task ResetFileCacheAsync()
- {
- FileCache = (await Client.GetFileEntryListAsync(_baseDirectoryPath))
- .Where(x => !x.IsFolder)
- .ToDictionary(x => x.Name, x => x);
- }
-
- public IEnumerable<IFileEntry> List()
- {
- return FileCache.Values;
- }
-
- public void Get(string filename, string localFilePath)
- {
- using (var fileStream = File.Create(localFilePath))
- Get(filename, fileStream);
- }
-
- public void Get(string filename, Stream stream)
- {
- Client.DownloadAsync(Path.Combine(_baseDirectoryPath, filename), stream).Wait();
- }
-
- public async Task PutAsync(string filename, string localFilePath, CancellationToken cancellationToken)
- {
- using (var fileStream = File.OpenRead(localFilePath))
- await PutAsync(filename, fileStream, cancellationToken);
- }
-
- public async Task PutAsync(string filename, Stream stream, CancellationToken cancellationToken)
- {
- try
- {
- var fileEntry = await Client.UploadAsync(stream, filename, _baseDirectoryPath, cancellationToken);
- FileCache[filename] = fileEntry;
- }
- catch
- {
- FileCache = null;
- throw;
- }
- }
-
- public void Delete(string filename)
- {
- try
- {
- if (!FileCache.ContainsKey(filename))
- {
- ResetFileCacheAsync().Wait();
-
- if (!FileCache.ContainsKey(filename))
- throw new FileMissingException();
- }
-
- Client.DeleteAsync(Path.Combine(_baseDirectoryPath, filename), _cancellationTokenSource.Token, false).Wait();
-
- FileCache.Remove(filename);
- }
- catch
- {
- FileCache = null;
- throw;
- }
- }
-
- public void CreateFolder()
- {
- var directoryParts = _baseDirectoryPath.Split('/').Where(d => !string.IsNullOrEmpty(d));
- string baseDirectory = "/";
-
- foreach (string directoryPart in directoryParts)
- {
- Client.CreateDirectoryAsync(directoryPart, baseDirectory, _cancellationTokenSource.Token).Wait();
- baseDirectory += directoryPart + "/";
- }
- }
-
- public void Test()
- {
- this.TestList();
- }
-
- #region IDisposable Support
- private bool _disposedValue = false; // To detect redundant calls
-
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposedValue)
- {
- if (disposing)
- {
- }
-
- _disposedValue = true;
- }
- }
-
- // This code added to correctly implement the disposable pattern.
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- Dispose(true);
- }
- #endregion
- }
-}
diff --git a/Duplicati/Library/Backend/IDrive/Properties/AssemblyInfo.cs b/Duplicati/Library/Backend/IDrive/Properties/AssemblyInfo.cs
deleted file mode 100644
index 80c373101..000000000
--- a/Duplicati/Library/Backend/IDrive/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (C) 2022, 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 System.Reflection;
-using System.Runtime.CompilerServices;
-
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
-
-[assembly: AssemblyTitle("Duplicati.Library.Backend.IDrive")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("Doug Krahmer")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-
-[assembly: AssemblyVersion("2.0.0.1")]
-
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-
diff --git a/Duplicati/Library/Backend/IDrive/Strings.cs b/Duplicati/Library/Backend/IDrive/Strings.cs
deleted file mode 100644
index 9bb775e29..000000000
--- a/Duplicati/Library/Backend/IDrive/Strings.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Duplicati.Library.Localization.Short;
-
-namespace Duplicati.Library.Backend.Strings
-{
- internal static class IDriveBackend
- {
- public static string DisplayName { get { return LC.L(@"IDrive"); } }
- public static string AuthPasswordDescriptionLong { get { return LC.L(@"The password used to connect to the server. This may also be supplied as the environment variable ""AUTH_PASSWORD""."); } }
- public static string AuthPasswordDescriptionShort { get { return LC.L(@"Supplies the password used to connect to the server"); } }
- public static string AuthUsernameDescriptionLong { get { return LC.L(@"The username used to connect to the server. This may also be supplied as the environment variable ""AUTH_USERNAME""."); } }
- public static string AuthUsernameDescriptionShort { get { return LC.L(@"Supplies the username used to connect to the server"); } }
- public static string AuthTwoFactorKeyDescriptionShort { get { return LC.L(@"The shared secret used to generate two-factor TOTP codes."); } }
- public static string AuthTwoFactorKeyDescriptionLong { get { return LC.L(@"For accounts with two-factor authentication enabled, this is the shared secret used to generate the two-factor TOTP codes."); } }
- public static string NoPasswordError { get { return LC.L(@"No password given"); } }
- public static string NoUsernameError { get { return LC.L(@"No username given"); } }
- public static string Description { get { return LC.L(@"This backend can read and write data to IDrive Sync. Allowed formats are: ""idrive://folder/subfolder"""); } }
- }
-} \ No newline at end of file
diff --git a/Duplicati/Library/Backend/IDrive/app.config b/Duplicati/Library/Backend/IDrive/app.config
deleted file mode 100644
index ad53561b2..000000000
--- a/Duplicati/Library/Backend/IDrive/app.config
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
- <startup>
- <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1" />
- </startup>
- <runtime>
- <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- </assemblyBinding>
- </runtime>
-</configuration>