const puppeteer = require ('puppeteer') const dns = require ('dns').promises const net = require ('net') const forbiddenNetworks = [ ['0.0.0.0', 8], ['10.0.0.0', 8], ['100.64.0.0', 10], ['127.0.0.0', 8], ['169.254.0.0', 16], ['172.16.0.0', 12], ['192.0.0.0', 24], ['192.0.2.0', 24], ['192.168.0.0', 16], ['198.18.0.0', 15], ['198.51.100.0', 24], ['203.0.113.0', 24], ['224.0.0.0', 4], ['240.0.0.0', 4], ['::', 128], ['::1', 128], ['fc00::', 7], ['fe80::', 10], ['ff00::', 8], ['2001:db8::', 32], ['::ffff:0:0', 96]] const blockList = new net.BlockList () forbiddenNetworks.forEach (([address, prefix]) => { blockList.addSubnet (address, prefix, net.isIPv6 (address) ? 'ipv6' : 'ipv4') }) const safeUrl = async rawUrl => { const url = new URL (rawUrl) if (!['http:', 'https:'].includes (url.protocol) || url.username || url.password) return false const addresses = await dns.lookup (url.hostname, { all: true, verbatim: true }) return addresses.length > 0 && addresses.every ( ({ address, family }) => !blockList.check (address, family === 6 ? 'ipv6' : 'ipv4')) } void (async () => { const url = process.argv[2] const output = process.argv[3] if (!(await safeUrl (url))) throw new Error ('Unsafe page URL') const browser = await puppeteer.launch ({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }) try { const page = await browser.newPage () await page.setRequestInterception (true) page.on ('request', request => { void safeUrl (request.url ()) .then (safe => safe ? request.continue () : request.abort ()) .catch (() => request.abort ()) }) await page.setViewport ({ width: 960, height: 960 }) await page.goto (url, { waitUntil: 'domcontentloaded', timeout: 12000 }) await new Promise (resolve => setTimeout (resolve, 1000)) await page.screenshot ({ path: output }) } finally { await browser.close () } }) ().catch (error => { console.error (error) process.exitCode = 1 })