fix: confirm the room ticket again after joining so a revocation during the join drops the connection

This commit is contained in:
DiheChen committed 2026-11-08 23:38:38 +08:00
1 parent 4f6858b17c
commit 5ee219caba
2 files changed
+58 -1

No files matched your search

+10 -1
View File
@@ -133,7 +133,16 @@ func (s *Service) EnterRoom(ctx context.Context, roomID, ticket string) (*realti
if holder.Bot {
return nil, ErrBotSession
}
return s.gateway.Join(logctx.WithMember(logctx.WithRoom(ctx, r.Info.ID), holder.Member.ID), r.Info.ID, holder.Member, holder.SessionTokenHash)
session, err := s.gateway.Join(logctx.WithMember(logctx.WithRoom(ctx, r.Info.ID), holder.Member.ID), r.Info.ID, holder.Member, holder.SessionTokenHash)
if err != nil {
return nil, err
}
// 作废时先删除票据、再通知断开:会话加入网关之前发出的通知它收不到,所以加入之后再确认一次票据。
if _, err := s.VerifyTicket(ctx, ticket); err != nil {
s.gateway.Leave(session)
return nil, err
}
return session, nil
}
func NewAPIKey() (string, port.NewAPIKey) {
+48
View File
@@ -9,6 +9,7 @@ import (
"log/slog"
"regexp"
"testing"
"testing/synctest"
"github.com/dihemoe/alisten/internal/app/port"
"github.com/dihemoe/alisten/internal/app/port/porttest"
@@ -170,6 +171,53 @@ func TestIssueTicketRejectsDeletedSession(t *testing.T) {
}
}
// 第一次查询照常,之后的查询都认为票据已经作废。
type revokedAfterFirstLookup struct {
port.Tickets
lookups int
}
func (r *revokedAfterFirstLookup) TicketHolder(ctx context.Context, tokenHash []byte) (port.TicketHolder, error) {
r.lookups++
if r.lookups > 1 {
return port.TicketHolder{}, port.ErrTicketNotFound
}
return r.Tickets.TicketHolder(ctx, tokenHash)
}
func TestEnterRoomLeavesWhenTicketIsRevokedWhileJoining(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
store := porttest.New()
node := porttest.NewRedis().Node("a")
host, gateway := realtime.New(store, store, nil, porttest.NewPreparer(), realtime.Cluster{Instance: "a", Leases: node, Liveness: node, Bus: node}, slog.New(slog.DiscardHandler))
ctx, stop := context.WithCancel(t.Context())
wait, err := realtime.Start(ctx, host, gateway)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
_ = host.Shutdown(context.Background())
_ = gateway.Shutdown(context.Background())
stop()
wait()
})
s := New(store, store, &revokedAfterFirstLookup{Tickets: store}, gateway)
alice := createMember(t, s)
id := createRoom(t, store, "")
ticket, err := s.IssueTicket(t.Context(), alice.Member.ID, alice.MemberToken, id, "")
if err != nil {
t.Fatal(err)
}
if _, err := s.EnterRoom(t.Context(), id, ticket); !errors.Is(err, ErrInvalidTicket) {
t.Errorf("加入期间票据被作废,错误 = %v,期望 ErrInvalidTicket", err)
}
if n := gateway.Sessions(); n != 0 {
t.Errorf("网关上残留 %d 个会话,期望 0", n)
}
})
}
type loggedSubscriptions struct {
port.Bus
logger *slog.Logger