UNPKG

frida-gadget-ios

Version:
148 lines (116 loc) 3.37 kB
const fs = require('fs'); const gadget = require('.'); const https = require('https'); const path = require('path'); const util = require('util'); const zlib = require('zlib'); const access = util.promisify(fs.access); const readdir = util.promisify(fs.readdir); const rename = util.promisify(fs.rename); const unlink = util.promisify(fs.unlink); async function run() { await pruneOldVersions(); if (await alreadyDownloaded()) return; await download(); } async function alreadyDownloaded() { try { await access(gadget.path, fs.constants.F_OK); return true; } catch (e) { return false; } } async function download() { const response = await httpsGet(`https://github.com/frida/frida/releases/download/${gadget.version}/frida-gadget-${gadget.version}-ios-universal.dylib.gz`); const tempGadgetPath = gadget.path + '.download'; const tempGadgetStream = fs.createWriteStream(tempGadgetPath); await pump(response, zlib.createGunzip(), tempGadgetStream); await rename(tempGadgetPath, gadget.path); } async function pruneOldVersions() { const gadgetDir = path.dirname(gadget.path); const currentName = path.basename(gadget.path); for (const name of await readdir(gadgetDir)) { if (name.startsWith('frida-gadget-') && name.endsWith('-ios-universal.dylib') && name !== currentName) { await unlink(path.join(gadgetDir, name)); } } } function httpsGet(url) { return new Promise((resolve, reject) => { let redirects = 0; tryGet(url); function tryGet(url) { const request = https.get(url, response => { tearDown(); const {statusCode, headers} = response; if (statusCode === 200) { resolve(response); } else { response.resume(); if (statusCode >= 300 && statusCode < 400 && headers.location !== undefined) { if (redirects === 10) { reject(new Error('Too many redirects')); return; } redirects++; tryGet(headers.location); } else { reject(new Error(`Download failed (code=${statusCode})`)); } } }); request.addListener('error', onError); function onError(error) { tearDown(); reject(error); } function tearDown() { request.removeListener('error', onError); } } }); } function pump(...streams) { return new Promise((resolve, reject) => { let done = false; streams.forEach(stream => { stream.addListener('error', onError); }); for (let i = 0; i !== streams.length - 1; i++) { const cur = streams[i]; const next = streams[i + 1]; cur.pipe(next); } const last = streams[streams.length - 1]; last.addListener('finish', onFinish); function onFinish() { if (done) return; done = true; tearDown(); resolve(); } function onError(error) { if (done) return; done = true; tearDown(); reject(error); } function tearDown() { last.removeListener('finish', onFinish); streams.forEach(stream => { stream.removeListener('error', onError); stream.destroy(); }); } }); } run().catch(onError); function onError(error) { console.error(error.message); process.exitCode = 1; }