GWM : server code rearranged
This commit is contained in:
parent
de5c505e01
commit
4f5ecedb8f
168
server.js
168
server.js
@ -1,6 +1,6 @@
|
||||
const express = require("express");
|
||||
const cors = require("cors");
|
||||
const helmet = require("helmet");
|
||||
const helmet = require("helmet");
|
||||
const morgan = require("morgan");
|
||||
const swaggerUi = require("swagger-ui-express");
|
||||
const swaggerJsdoc = require("swagger-jsdoc");
|
||||
@ -17,30 +17,42 @@ require("dotenv").config();
|
||||
const csrf = require("csurf");
|
||||
|
||||
const isProd = process.env.NODE_ENV === "production";
|
||||
const isLocal = process.env.NODE_ENV === "development";
|
||||
|
||||
/**
|
||||
* =========================
|
||||
* CSRF CONFIG (CORRECT)
|
||||
* =========================
|
||||
*/
|
||||
const csrfProtection = csrf({
|
||||
cookie: {
|
||||
key: "_csrf",
|
||||
httpOnly: true, // always true
|
||||
secure: isProd, // true only in production (HTTPS)
|
||||
sameSite: isProd ? "none" : "lax",
|
||||
// prod: cross-domain frontend → backend
|
||||
// dev : localhost friendly
|
||||
httpOnly: true,
|
||||
secure: isProd, // HTTPS in UAT/PROD
|
||||
sameSite: isProd ? "none" : "lax",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const app = express();
|
||||
|
||||
// REQUIRED for HSTS when behind proxy (AWS ALB / Nginx / Cloudflare)
|
||||
/**
|
||||
* REQUIRED for HSTS when behind proxy
|
||||
*/
|
||||
app.set("trust proxy", 1);
|
||||
|
||||
// GLOBAL MIDDLEWARE (body parsing)
|
||||
/**
|
||||
* =========================
|
||||
* GLOBAL MIDDLEWARE
|
||||
* =========================
|
||||
*/
|
||||
app.use(express.json());
|
||||
app.use(cookieParser());
|
||||
|
||||
const isLocal = process.env.NODE_ENV === "development";
|
||||
|
||||
/**
|
||||
* =========================
|
||||
* HELMET + SECURITY HEADERS
|
||||
* =========================
|
||||
*/
|
||||
app.use(
|
||||
helmet({
|
||||
contentSecurityPolicy: {
|
||||
@ -76,54 +88,64 @@ if (!isLocal) {
|
||||
app.use(morgan("dev"));
|
||||
app.use(sanitizeInput);
|
||||
|
||||
/**
|
||||
* =========================
|
||||
* CORS
|
||||
* =========================
|
||||
*/
|
||||
const allowedOrigins = process.env.ALLOWED_ORIGINS
|
||||
? process.env.ALLOWED_ORIGINS.split(",").map(origin => origin.trim())
|
||||
? process.env.ALLOWED_ORIGINS.split(",").map(o => o.trim())
|
||||
: [];
|
||||
app.use(cors({
|
||||
origin: allowedOrigins,
|
||||
credentials: true
|
||||
}));
|
||||
|
||||
console.log("is production = " + process.env.NODE_ENV === "production");
|
||||
console.log("allowedOrigins = " + allowedOrigins);
|
||||
app.use(
|
||||
cors({
|
||||
origin: allowedOrigins,
|
||||
credentials: true,
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* Manual headers (kept as-is, but fixed OPTIONS flow)
|
||||
*/
|
||||
app.use((req, res, next) => {
|
||||
console.log("Origin from header = " + req.headers.origin);
|
||||
if (allowedOrigins.includes(req.headers.origin)) {
|
||||
console.log("Origin set = " + req.headers.origin);
|
||||
res.header("Access-Control-Allow-Origin", req.headers.origin);
|
||||
}
|
||||
|
||||
res.header("Access-Control-Allow-Credentials", "true");
|
||||
res.header(
|
||||
"Access-Control-Allow-Headers",
|
||||
"Content-Type, Authorization, APP_SIGNATURE, x-app-signature"
|
||||
"Content-Type, Authorization, APP_SIGNATURE, x-app-signature, X-CSRF-Token"
|
||||
);
|
||||
res.header(
|
||||
"Access-Control-Allow-Methods",
|
||||
"GET, POST, PUT, PATCH, DELETE, OPTIONS"
|
||||
);
|
||||
|
||||
// ⚠️ IMPORTANT: DO NOT TERMINATE REQUEST HERE
|
||||
if (req.method === "OPTIONS") {
|
||||
return res.sendStatus(200);
|
||||
return next();
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// Swagger setup
|
||||
/**
|
||||
* =========================
|
||||
* SWAGGER
|
||||
* =========================
|
||||
*/
|
||||
const swaggerOptions = {
|
||||
definition: {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "FCSC IPI Survey",
|
||||
version: "1.0.0",
|
||||
description: "Federal Competitiveness and Statistics Centre (FCSC) - Industrial Production Index (IPI)",
|
||||
description:
|
||||
"Federal Competitiveness and Statistics Centre (FCSC) - Industrial Production Index (IPI)",
|
||||
},
|
||||
components: {
|
||||
securitySchemes: {
|
||||
// Optional: Still support Bearer for Swagger-only testing
|
||||
bearerAuth: {
|
||||
type: "http",
|
||||
scheme: "bearer",
|
||||
@ -132,8 +154,13 @@ const swaggerOptions = {
|
||||
appSignature: {
|
||||
type: "apiKey",
|
||||
in: "header",
|
||||
name: "x-app-signature"
|
||||
}
|
||||
name: "x-app-signature",
|
||||
},
|
||||
csrfToken: {
|
||||
type: "apiKey",
|
||||
in: "header",
|
||||
name: "X-CSRF-Token",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -147,26 +174,32 @@ app.use(
|
||||
swaggerUi.serve,
|
||||
swaggerUi.setup(swaggerDocs, {
|
||||
swaggerOptions: {
|
||||
withCredentials: true, // 🔥 VERY IMPORTANT
|
||||
withCredentials: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
// Routes
|
||||
/**
|
||||
* --------------------
|
||||
* =========================
|
||||
* AUTH (NO CSRF)
|
||||
* --------------------
|
||||
* =========================
|
||||
*/
|
||||
app.post("/api/auth/login",[verifySignature], authController.login);
|
||||
app.post("/api/forgot-password/request-otp",[verifySignature], establishmentController.forgotPasswordRequestOTP);
|
||||
app.post("/api/forgot-password/verify-otp",[verifySignature], establishmentController.forgotPasswordVerifyOTP);
|
||||
app.post("/api/auth/login", [verifySignature], authController.login);
|
||||
app.post(
|
||||
"/api/forgot-password/request-otp",
|
||||
[verifySignature],
|
||||
establishmentController.forgotPasswordRequestOTP
|
||||
);
|
||||
app.post(
|
||||
"/api/forgot-password/verify-otp",
|
||||
[verifySignature],
|
||||
establishmentController.forgotPasswordVerifyOTP
|
||||
);
|
||||
|
||||
/**
|
||||
* --------------------
|
||||
* =========================
|
||||
* CSRF TOKEN ENDPOINT
|
||||
* --------------------
|
||||
* =========================
|
||||
*/
|
||||
app.get("/api/csrf-token", csrfProtection, (req, res) => {
|
||||
res.status(200).json({
|
||||
@ -175,17 +208,28 @@ app.get("/api/csrf-token", csrfProtection, (req, res) => {
|
||||
});
|
||||
|
||||
/**
|
||||
* --------------------
|
||||
* PROTECTED ROUTES (CSRF REQUIRED)
|
||||
* --------------------
|
||||
* =========================
|
||||
* ENFORCE CSRF FOR STATE-CHANGING REQUESTS
|
||||
* =========================
|
||||
*/
|
||||
app.use("/api", csrfProtection, routes);
|
||||
// app.use("/api", routes);
|
||||
app.use((req, res, next) => {
|
||||
if (["GET", "HEAD", "OPTIONS"].includes(req.method)) {
|
||||
return next();
|
||||
}
|
||||
return csrfProtection(req, res, next);
|
||||
});
|
||||
|
||||
/**
|
||||
* --------------------
|
||||
* =========================
|
||||
* PROTECTED ROUTES
|
||||
* =========================
|
||||
*/
|
||||
app.use("/api", routes);
|
||||
|
||||
/**
|
||||
* =========================
|
||||
* CSRF ERROR HANDLER
|
||||
* --------------------
|
||||
* =========================
|
||||
*/
|
||||
app.use((err, req, res, next) => {
|
||||
if (err.code === "EBADCSRFTOKEN") {
|
||||
@ -197,28 +241,28 @@ app.use((err, req, res, next) => {
|
||||
next(err);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
apis: [path.join(__dirname, "app/routes/*.js")],
|
||||
|
||||
/**
|
||||
* =========================
|
||||
* TEST ROUTE
|
||||
* =========================
|
||||
*/
|
||||
app.get("/api/test", (req, res) => {
|
||||
res.json({ status: "success", message: "Test API working fine 🚀" });
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
//deployment route
|
||||
/**
|
||||
* =========================
|
||||
* DEPLOYMENT ROUTE
|
||||
* =========================
|
||||
*/
|
||||
const deploymentController = require("./app/controllers/deployment.controller");
|
||||
app.post("/deploy", deploymentController.deployment);
|
||||
|
||||
// Sync DB
|
||||
// db.sequelize.sync({ alter: true }).then(() => {
|
||||
// console.log("✅ Database connected & synced.");
|
||||
// });
|
||||
|
||||
// Start server
|
||||
/**
|
||||
* =========================
|
||||
* START SERVER
|
||||
* =========================
|
||||
*/
|
||||
const PORT = process.env.PORT || 5000;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`🚀 Server running on port ${PORT}`);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user