Skip to content

Commit

Permalink
feat: add image validation (#982)
Browse files Browse the repository at this point in the history
  • Loading branch information
the-fanan committed May 21, 2023
1 parent cc45daf commit 5ac1643
Show file tree
Hide file tree
Showing 41 changed files with 357 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ _testmain.go
*.test
*.out
*.txt
/**/*.DS_Store
cover.html
README.html
.idea
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ Baked-in Validations
| dirpath | Directory Path |
| file | Existing File |
| filepath | File Path |
| image | Image |
| isdefault | Is Default |
| len | Length |
| max | Maximum |
Expand Down
63 changes: 63 additions & 0 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"golang.org/x/crypto/sha3"
"golang.org/x/text/language"

"github.com/gabriel-vasile/mimetype"
"github.com/leodido/go-urn"
)

Expand Down Expand Up @@ -144,6 +145,7 @@ var (
"endswith": endsWith,
"startsnotwith": startsNotWith,
"endsnotwith": endsNotWith,
"image": isImage,
"isbn": isISBN,
"isbn10": isISBN10,
"isbn13": isISBN13,
Expand Down Expand Up @@ -1488,6 +1490,67 @@ func isFile(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}

// isImage is the validation function for validating if the current field's value contains the path to a valid image file
func isImage(fl FieldLevel) bool {
mimetypes := map[string]bool{
"image/bmp": true,
"image/cis-cod": true,
"image/gif": true,
"image/ief": true,
"image/jpeg": true,
"image/jp2": true,
"image/jpx": true,
"image/jpm": true,
"image/pipeg": true,
"image/png": true,
"image/svg+xml": true,
"image/tiff": true,
"image/webp": true,
"image/x-cmu-raster": true,
"image/x-cmx": true,
"image/x-icon": true,
"image/x-portable-anymap": true,
"image/x-portable-bitmap": true,
"image/x-portable-graymap": true,
"image/x-portable-pixmap": true,
"image/x-rgb": true,
"image/x-xbitmap": true,
"image/x-xpixmap": true,
"image/x-xwindowdump": true,
}
field := fl.Field()

switch field.Kind() {
case reflect.String:
filePath := field.String()
fileInfo, err := os.Stat(filePath)

if err != nil {
return false
}

if fileInfo.IsDir() {
return false
}

file, err := os.Open(filePath)
if err != nil {
return false
}
defer file.Close()

mime, err := mimetype.DetectReader(file)
if err != nil {
return false
}

if _, ok := mimetypes[mime.String()]; ok {
return true
}
}
return false
}

// isFilePath is the validation function for validating if the current field's value is a valid file path.
func isFilePath(fl FieldLevel) bool {

Expand Down
2 changes: 1 addition & 1 deletion country_codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -1135,7 +1135,7 @@ var iso3166_2 = map[string]bool{
"VN-69": true, "VN-70": true, "VN-71": true, "VN-72": true, "VN-73": true,
"VN-CT": true, "VN-DN": true, "VN-HN": true, "VN-HP": true, "VN-SG": true,
"VU-MAP": true, "VU-PAM": true, "VU-SAM": true, "VU-SEE": true, "VU-TAE": true,
"VU-TOB": true, "WF-SG": true,"WF-UV": true, "WS-AA": true, "WS-AL": true, "WS-AT": true, "WS-FA": true,
"VU-TOB": true, "WF-SG": true, "WF-UV": true, "WS-AA": true, "WS-AL": true, "WS-AT": true, "WS-FA": true,
"WS-GE": true, "WS-GI": true, "WS-PA": true, "WS-SA": true, "WS-TU": true,
"WS-VF": true, "WS-VS": true, "YE-AB": true, "YE-AD": true, "YE-AM": true,
"YE-BA": true, "YE-DA": true, "YE-DH": true, "YE-HD": true, "YE-HJ": true, "YE-HU": true,
Expand Down
25 changes: 12 additions & 13 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,6 @@ This validates that a string value is a valid JWT
Usage: jwt
# File
This validates that a string value contains a valid file path and that
Expand All @@ -872,6 +871,15 @@ This is done using os.Stat, which is a platform independent function.
Usage: file
# Image path
This validates that a string value contains a valid file path and that
the file exists on the machine and is an image.
This is done using os.Stat and github.com/gabriel-vasile/mimetype
Usage: image
# URL String
# File Path
Expand All @@ -881,7 +889,6 @@ This is done using os.Stat, which is a platform independent function.
Usage: filepath
# URL String
This validates that a string value contains a valid url
Expand Down Expand Up @@ -923,7 +930,6 @@ you can use this with the omitempty tag.
Usage: base64url
# Base64RawURL String
This validates that a string value contains a valid base64 URL safe value,
Expand All @@ -934,7 +940,6 @@ you can use this with the omitempty tag.
Usage: base64url
# Bitcoin Address
This validates that a string value contains a valid bitcoin address.
Expand Down Expand Up @@ -1267,7 +1272,6 @@ This is done using os.Stat, which is a platform independent function.
Usage: dir
# Directory Path
This validates that a string value contains a valid directory but does
Expand All @@ -1278,7 +1282,6 @@ may not exist at the time of validation.
Usage: dirpath
# HostPort
This validates that a string value contains a valid DNS hostname and port that
Expand Down Expand Up @@ -1350,42 +1353,38 @@ More information on https://semver.org/
Usage: semver
# CVE Identifier
This validates that a string value is a valid cve id, defined in cve mitre.
More information on https://cve.mitre.org/
Usage: cve
# Credit Card
This validates that a string value contains a valid credit card number using Luhn algorithm.
Usage: credit_card
# Luhn Checksum
Usage: luhn_checksum
Usage: luhn_checksum
This validates that a string or (u)int value contains a valid checksum using the Luhn algorithm.
# MongoDb ObjectID
This validates that a string is a valid 24 character hexadecimal string.
Usage: mongodb
Usage: mongodb
# Cron
This validates that a string value contains a valid cron expression.
Usage: cron
Alias Validators and Tags
# Alias Validators and Tags
Alias Validators and Tags
NOTE: When returning an error, the tag returned in "FieldError" will be
Expand Down
8 changes: 6 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ module github.com/go-playground/validator/v10
go 1.18

require (
github.com/gabriel-vasile/mimetype v1.4.2
github.com/go-playground/assert/v2 v2.2.0
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/leodido/go-urn v1.2.3
github.com/leodido/go-urn v1.2.4
golang.org/x/crypto v0.7.0
golang.org/x/text v0.8.0
)

require golang.org/x/sys v0.6.0 // indirect
require (
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect
)
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA=
github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand All @@ -20,6 +22,8 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
Expand Down
Binary file added testdata/music.mp3
Binary file not shown.
5 changes: 5 additions & 0 deletions translations/ar/ar.go
Original file line number Diff line number Diff line change
Expand Up @@ -1346,6 +1346,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return t
},
},
{
tag: "image",
translation: "يجب أن تكون {0} صورة صالحة",
override: false,
},
}

for _, t := range translations {
Expand Down
5 changes: 5 additions & 0 deletions translations/ar/ar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ func TestTranslations(t *testing.T) {
PostCode string `validate:"postcode_iso3166_alpha2=SG"`
PostCodeCountry string
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
Image string `validate:"image"`
}

var test Test
Expand Down Expand Up @@ -676,6 +677,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.PostCodeByField",
expected: "لا يتطابق PostCodeByField مع تنسيق الرمز البريدي للبلد في حقل PostCodeCountry",
},
{
ns: "Test.Image",
expected: "يجب أن تكون Image صورة صالحة",
},
}

for _, tt := range tests {
Expand Down
5 changes: 5 additions & 0 deletions translations/en/en.go
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be a valid boolean value",
override: false,
},
{
tag: "image",
translation: "{0} must be a valid image",
override: false,
},
{
tag: "cve",
translation: "{0} must be a valid cve identifier",
Expand Down
5 changes: 5 additions & 0 deletions translations/en/en_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ func TestTranslations(t *testing.T) {
PostCodeCountry string
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
BooleanString string `validate:"boolean"`
Image string `validate:"image"`
CveString string `validate:"cve"`
}

Expand Down Expand Up @@ -697,6 +698,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.BooleanString",
expected: "BooleanString must be a valid boolean value",
},
{
ns: "Test.Image",
expected: "Image must be a valid image",
},
{
ns: "Test.CveString",
expected: "CveString must be a valid cve identifier",
Expand Down
5 changes: 5 additions & 0 deletions translations/es/es.go
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return s
},
},
{
tag: "image",
translation: "{0} debe ser una imagen válida",
override: false,
},
}

for _, t := range translations {
Expand Down
5 changes: 5 additions & 0 deletions translations/es/es_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ func TestTranslations(t *testing.T) {
UniqueSlice []string `validate:"unique"`
UniqueArray [3]string `validate:"unique"`
UniqueMap map[string]string `validate:"unique"`
Image string `validate:"image"`
}

var test Test
Expand Down Expand Up @@ -638,6 +639,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UniqueMap",
expected: "UniqueMap debe contener valores únicos",
},
{
ns: "Test.Image",
expected: "Image debe ser una imagen válida",
},
}

for _, tt := range tests {
Expand Down
5 changes: 5 additions & 0 deletions translations/fa/fa.go
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return t
},
},
{
tag: "image",
translation: "{0} باید یک تصویر معتبر باشد",
override: false,
},
}

for _, t := range translations {
Expand Down
7 changes: 6 additions & 1 deletion translations/fa/fa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func TestTranslations(t *testing.T) {
PostCode string `validate:"postcode_iso3166_alpha2=SG"`
PostCodeCountry string
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
Image string `validate:"image"`
}

var test Test
Expand Down Expand Up @@ -671,8 +672,12 @@ func TestTranslations(t *testing.T) {
ns: "Test.PostCodeByField",
expected: "PostCodeByField یک کدپستی معتبر کشور فیلد PostCodeCountry نیست",
},
{
ns: "Test.Image",
expected: "Image باید یک تصویر معتبر باشد",
},
}

for _, tt := range tests {

var fe validator.FieldError
Expand Down
Loading

0 comments on commit 5ac1643

Please sign in to comment.