mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-14 12:38:45 +00:00
feat: add 'proof of React' challenge
Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
62
lib/challenge/preact/js/app.jsx
Normal file
62
lib/challenge/preact/js/app.jsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { render, h } from 'preact';
|
||||
import { useState, useEffect } from 'preact/hooks';
|
||||
import { g, j, u } from "./xeact.js";
|
||||
import { Sha256 } from '@aws-crypto/sha256-js';
|
||||
|
||||
/** @jsx h */
|
||||
|
||||
function toHexString(arr) {
|
||||
return Array.from(arr)
|
||||
.map((c) => c.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const [state, setState] = useState(null);
|
||||
const [imageURL, setImageURL] = useState(null);
|
||||
const [passed, setPassed] = useState(false);
|
||||
const [challenge, setChallenge] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
setState(j("preact_info"));
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setImageURL(state.pensive_url);
|
||||
const hash = new Sha256('');
|
||||
hash.update(state.challenge);
|
||||
setChallenge(toHexString(hash.digestSync()));
|
||||
}, [state]);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setPassed(true);
|
||||
}, state.difficulty * 100);
|
||||
|
||||
console.log(challenge);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [challenge]);
|
||||
|
||||
useEffect(() => {
|
||||
window.location.href = u(state.redir, {
|
||||
result: challenge,
|
||||
});
|
||||
}, [passed]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{imageURL !== null && (
|
||||
<img src={imageURL} style="width:100%;max-width:256px;" />
|
||||
)}
|
||||
{state !== null && (
|
||||
<div>
|
||||
<p id="status">{state.loading_message}</p>
|
||||
<p>{state.connection_security_message}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render(<App />, g("app"));
|
||||
120
lib/challenge/preact/js/xeact.js
Normal file
120
lib/challenge/preact/js/xeact.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Creates a DOM element, assigns the properties of `data` to it, and appends all `children`.
|
||||
*
|
||||
* @type{function(string|Function, Object=, Node|Array.<Node|string>=)}
|
||||
*/
|
||||
const h = (name, data = {}, children = []) => {
|
||||
const result =
|
||||
typeof name == "function" ? name(data) : Object.assign(document.createElement(name), data);
|
||||
if (!Array.isArray(children)) {
|
||||
children = [children];
|
||||
}
|
||||
result.append(...children);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a text node.
|
||||
*
|
||||
* Equivalent to `document.createTextNode(text)`
|
||||
*
|
||||
* @type{function(string): Text}
|
||||
*/
|
||||
const t = (text) => document.createTextNode(text);
|
||||
|
||||
/**
|
||||
* Remove all child nodes from a DOM element.
|
||||
*
|
||||
* @type{function(Node)}
|
||||
*/
|
||||
const x = (elem) => {
|
||||
while (elem.lastChild) {
|
||||
elem.removeChild(elem.lastChild);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all elements with the given ID.
|
||||
*
|
||||
* Equivalent to `document.getElementById(name)`
|
||||
*
|
||||
* @type{function(string): HTMLElement}
|
||||
*/
|
||||
const g = (name) => document.getElementById(name);
|
||||
|
||||
/**
|
||||
* Get all elements with the given class name.
|
||||
*
|
||||
* Equivalent to `document.getElementsByClassName(name)`
|
||||
*
|
||||
* @type{function(string): HTMLCollectionOf.<Element>}
|
||||
*/
|
||||
const c = (name) => document.getElementsByClassName(name);
|
||||
|
||||
/** @type{function(string): HTMLCollectionOf.<Element>} */
|
||||
const n = (name) => document.getElementsByName(name);
|
||||
|
||||
/**
|
||||
* Get all elements matching the given HTML selector.
|
||||
*
|
||||
* Matches selectors with `document.querySelectorAll(selector)`
|
||||
*
|
||||
* @type{function(string): Array.<HTMLElement>}
|
||||
*/
|
||||
const s = (selector) => Array.from(document.querySelectorAll(selector));
|
||||
|
||||
/**
|
||||
* Generate a relative URL from `url`, appending all key-value pairs from `params` as URL-encoded parameters.
|
||||
*
|
||||
* @type{function(string=, Object=): string}
|
||||
*/
|
||||
const u = (url = "", params = {}) => {
|
||||
let result = new URL(url, window.location.href);
|
||||
Object.entries(params).forEach((kv) => {
|
||||
let [k, v] = kv;
|
||||
result.searchParams.set(k, v);
|
||||
});
|
||||
return result.toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes a callback to run when all DOM content is loaded.
|
||||
*
|
||||
* Equivalent to `window.addEventListener('DOMContentLoaded', callback)`
|
||||
*
|
||||
* @type{function(function())}
|
||||
*/
|
||||
const r = (callback) => window.addEventListener("DOMContentLoaded", callback);
|
||||
|
||||
/**
|
||||
* Allows a stateful value to be tracked by consumers.
|
||||
*
|
||||
* This is the Xeact version of the React useState hook.
|
||||
*
|
||||
* @type{function(any): [function(): any, function(any): void]}
|
||||
*/
|
||||
const useState = (value = undefined) => {
|
||||
return [
|
||||
() => value,
|
||||
(x) => {
|
||||
value = x;
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Debounce an action for up to ms milliseconds.
|
||||
*
|
||||
* @type{function(number): function(function(any): void)}
|
||||
*/
|
||||
const d = (ms) => {
|
||||
let debounceTimer = null;
|
||||
return (f) => {
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(f, ms);
|
||||
};
|
||||
};
|
||||
|
||||
const j = (id) => JSON.parse(g(id).textContent);
|
||||
|
||||
export { h, t, x, g, j, c, n, u, s, r, useState, d };
|
||||
Reference in New Issue
Block a user