Client side atproto account migrator in your web browser, along with services for backups and adversarial migrations.

I think I may change the front end...

Changed files
+64 -30
web
+64 -30
web/templates/backups.askama.html
··· 17 17 showTwoFactorCodeInput: false, 18 18 error: null, 19 19 showStatusMessage: false, 20 - showLoginScreen: true, 20 + //The landing page to pick to login with password or oauth 21 + showLandingButtons: true, 22 + //Password login 23 + showLoginScreen: false, 21 24 showRepoNotFoundScreen: false, 22 25 addRecoveryKey: true, 23 26 // Rotation key flow state ··· 47 50 this.showStatusMessage = false; 48 51 } 49 52 }, 53 + handleShowLogin() { 54 + this.showLandingButtons = false; 55 + this.showLoginScreen = true; 56 + }, 57 + async handleOAuthSignup() { 58 + // TODO: Replace this URL with your actual OAuth signup endpoint for backups 59 + // If you have an environment-specific route, consider injecting it or making it configurable 60 + window.location.href = '/oauth/backups'; 61 + }, 50 62 async handleLoginSubmit() { 63 + this.error = null; 64 + this.showStatusMessage = false; 65 + this.showLandingButtons = false; 51 66 this.error = null; 52 67 this.showStatusMessage = false; 53 68 ··· 203 218 {% call cow::cow_header("Backups") %} 204 219 205 220 206 - <form id="backup-signup-form" @submit.prevent="await handleLoginSubmit()" x-show="showLoginScreen"> 221 + <!-- Landing choice: two buttons --> 222 + <div x-show="showLoginScreen"> 207 223 <!-- Informational section before sign-in --> 208 224 <div class="section" style="text-align: left;"> 209 - <p> 210 - PDS MOOver can provide worry free backups of your AT Protocol account. This is a free service for individual accounts and stores the backups on PDS MOOver's servers. Just like your <a target="_blank" rel="noopener noreferrer" href="https://blueskyweb.zendesk.com/hc/en-us/articles/15835264007693-Data-Privacy">AT Proto data</a>, this is also public. On login, you will be asked if you'd like to add a rotation key to your account. 211 - A rotation key is a recovery key that allows you to restore your account if your PDS ever goes down. If you're already signed up for backups, then you can log in here to manage them. 212 - </p> 225 + <p> 226 + PDS MOOver can provide worry-free backups of your AT Protocol account. 227 + This is a free service for individual accounts 228 + and stores the backups on PDS MOOver's servers. 229 + Just like your <a target="_blank" rel="noopener noreferrer" href="https://blueskyweb.zendesk.com/hc/en-us/articles/15835264007693-Data-Privacy">AT Proto data</a>, 230 + this is also public. 231 + <span x-show="showLoginScreen">On login, 232 + you will be asked if you'd like to add a rotation key to your account. 233 + A rotation key is a recovery key 234 + that allows you to restore your account if your PDS ever goes down. 235 + If you're already signed up for backups, then you can log in here to manage them.</span> 236 + 237 + </p> 213 238 </div> 214 - <!-- Sign-in section --> 215 - <div class="section"> 216 - <h2>Sign in to your account</h2> 217 - <div class="form-group"> 218 - <label for="handle">Handle</label> 219 - <input type="text" id="handle" name="handle" placeholder="alice.bsky.social" x-model="handle" required> 220 - </div> 221 239 222 - <div class="form-group"> 223 - <label for="password">Real Password</label> 224 - <input type="password" id="password" name="password" x-model="password" required> 225 - <p> If you are signing up and adding a rotation key you have to use your account's real password. If you are just managing your backups or have your own rotation key you can use an app password</p> 240 + <div x-show="showLandingButtons" class="actions" style="display: flex; gap: 1rem; flex-wrap: wrap;"> 241 + <button type="button" @click="handleShowLogin()">Sign in to add a recovery key</button> 242 + <button type="button" @click="await handleOAuthSignup()">Sign in for backups with OAuth</button> 243 + </div> 244 + 245 + <!-- Sign in with password section --> 246 + <form id="backup-signup-form" @submit.prevent="await handleLoginSubmit()"> 247 + 248 + <div class="section"> 249 + <h2>Sign in to your account</h2> 250 + <div class="form-group"> 251 + <label for="handle">Handle</label> 252 + <input type="text" id="handle" name="handle" placeholder="alice.bsky.social" x-model="handle" required> 253 + </div> 254 + 255 + <div class="form-group"> 256 + <label for="password">Real Password</label> 257 + <input type="password" id="password" name="password" x-model="password" required> 258 + <p> If you are signing up and adding a rotation key you have to use your account's real password. If you are just managing your backups or have your own rotation key you can use an app password</p> 259 + 260 + </div> 226 261 262 + <div x-show="showTwoFactorCodeInput" class="form-group"> 263 + <label for="two-factor-code">Two-factor code (email)</label> 264 + <input type="text" id="two-factor-code" name="two-factor-code" x-model="twoFactorCode"> 265 + <div class="error-message">Enter the 2FA code from your email.</div> 266 + </div> 227 267 </div> 228 268 229 - <div x-show="showTwoFactorCodeInput" class="form-group"> 230 - <label for="two-factor-code">Two-factor code (email)</label> 231 - <input type="text" id="two-factor-code" name="two-factor-code" x-model="twoFactorCode"> 232 - <div class="error-message">Enter the 2FA code from your email.</div> 269 + <div x-show="error" x-text="error" class="error-message"></div> 270 + <div x-show="showStatusMessage" id="status-message" class="status-message"></div> 271 + <div> 272 + <button type="submit">Login for backups</button> 233 273 </div> 234 - </div> 235 - 236 - <div x-show="error" x-text="error" class="error-message"></div> 237 - <div x-show="showStatusMessage" id="status-message" class="status-message"></div> 238 - <div> 239 - <button type="submit">Login for backups</button> 240 - </div> 241 - </form> 274 + </form> 275 + </div> 242 276 243 277 <!-- Repo not found prompt --> 244 278 <div class="section" x-show="showRepoNotFoundScreen"> ··· 298 332 </template> 299 333 300 334 <!-- Repo status view for signed-up users --> 301 - <div class="section" x-show="!showLoginScreen && !showRepoNotFoundScreen && !showRotationKeyScreen"> 335 + <div class="section" x-show="!showLandingButtons && !showLoginScreen && !showRepoNotFoundScreen && !showRotationKeyScreen"> 302 336 <div class="section-header"> 303 337 <h2 style="margin: 0;">Backup repository status</h2> 304 338 <button type="button" class="icon-button" title="Refresh status" aria-label="Refresh status" @click="refreshStatus">