216 lines
5.9 KiB
Perl
216 lines
5.9 KiB
Perl
package password_requests;
|
|
|
|
use strict;
|
|
use warnings;
|
|
no warnings 'redefine';
|
|
|
|
use Data::Dumper;
|
|
use Session::Token();
|
|
|
|
# table: calcms_password_requests
|
|
our @EXPORT_OK = qw(get insert delete get_columns);
|
|
|
|
use mail;
|
|
use uac;
|
|
use db;
|
|
use auth;
|
|
|
|
sub get_columns ($) {
|
|
my ($config) = @_;
|
|
my $dbh = db::connect($config);
|
|
return db::get_columns_hash( $dbh, 'calcms_password_requests' );
|
|
}
|
|
|
|
sub get ($$) {
|
|
my ($config, $condition) = @_;
|
|
|
|
my $dbh = db::connect($config);
|
|
my @conditions = ();
|
|
my @bind_values = ();
|
|
|
|
if ( defined $condition->{user} ) {
|
|
push @conditions, 'user=?';
|
|
push @bind_values, $condition->{user};
|
|
}
|
|
|
|
if ( defined $condition->{token} ) {
|
|
push @conditions, 'token=?';
|
|
push @bind_values, $condition->{token};
|
|
}
|
|
|
|
return undef if ( scalar @conditions ) == 0;
|
|
|
|
my $conditions = " where " . join( " and ", @conditions );
|
|
my $query = qq{
|
|
select *
|
|
from calcms_password_requests
|
|
$conditions
|
|
};
|
|
|
|
my $entries = db::get( $dbh, $query, \@bind_values );
|
|
return $entries->[0] || undef;
|
|
}
|
|
|
|
sub update($$) {
|
|
my ($config, $entry) = @_;
|
|
|
|
return unless defined $entry->{user};
|
|
|
|
my $dbh = db::connect($config);
|
|
my @keys = sort keys %$entry;
|
|
my $values = join( ",", map { $_ . '=?' } @keys);
|
|
my @bind_values = map { $entry->{$_} } @keys;
|
|
push @bind_values, $entry->{token};
|
|
|
|
my $query = qq{
|
|
update calcms_password_requests
|
|
set $values
|
|
where token=?
|
|
};
|
|
db::put( $dbh, $query, \@bind_values );
|
|
}
|
|
|
|
sub insert ($$) {
|
|
my ($config, $entry) = @_;
|
|
|
|
return undef unless defined $entry->{user};
|
|
|
|
my $dbh = db::connect($config);
|
|
return db::insert( $dbh, 'calcms_password_requests', $entry );
|
|
}
|
|
|
|
sub delete ($$) {
|
|
my ($config, $condition) = @_;
|
|
|
|
my @conditions = ();
|
|
my @bind_values = ();
|
|
|
|
if ( ( defined $condition->{user} ) && ( $condition->{user} ne '' ) ) {
|
|
push @conditions, 'user=?';
|
|
push @bind_values, $condition->{user};
|
|
}
|
|
|
|
if ( ( defined $condition->{token} ) && ( $condition->{token} ne '' ) ) {
|
|
push @conditions, 'token=?';
|
|
push @bind_values, $condition->{token};
|
|
}
|
|
|
|
return if ( scalar @conditions ) == 0;
|
|
my $conditions = " where " . join( " and ", @conditions );
|
|
|
|
my $dbh = db::connect($config);
|
|
|
|
my $query = qq{
|
|
delete
|
|
from calcms_password_requests
|
|
$conditions
|
|
};
|
|
|
|
db::put( $dbh, $query, \@bind_values );
|
|
}
|
|
|
|
sub sendToken ($$) {
|
|
my ($config, $entry) = @_;
|
|
|
|
return undef unless defined $entry->{user};
|
|
|
|
my $user = uac::get_user( $config, $entry->{user} );
|
|
return undef unless defined $user;
|
|
|
|
# check age of existing entry
|
|
my $oldEntry = password_requests::get( $config, { user => $entry->{user} } );
|
|
if ( defined $oldEntry ) {
|
|
my $createdAt = $oldEntry->{created_at};
|
|
my $age = time() - time::datetime_to_time($createdAt);
|
|
if ( $age < 60 ) {
|
|
print STDERR "too many requests";
|
|
return undef;
|
|
}
|
|
print STDERR "age=$age\n";
|
|
}
|
|
password_requests::delete( $config, $entry );
|
|
|
|
$entry->{max_attempts} = 0;
|
|
$entry->{token} = Session::Token->new->get;
|
|
|
|
my $baseUrl = $config->{locations}->{source_base_url} . $config->{locations}->{editor_base_url};
|
|
my $url = $baseUrl . "/request-password.cgi?token=" . $entry->{token};
|
|
my $content = "Hi,$user->{full_name}\n\n";
|
|
$content .= "Someone has just tried to reset your password for $baseUrl.\n\n";
|
|
$content .= "If you want to set a new password, please follow this link\n";
|
|
$content .= $url . "\n\n";
|
|
$content .= "If you do not want to set a new password, please ignore this mail.\n";
|
|
|
|
mail::send(
|
|
{
|
|
"From" => $config->{locations}->{email},
|
|
"To" => $user->{email},
|
|
"Subject" => "request to change password for $baseUrl",
|
|
"Data" => $content
|
|
}
|
|
);
|
|
|
|
password_requests::insert( $config, $entry );
|
|
}
|
|
|
|
sub changePassword ($$$) {
|
|
my ($config, $request, $userName) = @_;
|
|
|
|
my $params = $request->{params}->{checked};
|
|
my $permissions = $request->{permissions};
|
|
|
|
unless ( ( defined $userName ) || ( $userName eq '' ) ) {
|
|
return { error => 'The User could not be found.' };
|
|
}
|
|
|
|
my $user = uac::get_user( $config, $userName );
|
|
|
|
unless ( ( defined $user ) && ( defined $user->{id} ) && ( $user->{id} ne '' ) ) {
|
|
return { error => 'Te User ID could not be found.' };
|
|
}
|
|
|
|
if ( my $msg = password_requests::isPasswordInvalid( $params->{user_password} ) ) {
|
|
return { error => $msg } if $msg;
|
|
}
|
|
|
|
if ( $params->{user_password} ne $params->{user_password2} ) {
|
|
return { error => 'The passwords entered do not match.' };
|
|
}
|
|
|
|
my $crypt = auth::crypt_password( $params->{user_password} );
|
|
$user = { id => $user->{id} };
|
|
$user->{salt} = $crypt->{salt};
|
|
$user->{pass} = $crypt->{crypt};
|
|
|
|
$config->{access}->{write} = 1;
|
|
my $result = uac::update_user( $config, $user );
|
|
$config->{access}->{write} = 0;
|
|
return { success => "The password was changed for $userName." };
|
|
}
|
|
|
|
sub isPasswordInvalid($) {
|
|
my ($password) = @_;
|
|
unless ( defined $password || $password eq '' ) {
|
|
return "The password must not be empty.";
|
|
}
|
|
if ( length($password) < 8 ) {
|
|
return "The password must have at least 8 characters.";
|
|
}
|
|
unless ( $password =~ /[a-z]/ ) {
|
|
return "The password must contain at least one small character.";
|
|
}
|
|
unless ( $password =~ /[A-Z]/ ) {
|
|
return "The password must contain at least one big character";
|
|
}
|
|
unless ( $password =~ /[0-9]/ ) {
|
|
return "The password must contain at least one number.";
|
|
}
|
|
unless ( $password =~ /[^a-zA-Z0-9]/ ) {
|
|
return "The password must contain at least one special character.";
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#do not delete last line!
|
|
1;
|