perf: sync protocol and core hardening updates

This commit is contained in:
A 2026-07-11 19:48:26 +08:00
parent 152fed3b87
commit 4390ebf5a9
283 changed files with 29231 additions and 2295 deletions

View file

@ -0,0 +1,28 @@
package messages
import (
"context"
"errors"
"telesrv/internal/domain"
"telesrv/internal/store"
)
// ReserveAlbumGroup 把 RPC 已验证的一批 album item 交给持久层原子预留。
// 该能力只传 domain DTO;上传媒体解析与 tg 类型仍停留在 RPC edge。
func (s *Service) ReserveAlbumGroup(ctx context.Context, userID int64, req domain.AlbumGroupReservationRequest) (int64, error) {
if s == nil || s.messages == nil || userID <= 0 {
return 0, domain.ErrAlbumGroupReservationInvalid
}
if req.SenderUserID == 0 {
req.SenderUserID = userID
}
if req.SenderUserID != userID {
return 0, domain.ErrAlbumGroupReservationInvalid
}
reservations, ok := s.messages.(store.AlbumGroupStore)
if !ok {
return 0, errors.New("message store does not support album group reservations")
}
return reservations.ReserveAlbumGroup(ctx, req)
}

View file

@ -2,6 +2,7 @@ package messages
import (
"context"
"fmt"
"telesrv/internal/app/userprojection"
"telesrv/internal/domain"
@ -96,6 +97,28 @@ func (s *Service) SendPrivateText(ctx context.Context, userID int64, req domain.
if req.SenderUserID == 0 {
req.SenderUserID = userID
}
if req.SenderUserID != userID {
return domain.SendPrivateTextResult{}, domain.ErrUserSendRestricted
}
if req.RandomID != 0 && !req.IdempotencyPreflighted {
fingerprint, err := store.PrivateSendFingerprint(req)
if err != nil {
return domain.SendPrivateTextResult{}, err
}
req.IdempotencyFingerprint = fingerprint
if replayStore, ok := s.messages.(store.PrivateSendReplayStore); ok {
replay, found, err := replayStore.LookupPrivateSendReplay(ctx, domain.PrivateSendReplayRequest{
SenderUserID: req.SenderUserID,
RecipientUserID: req.RecipientUserID,
RandomID: req.RandomID,
IdempotencyFingerprint: fingerprint,
})
if err != nil || found {
return replay, err
}
req.IdempotencyPreflighted = true
}
}
if err := s.ensureCanSend(ctx, req.SenderUserID); err != nil {
return domain.SendPrivateTextResult{}, err
}
@ -113,6 +136,26 @@ func (s *Service) SendPrivateText(ctx context.Context, userID int64, req domain.
return res, err
}
// LookupPrivateSendReplay exposes the immutable receipt to the RPC boundary without executing
// send permission checks, business automation or bot responders. Sender identity is still bound
// to the authenticated app-service caller.
func (s *Service) LookupPrivateSendReplay(ctx context.Context, userID int64, req domain.PrivateSendReplayRequest) (domain.SendPrivateTextResult, bool, error) {
if s == nil || s.messages == nil || userID == 0 {
return domain.SendPrivateTextResult{}, false, nil
}
if req.SenderUserID == 0 {
req.SenderUserID = userID
}
if req.SenderUserID != userID || req.RecipientUserID == 0 || req.RandomID == 0 {
return domain.SendPrivateTextResult{}, false, fmt.Errorf("private send replay: invalid authenticated scope")
}
replayStore, ok := s.messages.(store.PrivateSendReplayStore)
if !ok {
return domain.SendPrivateTextResult{}, false, nil
}
return replayStore.LookupPrivateSendReplay(ctx, req)
}
func (s *Service) ensureCanSend(ctx context.Context, userID int64) error {
if s == nil || s.sendGate == nil || userID == 0 {
return nil

View file

@ -29,6 +29,38 @@ func TestServiceSendPrivateTextHonorsSendPermissionGate(t *testing.T) {
}
}
func TestServicePrivateReplayPrecedesCurrentSendPermissionGate(t *testing.T) {
ctx := context.Background()
messages := memory.NewMessageStore()
allowed := NewService(messages, nil)
req := domain.SendPrivateTextRequest{
SenderUserID: 1001,
RecipientUserID: 1002,
RandomID: 91,
Message: "committed before restriction",
Date: 1_700_000_000,
}
first, err := allowed.SendPrivateText(ctx, 1001, req)
if err != nil {
t.Fatalf("first SendPrivateText: %v", err)
}
denied := NewService(messages, nil, WithSendPermissionChecker(denySendChecker{}))
req.Date++ // execution time is not part of the immutable send intent.
replay, err := denied.SendPrivateText(ctx, 1001, req)
if err != nil {
t.Fatalf("replay through denied gate: %v", err)
}
if !replay.Duplicate || replay.SenderMessage.ID != first.SenderMessage.ID {
t.Fatalf("replay = %+v, want committed duplicate %d", replay, first.SenderMessage.ID)
}
req.Message = "different intent"
if _, err := denied.SendPrivateText(ctx, 1001, req); !errors.Is(err, domain.ErrMessageRandomIDDuplicate) {
t.Fatalf("conflicting replay err=%v, want ErrMessageRandomIDDuplicate before send gate", err)
}
}
func TestServiceForwardPrivateMessagesHonorsSendPermissionGate(t *testing.T) {
ctx := context.Background()
store := &gateMessageStore{}