+44
-16
apps/web/index.ts
+44
-16
apps/web/index.ts
···
1
+
import { isValidHandle } from "@atproto/syntax";
1
2
import { serve, type HttpBindings } from "@hono/node-server";
3
+
import { COOKIE_SECRET } from "@tealfmbot/common/constants.js";
2
4
import { logger } from "@tealfmbot/common/logger.js";
3
5
import { Hono } from "hono";
6
+
import { getSignedCookie } from "hono/cookie";
7
+
import { validator } from "hono/validator";
4
8
import pinoHttpLogger from "pino-http";
5
9
6
10
import { client } from "./client";
7
11
import { createSession, MAX_AGE } from "./utils";
8
-
import { getSignedCookie } from "hono/cookie";
9
-
import { COOKIE_SECRET } from "@tealfmbot/common/constants.js";
10
12
11
13
type Variables = {
12
14
logger: typeof logger;
···
27
29
});
28
30
29
31
app.get("/", (c) => {
30
-
c.var.logger.info("test log");
31
32
return c.text("yo!!");
32
33
});
33
34
35
+
app.get("/health", (c) => {
36
+
return c.json({ message: "OK" }, 200);
37
+
});
38
+
34
39
app.get("/oauth-client-metadata.json", (c) => {
35
40
c.header("Cache-Control", `max-age=${MAX_AGE}, public`);
36
41
return c.json(client.clientMetadata);
···
42
47
});
43
48
44
49
app.get("/oauth/callback", async (c) => {
45
-
c.header("Cache-Control", "no-store")
46
-
const params = new URLSearchParams(c.req.url.split("?")[1])
50
+
c.header("Cache-Control", "no-store");
51
+
const params = new URLSearchParams(c.req.url.split("?")[1]);
47
52
48
53
try {
49
-
const session = await getSignedCookie(c, COOKIE_SECRET, "__teal_fm_bot_session")
54
+
const session = await getSignedCookie(c, COOKIE_SECRET, "__teal_fm_bot_session");
50
55
if (session) {
51
56
try {
52
-
const oauthSession = await client.restore(session)
53
-
if (oauthSession) oauthSession.signOut()
54
-
} catch {
55
-
logger.warn("oauth restore failed")
57
+
const oauthSession = await client.restore(session);
58
+
if (oauthSession) oauthSession.signOut();
59
+
} catch (error) {
60
+
logger.warn({ error }, "oauth restore failed");
56
61
}
57
62
}
58
-
const oauth = await client.callback(params)
63
+
const oauth = await client.callback(params);
59
64
await createSession(oauth.session.did);
60
-
61
-
} catch {
62
-
logger.error("oauth callback failed")
65
+
} catch (error) {
66
+
logger.error({ error }, "oauth callback failed");
63
67
}
64
68
65
-
return c.redirect("/")
66
-
})
69
+
return c.redirect("/");
70
+
});
71
+
72
+
app.post(
73
+
"/login",
74
+
validator("form", (value, c) => {
75
+
const identifier = value["identifier"];
76
+
if (!identifier || typeof identifier !== "string" || !isValidHandle(identifier)) {
77
+
return c.json({ message: "Invalid handle, did or PDS URL" }, 400);
78
+
}
79
+
80
+
return {
81
+
identifier,
82
+
};
83
+
}),
84
+
(c) => {
85
+
c.header("Cache-Control", "no-store");
86
+
const { identifier } = c.req.valid("form");
87
+
try {
88
+
return c.text(identifier);
89
+
} catch (error) {
90
+
logger.error({ error }, "oauth authorize failed");
91
+
return c.json({ message: "oauth authorize failed" }, 500);
92
+
}
93
+
},
94
+
);
67
95
68
96
const server = serve({
69
97
fetch: app.fetch,
+1
apps/web/package.json
+1
apps/web/package.json
+12
-10
apps/web/utils.ts
+12
-10
apps/web/utils.ts
···
1
-
import { COOKIE_SECRET } from "@tealfmbot/common/constants.ts";
2
1
import type { Context } from "hono";
3
-
import { deleteCookie, generateSignedCookie, getSignedCookie } from "hono/cookie";
4
-
import { client } from "./client";
2
+
5
3
import { Agent } from "@atproto/api";
4
+
import { COOKIE_SECRET } from "@tealfmbot/common/constants.ts";
6
5
import { logger } from "@tealfmbot/common/logger.js";
6
+
import { deleteCookie, generateSignedCookie, getSignedCookie } from "hono/cookie";
7
+
8
+
import { client } from "./client";
7
9
8
10
export const MAX_AGE = process.env.NODE_ENV === "production" ? 60 : 0;
9
11
···
19
21
}
20
22
21
23
export async function getSessionAgent(c: Context) {
22
-
c.header("Vary", "Cookie")
23
-
const session = await getSignedCookie(c, COOKIE_SECRET, "__teal_fm_bot_session")
24
+
c.header("Vary", "Cookie");
25
+
const session = await getSignedCookie(c, COOKIE_SECRET, "__teal_fm_bot_session");
24
26
if (!session) return null;
25
-
c.header("Cache-Control", `max-age=${MAX_AGE}, private`)
27
+
c.header("Cache-Control", `max-age=${MAX_AGE}, private`);
26
28
27
29
try {
28
-
const oauthSession = await client.restore(session)
29
-
return oauthSession ? new Agent(oauthSession) : null
30
+
const oauthSession = await client.restore(session);
31
+
return oauthSession ? new Agent(oauthSession) : null;
30
32
} catch {
31
-
logger.warn("oauth restore failed")
32
-
deleteCookie(c, "__teal_fm_bot_session")
33
+
logger.warn("oauth restore failed");
34
+
deleteCookie(c, "__teal_fm_bot_session");
33
35
return null;
34
36
}
35
37
}