1
+ import 'helpers.dart' ;
2
+
3
+ RegExp _email = RegExp (
4
+ r"^((([a-z]|\d|[!#\$%&'*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$" );
5
+
6
+ RegExp _ipv4Maybe = RegExp (r'^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$' );
7
+ RegExp _ipv6 =
8
+ RegExp (r'^::|^::1|^([a-fA-F0-9]{1,4}::?){1,7}([a-fA-F0-9]{1,4})$' );
9
+
10
+ RegExp _creditCard = RegExp (
11
+ r'^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$' );
12
+
13
+ /// check if the string [str] is an email
14
+ bool isEmail (String str) {
15
+ return _email.hasMatch (str.toLowerCase ());
16
+ }
17
+
18
+ /// check if the string [str] is a URL
19
+ ///
20
+ /// * [protocols] sets the list of allowed protocols
21
+ /// * [requireTld] sets if TLD is required
22
+ /// * [requireProtocol] is a `bool` that sets if protocol is required for validation
23
+ /// * [allowUnderscore] sets if underscores are allowed
24
+ /// * [hostWhitelist] sets the list of allowed hosts
25
+ /// * [hostBlacklist] sets the list of disallowed hosts
26
+ bool isURL (String ? str,
27
+ {List <String ?> protocols = const ['http' , 'https' , 'ftp' ],
28
+ bool requireTld = true ,
29
+ bool requireProtocol = false ,
30
+ bool allowUnderscore = false ,
31
+ List <String > hostWhitelist = const [],
32
+ List <String > hostBlacklist = const []}) {
33
+ if (str == null ||
34
+ str.isEmpty ||
35
+ str.length > 2083 ||
36
+ str.startsWith ('mailto:' )) {
37
+ return false ;
38
+ }
39
+ int port;
40
+ String ? protocol, auth, user;
41
+ String host, hostname, port_str, path, query, hash;
42
+
43
+ // check protocol
44
+ var split = str.split ('://' );
45
+ if (split.length > 1 ) {
46
+ protocol = shift (split);
47
+ if (! protocols.contains (protocol)) {
48
+ return false ;
49
+ }
50
+ } else if (requireProtocol == true ) {
51
+ return false ;
52
+ }
53
+ str = split.join ('://' );
54
+
55
+ // check hash
56
+ split = str.split ('#' );
57
+ str = shift (split);
58
+ hash = split.join ('#' );
59
+ if (hash.isNotEmpty && RegExp (r'\s' ).hasMatch (hash)) {
60
+ return false ;
61
+ }
62
+
63
+ // check query params
64
+ split = str! .split ('?' );
65
+ str = shift (split);
66
+ query = split.join ('?' );
67
+ if (query.isNotEmpty && RegExp (r'\s' ).hasMatch (query)) {
68
+ return false ;
69
+ }
70
+
71
+ // check path
72
+ split = str! .split ('/' );
73
+ str = shift (split);
74
+ path = split.join ('/' );
75
+ if (path.isNotEmpty && RegExp (r'\s' ).hasMatch (path)) {
76
+ return false ;
77
+ }
78
+
79
+ // check auth type urls
80
+ split = str! .split ('@' );
81
+ if (split.length > 1 ) {
82
+ auth = shift (split);
83
+ if (auth? .contains (':' ) ?? false ) {
84
+ user = shift (auth! .split (':' ))! ;
85
+ if (! RegExp (r'^\S+$' ).hasMatch (user)) {
86
+ return false ;
87
+ }
88
+ if (! RegExp (r'^\S*$' ).hasMatch (user)) {
89
+ return false ;
90
+ }
91
+ }
92
+ }
93
+
94
+ // check hostname
95
+ hostname = split.join ('@' );
96
+ split = hostname.split (':' );
97
+ host = shift (split)! ;
98
+ if (split.isNotEmpty) {
99
+ port_str = split.join (':' );
100
+ try {
101
+ port = int .parse (port_str, radix: 10 );
102
+ } catch (e) {
103
+ return false ;
104
+ }
105
+ if (! RegExp (r'^[0-9]+$' ).hasMatch (port_str) || port <= 0 || port > 65535 ) {
106
+ return false ;
107
+ }
108
+ }
109
+
110
+ if (! isIP (host, null ) &&
111
+ ! isFQDN (host,
112
+ requireTld: requireTld, allowUnderscores: allowUnderscore) &&
113
+ host != 'localhost' ) {
114
+ return false ;
115
+ }
116
+
117
+ if (hostWhitelist.isNotEmpty && ! hostWhitelist.contains (host)) {
118
+ return false ;
119
+ }
120
+
121
+ if (hostBlacklist.isNotEmpty && hostBlacklist.contains (host)) {
122
+ return false ;
123
+ }
124
+
125
+ return true ;
126
+ }
127
+
128
+ /// check if the string [str] is IP [version] 4 or 6
129
+ ///
130
+ /// * [version] is a String or an `int` .
131
+ bool isIP (String ? str, int ? version) {
132
+ if (version == null ) {
133
+ return isIP (str, 4 ) || isIP (str, 6 );
134
+ } else if (version == 4 ) {
135
+ if (! _ipv4Maybe.hasMatch (str! )) {
136
+ return false ;
137
+ }
138
+ var parts = str.split ('.' );
139
+ parts.sort ((a, b) => int .parse (a) - int .parse (b));
140
+ return int .parse (parts[3 ]) <= 255 ;
141
+ }
142
+ return version == 6 && _ipv6.hasMatch (str! );
143
+ }
144
+
145
+ /// check if the string [str] is a fully qualified domain name (e.g. domain.com).
146
+ ///
147
+ /// * [requireTld] sets if TLD is required
148
+ /// * [allowUnderscore] sets if underscores are allowed
149
+ bool isFQDN (String str,
150
+ {bool requireTld = true , bool allowUnderscores = false }) {
151
+ var parts = str.split ('.' );
152
+ if (requireTld) {
153
+ var tld = parts.removeLast ();
154
+ if (parts.isEmpty || ! RegExp (r'^[a-z]{2,}$' ).hasMatch (tld)) {
155
+ return false ;
156
+ }
157
+ }
158
+
159
+ for (var part in parts) {
160
+ if (allowUnderscores) {
161
+ if (part.contains ('__' )) {
162
+ return false ;
163
+ }
164
+ }
165
+ if (! RegExp (r'^[a-z\\u00a1-\\uffff0-9-]+$' ).hasMatch (part)) {
166
+ return false ;
167
+ }
168
+ if (part[0 ] == '-' ||
169
+ part[part.length - 1 ] == '-' ||
170
+ part.contains ('---' )) {
171
+ return false ;
172
+ }
173
+ }
174
+ return true ;
175
+ }
176
+
177
+ /// check if the string is a credit card
178
+ bool isCreditCard (String str) {
179
+ var sanitized = str.replaceAll (RegExp (r'[^0-9]+' ), '' );
180
+ if (! _creditCard.hasMatch (sanitized)) {
181
+ return false ;
182
+ }
183
+
184
+ // Luhn algorithm
185
+ var sum = 0 ;
186
+ String digit;
187
+ var shouldDouble = false ;
188
+
189
+ for (var i = sanitized.length - 1 ; i >= 0 ; i-- ) {
190
+ digit = sanitized.substring (i, (i + 1 ));
191
+ var tmpNum = int .parse (digit);
192
+
193
+ if (shouldDouble == true ) {
194
+ tmpNum *= 2 ;
195
+ if (tmpNum >= 10 ) {
196
+ sum += ((tmpNum % 10 ) + 1 );
197
+ } else {
198
+ sum += tmpNum;
199
+ }
200
+ } else {
201
+ sum += tmpNum;
202
+ }
203
+ shouldDouble = ! shouldDouble;
204
+ }
205
+
206
+ return (sum % 10 == 0 );
207
+ }
208
+
209
+ /// check if the string is a date
210
+ bool isDate (String str) {
211
+ try {
212
+ DateTime .parse (str);
213
+ return true ;
214
+ } catch (e) {
215
+ return false ;
216
+ }
217
+ }
0 commit comments