Passed
Push — main ( 226e09...0f61b2 )
by Rushan
02:24 queued 12s
created

it.IPConstraint.validateIP   A

Complexity

Conditions 3

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 10
nop 2
dl 0
loc 15
ccs 8
cts 8
cp 1
crap 3
rs 9.9
c 0
b 0
f 0
1
package it
2
3
import (
4
	"errors"
5
	"net"
6
7
	"github.com/muonsoft/validation"
8
	"github.com/muonsoft/validation/code"
9
	"github.com/muonsoft/validation/is"
10
	"github.com/muonsoft/validation/message"
11
	"github.com/muonsoft/validation/validate"
12
)
13
14
// IsEmail is used for simplified validation of an email address. It allows all values
15
// with an "@" symbol in, and a "." in the second host part of the email address.
16
func IsEmail() validation.CustomStringConstraint {
17 1
	return validation.NewCustomStringConstraint(
18
		is.Email,
19
		"EmailConstraint",
20
		code.InvalidEmail,
21
		message.InvalidEmail,
22
	)
23
}
24
25
// IsHTML5Email is used for validation of an email address based on pattern for HTML5
26
// (see https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address).
27
func IsHTML5Email() validation.CustomStringConstraint {
28 1
	return validation.NewCustomStringConstraint(
29
		is.HTML5Email,
30
		"HTML5EmailConstraint",
31
		code.InvalidEmail,
32
		message.InvalidEmail,
33
	)
34
}
35
36
// URLConstraint is used to validate URL string. This constraint doesn’t check that the host of the
37
// given URL really exists, because the information of the DNS records is not reliable.
38
//
39
// This constraint doesn't check the length of the URL. Use LengthConstraint to check the length of the given value.
40
type URLConstraint struct {
41
	isIgnored              bool
42
	supportsRelativeSchema bool
43
	schemas                []string
44
	messageTemplate        string
45
}
46
47
// IsURL creates a URLConstraint to validate an URL. By default, constraint checks
48
// only for the http:// and https:// schemas. Use the WithSchemas method to configure
49
// the list of expected schemas. Also, you can use WithRelativeSchema to enable support
50
// of the relative schema (without schema, e.g. "//example.com").
51
func IsURL() URLConstraint {
52 1
	return URLConstraint{
53
		schemas:         []string{"http", "https"},
54
		messageTemplate: message.InvalidURL,
55
	}
56
}
57
58
// SetUp will return an error if the list of schemas is empty.
59
func (c URLConstraint) SetUp() error {
60 1
	if len(c.schemas) == 0 {
61 1
		return errEmptySchemas
62
	}
63
64 1
	return nil
65
}
66
67
// Name is the constraint name.
68
func (c URLConstraint) Name() string {
69 1
	return "URLConstraint"
70
}
71
72
// WithRelativeSchema enables support of relative URL schema, which means that URL value
73
// may be treated as relative (without schema, e.g. "//example.com").
74
func (c URLConstraint) WithRelativeSchema() URLConstraint {
75 1
	c.supportsRelativeSchema = true
76 1
	return c
77
}
78
79
// WithSchemas is used to set up a list of accepted schemas. For example, if you also consider the ftp:// type URLs
80
// to be valid, redefine the schemas list, listing http, https, and also ftp.
81
// If the list is empty, then an error will be returned by the SetUp method.
82
func (c URLConstraint) WithSchemas(schemas ...string) URLConstraint {
83 1
	c.schemas = schemas
84 1
	return c
85
}
86
87
// Message sets the violation message template. You can use template parameters
88
// for injecting its values into the final message:
89
//
90
//	{{ value }} - the current (invalid) value.
91
func (c URLConstraint) Message(message string) URLConstraint {
92 1
	c.messageTemplate = message
93 1
	return c
94
}
95
96
// When enables conditional validation of this constraint. If the expression evaluates to false,
97
// then the constraint will be ignored.
98
func (c URLConstraint) When(condition bool) URLConstraint {
99 1
	c.isIgnored = !condition
100 1
	return c
101
}
102
103
func (c URLConstraint) ValidateString(value *string, scope validation.Scope) error {
104 1
	if c.isIgnored || value == nil || *value == "" {
105 1
		return nil
106
	}
107
108 1
	schemas := c.schemas
109 1
	if c.supportsRelativeSchema {
110 1
		schemas = append(schemas, "")
111
	}
112 1
	if is.URL(*value, schemas...) {
113 1
		return nil
114
	}
115
116 1
	return scope.BuildViolation(code.InvalidURL, c.messageTemplate).
117
		AddParameter("{{ value }}", *value).
118
		CreateViolation()
119
}
120
121
// IPConstraint is used to validate IP address. You can check for different versions
122
// and restrict some ranges by additional options.
123
type IPConstraint struct {
124
	isIgnored    bool
125
	validate     func(value string, restrictions ...validate.IPRestriction) error
126
	restrictions []validate.IPRestriction
127
128
	invalidMessageTemplate    string
129
	prohibitedMessageTemplate string
130
}
131
132
// IsIP creates an IPConstraint to validate an IP address (IPv4 or IPv6).
133
func IsIP() IPConstraint {
134 1
	return newIPConstraint(validate.IP)
135
}
136
137
// IsIPv4 creates an IPConstraint to validate an IPv4 address.
138
func IsIPv4() IPConstraint {
139 1
	return newIPConstraint(validate.IPv4)
140
}
141
142
// IsIPv6 creates an IPConstraint to validate an IPv4 address.
143
func IsIPv6() IPConstraint {
144 1
	return newIPConstraint(validate.IPv6)
145
}
146
147
func newIPConstraint(validate func(value string, restrictions ...validate.IPRestriction) error) IPConstraint {
148 1
	return IPConstraint{
149
		validate:                  validate,
150
		invalidMessageTemplate:    message.InvalidIP,
151
		prohibitedMessageTemplate: message.ProhibitedIP,
152
	}
153
}
154
155
// SetUp always returns no error.
156
func (c IPConstraint) SetUp() error {
157 1
	return nil
158
}
159
160
// Name is the constraint name.
161
func (c IPConstraint) Name() string {
162
	return "IPConstraint"
163
}
164
165
// DenyPrivateIP denies using of private IPs according to RFC 1918 (IPv4 addresses)
166
// and RFC 4193 (IPv6 addresses).
167
func (c IPConstraint) DenyPrivateIP() IPConstraint {
168 1
	c.restrictions = append(c.restrictions, validate.DenyPrivateIP())
169 1
	return c
170
}
171
172
// DenyIP can be used to deny custom range of IP addresses.
173
func (c IPConstraint) DenyIP(restrict func(ip net.IP) bool) IPConstraint {
174 1
	c.restrictions = append(c.restrictions, restrict)
175 1
	return c
176
}
177
178
// InvalidMessage sets the violation message template for invalid IP case.
179
// You can use template parameters for injecting its values into the final message:
180
//
181
//	{{ value }} - the current (invalid) value.
182
func (c IPConstraint) InvalidMessage(message string) IPConstraint {
183 1
	c.invalidMessageTemplate = message
184 1
	return c
185
}
186
187
// ProhibitedMessage sets the violation message template for prohibited IP case.
188
// You can use template parameters for injecting its values into the final message:
189
//
190
//	{{ value }} - the current (invalid) value.
191
func (c IPConstraint) ProhibitedMessage(message string) IPConstraint {
192 1
	c.prohibitedMessageTemplate = message
193 1
	return c
194
}
195
196
// When enables conditional validation of this constraint. If the expression evaluates to false,
197
// then the constraint will be ignored.
198
func (c IPConstraint) When(condition bool) IPConstraint {
199 1
	c.isIgnored = !condition
200 1
	return c
201
}
202
203
func (c IPConstraint) ValidateString(value *string, scope validation.Scope) error {
204 1
	if c.isIgnored || value == nil || *value == "" {
205 1
		return nil
206
	}
207
208 1
	return c.validateIP(*value, scope)
209
}
210
211
func (c IPConstraint) validateIP(value string, scope validation.Scope) error {
212 1
	err := c.validate(value, c.restrictions...)
213 1
	if err != nil {
214 1
		var builder *validation.ViolationBuilder
215
216 1
		if errors.Is(err, validate.ErrProhibited) {
217 1
			builder = scope.BuildViolation(code.ProhibitedIP, c.prohibitedMessageTemplate)
218
		} else {
219 1
			builder = scope.BuildViolation(code.InvalidIP, c.invalidMessageTemplate)
220
		}
221
222 1
		return builder.AddParameter("{{ value }}", value).CreateViolation()
223
	}
224
225 1
	return nil
226
}
227