|
|
|
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;
|
|
|
|
protected _pin: 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._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;
|
|
|
|
this._pin = "";
|
|
|
|
if (this._conf.pin) {
|
|
|
|
this._pinAcquired = true;
|
|
|
|
this._pin = this._conf.pin;
|
|
|
|
this._conf.modal.modal.querySelector(".pin").textContent = this._pin;
|
|
|
|
} else if (this._conf.pinURL) {
|
|
|
|
_get(this._conf.pinURL, null, (req: XMLHttpRequest) => {
|
|
|
|
if (req.readyState == 4 && req.status == 200) {
|
|
|
|
this._pin = req.response["pin"];
|
|
|
|
this._conf.modal.modal.querySelector(".pin").textContent = this._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 += `<span class="img-circle lg mr-4"><img class="img-circle" src="${inv.icon}" width="64" height="64"></span>${window.discordServerName}`;
|
|
|
|
} else {
|
|
|
|
innerHTML += `
|
|
|
|
<span class="shield mr-4 bg-discord"><i class="ri-discord-fill ri-xl text-white"></i></span>${window.discordServerName}
|
|
|
|
`;
|
|
|
|
}
|
|
|
|
link.innerHTML = innerHTML;
|
|
|
|
});
|
|
|
|
|
|
|
|
onclick() {
|
|
|
|
if (this._conf.inviteURL != "") {
|
|
|
|
this._getInviteURL();
|
|
|
|
} else {
|
|
|
|
(document.getElementById("discord-invite") as HTMLSpanElement).parentElement.remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
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 = () => _get(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);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|