@@ -, +, @@ Until a satisfactory new password is entered, the old password is not reset. --- C4/Auth.pm | 2 + C4/Members.pm | 89 ++++++++- installer/data/mysql/kohastructure.sql | 11 ++ installer/data/mysql/sysprefs.sql | 1 + installer/data/mysql/updatedatabase.pl | 15 ++ .../prog/en/modules/admin/preferences/opac.pref | 7 + .../opac-tmpl/bootstrap/en/includes/masthead.inc | 5 +- .../opac-tmpl/bootstrap/en/modules/opac-auth.tt | 4 + .../opac-tmpl/bootstrap/en/modules/opac-main.tt | 3 + .../bootstrap/en/modules/opac-password-recovery.tt | 132 +++++++++++++ .../en/modules/opac-send-password-recovery.tt | 19 ++ koha-tmpl/opac-tmpl/prog/en/modules/opac-auth.tt | 3 + koha-tmpl/opac-tmpl/prog/en/modules/opac-main.tt | 6 +- .../prog/en/modules/opac-password-recovery.tt | 130 +++++++++++++ .../prog/en/modules/opac-send-password-recovery.tt | 17 ++ opac/opac-main.pl | 1 + opac/opac-password-recovery.pl | 205 ++++++++++++++++++++ 17 files changed, 647 insertions(+), 3 deletions(-) create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-password-recovery.tt create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-send-password-recovery.tt create mode 100644 koha-tmpl/opac-tmpl/prog/en/modules/opac-password-recovery.tt create mode 100644 koha-tmpl/opac-tmpl/prog/en/modules/opac-send-password-recovery.tt create mode 100755 opac/opac-password-recovery.pl --- a/C4/Auth.pm +++ a/C4/Auth.pm @@ -1068,6 +1068,8 @@ sub checkauth { PatronSelfRegistrationDefaultCategory => C4::Context->preference("PatronSelfRegistrationDefaultCategory"), persona => C4::Context->preference("Persona"), opac_css_override => $ENV{'OPAC_CSS_OVERRIDE'}, + OpacResetPassword => C4::Context->preference("OpacResetPassword"), + OpacPasswordChange => C4::Context->preference("OpacPasswordChange"), ); $template->param( OpacPublic => C4::Context->preference("OpacPublic")); --- a/C4/Members.pm +++ a/C4/Members.pm @@ -42,6 +42,12 @@ use Koha::Borrower::Debarments qw(IsDebarred); use Text::Unaccent qw( unac_string ); use Koha::AuthUtils qw(hash_password); +## Password recovery +use CGI; +use Encode qw(encode decode); +use MIME::QuotedPrint qw(encode_qp); +use Mail::Sendmail; + our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug); BEGIN { @@ -112,7 +118,12 @@ BEGIN { push @EXPORT, qw( &ModMember &changepassword - &ModPrivacy + &ModPrivacy + ); + + # Password recovery + push @EXPORT, qw( + &SendPasswordRecoveryEmail ); #Delete data @@ -2241,6 +2252,82 @@ sub ModPrivacy { privacy => $privacy ); } +=head2 SendPasswordRecoveryEmail + + SendPasswordRecoveryEmail( $borrowernumber, $email ); + +Sends email to user using template file opac-send-password-recovery.tt. +The mail contains a link to the script for password reset, with a unique key stored +in the database for validation + +=cut + +sub SendPasswordRecoveryEmail { + my $borrowernumber = shift; + my $email = shift; + my $dbh = C4::Context->dbh; + my $username = GetMemberDetails($borrowernumber)->{userid}; + + #generate UUID + my @chars = ("A".."Z", "a".."z", "0".."9"); + my $uuid_str; + $uuid_str .= $chars[rand @chars] for 1..32; + + #insert into database + my $sth = $dbh->prepare( 'INSERT INTO borrower_password_recovery VALUES (? ,? , ADDDATE(NOW(), INTERVAL 2 DAY) )' ); + $sth->execute($borrowernumber, $uuid_str); + + my $userEmail = ( $email ) ? $email : GetFirstValidEmailAddress($borrowernumber); + #define to/from emails + my $kohaEmail = C4::Context->preference( 'KohaAdminEmailAddress' ); + + #create link + my $uuidLink = "http://" . C4::Context->preference( 'OPACBaseURL' ) . "/cgi-bin/koha/opac-password-recovery.pl?uniqueKey=$uuid_str"; + #warn $uuidLink; + + #build email content + my $query = new CGI; + my ( $template2, $borrower_number, $cookie ) = C4::Auth::get_template_and_user( + { + template_name => "opac-send-password-recovery.tmpl", + query => $query, + type => "opac", + authnotrequired => 1, + } + ); + $template2->param( + uuidLink => $uuidLink, + username => $username, + ); + + # Getting template result and + my $template_res = $template2->output(); + + #Mail attributes + my %mail = ( + To => $userEmail, + From => $kohaEmail, + 'Content-Type' => 'text/html; charset=utf-8' + ); + + #getting mail properties + if ( $template_res =~ /(.*)/s ) { $mail{'subject'} = decode( 'utf-8', $1 ); } + if ( $template_res =~ /\n(.*)\n/s ) { $mail{'body'} = decode( 'utf-8', $1 ); } + #send mail + if ( sendmail %mail ) + { + # if it works.... + return 1; + } + else + { + # if it doesnt work.... + warn "Error sending mail: $Mail::Sendmail::error \n"; + return 0; + } +} + + =head2 AddMessage AddMessage( $borrowernumber, $message_type, $message, $branchcode ); --- a/installer/data/mysql/kohastructure.sql +++ a/installer/data/mysql/kohastructure.sql @@ -3393,6 +3393,17 @@ CREATE TABLE IF NOT EXISTS marc_modification_template_actions ( CONSTRAINT `mmta_ibfk_1` FOREIGN KEY (`template_id`) REFERENCES `marc_modification_templates` (`template_id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- Table structure for table 'borrower_password_recovery' +-- this stores the unique ID sent by email to the patron, for future validation +-- + +CREATE TABLE IF NOT EXISTS borrower_password_recovery ( + borrowernumber int(11) NOT NULL, + uuid varchar(128) NOT NULL, + valid_until timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + KEY borrowernumber (borrowernumber) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; --- a/installer/data/mysql/sysprefs.sql +++ a/installer/data/mysql/sysprefs.sql @@ -256,6 +256,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('opacreadinghistory','1','','If ON, enables display of Patron Circulation History in OPAC','YesNo'), ('OpacRenewalAllowed','0',NULL,'If ON, users can renew their issues directly from their OPAC account','YesNo'), ('OpacRenewalBranch','checkoutbranch','itemhomebranch|patronhomebranch|checkoutbranch|null','Choose how the branch for an OPAC renewal is recorded in statistics','Choice'), +('OpacResetPassword','1','','Shows the \'Forgot your password?\' link in the OPAC','YesNo'), ('OPACResultsSidebar','','70|10','Define HTML to be included on the search results page, underneath the facets sidebar','Textarea'), ('OPACSearchForTitleIn','
  • Other Libraries (WorldCat)
  • \n
  • Other Databases (Google Scholar)
  • \n
  • Online Stores (Bookfinder.com)
  • \n
  • Open Library (openlibrary.org)
  • ','70|10','Enter the HTML that will appear in the \'Search for this title in\' box on the detail page in the OPAC. Enter {TITLE}, {AUTHOR}, or {ISBN} in place of their respective variables in the URL. Leave blank to disable \'More Searches\' menu.','Textarea'), ('OpacSeparateHoldings','0',NULL,'Separate current branch holdings from other holdings (OPAC)','YesNo'), --- a/installer/data/mysql/updatedatabase.pl +++ a/installer/data/mysql/updatedatabase.pl @@ -7931,6 +7931,21 @@ if(CheckVersion($DBversion)) { } +$DBversion = "3.15.00.XXX"; +if ( CheckVersion($DBversion) ) { + $dbh->do("INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('OpacResetPassword','1','','Shows the ''Forgot your password?'' link in the OPAC','YesNo')"); + $dbh->do(q{ + CREATE TABLE IF NOT EXISTS borrower_password_recovery ( + borrowernumber int(11) NOT NULL, + uuid varchar(128) NOT NULL, + valid_until timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + KEY borrowernumber (borrowernumber) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + }); + print "Upgrade to $DBversion done (Bug 8753: Add forgot password link to OPAC)\n"; + SetVersion ($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref @@ -551,6 +551,13 @@ OPAC: track: "Track" no: "Don't track" - links that patrons click on + - + - pref: OpacResetPassword + default: 1 + choices: + yes: "On" + no: "Off" + - ". If On, the user can reset his password on OPAC." Shelf Browser: - --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc +++ a/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc @@ -278,10 +278,13 @@ [% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]

    Don't have an account? Register here.

    [% END %] + [% IF Koha.Preference('OpacPasswordChange') && Koha.Preference('OpacResetPassword') %] +

    Forgot your password?

    + [% END %] - + --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt +++ a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth.tt @@ -95,6 +95,10 @@ + [% IF Koha.Preference('OpacPasswordChange') && Koha.Preference('OpacResetPassword') %] +

    Forgot your password?

    + [% END %] +
    Don't have a password yet?

    If you don't have a password yet, stop by the circulation desk the next time you're in the library. We'll happily set one up for you.

    --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-main.tt +++ a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-main.tt @@ -78,6 +78,9 @@ [% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]

    Don't have an account? Register here.

    [% END %] + [% IF Koha.Preference('OpacPasswordChange') && Koha.Preference('OpacResetPassword') %] +

    Forgot your password?

    + [% END %]
    [% END # /casAuthentication %] --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-password-recovery.tt +++ a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-password-recovery.tt @@ -0,0 +1,132 @@ +[% USE Koha %] +[% INCLUDE 'doc-head-open.inc' %] +[% IF (LibraryNameTitle) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › +[% INCLUDE 'doc-head-close.inc' %] +[% BLOCK cssinclude %][% END %] +[% BLOCK jsinclude %] + +[% END %] + + + +
    +
    +[% INCLUDE 'masthead.inc' %] +
    +
    +
    +
    +[% IF (!Koha.Preference('OpacResetPassword')) %] +
    You can't reset your password.
    +[% ELSIF (password_recovery) %] + [% IF (hasError) %] + + [% IF (sendmailError) %] + An error has occured while sending you the password recovery link. +
    Please try again later. + [% ELSIF (errNoEmailFound) %] + No account was found with the email address "[% email %]" +
    Check if you typed it correctly. + [% ELSIF (errTooManyEmailFound) %] + More than one account has been found for the email address: "[% email %]" +
    Try yo use your alternative email if you have another. + [% ELSIF (errAlreadyStartRecovery) %] + The process of password recovery has already started for this account ("[% email %]") +
    Check your emails; you should recieve the link to reset your password. +
    If you didn't recieve it, click here to get a new password recovery link + [% END %] +

    Please contact the staff if you need further assistance. +
    + [% END %] +
    +
    + +
    + Password recovery form: +

    To reset your password, enter your email address. +
    A link to reset your password will be sent at this address.

    +
      +
    1. +
    +
    + +
    +
    +
    +
    + +[% ELSIF (new_password) %] + [% IF (errLinkNotValid) %] +
    + We could not authentify you as the account owner. +
    Be sure to use the link you recieved in your email. +
    + [% ELSE %] + [% IF (hasError) %] + + [% IF (errPassNotMatch) %] + The passwords entered does not match. +
    Please try again. + [% ELSIF (errPassTooShort) %] + The password is too short. +
    The password must contain at least [% minPassLength %] characters. + [% END %] +
    + [% END %] +
    +
    + +
    + Password recovery form: +

    The password must contain at least [% minPassLength %] characters.

    +
      +
    1. +
    2. +
    +
    + + + +
    +
    +
    +
    + [% END %] +[% ELSIF (mail_sent) %] +

    A mail has been sent to "[% email %]". +
    It contains a link to create a new password. +
    This link will be valid for 2 days from now.

    +
    Click here to return to the main page. +[% ELSIF (password_reset_done) %] +

    The password has been changed for the user "[% username %]". +
    You can now login using this form.

    +[% END %] +
    +
    +
    +
    +
    +
    + [% INCLUDE 'usermenu.inc' %] +
    +
    +
    +[% INCLUDE 'opac-bottom.inc' %] +
    --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-send-password-recovery.tt +++ a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-send-password-recovery.tt @@ -0,0 +1,19 @@ +[% USE Koha %] +[% INCLUDE 'doc-head-open.inc' %] +[% IF (LibraryNameTitle) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › +[% INCLUDE 'doc-head-close.inc' %] +[% BLOCK cssinclude %][% END %] + +[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha Online[% END %] - Password recovery + + + +

    This email has been sent in response to your password recovery request for the account [% username %].

    +

    +You can now create your new password using the following link: +
    [% uuidLink %] +

    +

    This link will be valid for 2 days from this email's reception, then you must reapply if you do not change your password.

    +

    Thank you.

    + + --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-auth.tt +++ a/koha-tmpl/opac-tmpl/prog/en/modules/opac-auth.tt @@ -85,6 +85,9 @@ please choose against which one you would like to authenticate:

    +[% IF Koha.Preference('OpacPasswordChange') && Koha.Preference('OpacResetPassword') %] +

    Forgot your password?

    +[% END %]
    Don't have a password yet?

    If you don't have a password yet, stop by the circulation desk the next time you're in the library. We'll happily set one up for you.

    Don't have a library card?

    If you don't have a library card, stop by your local library to sign up[% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %] or register here[% END %].

    --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-main.tt +++ a/koha-tmpl/opac-tmpl/prog/en/modules/opac-main.tt @@ -60,7 +60,11 @@ [% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]
    Don't have an account? Register here.
    [% END %] - + + [% IF Koha.Preference('OpacPasswordChange') && Koha.Preference('OpacResetPassword') %] +

    Forgot your password?

    + [% END %] +
    [% END %] --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-password-recovery.tt +++ a/koha-tmpl/opac-tmpl/prog/en/modules/opac-password-recovery.tt @@ -0,0 +1,130 @@ +[% USE Koha %] +[% INCLUDE 'doc-head-open.inc' %] +[% IF (LibraryNameTitle) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › +[% INCLUDE 'doc-head-close.inc' %] + + + + + +
    +
    +[% INCLUDE 'masthead.inc' %] +
    +
    +
    +
    +[% IF (!Koha.Preference('OpacResetPassword')) %] +
    You can't reset your password.
    +[% ELSIF (password_recovery) %] + [% IF (hasError) %] + + [% IF (sendmailError) %] + An error has occured while sending you the password recovery link. +
    Please try again later. + [% ELSIF (errNoEmailFound) %] + No account was found with the email address "[% email %]" +
    Check if you typed it correctly. + [% ELSIF (errTooManyEmailFound) %] + More than one account has been found for the email address: "[% email %]" +
    Try yo use your alternative email if you have another. + [% ELSIF (errAlreadyStartRecovery) %] + The process of password recovery has already started for this account ("[% email %]") +
    Check your emails; you should recieve the link to reset your password. +
    If you didn't recieve it, click here to get a new password recovery link + [% END %] +

    Please contact the staff if you need further assistance. +
    + [% END %] +
    +
    + +
    + Password recovery form: +

    To reset your password, enter your email address. +
    A link to reset your password will be sent at this address.

    +
      +
    1. +
    +
    + +
    +
    +
    +
    + +[% ELSIF (new_password) %] + [% IF (errLinkNotValid) %] +
    + We could not authentify you as the account owner. +
    Be sure to use the link you recieved in your email. +
    + [% ELSE %] + [% IF (hasError) %] + + [% IF (errPassNotMatch) %] + The passwords entered does not match. +
    Please try again. + [% ELSIF (errPassTooShort) %] + The password is too short. +
    The password must contain at least [% minPassLength %] characters. + [% END %] +
    + [% END %] +
    +
    + +
    + Password recovery form: +

    The password must contain at least [% minPassLength %] characters.

    +
      +
    1. +
    2. +
    +
    + + + +
    +
    +
    +
    + [% END %] +[% ELSIF (mail_sent) %] +

    A mail has been sent to "[% email %]". +
    It contains a link to create a new password. +
    This link will be valid for 2 days from now.

    +
    Click here to return to the main page. +[% ELSIF (password_reset_done) %] +

    The password has been changed for the user "[% username %]". +
    You can now login using this form.

    +[% END %] +
    +
    +
    +
    +
    +
    + [% INCLUDE 'usermenu.inc' %] +
    +
    +
    +[% INCLUDE 'opac-bottom.inc' %] +
    --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-send-password-recovery.tt +++ a/koha-tmpl/opac-tmpl/prog/en/modules/opac-send-password-recovery.tt @@ -0,0 +1,17 @@ +[% USE Koha %] +[% INCLUDE 'doc-head-open.inc' %] +[% IF (LibraryNameTitle) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › +[% INCLUDE 'doc-head-close.inc' %] +[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha Online[% END %] - Password recovery + + + +

    This email has been sent in response to your password recovery request for the account [% username %].

    +

    +You can now create your new password using the following link: +
    [% uuidLink %] +

    +

    This link will be valid for 2 days from this email's reception, then you must reapply if you do not change your password.

    +

    Thank you.

    + + --- a/opac/opac-main.pl +++ a/opac/opac-main.pl @@ -58,6 +58,7 @@ $template->param( koha_news_count => $koha_news_count, display_daily_quote => C4::Context->preference('QuoteOfTheDay'), daily_quote => $quote, + OpacResetPassword => C4::Context->preference('OpacResetPassword'), ); # If GoogleIndicTransliteration system preference is On Set paramter to load Google's javascript in OPAC search screens --- a/opac/opac-password-recovery.pl +++ a/opac/opac-password-recovery.pl @@ -0,0 +1,205 @@ +#!/usr/bin/perl + +use strict; +use Modern::Perl; + +use CGI; +use Mail::Sendmail; +use Digest::MD5 qw(md5_base64); +use HTML::Entities; + +use C4::Auth; +use C4::Koha; +use C4::Members qw(changepassword GetMember GetMemberDetails SendPasswordRecoveryEmail); +use C4::Output; +use C4::Context; + +my $query = new CGI; + +my ( $template, $borrowernumber, $cookie ) = get_template_and_user( + { + template_name => "opac-password-recovery.tmpl", + query => $query, + type => "opac", + authnotrequired => 1, + debug => 1, + } +); + +my $email = $query->param('email'); +my $password = $query->param('password'); +my $repeatPassword = $query->param('repeatPassword'); +my $minPassLength = C4::Context->preference('minPasswordLength'); +my $id = $query->param('id'); +my $uniqueKey = $query->param('uniqueKey'); +my $username = $query->param('username'); +my $borrower_number; + +#errors +my $hasError; + +#email form error +my $errNoEmailFound; +my $errAlreadyStartRecovery; + +#new password form error +my $errLinkNotValid; +my $errPassNotMatch; +my $errPassTooShort; + +my $dbh = C4::Context->dbh; + +$template->param( OpacResetPassword => C4::Context->preference("OpacResetPassword") ); + +if ( $query->param('sendEmail') || $query->param('resendEmail') ) { + #send mail + confirmation + + #try with the main email + my $borrower_number; + my %borrower_infos = GetMember( email => $email ); + if (%borrower_infos) { + $borrower_number = GetMember( email => $email )->{'borrowernumber'}; + $username = GetMemberDetails($borrower_number)->{'userid'}; + } + else { + #try with the secondary email + %borrower_infos = GetMember( emailpro => $email ); + if (%borrower_infos) { + $borrower_number = GetMember( emailpro => $email )->{'borrowernumber'}; + $username = GetMemberDetails($borrower_number)->{'userid'}; + } + else { + #try when the other contact email + %borrower_infos = GetMember( B_email => $email ); + if (%borrower_infos) { + $borrower_number = GetMember( B_email => $email )->{'borrowernumber'}; + $username = GetMemberDetails($borrower_number)->{'userid'}; + } + } + } + + if ( !$email || !$username || !$borrower_number ) { + $hasError = 1; + $errNoEmailFound = 1; + } + elsif ( !$query->param('resendEmail') ) { + my $sth = $dbh->prepare( +"SELECT borrowernumber FROM borrower_password_recovery WHERE NOW() < valid_until AND borrowernumber = ?" + ); + $sth->execute($borrower_number); + if ( my $already = $sth->fetchrow ) { + $hasError = 1; + $errAlreadyStartRecovery = 1; + } + } + + if ($hasError) { + $template->param( + hasError => 1, + errNoEmailFound => $errNoEmailFound, + errAlreadyStartRecovery => $errAlreadyStartRecovery, + password_recovery => 1, + email => HTML::Entities::encode($email), + ); + } + else { + #generate uuid and send recovery email + if ( SendPasswordRecoveryEmail( $borrower_number, $email ) ) { + # if it works.... + $template->param( + mail_sent => 1, + email => $email + ); + } + else { + # if it doesnt work.... + $template->param( + password_recovery => 1, + sendmailError => 1 + ); + } + } +} +elsif ( $query->param('passwordReset') ) { + #new password form + #check if the link is still valid + my $sth = $dbh->prepare( + "SELECT borrower_password_recovery.borrowernumber, userid + FROM borrower_password_recovery, borrowers + WHERE borrowers.borrowernumber = borrower_password_recovery.borrowernumber + AND NOW() < valid_until + AND uuid = ?" + ); + $sth->execute($uniqueKey); + ( $borrower_number, $username ) = $sth->fetchrow; + + #validate password length & match + if ( ($borrower_number) + && ( $password eq $repeatPassword ) + && ( length($password) >= $minPassLength ) ) + { #apply changes + changepassword( $username, $borrower_number, md5_base64($password) ); + + #remove entry + my $sth = $dbh->prepare( + "DELETE FROM borrower_password_recovery + WHERE uuid = ? + ORDER BY valid_until DESC LIMIT 1" + ); + $sth->execute($uniqueKey); + + $template->param( + password_reset_done => 1, + username => $username + ); + } + else { #errors + if ( !$borrower_number ) { #parameters not valid + $errLinkNotValid = 1; + } + elsif ( $password ne $repeatPassword ) { #passwords does not match + $errPassNotMatch = 1; + } + elsif ( length($password) < $minPassLength ) { #password too short + $errPassTooShort = 1; + } + $template->param( + new_password => 1, + minPassLength => $minPassLength, + email => $email, + uniqueKey => $uniqueKey, + errLinkNotValid => $errLinkNotValid, + errPassNotMatch => $errPassNotMatch, + errPassTooShort => $errPassTooShort, + hasError => 1 + ); + } +} +elsif ($uniqueKey) { #reset password form + #check if the link is valid + my $sth = $dbh->prepare( + "SELECT borrower_password_recovery.borrowernumber, userid + FROM borrower_password_recovery, borrowers + WHERE borrowers.borrowernumber = borrower_password_recovery.borrowernumber + AND NOW() < valid_until + AND uuid = ?" + ); + $sth->execute($uniqueKey); + ( $borrower_number, $username ) = $sth->fetchrow; + if ( !$borrower_number ) { + $errLinkNotValid = 1; + } + $template->param( + new_password => 1, + minPassLength => $minPassLength, + email => $email, + uniqueKey => $uniqueKey, + username => $username, + errLinkNotValid => $errLinkNotValid + ); +} +else { #password recovery form (to send email) + $template->param( password_recovery => 1 ); +} + +output_html_with_http_headers $query, $cookie, $template->output; --