152 lines
No EOL
3.7 KiB
Go
152 lines
No EOL
3.7 KiB
Go
package api
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
)
|
|
|
|
// Validate is a global validator instance
|
|
var Validate = validator.New()
|
|
|
|
// RegisterCustomValidations registers custom validation functions
|
|
func RegisterCustomValidations() {
|
|
// Register custom validation for issuer
|
|
Validate.RegisterValidation("issuer", validateIssuer)
|
|
|
|
// Register custom validation for XSS prevention
|
|
Validate.RegisterValidation("no_xss", validateNoXSS)
|
|
|
|
// Register custom validation for OTP secret
|
|
Validate.RegisterValidation("otpsecret", validateOTPSecret)
|
|
}
|
|
|
|
// validateOTPSecret validates that the OTP secret is in valid base32 format
|
|
func validateOTPSecret(fl validator.FieldLevel) bool {
|
|
secret := fl.Field().String()
|
|
|
|
// Check if the secret is not empty
|
|
if secret == "" {
|
|
return false
|
|
}
|
|
|
|
// Check if the secret is in base32 format (A-Z, 2-7)
|
|
base32Regex := regexp.MustCompile(`^[A-Z2-7]+=*$`)
|
|
if !base32Regex.MatchString(secret) {
|
|
return false
|
|
}
|
|
|
|
// Check if the length is valid (must be at least 16 characters)
|
|
if len(secret) < 16 || len(secret) > 128 {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// validateIssuer validates that the issuer field contains only allowed characters
|
|
func validateIssuer(fl validator.FieldLevel) bool {
|
|
issuer := fl.Field().String()
|
|
|
|
// Empty issuer is valid (since it's optional)
|
|
if issuer == "" {
|
|
return true
|
|
}
|
|
|
|
// Allow alphanumeric characters, spaces, and common punctuation
|
|
issuerRegex := regexp.MustCompile(`^[a-zA-Z0-9\s\-_.,:;!?()[\]{}'"]+package api
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
)
|
|
|
|
// Validate is a global validator instance
|
|
var Validate = validator.New()
|
|
|
|
// RegisterCustomValidations registers custom validation functions
|
|
func RegisterCustomValidations() {
|
|
// Register custom validation for issuer
|
|
Validate.RegisterValidation("issuer", validateIssuer)
|
|
|
|
// Register custom validation for XSS prevention
|
|
Validate.RegisterValidation("no_xss", validateNoXSS)
|
|
|
|
// Register custom validation for OTP secret
|
|
Validate.RegisterValidation("otpsecret", validateOTPSecret)
|
|
}
|
|
|
|
// validateOTPSecret validates that the OTP secret is in valid base32 format
|
|
func validateOTPSecret(fl validator.FieldLevel) bool {
|
|
secret := fl.Field().String()
|
|
|
|
// Check if the secret is not empty
|
|
if secret == "" {
|
|
return false
|
|
}
|
|
|
|
// Check if the secret is in base32 format (A-Z, 2-7)
|
|
base32Regex := regexp.MustCompile(`^[A-Z2-7]+=*$`)
|
|
if !base32Regex.MatchString(secret) {
|
|
return false
|
|
}
|
|
|
|
// Check if the length is valid (must be at least 16 characters)
|
|
if len(secret) < 16 || len(secret) > 128 {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
)
|
|
if !issuerRegex.MatchString(issuer) {
|
|
return false
|
|
}
|
|
|
|
// Check length
|
|
if len(issuer) > 100 {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// validateNoXSS validates that the field doesn't contain potential XSS payloads
|
|
func validateNoXSS(fl validator.FieldLevel) bool {
|
|
value := fl.Field().String()
|
|
|
|
// Check for HTML encoding
|
|
if strings.Contains(value, "&#") ||
|
|
strings.Contains(value, "<") ||
|
|
strings.Contains(value, ">") {
|
|
return false
|
|
}
|
|
|
|
// Check for common XSS patterns
|
|
suspiciousPatterns := []*regexp.Regexp{
|
|
regexp.MustCompile(`(?i)<script[^>]*>.*?</script>`),
|
|
regexp.MustCompile(`(?i)javascript:`),
|
|
regexp.MustCompile(`(?i)data:text/html`),
|
|
regexp.MustCompile(`(?i)on\w+\s*=`),
|
|
regexp.MustCompile(`(?i)<\s*img[^>]*src\s*=`),
|
|
regexp.MustCompile(`(?i)<\s*iframe`),
|
|
regexp.MustCompile(`(?i)<\s*object`),
|
|
regexp.MustCompile(`(?i)<\s*embed`),
|
|
regexp.MustCompile(`(?i)<\s*style`),
|
|
regexp.MustCompile(`(?i)<\s*form`),
|
|
regexp.MustCompile(`(?i)<\s*applet`),
|
|
regexp.MustCompile(`(?i)<\s*meta`),
|
|
}
|
|
|
|
for _, pattern := range suspiciousPatterns {
|
|
if pattern.MatchString(value) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
} |