summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDylan William Hardison <dylan@hardison.net>2018-10-02 20:22:05 +0200
committerdklawren <dklawren@users.noreply.github.com>2018-10-02 20:22:05 +0200
commit62412db14081dd66cd5b2701b598b5af9eb31528 (patch)
tree7e84a852449e530a0b0bae5ef581eace63c81e83
parentabe9b579f25120898b714d4b73343918169d48ac (diff)
downloadbugzilla-62412db14081dd66cd5b2701b598b5af9eb31528.tar.gz
bugzilla-62412db14081dd66cd5b2701b598b5af9eb31528.tar.xz
add helpers for handling logins and error handling
-rw-r--r--Bugzilla.pm3
-rw-r--r--Bugzilla/Constants.pm4
-rw-r--r--Bugzilla/Error.pm12
-rw-r--r--Bugzilla/Error/Base.pm21
-rw-r--r--Bugzilla/Error/Code.pm14
-rw-r--r--Bugzilla/Error/User.pm13
-rw-r--r--Bugzilla/Quantum.pm2
-rw-r--r--Bugzilla/Quantum/CGI.pm3
-rw-r--r--Bugzilla/Quantum/Home.pm26
-rw-r--r--Bugzilla/Quantum/Plugin/Glue.pm111
-rw-r--r--template/en/default/global/code-error.html.tmpl14
-rw-r--r--template/en/default/global/header.html.tmpl10
-rw-r--r--template/en/default/global/user-error.html.tmpl14
13 files changed, 211 insertions, 36 deletions
diff --git a/Bugzilla.pm b/Bugzilla.pm
index 05b231dcb..56020b230 100644
--- a/Bugzilla.pm
+++ b/Bugzilla.pm
@@ -483,6 +483,9 @@ sub usage_mode {
elsif ($newval == USAGE_MODE_REST) {
$class->error_mode(ERROR_MODE_REST);
}
+ elsif ($newval == USAGE_MODE_MOJO) {
+ $class->error_mode(ERROR_MODE_MOJO);
+ }
else {
ThrowCodeError('usage_mode_invalid',
{'invalid_usage_mode', $newval});
diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm
index 525705ce1..d0b74b5e3 100644
--- a/Bugzilla/Constants.pm
+++ b/Bugzilla/Constants.pm
@@ -131,6 +131,7 @@ use Memoize;
USAGE_MODE_JSON
USAGE_MODE_TEST
USAGE_MODE_REST
+ USAGE_MODE_MOJO
ERROR_MODE_WEBPAGE
ERROR_MODE_DIE
@@ -138,6 +139,7 @@ use Memoize;
ERROR_MODE_JSON_RPC
ERROR_MODE_TEST
ERROR_MODE_REST
+ ERROR_MODE_MOJO
COLOR_ERROR
COLOR_SUCCESS
@@ -488,6 +490,7 @@ use constant USAGE_MODE_EMAIL => 3;
use constant USAGE_MODE_JSON => 4;
use constant USAGE_MODE_TEST => 5;
use constant USAGE_MODE_REST => 6;
+use constant USAGE_MODE_MOJO => 7;
# Error modes. Default set by Bugzilla->usage_mode (so ERROR_MODE_WEBPAGE
# usually). Use with Bugzilla->error_mode.
@@ -497,6 +500,7 @@ use constant ERROR_MODE_DIE_SOAP_FAULT => 2;
use constant ERROR_MODE_JSON_RPC => 3;
use constant ERROR_MODE_TEST => 4;
use constant ERROR_MODE_REST => 5;
+use constant ERROR_MODE_MOJO => 6;
# The ANSI colors of messages that command-line scripts use
use constant COLOR_ERROR => 'red';
diff --git a/Bugzilla/Error.pm b/Bugzilla/Error.pm
index f932294b0..70430d40d 100644
--- a/Bugzilla/Error.pm
+++ b/Bugzilla/Error.pm
@@ -20,6 +20,8 @@ our @EXPORT = qw( ThrowCodeError ThrowTemplateError ThrowUserError ThrowErrorPag
use Bugzilla::Constants;
use Bugzilla::WebService::Constants;
use Bugzilla::Util;
+use Bugzilla::Error::User;
+use Bugzilla::Error::Code;
use Carp;
use Data::Dumper;
@@ -40,7 +42,6 @@ sub _in_eval {
sub _throw_error {
my ($name, $error, $vars, $logfunc) = @_;
$vars ||= {};
- $vars->{error} = $error;
# Make sure any transaction is rolled back (if supported).
# If we are within an eval(), do not roll back transactions as we are
@@ -48,6 +49,15 @@ sub _throw_error {
my $dbh = eval { Bugzilla->dbh };
$dbh->bz_rollback_transaction() if ($dbh && $dbh->bz_in_transaction() && !_in_eval());
+ if (Bugzilla->error_mode == ERROR_MODE_MOJO) {
+ my ($type) = $name =~ /^global\/(user|code)-error/;
+ my $class = $type ? 'Bugzilla::Error::' . ucfirst($type) : 'Mojo::Exception';
+ my $e = $class->new($error)->trace(2);
+ $e->vars($vars) if $e->can('vars');
+ CORE::die $e->inspect;
+ }
+
+ $vars->{error} = $error;
my $template = Bugzilla->template;
my $message;
diff --git a/Bugzilla/Error/Base.pm b/Bugzilla/Error/Base.pm
new file mode 100644
index 000000000..ea44c272a
--- /dev/null
+++ b/Bugzilla/Error/Base.pm
@@ -0,0 +1,21 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Error::Base;
+
+use 5.10.1;
+use Mojo::Base 'Mojo::Exception';
+
+has 'vars' => sub { {} };
+
+has 'template' => sub {
+ my $self = shift;
+ my $type = lc( (split(/::/, ref $self))[-1] );
+ return "global/$type-error";
+};
+
+1;
diff --git a/Bugzilla/Error/Code.pm b/Bugzilla/Error/Code.pm
new file mode 100644
index 000000000..27393fd17
--- /dev/null
+++ b/Bugzilla/Error/Code.pm
@@ -0,0 +1,14 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Error::Code;
+
+use 5.10.1;
+use Mojo::Base 'Bugzilla::Error::Base';
+
+
+1;
diff --git a/Bugzilla/Error/User.pm b/Bugzilla/Error/User.pm
new file mode 100644
index 000000000..aa87c9752
--- /dev/null
+++ b/Bugzilla/Error/User.pm
@@ -0,0 +1,13 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Error::User;
+
+use 5.10.1;
+use Mojo::Base 'Bugzilla::Error::Base';
+
+1;
diff --git a/Bugzilla/Quantum.pm b/Bugzilla/Quantum.pm
index e9e7713e2..f454a78c5 100644
--- a/Bugzilla/Quantum.pm
+++ b/Bugzilla/Quantum.pm
@@ -22,6 +22,7 @@ use Bugzilla::Install::Requirements ();
use Bugzilla::Logging;
use Bugzilla::Quantum::CGI;
use Bugzilla::Quantum::SES;
+use Bugzilla::Quantum::Home;
use Bugzilla::Quantum::Static;
use Mojo::Loader qw( find_modules );
use Module::Runtime qw( require_module );
@@ -98,6 +99,7 @@ sub setup_routes {
Bugzilla::Quantum::CGI->load_all($r);
Bugzilla::Quantum::CGI->load_one( 'bzapi_cgi', 'extensions/BzAPI/bin/rest.cgi' );
+ $r->get('/home')->to('Home#index');
$r->any('/')->to('CGI#index_cgi');
$r->any('/bug/<id:num>')->to('CGI#show_bug_cgi');
$r->any('/<id:num>')->to('CGI#show_bug_cgi');
diff --git a/Bugzilla/Quantum/CGI.pm b/Bugzilla/Quantum/CGI.pm
index 945a87d5b..317c189cc 100644
--- a/Bugzilla/Quantum/CGI.pm
+++ b/Bugzilla/Quantum/CGI.pm
@@ -19,7 +19,7 @@ use File::Spec::Functions qw(catfile);
use File::Slurper qw(read_text);
use English qw(-no_match_vars);
use Bugzilla::Quantum::Stdout;
-use Bugzilla::Constants qw(bz_locations);
+use Bugzilla::Constants qw(bz_locations USAGE_MODE_BROWSER);
our $C;
my %SEEN;
@@ -61,6 +61,7 @@ sub load_one {
# the finally block calls cleanup.
$c->stash->{cleanup_guard}->dismiss;
+ Bugzilla->usage_mode(USAGE_MODE_BROWSER);
try {
Bugzilla->init_page();
$inner->();
diff --git a/Bugzilla/Quantum/Home.pm b/Bugzilla/Quantum/Home.pm
new file mode 100644
index 000000000..b3f1ec1d1
--- /dev/null
+++ b/Bugzilla/Quantum/Home.pm
@@ -0,0 +1,26 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Quantum::Home;
+use Mojo::Base 'Mojolicious::Controller';
+
+use Bugzilla::Error;
+use Try::Tiny;
+use Bugzilla::Constants;
+
+sub index {
+ my ($c) = @_;
+ $c->bugzilla->login(LOGIN_REQUIRED) or return;
+ try {
+ ThrowUserError('invalid_username', { login => 'batman' }) if $c->param('error');
+ $c->render(handler => 'bugzilla', template => 'index');
+ } catch {
+ $c->bugzilla->error_page($_);
+ };
+}
+
+1;
diff --git a/Bugzilla/Quantum/Plugin/Glue.pm b/Bugzilla/Quantum/Plugin/Glue.pm
index e9d0056d0..8f4144589 100644
--- a/Bugzilla/Quantum/Plugin/Glue.pm
+++ b/Bugzilla/Quantum/Plugin/Glue.pm
@@ -13,7 +13,10 @@ use Try::Tiny;
use Bugzilla::Constants;
use Bugzilla::Logging;
use Bugzilla::RNG ();
-use JSON::MaybeXS qw(decode_json);
+use Bugzilla::Util qw(with_writable_database);
+use Mojo::Util qw(secure_compare);
+use Mojo::JSON qw(decode_json);
+use Scalar::Util qw(blessed);
use Scope::Guard;
sub register {
@@ -44,34 +47,110 @@ sub register {
}
Log::Log4perl::MDC->put( request_id => $c->req->request_id );
$c->stash->{cleanup_guard} = Scope::Guard->new( \&Bugzilla::cleanup );
+ Bugzilla->usage_mode(USAGE_MODE_MOJO);
}
);
-
$app->secrets( [ Bugzilla->localconfig->{side_wide_secret} ] );
$app->renderer->add_handler(
'bugzilla' => sub {
my ( $renderer, $c, $output, $options ) = @_;
- my $vars = delete $c->stash->{vars};
+ my %params;
# Helpers
- my %helper;
- foreach my $method ( grep {m/^\w+\z/} keys %{ $renderer->helpers } ) {
- my $sub = $renderer->helpers->{$method};
- $helper{$method} = sub { $c->$sub(@_) };
+ foreach my $method (grep { m/^\w+\z/ } keys %{$renderer->helpers}) {
+ my $sub = $renderer->helpers->{$method};
+ $params{$method} = sub { $c->$sub(@_) };
}
- $vars->{helper} = \%helper;
+ # Stash values
+ $params{$_} = $c->stash->{$_} for grep { m/^\w+\z/ } keys %{$c->stash};
- # The controller
- $vars->{c} = $c;
- my $name = $options->{template};
- unless ( $name =~ /\./ ) {
- $name = sprintf '%s.%s.tmpl', $options->{template}, $options->{format};
- }
+ $params{self} = $params{c} = $c;
+
+ my $name = sprintf '%s.%s.tmpl', $options->{template}, $options->{format};
my $template = Bugzilla->template;
- $template->process( $name, $vars, $output )
- or die $template->error;
+ $template->process( $name, \%params, $output )
+ or die $template->error;
+ }
+ );
+ $app->helper(
+ 'bugzilla.login_redirect_if_required' => sub {
+ my ( $c, $type ) = @_;
+
+ if ( $type == LOGIN_REQUIRED ) {
+ $c->redirect_to('/login');
+ return undef;
+ }
+ else {
+ return Bugzilla->user;
+ }
+ }
+ );
+ $app->helper(
+ 'bugzilla.login' => sub {
+ my ( $c, $type ) = @_;
+ $type //= LOGIN_NORMAL;
+
+ return Bugzilla->user if Bugzilla->user->id;
+
+ $type = LOGIN_REQUIRED if $c->param('GoAheadAndLogIn') || Bugzilla->params->{requirelogin};
+
+ # Allow templates to know that we're in a page that always requires
+ # login.
+ if ( $type == LOGIN_REQUIRED ) {
+ Bugzilla->request_cache->{page_requires_login} = 1;
+ }
+
+ my $login_cookie = $c->cookie("Bugzilla_logincookie");
+ my $user_id = $c->cookie("Bugzilla_login");
+ my $ip_addr = $c->tx->remote_address;
+
+ return $c->bugzilla->login_redirect_if_required($type) unless ( $login_cookie && $user_id );
+
+ my $db_cookie = Bugzilla->dbh->selectrow_array(
+ q{
+ SELECT cookie
+ FROM logincookies
+ WHERE cookie = ?
+ AND userid = ?
+ AND (restrict_ipaddr = 0 OR ipaddr = ?)
+ },
+ undef,
+ ( $login_cookie, $user_id, $ip_addr )
+ );
+
+ if ( defined $db_cookie && secure_compare( $login_cookie, $db_cookie ) ) {
+ my $user = Bugzilla::User->check( { id => $user_id, cache => 1 } );
+
+ # If we logged in successfully, then update the lastused
+ # time on the login cookie
+ with_writable_database {
+ Bugzilla->dbh->do( q{ UPDATE logincookies SET lastused = NOW() WHERE cookie = ? },
+ undef, $login_cookie );
+ };
+ Bugzilla->set_user($user);
+ return $user;
+ }
+ else {
+ return $c->bugzilla->login_redirect_if_required($type);
+ }
+ }
+ );
+ $app->helper(
+ 'bugzilla.error_page' => sub {
+ my ( $c, $error ) = @_;
+ if ( blessed $error && $error->isa('Bugzilla::Error::Base') ) {
+ $c->render(
+ handler => 'bugzilla',
+ template => $error->template,
+ error => $error->message,
+ %{ $error->vars }
+ );
+ }
+ else {
+ $c->reply->exception($error);
+ }
}
);
diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl
index 23d7c203b..8aaf10127 100644
--- a/template/en/default/global/code-error.html.tmpl
+++ b/template/en/default/global/code-error.html.tmpl
@@ -514,13 +514,15 @@
[%# We only want HTML error messages for ERROR_MODE_WEBPAGE %]
[% USE Bugzilla %]
-[% IF Bugzilla.error_mode != constants.ERROR_MODE_WEBPAGE %]
- [% IF Bugzilla.usage_mode == constants.USAGE_MODE_BROWSER %]
- [% error_message FILTER none %]
- [% ELSE %]
- [% error_message FILTER txt %]
+[% IF Bugzilla.usage_mode != constants.USAGE_MODE_MOJO %]
+ [% IF Bugzilla.error_mode != constants.ERROR_MODE_WEBPAGE %]
+ [% IF Bugzilla.usage_mode == constants.USAGE_MODE_BROWSER %]
+ [% error_message FILTER none %]
+ [% ELSE %]
+ [% error_message FILTER txt %]
+ [% END %]
+ [% RETURN %]
[% END %]
- [% RETURN %]
[% END %]
[% UNLESS header_done %]
diff --git a/template/en/default/global/header.html.tmpl b/template/en/default/global/header.html.tmpl
index 4c6069c74..1cb46a07a 100644
--- a/template/en/default/global/header.html.tmpl
+++ b/template/en/default/global/header.html.tmpl
@@ -346,12 +346,10 @@
<li role="presentation">
<a href="userprefs.cgi" role="menuitem" tabindex="-1">Preferences</a>
</li>
- [% IF user.authorizer.can_logout %]
- <li role="separator"></li>
- <li role="presentation">
- <a href="index.cgi?logout=1" role="menuitem" tabindex="-1">Log out</a>
- </li>
- [% END %]
+ <li role="separator"></li>
+ <li role="presentation">
+ <a href="index.cgi?logout=1" role="menuitem" tabindex="-1">Log out</a>
+ </li>
[% IF sudoer %]
<li role="presentation">
<a href="relogin.cgi?action=end-sudo" role="menuitem" tabindex="-1">End sudo session impersonating [% user.login FILTER html %]</a>
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index c6efb5649..9b0583009 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -1982,13 +1982,15 @@
[%# We only want HTML error messages for ERROR_MODE_WEBPAGE %]
[% USE Bugzilla %]
-[% IF Bugzilla.error_mode != constants.ERROR_MODE_WEBPAGE %]
- [% IF Bugzilla.usage_mode == constants.USAGE_MODE_BROWSER %]
- [% error_message FILTER none %]
- [% ELSE %]
- [% error_message FILTER txt %]
+[% IF Bugzilla.usage_mode != constants.USAGE_MODE_MOJO %]
+ [% IF Bugzilla.error_mode != constants.ERROR_MODE_WEBPAGE %]
+ [% IF Bugzilla.usage_mode == constants.USAGE_MODE_BROWSER %]
+ [% error_message FILTER none %]
+ [% ELSE %]
+ [% error_message FILTER txt %]
+ [% END %]
+ [% RETURN %]
[% END %]
- [% RETURN %]
[% END %]
[% UNLESS header_done %]