diff --git a/src/apps.js b/src/apps.js index 2d76dfccc..db7768906 100644 --- a/src/apps.js +++ b/src/apps.js @@ -397,8 +397,8 @@ function get(appId, callback) { for (let d of domainObjects) { domainObjectMap[d.domain] = d; } app.iconUrl = getIconUrlSync(app); - app.fqdn = domains.fqdn(app.location, domainObjectMap[app.domain]); - app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, domainObjectMap[ad.domain]); }); + app.fqdn = domains.fqdn(app.location, app.domain, domainObjectMap[app.domain].config); + app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, ad.domain, domainObjectMap[ad.domain].config); }); callback(null, app); }); @@ -431,8 +431,8 @@ function getByIpAddress(ip, callback) { for (let d of domainObjects) { domainObjectMap[d.domain] = d; } app.iconUrl = getIconUrlSync(app); - app.fqdn = domains.fqdn(app.location, domainObjectMap[app.domain]); - app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, domainObjectMap[ad.domain]); }); + app.fqdn = domains.fqdn(app.location, app.domain, domainObjectMap[app.domain].config); + app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, ad.domain, domainObjectMap[ad.domain].config); }); callback(null, app); }); @@ -457,8 +457,8 @@ function getAll(callback) { async.eachSeries(apps, function (app, iteratorDone) { app.iconUrl = getIconUrlSync(app); - app.fqdn = domains.fqdn(app.location, domainObjectMap[app.domain]); - app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, domainObjectMap[ad.domain]); }); + app.fqdn = domains.fqdn(app.location, app.domain, domainObjectMap[app.domain].config); + app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, ad.domain, domainObjectMap[ad.domain].config); }); iteratorDone(null, app); }, function (error) { diff --git a/src/cloudron.js b/src/cloudron.js index 025b2fe0f..6747a86a3 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -292,7 +292,7 @@ function setDashboardDomain(domain, callback) { 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)); - const fqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject); + const fqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject.domain, domainObject.config); config.setAdminDomain(domain); config.setAdminLocation(constants.ADMIN_LOCATION); diff --git a/src/domains.js b/src/domains.js index cfa4428a9..ab459ffc8 100644 --- a/src/domains.js +++ b/src/domains.js @@ -130,8 +130,12 @@ function verifyDnsConfig(dnsConfig, domain, zoneName, provider, ip, callback) { }); } -function fqdn(location, domainObject) { - return location + (location ? (domainObject.config.hyphenatedSubdomains ? '-' : '.') : '') + domainObject.domain; +function fqdn(location, domain, dnsConfig) { + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof domain, 'string'); + assert.strictEqual(typeof dnsConfig, 'object'); + + return location + (location ? (dnsConfig.hyphenatedSubdomains ? '-' : '.') : '') + domain; } // Hostname validation comes from RFC 1123 (section 2.1) @@ -142,7 +146,7 @@ function validateHostname(location, domainObject) { assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof domainObject, 'object'); - const hostname = fqdn(location, domainObject); + const hostname = fqdn(location, domainObject.domain, domainObject.config); const RESERVED_LOCATIONS = [ constants.API_LOCATION, @@ -467,7 +471,7 @@ function waitForDnsRecord(subdomain, domain, type, value, options, callback) { get(domain, function (error, domainObject) { if (error) return callback(error); - const hostname = fqdn(subdomain, domainObject); + const hostname = fqdn(subdomain, domainObject.domain, domainObject.config); api(domainObject.provider).waitForDns(hostname, domainObject.zoneName, type, value, options, callback); }); @@ -516,7 +520,7 @@ function prepareDashboardDomain(domain, auditSource, progressCallback, callback) (done) => { progressCallback({ percent: 40, message: 'Waiting for DNS' }); done(); }, waitForDnsRecord.bind(null, constants.ADMIN_LOCATION, domain, 'A', ip, { interval: 30000, times: 50000 }), (done) => { progressCallback({ percent: 70, message: 'Getting certificate' }); done(); }, - reverseProxy.ensureCertificate.bind(null, fqdn(constants.ADMIN_LOCATION, domainObject), domain, auditSource) + reverseProxy.ensureCertificate.bind(null, fqdn(constants.ADMIN_LOCATION, domainObject.domain, domainObject.config), domain, auditSource) ], function (error) { if (error) return callback(error); @@ -524,4 +528,4 @@ function prepareDashboardDomain(domain, auditSource, progressCallback, callback) }); }); }); -} \ No newline at end of file +} diff --git a/src/reverseproxy.js b/src/reverseproxy.js index 6895fb204..b533bcf44 100644 --- a/src/reverseproxy.js +++ b/src/reverseproxy.js @@ -168,7 +168,7 @@ function validateCertificate(location, domainObject, certificate) { if (cert && !key) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, 'missing key'); // -checkhost checks for SAN or CN exclusively. SAN takes precedence and if present, ignores the CN. - const fqdn = domains.fqdn(location, domainObject); + const fqdn = domains.fqdn(location, domainObject.domain, domainObject.config); var result = safe.child_process.execSync(`openssl x509 -noout -checkhost "${fqdn}"`, { encoding: 'utf8', input: cert }); if (result === null) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, 'Unable to get certificate subject:' + safe.error.message); @@ -278,7 +278,7 @@ function setAppCertificateSync(location, domainObject, certificate) { assert.strictEqual(typeof domainObject, 'object'); assert.strictEqual(typeof certificate, 'object'); - let fqdn = domains.fqdn(location, domainObject); + let fqdn = domains.fqdn(location, domainObject.domain, domainObject.config); if (certificate.cert && certificate.key) { if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, `${fqdn}.user.cert`), certificate.cert)) return safe.error; if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, `${fqdn}.user.key`), certificate.key)) return safe.error; @@ -412,7 +412,7 @@ function configureAdmin(domain, auditSource, callback) { domains.get(domain, function (error, domainObject) { if (error) return callback(error); - const adminFqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject); + const adminFqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject.domain, domainObject.config); ensureCertificate(adminFqdn, domainObject.domain, auditSource, function (error, bundle) { if (error) return callback(error); @@ -429,7 +429,7 @@ function writeAdminConfig(domain, callback) { domains.get(domain, function (error, domainObject) { if (error) return callback(error); - const adminFqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject); + const adminFqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject.domain, domainObject.config); getCertificate(adminFqdn, domainObject.domain, function (error, bundle) { if (error) return callback(error); diff --git a/src/test/reverseproxy-test.js b/src/test/reverseproxy-test.js index 4aa711fda..9e1a8f858 100644 --- a/src/test/reverseproxy-test.js +++ b/src/test/reverseproxy-test.js @@ -90,7 +90,7 @@ describe('Certificates', function () { }); it('does not allow cert without matching domain', function () { - expect(reverseProxy.validateCertificate('', { domain: 'cloudron.io' }, { cert: validCert0, key: validKey0 })).to.be.an(Error); + expect(reverseProxy.validateCertificate('', { domain: 'cloudron.io', config: {} }, { cert: validCert0, key: validKey0 })).to.be.an(Error); expect(reverseProxy.validateCertificate('cloudron.io', foobarDomain, { cert: validCert0, key: validKey0 })).to.be.an(Error); });