File Coverage

File:lib/Yukki/Web/Controller/Login.pm
Coverage:37.1%

linestmtbrancondsubpodtimecode
1package Yukki::Web::Controller::Login;
2
3
1
1
617
3
use v5.24;
4
1
1
1
3
1
5
use utf8;
5
1
1
1
10
1
3
use Moo;
6
7with 'Yukki::Web::Controller';
8
9
1
1
1
184
2
12
use Email::Address;
10
1
1
1
3
1
3
use Yukki::Error qw( http_throw );
11
1
1
1
145
1
5
use Yukki::TextUtil qw( dump_file );
12
13
1
1
1
127
2
3
use namespace::clean;
14
15# ABSTRACT: shows the login page and handles login
16
17 - 27
=head1 DESCRIPTION

Shows the login page and handles login.

=head1 METHODS

=head2 fire

Routes page reqquests to L</show_login_page>, submit requests to L</check_login_submission>, and exit requests to L</logout>.

=cut
28
29sub fire {
30
1
1
2
    my ($self, $ctx) = @_;
31
32
1
1
    my $res;
33
1
12
    my $action = $ctx->request->path_parameters->{action};
34
1
0
19
0
    if    ($action eq 'page')    { $self->show_login_page($ctx) }
35
1
4
    elsif ($action eq 'submit')  { $self->check_login_submission($ctx) }
36
0
0
    elsif ($action eq 'profile') { $self->show_profile_page($ctx) }
37
0
0
    elsif ($action eq 'update')  { $self->update_profile($ctx) }
38
0
0
    elsif ($action eq 'exit')    { $self->logout($ctx) }
39    else {
40
0
0
        http_throw('That login action does not exist.', {
41            status => 'NotFound',
42        })
43    }
44}
45
46 - 50
=head2 show_login_page

Calls L<Yukki::Web::View::Login/page> to display the login page.

=cut
51
52sub show_login_page {
53
0
1
0
    my ($self, $ctx) = @_;
54
55
0
0
    $ctx->response->body( $self->view('Login')->page($ctx) );
56}
57
58 - 62
=head2 show_profile_page

Calls L<Yukki::Web::View::Login/profile> to display the profile page.

=cut
63
64sub show_profile_page {
65
0
1
0
    my ($self, $ctx, $name, $email) = @_;
66
67
0
0
    $ctx->response->body(
68        $self->view('Login')->profile($ctx, $name, $email)
69    );
70}
71
72 - 76
=head2 update_profile

Validates the input user information and updates the user. Redirects the user back to the profile page.

=cut
77
78sub update_profile {
79
0
1
0
    my ($self, $ctx) = @_;
80
81    http_throw('You are not authorized to run this action.', {
82        status => 'Forbidden',
83
0
0
    }) unless $ctx->session->{user};
84
85
0
0
    my $login_name   = $ctx->request->body_parameters->{login_name};
86
87
0
0
    unless ($login_name eq $ctx->session->{user}{login_name}) {
88
0
0
        $ctx->add_errors('Are you sure you are logged in as the correct user? Please make sure and try again.');
89
0
0
        $ctx->response->redirect('/profile');
90
0
0
        return;
91    }
92
93
0
0
    my $name         = $ctx->request->body_parameters->{name};
94
0
0
    my $email        = $ctx->request->body_parameters->{email};
95
96
0
0
0
0
    $name  =~ s/^\s+//; $name  =~ s/\s+$//;
97
0
0
0
0
    $email =~ s/^\s+//; $email =~ s/\s+$//;
98
99
0
0
    my $invalid = 0;
100
0
0
    unless ($name =~ /\S+/) {
101
0
0
        $ctx->add_errors('name must contain at least one letter');
102
0
0
        $invalid++;
103    }
104
105
0
0
    my @emails = Email::Address->parse($email);
106
0
0
    if (@emails != 1) {
107
0
0
        $ctx->add_errors('that does not appear to be an email address');
108
0
0
        $invalid++;
109    }
110
111
0
0
    if ($invalid) {
112
0
0
        return $self->show_profile_page($ctx, $name, $email);
113    }
114
115
1
1
1
909
28038
6
    use DDP;
116
117
0
0
    my %user = $ctx->session->{user}->%*;
118
0
0
    p %user;
119
0
0
    $user{name}  = $name;
120
0
0
    $user{email} = $email;
121
122
0
0
    my $password_old = $ctx->request->body_parameters->{password_old};
123
0
0
    my $password_new = $ctx->request->body_parameters->{password_new};
124
0
0
    my $password_con = $ctx->request->body_parameters->{password_confirm};
125
126    # Only activate password check/reset if they use it
127
0
0
    if (length $password_old) {
128        my $okay = $self->check_password(
129            $ctx->session->{user},
130
0
0
            $password_old,
131        );
132
133
0
0
        unless ($okay) {
134
0
0
            $ctx->add_errors('the current password you entered is incorrect');
135
0
0
            return $self->show_profile_page($ctx, $name, $email);
136        }
137
138
0
0
        if (length($password_new) == 0) {
139
0
0
            $ctx->add_errors('you must enter a new password');
140
0
0
            return $self->show_profile_page($ctx, $name, $email);
141        }
142
143
0
0
        if ($password_old eq $password_new) {
144
0
0
            $ctx->add_errors('the new and old passwords you entered are the same');
145
0
0
            return $self->show_profile_page($ctx, $name, $email);
146        }
147
148
0
0
        if ($password_new ne $password_con) {
149
0
0
            $ctx->add_errors('the new passwords you entered do not match');
150
0
0
            return $self->show_profile_page($ctx, $name, $email);
151        }
152
153
0
0
        my $digest = $self->app->hasher;
154
0
0
        $digest->add($password_new);
155
0
0
        $user{password} = $digest->generate;
156    }
157
158
0
0
    my $user_file = $self->app->locate('user_path', $login_name);
159
0
0
    chmod 0600, "$user_file";
160
0
0
    dump_file($user_file, \%user);
161
0
0
    chmod 0400, "$user_file";
162
163
0
0
    $ctx->session->{user} = \%user;
164
165
0
0
    $ctx->response->redirect('/profile');
166
0
0
    return;
167}
168
169 - 173
=head2 check_password

Checks that the user's password is valid.

=cut
174
175sub check_password {
176
1
1
2
    my ($self, $user, $password) = @_;
177
178    return scalar $self->app->hasher->validate(
179        $user->{password},
180
1
9
        $password,
181    );
182}
183
184 - 188
=head2 check_login_submission

Authenticates a user login.

=cut
189
190sub check_login_submission {
191
1
1
3
    my ($self, $ctx) = @_;
192
193
1
11
    my $login_name = $ctx->request->body_parameters->{login_name};
194
1
445
    my $password   = $ctx->request->body_parameters->{password};
195
196
1
47
    my $user = $self->model('User')->find(login_name => $login_name);
197
198
1
70
    if (not ($user and $self->check_password($user, $password))) {
199
0
0
        $ctx->add_errors('no such user or you typed your password incorrectly');
200    }
201
202
1
317
    if ($ctx->has_errors) {
203
0
0
        $self->show_login_page($ctx);
204
0
0
        return;
205    }
206
207    else {
208
1
20
        $ctx->session->{user} = $user;
209
210
1
79
        $ctx->response->redirect($ctx->rebase_url('page/view/main'));
211
1
184
        return;
212    }
213}
214
215 - 219
=head2 logout

Expires the session, causing logout.

=cut
220
221sub logout {
222
0
1
    my ($self, $ctx) = @_;
223
224
0
    $ctx->session_options->{expire} = 1;
225
0
    $ctx->response->redirect($ctx->rebase_url('page/view/main'));
226}
227
2281;