perf: sync protocol and core hardening updates
This commit is contained in:
parent
152fed3b87
commit
4390ebf5a9
283 changed files with 29231 additions and 2295 deletions
84
internal/rpc/message_idempotency.go
Normal file
84
internal/rpc/message_idempotency.go
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"github.com/gotd/td/bin"
|
||||
"github.com/gotd/td/tg"
|
||||
)
|
||||
|
||||
// rpcRequestFingerprint 在任何自动实体补全、链接预览解析或上传媒体落库之前,
|
||||
// 对客户端原始 TL request 取稳定指纹。这样 lost-response 重放不会因服务端派生
|
||||
// photo/document id、pending webpage 状态等变化而被误判为另一条消息。
|
||||
func rpcRequestFingerprint(req bin.Encoder) ([]byte, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("fingerprint rpc request: nil request")
|
||||
}
|
||||
var b bin.Buffer
|
||||
if err := req.Encode(&b); err != nil {
|
||||
return nil, fmt.Errorf("fingerprint rpc request: %w", err)
|
||||
}
|
||||
sum := sha256.Sum256(b.Raw())
|
||||
return sum[:], nil
|
||||
}
|
||||
|
||||
// sendMessageIdempotencyFingerprint fingerprints only the durable message intent.
|
||||
// clear_draft/background/update_stickersets_order are one-shot client-side delivery
|
||||
// hints: after a lost response DrKLO/TDesktop may legitimately retry the same
|
||||
// random_id without them. They must not turn an exact send replay into
|
||||
// RANDOM_ID_DUPLICATE.
|
||||
func sendMessageIdempotencyFingerprint(req *tg.MessagesSendMessageRequest) ([]byte, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("fingerprint messages.sendMessage: nil request")
|
||||
}
|
||||
clone := *req
|
||||
clone.Flags = 0
|
||||
clone.ClearDraft = false
|
||||
clone.Background = false
|
||||
clone.UpdateStickersetsOrder = false
|
||||
return rpcRequestFingerprint(&clone)
|
||||
}
|
||||
|
||||
func sendMediaIdempotencyFingerprint(req *tg.MessagesSendMediaRequest) ([]byte, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("fingerprint messages.sendMedia: nil request")
|
||||
}
|
||||
clone := *req
|
||||
clone.Flags = 0
|
||||
clone.ClearDraft = false
|
||||
clone.Background = false
|
||||
clone.UpdateStickersetsOrder = false
|
||||
return rpcRequestFingerprint(&clone)
|
||||
}
|
||||
|
||||
// sendMultiMediaItemIdempotencyFingerprint deliberately reduces a batch to one
|
||||
// InputSingleMedia. A retry containing only the failed subset therefore produces
|
||||
// the same fingerprint for every surviving random_id as the original batch.
|
||||
func sendMultiMediaItemIdempotencyFingerprint(req *tg.MessagesSendMultiMediaRequest, item tg.InputSingleMedia) ([]byte, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("fingerprint messages.sendMultiMedia item: nil request")
|
||||
}
|
||||
clone := *req
|
||||
clone.Flags = 0
|
||||
clone.ClearDraft = false
|
||||
clone.Background = false
|
||||
clone.UpdateStickersetsOrder = false
|
||||
clone.MultiMedia = []tg.InputSingleMedia{item}
|
||||
return rpcRequestFingerprint(&clone)
|
||||
}
|
||||
|
||||
// forwardMessagesItemIdempotencyFingerprint makes the source message id and its
|
||||
// paired random_id the unit of idempotency. Hashing the full ID/RandomID vectors
|
||||
// incorrectly rejects a legal retry that contains only a failed subset.
|
||||
func forwardMessagesItemIdempotencyFingerprint(req *tg.MessagesForwardMessagesRequest, messageID int, randomID int64) ([]byte, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("fingerprint messages.forwardMessages item: nil request")
|
||||
}
|
||||
clone := *req
|
||||
clone.Flags = 0
|
||||
clone.Background = false
|
||||
clone.ID = []int{messageID}
|
||||
clone.RandomID = []int64{randomID}
|
||||
return rpcRequestFingerprint(&clone)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue