summaryrefslogtreecommitdiff
path: root/static/script
diff options
context:
space:
mode:
Diffstat (limited to 'static/script')
-rw-r--r--static/script/captcha.js143
1 files changed, 143 insertions, 0 deletions
diff --git a/static/script/captcha.js b/static/script/captcha.js
new file mode 100644
index 0000000..78dcb3d
--- /dev/null
+++ b/static/script/captcha.js
@@ -0,0 +1,143 @@
+textXform = {
+ "a": "\u{10900}",
+ "b": "\u{10901}",
+ "c": "\u{10902}",
+ "d": "\u{10903}",
+ "e": "\u{10904}",
+ "f": "\u{10905}",
+ "g": "\u{10906}",
+ "h": "\u{10907}",
+ "i": "\u{10908}",
+ "j": "\u{10909}",
+ "k": "\u{1090A}",
+ "l": "\u{1090B}",
+ "m": "\u{1090C}",
+ "n": "\u{1090D}",
+ "o": "\u{1090E}",
+ "p": "\u{1090F}",
+ "q": "\u{10910}",
+ "r": "\u{10911}",
+ "s": "\u{10912}",
+ "t": "\u{10913}",
+ "u": "\u{10914}",
+ "v": "\u{10915}",
+ ".": "\u{1091F}",
+}
+
+class DroseraCaptcha extends HTMLElement {
+ constructor() {
+ super();
+ }
+ onSquareClick(event) {
+ const square = event.target;
+ if (square.dataset.active === undefined) {
+ square.dataset.active = "1";
+ } else if (square.dataset.active == "1") {
+ square.dataset.active = "2";
+ } else if (square.dataset.active == "2") {
+ square.dataset.active = "3";
+ } else {
+ delete square.dataset.active;
+ }
+ event.preventDefault();
+ }
+ onSquareReset(event) {
+ const square = event.target;
+ delete square.dataset.active;
+ event.preventDefault();
+ }
+ onSquareContext(event) {
+ event.preventDefault();
+ }
+ onResetCaptcha(event) {
+ const grid = event.target.parentNode.getElementsByClassName("dsc-inner")[0];
+ for (const child of grid.childNodes) {
+ if (!child.disabled) {
+ delete child.dataset.active;
+ }
+ }
+ }
+ onSubmitCaptcha(event) {
+ const grid = event.target.parentNode.getElementsByClassName("dsc-inner")[0];
+ const output = grid.childNodes.values().map(square => square.dataset.active ?? "0").join("");
+ const params = new URLSearchParams({
+ size: this.size,
+ label: this.label,
+ lock: this.lock,
+ answer: output
+ })
+ console.log("/captcha?" + params.toString())
+ const request = new Request("/captcha?" + params.toString());
+ this.outer.disabled = true;
+ window.fetch(request).then(response => {
+ if (response.ok) {
+ this.outer.disabled = false;
+ this.outer.dataset.solved = "";
+ if (this.reload) {
+ location.reload();
+ }
+ } else {
+ this.outer.disabled = false;
+ }
+ })
+ }
+ connectedCallback() {
+ const shadow = this.attachShadow({ mode: "open" });
+
+ const linkElem = document.createElement("link");
+ linkElem.setAttribute("rel", "stylesheet");
+ linkElem.setAttribute("href", "/static/style/captcha.css");
+ shadow.appendChild(linkElem);
+
+ const outer = document.createElement("fieldset");
+ outer.className = "dsc-outer";
+ if (this.dataset.solved !== undefined) {
+ outer.dataset.solved = "";
+ }
+ this.reload = this.dataset.reload !== undefined;
+
+ const resetBtn = document.createElement("button");
+ resetBtn.innerText = "Reset"
+ resetBtn.addEventListener("click", this.onResetCaptcha);
+ const submitBtn = document.createElement("button");
+ submitBtn.className = "dsc-submit";
+ submitBtn.innerText = "Submit"
+ submitBtn.addEventListener("click", this.onSubmitCaptcha.bind(this));
+
+ const inner = document.createElement("div");
+ inner.style.gridTemplateColumns = `repeat(${this.dataset.size}, 1fr)`
+ inner.className = "dsc-inner";
+ for (var alp = 0; alp < this.dataset.size; alp++) {
+ for (var bet = 0; bet < this.dataset.size; bet++) {
+ const square = document.createElement("button");
+ square.tabIndex = 0;
+ square.addEventListener("click", this.onSquareClick);
+ square.addEventListener("auxclick", this.onSquareReset);
+ square.addEventListener("contextmenu", this.onSquareContext);
+ const label = document.createElement("span");
+ const shift = alp * this.dataset.size + bet;
+ label.innerText = textXform[this.dataset.label.at(shift)];
+ const lock = this.dataset.lock.at(shift);
+ if (lock != ".") {
+ square.dataset.active = lock;
+ square.disabled = true;
+ }
+ square.appendChild(label);
+ inner.appendChild(square);
+ }
+ }
+
+ this.size = this.dataset.size;
+ this.label = this.dataset.label;
+ this.lock = this.dataset.lock;
+ this.outer = outer;
+ this.inner = inner;
+
+ outer.appendChild(resetBtn);
+ outer.appendChild(inner);
+ outer.appendChild(submitBtn);
+ shadow.appendChild(outer);
+ }
+}
+
+customElements.define("drosera-captcha", DroseraCaptcha); \ No newline at end of file