7f2ecce57f
- add iceServers.js: allowlist-based validation/normalization of user-supplied STUN/TURN URLs (rejects javascript:/data:/http/ws, control chars, enforces limits) - add iceSettingsStore.js: opt-in persistence encrypted at rest with a non-extractable AES-GCM device key in IndexedDB; load/save/clear - add IceServerSettings.jsx modal: public vs custom servers, JSON/line input, live validation, relay-only toggle, 'Test servers' connectivity check, save-on-device prompt, forget-saved action - wire chosen servers/privacy mode into EnhancedSecureWebRTCManager construction (priority: custom > operator override > built-in defaults) - entry point on the connection-creation screen next to the relay-only toggle - add ice-servers-validation.test.mjs to the suite
122 lines
4.8 KiB
JavaScript
122 lines
4.8 KiB
JavaScript
import assert from 'node:assert';
|
|
import {
|
|
validateIceUrl,
|
|
normalizeIceServers,
|
|
parseIceServersInput,
|
|
listHasTurn,
|
|
ICE_LIMITS
|
|
} from '../src/network/iceServers.js';
|
|
|
|
// --- validateIceUrl: accepts valid STUN/TURN URLs ---
|
|
assert.strictEqual(validateIceUrl('stun:stun.example.com:3478'), null);
|
|
assert.strictEqual(validateIceUrl('stuns:stun.example.com:5349'), null);
|
|
assert.strictEqual(validateIceUrl('turn:turn.example.com:3478?transport=udp'), null);
|
|
assert.strictEqual(validateIceUrl('turns:turn.example.com:5349?transport=tcp'), null);
|
|
assert.strictEqual(validateIceUrl('turn:[2001:db8::1]:3478'), null);
|
|
assert.strictEqual(validateIceUrl('stun:198.51.100.10'), null);
|
|
|
|
// --- validateIceUrl: rejects dangerous / malformed schemes ---
|
|
assert.ok(validateIceUrl('javascript:alert(1)'));
|
|
assert.ok(validateIceUrl('data:text/html,<script>1</script>'));
|
|
assert.ok(validateIceUrl('http://evil.example.com'));
|
|
assert.ok(validateIceUrl('https://evil.example.com'));
|
|
assert.ok(validateIceUrl('ws://evil.example.com'));
|
|
assert.ok(validateIceUrl(' '));
|
|
assert.ok(validateIceUrl(''));
|
|
assert.ok(validateIceUrl(123));
|
|
assert.ok(validateIceUrl('stun:exa mple.com')); // space in host
|
|
assert.ok(validateIceUrl('turn:"><img src=x>')); // markup attempt
|
|
assert.ok(validateIceUrl('turn:host.com?transport=quic')); // bad transport
|
|
assert.ok(validateIceUrl('stun:host.com:99999999')); // absurd port length
|
|
assert.ok(validateIceUrl('stun:' + 'a'.repeat(ICE_LIMITS.MAX_STRING_LENGTH + 10)));
|
|
|
|
console.log('validateIceUrl checks passed');
|
|
|
|
// --- normalizeIceServers: valid structured entries ---
|
|
{
|
|
const { servers, errors, warnings } = normalizeIceServers([
|
|
{ urls: 'stun:stun.example.com:3478' },
|
|
{ urls: ['turn:turn.example.com:3478?transport=udp', 'turn:turn.example.com:3478?transport=tcp'], username: 'u', credential: 'c' }
|
|
]);
|
|
assert.strictEqual(errors.length, 0, `unexpected errors: ${errors}`);
|
|
assert.strictEqual(warnings.length, 0, `unexpected warnings: ${warnings}`);
|
|
assert.strictEqual(servers.length, 2);
|
|
assert.strictEqual(servers[0].urls, 'stun:stun.example.com:3478'); // single url collapses to string
|
|
assert.ok(Array.isArray(servers[1].urls));
|
|
assert.strictEqual(servers[1].username, 'u');
|
|
assert.strictEqual(servers[1].credential, 'c');
|
|
}
|
|
|
|
// --- normalizeIceServers: TURN without credentials -> warning, still included ---
|
|
{
|
|
const { servers, warnings } = normalizeIceServers([{ urls: 'turn:turn.example.com:3478' }]);
|
|
assert.strictEqual(servers.length, 1);
|
|
assert.ok(warnings.some(w => /username and credential/i.test(w)));
|
|
}
|
|
|
|
// --- normalizeIceServers: rejects malicious url, keeps clean ones, reports error ---
|
|
{
|
|
const { servers, errors } = normalizeIceServers([
|
|
{ urls: 'javascript:alert(1)' },
|
|
{ urls: 'stun:good.example.com:3478' }
|
|
]);
|
|
assert.ok(errors.length >= 1);
|
|
assert.strictEqual(servers.length, 1);
|
|
assert.strictEqual(servers[0].urls, 'stun:good.example.com:3478');
|
|
}
|
|
|
|
// --- normalizeIceServers: enforces server count limit ---
|
|
{
|
|
const many = Array.from({ length: ICE_LIMITS.MAX_SERVERS + 1 }, () => ({ urls: 'stun:x.example.com:3478' }));
|
|
const { servers, errors } = normalizeIceServers(many);
|
|
assert.strictEqual(servers.length, 0);
|
|
assert.ok(errors.some(e => /Too many servers/i.test(e)));
|
|
}
|
|
|
|
// --- normalizeIceServers: rejects control chars in credential ---
|
|
{
|
|
const { errors } = normalizeIceServers([
|
|
{ urls: 'turn:t.example.com:3478', username: 'u', credential: 'bad |