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/.cursor-server/data/User/History/-273157b5/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/.cursor-server/data/User/History/-273157b5/S4eU.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { Server as NetServer } from 'http';
import { Server as SocketIOServer } from 'socket.io';
import { NextApiResponseServerIO } from '@/types/socket';
import { getSession } from 'next-auth/react';
import { prisma } from '@/lib/prisma';

interface CaseChatMessage {
  id: string;
  caseId: string;
  content: string;
  senderId: string;
  senderName: string;
  senderAvatar?: string;
  senderRole: string;
  timestamp: number;
  isPublic: boolean;
  reactions?: {
    [key: string]: string[];
  };
}

interface CaseTypingData {
  caseId: string;
  userId: string;
  userName: string;
  isTyping: boolean;
  timestamp: number;
}

interface CaseChatUser {
  userId: string;
  userName: string;
  userAvatar?: string;
  userRole: string;
  joinedAt: number;
}

interface ProfileInteraction {
  type: 'follow' | 'unfollow' | 'friend_request' | 'friend_accept' | 'endorse' | 'message' | 'profile_view';
  fromUserId: string;
  fromUserName: string;
  fromUserAvatar?: string;
  toUserId: string;
  timestamp: number;
  data?: any; // Additional data like endorsement text, message content, etc.
}

interface Notification {
  id: string;
  type: string;
  title: string;
  message: string;
  userId: string;
  data?: any;
  isRead: boolean;
  createdAt: number;
}

// Store active case chat rooms
const caseChatRooms = new Map<string, Set<string>>(); // caseId -> Set of userIds
const caseTypingUsers = new Map<string, Map<string, CaseTypingData>>(); // caseId -> Map of userId -> typing data

// Store user connections for profile interactions
const userConnections = new Map<string, string>(); // userId -> socketId
const onlineUsers = new Set<string>(); // Set of online user IDs

// Helper function to create notifications in the main notification system
const createNotification = async (userId: string, type: string, message: string, data?: any) => {
  try {
    await prisma.notification.create({
      data: {
        userId,
        type,
        title: getNotificationTitle(type),
        message,
        data: data ? JSON.stringify(data) : null,
        isRead: false
      }
    });
  } catch (error) {
    console.error('Error creating notification:', error);
  }
};

const getNotificationTitle = (type: string) => {
  switch (type) {
    case 'follow': return 'New Follower';
    case 'friend_request': return 'Friend Request';
    case 'endorsement': return 'New Endorsement';
    case 'message': return 'New Message';
    case 'profile_view': return 'Profile Viewed';
    default: return 'Notification';
  }
};

export const config = {
  api: {
    bodyParser: false,
  },
};

const ioHandler = async (req: NextApiRequest, res: NextApiResponseServerIO) => {
  if (!res.socket.server.io) {
    console.log('Setting up WebSocket server...');
    
    const httpServer: NetServer = res.socket.server as any;
    const io = new SocketIOServer(httpServer, {
      path: '/api/_ws',
      addTrailingSlash: false,
      cors: {
        origin: process.env.NEXTAUTH_URL || 'http://localhost:3000',
        methods: ['GET', 'POST'],
      },
    });

    // Middleware to authenticate WebSocket connections
    io.use(async (socket, next) => {
      try {
        const session = await getSession({ req: socket.request as any });
        if (!session?.user?.id) {
          return next(new Error('Unauthorized'));
        }
        
        // Attach user data to socket
        socket.data.user = session.user;
        next();
      } catch (error) {
        next(new Error('Authentication failed'));
      }
    });

    io.on('connection', (socket) => {
      const userId = socket.data.user.id;
      const userName = socket.data.user.name;
      
      console.log(`User ${userName} connected to WebSocket`);
      
      // Track user connection
      userConnections.set(userId, socket.id);
      onlineUsers.add(userId);
      
      // Broadcast user online status
      socket.broadcast.emit('USER_STATUS_UPDATE', {
        userId,
        status: 'online',
        timestamp: Date.now()
      });

      // Handle case chat joining
      socket.on('JOIN_CASE_CHAT', async (data: { caseId: string }) => {
        try {
          const { caseId } = data;
          const userId = socket.data.user.id;
          const userName = socket.data.user.name;
          const userAvatar = socket.data.user.image;
          const userRole = socket.data.user.role || 'USER';

          // Verify case exists and is public
          const caseData = await prisma.legalCase.findUnique({
            where: { id: caseId },
            select: { id: true, isPublic: true, status: true }
          });

          if (!caseData || !caseData.isPublic) {
            socket.emit('error', { message: 'Case not found or not public' });
            return;
          }

          // Join the case chat room
          socket.join(`case_${caseId}`);

          // Add user to case chat room tracking
          if (!caseChatRooms.has(caseId)) {
            caseChatRooms.set(caseId, new Set());
          }
          caseChatRooms.get(caseId)!.add(userId);

          // Notify other users in the case chat
          socket.to(`case_${caseId}`).emit('CASE_USER_JOINED', {
            caseId,
            userId,
            userName,
            userAvatar,
            userRole,
            timestamp: Date.now()
          });

          // Send acknowledgment
          socket.emit('CASE_CHAT_JOINED', {
            caseId,
            userId,
            timestamp: Date.now()
          });

          console.log(`User ${userName} joined case chat: ${caseId}`);
        } catch (error) {
          console.error('Error joining case chat:', error);
          socket.emit('error', { message: 'Failed to join case chat' });
        }
      });

      // Handle case chat leaving
      socket.on('LEAVE_CASE_CHAT', async (data: { caseId: string }) => {
        try {
          const { caseId } = data;
          const userId = socket.data.user.id;
          const userName = socket.data.user.name;

          // Leave the case chat room
          socket.leave(`case_${caseId}`);

          // Remove user from case chat room tracking
          const roomUsers = caseChatRooms.get(caseId);
          if (roomUsers) {
            roomUsers.delete(userId);
            if (roomUsers.size === 0) {
              caseChatRooms.delete(caseId);
            }
          }

          // Remove typing indicator
          const caseTyping = caseTypingUsers.get(caseId);
          if (caseTyping) {
            caseTyping.delete(userId);
            if (caseTyping.size === 0) {
              caseTypingUsers.delete(caseId);
            }
          }

          // Notify other users in the case chat
          socket.to(`case_${caseId}`).emit('CASE_USER_LEFT', {
            caseId,
            userId,
            userName,
            timestamp: Date.now()
          });

          // Send acknowledgment
          socket.emit('CASE_CHAT_LEFT', {
            caseId,
            userId,
            timestamp: Date.now()
          });

          console.log(`User ${userName} left case chat: ${caseId}`);
        } catch (error) {
          console.error('Error leaving case chat:', error);
          socket.emit('error', { message: 'Failed to leave case chat' });
        }
      });

      // Handle case chat messages
      socket.on('CASE_MESSAGE', async (data: CaseChatMessage) => {
        try {
          const {
            caseId,
            content,
            isPublic
          } = data;

          const userId = socket.data.user.id;
          const userName = socket.data.user.name;
          const userAvatar = socket.data.user.image;
          const userRole = socket.data.user.role || 'USER';

          // Verify case exists and is public
          const caseData = await prisma.legalCase.findUnique({
            where: { id: caseId },
            select: { id: true, isPublic: true, status: true }
          });

          if (!caseData || !caseData.isPublic) {
            socket.emit('error', { message: 'Case not found or not public' });
            return;
          }

          // Create message object
          const message: CaseChatMessage = {
            id: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
            caseId,
            content: content.trim(),
            senderId: userId,
            senderName: userName,
            senderAvatar: userAvatar,
            senderRole: userRole,
            timestamp: Date.now(),
            isPublic,
            reactions: {}
          };

          // Save message to database if it's public
          if (isPublic) {
            try {
              await prisma.caseChatMessage.create({
                data: {
                  caseId,
                  content: message.content,
                  senderId: userId,
                  senderName: userName,
                  senderAvatar: userAvatar,
                  senderRole: userRole,
                  isPublic: true
                }
              });
            } catch (dbError) {
              console.error('Error saving case chat message to database:', dbError);
              // Continue even if database save fails
            }
          }

          // Broadcast message to all users in the case chat
          io.to(`case_${caseId}`).emit('CASE_MESSAGE', {
            type: 'CASE_MESSAGE',
            data: message
          });

          console.log(`Case chat message sent by ${userName} in case ${caseId}: ${content.substring(0, 50)}...`);
        } catch (error) {
          console.error('Error sending case chat message:', error);
          socket.emit('error', { message: 'Failed to send message' });
        }
      });

      // Handle case typing indicators
      socket.on('CASE_TYPING', (data: CaseTypingData) => {
        try {
          const { caseId, isTyping } = data;
          const userId = socket.data.user.id;
          const userName = socket.data.user.name;

          // Update typing state
          if (!caseTypingUsers.has(caseId)) {
            caseTypingUsers.set(caseId, new Map());
          }

          const caseTyping = caseTypingUsers.get(caseId)!;

          if (isTyping) {
            caseTyping.set(userId, {
              ...data,
              userId,
              userName
            });
          } else {
            caseTyping.delete(userId);
          }

          // Broadcast typing indicator to other users in the case chat
          socket.to(`case_${caseId}`).emit('CASE_TYPING', {
            type: 'CASE_TYPING',
            data: {
              caseId,
              userId,
              userName,
              isTyping,
              timestamp: Date.now()
            }
          });
        } catch (error) {
          console.error('Error handling case typing indicator:', error);
        }
      });

      // Handle regular room messages (existing functionality)
      socket.on('JOIN_ROOM', async (data: { chatRoomId: string }) => {
        try {
          const { chatRoomId } = data;
          const userId = socket.data.user.id;

          // Verify user has access to this chat room
          const chatRoom = await prisma.chatRoom.findFirst({
            where: {
              id: chatRoomId,
              participants: {
                some: {
                  userId: userId
                }
              }
            }
          });

          if (!chatRoom) {
            socket.emit('error', { message: 'Access denied to chat room' });
            return;
          }

          socket.join(chatRoomId);
          socket.emit('ROOM_JOINED', { chatRoomId });
        } catch (error) {
          console.error('Error joining room:', error);
          socket.emit('error', { message: 'Failed to join room' });
        }
      });

      socket.on('LEAVE_ROOM', (data: { chatRoomId: string }) => {
        const { chatRoomId } = data;
        socket.leave(chatRoomId);
        socket.emit('ROOM_LEFT', { chatRoomId });
      });

      socket.on('TYPING', (data: { roomId: string; isTyping: boolean }) => {
        const { roomId, isTyping } = data;
        socket.to(roomId).emit('TYPING', {
          roomId,
          userId: socket.data.user.id,
          userName: socket.data.user.name,
          isTyping,
          timestamp: Date.now()
        });
      });

      socket.on('PRESENCE_UPDATE', (data: { status: 'online' | 'away' }) => {
        // Broadcast presence update to all connected clients
        socket.broadcast.emit('PRESENCE_UPDATE', {
          userId: socket.data.user.id,
          status: data.status,
          timestamp: Date.now()
        });
      });

      // Handle disconnection
      socket.on('disconnect', () => {
        const userId = socket.data.user.id;
        const userName = socket.data.user.name;
        
        console.log(`User ${userName} disconnected from WebSocket`);
        
        // Remove user from tracking
        userConnections.delete(userId);
        onlineUsers.delete(userId);
        
        // Broadcast user offline status
        socket.broadcast.emit('USER_STATUS_UPDATE', {
          userId,
          status: 'offline',
          timestamp: Date.now()
        });
        
        // Remove user from all case chat rooms
        caseChatRooms.forEach((users, caseId) => {
          if (users.has(userId)) {
            users.delete(userId);
            
            // Notify other users
            socket.to(`case_${caseId}`).emit('CASE_USER_LEFT', {
              caseId,
              userId,
              userName,
              timestamp: Date.now()
            });

            if (users.size === 0) {
              caseChatRooms.delete(caseId);
            }
          }
        });

        // Remove typing indicators
        caseTypingUsers.forEach((users, caseId) => {
          if (users.has(userId)) {
            users.delete(userId);
            
            // Notify other users
            socket.to(`case_${caseId}`).emit('CASE_TYPING', {
              type: 'CASE_TYPING',
              data: {
                caseId,
                userId,
                userName,
                isTyping: false,
                timestamp: Date.now()
              }
            });

            if (users.size === 0) {
              caseTypingUsers.delete(caseId);
            }
          }
        });
      });

      // Handle ping/pong for latency measurement
      socket.on('ping', () => {
        socket.emit('pong');
      });

      // Profile interaction handlers
      socket.on('PROFILE_INTERACTION', async (data: ProfileInteraction) => {
        try {
          const { type, toUserId, data: interactionData } = data;
          const fromUserId = socket.data.user.id;
          const fromUserName = socket.data.user.name;
          const fromUserAvatar = socket.data.user.image;

          // Create interaction object
          const interaction: ProfileInteraction = {
            type,
            fromUserId,
            fromUserName,
            fromUserAvatar,
            toUserId,
            timestamp: Date.now(),
            data: interactionData
          };

          // Save interaction to database and create notification
          try {
            switch (type) {
              case 'follow':
                // Handle follow logic
                await createNotification(toUserId, 'follow', `${fromUserName} started following you`, {
                  fromUserId,
                  fromUserName,
                  fromUserAvatar
                });
                break;
              case 'friend_request':
                // Handle friend request logic
                await createNotification(toUserId, 'friend_request', `${fromUserName} sent you a friend request`, {
                  fromUserId,
                  fromUserName,
                  fromUserAvatar
                });
                break;
              case 'endorse':
                // Handle endorsement logic
                const endorsementText = interactionData?.text || 'endorsed your profile';
                await createNotification(toUserId, 'endorsement', `${fromUserName} ${endorsementText}`, {
                  fromUserId,
                  fromUserName,
                  fromUserAvatar,
                  endorsementText
                });
                break;
              case 'profile_view':
                // Handle profile view tracking (don't create notification for views)
                break;
            }
          } catch (dbError) {
            console.error('Error saving profile interaction to database:', dbError);
          }

          // Send notification to target user if they're online
          const targetSocketId = userConnections.get(toUserId);
          if (targetSocketId) {
            io.to(targetSocketId).emit('PROFILE_INTERACTION', {
              type: 'PROFILE_INTERACTION',
              data: interaction
            });
          }

          // Broadcast to all users following the target user (for activity feeds)
          socket.broadcast.emit('PROFILE_ACTIVITY', {
            type: 'PROFILE_ACTIVITY',
            data: interaction
          });

          console.log(`Profile interaction: ${fromUserName} ${type} ${toUserId}`);
        } catch (error) {
          console.error('Error handling profile interaction:', error);
          socket.emit('error', { message: 'Failed to process profile interaction' });
        }
      });

      // Handle online status updates
      socket.on('ONLINE_STATUS', (data: { status: 'online' | 'away' | 'offline' }) => {
        const userId = socket.data.user.id;
        const { status } = data;

        if (status === 'online') {
          onlineUsers.add(userId);
        } else if (status === 'offline') {
          onlineUsers.delete(userId);
        }

        // Broadcast status update to all connected users
        socket.broadcast.emit('USER_STATUS_UPDATE', {
          userId,
          status,
          timestamp: Date.now()
        });
      });

      // Handle profile view tracking
      socket.on('PROFILE_VIEW', async (data: { targetUserId: string }) => {
        try {
          const { targetUserId } = data;
          const viewerId = socket.data.user.id;
          const viewerName = socket.data.user.name;

          // Don't track self-views
          if (viewerId === targetUserId) return;

          // Create profile view interaction
          const interaction: ProfileInteraction = {
            type: 'profile_view',
            fromUserId: viewerId,
            fromUserName: viewerName,
            toUserId: targetUserId,
            timestamp: Date.now()
          };

          // Send to target user if they're online
          const targetSocketId = userConnections.get(targetUserId);
          if (targetSocketId) {
            io.to(targetSocketId).emit('PROFILE_VIEWED', {
              type: 'PROFILE_VIEWED',
              data: {
                viewerId,
                viewerName,
                timestamp: Date.now()
              }
            });
          }

          console.log(`Profile view: ${viewerName} viewed ${targetUserId}`);
        } catch (error) {
          console.error('Error handling profile view:', error);
        }
      });

      // Send initial connection confirmation
      socket.emit('connected', {
        userId: socket.data.user.id,
        userName: socket.data.user.name,
        timestamp: Date.now()
      });
    });

    res.socket.server.io = io;
  }

  res.end();
};

export default ioHandler; 

CasperSecurity Mini