Temporary usertokens via proof-of-work challenge (khanon/oai-reverse-proxy!68)
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
importScripts(
|
||||
"https://cdn.jsdelivr.net/npm/hash-wasm@4.11.0/dist/argon2.umd.min.js"
|
||||
);
|
||||
|
||||
let active = false;
|
||||
let nonce = 0;
|
||||
let signature = "";
|
||||
let lastNotify = 0;
|
||||
let hashesSinceLastNotify = 0;
|
||||
let params = {
|
||||
salt: null,
|
||||
hashLength: 0,
|
||||
iterations: 0,
|
||||
memorySize: 0,
|
||||
parallelism: 0,
|
||||
targetValue: BigInt(0),
|
||||
safariFix: false,
|
||||
};
|
||||
|
||||
self.onmessage = async (event) => {
|
||||
const { data } = event;
|
||||
switch (data.type) {
|
||||
case "stop":
|
||||
active = false;
|
||||
self.postMessage({ type: "paused", hashes: hashesSinceLastNotify });
|
||||
return;
|
||||
case "start":
|
||||
active = true;
|
||||
signature = data.signature;
|
||||
nonce = data.nonce;
|
||||
|
||||
const c = data.challenge;
|
||||
// decode salt to Uint8Array
|
||||
const salt = new Uint8Array(c.s.length / 2);
|
||||
for (let i = 0; i < c.s.length; i += 2) {
|
||||
salt[i / 2] = parseInt(c.s.slice(i, i + 2), 16);
|
||||
}
|
||||
|
||||
params = {
|
||||
salt: salt,
|
||||
hashLength: c.hl,
|
||||
iterations: c.t,
|
||||
memorySize: c.m,
|
||||
parallelism: c.p,
|
||||
targetValue: BigInt(c.d.slice(0, -1)),
|
||||
safariFix: data.isMobileWebkit,
|
||||
};
|
||||
|
||||
console.log("Started", params);
|
||||
self.postMessage({ type: "started" });
|
||||
setTimeout(solve, 0);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const doHash = async (password) => {
|
||||
const { salt, hashLength, iterations, memorySize, parallelism } = params;
|
||||
return await self.hashwasm.argon2id({
|
||||
password,
|
||||
salt,
|
||||
hashLength,
|
||||
iterations,
|
||||
memorySize,
|
||||
parallelism,
|
||||
});
|
||||
};
|
||||
|
||||
const checkHash = (hash) => {
|
||||
const { targetValue } = params;
|
||||
const hashValue = BigInt(`0x${hash}`);
|
||||
return hashValue <= targetValue;
|
||||
};
|
||||
|
||||
const solve = async () => {
|
||||
if (!active) {
|
||||
console.log("Stopped solver", nonce);
|
||||
return;
|
||||
}
|
||||
|
||||
// Safari WASM doesn't like multiple calls in one worker
|
||||
const batchSize = 1;
|
||||
const batch = [];
|
||||
for (let i = 0; i < batchSize; i++) {
|
||||
batch.push(nonce++);
|
||||
}
|
||||
|
||||
try {
|
||||
const results = await Promise.all(
|
||||
batch.map(async (nonce) => {
|
||||
const hash = await doHash(String(nonce));
|
||||
return { hash, nonce };
|
||||
})
|
||||
);
|
||||
hashesSinceLastNotify += batchSize;
|
||||
|
||||
const solution = results.find(({ hash }) => checkHash(hash));
|
||||
if (solution) {
|
||||
console.log("Solution found", solution, params.salt);
|
||||
self.postMessage({ type: "solved", nonce: solution.nonce });
|
||||
active = false;
|
||||
} else {
|
||||
if (Date.now() - lastNotify > 1000) {
|
||||
console.log("Last nonce", nonce, "Hashes", hashesSinceLastNotify);
|
||||
self.postMessage({ type: "progress", hashes: hashesSinceLastNotify });
|
||||
lastNotify = Date.now();
|
||||
hashesSinceLastNotify = 0;
|
||||
}
|
||||
setTimeout(solve, 10);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error", error);
|
||||
const stack = error.stack;
|
||||
const debug = {
|
||||
stack,
|
||||
lastNonce: nonce,
|
||||
targetValue: params.targetValue,
|
||||
};
|
||||
self.postMessage({ type: "error", error: error.message, debug });
|
||||
active = false;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user