source: josm/trunk/src/org/openstreetmap/josm/data/validation/routines/EmailValidator.java@ 7489

Last change on this file since 7489 was 7489, checked in by Don-vip, 10 years ago

fix #10393 - Validation of URLs and e-mails in relevant tags, using modified subset of Apache Commons Validator 1.4

File size: 6.4 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package org.openstreetmap.josm.data.validation.routines;
18
19import static org.openstreetmap.josm.tools.I18n.tr;
20
21import java.util.regex.Matcher;
22import java.util.regex.Pattern;
23
24/**
25 * <p>Perform email validations.</p>
26 * <p>
27 * This class is a Singleton; you can retrieve the instance via the getInstance() method.
28 * </p>
29 * <p>
30 * Based on a script by <a href="mailto:stamhankar@hotmail.com">Sandeep V. Tamhankar</a>
31 * http://javascript.internet.com
32 * </p>
33 * <p>
34 * This implementation is not guaranteed to catch all possible errors in an email address.
35 * For example, an address like nobody@noplace.somedog will pass validator, even though there
36 * is no TLD "somedog"
37 * </p>.
38 *
39 * @version $Revision: 1227719 $ $Date: 2012-01-05 18:45:51 +0100 (Thu, 05 Jan 2012) $
40 * @since Validator 1.4
41 */
42public class EmailValidator extends AbstractValidator {
43
44 private static final String SPECIAL_CHARS = "\\p{Cntrl}\\(\\)<>@,;:'\\\\\\\"\\.\\[\\]";
45 private static final String VALID_CHARS = "[^\\s" + SPECIAL_CHARS + "]";
46 private static final String QUOTED_USER = "(\"[^\"]*\")";
47 private static final String WORD = "((" + VALID_CHARS + "|')+|" + QUOTED_USER + ")";
48
49 private static final String LEGAL_ASCII_REGEX = "^\\p{ASCII}+$";
50 private static final String EMAIL_REGEX = "^\\s*?(.+)@(.+?)\\s*$";
51 private static final String IP_DOMAIN_REGEX = "^\\[(.*)\\]$";
52 private static final String USER_REGEX = "^\\s*" + WORD + "(\\." + WORD + ")*$";
53
54 private static final Pattern MATCH_ASCII_PATTERN = Pattern.compile(LEGAL_ASCII_REGEX);
55 private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);
56 private static final Pattern IP_DOMAIN_PATTERN = Pattern.compile(IP_DOMAIN_REGEX);
57 private static final Pattern USER_PATTERN = Pattern.compile(USER_REGEX);
58
59 private final boolean allowLocal;
60
61 /**
62 * Singleton instance of this class, which
63 * doesn't consider local addresses as valid.
64 */
65 private static final EmailValidator EMAIL_VALIDATOR = new EmailValidator(false);
66
67 /**
68 * Singleton instance of this class, which does
69 * consider local addresses valid.
70 */
71 private static final EmailValidator EMAIL_VALIDATOR_WITH_LOCAL = new EmailValidator(true);
72
73 /**
74 * Returns the Singleton instance of this validator.
75 *
76 * @return singleton instance of this validator.
77 */
78 public static EmailValidator getInstance() {
79 return EMAIL_VALIDATOR;
80 }
81
82 /**
83 * Returns the Singleton instance of this validator,
84 * with local validation as required.
85 *
86 * @param allowLocal Should local addresses be considered valid?
87 * @return singleton instance of this validator
88 */
89 public static EmailValidator getInstance(boolean allowLocal) {
90 if(allowLocal) {
91 return EMAIL_VALIDATOR_WITH_LOCAL;
92 }
93 return EMAIL_VALIDATOR;
94 }
95
96 /**
97 * Protected constructor for subclasses to use.
98 *
99 * @param allowLocal Should local addresses be considered valid?
100 */
101 protected EmailValidator(boolean allowLocal) {
102 super();
103 this.allowLocal = allowLocal;
104 }
105
106 /**
107 * <p>Checks if a field has a valid e-mail address.</p>
108 *
109 * @param email The value validation is being performed on. A <code>null</code>
110 * value is considered invalid.
111 * @return true if the email address is valid.
112 */
113 @Override
114 public boolean isValid(String email) {
115 if (email == null) {
116 return false;
117 }
118
119 Matcher asciiMatcher = MATCH_ASCII_PATTERN.matcher(email);
120 if (!asciiMatcher.matches()) {
121 setErrorMessage(tr("E-mail address contains non-ascii characters"));
122 setFix(email.replaceAll("[^\\p{ASCII}]+", ""));
123 return false;
124 }
125
126 // Check the whole email address structure
127 Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
128 if (!emailMatcher.matches()) {
129 setErrorMessage(tr("E-mail address is invalid"));
130 return false;
131 }
132
133 if (email.endsWith(".")) {
134 setErrorMessage(tr("E-mail address is invalid"));
135 return false;
136 }
137
138 String username = emailMatcher.group(1);
139 if (!isValidUser(username)) {
140 setErrorMessage(tr("E-mail address contains an invalid username: {0}", username));
141 return false;
142 }
143
144 String domain = emailMatcher.group(2);
145 if (!isValidDomain(domain)) {
146 setErrorMessage(tr("E-mail address contains an invalid domain: {0}", domain));
147 return false;
148 }
149
150 return true;
151 }
152
153 /**
154 * Returns true if the domain component of an email address is valid.
155 *
156 * @param domain being validated.
157 * @return true if the email address's domain is valid.
158 */
159 protected boolean isValidDomain(String domain) {
160 // see if domain is an IP address in brackets
161 Matcher ipDomainMatcher = IP_DOMAIN_PATTERN.matcher(domain);
162
163 if (ipDomainMatcher.matches()) {
164 InetAddressValidator inetAddressValidator =
165 InetAddressValidator.getInstance();
166 return inetAddressValidator.isValid(ipDomainMatcher.group(1));
167 } else {
168 // Domain is symbolic name
169 DomainValidator domainValidator =
170 DomainValidator.getInstance(allowLocal);
171 return domainValidator.isValid(domain);
172 }
173 }
174
175 /**
176 * Returns true if the user component of an email address is valid.
177 *
178 * @param user being validated
179 * @return true if the user name is valid.
180 */
181 protected boolean isValidUser(String user) {
182 return USER_PATTERN.matcher(user).matches();
183 }
184
185}
Note: See TracBrowser for help on using the repository browser.