diff --git a/config/config.example.yml b/config/config.example.yml index e779f36b..b226969a 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -4,11 +4,12 @@ app: base_url: http://localhost:3000 log_level: debug save_logs: "false" - secure_cookies: "false" server: external_port: "3000" internal_port: "3001" + internal_hostname: localhost + secure_cookies: "false" rate_limit: window_minutes: "1" diff --git a/server/auth/index.ts b/server/auth/index.ts index d33b94be..b6886f82 100644 --- a/server/auth/index.ts +++ b/server/auth/index.ts @@ -24,13 +24,9 @@ export const lucia = new Lucia(adapter, { expires: false, attributes: { sameSite: "strict", - secure: config.app.secure_cookies || false, + secure: config.server.secure_cookies || false, domain: - "." + - config.app.external_base_url - .split("://")[1] - .split(":")[0] - .split("/")[0], + "." + new URL(config.app.base_url).hostname.split(".").slice(-2).join("."), }, }, sessionExpiresIn: new TimeSpan(2, "w"), diff --git a/server/config.ts b/server/config.ts index 0f20f94f..13c684a5 100644 --- a/server/config.ts +++ b/server/config.ts @@ -10,11 +10,9 @@ const environmentSchema = z.object({ app: z.object({ name: z.string(), environment: z.enum(["dev", "prod"]), - external_base_url: z.string().url(), - internal_base_url: z.string().url(), + base_url: z.string().url(), log_level: z.enum(["debug", "info", "warn", "error"]), save_logs: z.string().transform((val) => val === "true"), - secure_cookies: z.string().transform((val) => val === "true"), }), server: z.object({ external_port: z @@ -25,6 +23,8 @@ const environmentSchema = z.object({ .string() .transform((val) => parseInt(val, 10)) .pipe(z.number()), + internal_hostname: z.string(), + secure_cookies: z.string().transform((val) => val === "true"), }), rate_limit: z.object({ window_minutes: z @@ -71,9 +71,19 @@ const loadConfig = (configPath: string) => { } }; -const configFilePath = path.join(APP_PATH, "config.yml"); +const configFilePath1 = path.join(APP_PATH, "config.yml"); +const configFilePath2 = path.join(APP_PATH, "config.yaml"); -const environment = loadConfig(configFilePath); +let environment: any; +if (fs.existsSync(configFilePath1)) { + environment = loadConfig(configFilePath1); +} else if (fs.existsSync(configFilePath2)) { + environment = loadConfig(configFilePath2); +} + +if (!environment) { + throw new Error("No configuration file found"); +} const parsedConfig = environmentSchema.safeParse(environment); @@ -82,4 +92,13 @@ if (!parsedConfig.success) { throw new Error(`Invalid configuration file: ${errors}`); } +process.env.NEXT_PUBLIC_EXTERNAL_API_BASE_URL = new URL( + "/api/v1", + parsedConfig.data.app.base_url, +).href; +process.env.NEXT_PUBLIC_INTERNAL_API_BASE_URL = new URL( + "/api/v1", + `http://${parsedConfig.data.server.internal_hostname}:${parsedConfig.data.server.external_port}`, +).href; + export default parsedConfig.data; diff --git a/server/index.ts b/server/index.ts index 6f9488bb..bebe581d 100644 --- a/server/index.ts +++ b/server/index.ts @@ -1,7 +1,7 @@ +import config from "@server/config"; import express, { Request, Response } from "express"; import next from "next"; import { parse } from "url"; -import config from "@server/config"; import logger from "@server/logger"; import helmet from "helmet"; import cors from "cors"; diff --git a/server/routers/auth/login.ts b/server/routers/auth/login.ts index e8500288..df24b34d 100644 --- a/server/routers/auth/login.ts +++ b/server/routers/auth/login.ts @@ -118,7 +118,7 @@ export async function login( const session = await lucia.createSession(existingUser.id, {}); const cookie = lucia.createSessionCookie(session.id).serialize(); - logger.debug("Session cookie", JSON.stringify(cookie, null, 2)); + res.appendHeader( "Set-Cookie", cookie diff --git a/server/routers/traefik/getTraefikConfig.ts b/server/routers/traefik/getTraefikConfig.ts index ca239637..cab58c8a 100644 --- a/server/routers/traefik/getTraefikConfig.ts +++ b/server/routers/traefik/getTraefikConfig.ts @@ -37,7 +37,10 @@ export function buildTraefikConfig( [middlewareName]: { plugin: { [middlewareName]: { - apiBaseUrl: config.app.internal_base_url, + apiBaseUrl: new URL( + "/api/v1", + `http://${config.server.internal_hostname}:${config.server.internal_port}`, + ).href, }, }, }, diff --git a/server/routers/user/getUser.ts b/server/routers/user/getUser.ts index 11dd428f..bbec51ad 100644 --- a/server/routers/user/getUser.ts +++ b/server/routers/user/getUser.ts @@ -1,24 +1,36 @@ -import { Request, Response, NextFunction } from 'express'; -import { z } from 'zod'; -import { db } from '@server/db'; -import { users } from '@server/db/schema'; -import { eq } from 'drizzle-orm'; +import { Request, Response, NextFunction } from "express"; +import { z } from "zod"; +import { db } from "@server/db"; +import { users } from "@server/db/schema"; +import { eq } from "drizzle-orm"; import response from "@server/utils/response"; -import HttpCode from '@server/types/HttpCode'; -import createHttpError from 'http-errors'; -import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions'; -import logger from '@server/logger'; +import HttpCode from "@server/types/HttpCode"; +import createHttpError from "http-errors"; +import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions"; +import logger from "@server/logger"; +export type GetUserResponse = { + email: string; + twoFactorEnabled: boolean; + emailVerified: boolean; +}; -export async function getUser(req: Request, res: Response, next: NextFunction): Promise { +export async function getUser( + req: Request, + res: Response, + next: NextFunction, +): Promise { try { const userId = req.user?.id; - + if (!userId) { - return next(createHttpError(HttpCode.UNAUTHORIZED, "User not found")); + return next( + createHttpError(HttpCode.UNAUTHORIZED, "User not found"), + ); } - const user = await db.select() + const user = await db + .select() .from(users) .where(eq(users.id, userId)) .limit(1); @@ -27,16 +39,16 @@ export async function getUser(req: Request, res: Response, next: NextFunction): return next( createHttpError( HttpCode.NOT_FOUND, - `User with ID ${userId} not found` - ) + `User with ID ${userId} not found`, + ), ); } - return response(res, { + return response(res, { data: { email: user[0].email, twoFactorEnabled: user[0].twoFactorEnabled, - emailVerified: user[0].emailVerified + emailVerified: user[0].emailVerified, }, success: true, error: false, @@ -45,6 +57,11 @@ export async function getUser(req: Request, res: Response, next: NextFunction): }); } catch (error) { logger.error(error); - return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred...")); + return next( + createHttpError( + HttpCode.INTERNAL_SERVER_ERROR, + "An error occurred...", + ), + ); } }