import cloneDeep from "lodash/cloneDeep"; import { type App, Modal, Notice, Setting } from "obsidian"; import { features } from "process"; import type { TransItemType } from "../../src/i18n"; import type RemotelySavePlugin from "../../src/main"; import { stringToFragment } from "../../src/misc"; import { DEFAULT_PRO_CONFIG, generateAuthUrlAndCodeVerifierChallenge, getAndSaveProEmail, getAndSaveProFeatures, sendAuthReq, setConfigBySuccessfullAuthInplace, } from "./account"; import { type FeatureInfo, PRO_CLIENT_ID, type ProConfig, } from "./baseTypesPro"; export class ProAuthModal extends Modal { readonly plugin: RemotelySavePlugin; readonly authDiv: HTMLDivElement; readonly revokeAuthDiv: HTMLDivElement; readonly revokeAuthSetting: Setting; readonly proFeaturesListSetting: Setting; readonly t: (x: TransItemType, vars?: any) => string; constructor( app: App, plugin: RemotelySavePlugin, authDiv: HTMLDivElement, revokeAuthDiv: HTMLDivElement, revokeAuthSetting: Setting, proFeaturesListSetting: Setting, t: (x: TransItemType, vars?: any) => string ) { super(app); this.plugin = plugin; this.authDiv = authDiv; this.revokeAuthDiv = revokeAuthDiv; this.revokeAuthSetting = revokeAuthSetting; this.proFeaturesListSetting = proFeaturesListSetting; this.t = t; } async onOpen() { const { contentEl } = this; const { authUrl, codeVerifier, codeChallenge } = await generateAuthUrlAndCodeVerifierChallenge(false); this.plugin.oauth2Info.verifier = codeVerifier; const t = this.t; const div2 = contentEl.createDiv(); div2.createEl( "button", { text: t("modal_proauth_copybutton"), }, (el) => { el.onclick = async () => { await navigator.clipboard.writeText(authUrl); new Notice(t("modal_proauth_copynotice")); }; } ); contentEl.createEl("p").createEl("a", { href: authUrl, text: authUrl, }); // manual paste let authCode = ""; new Setting(contentEl) .setName(t("modal_proauth_maualinput")) .setDesc(t("modal_proauth_maualinput_desc")) .addText((text) => text .setPlaceholder("") .setValue("") .onChange((val) => { authCode = val.trim(); }) ) .addButton(async (button) => { button.setButtonText(t("submit")); button.onClick(async () => { new Notice(t("modal_proauth_maualinput_notice")); try { const authRes = await sendAuthReq( codeVerifier ?? "verifier", authCode, async (e: any) => { new Notice(t("protocol_pro_connect_fail")); new Notice(`${e}`); throw e; } ); console.debug(authRes); const self = this; setConfigBySuccessfullAuthInplace( this.plugin.settings.pro!, authRes!, () => self.plugin.saveSettings() ); await getAndSaveProFeatures( this.plugin.settings.pro!, this.plugin.manifest.version, () => self.plugin.saveSettings() ); this.proFeaturesListSetting.setDesc( stringToFragment( t("settings_pro_features_desc", { features: featureListToText( this.plugin.settings.pro!.enabledProFeatures ), }) ) ); await getAndSaveProEmail( this.plugin.settings.pro!, this.plugin.manifest.version, () => self.plugin.saveSettings() ); new Notice( t("protocol_pro_connect_manualinput_succ", { email: this.plugin.settings.pro!.email ?? "(no email)", }) ); this.plugin.oauth2Info.verifier = ""; // reset it this.plugin.oauth2Info.authDiv?.toggleClass( "pro-auth-button-hide", this.plugin.settings.pro?.refreshToken !== "" ); this.plugin.oauth2Info.authDiv = undefined; this.plugin.oauth2Info.revokeAuthSetting?.setDesc( t("protocol_pro_connect_succ_revoke", { email: this.plugin.settings.pro?.email, }) ); this.plugin.oauth2Info.revokeAuthSetting = undefined; this.plugin.oauth2Info.revokeDiv?.toggleClass( "pro-revoke-auth-button-hide", this.plugin.settings.pro?.email === "" ); this.plugin.oauth2Info.revokeDiv = undefined; // try to remove data in clipboard await navigator.clipboard.writeText(""); this.close(); } catch (err) { console.error(err); new Notice(t("modal_proauth_maualinput_conn_fail")); } }); }); } onClose() { const { contentEl } = this; contentEl.empty(); } } export class ProRevokeAuthModal extends Modal { readonly plugin: RemotelySavePlugin; readonly authDiv: HTMLDivElement; readonly revokeAuthDiv: HTMLDivElement; readonly t: (x: TransItemType, vars?: any) => string; constructor( app: App, plugin: RemotelySavePlugin, authDiv: HTMLDivElement, revokeAuthDiv: HTMLDivElement, t: (x: TransItemType, vars?: any) => string ) { super(app); this.plugin = plugin; this.authDiv = authDiv; this.revokeAuthDiv = revokeAuthDiv; this.t = t; } async onOpen() { const { contentEl } = this; const t = this.t; contentEl.createEl("p", { text: t("modal_prorevokeauth"), }); new Setting(contentEl) .setName(t("modal_prorevokeauth_clean")) .setDesc(t("modal_prorevokeauth_clean_desc")) .addButton(async (button) => { button.setButtonText(t("modal_prorevokeauth_clean_button")); button.onClick(async () => { try { this.plugin.settings.pro = cloneDeep(DEFAULT_PRO_CONFIG); await this.plugin.saveSettings(); this.authDiv.toggleClass( "pro-auth-button-hide", this.plugin.settings.pro?.refreshToken !== "" ); this.revokeAuthDiv.toggleClass( "pro-revoke-auth-button-hide", this.plugin.settings.pro?.refreshToken === "" ); new Notice(t("modal_prorevokeauth_clean_notice")); this.close(); } catch (err) { console.error(err); new Notice(t("modal_prorevokeauth_clean_fail")); } }); }); } onClose() { const { contentEl } = this; contentEl.empty(); } } const featureListToText = (features: FeatureInfo[]) => { // TODO: i18n if (features === undefined || features.length === 0) { return "No features enabled."; } return features .map((x) => { return `${x.featureName} (expire: ${new Date( Number(x.expireAtTimeMs) ).toISOString()})`; }) .join("
"); }; export const generateProSettingsPart = ( proDiv: HTMLDivElement, t: (x: TransItemType, vars?: any) => string, app: App, plugin: RemotelySavePlugin, saveUpdatedConfigFunc: () => Promise | undefined, googleDriveAllowedToUsedDiv: HTMLDivElement, googleDriveNotShowUpHintSetting: Setting, boxAllowedToUsedDiv: HTMLDivElement, boxNotShowUpHintSetting: Setting, pCloudAllowedToUsedDiv: HTMLDivElement, pCloudNotShowUpHintSetting: Setting ) => { proDiv .createEl("h2", { text: t("settings_pro") }) .setAttribute("id", "settings-pro"); proDiv.createEl("div", { text: stringToFragment(t("settings_pro_tutorial")), }); const proSelectAuthDiv = proDiv.createDiv(); const proAuthDiv = proSelectAuthDiv.createDiv({ cls: "pro-auth-button-hide settings-auth-related", }); const proRevokeAuthDiv = proSelectAuthDiv.createDiv({ cls: "pro-revoke-auth-button-hide settings-auth-related", }); const proFeaturesListSetting = new Setting(proRevokeAuthDiv) .setName(t("settings_pro_features")) .setDesc( stringToFragment( t("settings_pro_features_desc", { features: featureListToText(plugin.settings.pro!.enabledProFeatures), }) ) ); proFeaturesListSetting.addButton(async (button) => { button.setButtonText(t("settings_pro_features_refresh_button")); button.onClick(async () => { new Notice(t("settings_pro_features_refresh_fetch")); await getAndSaveProFeatures( plugin.settings.pro!, plugin.manifest.version, saveUpdatedConfigFunc ); proFeaturesListSetting.setDesc( stringToFragment( t("settings_pro_features_desc", { features: featureListToText( plugin.settings.pro!.enabledProFeatures ), }) ) ); const allowGoogleDrive = plugin.settings.pro?.enabledProFeatures.filter( (x) => x.featureName === "feature-google_drive" ).length === 1; console.debug( `allow to show up google drive settings? ${allowGoogleDrive}` ); if (allowGoogleDrive) { googleDriveAllowedToUsedDiv.removeClass( "googledrive-allow-to-use-hide" ); googleDriveNotShowUpHintSetting.settingEl.addClass( "googledrive-allow-to-use-hide" ); } else { googleDriveAllowedToUsedDiv.addClass("googledrive-allow-to-use-hide"); googleDriveNotShowUpHintSetting.settingEl.removeClass( "googledrive-allow-to-use-hide" ); } const allowBox = plugin.settings.pro?.enabledProFeatures.filter( (x) => x.featureName === "feature-box" ).length === 1; console.debug(`allow to show up Box settings? ${allowBox}`); if (allowBox) { boxAllowedToUsedDiv.removeClass("box-allow-to-use-hide"); boxNotShowUpHintSetting.settingEl.addClass("box-allow-to-use-hide"); } else { boxAllowedToUsedDiv.addClass("box-allow-to-use-hide"); boxNotShowUpHintSetting.settingEl.removeClass("box-allow-to-use-hide"); } const allowPCloud = plugin.settings.pro?.enabledProFeatures.filter( (x) => x.featureName === "feature-pcloud" ).length === 1; console.debug(`allow to show up pCloud settings? ${allowPCloud}`); if (allowPCloud) { pCloudAllowedToUsedDiv.removeClass("pcloud-allow-to-use-hide"); pCloudNotShowUpHintSetting.settingEl.addClass( "pcloud-allow-to-use-hide" ); } else { pCloudAllowedToUsedDiv.addClass("pcloud-allow-to-use-hide"); pCloudNotShowUpHintSetting.settingEl.removeClass( "pcloud-allow-to-use-hide" ); } new Notice(t("settings_pro_features_refresh_succ")); }); }); const proRevokeAuthSetting = new Setting(proRevokeAuthDiv) .setName(t("settings_pro_revoke")) .setDesc( t("settings_pro_revoke_desc", { email: plugin.settings.pro?.email, }) ) .addButton(async (button) => { button.setButtonText(t("settings_pro_revoke_button")); button.onClick(async () => { new ProRevokeAuthModal( app, plugin, proAuthDiv, proRevokeAuthDiv, t ).open(); }); }); new Setting(proAuthDiv) .setName(t("settings_pro_intro")) .setDesc(stringToFragment(t("settings_pro_intro_desc"))) .addButton(async (button) => { button.setButtonText(t("settings_pro_intro_button")); button.onClick(async () => { window.open("https://remotelysave.com/user/signupin", "_self"); }); }); new Setting(proAuthDiv) .setName(t("settings_pro_auth")) .setDesc(t("settings_pro_auth_desc")) .addButton(async (button) => { button.setButtonText(t("settings_pro_auth_button")); button.onClick(async () => { const modal = new ProAuthModal( app, plugin, proAuthDiv, proRevokeAuthDiv, proRevokeAuthSetting, proFeaturesListSetting, t ); plugin.oauth2Info.helperModal = modal; plugin.oauth2Info.authDiv = proAuthDiv; plugin.oauth2Info.revokeDiv = proRevokeAuthDiv; plugin.oauth2Info.revokeAuthSetting = proRevokeAuthSetting; modal.open(); }); }); proAuthDiv.toggleClass( "pro-auth-button-hide", plugin.settings.pro?.refreshToken !== "" ); proRevokeAuthDiv.toggleClass( "pro-revoke-auth-button-hide", plugin.settings.pro?.refreshToken === "" ); };