'use strict'; const net = require('node:net'); function sourceUrl(value, prefix) { const url = new URL(value); if (url.protocol !== 'https:' || url.hostname !== 'weebcentral.com' || url.username || url.password || !url.pathname.startsWith(prefix)) { throw new Error('Source plugin returned an unexpected WeebCentral URL'); } return url.href; } function imageUrl(value) { const url = new URL(value); const hostname = url.hostname.toLowerCase(); if (url.protocol !== 'https:' || url.username || url.password || net.isIP(hostname) || hostname === 'localhost' || hostname.endsWith('.localhost') || hostname.endsWith('.local') || !hostname.includes('.')) { throw new Error('Source plugin returned an unsafe image URL'); } return url.href; } function validate(plugin, operation, output) { if (plugin !== 'weebcentral' || !output || typeof output !== 'object' || Array.isArray(output)) { throw new Error('Invalid source plugin output'); } if (operation === 'series') { if (typeof output.title !== 'string' || typeof output.listUrl !== 'string' && output.listUrl !== null) throw new Error('Invalid series parse'); if (output.listUrl !== null) sourceUrl(output.listUrl, '/series/'); } else if (operation === 'catalog') { if (!Array.isArray(output.chapters) || !Number.isInteger(output.chapterLinks) || output.chapterLinks < 0) throw new Error('Invalid catalog parse'); for (const chapter of output.chapters) { if (!chapter || typeof chapter.id !== 'string' || typeof chapter.number !== 'string') throw new Error('Invalid chapter reference'); sourceUrl(chapter.url, '/chapters/'); } } else if (operation === 'chapter') { sourceUrl(output.manifestUrl, '/chapters/'); if (!new URL(output.manifestUrl).pathname.endsWith('/images')) throw new Error('Invalid chapter image manifest'); } else if (operation === 'pages') { if (!Array.isArray(output.pages)) throw new Error('Invalid page parse'); for (const page of output.pages) imageUrl(page); } else throw new Error('Unknown source plugin operation'); return output; } module.exports = { validate };