Something went wrong. Try again.
Client side atproto account migrator in your web browser, along with services for backups and adversarial migrations. pdsmoover.com
pds atproto migrations moo cow
Something went wrong. Try again.
4.9 kB · 104 lines
Svelte
at oauth
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105<script lang="ts"> import {formatAddedDate} from '$lib/moover'; import Button from '$lib/components/ui/Button.svelte'; import StatusChip from '$lib/components/ui/StatusChip.svelte';
interface Props { /** Keys on the identity that the PDS did not claim as its own, or null when the PDS's key is unknown. */ heldKeys: string[] | null; /** How many rotation keys the DID document holds right now. */ docKeyCount: number; /** ISO dates keys were added, keyed by rotation key. */ addedDates?: Record<string, string>; /** Hostname of the PDS the account is on, when known. */ pdsHost?: string | null; /** A key was generated on this visit and is ticked. */ generatedIncluded: boolean; /** The advanced list differs from the identity in some way other than the generated key. */ otherChanges?: boolean; busy?: boolean; onGenerate: () => void; }
let { heldKeys, docKeyCount, addedDates = {}, pdsHost = null, generatedIncluded, otherChanges = false, busy = false, onGenerate, }: Props = $props();
const pdsName = $derived(pdsHost ? `your PDS (${pdsHost})` : 'your PDS'); const held = $derived(heldKeys ?? []); const hasOwn = $derived(held.length > 0); /** The most recent date among the held keys, when the audit log gave one. */ const latestAdded = $derived.by(() => { const dates = held.map((key) => addedDates[key]).filter((d): d is string => !!d); if (dates.length === 0) return null; return dates.reduce((a, b) => (new Date(b) > new Date(a) ? b : a)); }); const generateLabel = $derived(generatedIncluded ? 'Generate a different key' : hasOwn ? 'Generate another recovery key' : 'Generate a recovery key'); const generateVariant = $derived(generatedIncluded || hasOwn ? 'secondary' : 'primary'); /** Green once the user holds a key (or has one ready); amber when they still need one. */ const borderClass = $derived.by(() => { if (hasOwn || generatedIncluded) return 'border-[rgba(46,204,113,0.45)]'; if (heldKeys === null) return 'border-[rgba(127,127,127,0.35)]'; return 'border-[#f39c12]'; });</script>
<div class="rounded-lg border px-3.5 py-3 {borderClass}"> <div class="mb-2 flex flex-wrap items-center gap-1.5"> {#if heldKeys === null} <StatusChip variant="unknown">Unknown</StatusChip> {:else if docKeyCount === 0} <StatusChip variant="warn">No rotation keys at all</StatusChip> {:else if !hasOwn} <StatusChip variant="warn">No recovery key of your own</StatusChip> {:else} <StatusChip variant="good">{held.length} {held.length === 1 ? 'key' : 'keys'} of your own</StatusChip> {/if} {#if generatedIncluded} <StatusChip variant="good">New key ready to apply</StatusChip> {/if} {#if otherChanges} <StatusChip variant="note">Changes in Advanced</StatusChip> {/if} </div>
{#if heldKeys === null} <p class="mt-0"><strong>We cannot tell whether you already have a recovery key.</strong> Your PDS did not say which key is its own. The full list is under Advanced below.</p> {:else if docKeyCount === 0} <p class="mt-0"><strong>Your identity has no rotation keys at all.</strong> Right now nobody can change it, not even your PDS. Generate a recovery key to fix that.</p> {:else if !hasOwn} <p class="mt-0"><strong>You do not have a recovery key of your own yet.</strong> Right now only {pdsName} can change your identity. If it ever goes away or turns against you, you could not get your account back. Generate a recovery key and keep its private half somewhere safe.</p> {:else} <p class="mt-0"><strong>You have {held.length === 1 ? 'a key' : `${held.length} keys`} on your identity that {held.length === 1 ? 'isn\'t' : 'aren\'t'} your PDS's</strong>{#if latestAdded}, added {formatAddedDate(latestAdded)}{/if}. If that is yours and you still have its private half, you are set. If you have lost it, generate a new one.</p> {/if}
{#if generatedIncluded} <p class="text-[0.9em] opacity-80">A new recovery key is ready and will go at the top of the list. You get its private half to save once you apply.</p> {/if} {#if otherChanges} <p class="text-[0.9em] opacity-80">You have changes waiting in the advanced list below.</p> {/if}
<div class="mt-2 flex flex-wrap gap-2"> <Button id="generate-key" variant={generateVariant} disabled={busy} onclick={onGenerate}> {generateLabel} </Button> </div></div>