feat: sync durable moderation and appeals
This commit is contained in:
parent
e1a95c7318
commit
9f467f4be7
140 changed files with 13730 additions and 316 deletions
53
internal/app/authdiagnostics/service.go
Normal file
53
internal/app/authdiagnostics/service.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package authdiagnostics
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
codes store.CodeStore
|
||||
reports store.AuthDeliveryReportStore
|
||||
}
|
||||
|
||||
func NewService(codes store.CodeStore, reports store.AuthDeliveryReportStore) *Service {
|
||||
return &Service{codes: codes, reports: reports}
|
||||
}
|
||||
|
||||
func (s *Service) ReportMissingCode(ctx context.Context, req domain.AuthMissingCodeReportRequest) (domain.AuthDeliveryReport, bool, error) {
|
||||
phone := domain.NormalizePhone(req.Phone)
|
||||
if s == nil || s.codes == nil || s.reports == nil ||
|
||||
!domain.ValidPhone(phone) || req.PhoneCodeHash == "" {
|
||||
return domain.AuthDeliveryReport{}, false, domain.ErrPhoneCodeInvalid
|
||||
}
|
||||
record, found, err := s.codes.Get(ctx, req.PhoneCodeHash)
|
||||
if err != nil {
|
||||
return domain.AuthDeliveryReport{}, false, err
|
||||
}
|
||||
if !found {
|
||||
return domain.AuthDeliveryReport{}, false, domain.ErrPhoneCodeExpired
|
||||
}
|
||||
if record.Version != store.PhoneCodeVersionCurrent || record.Purpose != "" ||
|
||||
record.Phone != phone || !store.LoginCodeChannelVerifiable(record.Channel) {
|
||||
return domain.AuthDeliveryReport{}, false, domain.ErrPhoneCodeInvalid
|
||||
}
|
||||
var channel domain.AuthCodeDeliveryKind
|
||||
switch record.Channel {
|
||||
case store.PhoneCodeChannelPhone:
|
||||
channel = domain.AuthCodeDeliveryPhone
|
||||
case store.PhoneCodeChannelSMS:
|
||||
channel = domain.AuthCodeDeliverySMS
|
||||
default:
|
||||
return domain.AuthDeliveryReport{}, false, domain.ErrPhoneCodeInvalid
|
||||
}
|
||||
report, err := domain.NewAuthDeliveryReport(
|
||||
req.AuthKeyID, req.SessionID, req.ClientType, phone, req.PhoneCodeHash,
|
||||
record.IssuedUserID, record.DeliveryID, channel, req.MNC, req.CreatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return domain.AuthDeliveryReport{}, false, err
|
||||
}
|
||||
return s.reports.CreateAuthDeliveryReport(ctx, report)
|
||||
}
|
||||
81
internal/app/authdiagnostics/service_test.go
Normal file
81
internal/app/authdiagnostics/service_test.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package authdiagnostics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store"
|
||||
"telesrv/internal/store/memory"
|
||||
)
|
||||
|
||||
func TestReportMissingCodeValidatesLiveDeliveryAndStoresOnlyHashes(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
codes := memory.NewCodeStore()
|
||||
reports := memory.NewAuthDeliveryReportStore()
|
||||
const (
|
||||
phone = "15550001234"
|
||||
codeHash = "login-code-hash"
|
||||
)
|
||||
if err := codes.Set(ctx, codeHash, store.PhoneCode{
|
||||
Version: store.PhoneCodeVersionCurrent, Phone: phone, Code: "12345",
|
||||
DeliveryID: "delivery-1", Channel: store.PhoneCodeChannelSMS,
|
||||
IssuedUserID: 42,
|
||||
}, time.Hour); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service := NewService(codes, reports)
|
||||
now := time.Now().UTC()
|
||||
req := domain.AuthMissingCodeReportRequest{
|
||||
AuthKeyID: [8]byte{1, 2, 3}, SessionID: 99, ClientType: "tdesktop",
|
||||
Phone: "+1 (555) 000-1234", PhoneCodeHash: codeHash, MNC: "46000",
|
||||
CreatedAt: now,
|
||||
}
|
||||
first, created, err := service.ReportMissingCode(ctx, req)
|
||||
if err != nil || !created {
|
||||
t.Fatalf("first report created=%v err=%v", created, err)
|
||||
}
|
||||
second, created, err := service.ReportMissingCode(ctx, req)
|
||||
if err != nil || created || second.ID != first.ID {
|
||||
t.Fatalf("retry report=%+v created=%v err=%v", second, created, err)
|
||||
}
|
||||
stored := reports.Reports()
|
||||
if len(stored) != 1 {
|
||||
t.Fatalf("stored reports=%d, want 1", len(stored))
|
||||
}
|
||||
if stored[0].PhoneHash != sha256.Sum256([]byte(phone)) ||
|
||||
stored[0].CodeHash != sha256.Sum256([]byte(codeHash)) {
|
||||
t.Fatalf("stored hashes do not match normalized delivery identity: %+v", stored[0])
|
||||
}
|
||||
if stored[0].DeliveryID != "delivery-1" || stored[0].IssuedUserID != 42 ||
|
||||
stored[0].Channel != domain.AuthCodeDeliverySMS {
|
||||
t.Fatalf("stored delivery metadata=%+v", stored[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestReportMissingCodeRejectsUnknownOrMismatchedLoginState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
codes := memory.NewCodeStore()
|
||||
service := NewService(codes, memory.NewAuthDeliveryReportStore())
|
||||
now := time.Now().UTC()
|
||||
base := domain.AuthMissingCodeReportRequest{
|
||||
AuthKeyID: [8]byte{1}, SessionID: 10, Phone: "15550002222",
|
||||
PhoneCodeHash: "missing", CreatedAt: now,
|
||||
}
|
||||
if _, _, err := service.ReportMissingCode(ctx, base); !errors.Is(err, domain.ErrPhoneCodeExpired) {
|
||||
t.Fatalf("missing hash err=%v, want phone-code expired", err)
|
||||
}
|
||||
if err := codes.Set(ctx, "current", store.PhoneCode{
|
||||
Version: store.PhoneCodeVersionCurrent, Phone: "15550003333",
|
||||
Channel: store.PhoneCodeChannelPhone,
|
||||
}, time.Hour); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
base.PhoneCodeHash = "current"
|
||||
if _, _, err := service.ReportMissingCode(ctx, base); !errors.Is(err, domain.ErrPhoneCodeInvalid) {
|
||||
t.Fatalf("mismatched phone err=%v, want phone-code invalid", err)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue