aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/docs/CHANGELOG.md1
-rw-r--r--package.json6
-rw-r--r--web/index.templ7
-rw-r--r--web/index_templ.go16
-rw-r--r--web/js/main.mjs112
-rw-r--r--xess/xess.go1
-rw-r--r--xess/xess_templ.go2
7 files changed, 105 insertions, 40 deletions
diff --git a/docs/docs/CHANGELOG.md b/docs/docs/CHANGELOG.md
index a16b703..639d097 100644
--- a/docs/docs/CHANGELOG.md
+++ b/docs/docs/CHANGELOG.md
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Static asset builds are now done on demand instead of the results being committed to source control
- The Dockerfile has been removed as it is no longer in use
- Developer documentation has been added to the docs site
+- Show more errors when some predictable challenge page errors happen ([#150](https://github.com/TecharoHQ/anubis/issues/150))
## v1.15.0
diff --git a/package.json b/package.json
index aeb2f2a..e13b3b3 100644
--- a/package.json
+++ b/package.json
@@ -5,9 +5,9 @@
"main": "index.js",
"scripts": {
"test": "npm run assets && go test ./...",
- "test:integration": "npm run assets && go test ./internal/test",
- "assets": "./web/build.sh && ./xess/build.sh",
- "dev": "npm run assets && go run ./cmd/anubis",
+ "test:integration": "npm run assets && go test -v ./internal/test",
+ "assets": "go generate ./... && ./web/build.sh && ./xess/build.sh",
+ "dev": "npm run assets && go run ./cmd/anubis --use-remote-address",
"container": "npm run assets && go run ./cmd/containerbuild"
},
"author": "",
diff --git a/web/index.templ b/web/index.templ
index ca6086c..8aa626c 100644
--- a/web/index.templ
+++ b/web/index.templ
@@ -128,6 +128,11 @@ templ base(title string, body templ.Component) {
left: 12.28719px;
}
+ .mx-auto {
+ margin-left: auto;
+ margin-right: auto;
+ }
+
@keyframes lds-roller {
0% {
transform: rotate(0deg);
@@ -176,7 +181,7 @@ templ index() {
/>
<p id="status">Loading...</p>
<script async type="module" src={ "/.within.website/x/cmd/anubis/static/js/main.mjs?cacheBuster=" + anubis.Version }></script>
- <div id="spinner" class="lds-roller">
+ <div id="spinner" class="lds-roller mx-auto" style="display:none;">
<div></div>
<div></div>
<div></div>
diff --git a/web/index_templ.go b/web/index_templ.go
index e647132..7c4cf24 100644
--- a/web/index_templ.go
+++ b/web/index_templ.go
@@ -60,7 +60,7 @@ func base(title string, body templ.Component) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style>\n body,\n html {\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n margin-left: auto;\n margin-right: auto;\n }\n\n .centered-div {\n text-align: center;\n }\n\n .lds-roller,\n .lds-roller div,\n .lds-roller div:after {\n box-sizing: border-box;\n }\n\n .lds-roller {\n display: inline-block;\n position: relative;\n width: 80px;\n height: 80px;\n }\n\n .lds-roller div {\n animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n transform-origin: 40px 40px;\n }\n\n .lds-roller div:after {\n content: \" \";\n display: block;\n position: absolute;\n width: 7.2px;\n height: 7.2px;\n border-radius: 50%;\n background: currentColor;\n margin: -3.6px 0 0 -3.6px;\n }\n\n .lds-roller div:nth-child(1) {\n animation-delay: -0.036s;\n }\n\n .lds-roller div:nth-child(1):after {\n top: 62.62742px;\n left: 62.62742px;\n }\n\n .lds-roller div:nth-child(2) {\n animation-delay: -0.072s;\n }\n\n .lds-roller div:nth-child(2):after {\n top: 67.71281px;\n left: 56px;\n }\n\n .lds-roller div:nth-child(3) {\n animation-delay: -0.108s;\n }\n\n .lds-roller div:nth-child(3):after {\n top: 70.90963px;\n left: 48.28221px;\n }\n\n .lds-roller div:nth-child(4) {\n animation-delay: -0.144s;\n }\n\n .lds-roller div:nth-child(4):after {\n top: 72px;\n left: 40px;\n }\n\n .lds-roller div:nth-child(5) {\n animation-delay: -0.18s;\n }\n\n .lds-roller div:nth-child(5):after {\n top: 70.90963px;\n left: 31.71779px;\n }\n\n .lds-roller div:nth-child(6) {\n animation-delay: -0.216s;\n }\n\n .lds-roller div:nth-child(6):after {\n top: 67.71281px;\n left: 24px;\n }\n\n .lds-roller div:nth-child(7) {\n animation-delay: -0.252s;\n }\n\n .lds-roller div:nth-child(7):after {\n top: 62.62742px;\n left: 17.37258px;\n }\n\n .lds-roller div:nth-child(8) {\n animation-delay: -0.288s;\n }\n\n .lds-roller div:nth-child(8):after {\n top: 56px;\n left: 12.28719px;\n }\n\n @keyframes lds-roller {\n 0% {\n transform: rotate(0deg);\n }\n\n 100% {\n transform: rotate(360deg);\n }\n }\n </style>")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><style>\n body,\n html {\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n margin-left: auto;\n margin-right: auto;\n }\n\n .centered-div {\n text-align: center;\n }\n\n .lds-roller,\n .lds-roller div,\n .lds-roller div:after {\n box-sizing: border-box;\n }\n\n .lds-roller {\n display: inline-block;\n position: relative;\n width: 80px;\n height: 80px;\n }\n\n .lds-roller div {\n animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n transform-origin: 40px 40px;\n }\n\n .lds-roller div:after {\n content: \" \";\n display: block;\n position: absolute;\n width: 7.2px;\n height: 7.2px;\n border-radius: 50%;\n background: currentColor;\n margin: -3.6px 0 0 -3.6px;\n }\n\n .lds-roller div:nth-child(1) {\n animation-delay: -0.036s;\n }\n\n .lds-roller div:nth-child(1):after {\n top: 62.62742px;\n left: 62.62742px;\n }\n\n .lds-roller div:nth-child(2) {\n animation-delay: -0.072s;\n }\n\n .lds-roller div:nth-child(2):after {\n top: 67.71281px;\n left: 56px;\n }\n\n .lds-roller div:nth-child(3) {\n animation-delay: -0.108s;\n }\n\n .lds-roller div:nth-child(3):after {\n top: 70.90963px;\n left: 48.28221px;\n }\n\n .lds-roller div:nth-child(4) {\n animation-delay: -0.144s;\n }\n\n .lds-roller div:nth-child(4):after {\n top: 72px;\n left: 40px;\n }\n\n .lds-roller div:nth-child(5) {\n animation-delay: -0.18s;\n }\n\n .lds-roller div:nth-child(5):after {\n top: 70.90963px;\n left: 31.71779px;\n }\n\n .lds-roller div:nth-child(6) {\n animation-delay: -0.216s;\n }\n\n .lds-roller div:nth-child(6):after {\n top: 67.71281px;\n left: 24px;\n }\n\n .lds-roller div:nth-child(7) {\n animation-delay: -0.252s;\n }\n\n .lds-roller div:nth-child(7):after {\n top: 62.62742px;\n left: 17.37258px;\n }\n\n .lds-roller div:nth-child(8) {\n animation-delay: -0.288s;\n }\n\n .lds-roller div:nth-child(8):after {\n top: 56px;\n left: 12.28719px;\n }\n\n .mx-auto {\n margin-left: auto;\n margin-right: auto;\n }\n\n @keyframes lds-roller {\n 0% {\n transform: rotate(0deg);\n }\n\n 100% {\n transform: rotate(360deg);\n }\n }\n </style>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -75,7 +75,7 @@ func base(title string, body templ.Component) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 146, Col: 49}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 151, Col: 49}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@@ -126,7 +126,7 @@ func index() templ.Component {
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" +
anubis.Version)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 169, Col: 18}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 174, Col: 18}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@@ -140,7 +140,7 @@ func index() templ.Component {
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs("/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" +
anubis.Version)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 175, Col: 18}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 180, Col: 18}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@@ -153,13 +153,13 @@ func index() templ.Component {
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs("/.within.website/x/cmd/anubis/static/js/main.mjs?cacheBuster=" + anubis.Version)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 178, Col: 116}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 183, Col: 116}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\"></script><div id=\"spinner\" class=\"lds-roller\"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><details><summary>Why am I seeing this?</summary><p>You are seeing this because the administrator of this website has set up <a href=\"https://github.com/TecharoHQ/anubis\">Anubis</a> to protect the server against the scourge of <a href=\"https://thelibre.news/foss-infrastructure-is-under-attack-by-ai-companies/\">AI companies aggressively scraping websites</a>. This can and does cause downtime for the websites, which makes their resources inaccessible for everyone.</p><p>Anubis is a compromise. Anubis uses a <a href=\"https://anubis.techaro.lol/docs/design/why-proof-of-work\">Proof-of-Work</a> scheme in the vein of <a href=\"https://en.wikipedia.org/wiki/Hashcash\">Hashcash</a>, a proposed proof-of-work scheme for reducing email spam. The idea is that at individual scales the additional load is ignorable, but at mass scraper levels it adds up and makes scraping much more expensive.</p><p>Ultimately, this is a hack whose real purpose is to give a \"good enough\" placeholder solution so that more time can be spent on fingerprinting and identifying headless browsers (EG: via how they do font rendering) so that the challenge proof of work page doesn't need to be presented to users that are much more likely to be legitimate.</p><p>Please note that Anubis requires the use of modern JavaScript features that plugins like <a href=\"https://jshelter.org/\">JShelter</a> will disable. Please disable JShelter or other such plugins for this domain.</p></details><noscript><p>Sadly, you must enable JavaScript to get past this challenge. This is required because AI companies have changed the social contract around how website hosting works. A no-JS solution is a work-in-progress.</p></noscript><div id=\"testarea\"></div></div>")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\"></script><div id=\"spinner\" class=\"lds-roller mx-auto\" style=\"display:none;\"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><details><summary>Why am I seeing this?</summary><p>You are seeing this because the administrator of this website has set up <a href=\"https://github.com/TecharoHQ/anubis\">Anubis</a> to protect the server against the scourge of <a href=\"https://thelibre.news/foss-infrastructure-is-under-attack-by-ai-companies/\">AI companies aggressively scraping websites</a>. This can and does cause downtime for the websites, which makes their resources inaccessible for everyone.</p><p>Anubis is a compromise. Anubis uses a <a href=\"https://anubis.techaro.lol/docs/design/why-proof-of-work\">Proof-of-Work</a> scheme in the vein of <a href=\"https://en.wikipedia.org/wiki/Hashcash\">Hashcash</a>, a proposed proof-of-work scheme for reducing email spam. The idea is that at individual scales the additional load is ignorable, but at mass scraper levels it adds up and makes scraping much more expensive.</p><p>Ultimately, this is a hack whose real purpose is to give a \"good enough\" placeholder solution so that more time can be spent on fingerprinting and identifying headless browsers (EG: via how they do font rendering) so that the challenge proof of work page doesn't need to be presented to users that are much more likely to be legitimate.</p><p>Please note that Anubis requires the use of modern JavaScript features that plugins like <a href=\"https://jshelter.org/\">JShelter</a> will disable. Please disable JShelter or other such plugins for this domain.</p></details><noscript><p>Sadly, you must enable JavaScript to get past this challenge. This is required because AI companies have changed the social contract around how website hosting works. A no-JS solution is a work-in-progress.</p></noscript><div id=\"testarea\"></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -195,7 +195,7 @@ func errorPage(message string) templ.Component {
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs("/.within.website/x/cmd/anubis/static/img/sad.webp?cacheBuster=" + anubis.Version)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 211, Col: 90}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 216, Col: 90}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
@@ -208,7 +208,7 @@ func errorPage(message string) templ.Component {
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(message)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 213, Col: 14}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 218, Col: 14}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
diff --git a/web/js/main.mjs b/web/js/main.mjs
index 297f16f..daaafcf 100644
--- a/web/js/main.mjs
+++ b/web/js/main.mjs
@@ -5,7 +5,7 @@ import { testVideo } from "./video.mjs";
const algorithms = {
"fast": processFast,
"slow": processSlow,
-}
+};
// from Xeact
const u = (url = "", params = {}) => {
@@ -20,6 +20,19 @@ const u = (url = "", params = {}) => {
const imageURL = (mood, cacheBuster) =>
u(`/.within.website/x/cmd/anubis/static/img/${mood}.webp`, { cacheBuster });
+const dependencies = [
+ {
+ name: "WebCrypto",
+ msg: "Your browser doesn't have a functioning web.crypto element. Are you viewing this over a secure context?",
+ value: window.crypto,
+ },
+ {
+ name: "Web Workers",
+ msg: "Your browser doesn't support web workers (Anubis uses this to avoid freezing your browser). Do you have a plugin like JShelter installed?",
+ value: window.Worker,
+ },
+];
+
(async () => {
const status = document.getElementById('status');
const image = document.getElementById('image');
@@ -27,6 +40,25 @@ const imageURL = (mood, cacheBuster) =>
const spinner = document.getElementById('spinner');
const anubisVersion = JSON.parse(document.getElementById('anubis_version').textContent);
+ const ohNoes = ({
+ titleMsg, statusMsg, imageSrc,
+ }) => {
+ title.innerHTML = titleMsg;
+ status.innerHTML = statusMsg;
+ image.src = imageSrc;
+ spinner.innerHTML = "";
+ spinner.style.display = "none";
+ };
+
+ if (!window.isSecureContext) {
+ ohNoes({
+ titleMsg: "Your context is not secure!",
+ statusMsg: `Try connecting over HTTPS or let the admin know to set up HTTPS. For more information, see <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure">MDN</a>.`,
+ imageSrc: imageURL("sad", anubisVersion),
+ });
+ return;
+ }
+
// const testarea = document.getElementById('testarea');
// const videoWorks = await testVideo(testarea);
@@ -43,6 +75,17 @@ const imageURL = (mood, cacheBuster) =>
status.innerHTML = 'Calculating...';
+ for (const val of dependencies) {
+ const { value, name, msg } = val;
+ if (!value) {
+ ohNoes({
+ titleMsg: `Missing feature ${name}`,
+ statusMsg: msg,
+ imageSrc: imageURL("sad", anubisVersion),
+ })
+ }
+ }
+
const { challenge, rules } = await fetch("/.within.website/x/cmd/anubis/api/make-challenge", { method: "POST" })
.then(r => {
if (!r.ok) {
@@ -51,39 +94,56 @@ const imageURL = (mood, cacheBuster) =>
return r.json();
})
.catch(err => {
- title.innerHTML = "Oh no!";
- status.innerHTML = `Failed to fetch config: ${err.message}`;
- image.src = imageURL("sad", anubisVersion);
- spinner.innerHTML = "";
- spinner.style.display = "none";
+ ohNoes({
+ titleMsg: "Internal error!",
+ statusMsg: `Failed to fetch challenge config: ${err.message}`,
+ imageSrc: imageURL("sad", anubisVersion),
+ });
throw err;
});
const process = algorithms[rules.algorithm];
if (!process) {
- title.innerHTML = "Oh no!";
- status.innerHTML = `Failed to resolve check algorithm. You may want to reload the page.`;
- image.src = imageURL("sad", anubisVersion);
- spinner.innerHTML = "";
- spinner.style.display = "none";
+ ohNoes({
+ titleMsg: "Challenge error!",
+ statusMsg: `Failed to resolve check algorithm. You may want to reload the page.`,
+ imageSrc: imageURL("sad", anubisVersion),
+ });
return;
}
status.innerHTML = `Calculating...<br/>Difficulty: ${rules.report_as}`;
+ spinner.style.display = "block";
+
+ try {
+ const t0 = Date.now();
+ const { hash, nonce } = await process(challenge, rules.difficulty);
+ const t1 = Date.now();
+ console.log({ hash, nonce });
+
+ title.innerHTML = "Success!";
+ status.innerHTML = `Done! Took ${t1 - t0}ms, ${nonce} iterations`;
+ image.src = imageURL("happy", anubisVersion);
+ spinner.innerHTML = "";
+ spinner.style.display = "none";
+
+ setTimeout(() => {
+ const redir = window.location.href;
- const t0 = Date.now();
- const { hash, nonce } = await process(challenge, rules.difficulty);
- const t1 = Date.now();
- console.log({ hash, nonce });
-
- title.innerHTML = "Success!";
- status.innerHTML = `Done! Took ${t1 - t0}ms, ${nonce} iterations`;
- image.src = imageURL("happy", anubisVersion);
- spinner.innerHTML = "";
- spinner.style.display = "none";
-
- setTimeout(() => {
- const redir = window.location.href;
- window.location.href = u("/.within.website/x/cmd/anubis/api/pass-challenge", { response: hash, nonce, redir, elapsedTime: t1 - t0 });
- }, 250);
+ window.location.replace(
+ u("/.within.website/x/cmd/anubis/api/pass-challenge", {
+ response: hash,
+ nonce,
+ redir,
+ elapsedTime: t1 - t0
+ }),
+ );
+ }, 250);
+ } catch (err) {
+ ohNoes({
+ titleMsg: "Calculation error!",
+ statusMsg: `Failed to calculate challenge: ${err.message}`,
+ imageSrc: imageURL("sad", anubisVersion),
+ });
+ }
})(); \ No newline at end of file
diff --git a/xess/xess.go b/xess/xess.go
index 18d995d..fa87858 100644
--- a/xess/xess.go
+++ b/xess/xess.go
@@ -13,7 +13,6 @@ import (
)
//go:generate go run github.com/a-h/templ/cmd/templ@latest generate
-//go:generate npm run build
var (
//go:embed *.css static
diff --git a/xess/xess_templ.go b/xess/xess_templ.go
index d8cab57..c1fa412 100644
--- a/xess/xess_templ.go
+++ b/xess/xess_templ.go
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
-// templ: version: v0.3.850
+// templ: version: v0.3.857
package xess
//lint:file-ignore SA4006 This context is only used if a nested component is present.