diff --git a/src/LiveTokenStore.ts b/src/LiveTokenStore.ts index 1b140e0..8ac698f 100644 --- a/src/LiveTokenStore.ts +++ b/src/LiveTokenStore.ts @@ -39,11 +39,13 @@ async function refresh( if (entity instanceof S3RemoteDocument) { payload = JSON.stringify({ docId: entity.documentId, + folder: entity.folderId, relay: entity.relayId, }); } else if (entity instanceof S3RemoteFolder) { payload = JSON.stringify({ docId: entity.folderId, + folder: entity.folderId, relay: entity.relayId, }); } else { @@ -75,9 +77,12 @@ async function refresh( const clientToken = response.json as ClientToken; onSuccess(clientToken); }) - .catch((reason) => { - error(reason, payload); - onError(reason); + .catch((e) => { + error(e, payload); + if (e.status === 401) { + loginManager.pb.authStore.isValid; + } + onError(e); }); } diff --git a/src/LoginManager.ts b/src/LoginManager.ts index fb22958..91b6926 100644 --- a/src/LoginManager.ts +++ b/src/LoginManager.ts @@ -3,7 +3,12 @@ import { requestUrl } from "obsidian"; import { ObservableSet } from "./observable/ObservableSet"; import { User } from "./User"; -import PocketBase, { BaseAuthStore } from "pocketbase"; +import PocketBase, { + BaseAuthStore, + ClientResponseError, + type RecordAuthResponse, + type RecordModel, +} from "pocketbase"; import { curryLog } from "./debug"; import { Observable } from "./observable/Observable"; @@ -93,9 +98,13 @@ export class OAuth2Url extends Observable { delay: number = 0; _age: number = 0; - set(value: string) { + set(value: string | undefined) { this.url = value; - this._age = Date.now(); + if (value) { + this._age = Date.now(); + } else { + this._age = 0; + } this.notifyListeners(); } @@ -104,6 +113,45 @@ export class OAuth2Url extends Observable { } } +function openBrowserPopup(url?: string): Window | null { + if (typeof window === "undefined" || !window?.open) { + throw new ClientResponseError( + new Error( + `Not in a browser context - please pass a custom urlCallback function.` + ) + ); + } + + let width = 1024; + let height = 768; + + let windowWidth = window.innerWidth; + let windowHeight = window.innerHeight; + + // normalize window size + width = width > windowWidth ? windowWidth : width; + height = height > windowHeight ? windowHeight : height; + + let left = windowWidth / 2 - width / 2; + let top = windowHeight / 2 - height / 2; + + // note: we don't use the noopener and noreferrer attributes since + // for some reason browser blocks such windows then url is undefined/blank + return window.open( + url, + "popup_window", + "width=" + + width + + ",height=" + + height + + ",top=" + + top + + ",left=" + + left + + ",resizable,menubar=no" + ); +} + export class LoginManager extends Observable { pb: PocketBase; sm?: SubscriptionManager; @@ -115,9 +163,10 @@ export class LoginManager extends Observable { constructor(openSettings: () => Promise) { super(); this._log = curryLog("[LoginManager]"); + const pbLog = curryLog("[Pocketbase]"); this.pb = new PocketBase(AUTH_URL); this.pb.beforeSend = (url, options) => { - this._log(url, options); + pbLog(url, options); options.fetch = customFetch; return { url, options }; }; @@ -132,7 +181,7 @@ export class LoginManager extends Observable { this._log(message, ...args); } - setup(): boolean { + setup(authData?: RecordAuthResponse | undefined): boolean { if (!this.pb.authStore.isValid) { this.notifyListeners(); // notify anyway return false; @@ -141,7 +190,17 @@ export class LoginManager extends Observable { this.user = this.makeUser(this.pb.authStore); //this.sm = new SubscriptionManager(user); this.notifyListeners(); - //this.whoami(); + if (authData) { + this.pb + .collection("oauth2_response") + .create({ + user: authData.record.id, + oauth_response: authData.meta?.rawUser, + }) + .catch((reason) => { + this.log(reason); + }); + } return true; } @@ -183,29 +242,32 @@ export class LoginManager extends Observable { } logout() { + this.pb.cancelAllRequests(); this.pb.authStore.clear(); this.user = undefined; this.notifyListeners(); } - async login(): Promise { - await this.pb + login(): Promise { + let eagerDefaultPopup = openBrowserPopup(); + return this.pb .collection("users") .authWithOAuth2({ provider: "google", + fetch: fetch, + urlCallback: (url) => { + this.url.set(url); + if (eagerDefaultPopup) { + eagerDefaultPopup.location.href = url; + } else { + eagerDefaultPopup = openBrowserPopup(url); + } + }, }) .then((authData) => { - this.pb - .collection("oauth2_response") - .create({ - user: authData.record.id, - oauth_response: authData.meta?.rawUser, - }) - .catch((e) => { - // OAuth2 data already exists - }); + this.url.set(undefined); + return this.setup(authData); }); - return this.setup(); } async openLoginPage() { diff --git a/src/RelayManager.ts b/src/RelayManager.ts index 6c80a43..b521e0a 100644 --- a/src/RelayManager.ts +++ b/src/RelayManager.ts @@ -8,7 +8,12 @@ import { type Role, type RemoteSharedFolder as RemoteFolder, } from "./Relay"; -import PocketBase, { type ListResult, type RecordModel } from "pocketbase"; +import PocketBase, { + type AuthModel, + type ListResult, + type RecordModel, + type RecordSubscription, +} from "pocketbase"; import { ObservableMap } from "./observable/ObservableMap"; import { curryLog } from "./debug"; import { customFetch } from "./customFetch"; @@ -724,13 +729,8 @@ export class RelayManager { constructor() { this.log = curryLog("[RelayManager]", "log"); this.warn = curryLog("[RelayManager]", "warn"); - - this.pb = new PocketBase(AUTH_URL); - this.pb.beforeSend = (url, options) => { - this.log(url, options); - options.fetch = customFetch; - return { url, options }; - }; + this.pb = this.loginManager.pb; + this.sm = new SubscriptionManager(this.loginManager); // Build the NodeLists this.users = new ObservableMap(); @@ -1095,7 +1095,6 @@ export class RelayManager { } destroy(): void { - this.unsubscribe(); - this.pb.cancelAllRequests(); + this.sm.destroy(); } } diff --git a/src/components/LoggedIn.svelte b/src/components/LoggedIn.svelte index 3d8df0c..26da68c 100644 --- a/src/components/LoggedIn.svelte +++ b/src/components/LoggedIn.svelte @@ -1,4 +1,5 @@ @@ -23,21 +25,45 @@ name="Your account" description="You are currently logged in as: {$lm.user?.name}." > - + {:else} - - - + + + {:else} + + + + + + {/if} {/if}