Switch to internally managed roles, adapt frontend
This commit is contained in:
@@ -35,89 +35,88 @@ const homepage = new Response(Bun.file(path.join(FRONTEND_ROOT, "index.html")));
|
||||
|
||||
const databaseLayer = Database.FromPath(config.DB_PATH);
|
||||
|
||||
const login = (code: string | null, state: string | null) => Effect.gen(function* () {
|
||||
const { sessionId } = yield* Authentication.Authentication;
|
||||
const db = yield* Database.Database;
|
||||
|
||||
const session = yield* db
|
||||
.selectFrom("Session")
|
||||
.select(["codeVerifier"])
|
||||
.where("sessionId", "=", sessionId)
|
||||
.$call(Database.executeTakeFirst);
|
||||
|
||||
const codeVerifier = Option.fromNullable(session.codeVerifier);
|
||||
|
||||
if (code !== null && state !== null && Option.isSome(codeVerifier)) {
|
||||
const res = yield* fetch(config.OAUTH_TOKEN_ENDPOINT, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
"client_id": config.CLIENT_ID,
|
||||
"code": code,
|
||||
"redirect_uri": Authentication.REDIRECT_URI,
|
||||
"grant_type": "authorization_code",
|
||||
"code_verifier": codeVerifier.value,
|
||||
"client_secret": Redacted.value(config.CLIENT_SECRET),
|
||||
}).toString(),
|
||||
});
|
||||
|
||||
const body = yield* Body.json(res);
|
||||
const { id_token: idToken } = body as { id_token: string };
|
||||
const idTokenPayload = yield* pipe(
|
||||
idToken,
|
||||
Authentication.getJwtTokenPayload(Authentication.IdTokenPayload),
|
||||
);
|
||||
|
||||
const { userId } = yield* Authentication.upsertUser(idTokenPayload);
|
||||
|
||||
yield* db
|
||||
.updateTable("Session")
|
||||
.set({
|
||||
codeVerifier: null,
|
||||
state: null,
|
||||
userId,
|
||||
})
|
||||
.where("sessionId", "=", sessionId)
|
||||
.$call(Database.execute);
|
||||
}
|
||||
});
|
||||
|
||||
Bun.serve({
|
||||
routes: {
|
||||
...assetRoutes,
|
||||
"/login": {
|
||||
GET: async (req) => {
|
||||
const res = await pipe(
|
||||
GET: (req) => Effect.gen(function* () {
|
||||
const searchParams = new URL(req.url).searchParams;
|
||||
if (searchParams.has("code") || searchParams.has("state")) {
|
||||
const code = searchParams.get("code");
|
||||
const state = searchParams.get("state");
|
||||
|
||||
yield* login(code, state);
|
||||
|
||||
return Response.redirect(config.NODE_ENV === "production" ? `https://${config.HOSTNAME}/` : "http://localhost:5173/", 303);
|
||||
}
|
||||
|
||||
const res = yield* pipe(
|
||||
Authentication.Authentication,
|
||||
Effect.flatMap(({ sessionId }) => Authentication.makeAuthorizationUrl({
|
||||
external: new URL(req.url).searchParams.has("external"),
|
||||
sessionId,
|
||||
})),
|
||||
Effect.flatMap(({ sessionId }) => Authentication.makeAuthorizationUrl(sessionId)),
|
||||
Effect.map((url) => Response.redirect(url)),
|
||||
Effect.provide(Layer.provideMerge(Authentication.Live(req), databaseLayer)),
|
||||
Effect.runPromise,
|
||||
);
|
||||
|
||||
return res;
|
||||
},
|
||||
}).pipe(
|
||||
Effect.provide(Layer.provideMerge(Authentication.Live(req), databaseLayer)),
|
||||
Effect.runPromise,
|
||||
),
|
||||
POST: (req) => Effect.gen(function* () {
|
||||
const { sessionId } = yield* Authentication.Authentication;
|
||||
const db = yield* Database.Database;
|
||||
|
||||
const data = yield* Body.formData(req);
|
||||
|
||||
const code = data.get("code") as string | null;
|
||||
const state = data.get("state") as string | null;
|
||||
|
||||
const session = yield* db
|
||||
.selectFrom("Session")
|
||||
.select(["external", "codeVerifier"])
|
||||
.where("sessionId", "=", sessionId)
|
||||
.$call(Database.executeTakeFirst);
|
||||
|
||||
const external = pipe(
|
||||
session.external,
|
||||
Option.fromNullable,
|
||||
Option.map((external) => external !== 0),
|
||||
);
|
||||
|
||||
const codeVerifier = Option.fromNullable(session.codeVerifier);
|
||||
|
||||
if (code !== null && state !== null && Option.isSome(external) && Option.isSome(codeVerifier)) {
|
||||
const { tokenEndpoint } = external.value
|
||||
? Authentication.EXTERNAL_OAUTH_CONFIGURATION
|
||||
: Authentication.INTERNAL_OAUTH_CONFIGURATION;
|
||||
|
||||
const res = yield* fetch(tokenEndpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
"client_id": config.CLIENT_ID,
|
||||
"code": code,
|
||||
"redirect_uri": Authentication.REDIRECT_URI,
|
||||
"grant_type": "authorization_code",
|
||||
"code_verifier": codeVerifier.value,
|
||||
"client_secret": Redacted.value(config.CLIENT_SECRET),
|
||||
}).toString(),
|
||||
});
|
||||
|
||||
const {
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken,
|
||||
id_token: idToken,
|
||||
} = (yield* Body.json(res)) as {
|
||||
access_token: string,
|
||||
refresh_token: string,
|
||||
id_token: string,
|
||||
};
|
||||
|
||||
yield* db
|
||||
.updateTable("Session")
|
||||
.set({
|
||||
accessToken,
|
||||
refreshToken,
|
||||
idToken,
|
||||
codeVerifier: null,
|
||||
state: null,
|
||||
})
|
||||
.where("sessionId", "=", sessionId)
|
||||
.$call(Database.execute);
|
||||
}
|
||||
yield* login(code, state);
|
||||
|
||||
return Response.redirect(config.NODE_ENV === "production" ? `https://${config.HOSTNAME}/` : "http://localhost:5173/", 303);
|
||||
}).pipe(
|
||||
|
||||
Reference in New Issue
Block a user