mirror of
https://github.com/hrfee/jfa-go.git
synced 2026-01-18 16:47:42 +01:00
to change the urls of the admin page, the my account page and of invites. Seems to work, but need to check all the code over and test.
378 lines
14 KiB
TypeScript
378 lines
14 KiB
TypeScript
import { Modal } from "./modules/modal.js";
|
|
import { notificationBox, whichAnimationEvent } from "./modules/common.js";
|
|
import { _get, _post, toggleLoader, addLoader, removeLoader, toDateString } from "./modules/common.js";
|
|
import { loadLangSelector } from "./modules/lang.js";
|
|
import { Validator, ValidatorConf, ValidatorRespDTO } from "./modules/validator.js";
|
|
import { Discord, Telegram, Matrix, ServiceConfiguration, MatrixConfiguration } from "./modules/account-linking.js";
|
|
import { Captcha, GreCAPTCHA } from "./modules/captcha.js";
|
|
|
|
interface formWindow extends GlobalWindow {
|
|
invalidPassword: string;
|
|
successModal: Modal;
|
|
telegramModal: Modal;
|
|
discordModal: Modal;
|
|
matrixModal: Modal;
|
|
confirmationModal: Modal;
|
|
redirectToJellyfin: boolean;
|
|
code: string;
|
|
messages: { [key: string]: string };
|
|
confirmation: boolean;
|
|
telegramRequired: boolean;
|
|
telegramPIN: string;
|
|
discordRequired: boolean;
|
|
discordPIN: string;
|
|
discordStartCommand: string;
|
|
discordInviteLink: boolean;
|
|
discordServerName: string;
|
|
matrixRequired: boolean;
|
|
matrixUserID: string;
|
|
userExpiryEnabled: boolean;
|
|
userExpiryMonths: number;
|
|
userExpiryDays: number;
|
|
userExpiryHours: number;
|
|
userExpiryMinutes: number;
|
|
userExpiryMessage: string;
|
|
emailRequired: boolean;
|
|
captcha: boolean;
|
|
reCAPTCHA: boolean;
|
|
reCAPTCHASiteKey: string;
|
|
userPageEnabled: boolean;
|
|
userPageAddress: string;
|
|
customSuccessCard: boolean;
|
|
}
|
|
|
|
loadLangSelector("form");
|
|
|
|
window.notifications = new notificationBox(document.getElementById("notification-box") as HTMLDivElement);
|
|
|
|
window.animationEvent = whichAnimationEvent();
|
|
|
|
window.successModal = new Modal(document.getElementById("modal-success"), true);
|
|
|
|
|
|
var telegramVerified = false;
|
|
if (window.telegramEnabled) {
|
|
window.telegramModal = new Modal(document.getElementById("modal-telegram"), window.telegramRequired);
|
|
const telegramButton = document.getElementById("link-telegram") as HTMLSpanElement;
|
|
|
|
const telegramConf: ServiceConfiguration = {
|
|
modal: window.telegramModal as Modal,
|
|
pin: window.telegramPIN,
|
|
pinURL: "",
|
|
verifiedURL: window.pages.Form + "/" + window.code + "/telegram/verified/",
|
|
invalidCodeError: window.messages["errorInvalidPIN"],
|
|
accountLinkedError: window.messages["errorAccountLinked"],
|
|
successError: window.messages["verified"],
|
|
successFunc: (modalClosed: boolean) => {
|
|
if (modalClosed) return;
|
|
telegramVerified = true;
|
|
telegramButton.classList.add("unfocused");
|
|
document.getElementById("contact-via").classList.remove("unfocused");
|
|
document.getElementById("contact-via-email").parentElement.classList.remove("unfocused");
|
|
const checkbox = document.getElementById("contact-via-telegram") as HTMLInputElement;
|
|
checkbox.parentElement.classList.remove("unfocused");
|
|
checkbox.checked = true;
|
|
validator.validate();
|
|
}
|
|
};
|
|
|
|
const telegram = new Telegram(telegramConf);
|
|
|
|
telegramButton.onclick = () => { telegram.onclick(); };
|
|
}
|
|
|
|
var discordVerified = false;
|
|
if (window.discordEnabled) {
|
|
window.discordModal = new Modal(document.getElementById("modal-discord"), window.discordRequired);
|
|
const discordButton = document.getElementById("link-discord") as HTMLSpanElement;
|
|
|
|
const discordConf: ServiceConfiguration = {
|
|
modal: window.discordModal as Modal,
|
|
pin: window.discordPIN,
|
|
inviteURL: window.discordInviteLink ? (window.pages.Form + "/" + window.code + "/discord/invite") : "",
|
|
pinURL: "",
|
|
verifiedURL: window.pages.Form + "/" + window.code + "/discord/verified/",
|
|
invalidCodeError: window.messages["errorInvalidPIN"],
|
|
accountLinkedError: window.messages["errorAccountLinked"],
|
|
successError: window.messages["verified"],
|
|
successFunc: (modalClosed: boolean) => {
|
|
if (modalClosed) return;
|
|
discordVerified = true;
|
|
discordButton.classList.add("unfocused");
|
|
document.getElementById("contact-via").classList.remove("unfocused");
|
|
document.getElementById("contact-via-email").parentElement.classList.remove("unfocused");
|
|
const checkbox = document.getElementById("contact-via-discord") as HTMLInputElement;
|
|
checkbox.parentElement.classList.remove("unfocused")
|
|
checkbox.checked = true;
|
|
validator.validate();
|
|
}
|
|
};
|
|
|
|
const discord = new Discord(discordConf);
|
|
|
|
discordButton.onclick = () => { discord.onclick(); };
|
|
}
|
|
|
|
var matrixVerified = false;
|
|
var matrixPIN = "";
|
|
if (window.matrixEnabled) {
|
|
window.matrixModal = new Modal(document.getElementById("modal-matrix"), window.matrixRequired);
|
|
const matrixButton = document.getElementById("link-matrix") as HTMLSpanElement;
|
|
|
|
const matrixConf: MatrixConfiguration = {
|
|
modal: window.matrixModal as Modal,
|
|
sendMessageURL: window.pages.Form + "/" + window.code + "/matrix/user",
|
|
verifiedURL: window.pages.Form + "/" + window.code + "/matrix/verified/",
|
|
invalidCodeError: window.messages["errorInvalidPIN"],
|
|
accountLinkedError: window.messages["errorAccountLinked"],
|
|
unknownError: window.messages["errorUnknown"],
|
|
successError: window.messages["verified"],
|
|
successFunc: () => {
|
|
matrixVerified = true;
|
|
matrixPIN = matrix.pin;
|
|
matrixButton.classList.add("unfocused");
|
|
document.getElementById("contact-via").classList.remove("unfocused");
|
|
document.getElementById("contact-via-email").parentElement.classList.remove("unfocused");
|
|
const checkbox = document.getElementById("contact-via-matrix") as HTMLInputElement;
|
|
checkbox.parentElement.classList.remove("unfocused");
|
|
checkbox.checked = true;
|
|
validator.validate();
|
|
}
|
|
};
|
|
|
|
const matrix = new Matrix(matrixConf);
|
|
|
|
matrixButton.onclick = () => { matrix.show(); };
|
|
}
|
|
|
|
if (window.confirmation) {
|
|
window.confirmationModal = new Modal(document.getElementById("modal-confirmation"), true);
|
|
}
|
|
declare var window: formWindow;
|
|
|
|
if (window.userExpiryEnabled) {
|
|
const messageEl = document.getElementById("user-expiry-message") as HTMLElement;
|
|
const calculateTime = () => {
|
|
let time = new Date()
|
|
time.setMonth(time.getMonth() + window.userExpiryMonths);
|
|
time.setDate(time.getDate() + window.userExpiryDays);
|
|
time.setHours(time.getHours() + window.userExpiryHours);
|
|
time.setMinutes(time.getMinutes() + window.userExpiryMinutes);
|
|
messageEl.textContent = window.userExpiryMessage.replace("{date}", toDateString(time));
|
|
setTimeout(calculateTime, 1000);
|
|
};
|
|
document.addEventListener("timefmt-change", calculateTime)
|
|
calculateTime();
|
|
}
|
|
|
|
const form = document.getElementById("form-create") as HTMLFormElement;
|
|
const submitInput = form.querySelector("input[type=submit]") as HTMLInputElement;
|
|
const submitSpan = form.querySelector("span.submit") as HTMLSpanElement;
|
|
const submitText = submitSpan.textContent;
|
|
let usernameField = document.getElementById("create-username") as HTMLInputElement;
|
|
const emailField = document.getElementById("create-email") as HTMLInputElement;
|
|
if (!window.usernameEnabled) { usernameField.parentElement.remove(); usernameField = emailField; }
|
|
const passwordField = document.getElementById("create-password") as HTMLInputElement;
|
|
const rePasswordField = document.getElementById("create-reenter-password") as HTMLInputElement;
|
|
|
|
let captcha = new Captcha(window.code, window.captcha, window.reCAPTCHA, false);
|
|
|
|
const clearSubmitButton = () => {
|
|
submitInput.setCustomValidity("");
|
|
submitSpan.title = "";
|
|
};
|
|
|
|
const invalidMessage = (el: HTMLInputElement, msg: string) => {
|
|
el.setCustomValidity(msg);
|
|
submitInput.setCustomValidity(msg);
|
|
submitSpan.title = msg;
|
|
};
|
|
|
|
function _baseValidator(oncomplete: (valid: boolean) => void, captchaValid: boolean): void {
|
|
clearSubmitButton();
|
|
if (window.emailRequired) {
|
|
if (!emailField.value.includes("@")) {
|
|
oncomplete(false);
|
|
return;
|
|
}
|
|
}
|
|
usernameField.setCustomValidity("");
|
|
// Jellyfin doesn't like having "+" in the username field
|
|
if (usernameField.value.includes("+")) {
|
|
invalidMessage(usernameField, window.messages["errorSpecialSymbols"]);
|
|
oncomplete(false);
|
|
return;
|
|
}
|
|
if (window.discordEnabled && window.discordRequired && !discordVerified) {
|
|
oncomplete(false);
|
|
return;
|
|
}
|
|
if (window.telegramEnabled && window.telegramRequired && !telegramVerified) {
|
|
oncomplete(false);
|
|
return;
|
|
}
|
|
if (window.matrixEnabled && window.matrixRequired && !matrixVerified) {
|
|
oncomplete(false);
|
|
return;
|
|
}
|
|
if (window.captcha && !window.reCAPTCHA && !captchaValid) {
|
|
oncomplete(false);
|
|
return;
|
|
}
|
|
oncomplete(true);
|
|
}
|
|
|
|
let baseValidator = captcha.baseValidatorWrapper(_baseValidator);
|
|
|
|
declare var grecaptcha: GreCAPTCHA;
|
|
|
|
let validatorConf: ValidatorConf = {
|
|
passwordField: passwordField,
|
|
rePasswordField: rePasswordField,
|
|
submitInput: submitInput,
|
|
submitButton: submitSpan,
|
|
validatorFunc: baseValidator
|
|
};
|
|
|
|
let validator = new Validator(validatorConf);
|
|
var requirements = validator.requirements;
|
|
|
|
if (window.emailRequired) {
|
|
emailField.addEventListener("keyup", validator.validate)
|
|
}
|
|
|
|
interface sendDTO {
|
|
code: string;
|
|
email: string;
|
|
email_contact?: boolean;
|
|
username: string;
|
|
password: string;
|
|
telegram_pin?: string;
|
|
telegram_contact?: boolean;
|
|
discord_pin?: string;
|
|
discord_contact?: boolean;
|
|
matrix_pin?: string;
|
|
matrix_contact?: boolean;
|
|
captcha_id?: string;
|
|
captcha_text?: string;
|
|
}
|
|
|
|
if (window.captcha && !window.reCAPTCHA) {
|
|
captcha.generate();
|
|
(document.getElementById("captcha-regen") as HTMLSpanElement).onclick = captcha.generate;
|
|
captcha.input.onkeyup = validator.validate;
|
|
}
|
|
|
|
const create = (event: SubmitEvent) => {
|
|
event.preventDefault();
|
|
if (window.captcha && !window.reCAPTCHA && !captcha.verified) {
|
|
|
|
}
|
|
addLoader(submitSpan);
|
|
let send: sendDTO = {
|
|
code: window.code,
|
|
username: usernameField.value,
|
|
email: emailField.value,
|
|
email_contact: true,
|
|
password: passwordField.value
|
|
}
|
|
if (telegramVerified) {
|
|
send.telegram_pin = window.telegramPIN;
|
|
const checkbox = document.getElementById("contact-via-telegram") as HTMLInputElement;
|
|
if (checkbox.checked) {
|
|
send.telegram_contact = true;
|
|
}
|
|
}
|
|
if (discordVerified) {
|
|
send.discord_pin = window.discordPIN;
|
|
const checkbox = document.getElementById("contact-via-discord") as HTMLInputElement;
|
|
if (checkbox.checked) {
|
|
send.discord_contact = true;
|
|
}
|
|
}
|
|
if (matrixVerified) {
|
|
send.matrix_pin = matrixPIN;
|
|
const checkbox = document.getElementById("contact-via-matrix") as HTMLInputElement;
|
|
if (checkbox.checked) {
|
|
send.matrix_contact = true;
|
|
}
|
|
}
|
|
if (matrixVerified || discordVerified || telegramVerified) {
|
|
const checkbox = document.getElementById("contact-via-email") as HTMLInputElement;
|
|
send.email_contact = checkbox.checked;
|
|
}
|
|
if (window.captcha) {
|
|
if (window.reCAPTCHA) {
|
|
send.captcha_text = grecaptcha.getResponse();
|
|
} else {
|
|
send.captcha_id = captcha.captchaID;
|
|
send.captcha_text = captcha.input.value;
|
|
}
|
|
}
|
|
_post("/user/invite", send, (req: XMLHttpRequest) => {
|
|
if (req.readyState != 4) return;
|
|
removeLoader(submitSpan);
|
|
let vals = req.response as ValidatorRespDTO;
|
|
let valid = true;
|
|
for (let type in vals) {
|
|
if (requirements[type]) requirements[type].valid = vals[type];
|
|
if (!vals[type]) valid = false;
|
|
}
|
|
if (req.status == 200 && valid) {
|
|
if (window.redirectToJellyfin == true) {
|
|
const url = ((document.getElementById("modal-success") as HTMLDivElement).querySelector("a.submit") as HTMLAnchorElement).href;
|
|
window.location.href = url;
|
|
} else {
|
|
if (window.customSuccessCard) {
|
|
const content = window.successModal.asElement().querySelector(".card");
|
|
content.innerHTML = content.innerHTML.replace(new RegExp("{username}", "g"), send.username)
|
|
} else if (window.userPageEnabled) {
|
|
const userPageNoticeArea = document.getElementById("modal-success-user-page-area");
|
|
const link = `<a href="${window.userPageAddress}" target="_blank">${userPageNoticeArea.getAttribute("my-account-term")}</a>`;
|
|
userPageNoticeArea.innerHTML = userPageNoticeArea.textContent.replace("{myAccount}", link);
|
|
}
|
|
window.successModal.show();
|
|
}
|
|
} else if (req.status != 401 && req.status != 400){
|
|
submitSpan.classList.add("~critical");
|
|
submitSpan.classList.remove("~urge");
|
|
if (req.response["error"] as string) {
|
|
submitSpan.textContent = window.messages[req.response["error"]];
|
|
} else {
|
|
submitSpan.textContent = window.messages["errorPassword"];
|
|
}
|
|
setTimeout(() => {
|
|
submitSpan.classList.add("~urge");
|
|
submitSpan.classList.remove("~critical");
|
|
submitSpan.textContent = submitText;
|
|
}, 1000);
|
|
}
|
|
}, true, (req: XMLHttpRequest) => {
|
|
if (req.readyState != 4) return;
|
|
removeLoader(submitSpan);
|
|
if (req.status == 401 || req.status == 400) {
|
|
if (req.response["error"] as string) {
|
|
if (req.response["error"] == "confirmEmail") {
|
|
window.confirmationModal.show();
|
|
return;
|
|
}
|
|
if (req.response["error"] in window.messages) {
|
|
submitSpan.textContent = window.messages[req.response["error"]];
|
|
} else {
|
|
submitSpan.textContent = req.response["error"];
|
|
}
|
|
setTimeout(() => { submitSpan.textContent = submitText; }, 1000);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
validator.validate();
|
|
|
|
form.onsubmit = create;
|
|
|
|
const invitedByAside = document.getElementById("invite-from-user");
|
|
if (typeof(invitedByAside) != "undefined" && invitedByAside != null) {
|
|
invitedByAside.textContent = invitedByAside.textContent.replace("{user}", invitedByAside.getAttribute("data-from"));
|
|
}
|