Client side atproto account migrator in your web browser, along with services for backups and adversarial migrations.
pdsmoover.com
pds
atproto
migrations
moo
cow
1<script lang="ts">
2 import {handleAndPDSResolver} from '@pds-moover/moover'
3 import type {RotationKeyType} from '$lib/types';
4
5
6 let {handle, rotationKey}: {
7 handle: string,
8 rotationKey: RotationKeyType
9 } = $props();
10
11
12 const copyToClipboard = async (text: string) => {
13 try {
14 await navigator.clipboard.writeText(text);
15 alert('Copied to clipboard');
16 } catch (e) {
17 console.error(e);
18 alert('Failed to copy to clipboard');
19 }
20 }
21
22 const downloadNewRotationKey = async (rotationKey: RotationKeyType, handle: string) => {
23 if (!rotationKey) return;
24 //try and find the did to add to the file as well
25 let didText = '';
26 try {
27 let {usersDid} = await handleAndPDSResolver(handle);
28 didText = `DID: ${usersDid}\n`;
29 } catch (e) {
30 //sliently log. Rather the user have their rotation key than not. a did can always be found other ways if needed
31 console.error(e);
32 }
33
34 const content = `You can use these to recover your account if it's ever necessary via https://pdsmoover.com/restore. The restore process will ask for the Private key\n\nKEEP IN A SECURE LOCATION\n\n${didText}PublicKey: ${rotationKey.publicKey}\nPrivateKey: ${rotationKey.privateKey}\n`;
35 const blob = new Blob([content], {type: 'text/plain'});
36 const url = URL.createObjectURL(blob);
37 const a = document.createElement('a');
38 a.href = url;
39
40
41 a.download = `${handle}-rotation-key.txt`;
42 document.body.appendChild(a);
43 a.click();
44 document.body.removeChild(a);
45 URL.revokeObjectURL(url);
46 }
47</script>
48
49
50<div class="section" style="margin-top: 16px; border: 2px solid #f39c12; padding: 16px;">
51 <h3 style="color: #d35400;">Important: Save Your New Rotation Key Now</h3>
52 <p style="color: #c0392b; font-weight: bold;">
53 Warning: This is the only time we will show you your private rotation key. Save it in a secure place.
54 If you lose it, you may not be able to recover your account in the event of a PDS failure or hijack.
55 </p>
56 <div class="form-group">
57 <span>New Rotation Key (Private - keep secret)</span>
58 <div style="display:flex; gap:8px; align-items:center;">
59 {#if rotationKey}
60 <code
61 style="overflow-wrap:anywhere;">{rotationKey.privateKey}</code>
62 {/if}
63
64 <button type="button"
65 onclick={async () => await copyToClipboard(rotationKey.privateKey)}>Copy
66 </button>
67 </div>
68 </div>
69 <div class="form-group">
70 <button type="button" onclick={async () => await downloadNewRotationKey(rotationKey, handle)}>Download
71 Key File
72 </button>
73 </div>
74</div>