Something went wrong. Try again.
Our Personal Data Server from scratch!
Something went wrong. Try again.
5.4 kB · 198 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199import type { AccountResult, ExternalDidWebState, RegistrationInfo, RegistrationMode, RegistrationStep, SessionState,} from "./types.ts";
const STORAGE_KEY = "tranquil_registration_state";const MAX_AGE_MS = 60 * 60 * 1000;
interface StoredRegistrationState { version: 1; startedAt: string; mode: RegistrationMode; step: RegistrationStep; pdsHostname: string; info: RegistrationInfo; externalDidWeb: StoredExternalDidWebState; account: StoredAccountResult | null; session: StoredSessionState | null;}
interface StoredExternalDidWebState { keyMode: "reserved" | "byod"; reservedSigningKey?: string; byodPrivateKeyBase64?: string; byodPublicKeyMultibase?: string; initialDidDocument?: string; updatedDidDocument?: string;}
interface StoredAccountResult { did: string; handle: string; setupToken?: string; appPassword?: string; appPasswordName?: string;}
interface StoredSessionState { accessJwt: string; refreshJwt: string;}
function uint8ArrayToBase64(arr: Uint8Array): string { return btoa(Array.from(arr, (byte) => String.fromCharCode(byte)).join(""));}
function base64ToUint8Array(base64: string): Uint8Array { const binary = atob(base64); return Uint8Array.from(binary, (char) => char.charCodeAt(0));}
export function saveRegistrationState( mode: RegistrationMode, step: RegistrationStep, pdsHostname: string, info: RegistrationInfo, externalDidWeb: ExternalDidWebState, account: AccountResult | null, session: SessionState | null,): void { const stored: StoredRegistrationState = { version: 1, startedAt: new Date().toISOString(), mode, step, pdsHostname, info: { ...info, password: undefined }, externalDidWeb: { keyMode: externalDidWeb.keyMode, reservedSigningKey: externalDidWeb.reservedSigningKey, byodPrivateKeyBase64: externalDidWeb.byodPrivateKey ? uint8ArrayToBase64(externalDidWeb.byodPrivateKey) : undefined, byodPublicKeyMultibase: externalDidWeb.byodPublicKeyMultibase, initialDidDocument: externalDidWeb.initialDidDocument, updatedDidDocument: externalDidWeb.updatedDidDocument, }, account: account ? { did: account.did, handle: account.handle, setupToken: account.setupToken, appPassword: account.appPassword, appPasswordName: account.appPasswordName, } : null, session: session ? { accessJwt: session.accessJwt, refreshJwt: session.refreshJwt, } : null, };
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(stored)); } catch { /* localStorage unavailable */ }}
export function loadRegistrationState(): { mode: RegistrationMode; step: RegistrationStep; pdsHostname: string; info: RegistrationInfo; externalDidWeb: ExternalDidWebState; account: AccountResult | null; session: SessionState | null;} | null { try { const stored = localStorage.getItem(STORAGE_KEY); if (!stored) return null;
const state = JSON.parse(stored) as StoredRegistrationState;
if (state.version !== 1) { clearRegistrationState(); return null; }
const startedAt = new Date(state.startedAt).getTime(); if (Date.now() - startedAt > MAX_AGE_MS) { clearRegistrationState(); return null; }
return { mode: state.mode, step: state.step, pdsHostname: state.pdsHostname, info: state.info, externalDidWeb: { keyMode: state.externalDidWeb.keyMode, reservedSigningKey: state.externalDidWeb.reservedSigningKey, byodPrivateKey: state.externalDidWeb.byodPrivateKeyBase64 ? base64ToUint8Array(state.externalDidWeb.byodPrivateKeyBase64) : undefined, byodPublicKeyMultibase: state.externalDidWeb.byodPublicKeyMultibase, initialDidDocument: state.externalDidWeb.initialDidDocument, updatedDidDocument: state.externalDidWeb.updatedDidDocument, }, account: state.account ? { did: state.account.did as AccountResult["did"], handle: state.account.handle as AccountResult["handle"], setupToken: state.account.setupToken, appPassword: state.account.appPassword, appPasswordName: state.account.appPasswordName, } : null, session: state.session ? { accessJwt: state.session.accessJwt as SessionState["accessJwt"], refreshJwt: state.session.refreshJwt as SessionState["refreshJwt"], } : null, }; } catch { clearRegistrationState(); return null; }}
export function clearRegistrationState(): void { try { localStorage.removeItem(STORAGE_KEY); } catch { /* localStorage unavailable */ }}
export function hasPendingRegistration(): boolean { const state = loadRegistrationState(); return state !== null && state.step !== "info" && state.step !== "redirect-to-dashboard";}
export function getRegistrationResumeInfo(): { mode: RegistrationMode; handle: string; step: RegistrationStep; did?: string;} | null { const state = loadRegistrationState(); if ( !state || state.step === "info" || state.step === "redirect-to-dashboard" ) { return null; }
return { mode: state.mode, handle: state.info.handle, step: state.step, did: state.account?.did, };}