Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm
at main 3.8 kB view raw
1{{#*inline "description"}}A little identity-verifying auth service for microcosm demos{{/inline}} 2 3{{#*inline "main"}} 4<div class="mini-content"> 5 <div class="explain"> 6 <p>This is a little identity-verifying service for microcosm demos.</p> 7 <p>Only <strong>read access to your public data</strong> is required to connect: connecting does not grant any ability to modify your account or data.</p> 8 </div> 9 10 {{#if did}} 11 <p id="error-message" class="hidden"></p> 12 13 <p id="prompt" class="detail"> 14 Connected identity: 15 </p> 16 17 <div id="loader"> 18 <span class="spinner"></span> 19 </div> 20 21 <div id="user-info"> 22 <div id="handle-action" class="action"> 23 <span id="handle-view" class="handle"></span> 24 <button id="revoke">disconnect</button> 25 </div> 26 </div> 27 <script> 28 const errorEl = document.getElementById('error-message'); 29 const loaderEl = document.getElementById('loader'); 30 const handleViewEl = document.getElementById('handle-view'); 31 const revokeEl = document.getElementById('revoke'); // for known-did 32 33 function err(e, msg) { 34 loaderEl.classList.add('hidden'); 35 errorEl.classList.remove('hidden'); 36 errorEl.textContent = msg || e; 37 throw new Error(e); 38 } 39 40 // already-known user 41 ({{{json did}}}) && (async () => { 42 43 const handle = await lookUp({{{json fetch_key}}}); 44 45 loaderEl.classList.add('hidden'); 46 handleViewEl.textContent = `@${handle}`; 47 revokeEl.addEventListener('click', async () => { 48 try { 49 let res = await fetch('/disconnect', { method: 'POST', credentials: 'include' }); 50 if (!res.ok) throw res; 51 } catch (e) { 52 err(e, 'failed to clear session, sorry'); 53 } 54 window.location.replace(location.pathname); 55 window.location.reload(); // backup, in case there is no query? 56 }); 57 })(); 58 59 async function lookUp(fetch_key) { 60 let info; 61 try { 62 const resp = await fetch('/user-info', { 63 method: 'POST', 64 headers: {'Content-Type': 'application/json'}, 65 body: JSON.stringify({ fetch_key }), 66 }); 67 if (!resp.ok) throw resp; 68 info = await resp.json(); 69 } catch (e) { 70 err(e, 'failed to resolve handle from DID') 71 } 72 return info.handle; 73 } 74 </script> 75 {{else}} 76 77 <p class="hello-connect-plz">Connect your handle</p> 78 79 {{#if is_auth_reload}} 80 {{#if no_cookie}} 81 <p id="prompt" class="detail no"> 82 No identity connected. Your browser may be blocking access for connecting. 83 </p> 84 {{else}} 85 {{#if auth_failed}} 86 <p id="prompt" class="detail no"> 87 No identity connected. Connecting failed or was denied. 88 </p> 89 {{else}} 90 <p id="prompt" class="detail no"> 91 No identity connected. 92 </p> 93 {{/if}} 94 {{/if}} 95 {{/if}} 96 97 <div id="user-info"> 98 <form id="form-action" action="/auth" target="_blank" method="GET" class="action {{#if did}}hidden{{/if}}"> 99 <label> 100 @<input id="handle-input" class="handle" name="handle" placeholder="example.bsky.social" /> 101 </label> 102 <button id="connect" type="submit">connect</button> 103 </form> 104 </div> 105 {{/if}} 106 107</div> 108<script> 109window.addEventListener('storage', e => { 110 console.log('eyyy got storage', e); 111 if (e.key !== 'who-am-i') return; 112 if (!e.newValue) return; 113 if (e.newValue.result === 'success') { 114 window.location = '/?auth_reload=1'; 115 } else { 116 window.location = '/?auth_reload=1&auth_failed=1'; 117 } 118}); 119</script> 120{{/inline}} 121 122{{#> base-full}}{{/base-full}}