tangled
alpha
login
or
join now
yoyle.city
/
skittr
6
fork
atom
this repo has no description
atproto
bluesky
typescript
express
6
fork
atom
overview
issues
3
pulls
pipelines
3rd party PDS login
lime360
3 months ago
05266045
e03fc2c1
1/1
test.yml
success
13s
+56
-38
6 changed files
expand all
collapse all
unified
split
.gitignore
src
global.d.ts
index.ts
routes
account.ts
main.ts
mobile.ts
-3
.gitignore
reviewed
···
1
1
node_modules/*
2
2
dist/*
3
3
*.env
4
4
-
*.db
5
5
-
*.lock
6
6
-
package-lock.json
7
4
docker-compose.yml
+2
-1
src/global.d.ts
reviewed
···
2
2
3
3
declare module "express-session" {
4
4
interface SessionData {
5
5
-
handle?: string;
5
5
+
atp?: any;
6
6
accessJwt?: string;
7
7
refreshJwt?: string;
8
8
pds?: string;
9
9
+
handle?: string;
9
10
}
10
11
}
+27
-1
src/index.ts
reviewed
···
1
1
import path from "path";
2
2
import { fileURLToPath } from "url";
3
3
-
import express, { Express } from "express";
3
3
+
import express, { Express, Request, Response, NextFunction } from "express";
4
4
+
import { AtpAgent, AtpSessionEvent, AtpSessionData } from "@atproto/api";
4
5
import { engine } from "express-handlebars";
5
6
import router from "./routes/main.js";
6
7
import mobile from "./routes/mobile.js";
···
69
70
genid: () => crypto.randomUUID(),
70
71
}),
71
72
);
73
73
+
74
74
+
app.use((req: Request, res: Response, next: NextFunction) => {
75
75
+
const agent = new AtpAgent({
76
76
+
service: req.session.pds || "https://bsky.social",
77
77
+
persistSession: (e: AtpSessionEvent, s?: AtpSessionData) => {
78
78
+
if (s) {
79
79
+
req.session.atp = s;
80
80
+
} else {
81
81
+
delete req.session.atp;
82
82
+
}
83
83
+
}
84
84
+
});
85
85
+
86
86
+
if (req.session.atp) {
87
87
+
try {
88
88
+
agent.resumeSession(req.session.atp);
89
89
+
} catch (error) {
90
90
+
console.error(error);
91
91
+
delete req.session.atp;
92
92
+
}
93
93
+
}
94
94
+
95
95
+
(req as any).agent = agent;
96
96
+
next();
97
97
+
});
72
98
73
99
app.use(express.static("public"));
74
100
app.use(express.json());
+5
-10
src/routes/account.ts
reviewed
···
1
1
import { Router, Request, Response } from "express";
2
2
-
import { agent } from "../agent.js";
3
2
import { getActor, getActorDid } from "../lib/actor.js";
4
3
import { getTheme, putTheme } from "../lib/theme.js";
5
4
import multer from "multer";
6
6
-
import auth from "../lib/auth.js";
7
5
8
6
const account = Router();
9
7
const upload = multer({ storage: multer.memoryStorage() });
···
17
15
});
18
16
19
17
account.get("/design", async (req: Request, res: Response) => {
20
20
-
const curuser = await getActorDid(agent, req.cookies.handle);
18
18
+
const agent = (req as any).agent;
19
19
+
const curuser = await getActorDid(agent, (req as any).session.handle);
21
20
const existingusertheme = await getTheme(agent, curuser);
22
21
res.render("account/design", {
23
22
layout: null,
···
25
24
});
26
25
});
27
26
28
28
-
account.post(
29
29
-
"/design",
30
30
-
auth,
31
31
-
upload.single("background"),
32
32
-
async (req: Request, res: Response) => {
33
33
-
const { bg_color, text_color, link_color, side_color, side_border } =
34
34
-
req.body;
27
27
+
account.post("/design", upload.single("background"), async (req: Request, res: Response) => {
28
28
+
const { bg_color, text_color, link_color, side_color, side_border } = req.body;
29
29
+
const agent = (req as any).agent;
35
30
const did = await getActorDid(agent, req.cookies.handle);
36
31
const theme = {
37
32
bg_color: bg_color,
+10
-5
src/routes/main.ts
reviewed
···
32
32
});
33
33
34
34
router.get("/login", (req: Request, res: Response) => {
35
35
-
if (!req.cookies.handle) {
35
35
+
if (!req.session.handle) {
36
36
res.render("login", {
37
37
layout: "main",
38
38
title: "Bluesky",
···
44
44
});
45
45
46
46
router.get("/home", auth, async (req: Request, res: Response) => {
47
47
+
const agent = (req as any).agent;
47
48
const cursor = (req.query.cursor as string) || "";
48
48
-
const handle = req.cookies.handle;
49
49
+
const handle = req.session.handle as string;
49
50
const did = await getActorDid(agent, handle);
50
51
const actor = await getActor(agent, did);
51
52
const feed = await getTimeline(agent, cursor);
···
230
231
231
232
router.post("/status", auth, async (req: Request, res: Response) => {
232
233
const { mobile_text_content, layout } = req.body;
234
234
+
const agent = (req as any).agent;
233
235
234
236
const rt = new RichText({
235
237
text: mobile_text_content,
···
264
266
265
267
router.get("/like", auth, async (req: Request, res: Response) => {
266
268
const { postUri, cid } = req.params;
269
269
+
const agent = (req as any).agent;
267
270
268
271
try {
269
272
await agent.like(postUri, cid);
···
276
279
277
280
router.post("/follow", auth, async (req: Request, res: Response) => {
278
281
const { user } = req.body;
282
282
+
const agent = (req as any).agent;
279
283
const targetDid = await getActorDid(agent, user);
280
284
281
285
try {
···
289
293
290
294
router.post("/unfollow", auth, async (req: Request, res: Response) => {
291
295
const { user } = req.body;
296
296
+
const agent = (req as any).agent;
292
297
const targetDid = await getActorDid(agent, user);
293
298
294
299
try {
···
302
307
303
308
router.post("/sessions", async (req: Request, res: Response) => {
304
309
const { username_or_email, password, layout, pds_url } = req.body;
310
310
+
req.session.pds = pds_url;
311
311
+
const agent = (req as any).agent;
305
312
306
313
try {
307
314
await agent.login({
···
309
316
password: password,
310
317
});
311
318
312
312
-
res.cookie("handle", agent.session?.handle, { httpOnly: true });
313
313
-
res.cookie("accessJwt", agent.session?.accessJwt, { httpOnly: true });
314
314
-
res.cookie("refreshJwt", agent.session?.refreshJwt, { httpOnly: true });
319
319
+
req.session.handle = username_or_email;
315
320
316
321
if (layout === "mobile") {
317
322
res.redirect("/m/home");
+12
-18
src/routes/mobile.ts
reviewed
···
1
1
import { Router, Request, Response } from "express";
2
2
-
import { agent, pubagent } from "../agent.js";
2
2
+
import { pubagent } from "../agent.js";
3
3
import {
4
4
getActor,
5
5
getActorDid,
···
9
9
} from "../lib/actor.js";
10
10
import { getFeed, getFeedData } from "../lib/feed.js";
11
11
import { getTimeline } from "../lib/misc.js";
12
12
-
import auth from "../lib/auth.js";
13
12
14
13
const mobile = Router();
15
14
···
18
17
});
19
18
20
19
mobile.get("/login", (req: Request, res: Response) => {
21
21
-
if (!req.cookies.handle) {
20
20
+
if (!req.session.handle) {
22
21
res.render("mobile/login", {
23
22
layout: "mobile",
24
23
title: "Bluesky",
···
29
28
}
30
29
});
31
30
32
32
-
mobile.get("/home", auth, async (req: Request, res: Response) => {
31
31
+
mobile.get("/home", async (req: Request, res: Response) => {
32
32
+
const agent = (req as any).agent;
33
33
const cursor = (req.query.cursor as string) || "";
34
34
const feed = await getTimeline(agent, cursor);
35
35
···
38
38
title: "Bluesky",
39
39
feed: feed.feed,
40
40
cursor: feed.cursor,
41
41
-
curuser: req.cookies.handle,
41
41
+
curuser: req.session.handle,
42
42
year: new Date().getFullYear(),
43
43
});
44
44
});
···
55
55
actor: actor,
56
56
feed: feed.feed,
57
57
cursor: feed.cursor,
58
58
-
curuser: req.cookies.handle,
58
58
+
curuser: req.session.handle,
59
59
year: new Date().getFullYear(),
60
60
});
61
61
});
62
62
63
63
-
mobile.get(
64
64
-
"/profile/:handle/following",
65
65
-
async (req: Request, res: Response) => {
63
63
+
mobile.get("/profile/:handle/following", async (req: Request, res: Response) => {
66
64
const did = await getActorDid(pubagent, req.params.handle);
67
65
const actor = await getActor(pubagent, did);
68
66
const follows = await getActorFollows(pubagent, did);
···
72
70
title: "Bluesky / " + actor.handle,
73
71
actor: actor,
74
72
follows: follows,
75
75
-
curuser: req.cookies.handle,
73
73
+
curuser: req.session.handle,
76
74
year: new Date().getFullYear(),
77
75
});
78
76
},
79
77
);
80
78
81
81
-
mobile.get(
82
82
-
"/profile/:handle/followers",
83
83
-
async (req: Request, res: Response) => {
79
79
+
mobile.get("/profile/:handle/followers", async (req: Request, res: Response) => {
84
80
const did = await getActorDid(pubagent, req.params.handle);
85
81
const actor = await getActor(pubagent, did);
86
82
const followers = await getActorFollowers(pubagent, did);
···
90
86
title: "Bluesky / " + actor.handle,
91
87
actor: actor,
92
88
followers: followers,
93
93
-
curuser: req.cookies.handle,
89
89
+
curuser: req.session.handle,
94
90
year: new Date().getFullYear(),
95
91
});
96
92
},
97
93
);
98
94
99
99
-
mobile.get(
100
100
-
"/profile/:handle/feed/:record",
101
101
-
async (req: Request, res: Response) => {
95
95
+
mobile.get("/profile/:handle/feed/:record", async (req: Request, res: Response) => {
102
96
const cursor = (req.query.cursor as string) || "";
103
97
const did = await getActorDid(pubagent, req.params.handle);
104
98
const feed = await getFeed(pubagent, did, req.params.record, cursor);
···
110
104
feed: feed.feed,
111
105
cursor: feed.cursor,
112
106
feedData: feedData,
113
113
-
curuser: req.cookies.handle,
107
107
+
curuser: req.session.handle,
114
108
year: new Date().getFullYear(),
115
109
});
116
110
},