mirror of
https://gitgud.io/fatchan/haproxy-protection.git
synced 2025-05-09 02:05:37 +00:00
Ability to choose between sha256 or argon2 with env var close #21
This commit is contained in:
@ -19,6 +19,7 @@ NOTE: Use either HCAPTCHA_ or RECAPTHCA_, not both.
|
||||
- ARGON_TIME - argon2 iterations
|
||||
- ARGON_KB - argon2 memory usage in KB
|
||||
- POW_DIFFICULTY - pow difficulty
|
||||
- POW_TYPE - type of ahsh algorithm for pow "argon2" or "sha256"
|
||||
|
||||
#### Run in docker (for testing/development)
|
||||
|
||||
|
@ -32,6 +32,7 @@ services:
|
||||
- ARGON_TIME=2
|
||||
- ARGON_KB=512
|
||||
- POW_DIFFICULTY=24
|
||||
- POW_TYPE=argon2
|
||||
- TOR_CONTROL_PORT_PASSWORD=changeme
|
||||
|
||||
nginx:
|
||||
|
@ -81,7 +81,7 @@ const powFinished = new Promise(resolve => {
|
||||
|
||||
window.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
const { time, kb, pow, diff } = document.querySelector('[data-pow]').dataset;
|
||||
const { time, kb, pow, diff, mode } = document.querySelector('[data-pow]').dataset;
|
||||
window.addEventListener('storage', event => {
|
||||
if (event.key === 'basedflare-pow-response' && !finished) {
|
||||
console.log('Got answer', event.newValue, 'from storage event');
|
||||
@ -94,14 +94,15 @@ const powFinished = new Promise(resolve => {
|
||||
});
|
||||
|
||||
if (!wasmSupported) {
|
||||
return insertError('browser does not support WebAssembly.');
|
||||
return insertError('Browser does not support WebAssembly.');
|
||||
}
|
||||
const argonOpts = {
|
||||
const powOpts = {
|
||||
time: time,
|
||||
mem: kb,
|
||||
hashLen: 32,
|
||||
parallelism: 1,
|
||||
type: argon2.ArgonType.Argon2id,
|
||||
type: argon2 ? argon2.ArgonType.Argon2id : null,
|
||||
mode: mode,
|
||||
};
|
||||
console.log('Got pow', pow, 'with difficulty', diff);
|
||||
const eHashes = Math.pow(16, Math.floor(diff/8)) * ((diff%8)*2);
|
||||
@ -128,34 +129,16 @@ const powFinished = new Promise(resolve => {
|
||||
submitPow(`${pow}#${answer}`);
|
||||
}
|
||||
for (let i = 0; i < workerThreads; i++) {
|
||||
const argonWorker = new Worker('/.basedflare/js/worker.js');
|
||||
argonWorker.onmessage = messageHandler;
|
||||
workers.push(argonWorker);
|
||||
const powWorker = new Worker('/.basedflare/js/worker.js');
|
||||
powWorker.onmessage = messageHandler;
|
||||
workers.push(powWorker);
|
||||
}
|
||||
for (let i = 0; i < workerThreads; i++) {
|
||||
await new Promise(res => setTimeout(res, 10));
|
||||
workers[i].postMessage([userkey, challenge, diff, diffString, argonOpts, i, workerThreads]);
|
||||
workers[i].postMessage([userkey, challenge, diff, diffString, powOpts, i, workerThreads]);
|
||||
}
|
||||
} else {
|
||||
//TODO: remove this section, it _will_ cause problems
|
||||
console.warn('No webworker support, running in main/UI thread!');
|
||||
let i = 0;
|
||||
const start = Date.now();
|
||||
while(true) {
|
||||
const hash = await argon2.hash({
|
||||
pass: challenge + i.toString(),
|
||||
salt: userkey,
|
||||
...argonOpts,
|
||||
});
|
||||
if (hash.hashHex.startsWith(diffString)
|
||||
&& ((parseInt(hash.hashHex[diffString.length],16) &
|
||||
0xff >> (((diffString.length+1)*8)-diff)) === 0)) {
|
||||
console.log('Main thread found solution:', hash.hashHex, 'in', (Date.now()-start)+'ms');
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
submitPow(`${pow}#${i}`);
|
||||
return insertError('Browser does not support Web Workers.');
|
||||
}
|
||||
});
|
||||
}).then((powResponse) => {
|
||||
|
@ -1,7 +1,15 @@
|
||||
importScripts('/.basedflare/js/argon2.js');
|
||||
async function nativeHash(data, method) {
|
||||
const buffer = new TextEncoder('utf-8').encode(data);
|
||||
const hashBuffer = await crypto.subtle.digest(method, buffer)
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
|
||||
onmessage = async function(e) {
|
||||
const [userkey, challenge, diff, diffString, argonOpts, id, threads] = e.data;
|
||||
const [userkey, challenge, diff, diffString, powOpts, id, threads] = e.data;
|
||||
if (powOpts.mode === "argon2") {
|
||||
importScripts('/.basedflare/js/argon2.js');
|
||||
}
|
||||
console.log('Worker thread', id, 'started');
|
||||
let i = id;
|
||||
if (id === 0) {
|
||||
@ -10,15 +18,21 @@ onmessage = async function(e) {
|
||||
}, 500);
|
||||
}
|
||||
while(true) {
|
||||
const hash = await argon2.hash({
|
||||
pass: challenge + i.toString(),
|
||||
salt: userkey,
|
||||
...argonOpts,
|
||||
});
|
||||
let hash;
|
||||
if (powOpts.mode === "argon2") {
|
||||
const argonHash = await argon2.hash({
|
||||
pass: challenge + i.toString(),
|
||||
salt: userkey,
|
||||
...powOpts,
|
||||
});
|
||||
hash = argonHash.hashHex;
|
||||
} else {
|
||||
hash = await nativeHash(userkey + challenge + i.toString(), 'sha-256');
|
||||
}
|
||||
// This throttle seems to really help some browsers not stop the workers abruptly
|
||||
i % 10 === 0 && await new Promise(res => setTimeout(res, 10));
|
||||
if (hash.hashHex.startsWith(diffString)
|
||||
&& ((parseInt(hash.hashHex[diffString.length],16) &
|
||||
if (hash.toString().startsWith(diffString)
|
||||
&& ((parseInt(hash[diffString.length],16) &
|
||||
0xff >> (((diffString.length+1)*8)-diff)) === 0)) {
|
||||
console.log('Worker', id, 'found solution');
|
||||
postMessage([id, i]);
|
||||
|
@ -43,6 +43,9 @@ end
|
||||
|
||||
-- return true if hash passes difficulty
|
||||
function _M.checkdiff(hash, diff)
|
||||
if #hash == 0 then
|
||||
return false
|
||||
end
|
||||
local i = 1
|
||||
for j = 0, (diff-8), 8 do
|
||||
if hash:sub(i, i) ~= "0" then
|
||||
|
@ -9,13 +9,12 @@ local url = require("url")
|
||||
local utils = require("utils")
|
||||
local cookie = require("cookie")
|
||||
local json = require("json")
|
||||
local sha = require("sha")
|
||||
local randbytes = require("randbytes")
|
||||
local templates = require("templates")
|
||||
|
||||
-- POW
|
||||
local pow_type = os.getenv("POW_TYPE") or "argon2"
|
||||
local pow_difficulty = tonumber(os.getenv("POW_DIFFICULTY") or 18)
|
||||
|
||||
-- argon2
|
||||
local argon2 = require("argon2")
|
||||
local argon_kb = tonumber(os.getenv("ARGON_KB") or 6000)
|
||||
@ -25,9 +24,8 @@ argon2.m_cost(argon_kb)
|
||||
argon2.parallelism(1)
|
||||
argon2.hash_len(32)
|
||||
argon2.variant(argon2.variants.argon2_id)
|
||||
|
||||
-- sha2
|
||||
-- TODO
|
||||
local sha = require("sha")
|
||||
|
||||
-- environment variables
|
||||
local captcha_secret = os.getenv("HCAPTCHA_SECRET") or os.getenv("RECAPTCHA_SECRET")
|
||||
@ -144,14 +142,20 @@ function _M.view(applet)
|
||||
captcha_sitekey, captcha_script_src)
|
||||
else
|
||||
pow_body = templates.pow_section
|
||||
noscript_extra_body = string.format(templates.noscript_extra, user_key,
|
||||
local noscript_extra
|
||||
if pow_type == "argon2" then
|
||||
noscript_extra = templates.noscript_extra_argon2
|
||||
else
|
||||
noscript_extra = templates.noscript_extra_sha256
|
||||
end
|
||||
noscript_extra_body = string.format(noscript_extra, user_key,
|
||||
challenge_hash, expiry, signature, math.ceil(pow_difficulty/8),
|
||||
argon_time, argon_kb)
|
||||
end
|
||||
|
||||
-- sub in the body sections
|
||||
response_body = string.format(templates.body, combined_challenge,
|
||||
pow_difficulty, argon_time, argon_kb,
|
||||
pow_difficulty, argon_time, argon_kb, pow_type,
|
||||
site_name_body, pow_body, captcha_body, noscript_extra_body, ray_id)
|
||||
response_status_code = 403
|
||||
|
||||
@ -200,11 +204,14 @@ function _M.view(applet)
|
||||
if given_signature == generated_signature then
|
||||
|
||||
-- do the work with their given answer
|
||||
local full_hash = argon2.hash_encoded(given_challenge_hash .. given_answer, given_user_key)
|
||||
|
||||
-- check the output is correct
|
||||
local hash_output = utils.split(full_hash, '$')[6]:sub(0, 43) -- https://github.com/thibaultcha/lua-argon2/issues/37
|
||||
local hex_hash_output = sha.bin_to_hex(sha.base64_to_bin(hash_output));
|
||||
local hex_hash_output = ""
|
||||
if pow_type == "argon2" then
|
||||
local encoded_argon_hash = argon2.hash_encoded(given_challenge_hash .. given_answer, given_user_key)
|
||||
local trimmed_argon_hash = utils.split(encoded_argon_hash, '$')[6]:sub(0, 43) -- https://github.com/thibaultcha/lua-argon2/issues/37
|
||||
hex_hash_output = sha.bin_to_hex(sha.base64_to_bin(trimmed_argon_hash));
|
||||
else
|
||||
hex_hash_output = sha.sha256(given_user_key .. given_challenge_hash .. given_answer)
|
||||
end
|
||||
|
||||
if utils.checkdiff(hex_hash_output, pow_difficulty) then
|
||||
|
||||
|
@ -32,7 +32,7 @@ _M.body = [[
|
||||
<script src="/.basedflare/js/argon2.js"></script>
|
||||
<script src="/.basedflare/js/challenge.js"></script>
|
||||
</head>
|
||||
<body data-pow="%s" data-diff="%s" data-time="%s" data-kb="%s">
|
||||
<body data-pow="%s" data-diff="%s" data-time="%s" data-kb="%s" data-mode="%s">
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
@ -50,7 +50,7 @@ _M.body = [[
|
||||
</html>
|
||||
]]
|
||||
|
||||
_M.noscript_extra = [[
|
||||
_M.noscript_extra_argon2 = [[
|
||||
<details>
|
||||
<summary>No JavaScript?</summary>
|
||||
<ol>
|
||||
@ -68,6 +68,24 @@ _M.noscript_extra = [[
|
||||
</details>
|
||||
]]
|
||||
|
||||
_M.noscript_extra_sha256 = [[
|
||||
<details>
|
||||
<summary>No JavaScript?</summary>
|
||||
<ol>
|
||||
<li>
|
||||
<p>Run this in a linux terminal (requires <code>perl</code>):</p>
|
||||
<code style="word-break: break-all;">
|
||||
echo "dXNlIHN0cmljdDt1c2UgRGlnZXN0OjpTSEEgcXcoc2hhMjU2X2hleCk7cHJpbnQgIldvcmtpbmcuLi4iO215JGM9IiRBUkdWWzBdIi4iJEFSR1ZbMV0iO215JGlkPSRBUkdWWzRdKzA7bXkkZD0iMCJ4JGlkO215JGk9MDt3aGlsZSgxKXtsYXN0IGlmICRkIGVxIHN1YnN0ciBzaGEyNTZfaGV4KCRjLCRpKSwwLCRpZDskaSsrfXByaW50IlxuT3V0cHV0OlxuJEFSR1ZbMF0jJEFSR1ZbMV0jJEFSR1ZbMl0jJEFSR1ZbM10jJGlcbiI=" | base64 -d | perl -w - %s %s %s %s %s %s %s
|
||||
</code>
|
||||
<li>Paste the script output into the box and submit:
|
||||
<form method="post">
|
||||
<textarea name="pow_response" placeholder="script output" required></textarea>
|
||||
<div><input type="submit" value="submit" /></div>
|
||||
</form>
|
||||
</ol>
|
||||
</details>
|
||||
]]
|
||||
|
||||
-- title with favicon and hostname
|
||||
_M.site_name_section = [[
|
||||
<h3 class="pt">
|
||||
|
Reference in New Issue
Block a user