diff --git a/src/components/account.tsx b/src/components/account.tsx index 7e3195e..eba8e58 100644 --- a/src/components/account.tsx +++ b/src/components/account.tsx @@ -1,50 +1,67 @@ import { Client, CredentialManager } from "@atcute/client"; import { Did } from "@atcute/lexicons"; -import { deleteStoredSession, getSession, OAuthUserAgent } from "@atcute/oauth-browser-client"; +import { + createAuthorizationUrl, + deleteStoredSession, + getSession, + OAuthUserAgent, + resolveFromIdentity, +} from "@atcute/oauth-browser-client"; import { A } from "@solidjs/router"; import { createSignal, For, onMount, Show } from "solid-js"; -import { createStore } from "solid-js/store"; +import { createStore, produce } from "solid-js/store"; import { resolveDidDoc } from "../utils/api.js"; -import { agent, Login, retrieveSession, setAgent } from "./login.jsx"; +import { agent, Login, retrieveSession, Sessions, setAgent } from "./login.jsx"; import { Modal } from "./modal.jsx"; const AccountManager = () => { const [openManager, setOpenManager] = createSignal(false); - const [sessions, setSessions] = createStore>(); + const [sessions, setSessions] = createStore(); const [avatars, setAvatars] = createStore>(); onMount(async () => { - await retrieveSession(); + try { + await retrieveSession(); + } catch {} - const storedSessions = localStorage.getItem("atcute-oauth:sessions"); - if (storedSessions) { - const sessionDids = Object.keys(JSON.parse(storedSessions)) as Did[]; - sessionDids.forEach((did) => setSessions(did, "")); + const localSessions = localStorage.getItem("sessions"); + if (localSessions) { + const storedSessions: Sessions = JSON.parse(localSessions); + const sessionDids = Object.keys(storedSessions) as Did[]; sessionDids.forEach(async (did) => { const doc = await resolveDidDoc(did); doc.alsoKnownAs?.forEach((alias) => { if (alias.startsWith("at://")) { - setSessions(did, alias.replace("at://", "")); + setSessions(did, { + signedIn: storedSessions[did].signedIn, + handle: alias.replace("at://", ""), + }); return; } }); }); sessionDids.forEach(async (did) => { - try { - await getSession(did, { allowStale: true }); - const avatar = await getAvatar(did); - if (avatar) setAvatars(did, avatar); - } catch { - deleteStoredSession(did); - setSessions(did, undefined); - } + const avatar = await getAvatar(did); + if (avatar) setAvatars(did, avatar); }); } }); const resumeSession = async (did: Did) => { - localStorage.setItem("lastSignedIn", did); - retrieveSession(); + try { + localStorage.setItem("lastSignedIn", did); + await retrieveSession(); + } catch { + const resolved = await resolveFromIdentity(did); + const authUrl = await createAuthorizationUrl({ + scope: import.meta.env.VITE_OAUTH_SCOPE, + ...resolved, + }); + + await new Promise((resolve) => setTimeout(resolve, 250)); + + location.assign(authUrl); + } }; const removeSession = async (did: Did) => { @@ -56,7 +73,12 @@ const AccountManager = () => { } catch { deleteStoredSession(did); } - setSessions(did, undefined); + setSessions( + produce((accs) => { + delete accs[did]; + }), + ); + localStorage.setItem("sessions", JSON.stringify(sessions)); if (currentSession === did) setAgent(undefined); }; @@ -93,11 +115,16 @@ const AccountManager = () => { class="size-6 rounded-full" /> - {sessions[did]?.length ? sessions[did] : did} + + {sessions[did]?.handle ? sessions[did].handle : did} + - + + + + (); +type Account = { + signedIn: boolean; + handle?: string; +}; + +export type Sessions = Record; + const Login = () => { const [notice, setNotice] = createSignal(""); const [loginInput, setLoginInput] = createSignal(""); @@ -100,23 +107,34 @@ const retrieveSession = async () => { const did = session.info.sub; localStorage.setItem("lastSignedIn", did); + + const sessions = localStorage.getItem("sessions"); + const newSessions: Sessions = sessions ? JSON.parse(sessions) : { [did]: {} }; + newSessions[did] = { signedIn: true }; + localStorage.setItem("sessions", JSON.stringify(newSessions)); return session; } else { const lastSignedIn = localStorage.getItem("lastSignedIn"); if (lastSignedIn) { try { - return await getSession(lastSignedIn as Did); + const session = await getSession(lastSignedIn as Did); + const rpc = new Client({ handler: new OAuthUserAgent(session) }); + const res = await rpc.get("com.atproto.server.getSession"); + if (!res.ok) throw res.data.error; + return session; } catch (err) { - deleteStoredSession(lastSignedIn as Did); - localStorage.removeItem("lastSignedIn"); + const sessions = localStorage.getItem("sessions"); + const newSessions: Sessions = sessions ? JSON.parse(sessions) : {}; + newSessions[lastSignedIn].signedIn = false; + localStorage.setItem("sessions", JSON.stringify(newSessions)); throw err; } } } }; - const session = await init().catch(() => {}); + const session = await init(); if (session) setAgent(new OAuthUserAgent(session)); };