settings: the SIP port, with a check against other listeners
This commit is contained in:
1 parent
6893c55e1b
commit
f2868cf5d3
5 files changed
+87
-7
No files matched your search
@@ -115,6 +115,20 @@ export async function settingsRoutes(app: FastifyInstance) {
|
||||
}
|
||||
await checkRefs(db, values);
|
||||
const before = await getAllSettings(db);
|
||||
// SIP ports may not land on another listener (Asterisk would fail to start the transport).
|
||||
const c = app.config;
|
||||
const [sip, tls] = [
|
||||
(values['sip.udpPort'] ?? before['sip.udpPort']) as number,
|
||||
(values['sip.tlsPort'] ?? before['sip.tlsPort']) as number,
|
||||
];
|
||||
for (const port of [sip, tls])
|
||||
if ([80, 443, 8088, c.AMI_PORT, c.API_PORT].includes(port))
|
||||
throw badRequest(`Port ${port} is already used by SelfPhoneNG`);
|
||||
else if (port >= c.RTP_PORT_START && port <= c.RTP_PORT_END)
|
||||
throw badRequest(
|
||||
`Port ${port} is in the call audio range (${c.RTP_PORT_START}–${c.RTP_PORT_END})`,
|
||||
);
|
||||
if (sip === tls) throw badRequest('The SIP port and the TLS port must differ');
|
||||
if (values['sip.tlsEnabled'] === true && !before['sip.tlsEnabled']) {
|
||||
const cert = await readTlsCert(app.config.TLS_DIR);
|
||||
if (!cert.ok) throw badRequest(`Can't turn on TLS. ${cert.error}`);
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// The SIP port (Settings → Security), for routers or ISPs that keep UDP 5060 for themselves.
|
||||
import type { LightMyRequestResponse } from 'fastify';
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||
import { hasTestDb } from './db.ts';
|
||||
import { ADMIN, H, createTestApp } from './app.ts';
|
||||
|
||||
describe.skipIf(!hasTestDb)('SIP port setting', () => {
|
||||
let t: Awaited<ReturnType<typeof createTestApp>>;
|
||||
let req: (method: string, url: string, payload?: unknown) => Promise<LightMyRequestResponse>;
|
||||
|
||||
beforeAll(async () => {
|
||||
t = await createTestApp();
|
||||
await t.clearMustChange(ADMIN.email);
|
||||
const cookie = await t.login(ADMIN.email, ADMIN.password);
|
||||
req = (method, url, payload) =>
|
||||
t.app.inject({
|
||||
method: method as 'GET',
|
||||
url,
|
||||
payload: payload as object,
|
||||
headers: { ...H, cookie },
|
||||
});
|
||||
});
|
||||
afterAll(() => t?.close());
|
||||
|
||||
it('refuses ports something else listens on', async () => {
|
||||
for (const [port, msg] of [
|
||||
[8080, /already used/],
|
||||
[5038, /already used/],
|
||||
[15000, /call audio range/],
|
||||
[5061, /must differ/],
|
||||
] as const) {
|
||||
const r = await req('PATCH', '/api/settings', { 'sip.udpPort': port });
|
||||
expect(r.statusCode, String(port)).toBe(400);
|
||||
expect(r.json().error.message).toMatch(msg);
|
||||
}
|
||||
});
|
||||
|
||||
it('5080 is saved, and phones are told', async () => {
|
||||
const r = await req('PATCH', '/api/settings', { 'sip.udpPort': 5080 });
|
||||
expect(r.statusCode).toBe(200);
|
||||
expect(r.json()['sip.udpPort']).toBe(5080);
|
||||
expect((await req('GET', '/api/system/status')).json().ports.sip).toBe(5080);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user