pull/3727/head
hawklin2017 2 months ago
parent 09460ccefa
commit dcc0fc2e86

@ -77,7 +77,6 @@ func (s *rtcServer) SignalMessageAssemble(ctx context.Context, req *rtc.SignalMe
resp.Payload = &rtc.SignalResp_GetTokenByRoomID{GetTokenByRoomID: r}
respErr = err
default:
// Fix P0: 原代码在此调用 respErr.Error(),而 respErr 为 nil会直接 panic
return nil, errs.ErrArgs.WrapMsg("unknown signal payload type")
}
if respErr != nil {
@ -94,12 +93,10 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq,
log.ZError(ctx, "handleInvite", errs.ErrArgs, "r", "invitation is nil")
return nil, errs.ErrArgs.WrapMsg("invitation is nil")
}
// Fix P3: RoomID 统一由服务端生成,忽略客户端传入的值(客户端不应决定 RoomID
inv.RoomID = newRoomID()
inv.InviterUserID = req.UserID
inv.InitiateTime = time.Now().UnixMilli()
// 校验每位被邀请者的通话接受权限1-to-1 场景:有任一被邀请者拒绝则直接返错
for _, inviteeID := range inv.InviteeUserIDList {
allowed, err := s.isCallAllowed(ctx, req.UserID, inviteeID)
if err != nil {
@ -118,17 +115,12 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq,
token, err := s.genToken(inv.RoomID, req.UserID)
if err != nil {
// LiveKit Room 已创建,需要回滚
if _, delErr := s.roomClient.DeleteRoom(ctx, &livekit.DeleteRoomRequest{Room: inv.RoomID}); delErr != nil {
log.ZWarn(ctx, "handleInvite: rollback DeleteRoom failed", delErr, "roomID", inv.RoomID)
}
return nil, err
}
// Fix P1/幂等: CreateInvitation 失败分两种情况:
// - 重复 key相同 roomID 重试)→ 认为幂等成功,直接返回
// - 其他错误 → 回滚 LiveKit Room返回错误
// Fix P0: 原代码对失败仅打 warn导致 DB 无记录、Room 泄漏、后续流程断裂
if err := s.db.CreateInvitation(ctx, invitationToModel(inv, req.OfflinePushInfo)); err != nil {
if mongo.IsDuplicateKeyError(err) {
log.ZWarn(ctx, "handleInvite: duplicate invitation (idempotent retry)", err, "roomID", inv.RoomID)
@ -144,7 +136,7 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq,
if err != nil {
return nil, err
}
// Fix P1: 1v1 场景下,通知失败应返回错误(被叫收不到来电意味着主叫白等)
for _, inviteeID := range inv.InviteeUserIDList {
log.ZInfo(ctx, "sendSignalingNotification to invitee", "sendID", req.UserID, "recvID", inviteeID)
if err := s.sendSignalingNotification(ctx, req.UserID, inviteeID, int32(constant.SingleChatType), req.OfflinePushInfo, content); err != nil {
@ -167,7 +159,7 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
if inv == nil {
return nil, errs.ErrArgs.WrapMsg("invitation is nil")
}
// Fix P3: RoomID 统一由服务端生成
inv.RoomID = newRoomID()
inv.InviterUserID = req.UserID
inv.InitiateTime = time.Now().UnixMilli()
@ -184,7 +176,6 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
return nil, err
}
// Fix P0: CreateInvitation 失败需要回滚 LiveKit Room
if err := s.db.CreateInvitation(ctx, invitationToModel(inv, req.OfflinePushInfo)); err != nil {
if !mongo.IsDuplicateKeyError(err) {
if _, delErr := s.roomClient.DeleteRoom(ctx, &livekit.DeleteRoomRequest{Room: inv.RoomID}); delErr != nil {
@ -245,9 +236,6 @@ func (s *rtcServer) isCallAllowed(ctx context.Context, inviterID, inviteeID stri
}
}
// handleAccept processes a call acceptance.
// Fix P1(安全): 原代码完全信任客户端传入的 Invitation未从 DB 校验邀请真实存在。
// 攻击者可伪造任意 RoomID/InviterUserID 来获取 LiveKit Token 并加入房间。
func (s *rtcServer) handleAccept(ctx context.Context, req *rtc.SignalAcceptReq, signalReq *rtc.SignalReq) (*rtc.SignalAcceptResp, error) {
if req.Invitation == nil {
return nil, errs.ErrArgs.WrapMsg("invitation is nil")
@ -276,12 +264,11 @@ func (s *rtcServer) handleAccept(ctx context.Context, req *rtc.SignalAcceptReq,
if err != nil {
return nil, err
}
// 使用 DB 中的 InviterUserID防止客户端伪造通知目标
if err := s.sendSignalingNotification(ctx, req.UserID, dbInv.InviterUserID, sessionType, req.OfflinePushInfo, content); err != nil {
log.ZWarn(ctx, "sendSignalingNotification accept to inviter failed", err, "inviterID", dbInv.InviterUserID)
}
// Fix P2: 1v1 通话接受后删除邀请记录,避免冷启动时重复弹出已接通的来电
// TODO: 群通话可通过 RemoveInvitee 实现精细化状态管理
if dbInv.GroupID == "" {
if err := s.db.DeleteInvitation(ctx, dbInv.RoomID); err != nil {
@ -297,7 +284,6 @@ func (s *rtcServer) handleAccept(ctx context.Context, req *rtc.SignalAcceptReq,
}
// handleReject processes a call rejection.
// Fix P1(安全): 从 DB 验证邀请存在,并使用 DB 中的 InviterUserID防止客户端伪造通知目标。
func (s *rtcServer) handleReject(ctx context.Context, req *rtc.SignalRejectReq, signalReq *rtc.SignalReq) (*rtc.SignalRejectResp, error) {
if req.Invitation == nil {
return nil, errs.ErrArgs.WrapMsg("invitation is nil")
@ -337,7 +323,6 @@ func (s *rtcServer) handleReject(ctx context.Context, req *rtc.SignalRejectReq,
}
// handleCancel processes a call cancellation.
// Fix P1(安全): 从 DB 验证操作者是邀请发起方,防止被叫方冒充取消通话。
func (s *rtcServer) handleCancel(ctx context.Context, req *rtc.SignalCancelReq, signalReq *rtc.SignalReq) (*rtc.SignalCancelResp, error) {
if req.Invitation == nil {
return nil, errs.ErrArgs.WrapMsg("invitation is nil")
@ -373,7 +358,6 @@ func (s *rtcServer) handleCancel(ctx context.Context, req *rtc.SignalCancelReq,
}
// handleHungUp processes a call hang-up.
// Fix P1(安全): 从 DB 验证操作者是通话参与者,防止任意用户挂断他人通话并删除 LiveKit Room。
func (s *rtcServer) handleHungUp(ctx context.Context, req *rtc.SignalHungUpReq, signalReq *rtc.SignalReq) (*rtc.SignalHungUpResp, error) {
if req.Invitation == nil {
return nil, errs.ErrArgs.WrapMsg("invitation is nil")
@ -415,7 +399,6 @@ func (s *rtcServer) handleHungUp(ctx context.Context, req *rtc.SignalHungUpReq,
}
// handleGetTokenByRoomID returns a LiveKit token for an existing room.
// Fix P0(安全): 原代码无权限校验,任意已登录用户可获取任意房间的 Token可窃听他人通话。
func (s *rtcServer) handleGetTokenByRoomID(ctx context.Context, req *rtc.SignalGetTokenByRoomIDReq) (*rtc.SignalGetTokenByRoomIDResp, error) {
dbInv, err := s.db.GetInvitationByRoomID(ctx, req.RoomID)
if err != nil {
@ -706,8 +689,7 @@ func invitationToModel(inv *rtc.InvitationInfo, push *sdkws.OfflinePushInfo) *mo
InitiateTime: inv.InitiateTime,
BusyLineUserIDList: inv.BusyLineUserIDList,
CreateTime: now.UnixMilli(),
// Fix P1(TTL): 根据 Timeout 设置过期时间,配合 MongoDB TTL 索引自动清理
ExpireAt: now.Add(time.Duration(inv.Timeout+30) * time.Second),
ExpireAt: now.Add(time.Duration(inv.Timeout+30) * time.Second),
}
if push != nil {
m.OfflinePushTitle = push.Title
@ -738,7 +720,6 @@ func modelToInvitationInfo(m *model.SignalInvitation) *rtc.InvitationInfo {
}
// hungUpPeerIDsFromDB returns IDs that should receive hang-up notification, based on authoritative DB data.
// Fix P1(安全): 原 hungUpPeerIDs 使用客户端传入的 inv改为使用从 DB 获取的记录。
func hungUpPeerIDsFromDB(inv *model.SignalInvitation, callerID string) []string {
if callerID == inv.InviterUserID {
return inv.InviteeUserIDList

Loading…
Cancel
Save