spoof-detect / src /puppet.ts
Niv Sardi
deno port
dc89ab8
raw
history blame
3.19 kB
import Puppeteer from "https://deno.land/x/puppeteer@14.1.1/mod.ts";
import EventEmitter from "https://deno.land/x/events@v1.0.0/mod.ts";
import type { Browser, Page } from "https://deno.land/x/puppeteer@14.1.1/mod.ts";
const BROWSER_SIGNALS = [
'disconnected',
'targetchanged',
'targetcreated',
'targetdestroyed'
];
const CHROME_ARGS = [
'--no-sandbox',
'--disable-setuid-sandbox'
];
async function resolve(a: string) {
if (a.match(/(\d.?){4}/)) {
return a;
}
return await Deno.resolveDns(a, "A");
}
export default class Runner extends EventEmitter {
config: {
BROWSERLESS_HOST: string;
BROWSERLESS_PORT: string;
};
target: string;
browser: Browser | undefined;
connected: Promise<boolean> | undefined;
constructor(config = {
BROWSERLESS_HOST: Deno.env.get("BROWSERLESS_HOST") || "localhost",
BROWSERLESS_PORT: Deno.env.get("BROWSERLESS_PORT") || "3000",
}) {
super();
this.target = `ws://${config.BROWSERLESS_HOST}:${config.BROWSERLESS_PORT}`;
this.config = config;
this.connected
}
public async close() {
try {
if (this.browser) await this.browser.close();
} catch (err) {
console.error(`${err} on close`)
}
}
async connect() {
if (!this.connected)
this.connected = this._connect()
return this.connected
}
async _connect() {
try {
const host = await resolve(this.config.BROWSERLESS_HOST);
const ver = await fetch(`http://${host}:${this.config.BROWSERLESS_PORT}/json/version`)
.then(async res => await res.json())
this.target = ver.webSocketDebuggerUrl;
this.browser = this.browser || await Puppeteer.connect({
browserWSEndpoint: this.target
}).catch(() => {
console.error(`
⚠ COULD NOT CONNECT TO BROWSERLESS
🦄 will try to spawn a chromedriver instance for you to debug`)
return Puppeteer.launch({
args: CHROME_ARGS,
headless: false
})
});
if (!this.browser) {
console.error("couldn't init Browser");
return false;
}
BROWSER_SIGNALS.map(e => this.browser?.on(e, d => this.emit(`browser:${e}`, d)))
this.browser.on('error', e => console.error(`got browser error: ${e}`))
const pages = await this.browser.pages();
for (let p in pages) {
await pages[p].close();
}
this.emit("ready")
} catch (e) {
console.error(e);
}
return true;
}
public async run(fn: (page: Page) => void) {
await this.connect();
if (!this.browser) {
return;
}
try {
const page = await this.browser.newPage()
if (!page) {
return;
}
const ret = await fn(page)
await page.close()
return ret
} catch (e) {
return
}
}
}