// faviconHost tests (js/app.favicon.js) — the pure URL→validated-hostname // function that decides which domain (if any) is sent to the DuckDuckGo // favicon proxy. A bug here means a DNS-ish leak of the wrong host, so the // validation rules are worth pinning down. const test = require('node:test'); const assert = require('node:assert/strict'); const { loadApp } = require('./harness.js'); const T = loadApp().__test; const host = (s) => T.faviconHost(s); test('faviconHost: strips scheme, www, path, port', () => { assert.equal(host('https://www.github.com/user/repo'), 'github.com'); assert.equal(host('http://example.com'), 'example.com'); assert.equal(host('www.example.com'), 'example.com'); assert.equal(host('example.com:8443/login'), 'example.com'); assert.equal(host('HTTPS://WWW.Example.COM'), 'example.com'); }); test('faviconHost: keeps subdomains (SLD fallback is the caller\'s job)', () => { assert.equal(host('chat.qwen.ai'), 'chat.qwen.ai'); assert.equal(host('git.example.co.uk'), 'git.example.co.uk'); }); test('faviconHost: rejects non-hostnames → "" (no lookup, no leak)', () => { assert.equal(host('Gitea'), ''); // brand name, no dot assert.equal(host('my work pwd'), ''); // spaces assert.equal(host('localhost'), ''); // no TLD assert.equal(host(''), ''); assert.equal(host(null), ''); assert.equal(host(undefined), ''); }); test('faviconHost: rejects malformed dotting', () => { assert.equal(host('.example.com'), ''); // leading dot assert.equal(host('example.com.'), ''); // trailing dot assert.equal(host('a..b.com'), ''); // double dot assert.equal(host('example.x'), ''); // 1-char TLD }); test('faviconHost: rejects hostname-unsafe characters', () => { assert.equal(host('exa mple.com'), ''); assert.equal(host('exam_ple.com'), ''); // underscore not hostname-safe assert.equal(host('ex+ample.com'), ''); }); test('faviconHost: raw IPs are rejected (numeric final label fails the TLD rule)', () => { // NOTE: the source comment claims IPs "stay valid", but the TLD check // /\.[a-z]{2,}$/ requires a LETTERS final label, so a numeric last octet // is rejected → '' (no lookup). Actual behaviour, pinned here; the code // comment is inaccurate. Harmless: DDG has no favicon for a bare IP anyway. assert.equal(host('1.2.3.44'), ''); assert.equal(host('192.168.0.1'), ''); }); test('faviconHost: enforces the 253-char DNS cap', () => { const long = 'a'.repeat(250) + '.com'; // 254 chars assert.equal(host(long), ''); const ok = 'a'.repeat(60) + '.com'; // well under cap, valid assert.equal(host(ok), ok); });