![]() |
Xataface 2.0
Xataface Application Framework
|
00001 <?php 00002 class dataface_actions_forgot_password { 00003 public static $TABLE_RESET_PASSWORD = 'dataface__reset_password'; 00004 public static $EX_MULTIPLE_USERS_WITH_SAME_EMAIL = 500; 00005 public static $EX_NO_USERS_WITH_EMAIL = 501; 00006 public static $EX_NO_EMAIL_COLUMN_FOUND = 502; 00007 public static $EX_NO_USERNAME_COLUMN_FOUND = 504; 00008 public static $EX_NO_USERNAME_FOR_USER = 503; 00009 public static $EX_NO_SUCH_UUID = 505; 00010 public static $EX_USER_NOT_FOUND = 506; 00011 public static $EX_NO_EMAIL_FOR_USER = 507; 00012 public static $EX_NO_USERS_FOUND_WITH_USERNAME = 508; 00013 public static $EX_MULTIPLE_USERS_WITH_SAME_USERNAME = 509; 00014 00015 function handle($params){ 00016 00017 00018 $app = Dataface_Application::getInstance(); 00019 $query =& $app->getQuery(); 00020 $jt = Dataface_JavascriptTool::getInstance(); 00021 $jt->import('forgot_password.js'); 00022 00023 try { 00024 if ( isset($query['--uuid']) ){ 00025 // A uuid was supplied, 00026 $res = $this->reset_password_with_uuid($query['--uuid']); 00027 if ( $res ){ 00028 df_display(array(), 'xataface/forgot_password/password_has_been_reset.html'); 00029 exit; 00030 } else { 00031 throw new Exception("Failed to reset password for uuid ".$query['--uuid']); 00032 } 00033 00034 } else if ( isset($query['--email']) ){ 00035 00036 $this->send_reset_email_for_email($query['--email']); 00037 if ( @$query['--format'] == 'json' ){ 00038 $this->response(array( 00039 'code'=>200, 00040 'message'=>'An email has been sent to the provided email address with instructions for resetting your password.' 00041 )); 00042 exit; 00043 } else { 00044 df_display(array(), 'xataface/forgot_password/sent_email.html'); 00045 exit; 00046 } 00047 00048 00049 } else if ( isset($query['--username']) ){ 00050 00051 $this->send_reset_email_for_username($query['--username']); 00052 if ( @$query['--format'] == 'json' ){ 00053 $this->response(array( 00054 'code'=>200, 00055 'message'=> 'An email has been sent to the email on file for this user account with instructions for resetting the password.' 00056 )); 00057 exit; 00058 } else { 00059 df_display(array(), 'xataface/forgot_password/sent_email.html'); 00060 exit; 00061 } 00062 00063 00064 } else { 00065 00066 00067 df_display(array(), 'xataface/forgot_password/form.html'); 00068 exit; 00069 } 00070 } catch ( Exception $ex ){ 00071 00072 if ( @$query['--format'] == 'json' ){ 00073 $this->response(array( 00074 'code'=>$ex->getCode(), 00075 'message'=>$ex->getMessage() 00076 )); 00077 exit; 00078 } else { 00079 df_display(array('error'=>$ex->getMessage()), 'xataface/forgot_password/form.html'); 00080 } 00081 00082 } 00083 00084 00085 00086 } 00087 00088 00089 function response($p){ 00090 header('Content-type: text/json; charset="'.Dataface_Application::getInstance()->_conf['oe'].'"'); 00091 echo json_encode($p); 00092 00093 } 00094 00098 function create_reset_password_table(){ 00099 $table = self::$TABLE_RESET_PASSWORD; 00100 $res = mysql_query("create table if not exists `{$table}` ( 00101 request_id int(11) auto_increment primary key, 00102 request_uuid binary(32), 00103 username varchar(255), 00104 request_ip int(11), 00105 date_created datetime, 00106 expires int(11), 00107 key (request_uuid) )", df_db()); 00108 if ( !$res ) throw new Exception(mysql_error(df_db())); 00109 00110 } 00111 00112 00116 function clear_expired(){ 00117 $table = self::$TABLE_RESET_PASSWORD; 00118 $res = mysql_query("delete from `{$table}` where expires < ".time(), df_db()); 00119 if ( !$res ) throw new Exception(mysql_error(df_db())); 00120 00121 00122 00123 } 00124 00125 00126 function send_reset_email_for_username($username){ 00127 $auth = Dataface_AuthenticationTool::getInstance(); 00128 $usernameCol = $auth->usernameColumn; 00129 if ( !$usernameCol ) throw new Exception("No username Column found in the users table. Please specify one using the username_column directive in the [_auth] section of the conf.ini file.", self::$EX_NO_EMAIL_COLUMN_FOUND); 00130 00131 $people = df_get_records_array($auth->usersTable, array($usernameCol => '='.$username)); 00132 if ( !$people ) throw new Exception("No account found with that username", self::$EX_NO_USERS_FOUND_WITH_USERNAME); 00133 if ( count($people) > 1 ){ 00134 throw new Exception("Multiple users found with same username", self::$EX_MULTIPLE_USERS_WITH_SAME_USERNAME); 00135 00136 } else { 00137 00138 $this->send_reset_email_for_user($people[0]); 00139 00140 } 00141 00142 } 00143 00144 00145 00146 00158 function send_reset_email_for_email($email){ 00159 $auth = Dataface_AuthenticationTool::getInstance(); 00160 $emailCol = $auth->getEmailColumn(); 00161 if ( !$emailCol ) throw new Exception("No Email Column found in the users table. Please specify one using the email_column directive in the [_auth] section of the conf.ini file.", self::$EX_NO_EMAIL_COLUMN_FOUND); 00162 00163 $people = df_get_records_array($auth->usersTable, array($emailCol => '='.$email)); 00164 if ( !$people ) throw new Exception("No account found with that email address", self::$EX_NO_USERS_WITH_EMAIL); 00165 if ( count($people) > 1 ){ 00166 throw new Exception("Multiple users found with same email address", self::$EX_MULTIPLE_USERS_WITH_SAME_EMAIL); 00167 00168 } else { 00169 $this->send_reset_email_for_user($people[0]); 00170 00171 } 00172 00173 00174 } 00175 00186 public function send_reset_email_for_user(Dataface_Record $user){ 00187 $app = Dataface_Application::getInstance(); 00188 $auth = Dataface_AuthenticationTool::getInstance(); 00189 $emailCol = $auth->getEmailColumn(); 00190 $usernameCol = $auth->usernameColumn; 00191 00192 if ( !$emailCol ) throw new Exception("No Email Column found in the users table. Please specify one using the email_column directive in the [_auth] section of the conf.ini file.", self::$EX_NO_EMAIL_COLUMN_FOUND); 00193 if ( !$usernameCol ) throw new Exception("No username column found in the users table. Please specify one using the username_column directive in the [_auth] section of the conf.ini file.", self::$EX_NO_USERNAME_COLUMN_FOUND); 00194 if ( !$user ) throw new Exception("Cannot send email for null user", self::$EX_NO_USERS_FOUND_WITH_EMAIL); 00195 00196 00197 $username = $user->val($usernameCol); 00198 if ( !$username ){ 00199 throw new Exception("Cannot reset password for user without a username", self::$EX_NO_USERNAME_FOR_USER); 00200 } 00201 00202 $email = $user->val($emailCol); 00203 if ( !$email ) throw new Exception("User has not email address on file", $EX_NO_EMAIL_FOR_USER); 00204 00205 00206 $ip = null; 00207 $val = ip2long($_SERVER['REMOTE_ADDR']); 00208 if ( $val !== false ){ 00209 $ip = sprintf('%u', $val ); 00210 } 00211 00212 // Insert the entry 00213 $this->create_reset_password_table(); 00214 $table = self::$TABLE_RESET_PASSWORD; 00215 $sql = "insert into `{$table}` 00216 (`request_uuid`, `username`, `request_ip`, `date_created`, `expires`) 00217 values 00218 (UUID(),'".addslashes($username)."','".addslashes($ip)."', NOW(), ".(time()+600).")"; 00219 $res = mysql_query($sql, df_db()); 00220 if ( !$res ) throw new Exception(mysql_error(df_db())); 00221 $id = mysql_insert_id(df_db()); 00222 00223 $res = mysql_query("select * from `{$table}` where request_id='".addslashes($id)."'", df_db()); 00224 if ( !$res ) throw new Exception(mysql_error(df_db())); 00225 00226 $row = mysql_fetch_assoc($res); 00227 if ( !$row ) throw new Exception("Failed to fetch reset password request row from database after it has been inserted. This should never happen ... must be a bug"); 00228 00229 $uuid = $row['request_uuid']; 00230 if ( !$uuid ) throw new Exception("Blank uuid for the reset request. This should never happen. Must be a bug."); 00231 00232 $url = df_absolute_url(DATAFACE_SITE_HREF.'?-action=forgot_password&--uuid='.$uuid); 00233 $site_url = df_absolute_url(DATAFACE_SITE_URL); 00234 00235 $msg = <<<END 00236 You have requested to reset the password for the user '$username'. 00237 Please go to the URL below in order to proceed with resetting your password: 00238 <$url> 00239 00240 If you did not make this request, please disregard this email. 00241 END; 00242 00243 $subject = 'Password Reset'; 00244 00245 00246 $del = $app->getDelegate(); 00247 $info = array(); 00248 if ( isset($del) and method_exists($del, 'getResetPasswordEmailInfo') ){ 00249 $info = $del->getResetPasswordEmailInfo($user, $url); 00250 } 00251 00252 if ( isset($info['subject']) ) $subject = $info['subject']; 00253 if ( isset($info['message']) ) $msg = $info['message']; 00254 $parameters = null; 00255 if ( isset($info['parameters']) ) $parameters = $info['parameters']; 00256 00257 00258 00259 $site_title = $app->getSiteTitle(); 00260 $support_email = $_SERVER['SERVER_ADMIN']; 00261 if ( isset($app->_conf['admin_email']) ) $support_email = $app->_conf['admin_email']; 00262 if ( isset($app->_conf['support_email']) ) $support_email = $app->_conf['support_email']; 00263 00264 00265 $headers = 'From: '.$site_title.' <'.$support_email.'>'."\r\nReply-to: ".$site_title." <".$support_email.">"; 00266 if ( isset($info['headers']) ) $headers = $info['headers']; 00267 //echo "Subject: $subject \nEmail: $email \n$msg \nHeaders: $headers";exit; 00268 if ( @$app->_conf['_mail']['func'] ) $func = $app->_conf['_mail']['func']; 00269 else $func = 'mail'; 00270 $res = $func($email, 00271 $subject, 00272 $msg, 00273 $headers, 00274 $parameters); 00275 if ( !$res ){ 00276 throw new Exception('Failed to send activation email. Please try again later.', DATAFACE_E_ERROR); 00277 } else { 00278 //echo "Successfully sent mail to $email";exit; 00279 return true; 00280 } 00281 00282 00283 00284 } 00285 00286 00287 00288 public function reset_password_with_uuid($uuid){ 00289 $auth = Dataface_AuthenticationTool::getInstance(); 00290 $app = Dataface_Application::getInstance(); 00291 00292 $this->create_reset_password_table(); 00293 $this->clear_expired(); 00294 $table = self::$TABLE_RESET_PASSWORD; 00295 $res = mysql_query("select * from `{$table}` where request_uuid='".addslashes($uuid)."' limit 1", df_db()); 00296 if ( !$res ) throw new Exception(mysql_error(df_db())); 00297 $row = mysql_fetch_assoc($res); 00298 if ( !$row ) throw new Exception("No such reset request could be found", self::$EX_NO_SUCH_UUID); 00299 00300 if ( !$row['username'] ){ 00301 throw new Exception("Attempt to reset password for user with null username", self::$EX_NO_USERNAME_FOR_USER); 00302 00303 } 00304 $username = $row['username']; 00305 00306 00307 00308 00309 @mysql_free_result($res); 00310 00311 00312 00313 // now that we have the username, let's reset the password. 00314 //$rand = strval(rand())."".$uuid; 00315 $rand = md5($uuid); 00316 error_log("Rand is ".$rand); 00317 $pw = ''; 00318 for ( $i=0; $i<=16; $i+=2 ){ 00319 $pw .= $rand{$i}; 00320 } 00321 $password = $pw; 00322 //error_log("Password is $password"); 00323 $user = df_get_record($auth->usersTable, array($auth->usernameColumn => '='.$username)); 00324 if ( !$user ){ 00325 throw new Exception("No user account found with that username", self::$EX_USER_NOT_FOUND); 00326 00327 } 00328 $emailColumn = $auth->getEmailColumn(); 00329 if ( !$emailColumn ) throw new Exception("No email column found in the users table", self::$EX_NO_EMAIL_COLUMN_FOUND); 00330 $email = $user->val($emailColumn); 00331 00332 if ( !$email ){ 00333 throw new Exception("User has account has no email address on record. Please contact support to reset the password", self::$EX_NO_EMAIL_FOR_USER); 00334 00335 } 00336 00337 00338 $user->setValue($auth->passwordColumn, $password); 00339 $res = $user->save(); 00340 if ( PEAR::isError($res) ){ 00341 throw new Exception($res->getMessage()); 00342 } 00343 00344 00345 // Let's delete this request from the password reset requests. 00346 $this->delete_request_with_uuid($uuid); 00347 00348 // Now let's send the email. 00349 $del = $app->getDelegate(); 00350 $info = array(); 00351 if ( isset($del) and method_exists($del, 'getPasswordChangedEmailInfo') ){ 00352 $info = $del->getPasswordChangedEmailInfo($user, $password); 00353 } 00354 00355 $subject = 'Password Changed'; 00356 if ( isset($info['subject']) ) $subject = $info['subject']; 00357 00358 00359 $site_url = df_absolute_url(DATAFACE_SITE_HREF); 00360 00361 $msg = <<<END 00362 Your new temporary password is 00363 $password 00364 00365 You can change your password as follows: 00366 00367 1. Log in with your temporary password at <$site_url?-action=login> 00368 2. Click on the "My Profile" link in the upper right of the page 00369 3. Click on the "Edit" tab. 00370 4. Change your password in the edit form and click "Save" when done. 00371 END; 00372 00373 if ( isset($info['message']) ) $msg = $info['message']; 00374 00375 $parameters = null; 00376 if ( isset($info['parameters']) ) $parameters = $info['parameters']; 00377 00378 00379 00380 $site_title = $app->getSiteTitle(); 00381 $support_email = $_SERVER['SERVER_ADMIN']; 00382 if ( isset($app->_conf['admin_email']) ) $support_email = $app->_conf['admin_email']; 00383 if ( isset($app->_conf['support_email']) ) $support_email = $app->_conf['support_email']; 00384 00385 $headers = 'From: '.$site_title.' <'.$support_email.'>'."\r\nReply-to: ".$site_title." <".$support_email.">"; 00386 if ( isset($info['headers']) ) $headers = $info['headers']; 00387 00388 00389 if ( @$app->_conf['_mail']['func'] ) $func = $app->_conf['_mail']['func']; 00390 else $func = 'mail'; 00391 $res = $func($email, 00392 $subject, 00393 $msg, 00394 $headers, 00395 $parameters); 00396 if ( !$res ){ 00397 return PEAR::raiseError('Failed to send activation email. Please try again later.', DATAFACE_E_ERROR); 00398 } else { 00399 return true; 00400 } 00401 00402 00403 00404 00405 } 00406 00407 function delete_request_with_uuid($uuid){ 00408 $table = self::$TABLE_RESET_PASSWORD; 00409 $res = mysql_query("delete from `{$table}` where request_uuid='".addslashes($uuid)."' limit 1", df_db()); 00410 if ( !$res ) throw new Exception(mysql_error(df_db())); 00411 00412 } 00413 }