Merge pull request #4492 from TopperDEL/storj-dcs-update
Add Storj DCS backend and deprecated Tardigrade DCS backend. Storj renamed their "Tardigrade Decentralized Cloud Storage" product to "Storj DCS". This adds a new Storj DCS backend and deprecates the old Tardigrade one. A warning is issued to inform Tardigrade users to modify their configurations to use the new backend. This also adds a passphrase verification field to ensure that the user has provided the correct encryption passphrase.
This commit is contained in:
+7
-1
@@ -101,10 +101,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.CommandLine.Confi
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Encryption", "Duplicati\Library\Encryption\Duplicati.Library.Encryption.csproj", "{2CF2D90E-C25B-47AD-91E0-98451BAB8058}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Tardigrade", "Duplicati\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj", "{AE035E01-C917-4F13-A35E-78F21C1A2F17}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Storj", "Duplicati\Library\Backend\Storj\Duplicati.Library.Backend.Storj.csproj", "{AE035E01-C917-4F13-A35E-78F21C1A2F17}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.TencentCOS", "Duplicati\Library\Backend\TencentCOS\Duplicati.Library.Backend.TencentCOS.csproj", "{545DD6D4-9476-42D6-B51C-A28E000C489E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Tardigrade", "Duplicati\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj", "{9A04CB37-DA72-4008-9703-3AC5191974E9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -315,6 +317,10 @@ Global
|
||||
{545DD6D4-9476-42D6-B51C-A28E000C489E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{545DD6D4-9476-42D6-B51C-A28E000C489E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{545DD6D4-9476-42D6-B51C-A28E000C489E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9A04CB37-DA72-4008-9703-3AC5191974E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9A04CB37-DA72-4008-9703-3AC5191974E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9A04CB37-DA72-4008-9703-3AC5191974E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9A04CB37-DA72-4008-9703-3AC5191974E9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -86,8 +86,12 @@
|
||||
<Project>{32a74526-3e5f-413a-8cb4-1efdad4c8b91}</Project>
|
||||
<Name>Duplicati.Library.Backend.Sia</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<ProjectReference Include="..\..\Library\Backend\Storj\Duplicati.Library.Backend.Storj.csproj">
|
||||
<Project>{ae035e01-c917-4f13-a35e-78f21c1a2f17}</Project>
|
||||
<Name>Duplicati.Library.Backend.Storj</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<Project>{9a04cb37-da72-4008-9703-3ac5191974e9}</Project>
|
||||
<Name>Duplicati.Library.Backend.Tardigrade</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\TencentCOS\Duplicati.Library.Backend.TencentCOS.csproj">
|
||||
|
||||
@@ -92,8 +92,12 @@
|
||||
<Project>{C0270709-2A40-43B5-8CF1-69581B9FA2A1}</Project>
|
||||
<Name>Duplicati.Library.Backend.TahoeLAFS</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<ProjectReference Include="..\..\Library\Backend\Storj\Duplicati.Library.Backend.Storj.csproj">
|
||||
<Project>{ae035e01-c917-4f13-a35e-78f21c1a2f17}</Project>
|
||||
<Name>Duplicati.Library.Backend.Storj</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<Project>{9a04cb37-da72-4008-9703-3ac5191974e9}</Project>
|
||||
<Name>Duplicati.Library.Backend.Tardigrade</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\TencentCOS\Duplicati.Library.Backend.TencentCOS.csproj">
|
||||
|
||||
@@ -111,6 +111,10 @@
|
||||
<Project>{32a74526-3e5f-413a-8cb4-1efdad4c8b91}</Project>
|
||||
<Name>Duplicati.Library.Backend.Sia</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<Project>{9a04cb37-da72-4008-9703-3ac5191974e9}</Project>
|
||||
<Name>Duplicati.Library.Backend.Tardigrade</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Compression\Duplicati.Library.Compression.csproj">
|
||||
<Project>{19ECCE09-B5EB-406C-8C57-BAC66997D469}</Project>
|
||||
<Name>Duplicati.Library.Compression</Name>
|
||||
@@ -231,9 +235,9 @@
|
||||
<Project>{D63E53E4-A458-4C2F-914D-92F715F58ACF}</Project>
|
||||
<Name>Duplicati.Library.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<ProjectReference Include="..\Library\Backend\Storj\Duplicati.Library.Backend.Storj.csproj">
|
||||
<Project>{AE035E01-C917-4F13-A35E-78F21C1A2F17}</Project>
|
||||
<Name>Duplicati.Library.Backend.Tardigrade</Name>
|
||||
<Name>Duplicati.Library.Backend.Storj</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -256,4 +260,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -134,6 +134,10 @@
|
||||
<Project>{C0270709-2A40-43B5-8CF1-69581B9FA2A1}</Project>
|
||||
<Name>Duplicati.Library.Backend.TahoeLAFS</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<Project>{9a04cb37-da72-4008-9703-3ac5191974e9}</Project>
|
||||
<Name>Duplicati.Library.Backend.Tardigrade</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\WEBDAV\Duplicati.Library.Backend.WEBDAV.csproj">
|
||||
<Project>{BAE27510-8B5D-44B2-B33E-372A98908041}</Project>
|
||||
<Name>Duplicati.Library.Backend.WEBDAV</Name>
|
||||
@@ -182,9 +186,9 @@
|
||||
<Project>{D63E53E4-A458-4C2F-914D-92F715F58ACF}</Project>
|
||||
<Name>Duplicati.Library.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<ProjectReference Include="..\..\Library\Backend\Storj\Duplicati.Library.Backend.Storj.csproj">
|
||||
<Project>{AE035E01-C917-4F13-A35E-78F21C1A2F17}</Project>
|
||||
<Name>Duplicati.Library.Backend.Tardigrade</Name>
|
||||
<Name>Duplicati.Library.Backend.Storj</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -217,8 +217,12 @@
|
||||
<Project>{C0270709-2A40-43B5-8CF1-69581B9FA2A1}</Project>
|
||||
<Name>Duplicati.Library.Backend.TahoeLAFS</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<ProjectReference Include="..\..\Library\Backend\Storj\Duplicati.Library.Backend.Storj.csproj">
|
||||
<Project>{ae035e01-c917-4f13-a35e-78f21c1a2f17}</Project>
|
||||
<Name>Duplicati.Library.Backend.Storj</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<Project>{9a04cb37-da72-4008-9703-3ac5191974e9}</Project>
|
||||
<Name>Duplicati.Library.Backend.Tardigrade</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\TencentCOS\Duplicati.Library.Backend.TencentCOS.csproj">
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{AE035E01-C917-4F13-A35E-78F21C1A2F17}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Duplicati.Library.Backend.Storj</RootNamespace>
|
||||
<AssemblyName>Duplicati.Library.Backend.Storj</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SQLite-net, Version=1.7.335.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\sqlite-net-pcl.1.7.335\lib\netstandard2.0\SQLite-net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.batteries_v2, Version=2.0.3.851, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.batteries_v2.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.core, Version=2.0.3.851, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\SQLitePCLRaw.core.2.0.3\lib\netstandard2.0\SQLitePCLRaw.core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.nativelibrary, Version=2.0.3.851, Culture=neutral, PublicKeyToken=502ed628492ab262, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.nativelibrary.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.provider.dynamic_cdecl, Version=2.0.3.851, Culture=neutral, PublicKeyToken=b68184102cba0b3b, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.3\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="uplink.NET, Version=2.7.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\uplink.NET.2.7.1604\lib\netstandard2.0\uplink.NET.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="StorjFile.cs" />
|
||||
<Compile Include="Strings.cs" />
|
||||
<Compile Include="StorjBackend.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="StorjConfig.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Common\Duplicati.Library.Common.csproj">
|
||||
<Project>{d63e53e4-a458-4c2f-914d-92f715f58acf}</Project>
|
||||
<Name>Duplicati.Library.Common</Name>
|
||||
</ProjectReference>
|
||||
<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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="libstorj_uplink.dylib">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="libstorj_uplink.so">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="win-x64\storj_uplink.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="win-x86\storj_uplink.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets" Condition="Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" />
|
||||
</Project>
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||
// die einer Assembly zugeordnet sind.
|
||||
[assembly: AssemblyTitle("Duplicati.Library.Backend.Tardigrade")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Duplicati.Library.Backend.Tardigrade")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
|
||||
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
|
||||
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
|
||||
[assembly: Guid("ae035e01-c917-4f13-a35e-78f21c1a2f17")]
|
||||
|
||||
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||
//
|
||||
// Hauptversion
|
||||
// Nebenversion
|
||||
// Buildnummer
|
||||
// Revision
|
||||
//
|
||||
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
|
||||
// indem Sie "*" wie unten gezeigt eingeben:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly:InternalsVisibleTo("Duplicati.Library.Backend.Tardigrade")]
|
||||
@@ -0,0 +1,368 @@
|
||||
using Duplicati.Library.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using uplink.NET.Interfaces;
|
||||
using uplink.NET.Models;
|
||||
using uplink.NET.Services;
|
||||
|
||||
namespace Duplicati.Library.Backend.Storj
|
||||
{
|
||||
public class Storj : IStreamingBackend
|
||||
{
|
||||
private const string STORJ_AUTH_METHOD = "storj-auth-method";
|
||||
private const string STORJ_SATELLITE = "storj-satellite";
|
||||
private const string STORJ_API_KEY = "storj-api-key";
|
||||
private const string STORJ_SECRET = "storj-secret";
|
||||
private const string STORJ_SHARED_ACCESS = "storj-shared-access";
|
||||
private const string STORJ_BUCKET = "storj-bucket";
|
||||
private const string STORJ_FOLDER = "storj-folder";
|
||||
|
||||
private const string PROTOCOL_KEY = "storj";
|
||||
private const string STORJ_PARTNER_ID = "duplicati";
|
||||
|
||||
private readonly string _satellite;
|
||||
private readonly string _api_key;
|
||||
private readonly string _secret;
|
||||
private readonly string _bucket;
|
||||
private readonly string _folder;
|
||||
private Access _access;
|
||||
private IBucketService _bucketService;
|
||||
private IObjectService _objectService;
|
||||
|
||||
public static readonly Dictionary<string, string> KNOWN_STORJ_SATELLITES = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){
|
||||
{ "US Central", "us1.storj.io:7777" },
|
||||
{ "Asia East", "ap1.storj.io:7777" },
|
||||
{ "Europe", "eu1.storj.io:7777" },
|
||||
};
|
||||
|
||||
public static readonly Dictionary<string, string> KNOWN_AUTHENTICATION_METHODS = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){
|
||||
{ "API key", "API key" },
|
||||
{ "Access grant", "Access grant" },
|
||||
};
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
protected static extern IntPtr LoadLibrary(string filename);
|
||||
|
||||
private static bool _libraryLoaded = false;
|
||||
private static void InitStorjLibrary()
|
||||
{
|
||||
if (_libraryLoaded)
|
||||
return;
|
||||
|
||||
if (Duplicati.Library.Common.Platform.IsClientWindows) //We need to init only on Windows to distinguish between x64 and x86
|
||||
{
|
||||
if (System.Environment.Is64BitProcess)
|
||||
{
|
||||
var res = LoadLibrary("win-x64/storj_uplink.dll");
|
||||
}
|
||||
else
|
||||
{
|
||||
var res = LoadLibrary("win-x86/storj_uplink.dll");
|
||||
}
|
||||
}
|
||||
Access.SetTempDirectory(Library.Utility.TempFolder.SystemTempPath);
|
||||
_libraryLoaded = true;
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
// This constructor is needed by the BackendLoader.
|
||||
public Storj()
|
||||
{
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
// This constructor is needed by the BackendLoader.
|
||||
public Storj(string url, Dictionary<string, string> options)
|
||||
{
|
||||
InitStorjLibrary();
|
||||
|
||||
foreach(var option in options.ToList())
|
||||
{
|
||||
if(option.Key.ToLower().Contains("tardigrade"))
|
||||
{
|
||||
options.Add(option.Key.ToLower().Replace("tardigrade", "storj"), option.Value);
|
||||
}
|
||||
}
|
||||
|
||||
var auth_method = options[STORJ_AUTH_METHOD];
|
||||
if (auth_method == "Access grant")
|
||||
{
|
||||
//Create an access from the access grant
|
||||
var shared_access = options[STORJ_SHARED_ACCESS];
|
||||
_access = new Access(shared_access, new Config() { UserAgent = STORJ_PARTNER_ID });
|
||||
}
|
||||
else
|
||||
{
|
||||
//Create an access for a satellite, API key and encryption passphrase
|
||||
_satellite = options[STORJ_SATELLITE];
|
||||
|
||||
if (options.ContainsKey(STORJ_API_KEY))
|
||||
{
|
||||
_api_key = options[STORJ_API_KEY];
|
||||
}
|
||||
if (options.ContainsKey(STORJ_SECRET))
|
||||
{
|
||||
_secret = options[STORJ_SECRET];
|
||||
}
|
||||
|
||||
_access = new Access(_satellite, _api_key, _secret, new Config() { UserAgent = STORJ_PARTNER_ID });
|
||||
}
|
||||
|
||||
_bucketService = new BucketService(_access);
|
||||
_objectService = new ObjectService(_access);
|
||||
|
||||
//If no bucket was provided use the default "duplicati"-bucket
|
||||
if (options.ContainsKey(STORJ_BUCKET))
|
||||
{
|
||||
_bucket = options[STORJ_BUCKET];
|
||||
}
|
||||
else
|
||||
{
|
||||
_bucket = "duplicati";
|
||||
}
|
||||
|
||||
if (options.ContainsKey(STORJ_FOLDER))
|
||||
{
|
||||
_folder = options[STORJ_FOLDER];
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get { return Strings.Storj.DisplayName; }
|
||||
}
|
||||
|
||||
public string ProtocolKey => PROTOCOL_KEY;
|
||||
|
||||
public IList<ICommandLineArgument> SupportedCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(STORJ_AUTH_METHOD, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAuthMethodDescriptionShort, Strings.Storj.StorjAuthMethodDescriptionLong, "API key"),
|
||||
new CommandLineArgument(STORJ_SATELLITE, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSatelliteDescriptionShort, Strings.Storj.StorjSatelliteDescriptionLong, "us1.storj.io:7777"),
|
||||
new CommandLineArgument(STORJ_API_KEY, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAPIKeyDescriptionShort, Strings.Storj.StorjAPIKeyDescriptionLong),
|
||||
new CommandLineArgument(STORJ_SECRET, CommandLineArgument.ArgumentType.Password, Strings.Storj.StorjSecretDescriptionShort, Strings.Storj.StorjSecretDescriptionLong),
|
||||
new CommandLineArgument(STORJ_SHARED_ACCESS, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSharedAccessDescriptionShort, Strings.Storj.StorjSharedAccessDescriptionLong),
|
||||
new CommandLineArgument(STORJ_BUCKET, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjBucketDescriptionShort, Strings.Storj.StorjBucketDescriptionLong),
|
||||
new CommandLineArgument(STORJ_FOLDER, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjFolderDescriptionShort, Strings.Storj.StorjFolderDescriptionLong),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return Strings.Storj.Description;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] DNSName
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateFolder()
|
||||
{
|
||||
//Storj DCS has no folders
|
||||
}
|
||||
|
||||
public void Delete(string remotename)
|
||||
{
|
||||
var deleteTask = DeleteAsync(remotename);
|
||||
deleteTask.Wait();
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(string remotename)
|
||||
{
|
||||
try
|
||||
{
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
await _objectService.DeleteObjectAsync(bucket, GetBasePath() + remotename);
|
||||
}
|
||||
catch (Exception root)
|
||||
{
|
||||
throw new FileMissingException(root);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_objectService != null)
|
||||
{
|
||||
_objectService = null;
|
||||
}
|
||||
if (_bucketService != null)
|
||||
{
|
||||
_bucketService = null;
|
||||
}
|
||||
if (_access != null)
|
||||
{
|
||||
_access.Dispose();
|
||||
_access = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Get(string remotename, string filename)
|
||||
{
|
||||
var getTask = GetAsync(remotename, filename);
|
||||
getTask.Wait();
|
||||
}
|
||||
|
||||
public async Task GetAsync(string remotename, string filename)
|
||||
{
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false);
|
||||
await download.StartDownloadAsync();
|
||||
|
||||
if (download.Completed)
|
||||
{
|
||||
using (FileStream file = new FileStream(filename, FileMode.Create))
|
||||
{
|
||||
await file.WriteAsync(download.DownloadedBytes, 0, (int)download.BytesReceived);
|
||||
await file.FlushAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Get(string remotename, Stream stream)
|
||||
{
|
||||
var getTask = GetAsync(remotename, stream);
|
||||
getTask.Wait();
|
||||
}
|
||||
|
||||
public async Task GetAsync(string remotename, Stream stream)
|
||||
{
|
||||
int index = 0;
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false);
|
||||
download.DownloadOperationProgressChanged += (op) =>
|
||||
{
|
||||
int newPartLength = (int)op.BytesReceived - index;
|
||||
byte[] newPart = new byte[newPartLength];
|
||||
Array.Copy(op.DownloadedBytes, index, newPart, 0, newPartLength);
|
||||
stream.Write(newPart, 0, newPartLength);
|
||||
index = index + newPartLength;
|
||||
};
|
||||
await download.StartDownloadAsync();
|
||||
}
|
||||
|
||||
public IEnumerable<IFileEntry> List()
|
||||
{
|
||||
var listTask = ListAsync();
|
||||
listTask.Wait();
|
||||
return listTask.Result;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<IFileEntry>> ListAsync()
|
||||
{
|
||||
List<StorjFile> files = new List<StorjFile>();
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
var prefix = GetBasePath();
|
||||
var objects = await _objectService.ListObjectsAsync(bucket, new ListObjectsOptions { Recursive = true, System = true, Custom = true, Prefix = prefix });
|
||||
|
||||
foreach (var obj in objects.Items)
|
||||
{
|
||||
StorjFile file = new StorjFile(obj);
|
||||
if (prefix != "")
|
||||
{
|
||||
file.Name = file.Name.Replace(prefix, "");
|
||||
}
|
||||
files.Add(file);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
|
||||
{
|
||||
using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
await PutAsync(remotename, fs, cancelToken);
|
||||
}
|
||||
|
||||
public async Task PutAsync(string remotename, Stream stream, CancellationToken cancelToken)
|
||||
{
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
CustomMetadata custom = new CustomMetadata();
|
||||
custom.Entries.Add(new CustomMetadataEntry { Key = StorjFile.STORJ_LAST_ACCESS, Value = DateTime.Now.ToUniversalTime().ToString("O") });
|
||||
custom.Entries.Add(new CustomMetadataEntry { Key = StorjFile.STORJ_LAST_MODIFICATION, Value = DateTime.Now.ToUniversalTime().ToString("O") });
|
||||
var upload = await _objectService.UploadObjectAsync(bucket, GetBasePath() + remotename, new UploadOptions(), stream, custom, false);
|
||||
await upload.StartUploadAsync();
|
||||
}
|
||||
|
||||
public void Test()
|
||||
{
|
||||
var testTask = TestAsync();
|
||||
testTask.Wait(10000);
|
||||
if (!testTask.Result)
|
||||
{
|
||||
throw new Exception(Strings.Storj.TestConnectionFailed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test the connection by:
|
||||
/// - creating the bucket (if it not already exists)
|
||||
/// - uploading 256 random bytes to a test-file
|
||||
/// - downloading the file back and expecting 256 bytes
|
||||
/// </summary>
|
||||
/// <returns>true, if the test was successfull or and exception</returns>
|
||||
private async Task<bool> TestAsync()
|
||||
{
|
||||
string testFileName = GetBasePath() + "duplicati_test.dat";
|
||||
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
var upload = await _objectService.UploadObjectAsync(bucket, testFileName, new UploadOptions(), GetRandomBytes(256), false);
|
||||
await upload.StartUploadAsync();
|
||||
|
||||
var download = await _objectService.DownloadObjectAsync(bucket, testFileName, new DownloadOptions(), false);
|
||||
await download.StartDownloadAsync();
|
||||
|
||||
await _objectService.DeleteObjectAsync(bucket, testFileName);
|
||||
|
||||
if (download.Failed || download.BytesReceived != 256)
|
||||
{
|
||||
throw new Exception(download.ErrorMessage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the base path - depending on there is a folder set or not
|
||||
/// </summary>
|
||||
/// <returns>The base path within a bucket where the backup shall be placed</returns>
|
||||
private string GetBasePath()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_folder))
|
||||
return _folder + "/";
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates some random bytes with the given length - just for testing the connection
|
||||
/// </summary>
|
||||
/// <param name="length">The length of the bytes to create</param>
|
||||
/// <returns>A byte-array with the given length</returns>
|
||||
private static byte[] GetRandomBytes(long length)
|
||||
{
|
||||
byte[] bytes = new byte[length];
|
||||
Random rand = new Random();
|
||||
rand.NextBytes(bytes);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -5,12 +5,12 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Duplicati.Library.Backend.Tardigrade
|
||||
namespace Duplicati.Library.Backend.Storj
|
||||
{
|
||||
public class TardigradeConfig : IWebModule
|
||||
public class StorjConfig : IWebModule
|
||||
{
|
||||
private const ConfigType DEFAULT_CONFIG_TYPE = ConfigType.Satellites;
|
||||
private const string KEY_CONFIGTYPE = "tardigrade-config";
|
||||
private const string KEY_CONFIGTYPE = "storj-config";
|
||||
private static readonly string DEFAULT_CONFIG_TYPE_STR = Enum.GetName(typeof(ConfigType), DEFAULT_CONFIG_TYPE);
|
||||
|
||||
public enum ConfigType
|
||||
@@ -21,11 +21,11 @@ namespace Duplicati.Library.Backend.Tardigrade
|
||||
|
||||
#region IWebModule implementation
|
||||
|
||||
public string Key { get { return "tardigrade-getconfig"; } }
|
||||
public string Key { get { return "storj-getconfig"; } }
|
||||
|
||||
public string DisplayName { get { return "Tardigrade configuration module"; } }
|
||||
public string DisplayName { get { return "Storj DCS configuration module"; } }
|
||||
|
||||
public string Description { get { return "Exposes Tardigrade configuration as a web module"; } }
|
||||
public string Description { get { return "Exposes Storj DCS configuration as a web module"; } }
|
||||
|
||||
public IList<ICommandLineArgument> SupportedCommands
|
||||
{
|
||||
@@ -56,11 +56,11 @@ namespace Duplicati.Library.Backend.Tardigrade
|
||||
switch (ct)
|
||||
{
|
||||
case ConfigType.Satellites:
|
||||
return Tardigrade.KNOWN_TARDIGRADE_SATELLITES;
|
||||
return Storj.KNOWN_STORJ_SATELLITES;
|
||||
case ConfigType.AuthenticationMethods:
|
||||
return Tardigrade.KNOWN_AUTHENTICATION_METHODS;
|
||||
return Storj.KNOWN_AUTHENTICATION_METHODS;
|
||||
default:
|
||||
return Tardigrade.KNOWN_TARDIGRADE_SATELLITES;
|
||||
return Storj.KNOWN_STORJ_SATELLITES;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
+9
-9
@@ -5,12 +5,12 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Duplicati.Library.Backend.Tardigrade
|
||||
namespace Duplicati.Library.Backend.Storj
|
||||
{
|
||||
public class TardigradeFile : IFileEntry
|
||||
public class StorjFile : IFileEntry
|
||||
{
|
||||
public static readonly string TARDIGRADE_LAST_ACCESS = "DUPLICATI:LAST-ACCESS";
|
||||
public static readonly string TARDIGRADE_LAST_MODIFICATION = "DUPLICATI:LAST-MODIFICATION";
|
||||
public static readonly string STORJ_LAST_ACCESS = "DUPLICATI:LAST-ACCESS";
|
||||
public static readonly string STORJ_LAST_MODIFICATION = "DUPLICATI:LAST-MODIFICATION";
|
||||
public bool IsFolder { get; set; }
|
||||
|
||||
public DateTime LastAccess { get; set; }
|
||||
@@ -21,15 +21,15 @@ namespace Duplicati.Library.Backend.Tardigrade
|
||||
|
||||
public long Size { get; set; }
|
||||
|
||||
public TardigradeFile()
|
||||
public StorjFile()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public TardigradeFile(uplink.NET.Models.Object tardigradeObject)
|
||||
public StorjFile(uplink.NET.Models.Object tardigradeObject)
|
||||
{
|
||||
IsFolder = tardigradeObject.IsPrefix;
|
||||
var lastAccess = tardigradeObject.CustomMetaData.Entries.Where(e => e.Key == TARDIGRADE_LAST_ACCESS).FirstOrDefault();
|
||||
var lastAccess = tardigradeObject.CustomMetadata.Entries.Where(e => e.Key == STORJ_LAST_ACCESS).FirstOrDefault();
|
||||
if (lastAccess != null && !string.IsNullOrEmpty(lastAccess.Value))
|
||||
{
|
||||
LastAccess = DateTime.Parse(lastAccess.Value);
|
||||
@@ -39,7 +39,7 @@ namespace Duplicati.Library.Backend.Tardigrade
|
||||
LastAccess = DateTime.MinValue;
|
||||
}
|
||||
|
||||
var lastMod = tardigradeObject.CustomMetaData.Entries.Where(e => e.Key == TARDIGRADE_LAST_MODIFICATION).FirstOrDefault();
|
||||
var lastMod = tardigradeObject.CustomMetadata.Entries.Where(e => e.Key == STORJ_LAST_MODIFICATION).FirstOrDefault();
|
||||
if (lastMod != null && !string.IsNullOrEmpty(lastMod.Value))
|
||||
{
|
||||
LastModification = DateTime.Parse(lastMod.Value);
|
||||
@@ -50,7 +50,7 @@ namespace Duplicati.Library.Backend.Tardigrade
|
||||
}
|
||||
|
||||
Name = tardigradeObject.Key;
|
||||
Size = tardigradeObject.SystemMetaData.ContentLength;
|
||||
Size = tardigradeObject.SystemMetadata.ContentLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Duplicati.Library.Localization.Short;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Duplicati.Library.Backend.Strings
|
||||
{
|
||||
internal static class Storj
|
||||
{
|
||||
public static string DisplayName { get { return LC.L(@"Storj DCS (Decentralized Cloud Storage)"); } }
|
||||
public static string Description { get { return LC.L(@"This backend can read and write data to the Storj DCS."); } }
|
||||
public static string TestConnectionFailed { get { return LC.L(@"The connection-test failed."); } }
|
||||
public static string StorjAuthMethodDescriptionShort { get { return LC.L(@"The authentication method"); } }
|
||||
public static string StorjAuthMethodDescriptionLong { get { return LC.L(@"The authentication method describes which way to use to connect to the network - either via API key or via an access grant."); } }
|
||||
public static string StorjSatelliteDescriptionShort { get { return LC.L(@"The satellite"); } }
|
||||
public static string StorjSatelliteDescriptionLong { get { return LC.L(@"The satellite that keeps track of all metadata. Use a Storj DCS server for high-performance SLA-backed connectivity or use a community server. Or even host your own."); } }
|
||||
public static string StorjAPIKeyDescriptionShort { get { return LC.L(@"The API key"); } }
|
||||
public static string StorjAPIKeyDescriptionLong { get { return LC.L(@"The API key grants access to a specific project on your chosen satellite. Head over to the dashboard of your satellite to create one if you do not already have an API key."); } }
|
||||
public static string StorjSecretDescriptionShort { get { return LC.L(@"The encryption passphrase"); } }
|
||||
public static string StorjSecretDescriptionLong { get { return LC.L(@"The encryption passphrase is used to encrypt your data before sending it to the Storj network. This passphrase can be the only secret to provide - for Storj you do not necessary need any additional encryption (from Duplicati) in place."); } }
|
||||
public static string StorjSharedAccessDescriptionShort { get { return LC.L(@"The access grant"); } }
|
||||
public static string StorjSharedAccessDescriptionLong { get { return LC.L(@"An access grant contains all information in one encrypted string. You may use it instead of a satellite, API key and secret."); } }
|
||||
public static string StorjBucketDescriptionShort { get { return LC.L(@"The bucket"); } }
|
||||
public static string StorjBucketDescriptionLong { get { return LC.L(@"The bucket where the backup will reside in."); } }
|
||||
public static string StorjFolderDescriptionShort { get { return LC.L(@"The folder"); } }
|
||||
public static string StorjFolderDescriptionLong { get { return LC.L(@"The folder within the bucket where the backup will reside in."); } }
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="sqlite-net-pcl" version="1.7.335" targetFramework="net471" />
|
||||
<package id="SQLitePCLRaw.bundle_green" version="2.0.3" targetFramework="net471" />
|
||||
<package id="SQLitePCLRaw.core" version="2.0.3" targetFramework="net471" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3" version="2.0.3" targetFramework="net471" />
|
||||
<package id="SQLitePCLRaw.provider.dynamic_cdecl" version="2.0.3" targetFramework="net471" />
|
||||
<package id="System.Buffers" version="4.4.0" targetFramework="net471" />
|
||||
<package id="System.Memory" version="4.5.3" targetFramework="net471" />
|
||||
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net471" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net471" />
|
||||
<package id="uplink.NET" version="2.7.1604" targetFramework="net471" />
|
||||
</packages>
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{AE035E01-C917-4F13-A35E-78F21C1A2F17}</ProjectGuid>
|
||||
<ProjectGuid>{9A04CB37-DA72-4008-9703-3AC5191974E9}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Duplicati.Library.Backend.Tardigrade</RootNamespace>
|
||||
@@ -35,24 +35,50 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SQLite-net, Version=1.7.335.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\sqlite-net-pcl.1.7.335\lib\netstandard2.0\SQLite-net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.batteries_v2, Version=2.0.3.851, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.batteries_v2.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.core, Version=2.0.3.851, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\SQLitePCLRaw.core.2.0.3\lib\netstandard2.0\SQLitePCLRaw.core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.nativelibrary, Version=2.0.3.851, Culture=neutral, PublicKeyToken=502ed628492ab262, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.nativelibrary.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.provider.dynamic_cdecl, Version=2.0.3.851, Culture=neutral, PublicKeyToken=b68184102cba0b3b, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.3\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="uplink.NET, Version=2.3.4.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\uplink.NET.2.3.4\lib\netstandard2.0\uplink.NET.dll</HintPath>
|
||||
<Reference Include="uplink.NET, Version=2.7.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\uplink.NET.2.7.1604\lib\netstandard2.0\uplink.NET.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="TardigradeFile.cs" />
|
||||
<Compile Include="Strings.cs" />
|
||||
<Compile Include="TardigradeBackend.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="TardigradeConfig.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Common\Duplicati.Library.Common.csproj">
|
||||
@@ -71,29 +97,20 @@
|
||||
<Project>{de3e5d4c-51ab-4e5e-bee8-e636cebfba65}</Project>
|
||||
<Name>Duplicati.Library.Utility</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Storj\Duplicati.Library.Backend.Storj.csproj">
|
||||
<Project>{ae035e01-c917-4f13-a35e-78f21c1a2f17}</Project>
|
||||
<Name>Duplicati.Library.Backend.Storj</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="libstorj_uplink.dylib">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="libstorj_uplink.so">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="win-x64\storj_uplink.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="win-x86\storj_uplink.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\uplink.NET.2.3.4\build\net40\uplink.NET.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\uplink.NET.2.3.4\build\net40\uplink.NET.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
<Import Project="..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets" Condition="Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" />
|
||||
</Project>
|
||||
@@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
|
||||
[assembly: Guid("ae035e01-c917-4f13-a35e-78f21c1a2f17")]
|
||||
[assembly: Guid("9A04CB37-DA72-4008-9703-3AC5191974E9")]
|
||||
|
||||
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||
//
|
||||
|
||||
@@ -9,22 +9,7 @@ namespace Duplicati.Library.Backend.Strings
|
||||
{
|
||||
internal static class Tardigrade
|
||||
{
|
||||
public static string DisplayName { get { return LC.L(@"Tardigrade Decentralized Cloud Storage"); } }
|
||||
public static string Description { get { return LC.L(@"This backend can read and write data to the Tardigrade Decentralized Cloud Storage."); } }
|
||||
public static string TestConnectionFailed { get { return LC.L(@"The connection-test failed."); } }
|
||||
public static string TardigradeAuthMethodDescriptionShort { get { return LC.L(@"The authentication method"); } }
|
||||
public static string TardigradeAuthMethodDescriptionLong { get { return LC.L(@"The authentication method describes which way to use to connect to the network - either via API key or via an access grant."); } }
|
||||
public static string TardigradeSatelliteDescriptionShort { get { return LC.L(@"The satellite"); } }
|
||||
public static string TardigradeSatelliteDescriptionLong { get { return LC.L(@"The satellite that keeps track of all metadata. Use a Tardigrade-grade server for high-performance SLA-backed connectivity or use a community server. Or even host your own."); } }
|
||||
public static string TardigradeAPIKeyDescriptionShort { get { return LC.L(@"The API key"); } }
|
||||
public static string TardigradeAPIKeyDescriptionLong { get { return LC.L(@"The API key grants access to a specific project on your chosen satellite. Head over to the dashboard of your satellite to create one if you do not already have an API key."); } }
|
||||
public static string TardigradeSecretDescriptionShort { get { return LC.L(@"The encryption passphrase"); } }
|
||||
public static string TardigradeSecretDescriptionLong { get { return LC.L(@"The encryption passphrase is used to encrypt your data before sending it to the tardigrade network. This passphrase can be the only secret to provide - for Tardigrade you do not necessary need any additional encryption (from Duplicati) in place."); } }
|
||||
public static string TardigradeSharedAccessDescriptionShort { get { return LC.L(@"The access grant"); } }
|
||||
public static string TardigradeSharedAccessDescriptionLong { get { return LC.L(@"An access grant contains all information in one encrypted string. You may use it instead of a satellite, API key and secret."); } }
|
||||
public static string TardigradeBucketDescriptionShort { get { return LC.L(@"The bucket"); } }
|
||||
public static string TardigradeBucketDescriptionLong { get { return LC.L(@"The bucket where the backup will reside in."); } }
|
||||
public static string TardigradeFolderDescriptionShort { get { return LC.L(@"The folder"); } }
|
||||
public static string TardigradeFolderDescriptionLong { get { return LC.L(@"The folder within the bucket where the backup will reside in."); } }
|
||||
public static string DisplayName { get { return LC.L(@"Tardigrade Decentralised Cloud Storage (Deprecated)"); } }
|
||||
public static string Description { get { return LC.L(@"This backend can read and write data to the Tardigrade Decentralized Cloud Storage. It is deprecated - please move over to the new Storj DCS. (Deprecated)"); } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,15 @@ using uplink.NET.Services;
|
||||
|
||||
namespace Duplicati.Library.Backend.Tardigrade
|
||||
{
|
||||
public class Tardigrade : IStreamingBackend
|
||||
|
||||
/// <summary>
|
||||
/// This backend is deprecated! It will be removed in the future.
|
||||
/// Tardigrade renamed to Storj DCS in Spring 2021 - but existing Tardigrade-Configurations could not be easily renamed.
|
||||
/// So we decided to "copy" Tardigrade over to the new name Storj DCS. In order to reduce duplicate code, the old
|
||||
/// Tardigrade-Backend hands it's logic over to Storj DCS. Only the UI-specific part, the config-parameters and
|
||||
/// the protocol-key stay here named for Tardigrade.
|
||||
/// </summary>
|
||||
public class Tardigrade : Duplicati.Library.Backend.Storj.Storj, IStreamingBackend
|
||||
{
|
||||
private const string TARDIGRADE_AUTH_METHOD = "tardigrade-auth-method";
|
||||
private const string TARDIGRADE_SATELLITE = "tardigrade-satellite";
|
||||
@@ -23,339 +31,50 @@ namespace Duplicati.Library.Backend.Tardigrade
|
||||
private const string TARDIGRADE_SHARED_ACCESS = "tardigrade-shared-access";
|
||||
private const string TARDIGRADE_BUCKET = "tardigrade-bucket";
|
||||
private const string TARDIGRADE_FOLDER = "tardigrade-folder";
|
||||
|
||||
private const string PROTOCOL_KEY = "tardigrade";
|
||||
private const string TARDIGRADE_PARTNER_ID = "duplicati";
|
||||
|
||||
private readonly string _satellite;
|
||||
private readonly string _api_key;
|
||||
private readonly string _secret;
|
||||
private readonly string _bucket;
|
||||
private readonly string _folder;
|
||||
private Access _access;
|
||||
private IBucketService _bucketService;
|
||||
private IObjectService _objectService;
|
||||
|
||||
public static readonly Dictionary<string, string> KNOWN_TARDIGRADE_SATELLITES = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){
|
||||
{ "US Central 1", "us-central-1.tardigrade.io:7777" },
|
||||
{ "Asia East 1", "asia-east-1.tardigrade.io:7777" },
|
||||
{ "Saltlake", "saltlake.tardigrade.io:7777" },
|
||||
{ "Europe West 1", "europe-west-1.tardigrade.io:7777" },
|
||||
{ "Europe North 1", "europe-north-1.tardigrade.io:7777" },
|
||||
};
|
||||
|
||||
public static readonly Dictionary<string, string> KNOWN_AUTHENTICATION_METHODS = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){
|
||||
{ "API key", "API key" },
|
||||
{ "Access grant", "Access grant" },
|
||||
};
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
protected static extern IntPtr LoadLibrary(string filename);
|
||||
|
||||
private static bool _libraryLoaded = false;
|
||||
private static void InitStorjLibrary()
|
||||
{
|
||||
if (_libraryLoaded)
|
||||
return;
|
||||
|
||||
if (Duplicati.Library.Common.Platform.IsClientWindows) //We need to init only on Windows to distinguish between x64 and x86
|
||||
{
|
||||
if (System.Environment.Is64BitProcess)
|
||||
{
|
||||
var res = LoadLibrary("win-x64/storj_uplink.dll");
|
||||
}
|
||||
else
|
||||
{
|
||||
var res = LoadLibrary("win-x86/storj_uplink.dll");
|
||||
}
|
||||
}
|
||||
Access.SetTempDirectory(Library.Utility.TempFolder.SystemTempPath);
|
||||
_libraryLoaded = true;
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
// This constructor is needed by the BackendLoader.
|
||||
public Tardigrade()
|
||||
public Tardigrade():base()
|
||||
{
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
// This constructor is needed by the BackendLoader.
|
||||
public Tardigrade(string url, Dictionary<string, string> options)
|
||||
public Tardigrade(string url, Dictionary<string, string> options) :base(url, options)
|
||||
{
|
||||
InitStorjLibrary();
|
||||
|
||||
var auth_method = options[TARDIGRADE_AUTH_METHOD];
|
||||
if (auth_method == "Access grant")
|
||||
{
|
||||
//Create an access from the access grant
|
||||
var shared_access = options[TARDIGRADE_SHARED_ACCESS];
|
||||
_access = new Access(shared_access, new Config() { UserAgent = TARDIGRADE_PARTNER_ID });
|
||||
}
|
||||
else
|
||||
{
|
||||
//Create an access for a satellite, API key and encryption passphrase
|
||||
_satellite = options[TARDIGRADE_SATELLITE];
|
||||
|
||||
if (options.ContainsKey(TARDIGRADE_API_KEY))
|
||||
{
|
||||
_api_key = options[TARDIGRADE_API_KEY];
|
||||
}
|
||||
if (options.ContainsKey(TARDIGRADE_SECRET))
|
||||
{
|
||||
_secret = options[TARDIGRADE_SECRET];
|
||||
}
|
||||
|
||||
_access = new Access(_satellite, _api_key, _secret, new Config() { UserAgent = TARDIGRADE_PARTNER_ID });
|
||||
}
|
||||
|
||||
_bucketService = new BucketService(_access);
|
||||
_objectService = new ObjectService(_access);
|
||||
|
||||
//If no bucket was provided use the default "duplicati"-bucket
|
||||
if (options.ContainsKey(TARDIGRADE_BUCKET))
|
||||
{
|
||||
_bucket = options[TARDIGRADE_BUCKET];
|
||||
}
|
||||
else
|
||||
{
|
||||
_bucket = "duplicati";
|
||||
}
|
||||
|
||||
if (options.ContainsKey(TARDIGRADE_FOLDER))
|
||||
{
|
||||
_folder = options[TARDIGRADE_FOLDER];
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
public new string DisplayName
|
||||
{
|
||||
get { return Strings.Tardigrade.DisplayName; }
|
||||
}
|
||||
|
||||
public string ProtocolKey => PROTOCOL_KEY;
|
||||
public new string ProtocolKey => PROTOCOL_KEY;
|
||||
|
||||
public IList<ICommandLineArgument> SupportedCommands
|
||||
public new IList<ICommandLineArgument> SupportedCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(TARDIGRADE_AUTH_METHOD, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeAuthMethodDescriptionShort, Strings.Tardigrade.TardigradeAuthMethodDescriptionLong, "API key"),
|
||||
new CommandLineArgument(TARDIGRADE_SATELLITE, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeSatelliteDescriptionShort, Strings.Tardigrade.TardigradeSatelliteDescriptionLong, "us-central-1.tardigrade.io:7777"),
|
||||
new CommandLineArgument(TARDIGRADE_API_KEY, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeAPIKeyDescriptionShort, Strings.Tardigrade.TardigradeAPIKeyDescriptionLong),
|
||||
new CommandLineArgument(TARDIGRADE_SECRET, CommandLineArgument.ArgumentType.Password, Strings.Tardigrade.TardigradeSecretDescriptionShort, Strings.Tardigrade.TardigradeSecretDescriptionLong),
|
||||
new CommandLineArgument(TARDIGRADE_SHARED_ACCESS, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeSharedAccessDescriptionShort, Strings.Tardigrade.TardigradeSharedAccessDescriptionLong),
|
||||
new CommandLineArgument(TARDIGRADE_BUCKET, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeBucketDescriptionShort, Strings.Tardigrade.TardigradeBucketDescriptionLong),
|
||||
new CommandLineArgument(TARDIGRADE_FOLDER, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeFolderDescriptionShort, Strings.Tardigrade.TardigradeFolderDescriptionLong),
|
||||
new CommandLineArgument(TARDIGRADE_AUTH_METHOD, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAuthMethodDescriptionShort, Strings.Storj.StorjAuthMethodDescriptionLong, "API key", null, null),
|
||||
new CommandLineArgument(TARDIGRADE_SATELLITE, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSatelliteDescriptionShort, Strings.Storj.StorjSatelliteDescriptionLong, "us1.storj.io:7777", null, null),
|
||||
new CommandLineArgument(TARDIGRADE_API_KEY, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAPIKeyDescriptionShort, Strings.Storj.StorjAPIKeyDescriptionLong, null, null, null),
|
||||
new CommandLineArgument(TARDIGRADE_SECRET, CommandLineArgument.ArgumentType.Password, Strings.Storj.StorjSecretDescriptionShort, Strings.Storj.StorjSecretDescriptionLong, null, null, null),
|
||||
new CommandLineArgument(TARDIGRADE_SHARED_ACCESS, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSharedAccessDescriptionShort, Strings.Storj.StorjSharedAccessDescriptionLong, null, null, null),
|
||||
new CommandLineArgument(TARDIGRADE_BUCKET, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjBucketDescriptionShort, Strings.Storj.StorjBucketDescriptionLong, null, null, null),
|
||||
new CommandLineArgument(TARDIGRADE_FOLDER, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjFolderDescriptionShort, Strings.Storj.StorjFolderDescriptionLong, null, null, null),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
public new string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return Strings.Tardigrade.Description;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] DNSName
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateFolder()
|
||||
{
|
||||
//Tardigrade has no folders
|
||||
}
|
||||
|
||||
public void Delete(string remotename)
|
||||
{
|
||||
var deleteTask = DeleteAsync(remotename);
|
||||
deleteTask.Wait();
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(string remotename)
|
||||
{
|
||||
try
|
||||
{
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
await _objectService.DeleteObjectAsync(bucket, GetBasePath() + remotename);
|
||||
}
|
||||
catch (Exception root)
|
||||
{
|
||||
throw new FileMissingException(root);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_objectService != null)
|
||||
{
|
||||
_objectService = null;
|
||||
}
|
||||
if (_bucketService != null)
|
||||
{
|
||||
_bucketService = null;
|
||||
}
|
||||
if (_access != null)
|
||||
{
|
||||
_access.Dispose();
|
||||
_access = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Get(string remotename, string filename)
|
||||
{
|
||||
var getTask = GetAsync(remotename, filename);
|
||||
getTask.Wait();
|
||||
}
|
||||
|
||||
public async Task GetAsync(string remotename, string filename)
|
||||
{
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false);
|
||||
await download.StartDownloadAsync();
|
||||
|
||||
if (download.Completed)
|
||||
{
|
||||
using (FileStream file = new FileStream(filename, FileMode.Create))
|
||||
{
|
||||
await file.WriteAsync(download.DownloadedBytes, 0, (int)download.BytesReceived);
|
||||
await file.FlushAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Get(string remotename, Stream stream)
|
||||
{
|
||||
var getTask = GetAsync(remotename, stream);
|
||||
getTask.Wait();
|
||||
}
|
||||
|
||||
public async Task GetAsync(string remotename, Stream stream)
|
||||
{
|
||||
int index = 0;
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false);
|
||||
download.DownloadOperationProgressChanged += (op) =>
|
||||
{
|
||||
int newPartLength = (int)op.BytesReceived - index;
|
||||
byte[] newPart = new byte[newPartLength];
|
||||
Array.Copy(op.DownloadedBytes, index, newPart, 0, newPartLength);
|
||||
stream.Write(newPart, 0, newPartLength);
|
||||
index = index + newPartLength;
|
||||
};
|
||||
await download.StartDownloadAsync();
|
||||
}
|
||||
|
||||
public IEnumerable<IFileEntry> List()
|
||||
{
|
||||
var listTask = ListAsync();
|
||||
listTask.Wait();
|
||||
return listTask.Result;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<IFileEntry>> ListAsync()
|
||||
{
|
||||
List<TardigradeFile> files = new List<TardigradeFile>();
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
var prefix = GetBasePath();
|
||||
var objects = await _objectService.ListObjectsAsync(bucket, new ListObjectsOptions { Recursive = true, System = true, Custom = true, Prefix = prefix });
|
||||
|
||||
foreach (var obj in objects.Items)
|
||||
{
|
||||
TardigradeFile file = new TardigradeFile(obj);
|
||||
if (prefix != "")
|
||||
{
|
||||
file.Name = file.Name.Replace(prefix, "");
|
||||
}
|
||||
files.Add(file);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
|
||||
{
|
||||
using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
await PutAsync(remotename, fs, cancelToken);
|
||||
}
|
||||
|
||||
public async Task PutAsync(string remotename, Stream stream, CancellationToken cancelToken)
|
||||
{
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
CustomMetadata custom = new CustomMetadata();
|
||||
custom.Entries.Add(new CustomMetadataEntry { Key = TardigradeFile.TARDIGRADE_LAST_ACCESS, Value = DateTime.Now.ToUniversalTime().ToString("O") });
|
||||
custom.Entries.Add(new CustomMetadataEntry { Key = TardigradeFile.TARDIGRADE_LAST_MODIFICATION, Value = DateTime.Now.ToUniversalTime().ToString("O") });
|
||||
var upload = await _objectService.UploadObjectAsync(bucket, GetBasePath() + remotename, new UploadOptions(), stream, custom, false);
|
||||
await upload.StartUploadAsync();
|
||||
}
|
||||
|
||||
public void Test()
|
||||
{
|
||||
var testTask = TestAsync();
|
||||
testTask.Wait(10000);
|
||||
if (!testTask.Result)
|
||||
{
|
||||
throw new Exception(Strings.Tardigrade.TestConnectionFailed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test the connection by:
|
||||
/// - creating the bucket (if it not already exists)
|
||||
/// - uploading 256 random bytes to a test-file
|
||||
/// - downloading the file back and expecting 256 bytes
|
||||
/// </summary>
|
||||
/// <returns>true, if the test was successfull or and exception</returns>
|
||||
private async Task<bool> TestAsync()
|
||||
{
|
||||
string testFileName = GetBasePath() + "duplicati_test.dat";
|
||||
|
||||
var bucket = await _bucketService.EnsureBucketAsync(_bucket);
|
||||
var upload = await _objectService.UploadObjectAsync(bucket, testFileName, new UploadOptions(), GetRandomBytes(256), false);
|
||||
await upload.StartUploadAsync();
|
||||
|
||||
var download = await _objectService.DownloadObjectAsync(bucket, testFileName, new DownloadOptions(), false);
|
||||
await download.StartDownloadAsync();
|
||||
|
||||
await _objectService.DeleteObjectAsync(bucket, testFileName);
|
||||
|
||||
if (download.Failed || download.BytesReceived != 256)
|
||||
{
|
||||
throw new Exception(download.ErrorMessage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the base path - depending on there is a folder set or not
|
||||
/// </summary>
|
||||
/// <returns>The base path within a bucket where the backup shall be placed</returns>
|
||||
private string GetBasePath()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_folder))
|
||||
return _folder + "/";
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates some random bytes with the given length - just for testing the connection
|
||||
/// </summary>
|
||||
/// <param name="length">The length of the bytes to create</param>
|
||||
/// <returns>A byte-array with the given length</returns>
|
||||
private static byte[] GetRandomBytes(long length)
|
||||
{
|
||||
byte[] bytes = new byte[length];
|
||||
Random rand = new Random();
|
||||
rand.NextBytes(bytes);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="uplink.NET" version="2.3.4" targetFramework="net471" />
|
||||
<package id="sqlite-net-pcl" version="1.7.335" targetFramework="net471" />
|
||||
<package id="SQLitePCLRaw.bundle_green" version="2.0.3" targetFramework="net471" />
|
||||
<package id="SQLitePCLRaw.core" version="2.0.3" targetFramework="net471" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3" version="2.0.3" targetFramework="net471" />
|
||||
<package id="SQLitePCLRaw.provider.dynamic_cdecl" version="2.0.3" targetFramework="net471" />
|
||||
<package id="System.Buffers" version="4.4.0" targetFramework="net471" />
|
||||
<package id="System.Memory" version="4.5.3" targetFramework="net471" />
|
||||
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net471" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net471" />
|
||||
<package id="uplink.NET" version="2.7.1604" targetFramework="net471" />
|
||||
</packages>
|
||||
@@ -816,8 +816,12 @@ 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");
|
||||
|
||||
//TODO: Based on the action, see if all options are relevant
|
||||
}
|
||||
//Inform the user about the deprecated Tardigrade-Backend. They should switch to Storj DCS instead.
|
||||
if (string.Equals(new Library.Utility.Uri(m_backend).Scheme, "tardigrade", StringComparison.OrdinalIgnoreCase))
|
||||
Logging.Log.WriteWarningMessage(LOGTAG, "TardigradeRename", null, "The Tardigrade-backend got renamed to Storj DCS - please migrate your backups to the new configuration by changing the destination storage type to Storj DCS.");
|
||||
|
||||
//TODO: Based on the action, see if all options are relevant
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that expands the users chosen source input paths,
|
||||
|
||||
@@ -203,8 +203,12 @@
|
||||
<Project>{C0270709-2A40-43B5-8CF1-69581B9FA2A1}</Project>
|
||||
<Name>Duplicati.Library.Backend.TahoeLAFS</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<ProjectReference Include="..\Library\Backend\Storj\Duplicati.Library.Backend.Storj.csproj">
|
||||
<Project>{ae035e01-c917-4f13-a35e-78f21c1a2f17}</Project>
|
||||
<Name>Duplicati.Library.Backend.Storj</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Backend\Tardigrade\Duplicati.Library.Backend.Tardigrade.csproj">
|
||||
<Project>{9a04cb37-da72-4008-9703-3ac5191974e9}</Project>
|
||||
<Name>Duplicati.Library.Backend.Tardigrade</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Backend\TencentCOS\Duplicati.Library.Backend.TencentCOS.csproj">
|
||||
|
||||
@@ -29,8 +29,9 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
|
||||
EditUriBackendConfig.templates['box'] = 'templates/backends/oauth.html';
|
||||
EditUriBackendConfig.templates['dropbox'] = 'templates/backends/oauth.html';
|
||||
EditUriBackendConfig.templates['sia'] = 'templates/backends/sia.html';
|
||||
EditUriBackendConfig.templates['storj'] = 'templates/backends/storj.html';
|
||||
EditUriBackendConfig.templates['tardigrade'] = 'templates/backends/tardigrade.html';
|
||||
EditUriBackendConfig.templates['rclone'] = 'templates/backends/rclone.html';
|
||||
EditUriBackendConfig.templates['rclone'] = 'templates/backends/rclone.html';
|
||||
EditUriBackendConfig.templates['cos'] = 'templates/backends/cos.html';
|
||||
|
||||
EditUriBackendConfig.testers['s3'] = function(scope, callback) {
|
||||
@@ -157,21 +158,47 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
|
||||
scope.s3_client_options = s3_client_options;
|
||||
};
|
||||
|
||||
EditUriBackendConfig.loaders['storj'] = function (scope) {
|
||||
if (scope.storj_satellites == null) {
|
||||
AppService.post('/webmodule/storj-getconfig', {'storj-config': 'Satellites'}).then(function (data) {
|
||||
scope.storj_satellites = data.data.Result;
|
||||
if (scope.storj_satellite == undefined && scope.storj_satellite_custom == undefined)
|
||||
scope.storj_satellite = 'us1.storj.io:7777';
|
||||
|
||||
}, AppUtils.connectionError);
|
||||
} else {
|
||||
if (scope.storj_satellite == undefined && scope.storj_satellite_custom == undefined)
|
||||
scope.storj_satellite = 'us1.storj.io:7777';
|
||||
}
|
||||
|
||||
if (scope.storj_auth_methods == null) {
|
||||
AppService.post('/webmodule/storj-getconfig', {'storj-config': 'AuthenticationMethods'}).then(function (data) {
|
||||
scope.storj_auth_methods = data.data.Result;
|
||||
if (scope.storj_auth_method == undefined)
|
||||
scope.storj_auth_method = 'API key';
|
||||
|
||||
}, AppUtils.connectionError);
|
||||
} else {
|
||||
if (scope.storj_auth_method == undefined)
|
||||
scope.storj_auth_method = 'API key';
|
||||
}
|
||||
};
|
||||
|
||||
EditUriBackendConfig.loaders['tardigrade'] = function (scope) {
|
||||
if (scope.tardigrade_satellites == null) {
|
||||
AppService.post('/webmodule/tardigrade-getconfig', {'tardigrade-config': 'Satellites'}).then(function (data) {
|
||||
AppService.post('/webmodule/storj-getconfig', {'storj-config': 'Satellites'}).then(function (data) {
|
||||
scope.tardigrade_satellites = data.data.Result;
|
||||
if (scope.tardigrade_satellite == undefined && scope.tardigrade_satellite_custom == undefined)
|
||||
scope.tardigrade_satellite = 'us-central-1.tardigrade.io:7777';
|
||||
scope.tardigrade_satellite = 'us1.storj.io:7777';
|
||||
|
||||
}, AppUtils.connectionError);
|
||||
} else {
|
||||
if (scope.tardigrade_satellite == undefined && scope.tardigrade_satellite_custom == undefined)
|
||||
scope.tardigrade_satellite = 'us-central-1.tardigrade.io:7777';
|
||||
scope.tardigrade_satellite = 'us1.storj.io:7777';
|
||||
}
|
||||
|
||||
if (scope.tardigrade_auth_methods == null) {
|
||||
AppService.post('/webmodule/tardigrade-getconfig', {'tardigrade-config': 'AuthenticationMethods'}).then(function (data) {
|
||||
AppService.post('/webmodule/storj-getconfig', {'storj-config': 'AuthenticationMethods'}).then(function (data) {
|
||||
scope.tardigrade_auth_methods = data.data.Result;
|
||||
if (scope.tardigrade_auth_method == undefined)
|
||||
scope.tardigrade_auth_method = 'API key';
|
||||
@@ -486,7 +513,30 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
|
||||
delete options[nukeopts[x]];
|
||||
}
|
||||
|
||||
EditUriBackendConfig.parsers['tardigrade'] = function (scope, module, server, port, path, options) {
|
||||
EditUriBackendConfig.parsers['storj'] = function (scope, module, server, port, path, options) {
|
||||
if (options['--storj-auth-method'])
|
||||
scope.storj_auth_method = options['--storj-auth-method'];
|
||||
if (options['--storj-satellite'])
|
||||
scope.storj_satellite = options['--storj-satellite'];
|
||||
if (options['--storj-api-key'])
|
||||
scope.storj_api_key = options['--storj-api-key'];
|
||||
if (options['--storj-secret'])
|
||||
scope.storj_secret = options['--storj-secret'];
|
||||
if (options['--storj-secret-verify'])
|
||||
scope.storj_secret_verify = options['--storj-secret-verify'];
|
||||
if (options['--storj-shared-access'])
|
||||
scope.storj_shared_access = options['--storj-shared-access'];
|
||||
if (options['--storj-bucket'])
|
||||
scope.storj_bucket = options['--storj-bucket'];
|
||||
if (options['--storj-folder'])
|
||||
scope.storj_folder = options['--storj-folder'];
|
||||
|
||||
var nukeopts = ['--storj-auth-method','--storj-satellite', '--storj-api-key', '--storj-secret', '--storj-secret-verify', '--storj-shared-access', '--storj-bucket', '--storj-folder'];
|
||||
for (var x in nukeopts)
|
||||
delete options[nukeopts[x]];
|
||||
};
|
||||
|
||||
EditUriBackendConfig.parsers['tardigrade'] = function (scope, module, server, port, path, options) {
|
||||
if (options['--tardigrade-auth-method'])
|
||||
scope.tardigrade_auth_method = options['--tardigrade-auth-method'];
|
||||
if (options['--tardigrade-satellite'])
|
||||
@@ -495,14 +545,16 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
|
||||
scope.tardigrade_api_key = options['--tardigrade-api-key'];
|
||||
if (options['--tardigrade-secret'])
|
||||
scope.tardigrade_secret = options['--tardigrade-secret'];
|
||||
if (options['--tardigrade-shared-access'])
|
||||
if (options['--tardigrade-secret-verify'])
|
||||
scope.tardigrade_secret_verify = options['--tardigrade-secret-verify'];
|
||||
if (options['--tardigrade-shared-access'])
|
||||
scope.tardigrade_shared_access = options['--tardigrade-shared-access'];
|
||||
if (options['--tardigrade-bucket'])
|
||||
if (options['--tardigrade-bucket'])
|
||||
scope.tardigrade_bucket = options['--tardigrade-bucket'];
|
||||
if (options['--tardigrade-folder'])
|
||||
if (options['--tardigrade-folder'])
|
||||
scope.tardigrade_folder = options['--tardigrade-folder'];
|
||||
|
||||
var nukeopts = ['--tardigrade-auth-method','--tardigrade-satellite', '--tardigrade-api-key', '--tardigrade-secret', '--tardigrade-shared-access', '--tardigrade-bucket', '--tardigrade-folder'];
|
||||
|
||||
var nukeopts = ['--tardigrade-auth-method','--tardigrade-satellite', '--tardigrade-api-key', '--tardigrade-secret', '--tardigrade-secret-verify', '--tardigrade-shared-access', '--tardigrade-bucket', '--tardigrade-folder'];
|
||||
for (var x in nukeopts)
|
||||
delete options[nukeopts[x]];
|
||||
};
|
||||
@@ -743,15 +795,36 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
|
||||
return url;
|
||||
}
|
||||
|
||||
EditUriBackendConfig.builders['storj'] = function (scope) {
|
||||
var opts = {
|
||||
'storj-auth-method': scope.storj_auth_method,
|
||||
'storj-satellite': scope.storj_satellite,
|
||||
'storj-api-key': scope.storj_api_key,
|
||||
'storj-secret': scope.storj_secret,
|
||||
'storj-shared-access': scope.storj_shared_access,
|
||||
'storj-bucket': scope.storj_bucket,
|
||||
'storj-folder': scope.storj_folder
|
||||
};
|
||||
|
||||
EditUriBackendConfig.merge_in_advanced_options(scope, opts);
|
||||
|
||||
var url = AppUtils.format('{0}://storj.io/config{1}',
|
||||
scope.Backend.Key,
|
||||
AppUtils.encodeDictAsUrl(opts)
|
||||
);
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
EditUriBackendConfig.builders['tardigrade'] = function (scope) {
|
||||
var opts = {
|
||||
'tardigrade-auth-method': scope.tardigrade_auth_method,
|
||||
'tardigrade-auth-method': scope.tardigrade_auth_method,
|
||||
'tardigrade-satellite': scope.tardigrade_satellite,
|
||||
'tardigrade-api-key': scope.tardigrade_api_key,
|
||||
'tardigrade-secret': scope.tardigrade_secret,
|
||||
'tardigrade-shared-access': scope.tardigrade_shared_access,
|
||||
'tardigrade-bucket': scope.tardigrade_bucket,
|
||||
'tardigrade-folder': scope.tardigrade_folder
|
||||
'tardigrade-bucket': scope.tardigrade_bucket,
|
||||
'tardigrade-folder': scope.tardigrade_folder
|
||||
};
|
||||
|
||||
EditUriBackendConfig.merge_in_advanced_options(scope, opts);
|
||||
@@ -1110,7 +1183,71 @@ backupApp.service('EditUriBuiltins', function (AppService, AppUtils, SystemInfo,
|
||||
continuation();
|
||||
};
|
||||
|
||||
EditUriBackendConfig.validaters['storj'] = function (scope, continuation) {
|
||||
var res = true;
|
||||
|
||||
if(res && !scope['storj_auth_method']){
|
||||
res = EditUriBackendConfig.require_field(scope, 'storj_auth_method', gettextCatalog.getString('Authentication method'));
|
||||
}
|
||||
|
||||
if(res && scope['storj_auth_method'] == 'Access grant'){
|
||||
res = EditUriBackendConfig.require_field(scope, 'storj_shared_access', gettextCatalog.getString('storj_shared_access')) &&
|
||||
EditUriBackendConfig.require_field(scope, 'storj_bucket', gettextCatalog.getString('Bucket'));
|
||||
}
|
||||
|
||||
if(res && scope['storj_auth_method'] == 'API key'){
|
||||
res = EditUriBackendConfig.require_field(scope, 'storj_api_key', gettextCatalog.getString('API key')) &&
|
||||
EditUriBackendConfig.require_field(scope, 'storj_secret', gettextCatalog.getString('Encryption passphrase')) &&
|
||||
EditUriBackendConfig.require_field(scope, 'storj_bucket', gettextCatalog.getString('Bucket'));
|
||||
}
|
||||
|
||||
if(res && scope['storj_auth_method'] == 'API key' && !scope['storj_satellite']){
|
||||
res = EditUriBackendConfig.require_field(scope, 'storj_satellite_custom', gettextCatalog.getString('Custom Satellite'));
|
||||
}
|
||||
|
||||
if(res && scope['storj_auth_method'] == 'API key' && scope['storj_secret'] != scope['storj_secret_verify'])
|
||||
res = EditUriBackendConfig.show_error_dialog(gettextCatalog.getString('The encryption passphrases do not match'));
|
||||
|
||||
var re = new RegExp('^([a-z0-9]+([a-z0-9\-][a-z0-9])*)+(.[a-z0-9]+([a-z0-9\-][a-z0-9])*)*$');
|
||||
if(res && scope['storj_bucket'] && (!re.test(scope['storj_bucket']) || !(scope['storj_bucket'].length > 2 && scope['storj_bucket'].length < 64))){
|
||||
res = EditUriBackendConfig.show_error_dialog(gettextCatalog.getString('Bucket name can only be between 3 and 63 characters long and contain only lower-case characters, numbers, periods and dashes'));
|
||||
}
|
||||
|
||||
if (res)
|
||||
continuation();
|
||||
};
|
||||
|
||||
EditUriBackendConfig.validaters['tardigrade'] = function (scope, continuation) {
|
||||
var res = true;
|
||||
|
||||
if(res && !scope['tardigrade_auth_method']){
|
||||
res = EditUriBackendConfig.require_field(scope, 'tardigrade_auth_method', gettextCatalog.getString('Authentication method'));
|
||||
}
|
||||
|
||||
if(res && scope['tardigrade_auth_method'] == 'Access grant'){
|
||||
res = EditUriBackendConfig.require_field(scope, 'tardigrade_shared_access', gettextCatalog.getString('tardigrade_shared_access')) &&
|
||||
EditUriBackendConfig.require_field(scope, 'tardigrade_bucket', gettextCatalog.getString('Bucket'));
|
||||
}
|
||||
|
||||
if(res && scope['tardigrade_auth_method'] == 'API key'){
|
||||
res = EditUriBackendConfig.require_field(scope, 'tardigrade_api_key', gettextCatalog.getString('API key')) &&
|
||||
EditUriBackendConfig.require_field(scope, 'tardigrade_secret', gettextCatalog.getString('Encryption passphrase')) &&
|
||||
EditUriBackendConfig.require_field(scope, 'tardigrade_bucket', gettextCatalog.getString('Bucket'));
|
||||
}
|
||||
|
||||
if(res && scope['tardigrade_auth_method'] == 'API key' && !scope['tardigrade_satellite']){
|
||||
res = EditUriBackendConfig.require_field(scope, 'tardigrade_satellite_custom', gettextCatalog.getString('Custom Satellite'));
|
||||
}
|
||||
|
||||
if(res && scope['tardigrade_auth_method'] == 'API key' && scope['tardigrade_secret'] != scope['tardigrade_secret_verify'])
|
||||
res = EditUriBackendConfig.show_error_dialog(gettextCatalog.getString('The encryption passphrases do not match'));
|
||||
|
||||
var re = new RegExp('^([a-z0-9]+([a-z0-9\-][a-z0-9])*)+(.[a-z0-9]+([a-z0-9\-][a-z0-9])*)*$');
|
||||
if(res && scope['tardigrade_bucket'] && (!re.test(scope['tardigrade_bucket']) || !(scope['tardigrade_bucket'].length > 2 && scope['tardigrade_bucket'].length < 64))){
|
||||
res = EditUriBackendConfig.show_error_dialog(gettextCatalog.getString('Bucket name can only be between 3 and 63 characters long and contain only lower-case characters, numbers, periods and dashes'));
|
||||
}
|
||||
|
||||
if (res)
|
||||
continuation();
|
||||
};
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ backupApp.service('SystemInfo', function($rootScope, $timeout, $cookies, AppServ
|
||||
'mssp': null,
|
||||
'dropbox': null,
|
||||
'sia': null,
|
||||
'storj': null,
|
||||
'tardigrade': null,
|
||||
'jottacloud': null,
|
||||
'rclone': null,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<div class="input select">
|
||||
<label for="storj_auth_method" translate>Authentication method</label>
|
||||
<select name="storj_auth_method" id="storj_auth_method" ng-model="$parent.storj_auth_method"
|
||||
ng-options="v as k + ' (' + v + ')' for (k, v) in storj_auth_methods | orderBy: k">
|
||||
<option value="" translate >Authentication method ({{auth_method}})
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="input select" ng-show="$parent.storj_auth_method == 'API key'">
|
||||
<label for="storj_satellite" translate>Satellite</label>
|
||||
<select name="storj_satellite" id="storj_satellite" ng-model="$parent.storj_satellite"
|
||||
ng-options="v as k + ' (' + v + ')' for (k, v) in storj_satellites | orderBy: k">
|
||||
<option value="" translate translate-params-satellite="storj_satellite_custom || ''">Custom Satellite ({{satellite}})
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<input ng-hide="contains_value(storj_satellites, storj_satellite)" type="text" id="storj_satellite_custom"
|
||||
ng-model="$parent.storj_satellite_custom" placeholder="{{'Custom Satellite' | translate}}"/>
|
||||
</div>
|
||||
<div class="input text" ng-show="$parent.storj_auth_method == 'API key'">
|
||||
<label for="storj_api_key" translate>API key</label>
|
||||
<input type="text" name="storj_api_key" id="storj_api_key" ng-model="$parent.storj_api_key" placeholder="{{'The API key' | translate}}" />
|
||||
</div>
|
||||
<div class="input password" ng-show="$parent.storj_auth_method == 'API key'">
|
||||
<label for="storj_secret" translate>Encryption passphrase</label>
|
||||
<input autocomplete="new-password" type="password" name="storj_secret" id="storj_secret" ng-model="$parent.storj_secret" placeholder="{{'The encryption passphrase' | translate}}" />
|
||||
</div>
|
||||
<div class="input password" ng-show="$parent.storj_auth_method == 'API key'">
|
||||
<label for="storj_secret_verify" translate>Verify encryption passphrase</label>
|
||||
<input autocomplete="new-password" type="password" name="storj_secret_verify" id="storj_secret_verify" ng-model="$parent.storj_secret_verify" placeholder="{{'The encryption passphrase (for verification)' | translate}}" />
|
||||
</div>
|
||||
<div class="input text" ng-show="$parent.storj_auth_method == 'Access grant'">
|
||||
<label for="storj_shared_access" translate>Access grant</label>
|
||||
<input type="text" name="storj_shared_access" id="storj_shared_access" ng-model="$parent.storj_shared_access" placeholder="{{'The access grant instead of the info above'}}" />
|
||||
</div>
|
||||
<div class="input text">
|
||||
<label for="storj_bucket" translate>Bucket</label>
|
||||
<input type="text" name="storj_bucket" id="storj_bucket" ng-model="$parent.storj_bucket" placeholder="{{'The bucket for storing the backup'}}" />
|
||||
</div>
|
||||
<div class="input text">
|
||||
<label for="storj_folder" translate>Folder path</label>
|
||||
<input type="text" name="storj_folder" id="storj_folder" ng-model="$parent.storj_folder" placeholder="{{'The folder within the bucket for storing the backup'}}" />
|
||||
</div>
|
||||
@@ -25,6 +25,10 @@
|
||||
<label for="tardigrade_secret" translate>Encryption passphrase</label>
|
||||
<input autocomplete="new-password" type="password" name="tardigrade_secret" id="tardigrade_secret" ng-model="$parent.tardigrade_secret" placeholder="{{'The encryption passphrase' | translate}}" />
|
||||
</div>
|
||||
<div class="input password" ng-show="$parent.tardigrade_auth_method == 'API key'">
|
||||
<label for="tardigrade_secret_verify" translate>Verify encryption passphrase</label>
|
||||
<input autocomplete="new-password" type="password" name="tardigrade_secret_verify" id="tardigrade_secret_verify" ng-model="$parent.tardigrade_secret_verify" placeholder="{{'The encryption passphrase (for verification)' | translate}}" />
|
||||
</div>
|
||||
<div class="input text" ng-show="$parent.tardigrade_auth_method == 'Access grant'">
|
||||
<label for="tardigrade_shared_access" translate>Access grant</label>
|
||||
<input type="text" name="tardigrade_shared_access" id="tardigrade_shared_access" ng-model="$parent.tardigrade_shared_access" placeholder="{{'The access grant instead of the info above'}}" />
|
||||
|
||||
@@ -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 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, Tardigrade, SSH (SFTP), WebDAV, Tencent Cloud Object Storage (COS), [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, Storj DCS, SSH (SFTP), WebDAV, Tencent Cloud Object Storage (COS), [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.7.1+ or Mono 5.10.0+ required).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user