File size: 2,200 Bytes
87cb242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { UserModel } from '../db/mongo';
import { FriendRequestModel } from '../models/friend';
import { logger } from '../utils/logger';

/**
 * Check if two users are friends. Used before allowing signaling to prevent
 * stranger signaling attacks — only friends can initiate WebRTC offers.
 */
export async function areFriends(uidA: string, uidB: string): Promise<boolean> {
  const user = await UserModel.findOne({ uid: uidA, friends: uidB }, '_id').lean();
  return !!user;
}

/** Send a friend request (fromUid → toUid). Idempotent. */
export async function sendFriendRequest(fromUid: string, toUid: string): Promise<void> {
  await FriendRequestModel.findOneAndUpdate(
    { fromUid, toUid },
    { status: 'pending' },
    { upsert: true, new: true }
  );
}

/** Accept a friend request. Adds each user to the other's friends list. */
export async function acceptFriendRequest(fromUid: string, toUid: string): Promise<boolean> {
  const req = await FriendRequestModel.findOneAndUpdate(
    { fromUid, toUid, status: 'pending' },
    { status: 'accepted' }
  );
  if (!req) return false;

  // Add to both users' friend lists atomically
  await Promise.all([
    UserModel.updateOne({ uid: toUid }, { $addToSet: { friends: fromUid } }),
    UserModel.updateOne({ uid: fromUid }, { $addToSet: { friends: toUid } }),
  ]);

  return true;
}

/** Reject a friend request. */
export async function rejectFriendRequest(fromUid: string, toUid: string): Promise<void> {
  await FriendRequestModel.findOneAndUpdate(
    { fromUid, toUid, status: 'pending' },
    { status: 'rejected' }
  );
}

/** Remove a friend (unfriend). Removes from both sides. */
export async function removeFriend(uidA: string, uidB: string): Promise<void> {
  await Promise.all([
    UserModel.updateOne({ uid: uidA }, { $pull: { friends: uidB } }),
    UserModel.updateOne({ uid: uidB }, { $pull: { friends: uidA } }),
  ]);
  logger.info('Friendship removed', { uidA, uidB });
}

/** Get a user's friend list. Returns array of UIDs. */
export async function getFriendList(uid: string): Promise<string[]> {
  const user = await UserModel.findOne({ uid }, 'friends').lean();
  return (user?.friends as string[]) ?? [];
}