|
|
|
@ -109,6 +109,7 @@ var ( |
|
|
|
|
"isbn13": isISBN13, |
|
|
|
|
"eth_addr": isEthereumAddress, |
|
|
|
|
"btc_addr": isBitcoinAddress, |
|
|
|
|
"btc_addr_bech32": isBitcoinBech32Address, |
|
|
|
|
"uuid": isUUID, |
|
|
|
|
"uuid3": isUUID3, |
|
|
|
|
"uuid4": isUUID4, |
|
|
|
@ -393,58 +394,150 @@ func isISBN10(fl FieldLevel) bool { |
|
|
|
|
|
|
|
|
|
// IsEthereumAddress is the validation function for validating if the field's value is a valid ethereum address based currently only on the format
|
|
|
|
|
func isEthereumAddress(fl FieldLevel) bool { |
|
|
|
|
field := fl.Field() |
|
|
|
|
address := fl.Field().String() |
|
|
|
|
|
|
|
|
|
if !ethAddressRegex.MatchString(address) { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ethaddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ethAddressRegex.MatchString(field.String()) |
|
|
|
|
// checksum validation is blocked by https://github.com/golang/crypto/pull/28
|
|
|
|
|
|
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// IsBitcoinAddress is the validation function for validating if the field's value is a valid btc address, currently only based on the format
|
|
|
|
|
// IsBitcoinAddress is the validation function for validating if the field's value is a valid btc address
|
|
|
|
|
func isBitcoinAddress(fl FieldLevel) bool { |
|
|
|
|
address := fl.Field().String() |
|
|
|
|
|
|
|
|
|
if btcAddressRegex.MatchString(address) { |
|
|
|
|
|
|
|
|
|
alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") |
|
|
|
|
if !btcAddressRegex.MatchString(address) { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
decode := [25]byte{} |
|
|
|
|
alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") |
|
|
|
|
|
|
|
|
|
for _, n := range []byte(address) { |
|
|
|
|
d := bytes.IndexByte(alphabet, n) |
|
|
|
|
decode := [25]byte{} |
|
|
|
|
|
|
|
|
|
if(d == -1){ |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
for _, n := range []byte(address) { |
|
|
|
|
d := bytes.IndexByte(alphabet, n) |
|
|
|
|
|
|
|
|
|
for i := 24; i >= 0; i-- { |
|
|
|
|
d += 58 * int(decode[i]) |
|
|
|
|
decode[i] = byte(d % 256) |
|
|
|
|
d /= 256 |
|
|
|
|
} |
|
|
|
|
for i := 24; i >= 0; i-- { |
|
|
|
|
d += 58 * int(decode[i]) |
|
|
|
|
decode[i] = byte(d % 256) |
|
|
|
|
d /= 256 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if !(decode[0] == 0 || decode[0] == 5) { |
|
|
|
|
if !(decode[0] == 0 || decode[0] == 5) { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
h := sha256.New() |
|
|
|
|
h.Write(decode[:21]) |
|
|
|
|
d := h.Sum([]byte{}) |
|
|
|
|
h = sha256.New() |
|
|
|
|
h.Write(d) |
|
|
|
|
|
|
|
|
|
validchecksum := [4]byte{} |
|
|
|
|
computedchecksum := [4]byte{} |
|
|
|
|
|
|
|
|
|
copy(computedchecksum[:], h.Sum(d[:0])) |
|
|
|
|
copy(validchecksum[:], decode[21:]) |
|
|
|
|
|
|
|
|
|
return validchecksum == computedchecksum |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// IsBitcoinAddress is the validation function for validating if the field's value is a valid bech32 btc address
|
|
|
|
|
func isBitcoinBech32Address(fl FieldLevel) bool { |
|
|
|
|
address := fl.Field().String() |
|
|
|
|
|
|
|
|
|
if !btcAddressRegexBech32.MatchString(address){ |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
am := len(address) % 8 |
|
|
|
|
|
|
|
|
|
if am == 0 || am == 3 || am == 5{ |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
address = strings.ToLower(address) |
|
|
|
|
|
|
|
|
|
alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l" |
|
|
|
|
|
|
|
|
|
hr := []int{3, 3, 0, 2, 3} // the human readable part will always be bc
|
|
|
|
|
dp := []int{} |
|
|
|
|
|
|
|
|
|
for _, c := range []rune(address[3:]) { |
|
|
|
|
dp = append(dp, strings.IndexRune(alphabet, c)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ver := dp[0] |
|
|
|
|
|
|
|
|
|
if ver < 0 || ver > 16{ |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ver == 0 { |
|
|
|
|
if len(address) != 42 && len(address) != 62 { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
values := append(hr, dp...) |
|
|
|
|
|
|
|
|
|
GEN := []int{ 0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3 } |
|
|
|
|
|
|
|
|
|
p := 1 |
|
|
|
|
|
|
|
|
|
for _, v := range values { |
|
|
|
|
b := p >> 25 |
|
|
|
|
p = (p & 0x1ffffff) << 5 ^ v |
|
|
|
|
|
|
|
|
|
for i := 0; i < 5; i++ { |
|
|
|
|
if (b >> uint(i)) & 1 == 1 { |
|
|
|
|
p ^= GEN[i] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
h := sha256.New() |
|
|
|
|
h.Write(decode[:21]) |
|
|
|
|
d := h.Sum([]byte{}) |
|
|
|
|
h = sha256.New() |
|
|
|
|
h.Write(d) |
|
|
|
|
if p != 1 { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
validchecksum := [4]byte{} |
|
|
|
|
computedchecksum := [4]byte{} |
|
|
|
|
b := uint(0) |
|
|
|
|
acc := 0 |
|
|
|
|
mv := (1 << 5) - 1 |
|
|
|
|
|
|
|
|
|
copy(computedchecksum[:], h.Sum(d[:0])) |
|
|
|
|
copy(validchecksum[:], decode[21:]) |
|
|
|
|
sw := []int{} |
|
|
|
|
|
|
|
|
|
println(address, "::", validchecksum[:], computedchecksum[:]) |
|
|
|
|
dp = dp[:len(dp) - 6] |
|
|
|
|
|
|
|
|
|
return validchecksum == computedchecksum |
|
|
|
|
for _, v := range dp[1:]{ |
|
|
|
|
if v < 0 || (v >> 5) != 0{ |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
acc = (acc << 5) | v |
|
|
|
|
b += 5 |
|
|
|
|
for b >= 8{ |
|
|
|
|
b -= 8 |
|
|
|
|
sw = append(sw, (acc>>b)&mv) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(sw) < 2 || len(sw) > 40{ |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ver == 0 && len(sw) != 20 && len(sw) != 32 { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return btcAddressRegexBech32.MatchString(address) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param.
|
|
|
|
|