this repo has no description
at filter-styling 109 lines 3.1 kB view raw
1import { Did } from "@atcute/lexicons"; 2import { isHandle } from "@atcute/lexicons/syntax"; 3import { 4 configureOAuth, 5 createAuthorizationUrl, 6 deleteStoredSession, 7 finalizeAuthorization, 8 getSession, 9 OAuthUserAgent, 10 resolveFromIdentity, 11 resolveFromService, 12 type Session, 13} from "@atcute/oauth-browser-client"; 14import { createSignal } from "solid-js"; 15import { TextInput } from "./text-input"; 16 17configureOAuth({ 18 metadata: { 19 client_id: import.meta.env.VITE_OAUTH_CLIENT_ID, 20 redirect_uri: import.meta.env.VITE_OAUTH_REDIRECT_URL, 21 }, 22}); 23 24export const [agent, setAgent] = createSignal<OAuthUserAgent | undefined>(); 25 26const Login = () => { 27 const [notice, setNotice] = createSignal(""); 28 const [loginInput, setLoginInput] = createSignal(""); 29 30 const login = async (handle: string) => { 31 try { 32 if (!handle) return; 33 let resolved; 34 if (!isHandle(handle)) { 35 setNotice(`Resolving your service...`); 36 resolved = await resolveFromService(handle); 37 } else { 38 setNotice(`Resolving your identity...`); 39 resolved = await resolveFromIdentity(handle); 40 } 41 42 setNotice(`Contacting your data server...`); 43 const authUrl = await createAuthorizationUrl({ 44 scope: import.meta.env.VITE_OAUTH_SCOPE, 45 ...resolved, 46 }); 47 48 setNotice(`Redirecting...`); 49 await new Promise((resolve) => setTimeout(resolve, 250)); 50 51 location.assign(authUrl); 52 } catch (e) { 53 console.error(e); 54 setNotice(`${e}`); 55 } 56 }; 57 58 return ( 59 <form class="flex flex-col gap-y-2" onsubmit={(e) => e.preventDefault()}> 60 <div class="flex items-center gap-2"> 61 <label for="handle" class="flex items-center"> 62 <span class="iconify lucide--user-round-plus text-lg"></span> 63 </label> 64 <TextInput 65 id="handle" 66 placeholder="user.bsky.social" 67 onInput={(e) => setLoginInput(e.currentTarget.value)} 68 class="grow" 69 /> 70 <button onclick={() => login(loginInput())} class="iconify lucide--log-in text-lg"></button> 71 </div> 72 <div>{notice()}</div> 73 </form> 74 ); 75}; 76 77const retrieveSession = async () => { 78 const init = async (): Promise<Session | undefined> => { 79 const params = new URLSearchParams(location.hash.slice(1)); 80 81 if (params.has("state") && (params.has("code") || params.has("error"))) { 82 history.replaceState(null, "", location.pathname + location.search); 83 84 const session = await finalizeAuthorization(params); 85 const did = session.info.sub; 86 87 localStorage.setItem("lastSignedIn", did); 88 return session; 89 } else { 90 const lastSignedIn = localStorage.getItem("lastSignedIn"); 91 92 if (lastSignedIn) { 93 try { 94 return await getSession(lastSignedIn as Did); 95 } catch (err) { 96 deleteStoredSession(lastSignedIn as Did); 97 localStorage.removeItem("lastSignedIn"); 98 throw err; 99 } 100 } 101 } 102 }; 103 104 const session = await init().catch(() => {}); 105 106 if (session) setAgent(new OAuthUserAgent(session)); 107}; 108 109export { Login, retrieveSession };