import * as plugins from './plugins.js'; import * as paths from './paths.js'; import * as helpers from './helpers.js'; export interface IThreatFoxData { ID: string; Dateadded: string; URL: string; URLStatus: string; Threat: string; AssociatedTags: string; ThreatFoxLink: string; Reporter: string; } export class ThreatFox { private static readonly THREATFOX_API_URL: string = 'https://threatfox.abuse.ch/export/csv/full'; // Replace with actual API endpoint public async getData(): Promise { plugins.smartfile.fs.ensureDirSync(paths.threatFoxTmp); const zipPath = plugins.path.join(paths.threatFoxTmp, 'threatfox.zip'); const csvPath = plugins.path.join(paths.threatFoxTmp, 'full.csv'); const response = await plugins.nodeFetch(ThreatFox.THREATFOX_API_URL, { ...(helpers.findProxy() ? { agent: helpers.getAgent(), } : {}) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } await new Promise((resolve, reject) => { const fileStream = plugins.fs.createWriteStream(zipPath); // @ts-ignore const readable = plugins.stream.Readable.from(response.body); plugins.stream.pipeline(readable, fileStream, (err) => { if (err) reject(err); else resolve(null); }); }); await new Promise((resolve, reject) => { plugins.stream.pipeline( plugins.fs.createReadStream(zipPath), plugins.unzipper.Extract({ path: paths.threatFoxTmp }), (err) => { if (err) reject(err); else resolve(null); } ); }); let data: IThreatFoxData[] = []; await new Promise((resolve, reject) => { plugins.stream.pipeline( plugins.fs.createReadStream(csvPath), plugins.csv({ headers: ['ID', 'Dateadded', 'URL', 'URLStatus', 'Threat', 'AssociatedTags', 'ThreatFoxLink', 'Reporter'], mapValues: ({ header, value }) => value.trim() }), (err) => { if (err) reject(err); } ) .on('data', (row) => { data.push(row); }) .on('end', resolve) .on('error', reject); }); data = data.map((item) => { return { ...item, URL: item.URL?.replace('http', 'ht-NOCLICK-NOLINK-tp'), } }); plugins.smartfile.fs.removeSync(paths.threatFoxTmp); return data; } }