155 lines
4.1 KiB
TypeScript
155 lines
4.1 KiB
TypeScript
import {
|
|
createMiddleware,
|
|
createServerFn,
|
|
createServerOnlyFn,
|
|
} from "@tanstack/react-start";
|
|
import { getRequest } from "@tanstack/react-start/server";
|
|
import { Logger } from "@/lib/logger";
|
|
import { isAdminRole } from "@/features/core/utils/roles";
|
|
import z from "zod";
|
|
|
|
const logger = new Logger("Middleware");
|
|
|
|
export const PUBLIC_ROUTES = ["/login", "/logout", "/refresh-session"];
|
|
|
|
export const getSessionContext = createServerOnlyFn(
|
|
async (request: Request, options?: { isServerFunction?: boolean }) => {
|
|
const { getSessionContextCore } = await import("./supertokens-core.server");
|
|
return getSessionContextCore(request, options);
|
|
}
|
|
);
|
|
|
|
export const superTokensRequestMiddleware = createMiddleware({
|
|
type: "request",
|
|
}).server(async ({ next, request }) => {
|
|
const context = await getSessionContext(request);
|
|
return next({ context });
|
|
});
|
|
|
|
export const superTokensOptionalRequestMiddleware = createMiddleware({
|
|
type: "request",
|
|
}).server(async ({ next, request }) => {
|
|
type SessionContext = Awaited<ReturnType<typeof getSessionContext>>;
|
|
let context: SessionContext;
|
|
try {
|
|
context = await getSessionContext(request);
|
|
} catch {
|
|
context = {
|
|
userAuthId: null,
|
|
roles: [],
|
|
metadata: undefined,
|
|
phone: undefined,
|
|
player: null,
|
|
} as unknown as SessionContext;
|
|
}
|
|
return next({ context });
|
|
});
|
|
|
|
export const superTokensFunctionMiddleware = createMiddleware({
|
|
type: "function",
|
|
}).server(async ({ next }) => {
|
|
const request = getRequest();
|
|
|
|
try {
|
|
const context = await getSessionContext(request, { isServerFunction: true });
|
|
return next({ context });
|
|
} catch (error: any) {
|
|
if (error.message === "SESSION_REFRESH_REQUIRED") {
|
|
throw new Response(
|
|
JSON.stringify({
|
|
error: "SESSION_REFRESH_REQUIRED",
|
|
message: "Session needs to be refreshed"
|
|
}),
|
|
{
|
|
status: 401,
|
|
headers: { "Content-Type": "application/json" }
|
|
}
|
|
);
|
|
}
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
export const superTokensAdminFunctionMiddleware = createMiddleware({
|
|
type: "function",
|
|
}).server(async ({ next, serverFnMeta }) => {
|
|
const request = getRequest();
|
|
|
|
try {
|
|
const context = await getSessionContext(request, { isServerFunction: true });
|
|
|
|
if (isAdminRole(context.roles)) {
|
|
return next({ context });
|
|
}
|
|
|
|
logger.error("Unauthorized user in admin function.", {
|
|
userAuthId: context.userAuthId,
|
|
roles: context.roles,
|
|
});
|
|
const { recordDeniedServerFn } = await import("./activities");
|
|
recordDeniedServerFn(request, context.metadata, serverFnMeta);
|
|
throw new Error("Unauthorized");
|
|
} catch (error: any) {
|
|
if (error.message === "SESSION_REFRESH_REQUIRED") {
|
|
throw new Response(
|
|
JSON.stringify({
|
|
error: "SESSION_REFRESH_REQUIRED",
|
|
message: "Session needs to be refreshed"
|
|
}),
|
|
{
|
|
status: 401,
|
|
headers: { "Content-Type": "application/json" }
|
|
}
|
|
);
|
|
}
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
export const setUserMetadata = createServerFn({ method: "POST" })
|
|
.validator(
|
|
z
|
|
.object({
|
|
first_name: z
|
|
.string()
|
|
.min(2)
|
|
.max(20)
|
|
.regex(
|
|
/^[a-zA-Z0-9\s]+$/,
|
|
"First name must be 2-20 characters long and contain only letters and spaces"
|
|
),
|
|
last_name: z
|
|
.string()
|
|
.min(2)
|
|
.max(20)
|
|
.regex(
|
|
/^[a-zA-Z0-9\s]+$/,
|
|
"Last name must be 2-20 characters long and contain only letters and spaces"
|
|
),
|
|
player_id: z.string(),
|
|
})
|
|
.partial()
|
|
)
|
|
.middleware([superTokensFunctionMiddleware])
|
|
.handler(async ({ context, data }) => {
|
|
const { userAuthId, metadata } = context;
|
|
if (!userAuthId) return;
|
|
|
|
const { updateUserMetadataFields } = await import(
|
|
"./supertokens-core.server"
|
|
);
|
|
|
|
await updateUserMetadataFields(userAuthId, {
|
|
first_name: data.first_name,
|
|
last_name: data.last_name,
|
|
player_id: data.player_id,
|
|
});
|
|
|
|
return {
|
|
metadata: {
|
|
...metadata,
|
|
...data,
|
|
},
|
|
};
|
|
});
|