diff --git a/src/cloudron.js b/src/cloudron.js index cdd9cdc55..47f1a1c87 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -15,19 +15,18 @@ exports = module.exports = { onActivated: onActivated, + setDashboardDns: setDashboardDns, setDashboardDomain: setDashboardDomain, renewCerts: renewCerts, - checkDiskSpace: checkDiskSpace, - - configureWebadmin: configureWebadmin, - getWebadminStatus: getWebadminStatus + checkDiskSpace: checkDiskSpace }; var assert = require('assert'), async = require('async'), clients = require('./clients.js'), config = require('./config.js'), + constants = require('./constants.js'), cron = require('./cron.js'), debug = require('debug')('box:cloudron'), domains = require('./domains.js'), @@ -44,7 +43,6 @@ var assert = require('assert'), shell = require('./shell.js'), spawn = require('child_process').spawn, split = require('split'), - sysinfo = require('./sysinfo.js'), tasks = require('./tasks.js'), users = require('./users.js'), util = require('util'); @@ -283,54 +281,6 @@ function getLogs(unit, options, callback) { return callback(null, transformStream); } -function configureWebadmin(callback) { - assert.strictEqual(typeof callback, 'function'); - - debug('configureWebadmin: adminDomain:%s status:%j', config.adminDomain(), gWebadminStatus); - - if (process.env.BOX_ENV === 'test' || !config.adminDomain() || gWebadminStatus.configuring) return callback(); - - gWebadminStatus.configuring = true; // re-entracy guard - - function configureReverseProxy(error) { - debug('configureReverseProxy: error %j', error || null); - - reverseProxy.configureAdmin(config.adminDomain(), { userId: null, username: 'setup' }, function (error) { - debug('configureWebadmin: done error: %j', error || {}); - gWebadminStatus.configuring = false; - - if (error) return callback(error); - - gWebadminStatus.tls = true; - - callback(); - }); - } - - // update the DNS. configure nginx regardless of whether it succeeded so that - // box is accessible even if dns creds are invalid - sysinfo.getPublicIp(function (error, ip) { - if (error) return configureReverseProxy(error); - - domains.upsertDnsRecords(config.adminLocation(), config.adminDomain(), 'A', [ ip ], function (error) { - debug('addWebadminDnsRecord: updated records with error:', error); - if (error) return configureReverseProxy(error); - - domains.waitForDnsRecord(config.adminLocation(), config.adminDomain(), 'A', ip, { interval: 30000, times: 50000 }, function (error) { - if (error) return configureReverseProxy(error); - - gWebadminStatus.dns = true; - - configureReverseProxy(); - }); - }); - }); -} - -function getWebadminStatus() { - return gWebadminStatus; -} - function getStatus(callback) { assert.strictEqual(typeof callback, 'function'); @@ -354,26 +304,38 @@ function getStatus(callback) { }); } +function setDashboardDns(domain, auditSource, callback) { + assert.strictEqual(typeof domain, 'string'); + assert.strictEqual(typeof auditSource, 'object'); + assert.strictEqual(typeof callback, 'function'); + + debug(`setDashboardDns: ${domain}`); + + let task = tasks.startTask(tasks.TASK_DASHBOARD_DNS, [ domain, auditSource ]); + task.on('error', (error) => callback(new CloudronError(CloudronError.INTERNAL_ERROR, error))); + task.on('start', (taskId) => callback(null, taskId)); +} + function setDashboardDomain(domain, callback) { assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof callback, 'function'); debug(`setDashboardDomain: ${domain}`); - domains.get(domain, function (error, result) { + domains.get(domain, function (error, domainObject) { if (error && error.reason === DomainsError.NOT_FOUND) return callback(new CloudronError(CloudronError.BAD_FIELD, 'No such domain')); if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); - config.setAdminDomain(result.domain); - config.setAdminLocation('my'); - config.setAdminFqdn('my' + (result.config.hyphenatedSubdomains ? '-' : '.') + result.domain); + const fqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject); + + config.setAdminDomain(domain); + config.setAdminLocation(constants.ADMIN_LOCATION); + config.setAdminFqdn(fqdn); clients.addDefaultClients(config.adminOrigin(), function (error) { if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); callback(null); - - configureWebadmin(NOOP_CALLBACK); // ## trigger as task }); }); } diff --git a/src/domains.js b/src/domains.js index 08f0025e5..0e66bb32a 100644 --- a/src/domains.js +++ b/src/domains.js @@ -26,7 +26,7 @@ module.exports = exports = { parentDomain: parentDomain, - setupAdminDnsRecord: setupAdminDnsRecord, + setDashboardDnsRecord: setDashboardDnsRecord, DomainsError: DomainsError, @@ -35,6 +35,7 @@ module.exports = exports = { }; var assert = require('assert'), + async = require('async'), config = require('./config.js'), constants = require('./constants.js'), DatabaseError = require('./databaseerror.js'), @@ -497,21 +498,23 @@ function makeWildcard(hostname) { return parts.join('.'); } -function setupAdminDnsRecord(domain, callback) { +function setDashboardDnsRecord(domain, auditSource, progressCallback, callback) { assert.strictEqual(typeof domain, 'string'); + assert.strictEqual(typeof auditSource, 'object'); + assert.strictEqual(typeof progressCallback, 'function'); assert.strictEqual(typeof callback, 'function'); - sysinfo.getPublicIp(function (error, ip) { + get(domain, function (error, domainObject) { if (error) return callback(error); - upsertDnsRecords(constants.ADMIN_LOCATION, domain, 'A', [ ip ], function (error) { - if (error) return callback(error); + sysinfo.getPublicIp(function (error, ip) { + if (error) return callback(new DomainsError(DomainsError.EXTERNAL_ERROR, error.message)); - waitForDnsRecord(constants.ADMIN_LOCATION, domain, 'A', ip, { interval: 30000, times: 50000 }, function (error) { - if (error) return callback(error); - - callback(); - }); + async.series([ + upsertDnsRecords.bind(null, constants.ADMIN_LOCATION, domain, 'A', [ ip ]), + waitForDnsRecord.bind(null, constants.ADMIN_LOCATION, domain, 'A', ip, { interval: 30000, times: 50000 }), + reverseProxy.ensureCertificate.bind(null, fqdn(constants.ADMIN_LOCATION, domainObject), domain, auditSource) + ], callback); }); }); } \ No newline at end of file diff --git a/src/provision.js b/src/provision.js index c744f8477..d491c3088 100644 --- a/src/provision.js +++ b/src/provision.js @@ -150,7 +150,8 @@ function setup(dnsConfig, autoconf, auditSource, callback) { async.series([ mail.addDomain.bind(null, domain), - cloudron.setDashboardDomain.bind(null, domain), // triggers task to setup my. dns/cert/reverseproxy + cloudron.setDashboardDns.bind(null, domain, auditSource), + cloudron.setDashboardDomain.bind(null, domain), autoprovision.bind(null, autoconf), eventlog.add.bind(null, eventlog.ACTION_PROVISION, auditSource, { }) ], callback); diff --git a/src/reverseproxy.js b/src/reverseproxy.js index 8232342f2..bfbccd0b7 100644 --- a/src/reverseproxy.js +++ b/src/reverseproxy.js @@ -12,6 +12,7 @@ exports = module.exports = { validateCertificate: validateCertificate, getCertificate: getCertificate, + ensureCertificate: ensureCertificate, renewAll: renewAll, renewCerts: renewCerts, diff --git a/src/routes/cloudron.js b/src/routes/cloudron.js index 893f29e05..22154c502 100644 --- a/src/routes/cloudron.js +++ b/src/routes/cloudron.js @@ -13,6 +13,7 @@ exports = module.exports = { getLogStream: getLogStream, getStatus: getStatus, setDashboardDomain: setDashboardDomain, + setDashboardDns: setDashboardDns, renewCerts: renewCerts }; @@ -186,6 +187,17 @@ function setDashboardDomain(req, res, next) { }); } +function setDashboardDns(req, res, next) { + if (!req.body.domain || typeof req.body.domain !== 'string') return next(new HttpError(400, 'domain must be a string')); + + cloudron.setDashboardDns(req.body.domain, auditSource(req), function (error, taskId) { + if (error && error.reason === CloudronError.BAD_FIELD) return next(new HttpError(404, error.message)); + if (error) return next(new HttpError(500, error)); + + next(new HttpSuccess(202, { taskId })); + }); +} + function getStatus(req, res, next) { cloudron.getStatus(function (error, status) { if (error) return next(new HttpError(500, error)); diff --git a/src/server.js b/src/server.js index 919eefd19..d9a54181a 100644 --- a/src/server.js +++ b/src/server.js @@ -121,6 +121,7 @@ function initializeExpressSync() { // cloudron routes router.get ('/api/v1/cloudron/update', cloudronScope, routes.cloudron.getUpdateInfo); router.post('/api/v1/cloudron/update', cloudronScope, routes.cloudron.update); + router.post('/api/v1/cloudron/set_dashboard_dns', cloudronScope, routes.cloudron.setDashboardDns); router.post('/api/v1/cloudron/set_dashboard_domain', cloudronScope, routes.cloudron.setDashboardDomain); router.post('/api/v1/cloudron/renew_certs', cloudronScope, routes.cloudron.renewCerts); router.post('/api/v1/cloudron/check_for_updates', cloudronScope, routes.cloudron.checkForUpdates); diff --git a/src/tasks.js b/src/tasks.js index 7bb19673b..7790939af 100644 --- a/src/tasks.js +++ b/src/tasks.js @@ -18,6 +18,7 @@ exports = module.exports = { TASK_BACKUP: 'backup', TASK_UPDATE: 'update', TASK_RENEW_CERTS: 'renewcerts', + TASK_DASHBOARD_DNS: 'dashboardDns', // testing _TASK_IDENTITY: '_identity', diff --git a/src/taskworker.js b/src/taskworker.js index 76430a2b1..c20b520e8 100755 --- a/src/taskworker.js +++ b/src/taskworker.js @@ -6,6 +6,7 @@ var assert = require('assert'), backups = require('./backups.js'), database = require('./database.js'), debug = require('debug')('box:taskworker'), + domains = require('./domains.js'), reverseProxy = require('./reverseproxy.js'), tasks = require('./tasks.js'), updater = require('./updater.js'); @@ -16,6 +17,7 @@ const TASKS = { // indexed by task type backup: backups.backupBoxAndApps, update: updater.update, renewcerts: reverseProxy.renewCerts, + dashboardDns: domains.setDashboardDnsRecord, _identity: (arg, progressCallback, callback) => callback(null, arg), _error: (arg, progressCallback, callback) => callback(new Error(`Failed for arg: ${arg}`)),