added messages templates

This commit is contained in:
onysd 2026-09-01 14:40:06 +03:00
parent e8dc967e6a
commit 7cd1f64d0d
29 changed files with 1266 additions and 84 deletions

View file

@ -52,11 +52,24 @@ func SameLoginCodeFingerprint(stored []byte, expected [sha256.Size]byte) bool {
// RestoreLoginCodeDeliveryMessage reconstructs the immutable first result from
// a compact receipt. The secret code is not duplicated in the receipt: exact
// replay has already proven the supplied code fingerprint matches.
func RestoreLoginCodeDeliveryMessage(userID int64, code string, date int, privateMessageID int64, messageBoxID, pts int) (domain.Message, error) {
//
// template is the caller's currently-resolved login-code message template
// (see domain.ResolveLoginCodeMessageTemplate), not a historical snapshot of
// whatever template was in effect at original-delivery time -- the receipt
// does not persist that. In the ordinary case (a same-request or
// near-immediate idempotent retry, e.g. resendCode) the template cannot have
// changed in between, so this is a no-op distinction; if an admin edits the
// template in the narrow window between the original delivery and a later
// replay of the same phone_code_hash, the replay's reconstructed Body/Entities
// reflect the *current* template rather than the one actually persisted in
// the messages table, mirroring this codebase's established "identity is
// always read fresh, never versioned" convention (see internal/identity's
// package doc comment) rather than a regression specific to this function.
func RestoreLoginCodeDeliveryMessage(userID int64, template, code string, date int, privateMessageID int64, messageBoxID, pts int) (domain.Message, error) {
if privateMessageID <= 0 || messageBoxID <= 0 || messageBoxID > domain.MaxMessageBoxID || pts <= 0 {
return domain.Message{}, fmt.Errorf("restore login code delivery: %w: uid=%d box=%d pts=%d", domain.ErrLoginCodeDeliveryInvalid, privateMessageID, messageBoxID, pts)
}
msg, err := domain.OfficialLoginCodeMessage(userID, code, date)
msg, err := domain.OfficialLoginCodeMessage(userID, template, code, date)
if err != nil {
return domain.Message{}, err
}

View file

@ -49,11 +49,12 @@ func TestLoginCodeDeliveryKeyAndFingerprint(t *testing.T) {
}
func TestRestoreLoginCodeDeliveryMessage(t *testing.T) {
got, err := RestoreLoginCodeDeliveryMessage(1000000001, "12345", 1700000000, 91, 7, 12)
const template = "Your code is {{code}}."
got, err := RestoreLoginCodeDeliveryMessage(1000000001, template, "12345", 1700000000, 91, 7, 12)
if err != nil {
t.Fatalf("RestoreLoginCodeDeliveryMessage: %v", err)
}
want, err := domain.OfficialLoginCodeMessage(1000000001, "12345", 1700000000)
want, err := domain.OfficialLoginCodeMessage(1000000001, template, "12345", 1700000000)
if err != nil {
t.Fatalf("OfficialLoginCodeMessage: %v", err)
}
@ -61,7 +62,7 @@ func TestRestoreLoginCodeDeliveryMessage(t *testing.T) {
if !reflect.DeepEqual(got, want) {
t.Fatalf("restored message = %+v, want %+v", got, want)
}
if _, err := RestoreLoginCodeDeliveryMessage(1000000001, "12345", 1700000000, 0, 7, 12); !errors.Is(err, domain.ErrLoginCodeDeliveryInvalid) {
if _, err := RestoreLoginCodeDeliveryMessage(1000000001, template, "12345", 1700000000, 0, 7, 12); !errors.Is(err, domain.ErrLoginCodeDeliveryInvalid) {
t.Fatalf("invalid uid err = %v, want ErrLoginCodeDeliveryInvalid", err)
}
}

View file

@ -53,7 +53,7 @@ func (s *LoginCodeDeliveryStore) DeliverLoginCodeMessage(_ context.Context, req
if req.ExpiresAt <= int64(req.Date) {
return domain.LoginCodeDeliveryResult{}, fmt.Errorf("memory login code receipt expiry: %w: date=%d expires_at=%d", domain.ErrLoginCodeDeliveryInvalid, req.Date, req.ExpiresAt)
}
base, err := domain.OfficialLoginCodeMessage(req.UserID, req.Code, req.Date)
base, err := domain.OfficialLoginCodeMessage(req.UserID, req.Template, req.Code, req.Date)
if err != nil {
return domain.LoginCodeDeliveryResult{}, err
}
@ -70,6 +70,7 @@ func (s *LoginCodeDeliveryStore) DeliverLoginCodeMessage(_ context.Context, req
}
msg, err := store.RestoreLoginCodeDeliveryMessage(
receipt.userID,
req.Template,
req.Code,
receipt.messageDate,
receipt.privateMessageID,

View file

@ -55,7 +55,7 @@ func (s *MessageStore) DeliverLoginCodeMessage(ctx context.Context, req domain.L
if req.ExpiresAt <= int64(req.Date) {
return domain.LoginCodeDeliveryResult{}, fmt.Errorf("login code receipt expiry: %w: date=%d expires_at=%d", domain.ErrLoginCodeDeliveryInvalid, req.Date, req.ExpiresAt)
}
base, err := domain.OfficialLoginCodeMessage(req.UserID, req.Code, req.Date)
base, err := domain.OfficialLoginCodeMessage(req.UserID, req.Template, req.Code, req.Date)
if err != nil {
return domain.LoginCodeDeliveryResult{}, err
}
@ -99,6 +99,7 @@ func (s *MessageStore) DeliverLoginCodeMessage(ctx context.Context, req domain.L
}
msg, err := store.RestoreLoginCodeDeliveryMessage(
receipt.userID,
req.Template,
req.Code,
receipt.messageDate,
receipt.privateMessageID,
@ -266,6 +267,7 @@ func (s *MessageStore) recoverLoginCodeDeliveryAfterCommitError(
}
msg, err := store.RestoreLoginCodeDeliveryMessage(
receipt.userID,
req.Template,
req.Code,
receipt.messageDate,
receipt.privateMessageID,