mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-28 22:42:26 -05:00
[chore] remove nollamas middleware for now (after discussions with a security advisor) (#4433)
i'll keep this on a separate branch for now while i experiment with other possible alternatives, but for now both our hacky implementation especially, and more popular ones (like anubis) aren't looking too great on the deterrent front: https://github.com/eternal-flame-AD/pow-buster Co-authored-by: tobi <tobi.smethurst@protonmail.com> Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4433 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
247733aef4
commit
6801ce299a
28 changed files with 207 additions and 1395 deletions
|
|
@ -1,4 +1,3 @@
|
|||
node_modules
|
||||
prism.js
|
||||
prism.css
|
||||
nollamasworker/sha256.js
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.nollamas {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.nollamas-status {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
|
@ -73,24 +73,6 @@ skulk({
|
|||
["babelify", { global: true }]
|
||||
],
|
||||
},
|
||||
nollamas: {
|
||||
entryFile: "nollamas",
|
||||
outputFile: "nollamas.js",
|
||||
preset: ["js"],
|
||||
prodCfg: prodCfg,
|
||||
transform: [
|
||||
["babelify", { global: true }]
|
||||
],
|
||||
},
|
||||
nollamasworker: {
|
||||
entryFile: "nollamasworker",
|
||||
outputFile: "nollamasworker.js",
|
||||
preset: ["js"],
|
||||
prodCfg: prodCfg,
|
||||
transform: [
|
||||
["babelify", { global: true }]
|
||||
],
|
||||
},
|
||||
settings: {
|
||||
entryFile: "settings",
|
||||
outputFile: "settings.js",
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const explanation = "Your browser is currently solving a proof-of-work challenge designed to deter \"ai\" scrapers. This should take no more than a few seconds...";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// Get the nollamas section container.
|
||||
const nollamas = document.querySelector(".nollamas");
|
||||
|
||||
// Add some "loading" text to show that
|
||||
// a proof-of-work captcha is being done.
|
||||
const p = this.createElement("p");
|
||||
p.className = "nollamas-explanation";
|
||||
p.appendChild(document.createTextNode(explanation));
|
||||
nollamas.appendChild(p);
|
||||
|
||||
// Add a loading spinner, but only
|
||||
// animate it if motion is allowed.
|
||||
const spinner = document.createElement("i");
|
||||
spinner.className = "fa fa-spinner fa-2x fa-fw nollamas-status";
|
||||
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||||
spinner.className += " fa-pulse";
|
||||
}
|
||||
spinner.setAttribute("title","Solving...");
|
||||
spinner.setAttribute("aria-label", "Solving");
|
||||
nollamas.appendChild(spinner);
|
||||
|
||||
// Read the challenge and difficulty from
|
||||
// data attributes on the nollamas section.
|
||||
const seed = nollamas.dataset.nollamasSeed;
|
||||
const challenge = nollamas.dataset.nollamasChallenge;
|
||||
const threads = navigator.hardwareConcurrency;
|
||||
if (typeof(threads) != "number" || threads < 1) { threads = 1; }
|
||||
|
||||
console.log("seed:", seed); // eslint-disable-line no-console
|
||||
console.log("challenge:", challenge); // eslint-disable-line no-console
|
||||
console.log("threads:", threads); // eslint-disable-line no-console
|
||||
|
||||
// Create an array to track
|
||||
// all workers such that we
|
||||
// can terminate them all.
|
||||
const workers = [];
|
||||
const terminateAll = () => { workers.forEach((worker) => worker.terminate() ); };
|
||||
|
||||
// Get time before task completion.
|
||||
const startTime = performance.now();
|
||||
|
||||
// Prepare and start each worker,
|
||||
// adding them to the workers array.
|
||||
for (let i = 0; i < threads; i++) {
|
||||
const worker = new Worker("/assets/dist/nollamasworker.js");
|
||||
workers.push(worker);
|
||||
|
||||
// On any error terminate.
|
||||
worker.onerror = (ev) => {
|
||||
console.error("worker error:", ev); // eslint-disable-line no-console
|
||||
terminateAll();
|
||||
};
|
||||
|
||||
// Post worker message, where each
|
||||
// worker will compute nonces in range:
|
||||
// $threadNumber + $totalThreads * n
|
||||
worker.postMessage({
|
||||
challenge: challenge,
|
||||
threads: threads,
|
||||
thread: i,
|
||||
seed: seed,
|
||||
});
|
||||
|
||||
// Set main on-success function.
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data.done) {
|
||||
// Stop workers.
|
||||
terminateAll();
|
||||
|
||||
// Log which thread found the solution.
|
||||
console.log("solution from:", e.data.thread); // eslint-disable-line no-console
|
||||
|
||||
// Get total computation duration.
|
||||
const endTime = performance.now();
|
||||
const duration = endTime - startTime;
|
||||
|
||||
// Remove spinner and replace it with a tick
|
||||
// and info about how long it took to solve.
|
||||
nollamas.removeChild(spinner);
|
||||
const solutionWrapper = document.createElement("div");
|
||||
solutionWrapper.className = "nollamas-status";
|
||||
|
||||
const tick = document.createElement("i");
|
||||
tick.className = "fa fa-check fa-2x fa-fw";
|
||||
tick.setAttribute("title","Solved!");
|
||||
tick.setAttribute("aria-label", "Solved!");
|
||||
solutionWrapper.appendChild(tick);
|
||||
|
||||
const took = document.createElement("span");
|
||||
const solvedText = `Solved after ${e.data.nonce} iterations by worker ${e.data.thread} of ${threads}, in ${duration.toString()}ms!`;
|
||||
took.appendChild(document.createTextNode(solvedText));
|
||||
solutionWrapper.appendChild(took);
|
||||
|
||||
nollamas.appendChild(solutionWrapper);
|
||||
|
||||
// Wait for 500ms before redirecting, to give
|
||||
// visitors a shot at reading the message, but
|
||||
// not so long that they have to wait unduly.
|
||||
setTimeout(() => {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.set("nollamas_solution", e.data.nonce);
|
||||
window.location.replace(url.toString());
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import sha256 from "./sha256";
|
||||
|
||||
let compute = async function(seedStr, challengeStr, start, iter) {
|
||||
const textEncoder = new TextEncoder();
|
||||
|
||||
let nonce = start;
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
|
||||
// Create possible solution string from challenge string + nonce.
|
||||
const solution = textEncoder.encode(seedStr + nonce.toString());
|
||||
|
||||
// Generate hex encoded SHA256 hashsum of solution.
|
||||
const hashArray = Array.from(sha256(solution));
|
||||
const hashAsHex = hashArray.map(b => b.toString(16).padStart(2, "0")).join("");
|
||||
|
||||
// Check whether hex encoded
|
||||
// solution matches challenge.
|
||||
if (hashAsHex == challengeStr) {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
// Iter nonce.
|
||||
nonce += iter;
|
||||
}
|
||||
};
|
||||
|
||||
onmessage = async function(e) {
|
||||
const thread = e.data.thread;
|
||||
const threads = e.data.threads;
|
||||
console.log("worker started:", thread); // eslint-disable-line no-console
|
||||
|
||||
// Compute nonce value that produces 'challenge', for our allotted thread.
|
||||
let nonce = await compute(e.data.seed, e.data.challenge, thread, threads);
|
||||
|
||||
// Post the solution nonce back to caller with thread no.
|
||||
postMessage({ nonce: nonce, done: true, thread: thread });
|
||||
};
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 Andrea Griffini
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// sha256(data) returns the digest of an input piece of data.
|
||||
// sha256(none) returns an object you can call .add(data), and .digest() at the end.
|
||||
// the returned digest is a 32-byte Uint8Array instance with an added .hex() function.
|
||||
// input should be string (that will be encoded as UTF-8) or an array-like with values 0..255.
|
||||
// source: https://github.com/6502/sha256
|
||||
export default function sha256(data) {
|
||||
let h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a,
|
||||
h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19,
|
||||
tsz = 0, bp = 0;
|
||||
const k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2],
|
||||
rrot = (x, n) => (x >>> n) | (x << (32-n)),
|
||||
w = new Uint32Array(64),
|
||||
buf = new Uint8Array(64),
|
||||
process = () => {
|
||||
for (let j=0,r=0; j<16; j++,r+=4) {
|
||||
w[j] = (buf[r]<<24) | (buf[r+1]<<16) | (buf[r+2]<<8) | buf[r+3];
|
||||
}
|
||||
for (let j=16; j<64; j++) {
|
||||
let s0 = rrot(w[j-15], 7) ^ rrot(w[j-15], 18) ^ (w[j-15] >>> 3);
|
||||
let s1 = rrot(w[j-2], 17) ^ rrot(w[j-2], 19) ^ (w[j-2] >>> 10);
|
||||
w[j] = (w[j-16] + s0 + w[j-7] + s1) | 0;
|
||||
}
|
||||
let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
|
||||
for (let j=0; j<64; j++) {
|
||||
let S1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25),
|
||||
ch = (e & f) ^ ((~e) & g),
|
||||
t1 = (h + S1 + ch + k[j] + w[j]) | 0,
|
||||
S0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22),
|
||||
maj = (a & b) ^ (a & c) ^ (b & c),
|
||||
t2 = (S0 + maj) | 0;
|
||||
h = g; g = f; f = e; e = (d + t1)|0; d = c; c = b; b = a; a = (t1 + t2)|0;
|
||||
}
|
||||
h0 = (h0 + a)|0; h1 = (h1 + b)|0; h2 = (h2 + c)|0; h3 = (h3 + d)|0;
|
||||
h4 = (h4 + e)|0; h5 = (h5 + f)|0; h6 = (h6 + g)|0; h7 = (h7 + h)|0;
|
||||
bp = 0;
|
||||
},
|
||||
add = data => {
|
||||
if (typeof data === "string") {
|
||||
data = typeof TextEncoder === "undefined" ? Buffer.from(data) : (new TextEncoder).encode(data);
|
||||
}
|
||||
for (let i=0; i<data.length; i++) {
|
||||
buf[bp++] = data[i];
|
||||
if (bp === 64) {process();}
|
||||
}
|
||||
tsz += data.length;
|
||||
},
|
||||
digest = () => {
|
||||
buf[bp++] = 0x80; if (bp == 64) {process();}
|
||||
if (bp + 8 > 64) {
|
||||
while (bp < 64) {buf[bp++] = 0x00;}
|
||||
process();
|
||||
}
|
||||
while (bp < 58) {buf[bp++] = 0x00;}
|
||||
// Max number of bytes is 35,184,372,088,831
|
||||
let L = tsz * 8;
|
||||
buf[bp++] = (L / 1099511627776.) & 255;
|
||||
buf[bp++] = (L / 4294967296.) & 255;
|
||||
buf[bp++] = L >>> 24;
|
||||
buf[bp++] = (L >>> 16) & 255;
|
||||
buf[bp++] = (L >>> 8) & 255;
|
||||
buf[bp++] = L & 255;
|
||||
process();
|
||||
let reply = new Uint8Array(32);
|
||||
reply[ 0] = h0 >>> 24; reply[ 1] = (h0 >>> 16) & 255; reply[ 2] = (h0 >>> 8) & 255; reply[ 3] = h0 & 255;
|
||||
reply[ 4] = h1 >>> 24; reply[ 5] = (h1 >>> 16) & 255; reply[ 6] = (h1 >>> 8) & 255; reply[ 7] = h1 & 255;
|
||||
reply[ 8] = h2 >>> 24; reply[ 9] = (h2 >>> 16) & 255; reply[10] = (h2 >>> 8) & 255; reply[11] = h2 & 255;
|
||||
reply[12] = h3 >>> 24; reply[13] = (h3 >>> 16) & 255; reply[14] = (h3 >>> 8) & 255; reply[15] = h3 & 255;
|
||||
reply[16] = h4 >>> 24; reply[17] = (h4 >>> 16) & 255; reply[18] = (h4 >>> 8) & 255; reply[19] = h4 & 255;
|
||||
reply[20] = h5 >>> 24; reply[21] = (h5 >>> 16) & 255; reply[22] = (h5 >>> 8) & 255; reply[23] = h5 & 255;
|
||||
reply[24] = h6 >>> 24; reply[25] = (h6 >>> 16) & 255; reply[26] = (h6 >>> 8) & 255; reply[27] = h6 & 255;
|
||||
reply[28] = h7 >>> 24; reply[29] = (h7 >>> 16) & 255; reply[30] = (h7 >>> 8) & 255; reply[31] = h7 & 255;
|
||||
reply.hex = () => {
|
||||
let res = "";
|
||||
reply.forEach(x => res += ("0" + x.toString(16)).slice(-2)); // eslint-disable-line no-return-assign
|
||||
return res;
|
||||
};
|
||||
return reply;
|
||||
};
|
||||
if (data === undefined) {return {add, digest};}
|
||||
add(data);
|
||||
return digest();
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
{{- /*
|
||||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ -}}
|
||||
|
||||
{{- with . }}
|
||||
<main>
|
||||
<section class="nollamas"
|
||||
data-nollamas-seed="{{ .seed }}"
|
||||
data-nollamas-challenge="{{ .challenge }}"
|
||||
>
|
||||
<h1>Checking you're not a creepy crawler...</h1>
|
||||
<noscript>
|
||||
<p>
|
||||
The page you're visiting is guarded from "ai" scrapers
|
||||
and other crawlers by a proof-of-work challenge.
|
||||
</p>
|
||||
<p>
|
||||
Unfortunately, this means that Javascript is required.
|
||||
To see the page, <b>please enable Javascript and try again</b>.
|
||||
</p>
|
||||
<aside>
|
||||
Once your browser has completed the challenge, you can turn
|
||||
Javascript off again if you like. Revalidation is done once per hour.
|
||||
</aside>
|
||||
</noscript>
|
||||
</section>
|
||||
</main>
|
||||
{{- end }}
|
||||
Loading…
Add table
Add a link
Reference in a new issue