Skip to content

Commit

Permalink
Added IsHash and IsRsaPub funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
asaskevich committed Nov 11, 2017
1 parent 635ecdb commit 6c3cb32
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 1 deletion.
26 changes: 26 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#### Support
If you do have a contribution to the package, feel free to create a Pull Request or an Issue.

#### What to contribute
If you don't know what to do, there are some features and functions that need to be done

- [ ] Refactor code
- [ ] Edit docs and [https://github.com/asaskevich/govalidator/README.md](README): spellcheck, grammar and typo check
- [ ] Create actual list of contributors and projects that currently using this package
- [ ] Resolve [https://github.com/asaskevich/govalidator/issues](issues and bugs)
- [ ] Update actual [https://github.com/asaskevich/govalidator#list-of-functions](list of functions)
- [ ] Update [https://github.com/asaskevich/govalidator#validatestruct-2](list of validators) that available for `ValidateStruct` and add new
- [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc
- [ ] Implement [https://github.com/asaskevich/govalidator/issues/224](validation by maps)
- [ ] Implement fuzzing testing
- [ ] Implement some struct/map/array utilities
- [ ] Implement map/array validation
- [ ] Implement benchmarking
- [ ] Implement batch of examples
- [ ] Look at forks for new features and fixes

#### Advice
Feel free to create what you want, but keep in mind when you implement new features:
- Code must be clear and readable, names of variables/constants clearly describes what they are doing
- Public functions must be documented and described in source file and added to README.md to the list of available functions
- There are must be unit-tests for any new functions and improvements
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,31 @@ Documentation is available here: [godoc.org](https://godoc.org/github.com/asaske
Full information about code coverage is also available here: [govalidator on gocover.io](http://gocover.io/github.com/asaskevich/govalidator).

#### Support
If you do have a contribution for the package, feel free to create a Pull Request or an Issue.
If you do have a contribution to the package, feel free to create a Pull Request or an Issue.

#### What to contribute
If you don't know what to do, there are some features and functions that need to be done

- [ ] Refactor code
- [ ] Edit docs and [https://github.com/asaskevich/govalidator/README.md](README): spellcheck, grammar and typo check
- [ ] Create actual list of contributors and projects that currently using this package
- [ ] Resolve [https://github.com/asaskevich/govalidator/issues](issues and bugs)
- [ ] Update actual [https://github.com/asaskevich/govalidator#list-of-functions](list of functions)
- [ ] Update [https://github.com/asaskevich/govalidator#validatestruct-2](list of validators) that available for `ValidateStruct` and add new
- [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc
- [ ] Implement [https://github.com/asaskevich/govalidator/issues/224](validation by maps)
- [ ] Implement fuzzing testing
- [ ] Implement some struct/map/array utilities
- [ ] Implement map/array validation
- [ ] Implement benchmarking
- [ ] Implement batch of examples
- [ ] Look at forks for new features and fixes

#### Advice
Feel free to create what you want, but keep in mind when you implement new features:
- Code must be clear and readable, names of variables/constants clearly describes what they are doing
- Public functions must be documented and described in source file and added to README.md to the list of available functions
- There are must be unit-tests for any new functions and improvements

#### Special thanks to [contributors](https://github.com/asaskevich/govalidator/graphs/contributors)
* [Daniel Lohse](https://github.com/annismckenzie)
Expand Down
2 changes: 2 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var ParamTagMap = map[string]ParamValidator{
"stringlength": StringLength,
"matches": StringMatches,
"in": isInRaw,
"rsapub": IsRsaPub,
}

// ParamTagRegexMap maps param tags to their respective regexes.
Expand All @@ -44,6 +45,7 @@ var ParamTagRegexMap = map[string]*regexp.Regexp{
"stringlength": regexp.MustCompile("^stringlength\\((\\d+)\\|(\\d+)\\)$"),
"in": regexp.MustCompile(`^in\((.*)\)`),
"matches": regexp.MustCompile(`^matches\((.+)\)$`),
"rsapub": regexp.MustCompile("^rsapub\\((\\d+)\\)$"),
}

type customTypeTagMap struct {
Expand Down
78 changes: 78 additions & 0 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
package govalidator

import (
"bytes"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"io/ioutil"
"net"
"net/url"
"reflect"
Expand Down Expand Up @@ -493,6 +499,33 @@ func IsDNSName(str string) bool {
return !IsIP(str) && rxDNSName.MatchString(str)
}

// IsHash checks if a string is a hash of type algorithm.
// Algorithm is one of ['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']
func IsHash(str string, algorithm string) bool {
len := "0"
algo := strings.ToLower(algorithm)

if algo == "crc32" || algo == "crc32b" {
len = "8"
} else if algo == "md5" || algo == "md4" || algo == "ripemd128" || algo == "tiger128" {
len = "32"
} else if algo == "sha1" || algo == "ripemd160" || algo == "tiger160" {
len = "40"
} else if algo == "tiger192" {
len = "48"
} else if algo == "sha256" {
len = "64"
} else if algo == "sha384" {
len = "96"
} else if algo == "sha512" {
len = "128"
} else {
return false
}

return Matches(str, "^[a-f0-9]{" + len + "}$")
}

// IsDialString validates the given string for usage with the various Dial() functions
func IsDialString(str string) bool {

Expand Down Expand Up @@ -567,6 +600,40 @@ func IsLongitude(str string) bool {
return rxLongitude.MatchString(str)
}

// IsRsaPublicKey check if a string is valid public key with provided length
func IsRsaPublicKey(str string, keylen int) bool {
bb := bytes.NewBufferString(str)
pemBytes, err := ioutil.ReadAll(bb)
if err != nil {
return false
}
block, _ := pem.Decode(pemBytes)
if block != nil && block.Type != "PUBLIC KEY" {
return false
}
var der []byte

if block != nil {
der = block.Bytes
} else {
der, err = base64.StdEncoding.DecodeString(str)
if err != nil {
return false
}
}

key, err := x509.ParsePKIXPublicKey(der)
if err != nil {
return false
}
pubkey, ok := key.(*rsa.PublicKey)
if !ok {
return false
}
bitlen := len(pubkey.N.Bytes()) * 8
return bitlen == int(keylen)
}

func toJSONName(tag string) string {
if tag == "" {
return ""
Expand Down Expand Up @@ -748,6 +815,17 @@ func RuneLength(str string, params ...string) bool {
return StringLength(str, params...)
}

// IsRsaPub check whether string is valid RSA key
// Alias for IsRsaPublicKey
func IsRsaPub(str string, params ...string) bool {
if len(params) == 1 {
len, _ := ToInt(params[0])
return IsRsaPublicKey(str, int(len))
}

return false
}

// StringMatches checks if a string matches a given pattern.
func StringMatches(s string, params ...string) bool {
if len(params) == 1 {
Expand Down
74 changes: 74 additions & 0 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,37 @@ func TestIsInt(t *testing.T) {
}
}


func TestIsHash(t *testing.T) {
t.Parallel()

var tests = []struct {
param string
algo string
expected bool
}{
{"3ca25ae354e192b26879f651a51d92aa8a34d8d3", "sha1", true},
{"3ca25ae354e192b26879f651a51d34d8d3", "sha1", false},
{"3ca25ae354e192b26879f651a51d92aa8a34d8d3", "Tiger160", true},
{"3ca25ae354e192b26879f651a51d34d8d3", "ripemd160", false},
{"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898c", "sha256", true},
{"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898casfdsafsadfsdf", "sha256", false},
{"bf547c3fc5841a377eb1519c2890344dbab15c40ae4150b4b34443d2212e5b04aa9d58865bf03d8ae27840fef430b891", "sha384", true},
{"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898casfdsafsadfsdf", "sha384", false},
{"45bc5fa8cb45ee408c04b6269e9f1e1c17090c5ce26ffeeda2af097735b29953ce547e40ff3ad0d120e5361cc5f9cee35ea91ecd4077f3f589b4d439168f91b9", "sha512", true},
{"579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898casfdsafsadfsdf", "sha512", false},
{"46fc0125a148788a3ac1d649566fc04eb84a746f1a6e4fa7", "tiger192", true},
{"46fc0125a148788a3ac1d649566fc04eb84a746f1a6$$%@^", "TIGER192", false},
{"46fc0125a148788a3ac1d649566fc04eb84a746f1a6$$%@^", "SOMEHASH", false},
}
for _, test := range tests {
actual := IsHash(test.param, test.algo)
if actual != test.expected {
t.Errorf("Expected IsHash(%q, %q) to be %v, got %v", test.param, test.algo, test.expected, actual)
}
}
}

func TestIsEmail(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -633,6 +664,7 @@ func TestIsURL(t *testing.T) {
{"https://pbs.twimg.com/profile_images/560826135676588032/j8fWrmYY_normal.jpeg", true},
// according to #125
{"http://prometheus-alertmanager.service.q:9093", true},
{"aio1_alertmanager_container-63376c45:9093", true},
{"https://www.logn-123-123.url.with.sigle.letter.d:12345/url/path/foo?bar=zzz#user", true},
{"http://me.example.com", true},
{"http://www.me.example.com", true},
Expand Down Expand Up @@ -2964,3 +2996,45 @@ func TestValidatorIncludedInError(t *testing.T) {
}

}

func TestIsRsaPublicKey(t *testing.T) {
var tests = []struct {
rsastr string
keylen int
expected bool
}{
{`fubar`, 2048, false},
{`MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuu
XwKYLq0DKUE3t/HHsNdowfD9+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9BmMEcI3uoKbeXCbJRI
HoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzTUmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZ
B7ucimFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUvbQIDAQAB`, 2048, true},
{`MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuu
XwKYLq0DKUE3t/HHsNdowfD9+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9BmMEcI3uoKbeXCbJRI
HoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzTUmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZ
B7ucimFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUvbQIDAQAB`, 1024, false},
{`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7
x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuuXwKYLq0DKUE3t/HHsNdowfD9
+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9
BmMEcI3uoKbeXCbJRIHoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzT
UmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZB7uc
imFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUv
bQIDAQAB
-----END PUBLIC KEY-----`, 2048, true},
{`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvncDCeibmEkabJLmFec7
x9y86RP6dIvkVxxbQoOJo06E+p7tH6vCmiGHKnuuXwKYLq0DKUE3t/HHsNdowfD9
+NH8caLzmXqGBx45/Dzxnwqz0qYq7idK+Qff34qrk/YFoU7498U1Ee7PkKb7/VE9
BmMEcI3uoKbeXCbJRIHoTp8bUXOpNTSUfwUNwJzbm2nsHo2xu6virKtAZLTsJFzT
UmRd11MrWCvj59lWzt1/eIMN+ekjH8aXeLOOl54CL+kWp48C+V9BchyKCShZB7uc
imFvjHTtuxziXZQRO7HlcsBOa0WwvDJnRnskdyoD31s4F4jpKEYBJNWTo63v6lUv
bQIDAQAB
-----END PUBLIC KEY-----`, 4096, false},
}
for i, test := range tests {
actual := IsRsaPublicKey(test.rsastr, test.keylen)
if actual != test.expected {
t.Errorf("Expected TestIsRsaPublicKey(%d, %d) to be %v, got %v", i, test.keylen, test.expected, actual)
}
}
}

0 comments on commit 6c3cb32

Please sign in to comment.