update:deploy

This commit is contained in:
2026-03-10 00:38:50 +09:00
parent a2c714abef
commit 721110d5dd
2 changed files with 62 additions and 29 deletions

View File

@@ -1,49 +1,61 @@
import Fastify from 'fastify' import Fastify from "fastify";
import cors from '@fastify/cors' import cors from "@fastify/cors";
import cookie from '@fastify/cookie' import cookie from "@fastify/cookie";
import session from '@fastify/session' import session from "@fastify/session";
import csrf from '@fastify/csrf-protection' import csrf from "@fastify/csrf-protection";
import { authMiddleware } from './middleware/auth.js' import { authMiddleware } from "./middleware/auth.js";
import { storageMiddleware } from './middleware/storage.js' import { storageMiddleware } from "./middleware/storage.js";
import { ticketsRouter } from './routes/tickets.js' import { ticketsRouter } from "./routes/tickets.js";
import { authRouter } from './routes/auth.js' import { authRouter } from "./routes/auth.js";
import { SqliteSessionStore } from './db/sessionStore.js' import { SqliteSessionStore } from "./db/sessionStore.js";
import { cloudflareMiddleware } from "./middleware/cloudflare.js";
const isProd = process.env.NODE_ENV === 'production' const isProd = process.env.NODE_ENV === "production";
const app = Fastify({ logger: true }) const sessionSecret = process.env.SESSION_SECRET;
if (!sessionSecret) throw new Error("SESSION_SECRET env var is required");
const app = Fastify({
// In prod: warn-level only to reduce noise; in dev: full pretty logging
logger: isProd ? { level: "warn" } : true,
// Trust the nginx reverse proxy so secure cookies and req.ip work correctly
trustProxy: isProd,
});
await app.register(cors, { await app.register(cors, {
methods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'], methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
origin: process.env.FRONTEND_URL ?? 'http://localhost:5173', origin: process.env.FRONTEND_URL ?? "http://localhost:5173",
credentials: true, credentials: true,
}) });
await app.register(cookie) await app.register(cookie);
await app.register(session, { await app.register(session, {
secret: process.env.SESSION_SECRET!, secret: sessionSecret,
store: new SqliteSessionStore(), // ← persistent SQLite store store: new SqliteSessionStore(), // ← persistent SQLite store
cookie: { cookie: {
httpOnly: true, httpOnly: true,
secure: isProd, // HTTPS-only in production secure: isProd, // HTTPS-only in production
sameSite: isProd ? 'strict' : 'lax', // strict in prod, lax in dev sameSite: isProd ? "strict" : "lax", // strict in prod, lax in dev
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days in ms maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days in ms
}, },
saveUninitialized: false, saveUninitialized: false,
}) });
if (isProd) { if (isProd) {
await app.register(csrf, { await app.register(csrf, {
sessionPlugin: '@fastify/session', sessionPlugin: "@fastify/session",
}) });
} }
await app.register(authMiddleware) await app.register(authMiddleware);
await app.register(storageMiddleware) await app.register(storageMiddleware);
if (isProd) {
await app.register(cloudflareMiddleware);
}
await app.register(authRouter, { prefix: '/api/auth' }) await app.register(authRouter, { prefix: "/api/auth" });
await app.register(ticketsRouter, { prefix: '/api/tickets' }) await app.register(ticketsRouter, { prefix: "/api/tickets" });
await app.listen({ port: 4500, host: 'localhost' }) await app.listen({ port: 4500, host: process.env.HOST ?? "localhost" });

View File

@@ -0,0 +1,21 @@
import fp from "fastify-plugin";
import type { FastifyPluginAsync } from "fastify";
declare module "fastify" {
interface FastifyRequest {
// Real client IP resolved from CF-Connecting-IP in prod, req.ip in dev
clientIp: string;
}
}
export const cloudflareMiddleware: FastifyPluginAsync = fp(async (app) => {
app.decorateRequest("clientIp", "");
app.addHook("onRequest", async (req) => {
// CF-Connecting-IP is set by Cloudflare and cannot be spoofed by the client.
// X-Forwarded-For is not used here because it can be injected by anyone
// sending a request directly to the origin, bypassing Cloudflare.
const cfIp = req.headers["cf-connecting-ip"];
req.clientIp = (Array.isArray(cfIp) ? cfIp[0] : cfIp) ?? req.ip;
});
});