Subversion Repositories oidplus

Rev

Rev 279 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * OIDplus 2.0
  5.  * Copyright 2019 Daniel Marschall, ViaThinkSoft
  6.  *
  7.  * Licensed under the Apache License, Version 2.0 (the "License");
  8.  * you may not use this file except in compliance with the License.
  9.  * You may obtain a copy of the License at
  10.  *
  11.  *     http://www.apache.org/licenses/LICENSE-2.0
  12.  *
  13.  * Unless required by applicable law or agreed to in writing, software
  14.  * distributed under the License is distributed on an "AS IS" BASIS,
  15.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16.  * See the License for the specific language governing permissions and
  17.  * limitations under the License.
  18.  */
  19.  
  20. class OIDplusPagePublicForgotPassword extends OIDplusPagePluginPublic {
  21.  
  22.         public function action(&$handled) {
  23.                 if (isset($_POST["action"]) && ($_POST["action"] == "forgot_password")) {
  24.                         $handled = true;
  25.  
  26.                         $email = $_POST['email'];
  27.  
  28.                         if (!OIDplus::mailUtils()->validMailAddress($email)) {
  29.                                 throw new OIDplusException('Invalid email address');
  30.                         }
  31.  
  32.                         if (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false)) {
  33.                                 $secret=OIDplus::baseConfig()->getValue('RECAPTCHA_PRIVATE', '');
  34.                                 $response=$_POST["captcha"];
  35.                                 $verify=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$response}");
  36.                                 $captcha_success=json_decode($verify);
  37.                                 if ($captcha_success->success==false) {
  38.                                         throw new OIDplusException('Captcha wrong');
  39.                                 }
  40.                         }
  41.  
  42.                         OIDplus::logger()->log("RA($email)!", "A new password for '$email' was requested (forgot password)");
  43.  
  44.                         $timestamp = time();
  45.                         $activate_url = OIDplus::getSystemUrl() . '?goto='.urlencode('oidplus:reset_password$'.$email.'$'.$timestamp.'$'.OIDplus::authUtils()::makeAuthKey('reset_password;'.$email.';'.$timestamp));
  46.  
  47.                         $message = $this->getForgotPasswordText($_POST['email']);
  48.                         $message = str_replace('{{ACTIVATE_URL}}', $activate_url, $message);
  49.  
  50.                         OIDplus::mailUtils()->sendMail($email, OIDplus::config()->getValue('system_title').' - Password reset request', $message, OIDplus::config()->getValue('global_cc'));
  51.  
  52.                         echo json_encode(array("status" => 0));
  53.                 }
  54.  
  55.                 if (isset($_POST["action"]) && ($_POST["action"] == "reset_password")) {
  56.                         $handled = true;
  57.  
  58.                         $password1 = $_POST['password1'];
  59.                         $password2 = $_POST['password2'];
  60.                         $email = $_POST['email'];
  61.                         $auth = $_POST['auth'];
  62.                         $timestamp = $_POST['timestamp'];
  63.  
  64.                         if (!OIDplus::authUtils()::validateAuthKey('reset_password;'.$email.';'.$timestamp, $auth)) {
  65.                                 throw new OIDplusException('Invalid auth key');
  66.                         }
  67.  
  68.                         if ((OIDplus::config()->getValue('max_ra_pwd_reset_time') > 0) && (time()-$timestamp > OIDplus::config()->getValue('max_ra_pwd_reset_time'))) {
  69.                                 throw new OIDplusException('Invitation expired!');
  70.                         }
  71.  
  72.                         if ($password1 !== $password2) {
  73.                                 throw new OIDplusException('Passwords are not equal');
  74.                         }
  75.  
  76.                         if (strlen($password1) < OIDplus::config()->getValue('ra_min_password_length')) {
  77.                                 throw new OIDplusException('Password is too short. Minimum password length: '.OIDplus::config()->getValue('ra_min_password_length'));
  78.                         }
  79.  
  80.                         OIDplus::logger()->log("RA($email)!", "RA '$email' has reset his password (forgot passwort)");
  81.  
  82.                         $ra = new OIDplusRA($email);
  83.                         $ra->change_password($password1);
  84.  
  85.                         echo json_encode(array("status" => 0));
  86.                 }
  87.         }
  88.  
  89.         public function init($html=true) {
  90.                 OIDplus::config()->prepareConfigKey('max_ra_pwd_reset_time', 'Max RA password reset time in seconds (0 = infinite)', '0', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
  91.                         if (!is_numeric($value) || ($value < 0)) {
  92.                                 throw new OIDplusException("Please enter a valid value.");
  93.                         }
  94.                 });
  95.         }
  96.  
  97.         public function gui($id, &$out, &$handled) {
  98.                 if (explode('$',$id)[0] == 'oidplus:forgot_password') {
  99.                         $handled = true;
  100.  
  101.                         $out['title'] = 'Forgot password';
  102.                         $out['icon'] = OIDplus::webpath(__DIR__).'forgot_password_big.png';
  103.  
  104.                         try {
  105.                                 $out['text'] .= '<p>Please enter the email address of your account, and information about the password reset will be sent to you.</p>
  106.                                   <form id="forgotPasswordForm" onsubmit="return forgotPasswordFormOnSubmit();">
  107.                                     E-Mail: <input type="text" id="email" value=""/><br><br>'.
  108.                                  (OIDplus::baseConfig()->getValue('RECAPTCHA_ENABLED', false) ?
  109.                                  '<script> grecaptcha.render(document.getElementById("g-recaptcha"), { "sitekey" : "'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'" }); </script>'.
  110.                                  '<div id="g-recaptcha" class="g-recaptcha" data-sitekey="'.OIDplus::baseConfig()->getValue('RECAPTCHA_PUBLIC', '').'"></div>' : '').
  111.                                 ' <br>
  112.                                     <input type="submit" value="Send recovery information">
  113.                                   </form>';
  114.  
  115.                         } catch (Exception $e) {
  116.  
  117.                                 $out['icon'] = 'img/error_big.png';
  118.                                 $out['text'] = '<p>Error: '.htmlentities($e->getMessage()).'</p>';
  119.  
  120.                         }
  121.                 } else if (explode('$',$id)[0] == 'oidplus:reset_password') {
  122.                         $handled = true;
  123.  
  124.                         $email = explode('$',$id)[1];
  125.                         $timestamp = explode('$',$id)[2];
  126.                         $auth = explode('$',$id)[3];
  127.  
  128.                         $out['title'] = 'Reset password';
  129.                         $out['icon'] = OIDplus::webpath(__DIR__).'reset_password_big.png';
  130.  
  131.                         if (!OIDplus::authUtils()::validateAuthKey('reset_password;'.$email.';'.$timestamp, $auth)) {
  132.                                 $out['icon'] = 'img/error_big.png';
  133.                                 $out['text'] = 'Invalid authorization. Is the URL OK?';
  134.                         } else {
  135.                                 $out['text'] = '<p>E-Mail-Adress: <b>'.$email.'</b></p>
  136.  
  137.                                   <form id="resetPasswordForm" onsubmit="return resetPasswordFormOnSubmit();">
  138.                                     <input type="hidden" id="email" value="'.htmlentities($email).'"/>
  139.                                     <input type="hidden" id="timestamp" value="'.htmlentities($timestamp).'"/>
  140.                                     <input type="hidden" id="auth" value="'.htmlentities($auth).'"/>
  141.                                     <div><label class="padding_label">New password:</label><input type="password" id="password1" value=""/></div>
  142.                                     <div><label class="padding_label">Repeat:</label><input type="password" id="password2" value=""/></div>
  143.                                     <br><input type="submit" value="Change password">
  144.                                   </form>';
  145.                         }
  146.                 }
  147.         }
  148.  
  149.         public function publicSitemap(&$out) {
  150.                 $out[] = OIDplus::getSystemUrl().'?goto=oidplus:forgot_password';
  151.         }
  152.  
  153.         public function tree(&$json, $ra_email=null, $nonjs=false, $req_goto='') {
  154.                 return false;
  155.         }
  156.  
  157.         private function getForgotPasswordText($email) {
  158.                 $res = OIDplus::db()->query("select * from ###ra where email = ?", array($email));
  159.                 if ($res->num_rows() == 0) {
  160.                         throw new OIDplusException("This RA does not exist.");
  161.                 }
  162.  
  163.                 $message = file_get_contents(__DIR__ . '/forgot_password.tpl');
  164.  
  165.                 // Resolve stuff
  166.                 $message = str_replace('{{SYSTEM_URL}}', OIDplus::getSystemUrl(), $message);
  167.                 $message = str_replace('{{ADMIN_EMAIL}}', OIDplus::config()->getValue('admin_email'), $message);
  168.  
  169.                 // {{ACTIVATE_URL}} will be resolved in ajax.php
  170.  
  171.                 return $message;
  172.         }
  173.  
  174.         public function tree_search($request) {
  175.                 return false;
  176.         }
  177. }
  178.