merged from gramsrv upstream
This commit is contained in:
parent
79c64ee916
commit
21a0856587
651 changed files with 54774 additions and 4590 deletions
|
|
@ -2,13 +2,17 @@ package rpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/iamxvbaba/td/proto"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
const encryptedDifferencePageSize = 1000
|
||||
|
||||
// 私聊密聊 qts 消息收发 RPC handler(P1)。服务端是盲中继:sendEncrypted* 的 bytes 是
|
||||
// 客户端加密的 DecryptedMessage,服务端盲存进【接收方设备】的 qts 队列、原样转发,
|
||||
// 永不解密。在线推 updateNewEncryptedMessage(设备定向,离线靠 getDifference 补回)。
|
||||
|
|
@ -34,11 +38,16 @@ func (r *Router) pushEncryptedNewMessage(ctx context.Context, msg domain.SecretC
|
|||
_, _ = targeted.PushToUserAuthKey(ctx, msg.ReceiverUserID, deviceAuthKeyBytes(msg.ReceiverAuthKeyID), proto.MessageFromServer, upd)
|
||||
return
|
||||
}
|
||||
// 回退(测试替身/未装配定向能力):账号级推送。
|
||||
r.pushUserMessage(ctx, msg.ReceiverUserID, "secret chat message", upd)
|
||||
// 设备隔离是安全边界;缺少定向能力时只保留 durable qts,离线 difference 补回。
|
||||
r.log.Error("secret chat targeted session binder unavailable",
|
||||
zap.Int64("target_user_id", msg.ReceiverUserID),
|
||||
zap.Int64("target_auth_key_id", msg.ReceiverAuthKeyID))
|
||||
}
|
||||
|
||||
func (r *Router) sendEncryptedCommon(ctx context.Context, peer tg.InputEncryptedChat, randomID int64, data []byte, isService bool) (tg.MessagesSentEncryptedMessageClass, error) {
|
||||
if len(data) > domain.MaxSecretMessageDataBytes {
|
||||
return nil, dataTooLongErr()
|
||||
}
|
||||
if r.deps.SecretChats == nil {
|
||||
return nil, notImplementedErr()
|
||||
}
|
||||
|
|
@ -46,7 +55,11 @@ func (r *Router) sendEncryptedCommon(ctx context.Context, peer tg.InputEncrypted
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, stored, err := r.deps.SecretChats.SendEncrypted(ctx, peer.ChatID, userID, peer.AccessHash, domain.SecretMessageDelivery{
|
||||
deviceAuthKeyID, ok := businessAuthKeyIDFrom(ctx)
|
||||
if !ok {
|
||||
return nil, internalErr()
|
||||
}
|
||||
_, stored, err := r.deps.SecretChats.SendEncrypted(ctx, peer.ChatID, userID, deviceAuthKeyID, peer.AccessHash, domain.SecretMessageDelivery{
|
||||
RandomID: randomID,
|
||||
Bytes: data,
|
||||
IsService: isService,
|
||||
|
|
@ -130,27 +143,38 @@ func (r *Router) deviceEncryptedQts(ctx context.Context) int {
|
|||
return qts
|
||||
}
|
||||
|
||||
// encryptedDifference 返回当前设备 qts > sinceQts 的加密消息(TL 投影)与推进后的 qts
|
||||
// (getDifference 注入用)。无新消息时返回 (nil, sinceQts)。
|
||||
func (r *Router) encryptedDifference(ctx context.Context, sinceQts int) ([]tg.EncryptedMessageClass, int) {
|
||||
// encryptedDifference 返回当前设备 qts > sinceQts 的连续前缀、推进后的 qts 与是否还有
|
||||
// 下一页。存储错误或 qts gap 必须 fail-fast,禁止越过缺口推进客户端水位。
|
||||
func (r *Router) encryptedDifference(ctx context.Context, sinceQts int) ([]tg.EncryptedMessageClass, int, bool, error) {
|
||||
if r.deps.SecretChats == nil {
|
||||
return nil, sinceQts
|
||||
return nil, sinceQts, false, nil
|
||||
}
|
||||
deviceKey, ok := businessAuthKeyIDFrom(ctx)
|
||||
if !ok {
|
||||
return nil, sinceQts
|
||||
return nil, sinceQts, false, nil
|
||||
}
|
||||
msgs, err := r.deps.SecretChats.ListNewMessages(ctx, deviceKey, sinceQts, 0)
|
||||
if err != nil || len(msgs) == 0 {
|
||||
return nil, sinceQts
|
||||
msgs, err := r.deps.SecretChats.ListNewMessages(ctx, deviceKey, sinceQts, encryptedDifferencePageSize+1)
|
||||
if err != nil {
|
||||
return nil, sinceQts, false, err
|
||||
}
|
||||
if len(msgs) == 0 {
|
||||
return nil, sinceQts, false, nil
|
||||
}
|
||||
partial := len(msgs) > encryptedDifferencePageSize
|
||||
if partial {
|
||||
msgs = msgs[:encryptedDifferencePageSize]
|
||||
}
|
||||
out := make([]tg.EncryptedMessageClass, 0, len(msgs))
|
||||
newQts := sinceQts
|
||||
for _, m := range msgs {
|
||||
for i, m := range msgs {
|
||||
expected := newQts + 1
|
||||
if m.Qts != expected {
|
||||
return nil, sinceQts, false, fmt.Errorf("secret chat qts gap at index %d: got %d want %d", i, m.Qts, expected)
|
||||
}
|
||||
out = append(out, tgEncryptedMessage(m))
|
||||
newQts = m.Qts
|
||||
}
|
||||
return out, newQts
|
||||
return out, newQts, partial, nil
|
||||
}
|
||||
|
||||
// injectEncryptedMessages 把加密消息与推进后的 qts 注入差分响应(按类型分别写 State /
|
||||
|
|
@ -169,19 +193,28 @@ func injectEncryptedMessages(diff tg.UpdatesDifferenceClass, encMsgs []tg.Encryp
|
|||
|
||||
// encryptedStateUpdates 返回当前设备未投递的握手/已读状态事件重建出的 update(进
|
||||
// OtherUpdates)、涉及的 peer user id(补 Users)、以及要登记已投递的事件 id。
|
||||
// encryption 事件按 secret_chats 权威态重建(不固化快照)。
|
||||
func (r *Router) encryptedStateUpdates(ctx context.Context, userID int64) (updates []tg.UpdateClass, peerUserIDs []int64, eventIDs []int64) {
|
||||
// encryption 事件按 secret_chats 权威态重建(不固化密钥材料快照)。账号级邀请在
|
||||
// accept 后只对未绑定设备投影为 discarded;获胜设备消费并跳过,绝不能收到 normal 泄漏。
|
||||
func (r *Router) encryptedStateUpdates(ctx context.Context, userID int64) (updates []tg.UpdateClass, peerUserIDs []int64, eventIDs []int64, partial bool, err error) {
|
||||
if r.deps.SecretChats == nil {
|
||||
return nil, nil, nil
|
||||
return nil, nil, nil, false, nil
|
||||
}
|
||||
deviceKey, ok := businessAuthKeyIDFrom(ctx)
|
||||
if !ok {
|
||||
return nil, nil, nil
|
||||
return nil, nil, nil, false, nil
|
||||
}
|
||||
events, err := r.deps.SecretChats.ListStateEvents(ctx, userID, deviceKey, 0)
|
||||
if err != nil || len(events) == 0 {
|
||||
return nil, nil, nil
|
||||
events, err := r.deps.SecretChats.ListStateEvents(ctx, userID, deviceKey, encryptedDifferencePageSize+1)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
}
|
||||
if len(events) == 0 {
|
||||
return nil, nil, nil, false, nil
|
||||
}
|
||||
partial = len(events) > encryptedDifferencePageSize
|
||||
if partial {
|
||||
events = events[:encryptedDifferencePageSize]
|
||||
}
|
||||
seenEncryption := make(map[int]struct{})
|
||||
for _, ev := range events {
|
||||
switch ev.Type {
|
||||
case domain.EncryptedStateEventEncryption:
|
||||
|
|
@ -189,12 +222,23 @@ func (r *Router) encryptedStateUpdates(ctx context.Context, userID int64) (updat
|
|||
if gerr != nil || !found {
|
||||
continue
|
||||
}
|
||||
updates = append(updates, &tg.UpdateEncryption{
|
||||
Chat: tgEncryptedChatForViewer(chat, userID),
|
||||
Date: ev.Date,
|
||||
})
|
||||
peerUserIDs = append(peerUserIDs, chat.AdminUserID, chat.ParticipantUserID)
|
||||
eventIDs = append(eventIDs, ev.ID)
|
||||
if _, duplicate := seenEncryption[chat.ID]; duplicate {
|
||||
continue
|
||||
}
|
||||
seenEncryption[chat.ID] = struct{}{}
|
||||
|
||||
chatView := tgEncryptedChatForViewer(chat, userID)
|
||||
if ev.TargetAuthKeyID == 0 && chat.State == domain.SecretChatStateNormal {
|
||||
// 账号级事件只承载 accept 前邀请。accept 后获胜设备已有同步响应;其它设备
|
||||
// 必须收敛为 discarded,不能用当前 normal 权威态泄漏 access_hash/g_a。
|
||||
if chat.AuthKeyOf(userID) == deviceKey {
|
||||
continue
|
||||
}
|
||||
chatView = &tg.EncryptedChatDiscarded{ID: chat.ID, HistoryDeleted: true}
|
||||
}
|
||||
updates = append(updates, &tg.UpdateEncryption{Chat: chatView, Date: ev.Date})
|
||||
peerUserIDs = append(peerUserIDs, chat.AdminUserID, chat.ParticipantUserID)
|
||||
case domain.EncryptedStateEventRead:
|
||||
updates = append(updates, &tg.UpdateEncryptedMessagesRead{
|
||||
ChatID: ev.ChatID,
|
||||
|
|
@ -204,7 +248,7 @@ func (r *Router) encryptedStateUpdates(ctx context.Context, userID int64) (updat
|
|||
eventIDs = append(eventIDs, ev.ID)
|
||||
}
|
||||
}
|
||||
return updates, peerUserIDs, eventIDs
|
||||
return updates, peerUserIDs, eventIDs, partial, nil
|
||||
}
|
||||
|
||||
// injectEncryptedOtherUpdates 把握手/已读 update 追加进差分的 OtherUpdates、把 peer
|
||||
|
|
@ -214,6 +258,24 @@ func (r *Router) injectEncryptedOtherUpdates(ctx context.Context, viewerUserID i
|
|||
return diff
|
||||
}
|
||||
users := r.tgUsersForIDs(ctx, viewerUserID, peerUserIDs)
|
||||
return appendEncryptedOtherUpdates(diff, updates, users)
|
||||
}
|
||||
|
||||
func (r *Router) injectEncryptedOtherUpdatesStrict(ctx context.Context, viewerUserID int64, diff tg.UpdatesDifferenceClass, updates []tg.UpdateClass, peerUserIDs []int64, cache *viewerPeerCache) (tg.UpdatesDifferenceClass, error) {
|
||||
if len(updates) == 0 {
|
||||
return diff, nil
|
||||
}
|
||||
if cache == nil {
|
||||
cache = newViewerPeerCache(r)
|
||||
}
|
||||
users, err := cache.usersForIDsStrict(ctx, viewerUserID, peerUserIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appendEncryptedOtherUpdates(diff, updates, r.tgUsersForViewer(viewerUserID, users)), nil
|
||||
}
|
||||
|
||||
func appendEncryptedOtherUpdates(diff tg.UpdatesDifferenceClass, updates []tg.UpdateClass, users []tg.UserClass) tg.UpdatesDifferenceClass {
|
||||
switch v := diff.(type) {
|
||||
case *tg.UpdatesDifference:
|
||||
v.OtherUpdates = append(v.OtherUpdates, updates...)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue