diff --git a/src/apps.js b/src/apps.js index dc45f2949..263068617 100644 --- a/src/apps.js +++ b/src/apps.js @@ -1818,10 +1818,7 @@ async function setCertificate(app, data, auditSource) { const domainObject = await domains.get(domain); if (domainObject === null) throw new BoxError(BoxError.NOT_FOUND, 'Domain not found'); - if (cert && key) { - const error = reverseProxy.validateCertificate(subdomain, domain, { cert, key }); - if (error) throw error; - } + if (cert && key) await reverseProxy.validateCertificate(subdomain, domain, { cert, key }); const certificate = cert && key ? { cert, key } : null; const result = await database.query('UPDATE locations SET certificateJson=? WHERE location=? AND domain=?', [ certificate ? JSON.stringify(certificate) : null, subdomain, domain ]); diff --git a/src/domains.js b/src/domains.js index fee265929..a7a1f5ed6 100644 --- a/src/domains.js +++ b/src/domains.js @@ -142,8 +142,7 @@ async function add(domain, data, auditSource) { } if (fallbackCertificate) { - let error = reverseProxy.validateCertificate('test', domain, fallbackCertificate); - if (error) throw error; + await reverseProxy.validateCertificate('test', domain, fallbackCertificate); } else { fallbackCertificate = await reverseProxy.generateFallbackCertificate(domain); } @@ -214,10 +213,7 @@ async function setConfig(domain, data, auditSource) { zoneName = domainObject.zoneName; } - if (fallbackCertificate) { - let error = reverseProxy.validateCertificate('test', domain, fallbackCertificate); - if (error) throw error; - } + if (fallbackCertificate) await reverseProxy.validateCertificate('test', domain, fallbackCertificate); const tlsConfigError = validateTlsConfig(tlsConfig, provider); if (tlsConfigError) throw tlsConfigError; diff --git a/src/reverseproxy.js b/src/reverseproxy.js index 642fa2737..92ff45703 100644 --- a/src/reverseproxy.js +++ b/src/reverseproxy.js @@ -60,7 +60,6 @@ const acme2 = require('./acme2.js'), settings = require('./settings.js'), shell = require('./shell.js'), tasks = require('./tasks.js'), - util = require('util'), validator = require('validator'); const NGINX_APPCONFIG_EJS = fs.readFileSync(__dirname + '/nginxconfig.ejs', { encoding: 'utf8' }); @@ -73,13 +72,13 @@ function nginxLocation(s) { return `~ ^(?!(${re.slice(1)}))`; // negative regex assertion - https://stackoverflow.com/questions/16302897/nginx-location-not-equal-to-regex } -function getCertificateDatesSync(cert) { +async function getCertificateDates(cert) { assert.strictEqual(typeof cert, 'string'); - const result = safe.child_process.spawnSync('/usr/bin/openssl', [ 'x509', '-startdate', '-enddate', '-subject', '-noout' ], { input: cert, encoding: 'utf8' }); - if (!result) return { startDate: null, endDate: null } ; // some error + const [error, result] = await safe(shell.promises.exec('getCertificateDates', 'openssl x509 -startdate -enddate -subject -noout', { input: cert, encoding: 'utf8' })); + if (error) return { startDate: null, endDate: null } ; // some error - const lines = result.stdout.trim().split('\n'); + const lines = result.trim().split('\n'); const notBefore = lines[0].split('=')[1]; const notBeforeDate = new Date(notBefore); @@ -104,17 +103,17 @@ async function isOcspEnabled(certFilePath) { // We used to check for the must-staple in the cert using openssl x509 -text -noout -in ${certFilePath} | grep -q status_request // however, we cannot set the must-staple because first request to nginx fails because of it's OCSP caching behavior - const result = safe.child_process.execSync(`openssl x509 -in ${certFilePath} -noout -ocsp_uri`, { encoding: 'utf8' }); - return result && result.length > 0; // no error and has uri + const [error, result] = await safe(shell.promises.exec('isOscpEnabled', `openssl x509 -in ${certFilePath} -noout -ocsp_uri`, { encoding: 'utf8' })); + return !error && result.length > 0; // no error and has uri } // checks if the certificate matches the options provided by user (like wildcard, le-staging etc) -function providerMatchesSync(domainObject, cert) { +async function providerMatches(domainObject, cert) { assert.strictEqual(typeof domainObject, 'object'); assert.strictEqual(typeof cert, 'string'); - const subjectAndIssuer = safe.child_process.execSync('/usr/bin/openssl x509 -noout -subject -issuer', { encoding: 'utf8', input: cert }); - if (!subjectAndIssuer) return false; // something bad happenned + const [error, subjectAndIssuer] = await safe(shell.promises.exec('providerMatches', 'openssl x509 -noout -subject -issuer', { encoding: 'utf8', input: cert })); + if (error) return false; // something bad happenned const subject = subjectAndIssuer.match(/^subject=(.*)$/m)[1]; const domain = subject.substr(subject.indexOf('=') + 1).trim(); // subject can be /CN=, CN=, CN = and other forms @@ -131,7 +130,7 @@ function providerMatchesSync(domainObject, cert) { const mismatch = issuerMismatch || wildcardMismatch; - debug(`providerMatchesSync: subject=${subject} domain=${domain} issuer=${issuer} ` + debug(`providerMatches: subject=${subject} domain=${domain} issuer=${issuer} ` + `wildcard=${isWildcardCert}/${wildcard} prod=${isLetsEncryptProd}/${prod} ` + `issuerMismatch=${issuerMismatch} wildcardMismatch=${wildcardMismatch} match=${!mismatch}`); @@ -140,7 +139,7 @@ function providerMatchesSync(domainObject, cert) { // note: https://tools.ietf.org/html/rfc4346#section-7.4.2 (certificate_list) requires that the // servers certificate appears first (and not the intermediate cert) -function validateCertificate(subdomain, domain, certificate) { +async function validateCertificate(subdomain, domain, certificate) { assert.strictEqual(typeof subdomain, 'string'); assert.strictEqual(typeof domain, 'string'); assert(certificate && typeof certificate, 'object'); @@ -148,29 +147,28 @@ function validateCertificate(subdomain, domain, certificate) { const { cert, key } = certificate; // check for empty cert and key strings - if (!cert && key) return new BoxError(BoxError.BAD_FIELD, 'missing cert'); - if (cert && !key) return new BoxError(BoxError.BAD_FIELD, 'missing key'); + if (!cert && key) throw new BoxError(BoxError.BAD_FIELD, 'missing cert'); + if (cert && !key) throw new BoxError(BoxError.BAD_FIELD, 'missing key'); // -checkhost checks for SAN or CN exclusively. SAN takes precedence and if present, ignores the CN. const fqdn = dns.fqdn(subdomain, domain); - let result = safe.child_process.execSync(`openssl x509 -noout -checkhost "${fqdn}"`, { encoding: 'utf8', input: cert }); - if (result === null) return new BoxError(BoxError.BAD_FIELD, 'Unable to get certificate subject:' + safe.error.message); - - if (result.indexOf('does match certificate') === -1) return new BoxError(BoxError.BAD_FIELD, `Certificate is not valid for this domain. Expecting ${fqdn}`); + const [checkHostError, checkHostOutput] = await safe(shell.promises.exec('validateCertificate', `openssl x509 -noout -checkhost "${fqdn}"`, { encoding: 'utf8', input: cert })); + console.log(checkHostError, checkHostOutput); + if (checkHostError) throw new BoxError(BoxError.BAD_FIELD, 'Could not validate certificate'); + if (checkHostOutput.indexOf('does match certificate') === -1) throw new BoxError(BoxError.BAD_FIELD, `Certificate is not valid for this domain. Expecting ${fqdn}`); // check if public key in the cert and private key matches. pkey below works for RSA and ECDSA keys - const pubKeyFromCert = safe.child_process.execSync('openssl x509 -noout -pubkey', { encoding: 'utf8', input: cert }); - if (pubKeyFromCert === null) return new BoxError(BoxError.BAD_FIELD, `Unable to get public key from certificate: ${safe.error.message}`); + const [pubKeyError1, pubKeyFromCert] = await safe(shell.promises.exec('validateCertificate', 'openssl x509 -noout -pubkey', { encoding: 'utf8', input: cert })); + if (pubKeyError1) throw new BoxError(BoxError.BAD_FIELD, 'Could not get public key from cert'); + const [pubKeyError2, pubKeyFromKey] = await safe(shell.promises.exec('validateCertificate', 'openssl pkey -pubout', { encoding: 'utf8', input: key })); + if (pubKeyError2) throw new BoxError(BoxError.BAD_FIELD, 'Could not get public key from private key'); - const pubKeyFromKey = safe.child_process.execSync('openssl pkey -pubout', { encoding: 'utf8', input: key }); - if (pubKeyFromKey === null) return new BoxError(BoxError.BAD_FIELD, `Unable to get public key from private key: ${safe.error.message}`); - - if (pubKeyFromCert !== pubKeyFromKey) return new BoxError(BoxError.BAD_FIELD, 'Public key does not match the certificate.'); + if (pubKeyFromCert !== pubKeyFromKey) throw new BoxError(BoxError.BAD_FIELD, 'Public key does not match the certificate.'); // check expiration - result = safe.child_process.execSync('openssl x509 -checkend 0', { encoding: 'utf8', input: cert }); - if (!result) return new BoxError(BoxError.BAD_FIELD, 'Certificate has expired.'); + const [error] = await safe(shell.promises.exec('validateCertificate', 'openssl x509 -checkend 0', { encoding: 'utf8', input: cert })); + if (error) throw new BoxError(BoxError.BAD_FIELD, 'Certificate has expired'); return null; } @@ -209,8 +207,8 @@ async function generateFallbackCertificate(domain) { const configFile = path.join(os.tmpdir(), 'openssl-' + crypto.randomBytes(4).readUInt32LE(0) + '.conf'); safe.fs.writeFileSync(configFile, opensslConfWithSan, 'utf8'); // the days field is chosen to be less than 825 days per apple requirement (https://support.apple.com/en-us/HT210176) - const certCommand = util.format(`openssl req -x509 -newkey rsa:2048 -keyout ${keyFilePath} -out ${certFilePath} -days 800 -subj /CN=*.${cn} -extensions SAN -config ${configFile} -nodes`); - if (!safe.child_process.execSync(certCommand)) throw new BoxError(BoxError.OPENSSL_ERROR, safe.error.message); + const certCommand = `openssl req -x509 -newkey rsa:2048 -keyout ${keyFilePath} -out ${certFilePath} -days 800 -subj /CN=*.${cn} -extensions SAN -config ${configFile} -nodes`; + await shell.promises.exec('generateFallbackCertificate', certCommand, {}); safe.fs.unlinkSync(configFile); const cert = safe.fs.readFileSync(certFilePath, 'utf8'); @@ -267,11 +265,11 @@ function getAcmeCertificateNameSync(fqdn, domainObject) { } } -function needsRenewalSync(cert, options) { +async function needsRenewal(cert, options) { assert.strictEqual(typeof cert, 'string'); assert.strictEqual(typeof options, 'object'); - const { startDate, endDate } = getCertificateDatesSync(cert); + const { startDate, endDate } = await getCertificateDates(cert); const now = new Date(); let isExpiring; @@ -433,7 +431,9 @@ async function ensureCertificate(location, options, auditSource) { const cert = await blobs.getString(`${blobs.CERT_PREFIX}-${certName}.cert`); if (key && cert) { - if (providerMatchesSync(domainObject, cert) && !needsRenewalSync(cert, options)) { + const sameProvider = await providerMatches(domainObject, cert); + const outdated = await needsRenewal(cert, options); + if (sameProvider && !outdated) { debug(`ensureCertificate: ${fqdn} acme cert exists and is up to date`); return; } @@ -629,7 +629,7 @@ async function cleanupCerts(locations, auditSource, progressCallback) { if (certNamesInUse.has(certName)) continue; const cert = await blobs.getString(certId); - const { endDate } = getCertificateDatesSync(cert); + const { endDate } = await getCertificateDates(cert); if (!endDate) continue; // some error if (now - endDate >= (60 * 60 * 24 * 30 * 6 * 1000)) { // expired 6 months ago and not in use @@ -736,10 +736,7 @@ async function writeDefaultConfig(options) { const cn = 'cloudron-' + (new Date()).toISOString(); // randomize date a bit to keep firefox happy // the days field is chosen to be less than 825 days per apple requirement (https://support.apple.com/en-us/HT210176) - if (!safe.child_process.execSync(`openssl req -x509 -newkey rsa:2048 -keyout ${keyFilePath} -out ${certFilePath} -days 800 -subj /CN=${cn} -nodes`)) { - debug(`writeDefaultConfig: could not generate certificate: ${safe.error.message}`); - throw new BoxError(BoxError.OPENSSL_ERROR, safe.error); - } + await shell.promises.exec('writeDefaultConfig', `openssl req -x509 -newkey rsa:2048 -keyout ${keyFilePath} -out ${certFilePath} -days 800 -subj /CN=${cn} -nodes`, {}); } const data = { diff --git a/src/shell.js b/src/shell.js index 2f55e9d32..cfd540320 100644 --- a/src/shell.js +++ b/src/shell.js @@ -29,20 +29,26 @@ function exec(tag, cmd, options, callback) { debug(`${tag} exec: ${cmd}`); - child_process.exec(cmd, options, function (error, stdout, stderr) { + const cp = child_process.exec(cmd, options, function (error, stdout, stderr) { let e = null; if (error) { e = new BoxError(BoxError.SHELL_ERROR, `${tag} errored with code ${error.code} message ${error.message}`); e.stdout = stdout; // when promisified, this is the way to get stdout e.stderr = stderr; // when promisified, this is the way to get stderr - debug(e.message); + debug(`${tag}: ${cmd} errored`, error); } callback(e, stdout); }); + + if (options.input) { + cp.stdin.write(options.input); + cp.stdin.end(); + } } +// use this when you are afraid of how arguments will split up function spawn(tag, file, args, options, callback) { assert.strictEqual(typeof tag, 'string'); assert.strictEqual(typeof file, 'string'); diff --git a/src/test/reverseproxy-test.js b/src/test/reverseproxy-test.js index 34b7d44ac..a422a7b55 100644 --- a/src/test/reverseproxy-test.js +++ b/src/test/reverseproxy-test.js @@ -5,12 +5,14 @@ 'use strict'; -const common = require('./common.js'), +const BoxError = require('../boxerror.js'), + common = require('./common.js'), domains = require('../domains.js'), expect = require('expect.js'), fs = require('fs'), paths = require('../paths.js'), - reverseProxy = require('../reverseproxy.js'); + reverseProxy = require('../reverseproxy.js'), + safe = require('safetydance'); describe('Reverse Proxy', function () { const { setup, cleanup, domain, auditSource, app } = common; @@ -58,59 +60,70 @@ describe('Reverse Proxy', function () { const validCert3 = '-----BEGIN CERTIFICATE-----\nMIIC3DCCAcSgAwIBAgIJALcStAD5sDWEMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV\nBAMMDSouYW1hemluZy5jb20wHhcNMTgwMjA5MjIxMzM2WhcNMjgwMjA3MjIxMzM2\nWjAYMRYwFAYDVQQDDA0qLmFtYXppbmcuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAvp8dk13u4vmAfKfRNOO8+rVQ8q+vyR8scc9Euj0pTodLBflM\n2K6Zk0isirRzCL/jd4n1A6QrPeJ+r2J4xtHk2j+pavt8Sa2Go2MzpAe3OTuIqYJf\nUt7Im3f2Lb67itTPrpA2TR3A/dDFlazju+eBd3t3496Do8aBPpXAdOabfPsrv3nE\nx97vrr4tzeK3kG9u7GYuod5gyiwF2t5wSeMWbFk2oqkOCtHRXE77JDKVxIGiepnU\nTnkW9b7jIkiBQ1x0xHG4soewV2ymGHS2XrUHZ45FFMG7yVYpytKT9Iz9ty/z5VcL\nZ6NzgU/pKfQaIe8MpoDpVf5UNeB2DOAAEoJKKwIDAQABoykwJzAlBgNVHREEHjAc\nggthbWF6aW5nLmNvbYINKi5hbWF6aW5nLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA\nMULk6B9XrVPAole8W66o3WUUOrC7NVjbwZjr+Kp5oQTSo84qacaZS2C3ox/j/TZY\nUuNvoE6gIOHi+inN+G4P76K7NEvm8+Y1CeAyaPq01H4Qy2lk9F5wFMtPqvBZnF9C\nx1MvV30FruHXe5pDfnG1npKECpn2SgE3k6FRHM55u8rTMEm/O4TtsDq+fPqUvyWa\nZuRjPv4qVGGkoPyxA6iffxclpOAXs3JUgLcYoM2vxKC0YSOjHEa0p4uffX063Jgg\nybuy3OKvm+8L6moycX7J+LZK81dDTFDtF7PwrnRbpS4re0i/LSk23jDQvDOLnrAa\nSawRR8+1QHTENBo7dnP+NA==\n-----END CERTIFICATE-----'; const validKey3 = '-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+nx2TXe7i+YB8\np9E047z6tVDyr6/JHyxxz0S6PSlOh0sF+UzYrpmTSKyKtHMIv+N3ifUDpCs94n6v\nYnjG0eTaP6lq+3xJrYajYzOkB7c5O4ipgl9S3sibd/YtvruK1M+ukDZNHcD90MWV\nrOO754F3e3fj3oOjxoE+lcB05pt8+yu/ecTH3u+uvi3N4reQb27sZi6h3mDKLAXa\n3nBJ4xZsWTaiqQ4K0dFcTvskMpXEgaJ6mdROeRb1vuMiSIFDXHTEcbiyh7BXbKYY\ndLZetQdnjkUUwbvJVinK0pP0jP23L/PlVwtno3OBT+kp9Boh7wymgOlV/lQ14HYM\n4AASgkorAgMBAAECggEAdVSVLMcNqlGuv4vAHtDq2lpOaAKxrZbtkWPlxsisqzRl\nfljT7y+RQfHimkG16LXL+iFFWadsIlxOY/+1nZNGTPwQeNQwzVzs2ZbPC3DgW28E\nkGm56NVOHzu4oLGc2DhjWOxVMCRXTSN66sUPK/K0YunxgqXM2zrtBKvCWXI0VLlo\nN/UWAwHf4i0GWRl8u8PvxgMXlSW9p9l6gSsivWRMag9ADwRQ/NSKrRYkiOoRe3vz\nLxXARBvzeZXvOPVLGVRX4SIR7OmS8cC6Ol/rp1/ZFFID7aN+wdzphPSL1UNUriw4\nDv1mxz73SNakgeYSFBoWRS5BsJI01JoCoILsnhVCiQKBgQDyW+k5+j4K17fzwsmi\nyxZ0Nz/ncpkqxVrWYZM3pn7OVkb2NDArimEk53kmJ0hrT84kKJUYDx55R2TpnzpV\nMLmjxgs9TUrzZzsL/DP2ppkfE3OrPS+06OGa5GbURxD6KPvqDtOmU3oFyJ3f4YJR\nVK7RW+zO4sXEpHIxwdBXbYov1QKBgQDJWbt+W5M0sA2D5LrUBNMTvMdNnKH0syc2\nZlcIOdj6HuUIveYpBRq64Jn9VJpXMxQanwE+IUjCpPTa8wF0OA6MZPy6cfovqb8a\ni1/M/lvCoYVS3KHLcTOvTGD3xej0EUj13xWGNu8y3i7Z9/Bl21hEyjd0q0I5OqJx\no9Qa5TGR/wKBgBPfkYpdiMTe14i3ik09FgRFm4nhDcpCEKbPrYC8uF03Ge6KbQDF\nAh5ClN6aDggurRqt8Tvd0YPkZNP7aI8fxbk2PimystiuuFrNPX2WP6warjt2cvkE\nt6s522zAvxWkUrPor1ZONg1PXBLFrSf6J7OnNA3q7oina23FFM52fwRZAoGAZ7l7\nFffU2IKNI9HT0N7/YZ6RSVEUOXuFCsgjs5AhT5BUynERPTZs87I6gb9wltUwWRpq\nSHhbBDJ4FMa0jAtIq1hmvSF0EdOvJ9x+qJqr6JLOnMYd7zDMwFRna5yfigPRgx+9\n9dsc1CaTGiRYyg/5484MTWTgA51KC6Kq5IQHSj8CgYBr9rWgqM8hVCKSt1cMguQV\nTPaV97+u3kV2jFd/aVgDtCDIVvp5TPuqfskE1v3MsSjJ8hfHdYvyxZB8h8T4LlTD\n2HdxwCjVh2qirAvkar2b1mfA6R8msmVaIxBu4MqDcIPqR823klF7A8jSD3MGzYcU\nbnnxMdwgWQkmx0/6/90ZCg==\n-----END PRIVATE KEY-----\n'; - it('does not allow empty string for cert', function () { - expect(reverseProxy.validateCertificate('', foobarDomain, { cert: '', key: 'key' })).to.be.an(Error); + it('does not allow empty string for cert', async function () { + const [error] = await safe(reverseProxy.validateCertificate('', foobarDomain, { cert: '', key: 'key' })); + expect(error.reason).to.be(BoxError.BAD_FIELD); }); - it('does not allow empty string for key', function () { - expect(reverseProxy.validateCertificate('', foobarDomain, { cert: 'cert', key: '' })).to.be.an(Error); + it('does not allow empty string for key', async function () { + const [error] = await safe(reverseProxy.validateCertificate('', foobarDomain, { cert: 'cert', key: '' })); + expect(error.reason).to.be(BoxError.BAD_FIELD); }); - it('does not allow invalid cert', function () { - expect(reverseProxy.validateCertificate('', foobarDomain, { cert: 'someinvalidcert', key: validKey0 })).to.be.an(Error); + it('does not allow invalid cert', async function () { + const [error] = await safe(reverseProxy.validateCertificate('', foobarDomain, { cert: 'someinvalidcert', key: validKey0 })); + expect(error.reason).to.be(BoxError.BAD_FIELD); }); - it('does not allow invalid key', function () { - expect(reverseProxy.validateCertificate('', foobarDomain, { cert: validCert0, key: 'invalidkey' })).to.be.an(Error); + it('does not allow invalid key', async function () { + const [error] = await safe(reverseProxy.validateCertificate('', foobarDomain, { cert: validCert0, key: 'invalidkey' })); + expect(error.reason).to.be(BoxError.BAD_FIELD); }); - it('does not allow cert without matching domain', function () { - expect(reverseProxy.validateCertificate('', 'cloudron.io', { cert: validCert0, key: validKey0 })).to.be.an(Error); - expect(reverseProxy.validateCertificate('cloudron.io', foobarDomain, { cert: validCert0, key: validKey0 })).to.be.an(Error); + it('does not allow cert without matching domain', async function () { + const [error] = await safe(reverseProxy.validateCertificate('', 'cloudron.io', { cert: validCert0, key: validKey0 })); + expect(error.reason).to.be(BoxError.BAD_FIELD); + + const [error2] = await safe(reverseProxy.validateCertificate('cloudron.io', foobarDomain, { cert: validCert0, key: validKey0 })); + expect(error2.reason).to.be(BoxError.BAD_FIELD); }); - it('allows valid cert with matching domain', function () { - expect(reverseProxy.validateCertificate('', foobarDomain, { cert: validCert0, key: validKey0 })).to.be(null); + it('allows valid cert with matching domain', async function () { + await reverseProxy.validateCertificate('', foobarDomain, { cert: validCert0, key: validKey0 }); }); - it('allows valid cert with matching domain (wildcard)', function () { - expect(reverseProxy.validateCertificate('abc', foobarDomain, { cert: validCert1, key: validKey1 })).to.be(null); + it('allows valid cert with matching domain (wildcard)', async function () { + await reverseProxy.validateCertificate('abc', foobarDomain, { cert: validCert1, key: validKey1 }); }); - it('does now allow cert without matching domain (wildcard)', function () { - expect(reverseProxy.validateCertificate('', foobarDomain, { cert: validCert1, key: validKey1 })).to.be.an(Error); - expect(reverseProxy.validateCertificate('bar.abc', foobarDomain, { cert: validCert1, key: validKey1 })).to.be.an(Error); + it('does now allow cert without matching domain (wildcard)', async function () { + const [error] = await safe(reverseProxy.validateCertificate('', foobarDomain, { cert: validCert1, key: validKey1 })); + expect(error.reason).to.be(BoxError.BAD_FIELD); + + const [error2] = await safe(reverseProxy.validateCertificate('bar.abc', foobarDomain, { cert: validCert1, key: validKey1 })); + expect(error2.reason).to.be(BoxError.BAD_FIELD); }); - it('allows valid cert with matching domain (subdomain)', function () { - expect(reverseProxy.validateCertificate('baz', foobarDomain, { cert: validCert2, key: validKey2 })).to.be(null); + it('allows valid cert with matching domain (subdomain)', async function () { + await reverseProxy.validateCertificate('baz', foobarDomain, { cert: validCert2, key: validKey2 }); }); - it('does not allow cert without matching domain (subdomain)', function () { - expect(reverseProxy.validateCertificate('baz', foobarDomain, { cert: validCert0, key: validKey0 })).to.be.an(Error); + it('does not allow cert without matching domain (subdomain)', async function () { + const [error] = await safe(reverseProxy.validateCertificate('baz', foobarDomain, { cert: validCert0, key: validKey0 })); + expect(error.reason).to.be(BoxError.BAD_FIELD); }); - it('does not allow invalid cert/key tuple', function () { + it('does not allow invalid cert/key tuple', async function () { //expect(reverseProxy.validateCertificate('', foobarDomain, { cert: validCert0, key: validKey1 })).to.be.an(Error); }); - it('picks certificate in SAN', function () { - expect(reverseProxy.validateCertificate('', amazingDomain, { cert: validCert3, key: validKey3 })).to.be(null); - expect(reverseProxy.validateCertificate('subdomain', amazingDomain, { cert: validCert3, key: validKey3 })).to.be(null); + it('picks certificate in SAN', async function () { + await reverseProxy.validateCertificate('', amazingDomain, { cert: validCert3, key: validKey3 }); + await reverseProxy.validateCertificate('subdomain', amazingDomain, { cert: validCert3, key: validKey3 }); }); - it('allows valid cert with matching domain (subdomain) - ecdsa', function () { - expect(reverseProxy.validateCertificate('baz', foobarDomain, { cert: validCert4, key: validKey4 })).to.be(null); + it('allows valid cert with matching domain (subdomain) - ecdsa', async function () { + reverseProxy.validateCertificate('baz', foobarDomain, { cert: validCert4, key: validKey4 }); }); }); @@ -123,9 +136,9 @@ describe('Reverse Proxy', function () { expect(result).to.be.ok(); }); - it('can validate the certs', function () { - expect(reverseProxy.validateCertificate('foo', domain, result)).to.be(null); - expect(reverseProxy.validateCertificate('', domain, result)).to.be(null); + it('can validate the certs', async function () { + await reverseProxy.validateCertificate('foo', domain, result); + await reverseProxy.validateCertificate('', domain, result); }); });