aboutsummaryrefslogtreecommitdiff
path: root/src/PrisbeamDerpibooru.ts
diff options
context:
space:
mode:
authorRaindropsSys <raindrops@equestria.dev>2024-06-13 15:46:03 +0200
committerRaindropsSys <raindrops@equestria.dev>2024-06-13 15:46:03 +0200
commite44e2fe070484e06d384a31ef2699c3a2d5d474e (patch)
tree2d5eb5d1b01646270d18cf1f2d94519966d6e7de /src/PrisbeamDerpibooru.ts
downloadfaunerie-e44e2fe070484e06d384a31ef2699c3a2d5d474e.tar.gz
faunerie-e44e2fe070484e06d384a31ef2699c3a2d5d474e.tar.bz2
faunerie-e44e2fe070484e06d384a31ef2699c3a2d5d474e.zip
GitHub migration
Diffstat (limited to 'src/PrisbeamDerpibooru.ts')
-rwxr-xr-xsrc/PrisbeamDerpibooru.ts293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/PrisbeamDerpibooru.ts b/src/PrisbeamDerpibooru.ts
new file mode 100755
index 0000000..0680f13
--- /dev/null
+++ b/src/PrisbeamDerpibooru.ts
@@ -0,0 +1,293 @@
+import {PrisbeamApp} from "./PrisbeamApp";
+import {BrowserWindow, shell} from "@electron/remote";
+import {BrowserWindow as TBrowserWindow, SafeStorage} from "electron";
+
+interface DerpibooruJSDataStore {
+ fancyTagEdit: boolean;
+ fancyTagUpload: boolean;
+ filterId: number;
+ hiddenFilter: string;
+ hiddenTagList: number[];
+ ignoredTagList: number[];
+ interactions: any[];
+ spoilerType: string;
+ spoileredFilter: string;
+ spoileredTagList: number[];
+ userCanEditFilter: boolean;
+ userIsSignedIn: boolean;
+ watchedTagList: number[];
+}
+
+export class PrisbeamDerpibooru {
+ instance: PrisbeamApp;
+ enabled: boolean;
+ window: TBrowserWindow;
+ dataStore: DerpibooruJSDataStore;
+
+ constructor(instance: PrisbeamApp) {
+ this.instance = instance;
+ this.enabled = null;
+ }
+
+ async getDataStore() {
+ if (await this.window.webContents.executeJavaScript("!!document.getElementsByClassName(\"js-datastore\")[0]")) {
+ let attributes = await this.window.webContents.executeJavaScript("document.getElementsByClassName(\"js-datastore\")[0].getAttributeNames().filter(i => i.startsWith(\"data\"))");
+ let obj = {};
+
+ for (let name of attributes) {
+ let data = await this.window.webContents.executeJavaScript("document.getElementsByClassName(\"js-datastore\")[0].getAttribute(\"" + name + "\")");
+
+ name = name.substring(5).toLowerCase().replace(/-(.)/g, function(_: string, g: string) {
+ return g.toUpperCase();
+ });
+
+ try {
+ obj[name] = JSON.parse(data);
+ } catch (e) {
+ obj[name] = data;
+ }
+ }
+
+ return obj;
+ } else {
+ return {};
+ }
+ }
+
+ startLoginFlow() {
+ (document.getElementById("derpibooru-email") as HTMLInputElement).value = "";
+ (document.getElementById("derpibooru-password") as HTMLInputElement).value = "";
+ (document.getElementById("derpibooru-2fa") as HTMLInputElement).value = "";
+ document.getElementById("derpibooru-login-2fa").style.display = "none";
+ document.getElementById("derpibooru-login-initial").style.display = "";
+
+ this.setFormLock(false);
+ this.instance.dataStore.login.show();
+ }
+
+ validateEmail(email: string) {
+ return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+ .test(email.toLowerCase());
+ }
+
+ validateCredentials(email: string, password: string) {
+ if (email.trim() === "") {
+ alert("Please enter an email address.");
+ document.getElementById("derpibooru-email").focus();
+ return false;
+ }
+
+ if (password.trim() === "") {
+ alert("Please enter a password.");
+ document.getElementById("derpibooru-password").focus();
+ return false;
+ }
+
+ if (!this.validateEmail(email)) {
+ alert("Please enter a valid email address.");
+ document.getElementById("derpibooru-email").focus();
+ return false;
+ }
+
+ if (password.length < 12) {
+ alert("Your password must be at least 12 characters.");
+ document.getElementById("derpibooru-password").focus();
+ return false;
+ }
+
+ return true;
+ }
+
+ setFormLock(lock: boolean) {
+ document.getElementById("login").style['pointerEvents'] = lock ? "none" : "";
+ (document.getElementById("derpibooru-email") as HTMLInputElement).disabled = lock;
+ (document.getElementById("derpibooru-password") as HTMLInputElement).disabled = lock;
+ (document.getElementById("derpibooru-2fa") as HTMLInputElement).disabled = lock;
+ document.getElementById("derpibooru-confirm-btn").classList[lock ? "add" : "remove"]("disabled");
+ document.getElementById("derpibooru-confirm-btn2").classList[lock ? "add" : "remove"]("disabled");
+ }
+
+ async handleLoginPage(email?: string, password?: string) {
+ if (this.window.webContents.getURL().endsWith("/sessions/new") ||
+ this.window.webContents.getURL().endsWith("/sessions/new/") ||
+ this.window.webContents.getURL().endsWith("/sessions") ||
+ this.window.webContents.getURL().endsWith("/sessions/")) {
+ await this.requestCredentials(email, password);
+ } else if (this.window.webContents.getURL().endsWith("/sessions/totp/new") || this.window.webContents.getURL().endsWith("/sessions/totp/new/")) {
+ await this.request2fa();
+ } else {
+ await this.regularLoginItem();
+ }
+ }
+
+ async requestCredentials(email?: string, password?: string) {
+ let msg = await this.window.webContents.executeJavaScript('document.querySelector(".alert.alert-danger")?.innerText');
+
+ if (msg) {
+ alert(msg);
+ this.setFormLock(false);
+ document.getElementById("derpibooru-email").focus();
+ } else {
+ this.window.webContents.once("did-stop-loading", () => this.handleLoginPage(email, password));
+
+ await this.window.webContents.executeJavaScript("document.getElementById('user_email').value = \"" + email.trim().replaceAll('\\', '\\\\').replaceAll('"', '\\"') + "\";");
+ await this.window.webContents.executeJavaScript("document.getElementById('user_password').value = \"" + password.trim().replaceAll('\\', '\\\\').replaceAll('"', '\\"') + "\";");
+ await this.window.webContents.executeJavaScript("document.getElementById('user_remember_me').checked = true;");
+ await this.window.webContents.executeJavaScript('document.querySelector("[action=\\"/sessions\\"] [type=\\"submit\\"]").click();');
+ }
+ }
+
+ async request2fa() {
+ document.getElementById("derpibooru-login-2fa").style.display = "";
+ document.getElementById("derpibooru-login-initial").style.display = "none";
+ document.getElementById("derpibooru-2fa").focus();
+ this.setFormLock(false);
+ }
+
+ async loadUserData() {
+ if (!this.dataStore.userIsSignedIn) {
+ document.getElementById("derpibooru-login-btn").classList.remove("disabled");
+ document.getElementById("derpibooru-login").style.display = "";
+ Array.from(document.getElementsByClassName("derpibooru-when-logged-in"))
+ .map((i: HTMLElement) => i.style.display = "none");
+ } else {
+ document.getElementById("derpibooru-login-btn").classList.add("disabled");
+ document.getElementById("derpibooru-login").style.display = "none";
+ Array.from(document.getElementsByClassName("derpibooru-when-logged-in"))
+ .map((i: HTMLElement) => i.style.display = "");
+
+ let avatar = await this.window.webContents
+ .executeJavaScript('document.querySelector("[src^=\\"https://derpicdn.net/avatars/\\"]").src');
+ await this.instance.propertyStore.setItem("pba_derpibooru_avatar", avatar);
+ (document.getElementById("avatar") as HTMLImageElement).src = avatar;
+
+ this.window.webContents.on('did-stop-loading', async () => {
+ let apiKey = await this.window.webContents.executeJavaScript('document.getElementById("api-key").innerText.trim();');
+ let apiKeyToStore = apiKey;
+ let safeStorage: SafeStorage = require('@electron/remote').safeStorage;
+
+ if (safeStorage.isEncryptionAvailable()) {
+ apiKeyToStore = safeStorage.encryptString(apiKey).toString("base64");
+ }
+
+ await this.instance.propertyStore.setItem("pba_derpibooru_key_encrypted", apiKeyToStore);
+
+ let userName = await this.window.webContents.executeJavaScript('document.querySelector("[class=\\"header__link\\"][href^=\\"/profiles/\\"]").innerText');
+ await this.instance.propertyStore.setItem("pba_derpibooru_user_name", userName);
+ document.getElementById("user-name").innerText = "Logged in as: " + userName;
+ });
+
+ await this.window.loadURL("https://derpibooru.org/registrations/edit");
+ }
+ }
+
+ openManager() {
+ shell.openExternal("https://derpibooru.org/registrations/edit");
+ }
+
+ async logOut() {
+ if (confirm("Are you sure you want to log out from Derpibooru? Any features using Derpibooru will stop working and your Derpibooru user data will be removed from Prisbeam.")) {
+ await this.instance.propertyStore.removeItem("pba_derpibooru_user_name");
+ await this.instance.propertyStore.removeItem("pba_derpibooru_key_encrypted");
+ await this.instance.propertyStore.removeItem("pba_derpibooru_avatar");
+ await this.window.webContents.executeJavaScript('document.querySelector("[data-method=\\"delete\\"][href=\\"/sessions\\"]").click();');
+ location.reload();
+ }
+ }
+
+ async regularLoginItem() {
+ if ((await this.getDataStore() as DerpibooruJSDataStore).userIsSignedIn) {
+ this.setFormLock(false);
+ this.instance.dataStore.login.hide();
+ location.reload();
+ } else {
+ if (document.getElementById("derpibooru-login-2fa").style.display !== "none") {
+ alert("An invalid two-factor authentication code was entered. Please try again.");
+ (document.getElementById("derpibooru-2fa") as HTMLInputElement).value = "";
+ (document.getElementById("derpibooru-email") as HTMLInputElement).value = "";
+ (document.getElementById("derpibooru-password") as HTMLInputElement).value = "";
+ this.setFormLock(false);
+ }
+
+ document.getElementById("derpibooru-login-2fa").style.display = "none";
+ document.getElementById("derpibooru-login-initial").style.display = "";
+ }
+ }
+
+ submitLogin() {
+ let email = (document.getElementById("derpibooru-email") as HTMLInputElement).value;
+ let password = (document.getElementById("derpibooru-password") as HTMLInputElement).value;
+ if (!this.validateCredentials(email, password)) return;
+
+ this.setFormLock(true);
+ this.window.webContents.once("did-stop-loading", () => this.handleLoginPage(email, password));
+
+ this.window.loadURL("https://derpibooru.org/sessions/new");
+ }
+
+ async submit2fa() {
+ let mfa = parseInt((document.getElementById("derpibooru-2fa") as HTMLInputElement).value).toString();
+ if (mfa.length !== 6) {
+ alert("A two-factor authentication code contains 6 digits, but you entered " + mfa.length + ".");
+ document.getElementById("derpibooru-2fa").focus();
+ return;
+ }
+
+ this.setFormLock(true);
+ this.window.webContents.once("did-stop-loading", () => this.handleLoginPage(null, null));
+ await this.window.webContents.executeJavaScript("document.getElementById('user_twofactor_token').value = \"" + mfa.trim().replaceAll('\\', '\\\\').replaceAll('"', '\\"') + "\";");
+ await this.window.webContents.executeJavaScript("document.getElementById('user_remember_me').checked = true;");
+ await this.window.webContents.executeJavaScript('document.querySelector("[action=\\"/sessions/totp\\"] [type=\\"submit\\"]").click();');
+ }
+
+ initialize() {
+ document.getElementById("login").addEventListener("shown.bs.modal", () => {
+ if (this.window.webContents.getURL().endsWith("/sessions/totp/new") || this.window.webContents.getURL().endsWith("/sessions/totp/new/")) {
+ document.getElementById("derpibooru-login-2fa").style.display = "";
+ document.getElementById("derpibooru-login-initial").style.display = "none";
+ document.getElementById("derpibooru-2fa").focus();
+ } else {
+ document.getElementById("derpibooru-login-2fa").style.display = "none";
+ document.getElementById("derpibooru-login-initial").style.display = "";
+ document.getElementById("derpibooru-email").focus();
+ }
+ });
+
+ document.getElementById("derpibooru-email").onkeydown = document.getElementById("derpibooru-password").onkeydown = (event) => {
+ if (event.key === "Enter") {
+ this.submitLogin();
+ }
+ }
+
+ document.getElementById("derpibooru-2fa").onkeydown = (event) => {
+ if (event.key === "Enter") {
+ this.submit2fa();
+ }
+ }
+
+ document.getElementById("avatar").onerror = () => {
+ (document.getElementById("avatar") as HTMLImageElement).src = "../logo/placeholder.jpg";
+ }
+
+ return new Promise<void>(async (res) => {
+ this.enabled = false;
+
+ this.window = new BrowserWindow({
+ show: false
+ });
+
+ await this.window.loadURL("https://derpibooru.org");
+
+ this.dataStore = await this.getDataStore() as DerpibooruJSDataStore;
+ await this.loadUserData();
+ this.enabled = true;
+
+ this.window.webContents.on('did-stop-loading', async () => {
+ this.dataStore = await this.getDataStore() as DerpibooruJSDataStore;
+ if (!this.dataStore.userIsSignedIn) await this.loadUserData();
+ });
+
+ res();
+ })
+ }
+}