61 行
2.0 KiB
JavaScript
61 行
2.0 KiB
JavaScript
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
|
|
})
|