'use strict'; exports = module.exports = { getStatus, setupDnsAndCert, prepareDashboardDomain, setDashboardDomain, updateDashboardDomain, getTimeZone, setTimeZone, getLanguage, setLanguage, }; const apps = require('./apps.js'), appstore = require('./appstore.js'), assert = require('assert'), BoxError = require('./boxerror.js'), constants = require('./constants.js'), cron = require('./cron.js'), debug = require('debug')('box:cloudron'), dashboard = require('./dashboard.js'), dns = require('./dns.js'), eventlog = require('./eventlog.js'), moment = require('moment-timezone'), network = require('./network.js'), oidc = require('./oidc.js'), reverseProxy = require('./reverseproxy.js'), safe = require('safetydance'), services = require('./services.js'), settings = require('./settings.js'), tasks = require('./tasks.js'), translation = require('./translation.js'); async function getStatus() { return { version: constants.VERSION, }; } async function prepareDashboardDomain(domain, auditSource) { assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof auditSource, 'object'); debug(`prepareDashboardDomain: ${domain}`); if (constants.DEMO) throw new BoxError(BoxError.CONFLICT, 'Not allowed in demo mode'); const fqdn = dns.fqdn(constants.DASHBOARD_SUBDOMAIN, domain); const result = await apps.list(); if (result.some(app => app.fqdn === fqdn)) throw new BoxError(BoxError.BAD_STATE, 'Dashboard location conflicts with an existing app'); const taskId = await tasks.add(tasks.TASK_SETUP_DNS_AND_CERT, [ constants.DASHBOARD_SUBDOMAIN, domain, auditSource ]); tasks.startTask(taskId, {}); return taskId; } // call this only pre activation since it won't start mail server async function setDashboardDomain(domain, auditSource) { assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof auditSource, 'object'); debug(`setDashboardDomain: ${domain}`); await reverseProxy.writeDashboardConfig(domain); const fqdn = dns.fqdn(constants.DASHBOARD_SUBDOMAIN, domain); await dashboard.setLocation(domain, fqdn); await safe(appstore.updateCloudron({ domain }), { debug }); await eventlog.add(eventlog.ACTION_DASHBOARD_DOMAIN_UPDATE, auditSource, { domain, fqdn }); } // call this only post activation because it will restart mail server async function updateDashboardDomain(domain, auditSource) { assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof auditSource, 'object'); debug(`updateDashboardDomain: ${domain}`); if (constants.DEMO) throw new BoxError(BoxError.CONFLICT, 'Not allowed in demo mode'); await setDashboardDomain(domain, auditSource); // mark apps using oidc addon to be reconfigured const [, installedApps] = await safe(apps.list()); await safe(apps.configureInstalledApps(installedApps.filter((a) => !!a.manifest.addons.oidc), auditSource)); await safe(services.rebuildService('turn', auditSource), { debug }); // to update the realm variable await oidc.stop(); await oidc.start(); } async function setupDnsAndCert(subdomain, domain, auditSource, progressCallback) { assert.strictEqual(typeof subdomain, 'string'); assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof auditSource, 'object'); assert.strictEqual(typeof progressCallback, 'function'); const dashboardFqdn = dns.fqdn(subdomain, domain); const ipv4 = await network.getIPv4(); const ipv6 = await network.getIPv6(); progressCallback({ percent: 20, message: `Updating DNS of ${dashboardFqdn}` }); await dns.upsertDnsRecords(subdomain, domain, 'A', [ ipv4 ]); if (ipv6) await dns.upsertDnsRecords(subdomain, domain, 'AAAA', [ ipv6 ]); progressCallback({ percent: 40, message: `Waiting for DNS of ${dashboardFqdn}` }); await dns.waitForDnsRecord(subdomain, domain, 'A', ipv4, { interval: 30000, times: 50000 }); if (ipv6) await dns.waitForDnsRecord(subdomain, domain, 'AAAA', ipv6, { interval: 30000, times: 50000 }); progressCallback({ percent: 60, message: `Getting certificate of ${dashboardFqdn}` }); const location = { subdomain, domain, fqdn: dashboardFqdn, type: apps.LOCATION_TYPE_DASHBOARD, certificate: null }; await reverseProxy.ensureCertificate(location, {}, auditSource); } async function getTimeZone() { const tz = await settings.get(settings.TIME_ZONE_KEY); return tz || 'UTC'; } async function setTimeZone(tz) { assert.strictEqual(typeof tz, 'string'); if (moment.tz.names().indexOf(tz) === -1) throw new BoxError(BoxError.BAD_FIELD, 'Bad timeZone'); await settings.set(settings.TIME_ZONE_KEY, tz); await cron.handleTimeZoneChanged(tz); } async function getLanguage() { const value = await settings.get(settings.LANGUAGE_KEY); return value || 'en'; } async function setLanguage(language) { assert.strictEqual(typeof language, 'string'); const languages = await translation.listLanguages(); if (languages.indexOf(language) === -1) throw new BoxError(BoxError.BAD_FIELD, 'Language not found'); await settings.set(settings.LANGUAGE_KEY, language); }