cookies.ts 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import type { CookieOptions, Request } from "express";
  2. const LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "::1"]);
  3. function isIpAddress(host: string) {
  4. // Basic IPv4 check and IPv6 presence detection.
  5. if (/^\d{1,3}(\.\d{1,3}){3}$/.test(host)) return true;
  6. return host.includes(":");
  7. }
  8. function isSecureRequest(req: Request) {
  9. if (req.protocol === "https") return true;
  10. const forwardedProto = req.headers["x-forwarded-proto"];
  11. if (!forwardedProto) return false;
  12. const protoList = Array.isArray(forwardedProto)
  13. ? forwardedProto
  14. : forwardedProto.split(",");
  15. return protoList.some(proto => proto.trim().toLowerCase() === "https");
  16. }
  17. export function getSessionCookieOptions(
  18. req: Request
  19. ): Pick<CookieOptions, "domain" | "httpOnly" | "path" | "sameSite" | "secure"> {
  20. // const hostname = req.hostname;
  21. // const shouldSetDomain =
  22. // hostname &&
  23. // !LOCAL_HOSTS.has(hostname) &&
  24. // !isIpAddress(hostname) &&
  25. // hostname !== "127.0.0.1" &&
  26. // hostname !== "::1";
  27. // const domain =
  28. // shouldSetDomain && !hostname.startsWith(".")
  29. // ? `.${hostname}`
  30. // : shouldSetDomain
  31. // ? hostname
  32. // : undefined;
  33. const secure = isSecureRequest(req);
  34. // Scope the cookie to /chat/ so it is not sent to unrelated paths on the same domain.
  35. // Must match the Apache Alias base path for the chatbot.
  36. const basePath = process.env.COOKIE_BASE_PATH ?? "/";
  37. return {
  38. httpOnly: true,
  39. path: basePath,
  40. // SameSite=Lax is correct for same-site deployments (www.homelegance.com/chat/).
  41. // SameSite=None would require Secure=true which fails behind Apache proxy without trust-proxy config.
  42. sameSite: "lax",
  43. secure,
  44. };
  45. }