owpengram-server/internal/rpc/convert_encrypted.go

116 lines
3.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rpc
import (
"encoding/binary"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)
// 密聊Secret Chatdomain ↔ tg 投影。服务端是盲中继g_a/g_b/key_fingerprint
// 原样回放。chat 双视角不对称(见 docs/secret-chat-module.md §3.6
// - access_hash 双方不同(按 viewer 取 admin/participant 列)。
// - GAOrB 对 admin 视角是 g_b、对 participant 视角是 g_aTL 注释钉死)。
// - pending 态admin 看 encryptedChatWaiting无 g_aparticipant 看
// encryptedChatRequested携 g_a
// deviceAuthKeyBytes 把绑定维度的 int64 auth_key_id 转回 [8]byte用于 SessionManager
// 按业务 auth_key 定向投递)。与 businessAuthKeyInt64 互逆(小端)。
func deviceAuthKeyBytes(id int64) [8]byte {
var b [8]byte
binary.LittleEndian.PutUint64(b[:], uint64(id))
return b
}
// tgEncryptedMessage 把 qts 队列里的不透明加密消息投影为 TL EncryptedMessage(Service)。
// 盲中继Bytes 原样回放,不解密。
func tgEncryptedMessage(m domain.SecretChatMessage) tg.EncryptedMessageClass {
if m.IsService {
return &tg.EncryptedMessageService{
RandomID: m.RandomID,
ChatID: m.ChatID,
Date: m.Date,
Bytes: append([]byte(nil), m.Bytes...),
}
}
return &tg.EncryptedMessage{
RandomID: m.RandomID,
ChatID: m.ChatID,
Date: m.Date,
Bytes: append([]byte(nil), m.Bytes...),
File: tgEncryptedFile(m.File),
}
}
// tgEncryptedFile 把密聊文件快照投影为 TL EncryptedFile(Empty)。
func tgEncryptedFile(ref *domain.EncryptedFileRef) tg.EncryptedFileClass {
if ref == nil || ref.ID == 0 {
return &tg.EncryptedFileEmpty{}
}
return &tg.EncryptedFile{
ID: ref.ID,
AccessHash: ref.AccessHash,
Size: ref.Size,
DCID: ref.DCID,
KeyFingerprint: ref.KeyFingerprint,
}
}
// businessAuthKeyInt64 把 ctx 业务视角 auth_key_id[8]byte转成 DB/绑定维度的
// int64。必须与 store/postgres authKeyIDToInt64 同源小端MTProto 即 SHA1 低 64 位),
// 否则密聊绑定键与 update_states/authorizations 对不上。一致性见
// convert_encrypted_test.go。
func businessAuthKeyInt64(id [8]byte) int64 {
return int64(binary.LittleEndian.Uint64(id[:]))
}
// tgEncryptedChatForViewer 把密聊投影为 viewerID 视角的 EncryptedChatClass。
func tgEncryptedChatForViewer(chat domain.SecretChat, viewerID int64) tg.EncryptedChatClass {
if chat.Terminal() {
return &tg.EncryptedChatDiscarded{
HistoryDeleted: chat.HistoryDeleted,
ID: chat.ID,
}
}
accessHash := chat.AccessHashFor(viewerID)
if chat.State == domain.SecretChatStateNormal {
// GAOrBadmin 看 g_b、participant 看 g_a。
gaOrB := chat.GA
if chat.IsAdmin(viewerID) {
gaOrB = chat.GB
}
return &tg.EncryptedChat{
ID: chat.ID,
AccessHash: accessHash,
Date: chat.Date,
AdminID: chat.AdminUserID,
ParticipantID: chat.ParticipantUserID,
GAOrB: append([]byte(nil), gaOrB...),
KeyFingerprint: chat.KeyFingerprint,
}
}
// requested 态admin 视角 waiting无 g_aparticipant 视角 requested携 g_a
if chat.IsAdmin(viewerID) {
return &tg.EncryptedChatWaiting{
ID: chat.ID,
AccessHash: accessHash,
Date: chat.Date,
AdminID: chat.AdminUserID,
ParticipantID: chat.ParticipantUserID,
}
}
requested := &tg.EncryptedChatRequested{
ID: chat.ID,
AccessHash: accessHash,
Date: chat.Date,
AdminID: chat.AdminUserID,
ParticipantID: chat.ParticipantUserID,
GA: append([]byte(nil), chat.GA...),
}
if chat.FolderID != 0 {
requested.FolderID = chat.FolderID
requested.Flags.Set(0)
}
return requested
}