From 493bfd88f9749ec830216207776d2f309cfccd88 Mon Sep 17 00:00:00 2001 From: Thomas Lynch Date: Fri, 14 Apr 2023 21:47:01 +1000 Subject: [PATCH] Add and improve auto background solve --- src/js/auto.js | 238 +++++++++++++++++++++++++++----------------- src/js/auto.min.js | 2 +- src/js/challenge.js | 8 +- 3 files changed, 149 insertions(+), 99 deletions(-) diff --git a/src/js/auto.js b/src/js/auto.js index e6478d0..d84ef4b 100644 --- a/src/js/auto.js +++ b/src/js/auto.js @@ -1,98 +1,148 @@ -(() => { - const doBotCheck = async () => { - try { - const json = await fetch("/.basedflare/bot-check", { headers: { "accept": "application/json" }}) - .then(res => res.json()); - if (json && json.ch) { - if (json.ca) { - // TODO: captcha popup - } else { - const [ userkey, challenge, _expiry, _signature ] = json.ch.split("#"); - const [ mode, diff, argon_time, argon_kb ] = json.pow.split("#"); - if (mode === "argon2") { - if (!window.argon2) { - await new Promise((res) => { - const script = document.createElement("script"); - script.onload = () => res(); - script.src = "/.basedflare/js/argon2.min.js"; - document.head.appendChild(script); - }) - } - } - console.log(json) - const diffString = "0".repeat(diff); - const cpuThreads = window.navigator.hardwareConcurrency; - const isTor = location.hostname.endsWith(".onion"); - const workerThreads = (isTor || cpuThreads === 2) ? cpuThreads : Math.max(Math.ceil(cpuThreads / 2), cpuThreads - 1); - const workers = []; - let finished = false; - const messageHandler = (e) => { - if (e.data.length === 1) { - return console.log(e.data[0]); - } - if (finished) return; - finished = true; - workers.forEach((w) => w.terminate()); - const [_workerId, answer] = e.data; - fetch("/.basedflare/bot-check", { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - "pow_response": `${json.ch}#${answer}`, - }), - redirect: "manual", - }).then((res) => { - if (res.status >= 400) { - console.error("basedflare post status >= 400", res); - } - }).catch((e) => { - console.error(e) - }); - }; - for (let i = 0; i < workerThreads; i++) { - const powWorker = new Worker("/.basedflare/js/worker.min.js"); - powWorker.onmessage = messageHandler; - workers.push(powWorker); - powWorker.postMessage([ - userkey, - challenge, - diff, - diffString, - { - time: argon_time, - mem: argon_kb, - hashLen: 32, - parallelism: 1, - type: window.argon2 ? window.argon2.ArgonType.Argon2id : null, - mode: mode, - }, - i, - workerThreads, - ]); - } +if (!window._basedflareAuto) { + + class BasedFlareAuto { + + constuctor(cookieMinLife=600, maxFails=3) { + this.finished = false; + this.workers = []; + this.fails = 0; + this.cookieMinLife = cookieMinLife; + this.maxFails = maxFails; + this.timeout = null; + this.scriptSrc = "/.basedflare/js/argon2.min.js"; + this.checkCookie(); + } + + checkCookie() { + const powCookie = document.cookie + .split("; ") + .find((row) => row.startsWith("_basedflare_pow=")); + if (powCookie) { + const powCookieValue = powCookie.split("=")[1]; + const expiry = powCookieValue.split("#")[2]; + const remainingSecs = ((expiry*1000) - Date.now()) / 1000; + console.log('Basedflare cookie check, valid for', remainingSecs, 'seconds'); + if (remainingSecs <= this.cookieMinLife) { + return this.doBotCheck(); + } + this.timeout = setTimeout(this.checkCookie, Math.floor(((remainingSecs-this.cookieMinLife+(Math.random()*300))*1000))); + } + } + + includeScript(scriptSrc) { + return new Promise((res) => { + const script = document.createElement("script"); + script.onload = () => res(); + script.src = scriptSrc; + document.head.appendChild(script); + }); + } + + messageHandler(e, json) { + if (e.data.length === 1) { return; } + if (this.finished) return; + this.finished = true; + this.workers.forEach((w) => w.terminate()); + const [_workerId, answer] = e.data; + fetch("/.basedflare/bot-check", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: new URLSearchParams({ + "pow_response": `${json.ch}#${answer}`, + }), + redirect: "manual", + }).then((res) => { + if (res.status >= 400) { + this.fails++; + console.error("basedflare post status >= 400", res); + } + }).catch((e) => { + console.error(e) + }); + } + + checkRunning() { + const lastCheckTime = localStorage.getItem('_basedflare-auto'); + if (lastCheckTime) { + const lastCheckInt = parseInt(lastCheckTime); + if (Date.now() - lastCheckInt < 120) { + return true; + } //else its too old, we just continue + } + } + + async doProofOfWork(json) { + this.workers = []; + this.finished = true; + const [ userkey, challenge, _expiry, _signature ] = json.ch.split("#"); + const [ mode, diff, argon_time, argon_kb ] = json.pow.split("#"); + if (mode === "argon2") { + if (!window.argon2) { + await this.includeScript(this.scriptSrc); } } - } catch(e) { - console.error(e); - } - }; - const cookieMinLife = 600; - const checkCookie = () => { - const powCookie = document.cookie - .split("; ") - .find((row) => row.startsWith("_basedflare_pow=")); - if (powCookie) { - powCookieValue = powCookie.split("=")[1]; - const expiry = powCookieValue.split("#")[2]; - const remainingSecs = ((expiry*1000) - Date.now()) / 1000; - console.log('Basedflare cookie check, valid for', remainingSecs, 'seconds'); - if (remainingSecs < cookieMinLife) { - return doBotCheck(); + const diffString = "0".repeat(diff); + const cpuThreads = window.navigator.hardwareConcurrency; + const isTor = location.hostname.endsWith(".onion"); + const workerThreads = (isTor || cpuThreads === 2) ? cpuThreads : Math.max(Math.ceil(cpuThreads / 2), cpuThreads - 1); + for (let i = 0; i < workerThreads; i++) { + const powWorker = new Worker("/.basedflare/js/worker.min.js"); + powWorker.onmessage = (e) => this.messageHandler(e, json); + this.workers.push(powWorker); + powWorker.postMessage([ + userkey, + challenge, + diff, + diffString, + { + time: argon_time, + mem: argon_kb, + hashLen: 32, + parallelism: 1, + type: window.argon2 ? window.argon2.ArgonType.Argon2id : null, + mode: mode, + }, + i, + workerThreads, + ]); } - setTimeout(checkCookie, Math.floor(((remainingSecs-cookieMinLife-(Math.random()*300))*1000))); } - }; - checkCookie(); -})(); + + async doBotCheck() { + try { + if (this.checkRunning()) { return; } + localStorage.setItem('_basedflare-auto', Date.now()); + const json = await fetch("/.basedflare/bot-check", { + headers: { + "accept": "application/json" + } + }) + .then(res => res.json()); + if (!json || !json.ch) { + return; + } + console.log('Basedflare challenge successfully fetched', json); + if (json.ca) { + // TODO: doCaptchaPopup(); + console.warn('Basedflare auto captcha not yet supported'); + } else { + this.doProofOfWork(json); + } + } catch(e) { + console.error(e); + this.fails++; + } finally { + localStorage.removeItem('_basedflare-auto'); + if (this.fails < this.maxFails) { + this.timeout = setTimeout(this.checkCookie, 5000*this.fails); + } + } + } + + } + + window._basedflareAuto = new BasedFlareAuto(); + +} diff --git a/src/js/auto.min.js b/src/js/auto.min.js index 8f82c30..22d5714 100644 --- a/src/js/auto.min.js +++ b/src/js/auto.min.js @@ -1 +1 @@ -(()=>{const doBotCheck=async()=>{try{const json=await fetch("/.basedflare/bot-check",{headers:{"accept":"application/json"}}).then(res=>res.json());if(json&&json.ch){if(json.ca){}else{const[userkey,challenge,_expiry,_signature]=json.ch.split("#");const[mode,diff,argon_time,argon_kb]=json.pow.split("#");if(mode==="argon2"){if(!window.argon2){await new Promise((res)=>{const script=document.createElement("script");script.onload=()=>res();script.src="/.basedflare/js/argon2.min.js";document.head.appendChild(script)})}}console.log(json);const diffString="0".repeat(diff);const cpuThreads=window.navigator.hardwareConcurrency;const isTor=location.hostname.endsWith(".onion");const workerThreads=(isTor||cpuThreads===2)?cpuThreads:Math.max(Math.ceil(cpuThreads/2),cpuThreads-1);const workers=[];let finished=false;const messageHandler=(e)=>{if(e.data.length===1){return console.log(e.data[0])}if(finished){return}finished=true;workers.forEach((w)=>w.terminate());const[_workerId,answer]=e.data;fetch("/.basedflare/bot-check",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({"pow_response":`${json.ch }#${ answer }`}),redirect:"manual"}).then((res)=>{if(res.status>=400){console.error("basedflare post status >= 400",res)}}).catch((e)=>{console.error(e)})};for(let i=0;i{const powCookie=document.cookie.split("; ").find((row)=>row.startsWith("_basedflare_pow="));if(powCookie){powCookieValue=powCookie.split("=")[1];const expiry=powCookieValue.split("#")[2];const remainingSecs=((expiry*1000)-Date.now())/1000;console.log('Basedflare cookie check, valid for',remainingSecs,'seconds');if(remainingSecsrow.startsWith("_basedflare_pow="));if(powCookie){const powCookieValue=powCookie.split("=")[1];const expiry=powCookieValue.split("#")[2];const remainingSecs=((expiry*1000)-Date.now())/1000;console.log('Basedflare cookie check, valid for',remainingSecs,'seconds');if(remainingSecs<=this.cookieMinLife){return this.doBotCheck()}this.timeout=setTimeout(this.checkCookie,Math.floor(((remainingSecs-this.cookieMinLife+(Math.random()*300))*1000)))}}includeScript(scriptSrc){return new Promise((res)=>{const script=document.createElement("script");script.onload=()=>res();script.src=scriptSrc;document.head.appendChild(script)})}messageHandler(e,json){if(e.data.length===1){return}if(this.finished){return}this.finished=true;this.workers.forEach((w)=>w.terminate());const[_workerId,answer]=e.data;fetch("/.basedflare/bot-check",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({"pow_response":`${json.ch }#${ answer }`}),redirect:"manual"}).then((res)=>{if(res.status>=400){this.fails+=1;console.error("basedflare post status >= 400",res)}}).catch((e)=>{console.error(e)})}checkRunning(){const lastCheckTime=localStorage.getItem('_basedflare-auto');if(lastCheckTime){const lastCheckInt=parseInt(lastCheckTime);if(Date.now()-lastCheckInt<120){return true}}}async doProofOfWork(json){this.workers=[];this.finished=true;const[userkey,challenge,_expiry,_signature]=json.ch.split("#");const[mode,diff,argon_time,argon_kb]=json.pow.split("#");if(mode==="argon2"){if(!window.argon2){await this.includeScript(this.scriptSrc)}}const diffString="0".repeat(diff);const cpuThreads=window.navigator.hardwareConcurrency;const isTor=location.hostname.endsWith(".onion");const workerThreads=(isTor||cpuThreads===2)?cpuThreads:Math.max(Math.ceil(cpuThreads/2),cpuThreads-1);for(let i=0;ithis.messageHandler(e,json);this.workers.push(powWorker);powWorker.postMessage([userkey,challenge,diff,diffString,{time:argon_time,mem:argon_kb,hashLen:32,parallelism:1,type:window.argon2?window.argon2.ArgonType.Argon2id:null,mode:mode},i,workerThreads])}}async doBotCheck(){try{if(this.checkRunning()){return}localStorage.setItem('_basedflare-auto',Date.now());const json=await fetch("/.basedflare/bot-check",{headers:{"accept":"application/json"}}).then(res=>res.json());if(!json||!json.ch){return}console.log('Basedflare challenge successfully fetched',json);if(json.ca){console.warn('Basedflare auto captcha not yet supported')}else{this.doProofOfWork(json)}}catch(e){console.error(e);this.fails+=1}finally{localStorage.removeItem('_basedflare-auto');if(this.fails= 500) { return insertError("Server encountered an error."); } - window.localStorage.setItem("basedflare-redirect", Math.random()); + window.localStorage.setItem("_basedflare-redirect", Math.random()); finishRedirect(); }).catch(() => { insertError("Failed to send request to server."); @@ -114,7 +114,7 @@ const powFinished = new Promise((resolve) => { workers.forEach((w) => w.terminate()); }; const submitPow = (answer) => { - window.localStorage.setItem("basedflare-pow-response", answer); + window.localStorage.setItem("_basedflare-pow-response", answer); stopPow(); const dummyTime = 3500 - (Date.now() - start); window.setTimeout(() => { @@ -135,14 +135,14 @@ const powFinished = new Promise((resolve) => { } = document.querySelector("[data-pow]").dataset; window.addEventListener("storage", (event) => { - if (event.key === "basedflare-pow-response" && !finished) { + if (event.key === "_basedflare-pow-response" && !finished) { console.log("Got answer", event.newValue, "from storage event"); stopPow(); resolve({ answer: event.newValue, localStorage: true }); - } else if (event.key === "basedflare-redirect") { + } else if (event.key === "_basedflare-redirect") { console.log("Redirecting, solved in another tab"); finishRedirect(); }