The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use warnings;
use strict;

=head1 NAME

Jifty::Plugin::Authentication::Password::Action::Login

=cut

package Jifty::Plugin::Authentication::Password::Action::Login;
use base qw/Jifty::Action/;
use Digest::MD5 qw(md5_hex);

use constant TOKEN_EXPIRE_TIME => 30;

=head2 arguments

Return the email and password form fields

=cut

sub arguments { 
    return( { email => { label => _('Email'),
                           mandatory => 1,
                           ajax_validates => 1,
                            }  ,

              password => { type => 'password',
                            label => _('Password'),
			    # mandatory in some cases; see validate_password
                            mandatory => 0,
                        },
              hashed_password => { type => 'hidden',
                            label => _('Hashed Password'),
                        },
              remember => { type => 'checkbox',
                            label => _('Remember me?'),
                            hints => _('Your browser can remember your login for you'),
                            default => 0,
                          },
	      token => { type => 'hidden',
			 label => 'token',
			 mandatory => 0 },

          });

}

=head2 validate_email ADDRESS

Makes sure that the email submitted is a legal email and that there's a user in the database with it.

Overridden from Jifty::Action::Record.

=cut

sub validate_email {
    my $self  = shift;
    my $email = shift;

    my $u = Jifty->app_class('Model', 'User')->new(current_user => Jifty->app_class('CurrentUser')->superuser);
    $u->load_by_cols( email => $email );
    return $self->validation_error(email => _("It doesn't look like there's an account by that name.")) unless ($u->id);

    return $self->validation_ok('email');
}


=head2 validate_password PASSWORD

Makes sure that the password submitted actually exists, unless there's a token and a hashed
password.

Overridden from Jifty::Action::Record.

=cut

sub validate_password {
    my $self  = shift;
    my $pw = shift;
    my $token =  $self->argument_value('token') ||'';
    my $hashedpw =  $self->argument_value('hashed_password') ;


    if ($token eq '') { # we have no token, validate in a standard way
        unless ( defined $pw && length $pw ) {
            return $self->validation_error(password => "Please fill in this field." );
        }
    } else { # we have a token, so we should have a hashed pw
        my $emptypw = '';
        my $blankhash = md5_hex("$token $emptypw");
        if ($hashedpw eq $blankhash) {
            return $self->validation_error(password => "Please fill in this field." );
        }
        
    }


    return $self->validation_ok('password');
}

=head2 validate_token TOKEN

Make sure we issued the token within the last 30 seconds, otherwise
time out the request.

=cut

sub validate_token {
    my $self = shift;
    my $value = shift;
    if ($value) {
        if(int $value < (time - TOKEN_EXPIRE_TIME)) { 
            return $self->validation_error(token => "Your login attempt has timed out. Please try again.");
        }
        if ($value ne Jifty->web->session->get('login_token')) {
            return $self->validation_error(token => "That didn't work. Please try again.");
        }
        Jifty->web->session->set(login_token => '');
    }
    return $self->validation_ok("token");
}

=head2 take_action

Actually check the user's password. If it's right, log them in.
Otherwise, throw an error.


=cut

sub take_action {
    my $self = shift;
    my $user = Jifty->app_class('Model', 'User')->new(current_user => Jifty->app_class('CurrentUser')->superuser);
    $user->load_by_cols( email => $self->argument_value('email') );


    my $password = $self->argument_value('password');
    my $token    = $self->argument_value('token') || '';
    my $hashedpw = $self->argument_value('hashed_password');


    if ( $token ne '' ) {   # browser supports javascript, do password hashing
        unless ( $user->id && $user->hashed_password_is( $hashedpw, $token ) )
        {
            $self->result->error( _('You may have mistyped your email or password. Give it another shot.'));
            return;
        }
        Jifty->web->session->set( login_token => '' );
    } else {                # no password hashing over the wire
        unless ( $user->id && $user->password_is($password) ) {
            $self->result->error( _('You may have mistyped your email or password. Give it another shot.'));
            return;
        }
    }
    unless ($user->email_confirmed) {
                $self->result->error( q{You haven't confirmed your account yet.} );        return;
                    }

    # Set up our login message
    $self->result->message( $self->login_message($user));
    $self->result->content( id => $user->id );

    # Actually do the signin thing.
    Jifty->web->current_user(Jifty->app_class('CurrentUser')->new( id => $user->id));
    Jifty->web->session->expires( $self->argument_value('remember') ? '+1y' : undef );
    Jifty->web->session->set_cookie;

    return 1;
}

=head2 login_message $user_object

Returns the "hi, you're logged in message"

=cut


sub login_message {
    my $self = shift;
    my $user = shift;
    return _("Welcome back, %1.", $user->name);
}

1;