tangled
alpha
login
or
join now
retr0.id
/
pdsls
forked from
pds.ls/pdsls
1
fork
atom
atproto explorer
1
fork
atom
overview
issues
pulls
pipelines
new auth logic
handle.invalid
4 months ago
895e336f
4e4b7dfc
verified
This commit was signed with the committer's
known signature
.
handle.invalid
SSH Key Fingerprint:
SHA256:mBrT4x0JdzLpbVR95g1hjI1aaErfC02kmLRkPXwsYCk=
+73
-28
2 changed files
expand all
collapse all
unified
split
src
components
account.tsx
login.tsx
+50
-23
src/components/account.tsx
···
1
import { Client, CredentialManager } from "@atcute/client";
2
import { Did } from "@atcute/lexicons";
3
-
import { deleteStoredSession, getSession, OAuthUserAgent } from "@atcute/oauth-browser-client";
0
0
0
0
0
0
4
import { A } from "@solidjs/router";
5
import { createSignal, For, onMount, Show } from "solid-js";
6
-
import { createStore } from "solid-js/store";
7
import { resolveDidDoc } from "../utils/api.js";
8
-
import { agent, Login, retrieveSession, setAgent } from "./login.jsx";
9
import { Modal } from "./modal.jsx";
10
11
const AccountManager = () => {
12
const [openManager, setOpenManager] = createSignal(false);
13
-
const [sessions, setSessions] = createStore<Record<string, string | undefined>>();
14
const [avatars, setAvatars] = createStore<Record<Did, string>>();
15
16
onMount(async () => {
17
-
await retrieveSession();
0
0
18
19
-
const storedSessions = localStorage.getItem("atcute-oauth:sessions");
20
-
if (storedSessions) {
21
-
const sessionDids = Object.keys(JSON.parse(storedSessions)) as Did[];
22
-
sessionDids.forEach((did) => setSessions(did, ""));
23
sessionDids.forEach(async (did) => {
24
const doc = await resolveDidDoc(did);
25
doc.alsoKnownAs?.forEach((alias) => {
26
if (alias.startsWith("at://")) {
27
-
setSessions(did, alias.replace("at://", ""));
0
0
0
28
return;
29
}
30
});
31
});
32
sessionDids.forEach(async (did) => {
33
-
try {
34
-
await getSession(did, { allowStale: true });
35
-
const avatar = await getAvatar(did);
36
-
if (avatar) setAvatars(did, avatar);
37
-
} catch {
38
-
deleteStoredSession(did);
39
-
setSessions(did, undefined);
40
-
}
41
});
42
}
43
});
44
45
const resumeSession = async (did: Did) => {
46
-
localStorage.setItem("lastSignedIn", did);
47
-
retrieveSession();
0
0
0
0
0
0
0
0
0
0
0
0
48
};
49
50
const removeSession = async (did: Did) => {
···
56
} catch {
57
deleteStoredSession(did);
58
}
59
-
setSessions(did, undefined);
0
0
0
0
0
60
if (currentSession === did) setAgent(undefined);
61
};
62
···
93
class="size-6 rounded-full"
94
/>
95
</Show>
96
-
<span class="truncate">{sessions[did]?.length ? sessions[did] : did}</span>
0
0
97
</span>
98
-
<Show when={did === agent()?.sub}>
99
<span class="iconify lucide--check shrink-0 text-green-500 dark:text-green-400"></span>
0
0
0
100
</Show>
101
</button>
102
<A
···
1
import { Client, CredentialManager } from "@atcute/client";
2
import { Did } from "@atcute/lexicons";
3
+
import {
4
+
createAuthorizationUrl,
5
+
deleteStoredSession,
6
+
getSession,
7
+
OAuthUserAgent,
8
+
resolveFromIdentity,
9
+
} from "@atcute/oauth-browser-client";
10
import { A } from "@solidjs/router";
11
import { createSignal, For, onMount, Show } from "solid-js";
12
+
import { createStore, produce } from "solid-js/store";
13
import { resolveDidDoc } from "../utils/api.js";
14
+
import { agent, Login, retrieveSession, Sessions, setAgent } from "./login.jsx";
15
import { Modal } from "./modal.jsx";
16
17
const AccountManager = () => {
18
const [openManager, setOpenManager] = createSignal(false);
19
+
const [sessions, setSessions] = createStore<Sessions>();
20
const [avatars, setAvatars] = createStore<Record<Did, string>>();
21
22
onMount(async () => {
23
+
try {
24
+
await retrieveSession();
25
+
} catch {}
26
27
+
const localSessions = localStorage.getItem("sessions");
28
+
if (localSessions) {
29
+
const storedSessions: Sessions = JSON.parse(localSessions);
30
+
const sessionDids = Object.keys(storedSessions) as Did[];
31
sessionDids.forEach(async (did) => {
32
const doc = await resolveDidDoc(did);
33
doc.alsoKnownAs?.forEach((alias) => {
34
if (alias.startsWith("at://")) {
35
+
setSessions(did, {
36
+
signedIn: storedSessions[did].signedIn,
37
+
handle: alias.replace("at://", ""),
38
+
});
39
return;
40
}
41
});
42
});
43
sessionDids.forEach(async (did) => {
44
+
const avatar = await getAvatar(did);
45
+
if (avatar) setAvatars(did, avatar);
0
0
0
0
0
0
46
});
47
}
48
});
49
50
const resumeSession = async (did: Did) => {
51
+
try {
52
+
localStorage.setItem("lastSignedIn", did);
53
+
await retrieveSession();
54
+
} catch {
55
+
const resolved = await resolveFromIdentity(did);
56
+
const authUrl = await createAuthorizationUrl({
57
+
scope: import.meta.env.VITE_OAUTH_SCOPE,
58
+
...resolved,
59
+
});
60
+
61
+
await new Promise((resolve) => setTimeout(resolve, 250));
62
+
63
+
location.assign(authUrl);
64
+
}
65
};
66
67
const removeSession = async (did: Did) => {
···
73
} catch {
74
deleteStoredSession(did);
75
}
76
+
setSessions(
77
+
produce((accs) => {
78
+
delete accs[did];
79
+
}),
80
+
);
81
+
localStorage.setItem("sessions", JSON.stringify(sessions));
82
if (currentSession === did) setAgent(undefined);
83
};
84
···
115
class="size-6 rounded-full"
116
/>
117
</Show>
118
+
<span class="truncate">
119
+
{sessions[did]?.handle ? sessions[did].handle : did}
120
+
</span>
121
</span>
122
+
<Show when={did === agent()?.sub && sessions[did].signedIn}>
123
<span class="iconify lucide--check shrink-0 text-green-500 dark:text-green-400"></span>
124
+
</Show>
125
+
<Show when={!sessions[did].signedIn}>
126
+
<span class="iconify lucide--circle-alert shrink-0 text-red-500 dark:text-red-400"></span>
127
</Show>
128
</button>
129
<A
+23
-5
src/components/login.tsx
···
0
1
import { Did } from "@atcute/lexicons";
2
import { isHandle } from "@atcute/lexicons/syntax";
3
import {
4
configureOAuth,
5
createAuthorizationUrl,
6
-
deleteStoredSession,
7
finalizeAuthorization,
8
getSession,
9
OAuthUserAgent,
···
21
});
22
23
export const [agent, setAgent] = createSignal<OAuthUserAgent | undefined>();
0
0
0
0
0
0
0
24
25
const Login = () => {
26
const [notice, setNotice] = createSignal("");
···
100
const did = session.info.sub;
101
102
localStorage.setItem("lastSignedIn", did);
0
0
0
0
0
103
return session;
104
} else {
105
const lastSignedIn = localStorage.getItem("lastSignedIn");
106
107
if (lastSignedIn) {
108
try {
109
-
return await getSession(lastSignedIn as Did);
0
0
0
0
110
} catch (err) {
111
-
deleteStoredSession(lastSignedIn as Did);
112
-
localStorage.removeItem("lastSignedIn");
0
0
113
throw err;
114
}
115
}
116
}
117
};
118
119
-
const session = await init().catch(() => {});
120
121
if (session) setAgent(new OAuthUserAgent(session));
122
};
···
1
+
import { Client } from "@atcute/client";
2
import { Did } from "@atcute/lexicons";
3
import { isHandle } from "@atcute/lexicons/syntax";
4
import {
5
configureOAuth,
6
createAuthorizationUrl,
0
7
finalizeAuthorization,
8
getSession,
9
OAuthUserAgent,
···
21
});
22
23
export const [agent, setAgent] = createSignal<OAuthUserAgent | undefined>();
24
+
25
+
type Account = {
26
+
signedIn: boolean;
27
+
handle?: string;
28
+
};
29
+
30
+
export type Sessions = Record<string, Account>;
31
32
const Login = () => {
33
const [notice, setNotice] = createSignal("");
···
107
const did = session.info.sub;
108
109
localStorage.setItem("lastSignedIn", did);
110
+
111
+
const sessions = localStorage.getItem("sessions");
112
+
const newSessions: Sessions = sessions ? JSON.parse(sessions) : { [did]: {} };
113
+
newSessions[did] = { signedIn: true };
114
+
localStorage.setItem("sessions", JSON.stringify(newSessions));
115
return session;
116
} else {
117
const lastSignedIn = localStorage.getItem("lastSignedIn");
118
119
if (lastSignedIn) {
120
try {
121
+
const session = await getSession(lastSignedIn as Did);
122
+
const rpc = new Client({ handler: new OAuthUserAgent(session) });
123
+
const res = await rpc.get("com.atproto.server.getSession");
124
+
if (!res.ok) throw res.data.error;
125
+
return session;
126
} catch (err) {
127
+
const sessions = localStorage.getItem("sessions");
128
+
const newSessions: Sessions = sessions ? JSON.parse(sessions) : {};
129
+
newSessions[lastSignedIn].signedIn = false;
130
+
localStorage.setItem("sessions", JSON.stringify(newSessions));
131
throw err;
132
}
133
}
134
}
135
};
136
137
+
const session = await init();
138
139
if (session) setAgent(new OAuthUserAgent(session));
140
};