owpengram-server/internal/app/auth/login_code_message_template_test.go
2026-09-01 14:40:06 +03:00

122 lines
4.8 KiB
Go

package auth
import (
"context"
"strings"
"testing"
"telesrv/internal/domain"
"telesrv/internal/identity"
"telesrv/internal/store/memory"
)
// TestLoginCodeMessageTemplateResolutionPrecedence exercises
// WithLoginCodeMessageTemplate/resolveLoginCodeMessageTemplate's precedence
// (panel override > env default > compiled-in default) end to end through
// SignUp's bootstrap recordLoginMessage path (phone channel, no owner/dialog
// yet -- see service.go's rec.Channel == codeChannelPhone branch), mirroring
// how welcome_message_test.go exercises WithLoginWelcomeMessages.
func TestLoginCodeMessageTemplateResolutionPrecedence(t *testing.T) {
ctx := context.Background()
newSvc := func(store *identity.Store, envDefault string) (*Service, *memory.MessageStore) {
dialogs := memory.NewDialogStore()
messages := memory.NewMessageStore(dialogs)
return NewService(memory.NewUserStore(), memory.NewAuthorizationStore(), memory.NewCodeStore(), nil, nil, "12345",
WithLoginMessages(messages, dialogs),
WithLoginCodeMessageTemplate(store, envDefault),
), messages
}
// No override, no env default: falls back to the compiled-in default.
t.Run("compiled-in default", func(t *testing.T) {
svc, messages := newSvc(nil, "")
u := signUpPhoneForLoginCodeMessage(t, ctx, svc, "+15550771001")
body := codeMessageBody(t, ctx, messages, u.ID)
if !strings.Contains(body, "Login code: 12345") {
t.Fatalf("body = %q, want compiled-in default rendering", body)
}
})
// Env default set, no panel override: env default wins.
t.Run("env default", func(t *testing.T) {
svc, messages := newSvc(nil, "Env says your code is {{code}}.")
u := signUpPhoneForLoginCodeMessage(t, ctx, svc, "+15550771002")
body := codeMessageBody(t, ctx, messages, u.ID)
if body != "Env says your code is 12345." {
t.Fatalf("body = %q, want env-default rendering", body)
}
})
// Panel override set: wins over both the env default and the compiled-in
// default, and is read fresh (not cached) -- see resolveLoginCodeMessageTemplate.
t.Run("panel override wins and is read fresh", func(t *testing.T) {
store := identity.NewStore(t.TempDir())
svc, messages := newSvc(store, "Env says your code is {{code}}.")
u := signUpPhoneForLoginCodeMessage(t, ctx, svc, "+15550771003")
body := codeMessageBody(t, ctx, messages, u.ID)
if body != "Env says your code is 12345." {
t.Fatalf("body before override = %q, want env-default rendering", body)
}
if err := store.SetLoginCodeMessageTemplate("Panel says your code is {{code}}."); err != nil {
t.Fatalf("SetLoginCodeMessageTemplate: %v", err)
}
u2 := signUpPhoneForLoginCodeMessage(t, ctx, svc, "+15550771004")
body2 := codeMessageBody(t, ctx, messages, u2.ID)
if body2 != "Panel says your code is 12345." {
t.Fatalf("body after override = %q, want panel-override rendering with no restart", body2)
}
})
// A saved-but-somehow-invalid panel override (missing {{code}} --
// bypassing the admin-API validation, e.g. a hand-edited identity.json)
// must never reach a client with the code silently missing: defense in
// depth falls back to the compiled-in default instead.
t.Run("invalid panel override falls back safely", func(t *testing.T) {
store := identity.NewStore(t.TempDir())
if err := store.SetLoginCodeMessageTemplate("no placeholder here"); err != nil {
t.Fatalf("SetLoginCodeMessageTemplate: %v", err)
}
svc, messages := newSvc(store, "")
u := signUpPhoneForLoginCodeMessage(t, ctx, svc, "+15550771005")
body := codeMessageBody(t, ctx, messages, u.ID)
if !strings.Contains(body, "12345") {
t.Fatalf("body = %q, want the code delivered via fallback despite invalid override", body)
}
})
}
func signUpPhoneForLoginCodeMessage(t *testing.T, ctx context.Context, svc *Service, phone string) domain.User {
t.Helper()
hash, err := svc.SendCode(ctx, phone)
if err != nil {
t.Fatalf("SendCode: %v", err)
}
verifyCodeForSignUp(t, svc, phone, hash, "12345")
u, _, err := svc.SignUp(ctx, domain.Authorization{}, phone, hash, "Code", "Template")
if err != nil {
t.Fatalf("SignUp: %v", err)
}
return u
}
// codeMessageBody finds the login-code delivery message among the user's
// full message history (not the dialog summary, which only tracks each
// peer's single top message -- SignUp's welcome message overwrites the
// 777000 dialog's top message right after the login-code one is written).
func codeMessageBody(t *testing.T, ctx context.Context, messages *memory.MessageStore, userID int64) string {
t.Helper()
list, err := messages.ListByUser(ctx, userID, domain.MessageFilter{Limit: 10})
if err != nil {
t.Fatalf("ListByUser: %v", err)
}
for _, msg := range list.Messages {
if strings.Contains(msg.Body, "12345") {
return msg.Body
}
}
t.Fatalf("no login-code message (containing 12345) found among %d messages for user %d", len(list.Messages), userID)
return ""
}