diff --git a/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js b/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js
index 5ed824925..63a94b64d 100644
--- a/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js
+++ b/Duplicati/Server/webroot/ngax/scripts/services/EditUriBuiltins.js
@@ -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();
};
diff --git a/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js b/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js
index c422020e5..b6b4e4e52 100644
--- a/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js
+++ b/Duplicati/Server/webroot/ngax/scripts/services/SystemInfo.js
@@ -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,
diff --git a/Duplicati/Server/webroot/ngax/templates/backends/storj.html b/Duplicati/Server/webroot/ngax/templates/backends/storj.html
new file mode 100644
index 000000000..bb25db55a
--- /dev/null
+++ b/Duplicati/Server/webroot/ngax/templates/backends/storj.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Duplicati/Server/webroot/ngax/templates/backends/tardigrade.html b/Duplicati/Server/webroot/ngax/templates/backends/tardigrade.html
index eaa094c69..0131cab56 100644
--- a/Duplicati/Server/webroot/ngax/templates/backends/tardigrade.html
+++ b/Duplicati/Server/webroot/ngax/templates/backends/tardigrade.html
@@ -25,6 +25,10 @@
+
+
+
+
diff --git a/README.md b/README.md
index 5b1e2d8d1..4200e63b8 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ Removed Gitter
Duplicati is a free, open source, backup client that securely stores encrypted, incremental, compressed backups on cloud storage services and remote file servers. It works with:
- *Amazon 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).