diff --git a/src/boxerror.js b/src/boxerror.js index a0e832bb7..f08612b82 100644 --- a/src/boxerror.js +++ b/src/boxerror.js @@ -45,6 +45,7 @@ BoxError.FS_ERROR = 'FileSystem Error'; BoxError.INTERNAL_ERROR = 'Internal Error'; BoxError.LOGROTATE_ERROR = 'Logrotate Error'; BoxError.NETWORK_ERROR = 'Network Error'; +BoxError.NGINX_ERROR = 'Nginx Error'; BoxError.NOT_FOUND = 'Not found'; BoxError.OPENSSL_ERROR = 'OpenSSL Error'; BoxError.REVERSEPROXY_ERROR = 'ReverseProxy Error'; diff --git a/src/domains.js b/src/domains.js index e1d43a1a8..24047d3d4 100644 --- a/src/domains.js +++ b/src/domains.js @@ -43,7 +43,6 @@ var assert = require('assert'), domaindb = require('./domaindb.js'), eventlog = require('./eventlog.js'), reverseProxy = require('./reverseproxy.js'), - ReverseProxyError = reverseProxy.ReverseProxyError, safe = require('safetydance'), settings = require('./settings.js'), sysinfo = require('./sysinfo.js'), @@ -255,9 +254,7 @@ function get(domain, callback) { if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new DomainsError(DomainsError.NOT_FOUND)); if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); - reverseProxy.getFallbackCertificate(domain, function (error, bundle) { - if (error && error.reason !== ReverseProxyError.NOT_FOUND) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); - + reverseProxy.getFallbackCertificate(domain, function (_, bundle) { // never returns an error var cert = safe.fs.readFileSync(bundle.certFilePath, 'utf-8'); var key = safe.fs.readFileSync(bundle.keyFilePath, 'utf-8'); diff --git a/src/reverseproxy.js b/src/reverseproxy.js index 7582f4532..86405c673 100644 --- a/src/reverseproxy.js +++ b/src/reverseproxy.js @@ -1,8 +1,6 @@ 'use strict'; exports = module.exports = { - ReverseProxyError: ReverseProxyError, - setFallbackCertificate: setFallbackCertificate, getFallbackCertificate: getFallbackCertificate, @@ -36,6 +34,7 @@ var acme2 = require('./cert/acme2.js'), apps = require('./apps.js'), assert = require('assert'), async = require('async'), + BoxError = require('./boxerror.js'), caas = require('./cert/caas.js'), constants = require('./constants.js'), crypto = require('crypto'), @@ -60,29 +59,6 @@ var acme2 = require('./cert/acme2.js'), var NGINX_APPCONFIG_EJS = fs.readFileSync(__dirname + '/nginxconfig.ejs', { encoding: 'utf8' }), RELOAD_NGINX_CMD = path.join(__dirname, 'scripts/reloadnginx.sh'); -function ReverseProxyError(reason, errorOrMessage) { - assert.strictEqual(typeof reason, 'string'); - assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined'); - - Error.call(this); - Error.captureStackTrace(this, this.constructor); - - this.name = this.constructor.name; - this.reason = reason; - if (typeof errorOrMessage === 'undefined') { - this.message = reason; - } else if (typeof errorOrMessage === 'string') { - this.message = errorOrMessage; - } else { - this.message = 'Internal error'; - this.nestedError = errorOrMessage; - } -} -util.inherits(ReverseProxyError, Error); -ReverseProxyError.INTERNAL_ERROR = 'Internal Error'; -ReverseProxyError.INVALID_CERT = 'Invalid certificate'; -ReverseProxyError.NOT_FOUND = 'Not Found'; - function getCertApi(domainObject, callback) { assert.strictEqual(typeof domainObject, 'object'); assert.strictEqual(typeof callback, 'function'); @@ -164,29 +140,29 @@ function validateCertificate(location, domainObject, certificate) { const cert = certificate.cert, key = certificate.key; // check for empty cert and key strings - if (!cert && key) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, 'missing cert'); - if (cert && !key) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, 'missing key'); + if (!cert && key) return new BoxError(BoxError.BAD_FIELD, 'missing cert', { field: 'cert' }); + if (cert && !key) return new BoxError(BoxError.BAD_FIELD, 'missing key', { field: 'key' }); // -checkhost checks for SAN or CN exclusively. SAN takes precedence and if present, ignores the CN. const fqdn = domains.fqdn(location, domainObject); 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); + if (result === null) return new BoxError(BoxError.BAD_FIELD, 'Unable to get certificate subject:' + safe.error.message, { field: 'cert' }); - if (result.indexOf('does match certificate') === -1) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, `Certificate is not valid for this domain. Expecting ${fqdn}`); + if (result.indexOf('does match certificate') === -1) return new BoxError(BoxError.BAD_FIELD, `Certificate is not valid for this domain. Expecting ${fqdn}`, { field: 'cert' }); // http://httpd.apache.org/docs/2.0/ssl/ssl_faq.html#verify var certModulus = safe.child_process.execSync('openssl x509 -noout -modulus', { encoding: 'utf8', input: cert }); - if (certModulus === null) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, `Unable to get cert modulus: ${safe.error.message}`); + if (certModulus === null) return new BoxError(BoxError.BAD_FIELD, `Unable to get cert modulus: ${safe.error.message}`, { field: 'cert' }); var keyModulus = safe.child_process.execSync('openssl rsa -noout -modulus', { encoding: 'utf8', input: key }); - if (keyModulus === null) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, `Unable to get key modulus: ${safe.error.message}`); + if (keyModulus === null) return new BoxError(BoxError.BAD_FIELD, `Unable to get key modulus: ${safe.error.message}`, { field: 'cert' }); - if (certModulus !== keyModulus) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, 'Key does not match the certificate.'); + if (certModulus !== keyModulus) return new BoxError(BoxError.BAD_FIELD, 'Key does not match the certificate.', { field: 'cert' }); // check expiration result = safe.child_process.execSync('openssl x509 -checkend 0', { encoding: 'utf8', input: cert }); - if (!result) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, 'Certificate has expired.'); + if (!result) return new BoxError(BoxError.BAD_FIELD, 'Certificate has expired.', { field: 'cert' }); return null; } @@ -215,7 +191,7 @@ function generateFallbackCertificateSync(domainObject) { let configFile = path.join(os.tmpdir(), 'openssl-' + crypto.randomBytes(4).readUInt32LE(0) + '.conf'); safe.fs.writeFileSync(configFile, opensslConfWithSan, 'utf8'); let certCommand = util.format(`openssl req -x509 -newkey rsa:2048 -keyout ${keyFilePath} -out ${certFilePath} -days 3650 -subj /CN=*.${cn} -extensions SAN -config ${configFile} -nodes`); - if (!safe.child_process.execSync(certCommand)) return { error: new ReverseProxyError(ReverseProxyError.INTERNAL_ERROR, safe.error.message) }; + if (!safe.child_process.execSync(certCommand)) return { error: new BoxError(BoxError.OPENSSL_ERROR, safe.error.message) }; safe.fs.unlinkSync(configFile); const cert = safe.fs.readFileSync(certFilePath, 'utf8'); @@ -237,17 +213,17 @@ function setFallbackCertificate(domain, fallback, callback) { if (fallback.restricted) { // restricted certs are not backed up debug(`setFallbackCertificate: setting restricted certs for domain ${domain}`); - if (!safe.fs.writeFileSync(path.join(paths.NGINX_CERT_DIR, `${domain}.host.cert`), fallback.cert)) return callback(new ReverseProxyError(ReverseProxyError.INTERNAL_ERROR, safe.error.message)); - if (!safe.fs.writeFileSync(path.join(paths.NGINX_CERT_DIR, `${domain}.host.key`), fallback.key)) return callback(new ReverseProxyError(ReverseProxyError.INTERNAL_ERROR, safe.error.message)); + if (!safe.fs.writeFileSync(path.join(paths.NGINX_CERT_DIR, `${domain}.host.cert`), fallback.cert)) return callback(new BoxError(BoxError.FS_ERROR, safe.error.message)); + if (!safe.fs.writeFileSync(path.join(paths.NGINX_CERT_DIR, `${domain}.host.key`), fallback.key)) return callback(new BoxError(BoxError.FS_ERROR, safe.error.message)); } else { debug(`setFallbackCertificate: setting certs for domain ${domain}`); - if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, `${domain}.host.cert`), fallback.cert)) return callback(new ReverseProxyError(ReverseProxyError.INTERNAL_ERROR, safe.error.message)); - if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, `${domain}.host.key`), fallback.key)) return callback(new ReverseProxyError(ReverseProxyError.INTERNAL_ERROR, safe.error.message)); + if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, `${domain}.host.cert`), fallback.cert)) return callback(new BoxError(BoxError.FS_ERROR, safe.error.message)); + if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, `${domain}.host.key`), fallback.key)) return callback(new BoxError(BoxError.FS_ERROR, safe.error.message)); } // TODO: maybe the cert is being used by the mail container reload(function (error) { - if (error) return callback(new ReverseProxyError(ReverseProxyError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.NGINX_ERROR, error)); return callback(null); });