import { Modal } from "../modules/modal.js"; import { _get, _post, toggleLoader, addLoader, removeLoader } from "../modules/common.js"; interface formWindow extends Window { 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; } declare var window: formWindow; export interface ServiceConfiguration { modal: Modal; pin: string; inviteURL?: string; pinURL: string; verifiedURL: string; invalidCodeError: string; accountLinkedError: string; successError: string; successFunc: (modalClosed: boolean) => void; }; export interface DiscordInvite { invite: string; icon: string; } export class ServiceLinker { protected _conf: ServiceConfiguration; protected _pinAcquired = false; protected _modalClosed = false; protected _waiting: HTMLSpanElement; protected _verified = false; protected _name: string; get verified(): boolean { return this._verified; } constructor(conf: ServiceConfiguration) { this._conf = conf; this._conf.modal.onclose = () => { this._modalClosed = true; toggleLoader(this._waiting); }; } protected _checkVerified = () => { if (this._modalClosed) return; if (!this._pinAcquired) { setTimeout(this._checkVerified, 1500); return; } _get(this._conf.verifiedURL + this._conf.pin, null, (req: XMLHttpRequest) => { if (req.readyState != 4) return; if (req.status == 401) { this._conf.modal.close(); window.notifications.customError("invalidCodeError", this._conf.invalidCodeError); } else if (req.status == 400) { this._conf.modal.close(); window.notifications.customError("accountLinkedError", this._conf.accountLinkedError); } else if (req.status == 200) { if (req.response["success"] as boolean) { this._verified = true; this._waiting.classList.add("~positive"); this._waiting.classList.remove("~info"); window.notifications.customPositive(this._name + "Verified", "", this._conf.successError); if (this._conf.successFunc) { this._conf.successFunc(false); } setTimeout(() => { this._conf.modal.close(); if (this._conf.successFunc) { this._conf.successFunc(true); } }, 2000); } else if (!this._modalClosed) { setTimeout(this._checkVerified, 1500); } } }); }; onclick() { toggleLoader(this._waiting); this._pinAcquired = false; if (this._conf.pin) { this._pinAcquired = true; this._conf.modal.modal.querySelector(".pin").textContent = this._conf.pin; } else if (this._conf.pinURL) { _get(this._conf.pinURL, null, (req: XMLHttpRequest) => { if (req.readyState == 4 && req.status == 200) { this._conf.pin = req.response["pin"]; this._conf.modal.modal.querySelector(".pin").textContent = this._conf.pin; this._pinAcquired = true; } }); } this._modalClosed = false; this._conf.modal.show(); this._checkVerified(); } } export class Discord extends ServiceLinker { constructor(conf: ServiceConfiguration) { super(conf); this._name = "discord"; this._waiting = document.getElementById("discord-waiting") as HTMLSpanElement; } private _getInviteURL = () => _get(this._conf.inviteURL, null, (req: XMLHttpRequest) => { if (req.readyState != 4) return; const inv = req.response as DiscordInvite; const link = document.getElementById("discord-invite") as HTMLSpanElement; (link.parentElement as HTMLAnchorElement).href = inv.invite; (link.parentElement as HTMLAnchorElement).target = "_blank"; let innerHTML = ``; if (inv.icon != "") { innerHTML += `${window.discordServerName}`; } else { innerHTML += ` ${window.discordServerName} `; } link.innerHTML = innerHTML; }); onclick() { if (this._conf.inviteURL != "") { this._getInviteURL(); } super.onclick(); } } export class Telegram extends ServiceLinker { constructor(conf: ServiceConfiguration) { super(conf); this._name = "telegram"; this._waiting = document.getElementById("telegram-waiting") as HTMLSpanElement; } }; export interface MatrixConfiguration { modal: Modal; sendMessageURL: string; verifiedURL: string; invalidCodeError: string; accountLinkedError: string; unknownError: string; successError: string; successFunc: () => void; } export class Matrix { private _conf: MatrixConfiguration; private _verified = false; private _name: string = "matrix"; private _userID: string = ""; private _pin: string = ""; private _input: HTMLInputElement; private _submit: HTMLSpanElement; get verified(): boolean { return this._verified; } get pin(): string { return this._pin; } constructor(conf: MatrixConfiguration) { this._conf = conf; this._input = document.getElementById("matrix-userid") as HTMLInputElement; this._submit = document.getElementById("matrix-send") as HTMLSpanElement; this._submit.onclick = () => { this._onclick(); }; } private _onclick = () => { addLoader(this._submit); if (this._userID == "") { this._sendMessage(); } else { this._verifyCode(); } }; show = () => { this._input.value = ""; this._conf.modal.show(); } private _sendMessage = () => _post(this._conf.sendMessageURL, { "user_id": this._input.value }, (req: XMLHttpRequest) => { if (req.readyState != 4) return; removeLoader(this._submit); if (req.status == 400 && req.response["error"] == "errorAccountLinked") { this._conf.modal.close(); window.notifications.customError("accountLinkedError", this._conf.accountLinkedError); return; } else if (req.status != 200) { this._conf.modal.close(); window.notifications.customError("unknownError", this._conf.unknownError); return; } this._userID = this._input.value; this._submit.classList.add("~positive"); this._submit.classList.remove("~info"); setTimeout(() => { this._submit.classList.add("~info"); this._submit.classList.remove("~positive"); }, 2000); this._input.placeholder = "PIN"; this._input.value = ""; }); private _verifyCode = () => _post(this._conf.verifiedURL + this._userID + "/" + this._input.value, null, (req: XMLHttpRequest) => { if (req.readyState != 4) return; removeLoader(this._submit); const valid = req.response["success"] as boolean; if (valid) { this._conf.modal.close(); window.notifications.customPositive(this._name + "Verified", "", this._conf.successError); this._verified = true; this._pin = this._input.value; if (this._conf.successFunc) { this._conf.successFunc(); } } else { window.notifications.customError("invalidCodeError", this._conf.invalidCodeError); this._submit.classList.add("~critical"); this._submit.classList.remove("~info"); setTimeout(() => { this._submit.classList.add("~info"); this._submit.classList.remove("~critical"); }, 800); } }, true); }