T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/domains/lavocat.ca/public_html/src/lib/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.ca/public_html/src/lib/auth.ts
import { NextAuthOptions } from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import { compare } from 'bcryptjs';
import { prisma } from '@/lib/prisma';

export const authOptions: NextAuthOptions = {
  providers: [
    CredentialsProvider({
      name: 'Credentials',
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" }
      },
      async authorize(credentials) {
        if (!credentials?.email || !credentials?.password) {
          return null;
        }

        try {
          // Find user by email
          const user = await prisma.user.findUnique({
            where: { email: credentials.email },
            select: {
              id: true,
              email: true,
              password: true,
              role: true,
              name: true,
              isVerified: true,
              verificationStatus: true,
            },
          });

          if (!user) {
            return null;
          }

          // Verify password
          const isValid = await compare(credentials.password, user.password);

          if (!isValid) {
            return null;
          }

          // Return user without password, ensuring name is never null
          const { password: _, ...userWithoutPassword } = user;
          return {
            ...userWithoutPassword,
            name: userWithoutPassword.name || userWithoutPassword.email, // Use email as fallback if name is null
          };
        } catch (error) {
          console.error('Auth error:', error);
          return null;
        }
      }
    })
  ],
  session: {
    strategy: 'jwt',
    maxAge: 30 * 24 * 60 * 60, // 30 days
  },
  cookies: {
    sessionToken: {
      name: process.env.NODE_ENV === 'development' ? 'next-auth.session-token' : '__Secure-next-auth.session-token',
      options: {
        httpOnly: true,
        sameSite: 'lax',
        path: '/',
        secure: process.env.NODE_ENV === 'production',
        // Don't set domain in development to allow network access
        domain: process.env.NODE_ENV === 'production' ? process.env.COOKIE_DOMAIN : undefined
      }
    }
  },
  pages: {
    signIn: '/auth/login',
    signOut: '/auth/login',
    error: '/auth/error',
  },
  callbacks: {
    async jwt({ token, user, trigger }) {
      try {
        console.log('JWT Callback - trigger:', trigger);
        console.log('JWT Callback - user:', user ? { id: user.id, email: user.email, role: user.role } : null);
        
        // Handle fresh login
        if (user) {
          // Store user data in token
          token.id = user.id;
          token.role = user.role;
          token.email = user.email;
          token.name = user.name || user.email;
          token.profilePicture = user.profilePicture || undefined;
          token.username = user.username || undefined;
          token.isVerified = (user as any).isVerified || false;
          token.verificationStatus = (user as any).verificationStatus || 'PENDING';
          token.isImpersonating = user.isImpersonating || false;
          token.originalUser = user.originalUser || undefined;
          
          console.log('JWT Callback - Updated token from user:', { 
            id: token.id, 
            role: token.role, 
            isImpersonating: token.isImpersonating 
          });
        } else if (token.id) {
          // Check for impersonation sessions on ALL requests (including 'update' triggers)
          // This ensures impersonation state is always current
          try {
            console.log('JWT Callback - Checking for impersonation sessions...');
            const impersonationSession = await prisma.impersonationSession.findFirst({
              where: {
                originalUserId: token.id as string,
                isActive: true,
                expiresAt: { gt: new Date() } // Only get non-expired sessions
              },
              include: {
                impersonatedUser: {
                  select: {
                    id: true,
                    email: true,
                    name: true,
                    role: true,
                    profilePicture: true,
                    username: true
                  }
                },
                originalUser: {
                  select: {
                    id: true,
                    email: true,
                    name: true,
                    role: true,
                    profilePicture: true,
                    username: true
                  }
                }
              }
            });

            if (impersonationSession) {
              // Apply impersonation
              const impersonatedUser = impersonationSession.impersonatedUser;
              token.id = impersonatedUser.id;
              token.email = impersonatedUser.email;
              token.name = impersonatedUser.name || impersonatedUser.email;
              token.role = impersonatedUser.role;
              token.profilePicture = impersonatedUser.profilePicture || undefined;
              token.username = impersonatedUser.username || undefined;
              token.isImpersonating = true;
              token.originalUser = {
                id: impersonationSession.originalUser.id,
                email: impersonationSession.originalUser.email,
                name: impersonationSession.originalUser.name || impersonationSession.originalUser.email,
                role: impersonationSession.originalUser.role,
                profilePicture: impersonationSession.originalUser.profilePicture || undefined,
                username: impersonationSession.originalUser.username || undefined
              };
              
              console.log('JWT Callback - Applied impersonation:', { 
                originalId: token.originalUser.id,
                impersonatedId: token.id,
                originalRole: token.originalUser.role,
                impersonatedRole: token.role
              });
            } else if (token.isImpersonating) {
              // No active impersonation found, restore original user
              if (token.originalUser) {
                console.log('JWT Callback - Restoring original user from token');
                token.id = token.originalUser.id;
                token.email = token.originalUser.email;
                token.name = token.originalUser.name || token.originalUser.email;
                token.role = token.originalUser.role;
                token.profilePicture = token.originalUser.profilePicture || undefined;
                token.username = token.originalUser.username || undefined;
              }
              token.isImpersonating = false;
              token.originalUser = undefined;
              console.log('JWT Callback - Cleared impersonation state');
            }
          } catch (error) {
            console.error('JWT Callback - Database error:', error);
            // On error, clear impersonation state
            if (token.isImpersonating && token.originalUser) {
              console.log('JWT Callback - Error occurred, restoring original user');
              token.id = token.originalUser.id;
              token.email = token.originalUser.email;
              token.name = token.originalUser.name || token.originalUser.email;
              token.role = token.originalUser.role;
              token.profilePicture = token.originalUser.profilePicture || undefined;
              token.username = token.originalUser.username || undefined;
              token.isImpersonating = false;
              token.originalUser = undefined;
            }
          }
        }
        
        console.log('JWT Callback - Final token:', { 
          id: token.id, 
          email: token.email, 
          role: token.role, 
          isImpersonating: token.isImpersonating 
        });
        return token;
      } catch (err) {
        console.error('JWT Callback - Error:', err);
        return token;
      }
    },
    async session({ session, token }) {
      try {
        console.log('Session Callback - token:', { id: token.id, email: token.email, role: token.role, isImpersonating: token.isImpersonating });
        console.log('Session Callback - session before:', session);
        
        if (token && session.user) {
          session.user.id = token.id as string;
          session.user.role = token.role as string;
          session.user.email = token.email as string;
          session.user.name = token.name as string;
          session.user.profilePicture = token.profilePicture as string;
          session.user.username = token.username as string;
          session.user.isVerified = token.isVerified as boolean;
          session.user.verificationStatus = token.verificationStatus as string;
          session.user.isImpersonating = token.isImpersonating as boolean;
          session.user.originalUser = token.originalUser as any;
        }
        
        console.log('Session Callback - session after:', session);
        console.log('Session Callback - Final user ID:', session.user?.id);
        return session;
      } catch (err) {
        console.error('Session Callback - Error:', err);
        return session;
      }
    },
    async redirect({ url, baseUrl }) {
      // Only force home/dashboard for login page or base
      if (url === baseUrl || url === `${baseUrl}/` || url.endsWith('/auth/login')) {
        return baseUrl;
      }
      // If URL is relative, make it absolute
      if (url.startsWith('/')) {
        return `${baseUrl}${url}`;
      }
      // If URL is on the same domain, allow it
      if (url.startsWith(baseUrl)) {
        return url;
      }
      // Default to base URL for external URLs (security)
      return baseUrl;
    }
  },
  secret: process.env.NEXTAUTH_SECRET || '3560f921b7bbf968e64fbc2835960840d184fcb95977e960a2124de6bbbed2d3',
  debug: process.env.NODE_ENV === 'development',
}; 

CasperSecurity Mini