mirror of
https://github.com/ancsemi/Haven.git
synced 2026-10-27 17:15:24 +00:00
4.5.0 taught the server to make its certificate itself, but Start Haven.bat, Install Haven.ps1 and the web installer still went looking for openssl.exe first and reported a skipped certificate as done. They now call the same generator through scripts/gen-cert.js, the certificate carries the CA and server-auth flags phones expect when you import it, and the guide and support page stop telling people to install OpenSSL. Reported by MutantRabbit767.
56 lines
3.0 KiB
JavaScript
56 lines
3.0 KiB
JavaScript
'use strict';
|
|
const assert = require('node:assert/strict');
|
|
const test = require('node:test');
|
|
const crypto = require('crypto');
|
|
const fs = require('fs');
|
|
const https = require('https');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
const { generate, ensureCerts, localNames } = require('../src/selfsignedCert');
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'haven-cert-'));
|
|
const made = ensureCerts(dir);
|
|
const certPem = fs.readFileSync(made.certPath, 'utf8');
|
|
const keyPem = fs.readFileSync(made.keyPath, 'utf8');
|
|
const x509 = new crypto.X509Certificate(certPem);
|
|
test('writes cert.pem and key.pem once and leaves them alone after that', () => {
|
|
assert.equal(made.created, true);
|
|
assert.match(certPem, /^-----BEGIN CERTIFICATE-----\n[\s\S]+\n-----END CERTIFICATE-----\n$/);
|
|
assert.match(keyPem, /^-----BEGIN PRIVATE KEY-----/);
|
|
const again = ensureCerts(dir);
|
|
assert.equal(again.created, false);
|
|
assert.equal(fs.readFileSync(again.certPath, 'utf8'), certPem);
|
|
});
|
|
test('parses as a v3 self-signed cert that Node itself trusts as its own issuer', () => {
|
|
assert.equal(x509.subject, 'CN=Haven');
|
|
assert.equal(x509.issuer, 'CN=Haven');
|
|
assert.equal(x509.verify(x509.publicKey), true);
|
|
assert.equal(x509.checkPrivateKey(crypto.createPrivateKey(keyPem)), true);
|
|
assert.ok(x509.ca);
|
|
assert.ok(new Date(x509.validTo).getTime() - new Date(x509.validFrom).getTime() > 3649 * 86400000);
|
|
assert.deepEqual(x509.keyUsage, ['1.3.6.1.5.5.7.3.1']);
|
|
});
|
|
test('SAN covers localhost, the loopback IP, the LAN IPv4s and the hostname', () => {
|
|
const san = x509.subjectAltName;
|
|
assert.match(san, /DNS:localhost/);
|
|
assert.match(san, /IP Address:127\.0\.0\.1/);
|
|
for (const n of localNames()) assert.ok(san.includes(/^\d/.test(n) ? `IP Address:${n}` : `DNS:${n}`), `${n} missing from ${san}`);
|
|
assert.equal(x509.checkHost('localhost'), 'localhost');
|
|
assert.equal(x509.checkIP('127.0.0.1'), '127.0.0.1');
|
|
});
|
|
test('custom names and CN land in the SAN, junk is dropped, and 2050+ expiry still parses', () => {
|
|
const r = generate({ cn: 'haven.example.org', names: ['10.0.0.5', 'bad name!', 'box'], days: 365 * 30 });
|
|
const c = new crypto.X509Certificate(r.cert);
|
|
assert.equal(c.subject, 'CN=haven.example.org');
|
|
assert.equal(c.subjectAltName, 'DNS:haven.example.org, IP Address:10.0.0.5, DNS:box');
|
|
assert.equal(new Date(c.validTo).getUTCFullYear() >= 2050, true);
|
|
assert.equal(c.verify(c.publicKey), true);
|
|
});
|
|
test('a real TLS handshake succeeds against the generated pair', async () => {
|
|
const server = https.createServer({ cert: certPem, key: keyPem }, (req, res) => res.end('ok'));
|
|
await new Promise(r => server.listen(0, '127.0.0.1', r));
|
|
const port = server.address().port;
|
|
const body = await new Promise((resolve, reject) => https.get({ host: '127.0.0.1', port, path: '/', ca: certPem, servername: 'localhost' }, res => { let d = ''; res.on('data', c => d += c); res.on('end', () => resolve(d)); }).on('error', reject));
|
|
server.close();
|
|
assert.equal(body, 'ok');
|
|
});
|