···1<!doctype html>
0023-<p>oh sick. hey {{ did }}. you can close this window now.</p>
045<script>
6// TODO: tie this back to its source...........
···11 token: {{{json token}}},
12 fetch_key: {{{json fetch_key}}},
13}));
014window.close();
15</script>
···1<!doctype html>
2+<meta charset="utf-8" />
3+<title>great job!</title>
45+<h1>oauth success!</h1>
6+<p>this window should automatically close itself (probably a bug if it hasn't)</p>
78<script>
9// TODO: tie this back to its source...........
···14 token: {{{json token}}},
15 fetch_key: {{{json fetch_key}}},
16}));
17+// TODO: probably also wait for a reply from the frame and show an error if not
18window.close();
19</script>
+45-4
who-am-i/templates/hello.hbs
···4<div class="mini-content">
5 <div class="explain">
6 <p>This is a little identity-verifying service for microcosm demos.</p>
07 </div>
89 {{#if did}}
···50 } catch (e) {
51 err(e, 'failed to clear session, sorry');
52 }
53- window.location.reload();
054 });
55 })();
56···71 }
72 </script>
73 {{else}}
74- <p id="prompt" class="detail no">
75- No identity connected.
76- </p>
0000000000000000000000000077 {{/if}}
078</div>
00000000000079{{/inline}}
8081{{#> base-full}}{{/base-full}}
···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>
910 {{#if did}}
···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···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>
109+window.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}}
121122{{#> base-full}}{{/base-full}}
+18-1
who-am-i/templates/prompt.hbs
···27 </div>
28</div>
2900000303132<script>
···39const formEl = document.getElementById('form-action'); // for anon
40const allowEl = document.getElementById('handle-action'); // for known-did
41const connectEl = document.getElementById('connect'); // for anon
04243function err(e, msg) {
44 loaderEl.classList.add('hidden');
···66 window.open(url, '_blank');
67};
6800000000000069window.addEventListener('storage', async e => {
70 // here's a fun minor vuln: we can't tell which flow triggers the storage event.
71 // so if you have two flows going, it grants for both (or the first responder?) if you grant for either.
···79 console.error("hmm, heard from localstorage but did not get DID", details, e);
80 err('sorry, something went wrong getting your details');
81 }
82- localStorage.removeItem(e.key);
8384 let parsed;
85 try {
···27 </div>
28</div>
2930+<div id="need-storage" class="hidden">
31+ <p class="problem">Sorry, your browser is blocking access.</p>
32+ <p>Try <a href="/" target="_blank">connecting directly</a> first (but no promises).</p>
33+</div>
34+353637<script>
···44const formEl = document.getElementById('form-action'); // for anon
45const allowEl = document.getElementById('handle-action'); // for known-did
46const connectEl = document.getElementById('connect'); // for anon
47+const needStorageEl = document.getElementById('need-storage'); // for safari/frame isolation
4849function err(e, msg) {
50 loaderEl.classList.add('hidden');
···72 window.open(url, '_blank');
73};
7475+// check if we may be partitioned, preventing access after auth completion
76+// this should only happen if on a browser that implements storage access api
77+if ('hasStorageAccess' in document) {
78+ document.hasStorageAccess().then((hasAccess) => {
79+ if (!hasAccess) {
80+ promptEl.classList.add('hidden');
81+ infoEl.classList.add('hidden');
82+ needStorageEl.classList.remove('hidden');
83+ }
84+ });
85+}
86+87window.addEventListener('storage', async e => {
88 // here's a fun minor vuln: we can't tell which flow triggers the storage event.
89 // so if you have two flows going, it grants for both (or the first responder?) if you grant for either.
···97 console.error("hmm, heard from localstorage but did not get DID", details, e);
98 err('sorry, something went wrong getting your details');
99 }
0100101 let parsed;
102 try {