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{%- import "partials/cow-header.askama.html" as cow -%}
2
3{% extends "layout.askama.html" %}
4
5{% block meta %}
6 <meta property="og:description" content="Generate a new ATProto rotation key"/>
7{% endblock %}
8
9{% block content %}
10<script>
11 document.addEventListener('alpine:init', () => {
12 window.Alpine.data('rotationKey', () => ({
13 newlyCreatedRotationKey: null, // { publicKey, privateKey }
14 error: null,
15 status: null,
16 async generateNewKey() {
17 this.error = null;
18 this.status = 'Generating a new rotation key…';
19 try {
20 const created = await window.PlcOps.createANewSecp256k1();
21 this.newlyCreatedRotationKey = created;
22 this.status = 'New rotation key generated.';
23 } catch (e) {
24 console.error(e);
25 this.error = e?.message || 'Failed to generate a new rotation key';
26 this.status = null;
27 }
28 },
29 }));
30 });
31</script>
32
33<div class="container" x-data="rotationKey">
34 {% call cow::cow_header("Rotation Key") %}
35
36 <div class="section">
37 <p style="text-align: left;">This page lets you generate a new rotation key for recovery. Keep it safe — we will only show the private key once.</p>
38 <div class="form-group">
39 <button type="button" @click="generateNewKey()">Generate New Rotation Key</button>
40 </div>
41 </div>
42
43 <div x-show="status" x-text="status" class="status-message"></div>
44 <div x-show="error" x-text="error" class="error-message"></div>
45
46 <template x-if="newlyCreatedRotationKey">
47 <div x-data="{newlyCreatedRotationKey: newlyCreatedRotationKey}">
48 {% include "partials/rotation_key_display.askama.html" %}
49 </div>
50 </template>
51</div>
52
53{% endblock %}