Commit 96624a11 authored by Frédéric Buclin's avatar Frédéric Buclin

Bug 319953: Missing real email syntax check

r=glob a=LpSolit
parent 3d3cb31a
...@@ -38,6 +38,8 @@ use Bugzilla::Error; ...@@ -38,6 +38,8 @@ use Bugzilla::Error;
use Bugzilla::Util; use Bugzilla::Util;
use Bugzilla::Group; use Bugzilla::Group;
use Email::Address;
use base qw(Bugzilla::Object); use base qw(Bugzilla::Object);
############################### ###############################
...@@ -287,15 +289,11 @@ sub _check_cc_list { ...@@ -287,15 +289,11 @@ sub _check_cc_list {
|| ThrowUserError('flag_type_cc_list_invalid', { cc_list => $cc_list }); || ThrowUserError('flag_type_cc_list_invalid', { cc_list => $cc_list });
my @addresses = split(/[,\s]+/, $cc_list); my @addresses = split(/[,\s]+/, $cc_list);
# We do not call Util::validate_email_syntax because these my $addr_spec = $Email::Address::addr_spec;
# addresses do not require to match 'emailregexp' and do not # We do not call check_email_syntax() because these addresses do not
# depend on 'emailsuffix'. So we limit ourselves to a simple # require to match 'emailregexp' and do not depend on 'emailsuffix'.
# sanity check:
# - match the syntax of a fully qualified email address;
# - do not contain any illegal character.
foreach my $address (@addresses) { foreach my $address (@addresses) {
($address =~ /^[\w\.\+\-=]+@[\w\.\-]+\.[\w\-]+$/ ($address !~ /\P{ASCII}/ && $address =~ /^$addr_spec$/)
&& $address !~ /[\\\(\)<>&,;:"\[\] \t\r\n]/)
|| ThrowUserError('illegal_email_address', || ThrowUserError('illegal_email_address',
{addr => $address, default => 1}); {addr => $address, default => 1});
} }
......
...@@ -195,8 +195,7 @@ sub check_login_name_for_creation { ...@@ -195,8 +195,7 @@ sub check_login_name_for_creation {
my ($invocant, $name) = @_; my ($invocant, $name) = @_;
$name = trim($name); $name = trim($name);
$name || ThrowUserError('user_login_required'); $name || ThrowUserError('user_login_required');
validate_email_syntax($name) check_email_syntax($name);
|| ThrowUserError('illegal_email_address', { addr => $name });
# Check the name if it's a new user, or if we're changing the name. # Check the name if it's a new user, or if we're changing the name.
if (!ref($invocant) || $invocant->login ne $name) { if (!ref($invocant) || $invocant->login ne $name) {
......
...@@ -20,7 +20,7 @@ use base qw(Exporter); ...@@ -20,7 +20,7 @@ use base qw(Exporter);
format_time validate_date validate_time datetime_from format_time validate_date validate_time datetime_from
file_mod_time is_7bit_clean file_mod_time is_7bit_clean
bz_crypt generate_random_password bz_crypt generate_random_password
validate_email_syntax clean_text validate_email_syntax check_email_syntax clean_text
get_text template_var disable_utf8 get_text template_var disable_utf8
detect_encoding); detect_encoding);
...@@ -552,7 +552,13 @@ sub generate_random_password { ...@@ -552,7 +552,13 @@ sub generate_random_password {
sub validate_email_syntax { sub validate_email_syntax {
my ($addr) = @_; my ($addr) = @_;
my $match = Bugzilla->params->{'emailregexp'}; my $match = Bugzilla->params->{'emailregexp'};
my $ret = ($addr =~ /$match/ && $addr !~ /[\\\(\)<>&,;:"\[\] \t\r\n]/); my $email = $addr . Bugzilla->params->{'emailsuffix'};
# This regexp follows RFC 2822 section 3.4.1.
my $addr_spec = $Email::Address::addr_spec;
# RFC 2822 section 2.1 specifies that email addresses must
# be made of US-ASCII characters only.
# Email::Address::addr_spec doesn't enforce this.
my $ret = ($addr =~ /$match/ && $email !~ /\P{ASCII}/ && $email =~ /^$addr_spec$/);
if ($ret) { if ($ret) {
# We assume these checks to suffice to consider the address untainted. # We assume these checks to suffice to consider the address untainted.
trick_taint($_[0]); trick_taint($_[0]);
...@@ -560,6 +566,15 @@ sub validate_email_syntax { ...@@ -560,6 +566,15 @@ sub validate_email_syntax {
return $ret ? 1 : 0; return $ret ? 1 : 0;
} }
sub check_email_syntax {
my ($addr) = @_;
unless (validate_email_syntax(@_)) {
my $email = $addr . Bugzilla->params->{'emailsuffix'};
ThrowUserError('illegal_email_address', { addr => $email });
}
}
sub validate_date { sub validate_date {
my ($date) = @_; my ($date) = @_;
my $date2; my $date2;
...@@ -763,6 +778,7 @@ Bugzilla::Util - Generic utility functions for bugzilla ...@@ -763,6 +778,7 @@ Bugzilla::Util - Generic utility functions for bugzilla
# Validation Functions # Validation Functions
validate_email_syntax($email); validate_email_syntax($email);
check_email_syntax($email);
validate_date($date); validate_date($date);
# DB-related functions # DB-related functions
...@@ -1069,6 +1085,12 @@ Do a syntax checking for a legal email address and returns 1 if ...@@ -1069,6 +1085,12 @@ Do a syntax checking for a legal email address and returns 1 if
the check is successful, else returns 0. the check is successful, else returns 0.
Untaints C<$email> if successful. Untaints C<$email> if successful.
=item C<check_email_syntax($email)>
Do a syntax checking for a legal email address and throws an error
if the check fails.
Untaints C<$email> if successful.
=item C<validate_date($date)> =item C<validate_date($date)>
Make sure the date has the correct format and returns 1 if Make sure the date has the correct format and returns 1 if
......
...@@ -288,11 +288,11 @@ ...@@ -288,11 +288,11 @@
<para> <para>
Defines the regular expression used to validate email addresses Defines the regular expression used to validate email addresses
used for login names. The default attempts to match fully used for login names. The default attempts to match fully
qualified email addresses (i.e. 'user@example.com'). Some qualified email addresses (i.e. 'user@example.com') in a slightly
Bugzilla installations allow only local user names (i.e 'user' more restrictive way than what is allowed in RFC 2822.
instead of 'user@example.com'). In that case, the Some Bugzilla installations allow only local user names (i.e 'user'
<command>emailsuffix</command> parameter should be used to define instead of 'user@example.com'). In that case, this parameter
the email domain. should be used to define the email domain.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
use lib 't'; use lib 't';
use Support::Files; use Support::Files;
use Test::More tests => 15; use Test::More tests => 17;
BEGIN { BEGIN {
use_ok(Bugzilla); use_ok(Bugzilla);
...@@ -58,6 +58,16 @@ foreach my $input (keys %email_strings) { ...@@ -58,6 +58,16 @@ foreach my $input (keys %email_strings) {
"email_filter('$input')"); "email_filter('$input')");
} }
# validate_email_syntax. We need to override some parameters.
my $params = Bugzilla->params;
$params->{emailregexp} = '.*';
$params->{emailsuffix} = '';
my $ascii_email = 'admin@company.com';
# U+0430 returns the Cyrillic "а", which looks similar to the ASCII "a".
my $utf8_email = "\N{U+0430}dmin\@company.com";
ok(validate_email_syntax($ascii_email), 'correctly formatted ASCII-only email address is valid');
ok(!validate_email_syntax($utf8_email), 'correctly formatted email address with non-ASCII characters is rejected');
# diff_arrays(): # diff_arrays():
my @old_array = qw(alpha beta alpha gamma gamma beta alpha delta epsilon gamma); my @old_array = qw(alpha beta alpha gamma gamma beta alpha delta epsilon gamma);
my @new_array = qw(alpha alpha beta gamma epsilon delta beta delta); my @new_array = qw(alpha alpha beta gamma epsilon delta beta delta);
......
...@@ -93,10 +93,13 @@ ...@@ -93,10 +93,13 @@
"front page will require a login. No anonymous users will " _ "front page will require a login. No anonymous users will " _
"be permitted.", "be permitted.",
emailregexp => "This defines the regexp to use for legal email addresses. The " _ emailregexp =>
"default tries to match fully qualified email addresses. Another " _ "This defines the regular expression to use for legal email addresses. " _
"popular value to put here is <tt>^[^@]+$</tt>, which means " _ "The default tries to match fully qualified email addresses. " _
"'local usernames, no @ allowed.'", "Use <tt>.*</tt> to accept any email address following the " _
"<a href='http://tools.ietf.org/html/rfc2822#section-3.4.1'>RFC 2822</a> " _
"specification. Another popular value to put here is <tt>^[^@]+$</tt>, " _
"which means 'local usernames, no @ allowed.'",
emailregexpdesc => "This describes in English words what kinds of legal addresses " _ emailregexpdesc => "This describes in English words what kinds of legal addresses " _
"are allowed by the <tt>emailregexp</tt> param.", "are allowed by the <tt>emailregexp</tt> param.",
......
...@@ -36,8 +36,7 @@ ...@@ -36,8 +36,7 @@
[% ELSE %] [% ELSE %]
[%+ Param('emailregexpdesc') FILTER html_light %] [%+ Param('emailregexpdesc') FILTER html_light %]
[% END %] [% END %]
It must also not contain any of these special characters: It also must not contain any illegal characters.
<tt>\ ( ) &amp; &lt; &gt; , ; : &quot; [ ]</tt>, or any whitespace.
[% ELSIF error == "authres_unhandled" %] [% ELSIF error == "authres_unhandled" %]
The result value of [% value FILTER html %] was not handled by The result value of [% value FILTER html %] was not handled by
......
...@@ -841,8 +841,7 @@ ...@@ -841,8 +841,7 @@
[% ELSE %] [% ELSE %]
[%+ Param('emailregexpdesc') FILTER html_light %] [%+ Param('emailregexpdesc') FILTER html_light %]
[% END %] [% END %]
It must also not contain any of these special characters: It also must not contain any illegal characters.
<tt>\ ( ) &amp; &lt; &gt; , ; : &quot; [ ]</tt>, or any whitespace.
[% ELSIF error == "illegal_frequency" %] [% ELSIF error == "illegal_frequency" %]
[% title = "Too Frequent" %] [% title = "Too Frequent" %]
......
...@@ -117,9 +117,7 @@ sub requestChangePassword { ...@@ -117,9 +117,7 @@ sub requestChangePassword {
my $login_name = $cgi->param('loginname') my $login_name = $cgi->param('loginname')
or ThrowUserError("login_needed_for_password_change"); or ThrowUserError("login_needed_for_password_change");
validate_email_syntax($login_name) check_email_syntax($login_name);
|| ThrowUserError('illegal_email_address', {addr => $login_name});
my $user = Bugzilla::User->check($login_name); my $user = Bugzilla::User->check($login_name);
# Make sure the user account is active. # Make sure the user account is active.
......
...@@ -111,8 +111,7 @@ sub SaveAccount { ...@@ -111,8 +111,7 @@ sub SaveAccount {
} }
# Before changing an email address, confirm one does not exist. # Before changing an email address, confirm one does not exist.
validate_email_syntax($new_login_name) check_email_syntax($new_login_name);
|| ThrowUserError('illegal_email_address', {addr => $new_login_name});
is_available_username($new_login_name) is_available_username($new_login_name)
|| ThrowUserError("account_exists", {email => $new_login_name}); || ThrowUserError("account_exists", {email => $new_login_name});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment