diff --git a/actions/login.php b/actions/login.php index 3919b4f7e7..83fa3ed23c 100644 --- a/actions/login.php +++ b/actions/login.php @@ -75,6 +75,10 @@ class LoginAction extends Action { 'not for shared computers!')); common_submit('submit', _t('Login')); common_element_end('form'); + common_element_start('p'); + common_element('a', array('href' => common_local_url('recoverpassword')), + _t('Lost or forgotten password?')); + common_element_end('p'); common_show_footer(); } diff --git a/actions/recoverpassword.php b/actions/recoverpassword.php new file mode 100644 index 0000000000..66267e558a --- /dev/null +++ b/actions/recoverpassword.php @@ -0,0 +1,236 @@ +. + */ + +if (!defined('LACONICA')) { exit(1); } + +class RecoverpasswordAction extends Action { + + function handle($args) { + parent::handle($args); + if (common_logged_in()) { + $this->client_error(_t('You are already logged in!')); + return; + } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { + if ($this->arg('recover')) { + $this->recover_password(); + } else if ($this->arg('reset')) { + $this->reset_password(); + } else { + $this->client_error(_t('Unexpected form.')); + } + } else { + if ($this->trimmed('code')) { + $this->check_code(); + } else { + $this->show_form(); + } + } + } + + function check_code() { + $code = $this->trimmed('code'); + $confirm = Confirm_address::staticGet($code); + if ($confirm && $confirm->type == 'recover') { + $user = User::staticGet($confirm->user_id); + if ($user) { + $result = $confirm->delete(); + if (!$result) { + common_log_db_error($confirm, 'DELETE', __FILE__); + common_server_error(_t('Error with confirmation code.')); + return; + } + $this->set_temp_user($user); + $this->show_password_form(); + } + } + } + + function set_temp_user(&$user) { + common_ensure_session(); + $_SESSION['tempuser'] = $user->id; + } + + function get_temp_user() { + common_ensure_session(); + $user_id = $_SESSION['tempuser']; + if ($user_id) { + $user = User::staticGet($user_id); + } + return $user; + } + + function clear_temp_user() { + common_ensure_session(); + unset($_SESSION['tempuser']); + } + + function show_top($msg=NULL) { + if ($msg) { + $this->message($msg, $success); + } else { + common_element('div', 'instructions', + _t('If you\'ve forgotten or lost your' . + ' password, you can get a new one sent ' . + ' the email address you have stored ' . + ' in your account.')); + } + } + + function show_password_top($msg=NULL) { + if ($msg) { + $this->message($msg, $success); + } else { + common_element('div', 'instructions', + _t('You\ve been identified . Enter a ' . + ' new password below. ')); + } + } + + function show_form($msg=NULL) { + + common_show_header(_t('Recover password'), NULL, + $msg, array($this, 'show_top')); + + common_element_start('form', array('method' => 'POST', + 'id' => 'recoverpassword', + 'action' => common_local_url('recoverpassword'))); + common_input('nicknameoremail', _t('Nickname or email'), + $this->trimmed('nicknameoremail'), + _t('Your nickname on this server, ' . + 'or your registered email address.')); + common_submit('recover', _t('Recover')); + common_element_end('form'); + common_show_footer(); + } + + function show_password_form($msg=NULL) { + + common_show_header(_t('Reset password'), NULL, + $msg, array($this, 'show_password_top')); + + common_element_start('form', array('method' => 'POST', + 'id' => 'recoverpassword', + 'action' => common_local_url('recoverpassword'))); + common_password('newpassword', _t('New password'), + _t('6 or more characters, and don\'t forget it!')); + common_password('confirm', _t('Confirm'), + _t('Same as password above')); + common_submit('reset', _t('Reset')); + common_element_end('form'); + common_show_footer(); + } + + function recover_password() { + $nore = $this->trimmed('nicknameoremail'); + if (!$nore) { + $this->show_form(_t('Enter a nickname or email address.')); + return; + } + $user = User::staticGet('email', common_canonical_email($nore)); + if (!$user) { + $user = User::staticGet('nickname', common_canonical_nickname($nore)); + } + + if (!$user) { + $this->show_form(_t('No such user.')); + return; + } + if (!$user->email) { + $this->client_error(_t('No registered email address for that user.')); + return; + } + + $confirm = new Confirm_address(); + $confirm->code = common_confirmation_code(128); + $confirm->type = 'recover'; + $confirm->user_id = $user->id; + $confirm->address = $user->email; + + if (!$confirm->insert()) { + common_log_db_error($confirm, 'INSERT', __FILE__); + $this->server_error(_t('Error saving address confirmation.')); + return; + } + + $body = "Hey, $user->nickname."; + $body .= "\n\n"; + $body .= 'Someone just asked for a new password ' . + 'for this account on ' . common_config('site', 'name') . '.'; + $body .= "\n\n"; + $body .= 'If it was you, and you want to confirm, use the URL below:'; + $body .= "\n\n"; + $body .= "\t".common_local_url('confirmaddress', + array('code' => $code)); + $body .= "\n\n"; + $body .= 'If not, just ignore this message.'; + $body .= "\n\n"; + $body .= 'Thanks for your time, '; + $body .= "\n"; + $body .= common_config('site', 'name'); + $body .= "\n"; + + return mail_to_user($user, _t('Password recovery requested'), $body); + } + + function reset_password() { + + $user = $this->get_temp_user(); + + if (!$user) { + $this->client_error(_t('Unexpected password reset.')); + return; + } + $password = $this->trimmed('password'); + $confirm = $this->trimmed('confirm'); + if (!$password || strlen($password) < 6) { + $this->show_password_form(_t('Password must be 6 chars or more.')); + return; + } + if ($password != $confirm) { + $this->show_password_form(_t('Password and confirmation do not match.')); + return; + } + + # OK, we're ready to go + + $original = clone($user); + + $user->password = common_munge_password($newpassword, $user->id); + + if (!$user->update($original)) { + common_log_db_error($user, 'UPDATE', __FILE__); + common_server_error(_t('Can\'t save new password.')); + return; + } + + $this->clear_temp_user(); + + if (!common_set_user($user->nickname)) { + common_server_error(_t('Error setting user.')); + return; + } + + common_real_login(true); + + common_show_header(_('Password saved.')); + common_element('p', NULL, _t('New password successfully saved. ' . + 'You are now logged in.')); + common_show_footer(); + } +} diff --git a/lib/mail.php b/lib/mail.php index 91eafa97ee..ef33b2127b 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -42,8 +42,10 @@ function mail_send($recipients, $headers, $body) { assert($backend); # throws an error if it's bad $sent = $backend->send($recipients, $headers, $body); if (PEAR::isError($sent)) { - common_server_error($sent->getMessage(), 500); + common_log(LOG_ERROR, 'Email error: ' . $sent->getMessage()); + return false; } + return true; } function mail_notify_from() { @@ -55,7 +57,23 @@ function mail_notify_from() { } } +function mail_to_user(&$user, $subject, $body, $address=NULL) { + if (!$address) { + $address = $user->email; + } + + $recipients = $address; + $profile = $user->getProfile(); + + $headers['From'] = mail_notify_from(); + $headers['To'] = $profile->getBestName() . ' <' . $address . '>'; + $headers['Subject'] = $subject; + + return mail_send($recipients, $headers, $body); +} + # For confirming a Jabber address +# XXX: change to use mail_to_user() above function mail_confirm_address($code, $nickname, $address) { $recipients = $address;