UNPKG

@authduo/authduo

Version:

Free User-sovereign Authentication for the World

81 lines 2.88 kB
import { pubsub, signal } from "@benev/slate"; import { Login } from "./utils/login.js"; import { openPopup } from "./utils/open-popup.js"; import { nullcatch } from "../auth/utils/nullcatch.js"; import { JsonStorage } from "../tools/json-storage.js"; import { setupInApp } from "../manager/fed-api/setup-in-app.js"; export class Auth { static defaultUrl = "https://authduo.org/"; static version = 1; static #auth = null; static get() { if (!this.#auth) this.#auth = new this(); return this.#auth; } onChange = pubsub(); #fileStorage = new JsonStorage("authduo"); #login = signal(null); constructor() { this.#fileStorage.onChangeFromOutside(() => void this.load()); this.#login.on(login => this.onChange.publish(login)); this.load(); } get authfile() { const authfile = this.#fileStorage.get(); return (authfile && "version" in authfile && authfile.version === Auth.version) ? authfile : { version: Auth.version, tokens: null }; } async load() { const { tokens } = this.authfile; this.#login.value = tokens && await nullcatch(async () => Login.verify(tokens, { allowedAudiences: [window.origin] })); return this.#login.value; } save(tokens) { const { authfile } = this; authfile.tokens = tokens; this.#fileStorage.set(authfile); } get login() { const login = this.#login.value; const valid = login && (Date.now() < login.expiresAt); if (!valid && login) this.#login.value = null; return this.#login.value; } set login(login) { this.#login.value = login; this.save(login && login.tokens); } async popup(url = Auth.defaultUrl) { const appWindow = window; const popupWindow = openPopup(url); if (!popupWindow) return null; const appOrigin = window.origin; const popupOrigin = new URL(url, window.location.href).origin; return new Promise((resolve, reject) => { const { dispose } = setupInApp(appWindow, popupWindow, popupOrigin, async (loginTokens) => { popupWindow.close(); try { this.login = await nullcatch(async () => Login.verify(loginTokens, { allowedIssuers: [popupOrigin], allowedAudiences: [appOrigin], })); dispose(); resolve(this.login); } catch (err) { dispose(); reject(err); } }); popupWindow.onclose = () => { dispose(); resolve(this.login); }; }); } } //# sourceMappingURL=auth.js.map