Files
cloudron-box/src/views/domains.js

467 lines
18 KiB
JavaScript
Raw Normal View History

2018-01-22 13:01:38 -08:00
'use strict';
/* global asyncForEach:false */
2018-01-22 13:01:38 -08:00
angular.module('Application').controller('DomainsController', ['$scope', '$location', 'Client', 'ngTld', function ($scope, $location, Client, ngTld) {
2018-08-03 10:09:04 -07:00
Client.onReady(function () { if (!Client.getUserInfo().admin) $location.path('/'); });
2018-01-22 13:01:38 -08:00
$scope.config = Client.getConfig();
$scope.domains = [];
$scope.ready = false;
2018-09-12 11:45:07 -07:00
// currently, validation of wildcard with various provider is done server side
$scope.tlsProvider = [
{ name: 'Let\'s Encrypt Prod', value: 'letsencrypt-prod' },
{ name: 'Let\'s Encrypt Prod - Wildcard', value: 'letsencrypt-prod-wildcard' },
{ name: 'Let\'s Encrypt Staging', value: 'letsencrypt-staging' },
{ name: 'Let\'s Encrypt Staging - Wildcard', value: 'letsencrypt-staging-wildcard' },
{ name: 'Custom Wildcard Certificate', value: 'fallback' },
];
2018-01-22 13:01:38 -08:00
// keep in sync with setupdns.js
$scope.dnsProvider = [
{ name: 'AWS Route53', value: 'route53' },
{ name: 'Cloudflare (DNS only)', value: 'cloudflare' },
{ name: 'Digital Ocean', value: 'digitalocean' },
{ name: 'Gandi LiveDNS', value: 'gandi' },
2018-05-06 21:52:25 -07:00
{ name: 'GoDaddy', value: 'godaddy' },
2018-01-22 13:01:38 -08:00
{ name: 'Google Cloud DNS', value: 'gcdns' },
2018-05-09 12:24:46 +02:00
{ name: 'Name.com', value: 'namecom' },
2018-01-22 13:01:38 -08:00
{ name: 'Wildcard', value: 'wildcard' },
{ name: 'Manual (not recommended)', value: 'manual' },
{ name: 'No-op (only for development)', value: 'noop' }
];
$scope.prettyProviderName = function (domain) {
switch (domain.provider) {
2018-03-09 00:29:00 -08:00
case 'caas': return 'Managed Cloudron';
case 'route53': return 'AWS Route53';
case 'cloudflare': return 'Cloudflare (DNS only)';
case 'digitalocean': return 'Digital Ocean';
case 'gandi': return 'Gandi LiveDNS';
2018-05-09 12:24:46 +02:00
case 'namecom': return 'Name.com';
case 'gcdns': return 'Google Cloud';
2018-05-06 21:52:25 -07:00
case 'godaddy': return 'GoDaddy';
2018-09-06 19:49:20 -07:00
case 'manual': return 'Manual';
case 'wildcard': return 'Wildcard';
case 'noop': return 'No-op';
default: return 'Unknown';
}
};
2018-09-12 14:40:12 -07:00
$scope.needsPort80 = function (dnsProvider, tlsProvider) {
return ((dnsProvider === 'manual' || dnsProvider === 'noop' || dnsProvider === 'wildcard') &&
(tlsProvider === 'letsencrypt-prod' || tlsProvider === 'letsencrypt-staging'));
};
2018-01-22 13:01:38 -08:00
function readFileLocally(obj, file, fileName) {
return function (event) {
$scope.$apply(function () {
obj[file] = null;
obj[fileName] = event.target.files[0].name;
var reader = new FileReader();
reader.onload = function (result) {
if (!result.target || !result.target.result) return console.error('Unable to read local file');
obj[file] = result.target.result;
};
reader.readAsText(event.target.files[0]);
});
};
}
function getDomains(callback) {
var domains = [ ];
Client.getDomains(function (error, results) {
if (error) return console.error(error);
asyncForEach(results, function (result, iteratorDone) {
2018-09-05 23:13:52 -07:00
if (result.locked) {
domains.push(result);
return iteratorDone();
}
Client.getDomain(result.domain, function (error, domain) {
if (error) return iteratorDone(error);
domains.push(domain);
iteratorDone();
});
}, function (error) {
callback(error, domains);
});
});
}
2018-01-22 13:01:38 -08:00
// We reused configure also for adding domains to avoid much code duplication
$scope.domainConfigure = {
adding: false,
error: null,
busy: false,
domain: null,
advancedVisible: false,
2018-01-22 13:01:38 -08:00
// form model
newDomain: '',
accessKeyId: '',
secretAccessKey: '',
gcdnsKey: { keyFileName: '', content: '' },
digitalOceanToken: '',
gandiApiKey: '',
2018-05-06 21:52:25 -07:00
godaddyApiKey: '',
godaddyApiSecret: '',
2018-01-22 13:01:38 -08:00
cloudflareToken: '',
cloudflareEmail: '',
2018-05-09 12:24:46 +02:00
nameComToken: '',
nameComUsername: '',
2018-01-22 13:01:38 -08:00
provider: 'route53',
zoneName: '',
hyphenatedSubdomains: false,
tlsConfig: {
provider: 'letsencrypt-prod-wildcard'
},
2018-01-22 13:01:38 -08:00
fallbackCert: {
certificateFile: null,
certificateFileName: '',
keyFile: null,
keyFileName: ''
},
setDefaultTlsProvider: function () {
var dnsProvider = $scope.domainConfigure.provider;
// wildcard LE won't work without automated DNS
if (dnsProvider === 'manual' || dnsProvider === 'noop' || dnsProvider === 'wildcard') {
$scope.domainConfigure.tlsConfig.provider = 'letsencrypt-prod';
} else {
$scope.domainConfigure.tlsConfig.provider = 'letsencrypt-prod-wildcard';
}
},
2018-01-22 13:01:38 -08:00
show: function (domain) {
$scope.domainConfigure.reset();
if (domain) {
$scope.domainConfigure.domain = domain;
$scope.domainConfigure.accessKeyId = domain.config.accessKeyId;
$scope.domainConfigure.secretAccessKey = domain.config.secretAccessKey;
$scope.domainConfigure.gcdnsKey.keyFileName = '';
$scope.domainConfigure.gcdnsKey.content = '';
if ($scope.domainConfigure.provider === 'gcdns') {
$scope.domainConfigure.gcdnsKey.keyFileName = domain.config.credentials && domain.config.credentials.client_email;
$scope.domainConfigure.gcdnsKey.content = JSON.stringify({
"project_id": domain.config.projectId,
"credentials": domain.config.credentials
});
}
$scope.domainConfigure.digitalOceanToken = domain.provider === 'digitalocean' ? domain.config.token : '';
$scope.domainConfigure.gandiApiKey = domain.provider === 'gandi' ? domain.config.token : '';
2018-01-22 13:01:38 -08:00
$scope.domainConfigure.cloudflareToken = domain.provider === 'cloudflare' ? domain.config.token : '';
2018-05-06 21:52:25 -07:00
$scope.domainConfigure.cloudflareEmail = domain.provider === 'cloudflare' ? domain.config.email : '';
$scope.domainConfigure.godaddyApiKey = domain.provider === 'godaddy' ? domain.config.apiKey : '';
$scope.domainConfigure.godaddyApiSecret = domain.provider === 'godaddy' ? domain.config.apiSecret : '';
2018-01-22 13:01:38 -08:00
2018-05-09 12:24:46 +02:00
$scope.domainConfigure.nameComToken = domain.provider === 'namecom' ? domain.config.token : '';
$scope.domainConfigure.nameComUsername = domain.provider === 'namecom' ? domain.config.username : '';
2018-01-22 13:01:38 -08:00
$scope.domainConfigure.provider = domain.provider;
$scope.domainConfigure.tlsConfig.provider = domain.tlsConfig.provider;
2018-09-12 11:45:07 -07:00
if (domain.tlsConfig.provider.indexOf('letsencrypt') === 0) {
if (domain.tlsConfig.wildcard) $scope.domainConfigure.tlsConfig.provider += '-wildcard';
}
$scope.domainConfigure.zoneName = domain.zoneName;
$scope.domainConfigure.hyphenatedSubdomains = !!domain.config.hyphenatedSubdomains;
2018-01-22 13:01:38 -08:00
} else {
$scope.domainConfigure.adding = true;
}
$('#domainConfigureModal').modal('show');
},
submit: function () {
$scope.domainConfigure.busy = true;
$scope.domainConfigure.error = null;
var provider = $scope.domainConfigure.provider;
var data = {};
2018-01-22 13:01:38 -08:00
if (provider === 'route53') {
data.accessKeyId = $scope.domainConfigure.accessKeyId;
data.secretAccessKey = $scope.domainConfigure.secretAccessKey;
2018-05-07 13:18:51 -07:00
} else if (provider === 'gcdns') {
2018-01-22 13:01:38 -08:00
try {
var serviceAccountKey = JSON.parse($scope.domainConfigure.gcdnsKey.content);
data.projectId = serviceAccountKey.project_id;
data.credentials = {
client_email: serviceAccountKey.client_email,
private_key: serviceAccountKey.private_key
};
if (!data.projectId || !data.credentials || !data.credentials.client_email || !data.credentials.private_key) {
throw 'fields_missing';
}
} catch (e) {
$scope.domainConfigure.error = 'Cannot parse Google Service Account Key: ' + e.message;
$scope.domainConfigure.busy = false;
return;
}
} else if (provider === 'digitalocean') {
data.token = $scope.domainConfigure.digitalOceanToken;
} else if (provider === 'gandi') {
data.token = $scope.domainConfigure.gandiApiKey;
2018-05-06 21:52:25 -07:00
} else if (provider === 'godaddy') {
data.apiKey = $scope.domainConfigure.godaddyApiKey;
data.apiSecret = $scope.domainConfigure.godaddyApiSecret;
2018-01-22 13:01:38 -08:00
} else if (provider === 'cloudflare') {
data.token = $scope.domainConfigure.cloudflareToken;
data.email = $scope.domainConfigure.cloudflareEmail;
2018-05-09 12:24:46 +02:00
} else if (provider === 'namecom') {
data.token = $scope.domainConfigure.nameComToken;
data.username = $scope.domainConfigure.nameComUsername;
2018-01-22 13:01:38 -08:00
}
data.hyphenatedSubdomains = $scope.domainConfigure.hyphenatedSubdomains;
2018-01-22 13:01:38 -08:00
var fallbackCertificate = null;
if ($scope.domainConfigure.fallbackCert.certificateFile && $scope.domainConfigure.fallbackCert.keyFile) {
fallbackCertificate = {
cert: $scope.domainConfigure.fallbackCert.certificateFile,
key: $scope.domainConfigure.fallbackCert.keyFile
};
}
2018-09-12 11:45:07 -07:00
var tlsConfig = {
provider: $scope.domainConfigure.tlsConfig.provider,
wildcard: false
};
if ($scope.domainConfigure.tlsConfig.provider.indexOf('-wildcard') !== -1) {
tlsConfig.provider = tlsConfig.provider.replace('-wildcard', '');
tlsConfig.wildcard = true;
}
2018-01-22 13:01:38 -08:00
// choose the right api, since we reuse this for adding and configuring domains
var func;
2018-09-12 11:45:07 -07:00
if ($scope.domainConfigure.adding) func = Client.addDomain.bind(Client, $scope.domainConfigure.newDomain, $scope.domainConfigure.zoneName, provider, data, fallbackCertificate, tlsConfig);
else func = Client.updateDomain.bind(Client, $scope.domainConfigure.domain.domain, $scope.domainConfigure.zoneName, provider, data, fallbackCertificate, tlsConfig);
2018-01-22 13:01:38 -08:00
func(function (error) {
$scope.domainConfigure.busy = false;
if (error) {
$scope.domainConfigure.error = error.message;
return;
}
$('#domainConfigureModal').modal('hide');
$scope.domainConfigure.reset();
// reload the domains
getDomains(function (error, result) {
2018-01-22 13:01:38 -08:00
if (error) return console.error(error);
$scope.domains = result;
});
});
},
reset: function () {
$scope.domainConfigure.adding = false;
$scope.domainConfigure.advancedVisible = false;
2018-01-22 13:01:38 -08:00
$scope.domainConfigure.newDomain = '';
$scope.domainConfigure.busy = false;
$scope.domainConfigure.error = null;
$scope.domainConfigure.provider = '';
$scope.domainConfigure.accessKeyId = '';
$scope.domainConfigure.secretAccessKey = '';
$scope.domainConfigure.gcdnsKey.keyFileName = '';
$scope.domainConfigure.gcdnsKey.content = '';
$scope.domainConfigure.digitalOceanToken = '';
$scope.domainConfigure.gandiApiKey = '';
2018-05-06 21:52:25 -07:00
$scope.domainConfigure.godaddyApiKey = '';
$scope.domainConfigure.godaddyApiSecret = '';
2018-01-22 13:01:38 -08:00
$scope.domainConfigure.cloudflareToken = '';
$scope.domainConfigure.cloudflareEmail = '';
2018-05-09 12:24:46 +02:00
$scope.domainConfigure.nameComToken = '';
$scope.domainConfigure.nameComUsername = '';
2018-01-22 13:01:38 -08:00
$scope.domainConfigure.tlsConfig.provider = 'letsencrypt-prod';
$scope.domainConfigure.zoneName = '';
$scope.domainConfigure.hyphenatedSubdomains = false;
2018-01-22 13:01:38 -08:00
$scope.domainConfigureForm.$setPristine();
$scope.domainConfigureForm.$setUntouched();
}
};
$scope.domainMigrate = {
busy: false,
error: null,
domain: null,
password: null,
show: function (domain) {
$scope.domainMigrate.reset();
$scope.domainMigrate.domain = domain;
$('#domainMigrateModal').modal('show');
},
submit: function () {
var setupDNSUrl = '/setupdns.html?admin_fqdn=my' + ($scope.domainMigrate.domain.provider === 'caas' ? '-' : '.') + $scope.domainMigrate.domain.domain;
$scope.domainMigrate.busy = true;
$scope.domainMigrate.error = null;
Client.setAdmin($scope.domainMigrate.domain.domain, $scope.domainMigrate.password, function (error) {
if (error && (error.statusCode === 403 || error.statusCode === 409)) {
$scope.domainMigrate.password = '';
$scope.domainMigrate.error = error.message;
$scope.domainMigrateForm.password.$setPristine();
$('#domainMigratePasswordInput').focus();
} else if (error) {
Client.error(error);
} else {
$('#domainMigrateModal').modal('hide');
$scope.domainMigrate.reset();
window.location.href = setupDNSUrl;
}
$scope.domainMigrate.busy = false;
});
},
reset: function () {
$scope.domainMigrate.busy = false;
$scope.domainMigrate.error = null;
$scope.domainMigrate.domain = null;
$scope.domainMigrate.password = '';
$scope.domainMigrateForm.$setPristine();
$scope.domainMigrateForm.$setUntouched();
}
};
2018-10-24 15:24:23 -07:00
$scope.domainRenewCerts = {
busy: false,
error: null,
domain: null,
show: function (domain) {
$scope.domainRenewCerts.reset();
$scope.domainRenewCerts.domain = domain;
$('#domainRenewCertsModal').modal('show');
},
submit: function () {
$scope.domainRenewCerts.busy = true;
$scope.domainRenewCerts.error = null;
Client.renewCerts($scope.domainRenewCerts.domain.domain, function (error) {
if (error) {
Client.error(error);
} else {
$('#domainRenewCertsModal').modal('hide');
$scope.domainRenewCerts.reset();
}
$scope.domainRenewCerts.busy = false;
});
},
reset: function () {
$scope.domainRenewCerts.busy = false;
$scope.domainRenewCerts.error = null;
$scope.domainRenewCerts.domain = null;
}
};
2018-01-22 13:01:38 -08:00
$scope.domainRemove = {
busy: false,
error: null,
domain: null,
password: '',
show: function (domain) {
$scope.domainRemove.reset();
$scope.domainRemove.domain = domain;
$('#domainRemoveModal').modal('show');
},
submit: function () {
$scope.domainRemove.busy = true;
$scope.domainRemove.error = null;
Client.removeDomain($scope.domainRemove.domain.domain, $scope.domainRemove.password, function (error) {
2018-06-18 18:57:00 -07:00
if (error && (error.statusCode === 403 || error.statusCode === 409)) {
2018-01-22 13:01:38 -08:00
$scope.domainRemove.password = '';
$scope.domainRemove.error = error.message;
$scope.domainRemoveForm.password.$setPristine();
$('#domainRemovePasswordInput').focus();
} else if (error) {
Client.error(error);
} else {
$('#domainRemoveModal').modal('hide');
$scope.domainRemove.reset();
// reload the domains
getDomains(function (error, result) {
2018-01-22 13:01:38 -08:00
if (error) return console.error(error);
$scope.domains = result;
});
}
$scope.domainRemove.busy = false;
});
},
reset: function () {
$scope.domainRemove.busy = false;
$scope.domainRemove.error = null;
$scope.domainRemove.domain = null;
$scope.domainRemove.password = '';
$scope.domainRemoveForm.$setPristine();
$scope.domainRemoveForm.$setUntouched();
}
};
Client.onReady(function () {
getDomains(function (error, result) {
2018-01-22 13:01:38 -08:00
if (error) return console.error(error);
$scope.domains = result;
$scope.ready = true;
});
});
document.getElementById('gcdnsKeyFileInput').onchange = readFileLocally($scope.domainConfigure.gcdnsKey, 'content', 'keyFileName');
document.getElementById('fallbackCertFileInput').onchange = readFileLocally($scope.domainConfigure.fallbackCert, 'certificateFile', 'certificateFileName');
document.getElementById('fallbackKeyFileInput').onchange = readFileLocally($scope.domainConfigure.fallbackCert, 'keyFile', 'keyFileName');
// setup all the dialog focus handling
['domainConfigureModal', 'domainMigrateModal', 'domainRemoveModal'].forEach(function (id) {
$('#' + id).on('shown.bs.modal', function () {
$(this).find("[autofocus]:first").focus();
});
});
$('.modal-backdrop').remove();
}]);