mirror of
https://github.com/sigmasternchen/axowall
synced 2025-03-15 08:38:55 +00:00
move css to build step, add challenge url
This commit is contained in:
parent
1877b1aa6e
commit
52309a8e21
7 changed files with 142 additions and 103 deletions
|
@ -5,6 +5,7 @@
|
||||||
"main": "src/main.ts",
|
"main": "src/main.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "esbuild src/main.ts --bundle --outfile=public/bundle.js",
|
"build": "esbuild src/main.ts --bundle --outfile=public/bundle.js",
|
||||||
|
"build-mini": "esbuild src/main.ts --minify --bundle --outfile=public/bundle.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
5
public/challenge.json
Normal file
5
public/challenge.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"algo": "SHA-256",
|
||||||
|
"prefixBits": "15",
|
||||||
|
"input": "challenge:"
|
||||||
|
}
|
|
@ -2,85 +2,9 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script src="bundle.js"></script>
|
<script src="bundle.js"></script>
|
||||||
<style>
|
<link href="bundle.css" rel="stylesheet">
|
||||||
.captcha {
|
|
||||||
width: 300px;
|
|
||||||
height: 70px;
|
|
||||||
padding: 19px;
|
|
||||||
border: 1px solid grey;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 20px;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.captcha span {
|
|
||||||
position: relative;
|
|
||||||
top: -9px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.captcha .checkbox {
|
|
||||||
position: relative;
|
|
||||||
margin: 0;
|
|
||||||
margin-right: 20px;
|
|
||||||
height: 30px;
|
|
||||||
width: 30px;
|
|
||||||
display: inline-block;
|
|
||||||
background-color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 1px solid black;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.captcha .checkbox:hover {
|
|
||||||
background-color: lightgrey;
|
|
||||||
}
|
|
||||||
|
|
||||||
.captcha .checkbox.checked {
|
|
||||||
background-color: #2196F3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.captcha .checkbox.checked::before {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
content: "";
|
|
||||||
width: 7px;
|
|
||||||
height: 15px;
|
|
||||||
top: 2px;
|
|
||||||
left: 9px;
|
|
||||||
border: white solid;
|
|
||||||
border-width: 0 5px 5px 0;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.captcha .checkbox.loading {
|
|
||||||
}
|
|
||||||
|
|
||||||
.captcha .checkbox.loading::before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 2.5px;
|
|
||||||
left: 2.5px;
|
|
||||||
width: 17px;
|
|
||||||
height: 17px;
|
|
||||||
border: 4px solid;
|
|
||||||
border-radius: 50%;
|
|
||||||
border-color: black transparent black transparent;
|
|
||||||
animation: captchaLoading infinite 1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes captchaLoading {
|
|
||||||
to{
|
|
||||||
transform: rotate(.5turn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="captcha"></div>
|
<div class="captcha" data-challenge-url="/challenge.json"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
10
src/challenge.ts
Normal file
10
src/challenge.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
export type Challenge = {
|
||||||
|
algo: string,
|
||||||
|
prefixBits: number,
|
||||||
|
input: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateChallenge(challenge: Challenge): boolean {
|
||||||
|
return !!challenge.algo && challenge.prefixBits > 0 && !!challenge.input;
|
||||||
|
}
|
70
src/default-styles.css
Normal file
70
src/default-styles.css
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
.captcha {
|
||||||
|
width: 300px;
|
||||||
|
height: 70px;
|
||||||
|
padding: 19px;
|
||||||
|
border: 1px solid grey;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 20px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha span {
|
||||||
|
position: relative;
|
||||||
|
top: -9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha .checkbox {
|
||||||
|
position: relative;
|
||||||
|
margin: 0 20px 0 0;
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha .checkbox:hover {
|
||||||
|
background-color: lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha .checkbox.checked {
|
||||||
|
background-color: #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha .checkbox.checked::before {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
width: 7px;
|
||||||
|
height: 15px;
|
||||||
|
top: 2px;
|
||||||
|
left: 9px;
|
||||||
|
border: white solid;
|
||||||
|
border-width: 0 5px 5px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha .checkbox.loading {
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha .checkbox.loading::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 3px;
|
||||||
|
width: 17px;
|
||||||
|
height: 17px;
|
||||||
|
border: 4px solid;
|
||||||
|
border-radius: 50%;
|
||||||
|
border-color: black transparent black transparent;
|
||||||
|
animation: captchaLoading infinite 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes captchaLoading {
|
||||||
|
to {
|
||||||
|
transform: rotate(.5turn)
|
||||||
|
}
|
||||||
|
}
|
49
src/main.ts
49
src/main.ts
|
@ -1,6 +1,9 @@
|
||||||
import {makeSuffix} from "./content";
|
import {makeSuffix} from "./content";
|
||||||
import {digest, sha256} from "./hash";
|
import {digest, sha256} from "./hash";
|
||||||
|
|
||||||
|
import "./default-styles.css";
|
||||||
|
import {Challenge, validateChallenge} from "./challenge";
|
||||||
|
|
||||||
async function findHashWithPrefix(hashPrefixBits: number, inputPrefix: string): Promise<string> {
|
async function findHashWithPrefix(hashPrefixBits: number, inputPrefix: string): Promise<string> {
|
||||||
const hashPrefix = new Uint8Array(Array(Math.ceil(hashPrefixBits / 8)).map(_ => 0));
|
const hashPrefix = new Uint8Array(Array(Math.ceil(hashPrefixBits / 8)).map(_ => 0));
|
||||||
let iteration = 0;
|
let iteration = 0;
|
||||||
|
@ -13,10 +16,7 @@ async function findHashWithPrefix(hashPrefixBits: number, inputPrefix: string):
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", () => {
|
function initCaptchaContentAndGetCheckbox(captcha: Element): Element {
|
||||||
console.log("load");
|
|
||||||
[...document.getElementsByClassName("captcha")].forEach(captcha => {
|
|
||||||
console.dir(captcha);
|
|
||||||
const checkbox = document.createElement("div");
|
const checkbox = document.createElement("div");
|
||||||
checkbox.classList.add("checkbox");
|
checkbox.classList.add("checkbox");
|
||||||
captcha.append(checkbox);
|
captcha.append(checkbox);
|
||||||
|
@ -25,18 +25,47 @@ window.addEventListener("load", () => {
|
||||||
text.innerText = "I am not a robot";
|
text.innerText = "I am not a robot";
|
||||||
captcha.append(text);
|
captcha.append(text);
|
||||||
|
|
||||||
checkbox.addEventListener("click", async function() {
|
return checkbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareChallengeExecution(challenge: Challenge): () => Promise<void> {
|
||||||
|
return async function() {
|
||||||
console.log("Calculating...");
|
console.log("Calculating...");
|
||||||
|
|
||||||
this.classList.add("loading");
|
this.classList.add("loading");
|
||||||
|
|
||||||
const challenge = makeSuffix(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)) + ":" + makeSuffix(new Date().valueOf()) + ":";
|
const response = await findHashWithPrefix(challenge.prefixBits, challenge.input);
|
||||||
|
|
||||||
const response = await findHashWithPrefix(15, challenge);
|
|
||||||
console.log("Challenge Response: " + response);
|
console.log("Challenge Response: " + response);
|
||||||
|
|
||||||
this.classList.remove("loading");
|
this.classList.remove("loading");
|
||||||
this.classList.add("checked");
|
this.classList.add("checked");
|
||||||
})
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
async function prepareCaptcha(captcha: Element) {
|
||||||
|
const challengeUrl = captcha.getAttribute("data-challenge-url");
|
||||||
|
if (!challengeUrl) {
|
||||||
|
console.warn("No challenge URL found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkbox = initCaptchaContentAndGetCheckbox(captcha);
|
||||||
|
checkbox.classList.add("loading");
|
||||||
|
|
||||||
|
const challengeResponse = await fetch(challengeUrl);
|
||||||
|
const challenge = await challengeResponse.json() as Challenge;
|
||||||
|
|
||||||
|
if (!validateChallenge(challenge)) {
|
||||||
|
console.warn("Challenge is invalid.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkbox.classList.remove("loading");
|
||||||
|
|
||||||
|
checkbox.addEventListener("click", prepareChallengeExecution(challenge));
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
console.log("load");
|
||||||
|
[...document.getElementsByClassName("captcha")].forEach(prepareCaptcha);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue