+37
-11
apps/web/index.ts
+37
-11
apps/web/index.ts
···
2
2
import { COOKIE_SECRET } from "@tealfmbot/common/constants.js";
3
3
import { logger } from "@tealfmbot/common/logger.js";
4
4
import { Hono } from "hono";
5
-
import { getSignedCookie } from "hono/cookie";
5
+
import { deleteCookie, getSignedCookie } from "hono/cookie";
6
6
import { html } from "hono/html";
7
7
import { validator } from "hono/validator";
8
8
import pinoHttpLogger from "pino-http";
9
9
10
10
import { client } from "./client";
11
-
import { createSession, MAX_AGE, validateIdentifier } from "./utils";
11
+
import { createSession, getSessionAgent, MAX_AGE, validateIdentifier } from "./utils";
12
12
13
13
type Variables = {
14
14
logger: typeof logger;
···
32
32
return c.text("yo!!");
33
33
});
34
34
35
+
app.get("/dashboard", async (c) => {
36
+
const agent = await getSessionAgent(c);
37
+
if (agent?.assertAuthenticated()) {
38
+
return c.redirect("/login");
39
+
}
40
+
return c.html(html`
41
+
<h1>Dashboard</h1>
42
+
<p>DID: ${agent?.assertDid}</p>
43
+
<form method="post" action="/logout">
44
+
<button type="submit">Log out</button>
45
+
</form>
46
+
`);
47
+
});
48
+
35
49
app.get("/health", (c) => {
36
50
return c.json({ message: "OK" }, 200);
37
51
});
···
61
75
}
62
76
}
63
77
const oauth = await client.callback(params);
64
-
await createSession(oauth.session.did);
78
+
const cookie = await createSession(oauth.session.did);
79
+
c.header("Set-Cookie", cookie);
65
80
} catch (error) {
66
81
logger.error({ error }, "oauth callback failed");
67
82
}
68
83
69
-
return c.redirect("/");
84
+
return c.redirect("/dashboard");
70
85
});
71
86
72
87
app.get("/login", (c) => {
···
98
113
const { identifier } = c.req.valid("form");
99
114
const ac = new AbortController();
100
115
try {
101
-
// if (identifier.startsWith("did:web")) {
102
-
// const id = identifier.split(":")[2]
103
-
// const url = await client.authorize(identifier, {
104
-
// signal: ac.signal
105
-
// })
106
-
// }
107
116
const url = await client.authorize(identifier, {
108
117
signal: ac.signal,
109
118
});
110
-
return c.redirect(url.href);
119
+
return c.redirect(url.href.toString());
111
120
} catch (error) {
112
121
logger.error({ error }, "oauth authorize failed");
113
122
return c.json({ message: "oauth authorize failed" }, 500);
114
123
}
115
124
},
116
125
);
126
+
127
+
app.post("/logout", async (c) => {
128
+
c.header("Cache-Control", "no-store");
129
+
const session = await getSignedCookie(c, COOKIE_SECRET, "__teal_fm_bot_session");
130
+
if (session) {
131
+
try {
132
+
const oauthSession = await client.restore(session);
133
+
if (oauthSession) await oauthSession.signOut();
134
+
} catch (error) {
135
+
logger.warn({ error }, "Failed to revoke credentials");
136
+
}
137
+
}
138
+
139
+
deleteCookie(c, "__teal_fm_bot_session");
140
+
141
+
return c.redirect("/login");
142
+
});
117
143
118
144
const server = serve({
119
145
fetch: app.fetch,
+1
-1
apps/web/utils.ts
+1
-1
apps/web/utils.ts
···
14
14
export async function createSession(value: string) {
15
15
const cookie = await generateSignedCookie("__teal_fm_bot_session", value, COOKIE_SECRET, {
16
16
path: "/",
17
-
secure: process.env.NODE_ENV === "development" ? false : true,
17
+
secure: process.env.NODE_ENV === "production",
18
18
httpOnly: true,
19
19
sameSite: "lax",
20
20
maxAge: 60 * 60 * 24 * 7,