mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 17:10:10 +00:00
form: modularize captcha somewhat
This commit is contained in:
parent
6e205760c3
commit
ab05c07469
59
ts/form.ts
59
ts/form.ts
@ -4,6 +4,7 @@ import { _get, _post, toggleLoader, addLoader, removeLoader, toDateString } from
|
|||||||
import { loadLangSelector } from "./modules/lang.js";
|
import { loadLangSelector } from "./modules/lang.js";
|
||||||
import { Validator, ValidatorConf, ValidatorRespDTO } from "./modules/validator.js";
|
import { Validator, ValidatorConf, ValidatorRespDTO } from "./modules/validator.js";
|
||||||
import { Discord, Telegram, Matrix, ServiceConfiguration, MatrixConfiguration } from "./modules/account-linking.js";
|
import { Discord, Telegram, Matrix, ServiceConfiguration, MatrixConfiguration } from "./modules/account-linking.js";
|
||||||
|
import { Captcha } from "./modules/captcha.js";
|
||||||
|
|
||||||
interface formWindow extends Window {
|
interface formWindow extends Window {
|
||||||
invalidPassword: string;
|
invalidPassword: string;
|
||||||
@ -172,35 +173,7 @@ if (!window.usernameEnabled) { usernameField.parentElement.remove(); usernameFie
|
|||||||
const passwordField = document.getElementById("create-password") as HTMLInputElement;
|
const passwordField = document.getElementById("create-password") as HTMLInputElement;
|
||||||
const rePasswordField = document.getElementById("create-reenter-password") as HTMLInputElement;
|
const rePasswordField = document.getElementById("create-reenter-password") as HTMLInputElement;
|
||||||
|
|
||||||
let captchaVerified = false;
|
let captcha = new Captcha(window.code, window.captcha, window.reCAPTCHA);
|
||||||
let captchaID = "";
|
|
||||||
let captchaInput = document.getElementById("captcha-input") as HTMLInputElement;
|
|
||||||
const captchaCheckbox = document.getElementById("captcha-success") as HTMLSpanElement;
|
|
||||||
let prevCaptcha = "";
|
|
||||||
|
|
||||||
let baseValidator = (oncomplete: (valid: boolean) => void): void => {
|
|
||||||
if (window.captcha && !window.reCAPTCHA && (captchaInput.value != prevCaptcha)) {
|
|
||||||
prevCaptcha = captchaInput.value;
|
|
||||||
_post("/captcha/verify/" + window.code + "/" + captchaID + "/" + captchaInput.value, null, (req: XMLHttpRequest) => {
|
|
||||||
if (req.readyState == 4) {
|
|
||||||
if (req.status == 204) {
|
|
||||||
captchaCheckbox.innerHTML = `<i class="ri-check-line"></i>`;
|
|
||||||
captchaCheckbox.classList.add("~positive");
|
|
||||||
captchaCheckbox.classList.remove("~critical");
|
|
||||||
captchaVerified = true;
|
|
||||||
} else {
|
|
||||||
captchaCheckbox.innerHTML = `<i class="ri-close-line"></i>`;
|
|
||||||
captchaCheckbox.classList.add("~critical");
|
|
||||||
captchaCheckbox.classList.remove("~positive");
|
|
||||||
captchaVerified = false;
|
|
||||||
}
|
|
||||||
_baseValidator(oncomplete, captchaVerified);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
_baseValidator(oncomplete, captchaVerified);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function _baseValidator(oncomplete: (valid: boolean) => void, captchaValid: boolean): void {
|
function _baseValidator(oncomplete: (valid: boolean) => void, captchaValid: boolean): void {
|
||||||
if (window.emailRequired) {
|
if (window.emailRequired) {
|
||||||
@ -228,6 +201,8 @@ function _baseValidator(oncomplete: (valid: boolean) => void, captchaValid: bool
|
|||||||
oncomplete(true);
|
oncomplete(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let baseValidator = captcha.baseValidatorWrapper(_baseValidator);
|
||||||
|
|
||||||
interface GreCAPTCHA {
|
interface GreCAPTCHA {
|
||||||
render: (container: HTMLDivElement, parameters: {
|
render: (container: HTMLDivElement, parameters: {
|
||||||
sitekey?: string,
|
sitekey?: string,
|
||||||
@ -273,29 +248,15 @@ interface sendDTO {
|
|||||||
captcha_text?: string;
|
captcha_text?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const genCaptcha = () => {
|
|
||||||
_get("/captcha/gen/"+window.code, null, (req: XMLHttpRequest) => {
|
|
||||||
if (req.readyState == 4) {
|
|
||||||
if (req.status == 200) {
|
|
||||||
captchaID = req.response["id"];
|
|
||||||
document.getElementById("captcha-img").innerHTML = `
|
|
||||||
<img class="w-100" src="${window.location.toString().substring(0, window.location.toString().lastIndexOf("/invite"))}/captcha/img/${window.code}/${captchaID}"></img>
|
|
||||||
`;
|
|
||||||
captchaInput.value = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (window.captcha && !window.reCAPTCHA) {
|
if (window.captcha && !window.reCAPTCHA) {
|
||||||
genCaptcha();
|
captcha.generate();
|
||||||
(document.getElementById("captcha-regen") as HTMLSpanElement).onclick = genCaptcha;
|
(document.getElementById("captcha-regen") as HTMLSpanElement).onclick = captcha.generate;
|
||||||
captchaInput.onkeyup = validator.validate;
|
captcha.input.onkeyup = validator.validate;
|
||||||
}
|
}
|
||||||
|
|
||||||
const create = (event: SubmitEvent) => {
|
const create = (event: SubmitEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (window.captcha && !window.reCAPTCHA && !captchaVerified) {
|
if (window.captcha && !window.reCAPTCHA && !captcha.verified) {
|
||||||
|
|
||||||
}
|
}
|
||||||
addLoader(submitSpan);
|
addLoader(submitSpan);
|
||||||
@ -330,8 +291,8 @@ const create = (event: SubmitEvent) => {
|
|||||||
if (window.reCAPTCHA) {
|
if (window.reCAPTCHA) {
|
||||||
send.captcha_text = grecaptcha.getResponse();
|
send.captcha_text = grecaptcha.getResponse();
|
||||||
} else {
|
} else {
|
||||||
send.captcha_id = captchaID;
|
send.captcha_id = captcha.captchaID;
|
||||||
send.captcha_text = captchaInput.value;
|
send.captcha_text = captcha.input.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_post("/newUser", send, (req: XMLHttpRequest) => {
|
_post("/newUser", send, (req: XMLHttpRequest) => {
|
||||||
|
64
ts/modules/captcha.ts
Normal file
64
ts/modules/captcha.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { _get, _post } from "./common.js";
|
||||||
|
|
||||||
|
export class Captcha {
|
||||||
|
enabled = true;
|
||||||
|
verified = false;
|
||||||
|
captchaID = "";
|
||||||
|
input = document.getElementById("captcha-input") as HTMLInputElement;
|
||||||
|
checkbox = document.getElementById("captcha-success") as HTMLSpanElement;
|
||||||
|
previous = "";
|
||||||
|
reCAPTCHA = false;
|
||||||
|
code = "";
|
||||||
|
|
||||||
|
get value(): string { return this.input.value; }
|
||||||
|
|
||||||
|
hasChanged = (): boolean => { return this.value != this.previous; }
|
||||||
|
|
||||||
|
baseValidatorWrapper = (_baseValidator: (oncomplete: (valid: boolean) => void, captchaValid: boolean) => void) => {
|
||||||
|
return (oncomplete: (valid: boolean) => void): void => {
|
||||||
|
if (this.enabled && !this.reCAPTCHA && this.hasChanged()) {
|
||||||
|
this.previous = this.value;
|
||||||
|
this.verify(() => {
|
||||||
|
_baseValidator(oncomplete, this.verified);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
_baseValidator(oncomplete, this.verified);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
verify = (callback: () => void) => _post("/captcha/verify/" + this.code + "/" + this.captchaID + "/" + this.input.value, null, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
if (req.status == 204) {
|
||||||
|
this.checkbox.innerHTML = `<i class="ri-check-line"></i>`;
|
||||||
|
this.checkbox.classList.add("~positive");
|
||||||
|
this.checkbox.classList.remove("~critical");
|
||||||
|
this.verified = true;
|
||||||
|
} else {
|
||||||
|
this.checkbox.innerHTML = `<i class="ri-close-line"></i>`;
|
||||||
|
this.checkbox.classList.add("~critical");
|
||||||
|
this.checkbox.classList.remove("~positive");
|
||||||
|
this.verified = false;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
generate = () => _get("/captcha/gen/"+this.code, null, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
if (req.status == 200) {
|
||||||
|
this.captchaID = req.response["id"];
|
||||||
|
document.getElementById("captcha-img").innerHTML = `
|
||||||
|
<img class="w-100" src="${window.location.toString().substring(0, window.location.toString().lastIndexOf("/invite"))}/captcha/img/${this.code}/${this.captchaID}"></img>
|
||||||
|
`;
|
||||||
|
this.input.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor(code: string, enabled: boolean, reCAPTCHA: boolean) {
|
||||||
|
this.code = code;
|
||||||
|
this.enabled = enabled;
|
||||||
|
this.reCAPTCHA = reCAPTCHA;
|
||||||
|
}
|
||||||
|
}
|
@ -28,6 +28,9 @@ interface formWindow extends Window {
|
|||||||
userExpiryHours: number;
|
userExpiryHours: number;
|
||||||
userExpiryMinutes: number;
|
userExpiryMinutes: number;
|
||||||
userExpiryMessage: string;
|
userExpiryMessage: string;
|
||||||
|
captcha: boolean;
|
||||||
|
reCAPTCHA: boolean;
|
||||||
|
reCAPTCHASiteKey: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadLangSelector("pwr");
|
loadLangSelector("pwr");
|
||||||
|
3
views.go
3
views.go
@ -296,6 +296,9 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
|
|||||||
data["telegramEnabled"] = false
|
data["telegramEnabled"] = false
|
||||||
data["discordEnabled"] = false
|
data["discordEnabled"] = false
|
||||||
data["matrixEnabled"] = false
|
data["matrixEnabled"] = false
|
||||||
|
data["captcha"] = app.config.Section("captcha").Key("enabled").MustBool(false)
|
||||||
|
data["reCAPTCHA"] = app.config.Section("captcha").Key("recaptcha").MustBool(false)
|
||||||
|
data["reCAPTCHASiteKey"] = app.config.Section("captcha").Key("recaptcha_site_key").MustString("")
|
||||||
gcHTML(gc, http.StatusOK, "form-loader.html", data)
|
gcHTML(gc, http.StatusOK, "form-loader.html", data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user