Compare commits

...

7 Commits

  1. 19
      src/js/auto.js
  2. 2
      src/js/auto.min.js
  3. 12
      src/js/challenge.js
  4. 2
      src/js/challenge.min.js
  5. 18
      src/lua/scripts/bot-check.lua

@ -40,6 +40,15 @@ if (!window._basedflareAuto) {
});
};
clearCookiesForDomains = (domain) => {
const parts = domain.split('.');
for (let i = 0; i < parts.length - 1; i++) {
const subdomain = parts.slice(i).join('.');
document.cookie = `_basedflare_pow=; Max-Age=-9999999; Path=/; Domain=.${subdomain}`;
document.cookie = `_basedflare_captcha=; Max-Age=-9999999; Path=/; Domain=.${subdomain}`;
}
};
messageHandler = (e, json) => {
console.log('messageHandler')
if (e.data.length === 1) { return; }
@ -57,13 +66,17 @@ if (!window._basedflareAuto) {
}),
redirect: "manual",
}).then((res) => {
if (res.status >= 400) {
this.fails++;
console.error("basedflare post status >= 400", res);
if (res.status >= 400 && res.status < 500) {
clearCookiesForDomains(location.hostname);
console.error("Server rejected your submission.");
} else if (res.status >= 500) {
console.error("Server encountered an error.");
}
this.fails++;
}).catch((e) => {
console.error(e);
}).finally(() => {
clearCookiesForDomains(location.hostname);
localStorage.removeItem('_basedflare-auto');
});
};

@ -1 +1 @@
if(!window._basedflareAuto){class BasedFlareAuto{constructor(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=()=>{console.log('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 valid for',remainingSecs,'seconds');if(remainingSecs<=this.cookieMinLife){return this.doBotCheck()}this.timeout=setTimeout(this.checkCookie,Math.max(5000,Math.floor(((remainingSecs-this.cookieMinLife+(Math.random()*300))*1000))))}};includeScript=(scriptSrc)=>{console.log('includeScript');return new Promise((res)=>{const script=document.createElement("script");script.onload=()=>res();script.src=scriptSrc;document.head.appendChild(script)})};messageHandler=(e,json)=>{console.log('messageHandler');if(e.data.length===1){return}if(this.finished){return}this.workers.forEach((w)=>w.terminate());this.finished=true;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)}).finally(()=>{localStorage.removeItem('_basedflare-auto')})};checkRunning=()=>{console.log('checkRunning');const lastCheckTime=localStorage.getItem('_basedflare-auto');if(lastCheckTime){const lastCheckInt=parseInt(lastCheckTime);if(Date.now()-lastCheckInt<120){console.log('Already running recently');return true}}};doProofOfWork=async(json)=>{console.log('doProofOfWork');this.workers=[];this.finished=false;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;i<workerThreads;i+=1){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])}};doBotCheck=async()=>{console.log('doBotCheck');if(this.checkRunning()){return}localStorage.setItem('_basedflare-auto',Date.now());try{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{await this.doProofOfWork(json)}}catch(e){console.error(e);this.fails+=1}finally{if(this.fails<this.maxFails){this.timeout=setTimeout(this.checkCookie,30000)}}}}window._basedflareAuto=new BasedFlareAuto()}
if(!window._basedflareAuto){class BasedFlareAuto{constructor(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=()=>{console.log('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 valid for',remainingSecs,'seconds');if(remainingSecs<=this.cookieMinLife){return this.doBotCheck()}this.timeout=setTimeout(this.checkCookie,Math.max(5000,Math.floor(((remainingSecs-this.cookieMinLife+(Math.random()*300))*1000))))}};includeScript=(scriptSrc)=>{console.log('includeScript');return new Promise((res)=>{const script=document.createElement("script");script.onload=()=>res();script.src=scriptSrc;document.head.appendChild(script)})};clearCookiesForDomains=(domain)=>{const parts=domain.split('.');for(let i=0;i<parts.length-1;i+=1){const subdomain=parts.slice(i).join('.');document.cookie=`_basedflare_pow=; Max-Age=-9999999; Path=/; Domain=.${ subdomain }`;document.cookie=`_basedflare_captcha=; Max-Age=-9999999; Path=/; Domain=.${ subdomain }`}};messageHandler=(e,json)=>{console.log('messageHandler');if(e.data.length===1){return}if(this.finished){return}this.workers.forEach((w)=>w.terminate());this.finished=true;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&&res.status<500){clearCookiesForDomains(location.hostname);console.error("Server rejected your submission.")}else if(res.status>=500){console.error("Server encountered an error.")}this.fails+=1}).catch((e)=>{console.error(e)}).finally(()=>{clearCookiesForDomains(location.hostname);localStorage.removeItem('_basedflare-auto')})};checkRunning=()=>{console.log('checkRunning');const lastCheckTime=localStorage.getItem('_basedflare-auto');if(lastCheckTime){const lastCheckInt=parseInt(lastCheckTime);if(Date.now()-lastCheckInt<120){console.log('Already running recently');return true}}};doProofOfWork=async(json)=>{console.log('doProofOfWork');this.workers=[];this.finished=false;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;i<workerThreads;i+=1){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])}};doBotCheck=async()=>{console.log('doBotCheck');if(this.checkRunning()){return}localStorage.setItem('_basedflare-auto',Date.now());try{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{await this.doProofOfWork(json)}}catch(e){console.error(e);this.fails+=1}finally{if(this.fails<this.maxFails){this.timeout=setTimeout(this.checkCookie,30000)}}}}window._basedflareAuto=new BasedFlareAuto()}

@ -76,6 +76,16 @@ const wasmSupported = (() => {
// }
// };
function clearCookiesForDomains(domain) {
const parts = domain.split('.');
for (let i = 0; i < parts.length - 1; i++) {
const subdomain = parts.slice(i).join('.');
document.cookie = `_basedflare_pow=; Max-Age=-9999999; Path=/; Domain=.${subdomain}`;
document.cookie = `_basedflare_captcha=; Max-Age=-9999999; Path=/; Domain=.${subdomain}`;
}
location.reload();
}
function postResponse(powResponse, captchaResponse) {
const body = {
"pow_response": powResponse,
@ -94,6 +104,7 @@ function postResponse(powResponse, captchaResponse) {
}).then((res) => {
const s = res.status;
if (s >= 400 && s < 500) {
clearCookiesForDomains(location.hostname);
return insertError(__("Server rejected your submission."));
} else if (s >= 500) {
return insertError(__("Server encountered an error."));
@ -101,6 +112,7 @@ function postResponse(powResponse, captchaResponse) {
window.localStorage.setItem("_basedflare-redirect", Math.random());
finishRedirect();
}).catch(() => {
clearCookiesForDomains(location.hostname);
insertError(__("Failed to send request to server."));
});
}

File diff suppressed because one or more lines are too long

@ -73,6 +73,11 @@ else
captcha_backend_name = "recaptcha"
end
function _M.secondsToDate(seconds)
local formattedDate = os.date("!%a, %d-%b-%y %H:%M:%S GMT", seconds)
return formattedDate
end
-- kill a tor circuit
function _M.kill_tor_circuit(txn)
local ip = txn.sf:src()
@ -245,6 +250,7 @@ function _M.view(applet)
-- if they fail, set a var for use in ACLs later
local valid_submission = false
local number_expiry = nil
-- parsed POST body
local parsed_body = url.parseQuery(applet.receive(applet))
@ -271,7 +277,7 @@ function _M.view(applet)
local given_answer = split_response[5]
-- expiry check
local number_expiry = tonumber(given_expiry, 10)
number_expiry = tonumber(given_expiry, 10)
if number_expiry ~= nil and number_expiry > core.now()['sec'] then
-- regenerate the challenge and compare it
@ -299,12 +305,14 @@ function _M.view(applet)
-- the answer was good, give them a cookie
local signature = sha.hmac(sha.sha3_256, hmac_cookie_secret, given_user_key .. given_challenge_hash .. given_expiry .. given_answer)
local combined_cookie = given_user_key .. "#" .. given_challenge_hash .. "#" .. given_expiry .. "#" .. given_answer .. "#" .. signature
local expiry_date_p = _M.secondsToDate(number_expiry)
applet:add_header(
"set-cookie",
string.format(
--"_basedflare_pow=%s; Expires=Thu, 31-Dec-37 23:55:55 GMT; Path=/; Domain=.%s; SameSite=Strict; HttpOnly;%s",
"_basedflare_pow=%s; Expires=Thu, 31-Dec-37 23:55:55 GMT; Path=/; Domain=%s; SameSite=Strict; %s",
--"_basedflare_pow=%s; Expires=%s; Path=/; Domain=.%s; SameSite=Strict; HttpOnly;%s",
"_basedflare_pow=%s; Expires=%s; Path=/; Domain=%s; SameSite=Strict; %s",
combined_cookie,
expiry_date_p,
applet.headers['host'][0],
secure_cookie_flag
)
@ -363,11 +371,13 @@ function _M.view(applet)
local user_hash = utils.generate_challenge(applet, captcha_cookie_secret, user_key, ddos_config, true)
local signature = sha.hmac(sha.sha3_256, hmac_cookie_secret, user_key .. user_hash .. matched_expiry)
local combined_cookie = user_key .. "#" .. user_hash .. "#" .. matched_expiry .. "#" .. signature
local expiry_date_c = _M.secondsToDate(number_expiry)
applet:add_header(
"set-cookie",
string.format(
"_basedflare_captcha=%s; Expires=Thu, 31-Dec-37 23:55:55 GMT; Path=/; Domain=%s; SameSite=Strict; HttpOnly;%s",
"_basedflare_captcha=%s; Expires=%s; Path=/; Domain=%s; SameSite=Strict; HttpOnly;%s",
combined_cookie,
expiry_date_c,
applet.headers['host'][0],
secure_cookie_flag
)

Loading…
Cancel
Save