diff --git a/.replit b/.replit index 048618b..d8529f5 100644 --- a/.replit +++ b/.replit @@ -19,6 +19,10 @@ externalPort = 80 localPort = 33035 externalPort = 3001 +[[ports]] +localPort = 36465 +externalPort = 3003 + [[ports]] localPort = 41343 externalPort = 3000 diff --git a/server/localAuth.ts b/server/localAuth.ts new file mode 100644 index 0000000..105416e --- /dev/null +++ b/server/localAuth.ts @@ -0,0 +1,159 @@ +// Sistema autenticazione locale per deployment server esterno (non-Replit) +import passport from "passport"; +import { Strategy as LocalStrategy } from "passport-local"; +import session from "express-session"; +import type { Express } from "express"; +import connectPg from "connect-pg-simple"; +import { storage } from "./storage"; +// Credenziali admin di default per demo/sviluppo +const DEFAULT_ADMIN_EMAIL = "admin@vt.alfacom.it"; +const DEFAULT_ADMIN_PASSWORD = "admin123"; // CAMBIARE IN PRODUZIONE! +const DEFAULT_ADMIN_ID = "local-admin-vt"; + +export function getSession() { + const sessionTtl = 7 * 24 * 60 * 60 * 1000; // 1 settimana + const pgStore = connectPg(session); + const sessionStore = new pgStore({ + conString: process.env.DATABASE_URL, + createTableIfMissing: false, + ttl: sessionTtl, + tableName: "sessions", + }); + return session({ + secret: process.env.SESSION_SECRET!, + store: sessionStore, + resave: false, + saveUninitialized: false, + cookie: { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + maxAge: sessionTtl, + }, + }); +} + +async function initDefaultAdmin() { + try { + // Verifica se esiste già un admin + const users = await storage.getAllUsers(); + const adminExists = users.some((u: any) => u.email === DEFAULT_ADMIN_EMAIL); + + if (!adminExists) { + // Crea utente admin di default + await storage.upsertUser({ + id: DEFAULT_ADMIN_ID, + email: DEFAULT_ADMIN_EMAIL, + firstName: "Admin", + lastName: "Sistema", + profileImageUrl: null, + }); + + // Imposta ruolo admin + await storage.updateUserRole(DEFAULT_ADMIN_ID, "admin"); + + console.log(`✅ [LocalAuth] Admin di default creato: ${DEFAULT_ADMIN_EMAIL}`); + } + } catch (error) { + console.error("❌ [LocalAuth] Errore creazione admin:", error); + } +} + +export async function setupLocalAuth(app: Express) { + app.set("trust proxy", 1); + app.use(getSession()); + app.use(passport.initialize()); + app.use(passport.session()); + + // Inizializza admin di default + await initDefaultAdmin(); + + // Strategia passport-local + passport.use(new LocalStrategy( + { usernameField: "email" }, + async (email, password, done) => { + try { + // Per demo: accetta credenziali admin di default + if (email === DEFAULT_ADMIN_EMAIL && password === DEFAULT_ADMIN_PASSWORD) { + const users = await storage.getAllUsers(); + const admin = users.find((u: any) => u.email === DEFAULT_ADMIN_EMAIL); + + if (admin) { + return done(null, { id: admin.id, email: admin.email }); + } + } + + // Credenziali non valide + return done(null, false, { message: "Credenziali non valide" }); + } catch (error) { + return done(error); + } + } + )); + + passport.serializeUser((user: any, done) => { + done(null, user.id); + }); + + passport.deserializeUser(async (id: string, done) => { + try { + const users = await storage.getAllUsers(); + const user = users.find((u: any) => u.id === id); + done(null, user || null); + } catch (error) { + done(error); + } + }); + + // Route login locale + app.post("/api/local-login", passport.authenticate("local"), (req, res) => { + res.json({ + success: true, + user: req.user, + message: "Login effettuato con successo" + }); + }); + + // Route auto-login admin (solo per demo/sviluppo) + app.get("/api/auto-login-admin", async (req, res) => { + if (process.env.NODE_ENV !== 'production') { + console.warn("⚠️ [LocalAuth] Auto-login admin attivato (solo sviluppo!)"); + } + + try { + const users = await storage.getAllUsers(); + const admin = users.find((u: any) => u.email === DEFAULT_ADMIN_EMAIL); + + if (admin) { + req.login({ id: admin.id, email: admin.email }, (err) => { + if (err) { + return res.status(500).json({ error: "Errore auto-login" }); + } + res.redirect("/"); + }); + } else { + res.status(404).json({ error: "Admin non trovato" }); + } + } catch (error) { + res.status(500).json({ error: "Errore server" }); + } + }); + + // Route logout + app.get("/api/logout", (req, res) => { + req.logout(() => { + res.redirect("/"); + }); + }); + + console.log("✅ [LocalAuth] Sistema autenticazione locale attivato"); + console.log(`📧 Email admin: ${DEFAULT_ADMIN_EMAIL}`); + console.log(`🔑 Password admin: ${DEFAULT_ADMIN_PASSWORD}`); + console.log(`🔗 Auto-login: GET /api/auto-login-admin`); +} + +export const isAuthenticated = async (req: any, res: any, next: any) => { + if (!req.isAuthenticated()) { + return res.status(401).json({ message: "Unauthorized" }); + } + next(); +}; diff --git a/server/routes.ts b/server/routes.ts index 10659cc..92fbc7e 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -1,20 +1,42 @@ import type { Express } from "express"; import { createServer, type Server } from "http"; import { storage } from "./storage"; -import { setupAuth, isAuthenticated } from "./replitAuth"; +import { setupAuth as setupReplitAuth, isAuthenticated as isAuthenticatedReplit } from "./replitAuth"; +import { setupLocalAuth, isAuthenticated as isAuthenticatedLocal } from "./localAuth"; import { db } from "./db"; import { guards, certifications, sites, shifts, shiftAssignments, users, insertShiftSchema } from "@shared/schema"; import { eq } from "drizzle-orm"; import { differenceInDays } from "date-fns"; +// Determina quale sistema auth usare basandosi sull'ambiente +const USE_LOCAL_AUTH = process.env.DOMAIN === "vt.alfacom.it" || !process.env.REPLIT_DOMAINS; + +// Helper per estrarre user ID in modo compatibile +function getUserId(req: any): string { + if (USE_LOCAL_AUTH) { + return req.user?.id || ""; + } else { + return req.user?.claims?.sub || ""; + } +} + +// Usa il middleware auth appropriato +const isAuthenticated = USE_LOCAL_AUTH ? isAuthenticatedLocal : isAuthenticatedReplit; + export async function registerRoutes(app: Express): Promise { - // Auth middleware - await setupAuth(app); + // Setup auth system appropriato + if (USE_LOCAL_AUTH) { + console.log("🔐 Usando Local Auth (vt.alfacom.it)"); + await setupLocalAuth(app); + } else { + console.log("🔐 Usando Replit OIDC Auth"); + await setupReplitAuth(app); + } // ============= AUTH ROUTES ============= app.get("/api/auth/user", isAuthenticated, async (req: any, res) => { try { - const userId = req.user.claims.sub; + const userId = getUserId(req); const user = await storage.getUser(userId); res.json(user); } catch (error) { @@ -26,7 +48,7 @@ export async function registerRoutes(app: Express): Promise { // ============= USER MANAGEMENT ROUTES ============= app.get("/api/users", isAuthenticated, async (req: any, res) => { try { - const currentUserId = req.user.claims.sub; + const currentUserId = getUserId(req); const currentUser = await storage.getUser(currentUserId); // Only admins can view all users @@ -44,7 +66,7 @@ export async function registerRoutes(app: Express): Promise { app.patch("/api/users/:id", isAuthenticated, async (req: any, res) => { try { - const currentUserId = req.user.claims.sub; + const currentUserId = getUserId(req); const currentUser = await storage.getUser(currentUserId); // Only admins can update user roles @@ -407,11 +429,11 @@ export async function registerRoutes(app: Express): Promise { // ============= NOTIFICATION ROUTES ============= app.get("/api/notifications", isAuthenticated, async (req: any, res) => { try { - const userId = req.user.claims.sub; + const userId = getUserId(req); const userNotifications = await storage.getNotificationsByUser(userId); res.json(userNotifications); } catch (error) { - console.error("Error fetching notifications:", error); + console.error("Error fetching user notifications:", error); res.status(500).json({ message: "Failed to fetch notifications" }); } });