diff --git a/Bugzilla/Install/Filesystem.pm b/Bugzilla/Install/Filesystem.pm index 4f133d8656..fb894a5b67 100644 --- a/Bugzilla/Install/Filesystem.pm +++ b/Bugzilla/Install/Filesystem.pm @@ -214,6 +214,8 @@ sub FILESYSTEM { dirs => DIR_CGI_WRITE }, $assetsdir => { files => WS_SERVE, dirs => DIR_CGI_OVERWRITE | DIR_ALSO_WS_SERVE }, + "$datadir/captcha" => { files => CGI_WRITE, + dirs => DIR_CGI_WRITE }, # Readable directories "$datadir/mining" => { files => CGI_READ, @@ -282,6 +284,7 @@ sub FILESYSTEM { $extensionsdir => DIR_CGI_READ, # Directories that cgi scripts can write to. "$datadir/db" => DIR_CGI_WRITE, + "$datadir/captcha" => DIR_CGI_WRITE, $attachdir => DIR_CGI_WRITE, $graphsdir => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE, $webdotdir => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE, @@ -430,7 +433,7 @@ EOT "$assetsdir/.htaccess" => { perms => WS_SERVE, contents => < + Allow from all diff --git a/Bugzilla/Install/Requirements.pm b/Bugzilla/Install/Requirements.pm index a688a0ffa2..82a4ff9fe7 100644 --- a/Bugzilla/Install/Requirements.pm +++ b/Bugzilla/Install/Requirements.pm @@ -166,6 +166,11 @@ sub REQUIRED_MODULES { # 2.0 is the first version that will work with JSON::RPC. version => '2.01', }, + { + package => 'Authen-Captcha', + module => 'Authen::Captcha', + version => '1.024', + }, ); if (ON_WINDOWS) { diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index ce027171bd..3e9136efc7 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -591,6 +591,18 @@ sub _concatenate_js { return [ $file ]; } +sub _captcha_path { + my $token = shift; + return "" unless $token; + + my $cgi_path = bz_locations()->{cgi_path}; + my $assets_path = bz_locations()->{assetsdir}; + my $captcha_path = "$assets_path" . "/$token.png"; + + $captcha_path =~ s/^\Q$cgi_path\E\///o; + return $captcha_path; +} + # YUI dependency resolution sub yui_resolve_deps { my ($yui, $yui_deps) = @_; @@ -1112,6 +1124,7 @@ sub create { 'css_files' => \&css_files, yui_resolve_deps => \&yui_resolve_deps, concatenate_js => \&_concatenate_js, + captcha_path => \&_captcha_path, # All classifications (sorted by sortkey, name) 'all_classifications' => sub { diff --git a/createaccount.cgi b/createaccount.cgi index 8960434093..e211454e0d 100755 --- a/createaccount.cgi +++ b/createaccount.cgi @@ -17,6 +17,8 @@ use Bugzilla::Constants; use Bugzilla::Error; use Bugzilla::Token; +use Authen::Captcha; + # Just in case someone already has an account, let them get the correct footer # on an error message. The user is logged out just after the account is # actually created. @@ -33,13 +35,32 @@ my $login = $cgi->param('login'); my $uid = $cgi->param('uid'); # Modified for Mer to send uid to account creation and to put uid into -# the $vars for the templates +# the $vars for the templates. And added captcha for the robots + +my $captcha_data = bz_locations()->{'datadir'} . "/captcha"; +my $captcha_output = bz_locations()->{'assetsdir'}; +my $captcha = Authen::Captcha->new( + data_folder => $captcha_data, + output_folder => $captcha_output, +); + if (defined($login)) { # Check the hash token to make sure this user actually submitted # the create account form. my $token = $cgi->param('token'); check_hash_token($token, ['create_account']); + my $captcha_token = $cgi->param('captcha_token'); + my $captcha_code = $cgi->param('captcha_code'); + my $result = $captcha->check_code($captcha_code, $captcha_token); + if ($result == 0) { + ThrowCodeError('captcha_check_error'); + } elsif ($result == -1) { + ThrowUserError('captcha_expired'); + } elsif ($result < -1 ) { + ThrowUserError('captcha_invalid'); + } + $user->check_and_send_account_creation_confirmation($login, $uid); $vars->{'login'} = $login; $vars->{'uid'} = $uid; @@ -49,6 +70,8 @@ if (defined($login)) { exit; } +$vars->{'captcha_token'} = $captcha->generate_code(10); + # Show the standard "would you like to create an account?" form. $template->process("account/create.html.tmpl", $vars) || ThrowTemplateError($template->error()); diff --git a/template/en/default/account/create.html.tmpl b/template/en/default/account/create.html.tmpl index 637fd5497b..ab5dfe8689 100644 --- a/template/en/default/account/create.html.tmpl +++ b/template/en/default/account/create.html.tmpl @@ -86,6 +86,14 @@ Username: + +

+ + Enter the above code: + + + + diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl index d73d75e135..70e8862946 100644 --- a/template/en/default/global/code-error.html.tmpl +++ b/template/en/default/global/code-error.html.tmpl @@ -389,6 +389,10 @@ Bugzilla does not support the search type "[% operator.truncate(30, "...") FILTER html %]". + [% ELSIF error == "captcha_check_error" %] + [% title = "Captcha check failed" %] + Checking the captcha code failed. + [% ELSE %] [%# Try to find hooked error messages %] [% error_message = Hook.process("errors") %] diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 3bd1181a14..c00e721e03 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -1947,6 +1947,14 @@ [% END %] with the External Login ID "[% extern_id FILTER html %]". + [% ELSIF error == "captcha_expired" %] + [% title = "Invalid captcha" %] + The used captcha has already expired. + + [% ELSIF error == "captcha_invalid" %] + [% title = "Invalid captcha" %] + The given captcha code is not correct. + [% ELSE %] [%# Try to find hooked error messages %]