]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
add helpers for handling logins and error handling
authorDylan William Hardison <dylan@hardison.net>
Tue, 2 Oct 2018 18:22:05 +0000 (14:22 -0400)
committerdklawren <dklawren@users.noreply.github.com>
Tue, 2 Oct 2018 18:22:05 +0000 (14:22 -0400)
13 files changed:
Bugzilla.pm
Bugzilla/Constants.pm
Bugzilla/Error.pm
Bugzilla/Error/Base.pm [new file with mode: 0644]
Bugzilla/Error/Code.pm [new file with mode: 0644]
Bugzilla/Error/User.pm [new file with mode: 0644]
Bugzilla/Quantum.pm
Bugzilla/Quantum/CGI.pm
Bugzilla/Quantum/Home.pm [new file with mode: 0644]
Bugzilla/Quantum/Plugin/Glue.pm
template/en/default/global/code-error.html.tmpl
template/en/default/global/header.html.tmpl
template/en/default/global/user-error.html.tmpl

index 05b231dcb4588ea798487a5d90ecb57fb4f4a4a5..56020b23010c06f15094d05d27ef004af5417895 100644 (file)
@@ -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});
index 525705ce17a3b8c59f8d4db9a58e93cd55903074..d0b74b5e397bb7f49189035288168d3d4c062022 100644 (file)
@@ -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';
index f932294b01522f9b54a092ff6096c4ed30586338..70430d40d92d5f80c9ff992e40df3b4f4f746b94 100644 (file)
@@ -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 (file)
index 0000000..ea44c27
--- /dev/null
@@ -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 (file)
index 0000000..27393fd
--- /dev/null
@@ -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 (file)
index 0000000..aa87c97
--- /dev/null
@@ -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;
index e9e7713e2775fd9588f3c904e378b6fb565cc645..f454a78c5e82f030b8a4d74ca674e71ed81c9871 100644 (file)
@@ -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');
index 945a87d5b3301a057b776bafa1cc70352f36ff65..317c189cce1d73bc0b9c1557ad1f000c9dc91994 100644 (file)
@@ -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 (file)
index 0000000..b3f1ec1
--- /dev/null
@@ -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;
index e9d0056d0a82d221807d85539576dd60a0ead500..8f41445894a8f5fbd0269f5d9a90bc9eef01e4bb 100644 (file)
@@ -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);
+            }
         }
     );
 
index 23d7c203b7239bc045205242cb9c6872c18545bf..8aaf1012794e8e0d0c7104d0911d36c7395b33a0 100644 (file)
 
 [%# 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 %]
index 4c6069c7412ec90b10e8265ee5d4f529abfd9ae8..1cb46a07aa620d746be30e324e61068dc6c519c5 100644 (file)
           <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>
index c6efb56495f9e3563ea26c0d1fa17089c299face..9b058300905517ea67cf2019c1911426e90b2cfb 100644 (file)
 
 [%# 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 %]