- Introduced the `@types/cookie-signature` dependency to facilitate proper signing of session cookies. - Updated session middleware to create a securely signed cookie using the session secret, improving session management for mobile applications. - Enhanced logging for cookie creation and error handling to aid in debugging session issues.
105 lines
3.8 KiB
TypeScript
105 lines
3.8 KiB
TypeScript
import session from "express-session";
|
|
import db from "../config/db";
|
|
import { isProduction } from "../shared/utils";
|
|
import * as cookieSignature from "cookie-signature";
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
const pgSession = require("connect-pg-simple")(session);
|
|
|
|
const sessionConfig = {
|
|
name: process.env.SESSION_NAME,
|
|
secret: process.env.SESSION_SECRET || "development-secret-key",
|
|
proxy: false,
|
|
resave: false,
|
|
saveUninitialized: true,
|
|
rolling: true,
|
|
store: new pgSession({
|
|
pool: db.pool,
|
|
tableName: "pg_sessions"
|
|
}),
|
|
cookie: {
|
|
path: "/",
|
|
httpOnly: true,
|
|
// For mobile app support, we might need these settings:
|
|
sameSite: isProduction() ? "none" as const : "lax" as const,
|
|
secure: isProduction(), // Required when sameSite is "none"
|
|
domain: isProduction() ? ".worklenz.com" : undefined,
|
|
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
|
|
},
|
|
// Custom session ID handling for mobile apps
|
|
genid: () => {
|
|
return require('uid-safe').sync(24);
|
|
}
|
|
};
|
|
|
|
console.log("Session configuration:", {
|
|
...sessionConfig,
|
|
secret: "[REDACTED]"
|
|
});
|
|
|
|
const sessionMiddleware = session(sessionConfig);
|
|
|
|
// Enhanced session middleware that supports both cookies and headers for mobile apps
|
|
export default (req: any, res: any, next: any) => {
|
|
// Check if mobile app is sending session ID via header (fallback for cookie issues)
|
|
const headerSessionId = req.headers['x-session-id'];
|
|
const headerSessionName = req.headers['x-session-name'];
|
|
|
|
console.log("Session middleware debug:");
|
|
console.log("- Cookie header:", req.headers.cookie);
|
|
console.log("- X-Session-ID header:", headerSessionId);
|
|
console.log("- X-Session-Name header:", headerSessionName);
|
|
|
|
if (headerSessionId && headerSessionName) {
|
|
console.log("Mobile app using header-based session:", headerSessionId);
|
|
|
|
// The problem is cookie signature - we need to create a properly signed cookie
|
|
const secret = process.env.SESSION_SECRET || "development-secret-key";
|
|
|
|
try {
|
|
// Create a signed cookie using the session secret
|
|
const signedSessionId = 's:' + cookieSignature.sign(headerSessionId, secret);
|
|
const encodedSignedId = encodeURIComponent(signedSessionId);
|
|
const sessionCookie = `${headerSessionName}=${encodedSignedId}`;
|
|
|
|
console.log("Creating signed session cookie:");
|
|
console.log("- Raw session ID:", headerSessionId);
|
|
console.log("- Signed session ID:", signedSessionId);
|
|
console.log("- Encoded signed ID:", encodedSignedId);
|
|
console.log("- Final cookie:", sessionCookie);
|
|
|
|
if (req.headers.cookie) {
|
|
// Replace existing session cookie while keeping other cookies
|
|
req.headers.cookie = req.headers.cookie
|
|
.split(';')
|
|
.filter((cookie: string) => !cookie.trim().startsWith(headerSessionName))
|
|
.concat(sessionCookie)
|
|
.join(';');
|
|
} else {
|
|
// Set the session cookie from header
|
|
req.headers.cookie = sessionCookie;
|
|
}
|
|
console.log("Updated cookie header:", req.headers.cookie);
|
|
} catch (error) {
|
|
console.log("Error creating signed cookie:", error);
|
|
// Fallback to the old method
|
|
const sessionCookie = `${headerSessionName}=s%3A${headerSessionId}`;
|
|
req.headers.cookie = sessionCookie;
|
|
}
|
|
}
|
|
|
|
sessionMiddleware(req, res, (err: any) => {
|
|
if (err) {
|
|
console.log("Session middleware error:", err);
|
|
}
|
|
|
|
// Debug what the session middleware produced
|
|
console.log("After session middleware:");
|
|
console.log("- Session ID:", (req as any).sessionID);
|
|
console.log("- Session data exists:", !!(req as any).session);
|
|
console.log("- Session passport data:", (req as any).session?.passport);
|
|
console.log("- Is authenticated:", !!(req as any).isAuthenticated && (req as any).isAuthenticated());
|
|
|
|
next(err);
|
|
});
|
|
}; |