package realname import ( "context" "crypto/rand" "encoding/hex" "errors" "strings" "time" ) type Provider interface { Start(ctx context.Context, req StartRequest) (ProviderResult, error) } type StartRequest struct { UserID uint64 Name string IDNo string } type ProviderResult struct { ProviderOrderNo string Status string MaskedName string MaskedIDNo string VerifiedAt *time.Time FailReason string } type MockProvider struct{} func NewMockProvider() *MockProvider { return &MockProvider{} } func (p *MockProvider) Start(_ context.Context, req StartRequest) (ProviderResult, error) { if strings.TrimSpace(req.Name) == "" || strings.TrimSpace(req.IDNo) == "" { return ProviderResult{}, errors.New("name and id no are required") } orderNo, err := randomOrderNo() if err != nil { return ProviderResult{}, err } now := time.Now() return ProviderResult{ ProviderOrderNo: orderNo, Status: StatusVerified, MaskedName: maskName(req.Name), MaskedIDNo: maskIDNo(req.IDNo), VerifiedAt: &now, }, nil } func randomOrderNo() (string, error) { buf := make([]byte, 8) if _, err := rand.Read(buf); err != nil { return "", err } return "mock_rn_" + hex.EncodeToString(buf), nil } func maskName(name string) string { name = strings.TrimSpace(name) if len([]rune(name)) <= 1 { return name } runes := []rune(name) return string(runes[0]) + strings.Repeat("*", len(runes)-1) } func maskIDNo(idNo string) string { idNo = strings.TrimSpace(idNo) if len(idNo) <= 8 { return idNo } return idNo[:4] + strings.Repeat("*", len(idNo)-8) + idNo[len(idNo)-4:] }