package contacts import ( "net/mail" "strconv" "strings" "github.com/ultisuite/ulti-backend/internal/api/apivalidate" "github.com/ultisuite/ulti-backend/internal/nextcloud" ) const ( maxRequestBody = 64 << 10 maxSyncTokenLen = 8192 ) func validateSyncToken(raw string) (string, *apivalidate.ValidationError) { raw = strings.TrimSpace(raw) if raw == "" { return "", nil } if len(raw) > maxSyncTokenLen { return "", apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "sync_token", Message: "too long", }) } if strings.ContainsAny(raw, "\r\n\x00") || strings.ContainsAny(raw, "<>&") { return "", apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "sync_token", Message: "invalid", }) } return raw, nil } func validateCreateContact(contact *nextcloud.Contact) *apivalidate.ValidationError { if strings.TrimSpace(contact.FullName) == "" { return apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "full_name", Message: "required", }) } return nil } func validateIfMatch(ifMatch string) *apivalidate.ValidationError { if strings.TrimSpace(ifMatch) == "" { return apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "If-Match", Message: "required", }) } if strings.ContainsAny(ifMatch, "\r\n") { return apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "If-Match", Message: "invalid", }) } return nil } func validateDeletePath(path string) *apivalidate.ValidationError { if strings.TrimSpace(path) == "" { return apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "path", Message: "required", }) } return nil } func validateInteractionQuery(emailRaw, limitRaw string) (string, int, *apivalidate.ValidationError) { email := strings.TrimSpace(emailRaw) if email == "" { return "", 0, apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "email", Message: "required", }) } if len(email) > 320 || strings.ContainsAny(email, "\r\n") { return "", 0, apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "email", Message: "invalid", }) } parsed, err := mail.ParseAddress(email) if err != nil || parsed.Address == "" { return "", 0, apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "email", Message: "invalid", }) } limit := 20 raw := strings.TrimSpace(limitRaw) if raw != "" { parsedLimit, err := strconv.Atoi(raw) if err != nil || parsedLimit < 1 || parsedLimit > 100 { return "", 0, apivalidate.NewValidationError(apivalidate.FieldDetail{ Field: "limit", Message: "must be between 1 and 100", }) } limit = parsedLimit } return parsed.Address, limit, nil }