mirror of https://github.com/OpenVidu/openvidu.git
153 lines
4.0 KiB
TypeScript
153 lines
4.0 KiB
TypeScript
import { execFileSync } from 'node:child_process';
|
|
import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
|
|
import { GenericContainer, type StartedTestContainer, Wait } from 'testcontainers';
|
|
import { afterAll, beforeAll, describe, expect, inject, it } from 'vitest';
|
|
|
|
import { startDashboard } from '../../src/lifecycle/startup.js';
|
|
import { freePort } from '../support/free-port.js';
|
|
|
|
const MONGO_IMAGE = process.env.DASHBOARD_TEST_MONGO_IMAGE ?? 'openvidu/mongodb:8.0.29-r1';
|
|
|
|
/** A private CA and a localhost server certificate signed by it, generated with openssl for this run. */
|
|
function certificates(): { dir: string; ca: string; serverPem: string } {
|
|
const dir = mkdtempSync(join(tmpdir(), 'dashboard-tls-'));
|
|
const run = (...args: string[]) => execFileSync('openssl', args, { cwd: dir, stdio: 'pipe' });
|
|
run(
|
|
'req',
|
|
'-x509',
|
|
'-newkey',
|
|
'rsa:2048',
|
|
'-nodes',
|
|
'-keyout',
|
|
'ca.key',
|
|
'-out',
|
|
'ca.pem',
|
|
'-days',
|
|
'2',
|
|
'-subj',
|
|
'/CN=dashboard-test-ca'
|
|
);
|
|
run(
|
|
'req',
|
|
'-newkey',
|
|
'rsa:2048',
|
|
'-nodes',
|
|
'-keyout',
|
|
'server.key',
|
|
'-out',
|
|
'server.csr',
|
|
'-subj',
|
|
'/CN=localhost'
|
|
);
|
|
writeFileSync(join(dir, 'san.cnf'), 'subjectAltName=DNS:localhost,IP:127.0.0.1\n');
|
|
run(
|
|
'x509',
|
|
'-req',
|
|
'-in',
|
|
'server.csr',
|
|
'-CA',
|
|
'ca.pem',
|
|
'-CAkey',
|
|
'ca.key',
|
|
'-CAcreateserial',
|
|
'-out',
|
|
'server.crt',
|
|
'-days',
|
|
'2',
|
|
'-extfile',
|
|
'san.cnf'
|
|
);
|
|
const serverPem = join(dir, 'server.pem');
|
|
writeFileSync(
|
|
serverPem,
|
|
readFileSync(join(dir, 'server.crt'), 'utf8') + readFileSync(join(dir, 'server.key'), 'utf8')
|
|
);
|
|
|
|
return { dir, ca: join(dir, 'ca.pem'), serverPem };
|
|
}
|
|
|
|
// Runs with the other MongoDB suites; Docker availability is what mongoUri reports.
|
|
describe.skipIf(inject('mongoUri') === '')('MongoDB with a private CA', () => {
|
|
let container: StartedTestContainer;
|
|
let tls: ReturnType<typeof certificates>;
|
|
let url: string;
|
|
|
|
beforeAll(async () => {
|
|
tls = certificates();
|
|
container = await new GenericContainer(MONGO_IMAGE)
|
|
.withEntrypoint(['/opt/bitnami/mongodb/bin/mongod'])
|
|
.withCommand([
|
|
'--bind_ip_all',
|
|
'--port',
|
|
'27017',
|
|
'--dbpath',
|
|
'/tmp',
|
|
'--wiredTigerCacheSizeGB',
|
|
'0.25',
|
|
'--tlsMode',
|
|
'requireTLS',
|
|
'--tlsCertificateKeyFile',
|
|
'/certs/server.pem',
|
|
'--tlsCAFile',
|
|
'/certs/ca.pem',
|
|
'--tlsAllowConnectionsWithoutCertificates'
|
|
])
|
|
.withCopyFilesToContainer([
|
|
{ source: tls.serverPem, target: '/certs/server.pem', mode: 0o644 },
|
|
{ source: tls.ca, target: '/certs/ca.pem', mode: 0o644 }
|
|
])
|
|
.withExposedPorts(27017)
|
|
.withResourcesQuota({ memory: 1 })
|
|
.withWaitStrategy(Wait.forListeningPorts())
|
|
.start();
|
|
url = `mongodb://localhost:${String(container.getMappedPort(27017))}/?directConnection=true`;
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await container.stop();
|
|
});
|
|
|
|
async function start(env: NodeJS.ProcessEnv) {
|
|
const exits: number[] = [];
|
|
const running = await startDashboard({
|
|
edition: 'ce',
|
|
version: '3.10.0-test',
|
|
appRoot: '/nonexistent',
|
|
handleSignals: false,
|
|
exit: (code) => exits.push(code),
|
|
env: {
|
|
ADMIN_USERNAME: 'admin',
|
|
ADMIN_PASSWORD: 'secret',
|
|
LOG_LEVEL: 'error',
|
|
SERVER_PORT: String(await freePort()),
|
|
DATABASE_URL: url,
|
|
...env
|
|
}
|
|
});
|
|
|
|
return { running, exits };
|
|
}
|
|
|
|
it('connects when DATABASE_TLS_CA_FILE trusts the server certificate', async () => {
|
|
const { running, exits } = await start({ DATABASE_TLS_CA_FILE: tls.ca });
|
|
expect(running).toBeDefined();
|
|
await running?.shutdown.run(0);
|
|
expect(exits).toEqual([0]);
|
|
});
|
|
|
|
it('does not connect without the CA file', async () => {
|
|
const { running, exits } = await start({});
|
|
expect(running).toBeUndefined();
|
|
expect(exits).toEqual([1]);
|
|
}, 30_000);
|
|
|
|
it('exits with code 1 when the CA file cannot be read', async () => {
|
|
const { running, exits } = await start({ DATABASE_TLS_CA_FILE: join(tls.dir, 'missing.pem') });
|
|
expect(running).toBeUndefined();
|
|
expect(exits).toEqual([1]);
|
|
});
|
|
});
|