import { extractResources, analyze, isPublicHost, isPrivateIp } from '../src/scan.js'; let fail = 0; const ok = (name, cond, extra = '') => { console.log((cond ? '[PASS] ' : '[FAIL] ') + name + (cond ? '' : ' ' + extra)); if (!cond) fail++; }; const html = ` x `; const base = 'https://example.com/page/'; const resources = extractResources(html, base); ok('finds google maps iframe', resources.some((r) => r.type === 'iframe' && r.url.includes('google.com/maps'))); ok('finds youtube-nocookie iframe', resources.some((r) => r.url.includes('youtube-nocookie.com/embed'))); ok('skips data: iframe', !resources.some((r) => r.url.startsWith('data:'))); ok('finds external script (gtm)', resources.some((r) => r.type === 'script' && r.url.includes('googletagmanager.com'))); ok('resolves relative script to absolute', resources.some((r) => r.url === 'https://example.com/wp-includes/js/jquery.js')); ok('finds external img', resources.some((r) => r.type === 'img' && r.url.includes('cdn.example.com'))); ok('finds link stylesheet', resources.some((r) => r.type === 'link' && r.url.includes('fonts.googleapis.com'))); ok('finds object data (vimeo)', resources.some((r) => r.type === 'object' && r.url.includes('player.vimeo.com'))); ok('ignores anchor href', !resources.some((r) => r.url.includes('twitter.com'))); const findings = analyze([{ url: base, resources }], 'example.com'); const byHost = Object.fromEntries(findings.map((f) => [f.host, f])); ok('example.com is first-party', byHost['example.com'] && byHost['example.com'].third_party === false); ok('cdn.example.com is first-party (subdomain)', byHost['cdn.example.com'].third_party === false); ok('google.com is third-party', byHost['google.com'].third_party === true); ok('googletagmanager third-party', byHost['googletagmanager.com'].third_party === true); ok('third-party sorted first', findings[0].third_party === true); ok('suggested_pattern = host', byHost['player.vimeo.com'].suggested_pattern === 'player.vimeo.com'); ok('types aggregated', Array.isArray(byHost['google.com'].types) && byHost['google.com'].types.includes('iframe')); ok('sample_urls capped at 3', findings.every((f) => f.sample_urls.length <= 3)); ok('pages list source page', Array.isArray(byHost['google.com'].pages) && byHost['google.com'].pages.includes(base)); // pages aggregate across multiple scanned pages const multi = analyze([ { url: 'https://example.com/a', resources: [{ url: 'https://google.com/maps', type: 'iframe' }] }, { url: 'https://example.com/b', resources: [{ url: 'https://google.com/maps', type: 'iframe' }] }, ], 'example.com'); ok('host found on both pages', multi[0].pages.length === 2 && multi[0].pages.includes('https://example.com/a') && multi[0].pages.includes('https://example.com/b')); // www normalization: www.google.com counts as google.com const f2 = analyze([{ url: base, resources: [{ url: 'https://www.google.com/x', type: 'iframe' }] }], 'example.com'); ok('www stripped in host grouping', f2[0].host === 'google.com'); // isPublicHost ok('localhost not public', isPublicHost('localhost') === false); ok('127.0.0.1 not public', isPublicHost('127.0.0.1') === false); ok('10.x not public', isPublicHost('10.1.2.3') === false); ok('192.168 not public', isPublicHost('192.168.0.1') === false); ok('172.16 not public', isPublicHost('172.16.0.1') === false); ok('172.32 IS public', isPublicHost('172.32.0.1') === true); ok('public domain ok', isPublicHost('kunde-a.de') === true); // isPrivateIp (post-DNS-resolution SSRF guard) ok('metadata 169.254.169.254 private', isPrivateIp('169.254.169.254') === true); ok('127.0.0.1 private', isPrivateIp('127.0.0.1') === true); ok('10.x private', isPrivateIp('10.0.0.5') === true); ok('192.168 private', isPrivateIp('192.168.1.1') === true); ok('172.16 private', isPrivateIp('172.16.5.5') === true); ok('172.32 public ip', isPrivateIp('172.32.0.1') === false); ok('CGNAT 100.64 private', isPrivateIp('100.64.0.1') === true); ok('public ip allowed', isPrivateIp('93.184.216.34') === false); ok('::1 private', isPrivateIp('::1') === true); ok('fe80 link-local private', isPrivateIp('fe80::1') === true); ok('fd00 ula private', isPrivateIp('fd12::1') === true); ok('ipv4-mapped metadata private', isPrivateIp('::ffff:169.254.169.254') === true); ok('global ipv6 allowed', isPrivateIp('2606:2800:220:1:248:1893:25c8:1946') === false); ok('empty ip unsafe', isPrivateIp('') === true); console.log('\n' + (fail === 0 ? 'ALL PASSED' : fail + ' FAILED')); process.exit(fail === 0 ? 0 : 1);