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