2017-01-24 18:55:20 +01:00
|
|
|
package Lemonldap::NG::Portal::Lib::Captcha;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use GD::SecurityImage use_magick => 1;
|
|
|
|
use Mouse;
|
|
|
|
use MIME::Base64;
|
|
|
|
|
2019-02-12 18:21:38 +01:00
|
|
|
our $VERSION = '2.1.0';
|
2017-01-24 18:55:20 +01:00
|
|
|
|
|
|
|
extends 'Lemonldap::NG::Common::Module';
|
|
|
|
|
2017-03-27 18:51:18 +02:00
|
|
|
has width => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub { $_[0]->{conf}->{captchaWidth} || 220 }
|
|
|
|
);
|
|
|
|
has height => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub { $_[0]->{conf}->{captchaHeight} || 40 }
|
|
|
|
);
|
|
|
|
has lines => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub { $_[0]->{conf}->{captchaLines} || 5 }
|
|
|
|
);
|
|
|
|
has scramble => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub { $_[0]->{conf}->{captchaScramble} || 1 }
|
|
|
|
);
|
|
|
|
has fgColor => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub { $_[0]->{conf}->{captchaFg} || '#403030' }
|
|
|
|
);
|
|
|
|
has bgColor => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub { $_[0]->{conf}->{captchaBg} || '#FF644B' }
|
|
|
|
);
|
|
|
|
has rndmax => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub { $_[0]->{conf}->{captcha_size} || 6 }
|
|
|
|
);
|
|
|
|
has timeout => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub { $_[0]->{conf}->{formTimeout} }
|
|
|
|
);
|
2017-01-24 22:02:02 +01:00
|
|
|
|
|
|
|
has ott => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub {
|
2017-01-25 23:08:15 +01:00
|
|
|
my $ott = $_[0]->{p}->loadModule('::Lib::OneTimeToken');
|
|
|
|
$ott->timeout( $_[0]->timeout );
|
2017-01-24 22:02:02 +01:00
|
|
|
return $ott;
|
|
|
|
}
|
|
|
|
);
|
2017-01-24 18:55:20 +01:00
|
|
|
|
2018-10-03 22:31:28 +02:00
|
|
|
sub init { 1 }
|
|
|
|
|
2017-01-25 12:11:48 +01:00
|
|
|
# Returns secret + a HTML image src content
|
2017-01-24 18:55:20 +01:00
|
|
|
sub getCaptcha {
|
|
|
|
my ($self) = @_;
|
|
|
|
my $image = GD::SecurityImage->new(
|
|
|
|
width => $self->width,
|
2017-01-25 23:08:15 +01:00
|
|
|
height => $self->height,
|
2017-01-24 18:55:20 +01:00
|
|
|
lines => $self->lines,
|
|
|
|
gd_font => 'Giant',
|
|
|
|
scramble => $self->scramble,
|
2017-01-24 22:02:02 +01:00
|
|
|
rndmax => $self->rndmax,
|
2017-01-24 18:55:20 +01:00
|
|
|
);
|
|
|
|
$image->random;
|
|
|
|
$image->create( 'normal', 'default', $self->fgColor, $self->bgColor );
|
|
|
|
my ( $imageData, $mimeType, $rdm ) = $image->out( force => 'png' );
|
2017-01-25 12:11:48 +01:00
|
|
|
my $img = 'data:image/png;base64,' . encode_base64( $imageData, '' );
|
2017-01-24 22:02:02 +01:00
|
|
|
my $token = $self->ott->createToken( { captcha => $rdm } );
|
|
|
|
return ( $token, $img );
|
|
|
|
}
|
|
|
|
|
|
|
|
sub validateCaptcha {
|
|
|
|
my ( $self, $token, $value ) = @_;
|
|
|
|
my $s = $self->ott->getToken($token);
|
|
|
|
unless ($s) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->warn("Captcha token $token isn't valid");
|
2017-01-24 22:02:02 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2018-12-17 19:34:28 +01:00
|
|
|
unless ( $s->{captcha} eq $value ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->notice('Bad captcha response');
|
2017-01-25 12:11:48 +01:00
|
|
|
return 0;
|
2017-01-24 22:02:02 +01:00
|
|
|
}
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug('Good captcha response');
|
2017-01-24 22:02:02 +01:00
|
|
|
return 1;
|
2017-01-24 18:55:20 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 22:42:42 +01:00
|
|
|
sub setCaptcha {
|
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
my ( $token, $image ) = $self->getCaptcha;
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug('Prepare captcha');
|
2017-01-26 22:42:42 +01:00
|
|
|
$req->token($token);
|
2019-03-27 12:30:11 +01:00
|
|
|
$req->tplParams->{CAPTCHA_SRC} = $req->captcha($image);
|
|
|
|
$req->tplParams->{CAPTCHA_SIZE} = $self->rndmax;
|
2017-01-26 22:42:42 +01:00
|
|
|
}
|
|
|
|
|
2017-01-24 18:55:20 +01:00
|
|
|
1;
|