test(diagnostics): live network-bind path — allowlisted non-loopback peer connects over a real 0.0.0.0 socket
Closes the one link the unit/wiring tests covered only by composition: binds 0.0.0.0, allowlists a real LAN IPv4, and asserts auth-ok over a real socket (the Tailscale path). Skips when no non-internal IPv4 interface exists. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8dff455062
commit
b25b51840d
@ -1,10 +1,20 @@
|
|||||||
const { test } = require('node:test');
|
const { test } = require('node:test');
|
||||||
const assert = require('node:assert');
|
const assert = require('node:assert');
|
||||||
|
const os = require('os');
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
const RemoteServer = require('../lib/remote-server');
|
const RemoteServer = require('../lib/remote-server');
|
||||||
|
|
||||||
const TOKEN = 'a'.repeat(64);
|
const TOKEN = 'a'.repeat(64);
|
||||||
|
|
||||||
|
function firstLanIpv4() {
|
||||||
|
for (const entry of Object.values(os.networkInterfaces())) {
|
||||||
|
for (const net of (entry || [])) {
|
||||||
|
if (net && net.family === 'IPv4' && !net.internal && net.address) return net.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function startAgent(onDiagnosticRequest, extra) {
|
function startAgent(onDiagnosticRequest, extra) {
|
||||||
const srv = new RemoteServer();
|
const srv = new RemoteServer();
|
||||||
return srv.start({ port: 0, host: '127.0.0.1', token: TOKEN, diagnosticMode: true, onDiagnosticRequest, ...(extra || {}) })
|
return srv.start({ port: 0, host: '127.0.0.1', token: TOKEN, diagnosticMode: true, onDiagnosticRequest, ...(extra || {}) })
|
||||||
@ -78,6 +88,22 @@ test('a loopback diagnostic client connects even with a non-matching allowlist (
|
|||||||
ws.close(); agent.stop();
|
ws.close(); agent.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('network bind (0.0.0.0): an allowlisted non-loopback peer connects over a real socket (the Tailscale path)', async (t) => {
|
||||||
|
const lan = firstLanIpv4();
|
||||||
|
if (!lan) { t.skip('no non-internal IPv4 interface available'); return; }
|
||||||
|
const agent = await startAgent(() => {}, { host: '0.0.0.0', allowlist: [lan] });
|
||||||
|
const port = agent.getPort();
|
||||||
|
const ws = new WebSocket(`ws://${lan}:${port}`);
|
||||||
|
try {
|
||||||
|
await new Promise((resolve, reject) => { ws.on('open', resolve); ws.on('error', reject); });
|
||||||
|
ws.send(JSON.stringify({ type: 'auth', token: TOKEN, role: 'diagnostic' }));
|
||||||
|
const ok = await once(ws, 'auth-ok');
|
||||||
|
assert.ok(ok.clientId, 'allowlisted LAN peer authed over the 0.0.0.0 bind');
|
||||||
|
} finally {
|
||||||
|
ws.close(); agent.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('wrong token is rejected and the ip is locked out after 5 attempts', async () => {
|
test('wrong token is rejected and the ip is locked out after 5 attempts', async () => {
|
||||||
const agent = await startAgent(() => {});
|
const agent = await startAgent(() => {});
|
||||||
const port = agent.getPort();
|
const port = agent.getPort();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user