fix
This commit is contained in:
parent
ef325f31da
commit
79c64ee916
14 changed files with 283 additions and 50 deletions
|
|
@ -23,6 +23,10 @@ type Service struct {
|
|||
participantCache *participantsReadModelCache
|
||||
activeIDsCache *activeChannelIDsReadModelCache
|
||||
botMemberIDsCache *activeBotMemberIDsCache
|
||||
// reserved blocks the self-service UpdateUsername (not AdminSetUsername)
|
||||
// from claiming a config.ReservedUsernames entry -- see
|
||||
// domain.ReservedUsernameSet.
|
||||
reserved domain.ReservedUsernameSet
|
||||
}
|
||||
|
||||
type Option func(*Service)
|
||||
|
|
@ -68,6 +72,14 @@ func WithSendPermissionChecker(c SendPermissionChecker) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// WithReservedUsernames mirrors config.ReservedUsernames: the self-service
|
||||
// UpdateUsername refuses to set any of these.
|
||||
func WithReservedUsernames(names []string) Option {
|
||||
return func(s *Service) {
|
||||
s.reserved = domain.NewReservedUsernameSet(names)
|
||||
}
|
||||
}
|
||||
|
||||
// CreateMegagroupFromCreateChat handles messages.createChat by directly creating a megagroup.
|
||||
func (s *Service) CreateMegagroupFromCreateChat(ctx context.Context, userID int64, req domain.CreateChannelRequest) (domain.CreateChannelResult, error) {
|
||||
req.CreatorUserID = userID
|
||||
|
|
@ -501,8 +513,19 @@ func (s *Service) UpdateUsername(ctx context.Context, userID int64, req domain.U
|
|||
return domain.Channel{}, domain.ErrChannelInvalid
|
||||
}
|
||||
req.Username = normalizeChannelUsername(req.Username)
|
||||
if req.Username != "" && !validChannelUsername(req.Username) {
|
||||
return domain.Channel{}, domain.ErrUsernameInvalid
|
||||
// Re-submitting the username the channel already has is a no-op, not a
|
||||
// claim -- checked before any validation (including the reserved-word
|
||||
// list) so a name that was fine to keep before this feature existed (or
|
||||
// before it was added to config.ReservedUsernames) never gets rejected
|
||||
// just because the client re-sent an unchanged value.
|
||||
current, err := s.channels.GetChannelByID(ctx, req.ChannelID)
|
||||
if err != nil {
|
||||
return domain.Channel{}, err
|
||||
}
|
||||
if !strings.EqualFold(current.Username, req.Username) {
|
||||
if req.Username != "" && (!validChannelUsername(req.Username) || s.reserved.Contains(req.Username)) {
|
||||
return domain.Channel{}, domain.ErrUsernameInvalid
|
||||
}
|
||||
}
|
||||
return s.channels.UpdateUsername(ctx, req)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2716,6 +2716,46 @@ func TestChannelUsernameAndSignatures(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestChannelUsernameReservedBlocksNewClaimsButKeepsExisting mirrors
|
||||
// internal/app/users' identical test: adding a word to
|
||||
// config.ReservedUsernames (or turning the feature on after a channel
|
||||
// already owns a matching username) must never break a channel that
|
||||
// already has it -- only a genuinely new claim of a reserved word is
|
||||
// refused.
|
||||
func TestChannelUsernameReservedBlocksNewClaimsButKeepsExisting(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
channelStore := memory.NewChannelStore()
|
||||
service := NewService(channelStore, WithReservedUsernames([]string{"admin"}))
|
||||
grandfathered, err := service.CreateMegagroupFromCreateChat(ctx, 1001, domain.CreateChannelRequest{Title: "Old", Date: 10})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateMegagroupFromCreateChat: %v", err)
|
||||
}
|
||||
if _, err := channelStore.UpdateUsername(ctx, domain.UpdateChannelUsernameRequest{
|
||||
ChannelID: grandfathered.Channel.ID,
|
||||
UserID: 1001,
|
||||
Username: "admin",
|
||||
}); err != nil {
|
||||
t.Fatalf("seed grandfathered username directly on the store: %v", err)
|
||||
}
|
||||
newcomer, err := service.CreateMegagroupFromCreateChat(ctx, 1002, domain.CreateChannelRequest{Title: "New", Date: 11})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateMegagroupFromCreateChat other: %v", err)
|
||||
}
|
||||
|
||||
// Re-submitting the exact same (grandfathered) reserved username falls
|
||||
// through to the store's own no-op detection (ErrChannelNotModified),
|
||||
// not a validation rejection -- reaching that error at all proves the
|
||||
// reserved check was bypassed for the unchanged value.
|
||||
if _, err := service.UpdateUsername(ctx, 1001, domain.UpdateChannelUsernameRequest{ChannelID: grandfathered.Channel.ID, Username: "@Admin"}); !errors.Is(err, domain.ErrChannelNotModified) {
|
||||
t.Fatalf("re-submit grandfathered username err = %v, want ErrChannelNotModified", err)
|
||||
}
|
||||
// A different channel claiming the same reserved word for the first
|
||||
// time must still be refused.
|
||||
if _, err := service.UpdateUsername(ctx, 1002, domain.UpdateChannelUsernameRequest{ChannelID: newcomer.Channel.ID, Username: "admin"}); !errors.Is(err, domain.ErrUsernameInvalid) {
|
||||
t.Fatalf("new claim of reserved username err = %v, want username invalid", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListStoryPostableChannelsFiltersPostStoryRights(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
service := NewService(memory.NewChannelStore())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue