1<?php
2/*
3* e107 website system
4*
5* Copyright 2008-2014 e107 Inc (e107.org)
6* Released under the terms and conditions of the
7* GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
8*
9* Interface for users who have forgotten their password
10*
11*/
12
13
14$_E107['allow_guest'] = true;
15require_once('class2.php');
16
17e107::coreLan('fpw');
18
19$tp = e107::getParser();
20
21if (USER && !getperms('0'))
22{
23	e107::redirect();
24	exit;
25}
26
27if($pref['fpwcode'] && extension_loaded('gd'))
28{
29	define('USE_IMAGECODE', TRUE);
30	$sec_img = e107::getSecureImg();
31}
32else
33{
34	define('USE_IMAGECODE', FALSE);
35}
36
37
38class fpw_shortcodes extends e_shortcode
39{
40	private $secImg;
41
42	function __construct()
43	{
44		parent::__construct();
45		global $sec_img;
46		$this->secImg = $sec_img;
47	}
48
49	function sc_fpw_username($parm=null) // used when email login is disabled
50	{
51		// return "<input class='tbox' type='text' name='username' size='40' value='' maxlength='100' />";
52		return e107::getForm()->text('username'); // $frm->userpicker()?
53	}
54
55	function sc_fpw_useremail($parm=null)
56	{
57		// return '<input class="tbox form-control" type="text" name="email" size="40" value="" maxlength="100" placeholder="Email" required="required" type="email">';
58		// return "<input class='tbox' type='text' name='email' size='40' value='' maxlength='100' />";
59		return e107::getForm()->email('email', '', 200, array('placeholder' => 'Email', 'required' => 'required'));
60	}
61
62	function sc_fpw_submit($parm=null)
63	{
64		// return '<button type="submit" name="pwsubmit" class="button btn btn-primary btn-block reset">'.$label.'</button>';
65		// return "<input class='button btn btn-primary btn-block' type='submit' name='pwsubmit' value='".$label."' />";
66		$label = deftrue('LAN_FPW_102', LAN_SUBMIT);
67		return e107::getForm()->button('pwsubmit', $label);
68	}
69
70	function sc_fpw_captcha_lan($parm=null)
71	{
72		return LAN_ENTER_CODE;
73	}
74
75	function sc_fpw_captcha_hidden($parm=null)
76	{
77		return; // no longer required - included in renderInput();
78	}
79
80	/**
81	 * @param string $parm
82	 * @return mixed|null|string
83	 */
84	function sc_fpw_captcha_img($parm='')
85	{
86		if(USE_IMAGECODE)
87		{
88			return $this->secImg->renderImage();
89		}
90
91		return null;
92	}
93
94	/**
95	 * @param string $parm
96	 * @return mixed|null|string
97	 */
98	function sc_fpw_captcha_input($parm=null)
99	{
100		if(USE_IMAGECODE)
101		{
102			return $this->secImg->renderInput();
103		}
104
105		return null;
106	}
107
108	function sc_fpw_logo($parm='')
109	{
110		// Unused at the moment.
111	}
112
113	function sc_fpw_text($parm=null)
114	{
115		return deftrue('LAN_FPW_101',"Not to worry. Just enter your email address below and we'll send you an instruction email for recovery.");
116	}
117}
118
119
120if ($pref['membersonly_enabled'])
121{
122	$sc = array (
123		'FPW_LOGIN_LOGO' => file_exists(THEME."images/login_logo.png") ? "<img src='".THEME_ABS."images/login_logo.png' alt='' />\n" : "<img src='".e_IMAGE_ABS."logo.png' alt='' />\n"
124	);
125
126
127	if(deftrue('BOOTSTRAP'))
128	{
129		$FPW_TABLE_HEADER = e107::getCoreTemplate('fpw','header');
130		$FPW_TABLE_FOOTER = e107::getCoreTemplate('fpw','footer');
131	}
132	else
133	{
134		require_once (e107::coreTemplatePath('fpw')); //correct way to load a core template.
135	}
136
137	define('e_IFRAME', true);
138	$HEAD = $tp->simpleParse($FPW_TABLE_HEADER, $sc);
139	$FOOT = $tp->simpleParse($FPW_TABLE_FOOTER, $sc);
140
141	define('e_IFRAME_HEADER', $HEAD);
142	define('e_IFRAME_FOOTER' , $FOOT);
143
144
145}
146
147$user_info = e107::getUserSession();
148
149require_once(HEADERF);
150
151function fpw_error($txt)
152{
153	if(deftrue('BOOTSTRAP'))
154	{
155		e107::getMessage()->addError($txt);
156		e107::getRender()->tablerender(LAN_03, e107::getMessage()->render());
157		require_once(FOOTERF);
158		exit;
159	}
160
161	e107::getRender()->tablerender(LAN_03, "<div class='fpw-page'>".$txt."</div>", 'fpw');
162	require_once(FOOTERF);
163	exit;
164}
165
166//the separator character used
167define('FPW_SEPARATOR', '#');
168//$fpw_sep = '#';
169
170
171// User has clicked on the emailed link
172if(e_QUERY)
173{
174	// Make sure login menu is not giving any troubles
175	define('FPW_ACTIVE','TRUE');
176
177	// Verify the password reset code syntax
178	$tmpinfo = preg_replace("#[\W_]#", "", e107::getParser()->toDB(e_QUERY, true));			// query part is a 'random' number
179	if ($tmpinfo != e_QUERY)
180	{
181		// Shouldn't be any characters that toDB() changes
182		//die();
183		e107::getRedirect()->redirect(SITEURL);
184	}
185
186	// Verify the password reset code
187	if ($sql->select('tmp', '*', "`tmp_ip`='pwreset' AND `tmp_info` LIKE '%".FPW_SEPARATOR.$tmpinfo."' "))
188	{
189		$row = $sql->fetch();
190
191		// Delete the record
192
193		if(time() > (int) $row['tmp_time'])
194		{
195			$sql->delete('tmp', "`tmp_time` = ".$row['tmp_time']." AND `tmp_info` = '".$row['tmp_info']."' ");
196			e107::getMessage()->addDebug("Tmp Password Reset Entry Deleted");
197		}
198
199		$sql->delete('tmp', "tmp_time < ".time()); // cleanup table.
200
201		list($uid, $loginName, $md5) = explode(FPW_SEPARATOR, $row['tmp_info']);
202		$loginName = $tp->toDB($loginName, true);
203
204		// This should never happen!
205		if($md5 != $tmpinfo)
206		{
207			e107::getRedirect()->redirect(SITEURL);
208		}
209
210		// Generate new temporary password
211		$pwdArray = e107::getUserSession()->resetPassword($uid,$loginName, array('return'=>'array'));
212
213		if($pwdArray === false)
214		{
215			fpw_error(LAN_214);
216		}
217
218		$newpw = $pwdArray['password'];
219
220
221
222		// Details for admin log
223		$do_log = array();
224		$do_log['password_action']      = LAN_FPW21;
225		$do_log['user_loginname']       = $loginName;
226		$do_log['activation_code']      = $tmpinfo;
227		$do_log['user_password']        = $newpw;
228		$do_log['user_password_hash']   = $pwdArray['hash'];
229		$do_log['expires']              = date(DATE_W3C,$row['tmp_time']);
230
231
232		// Prepare new information to display to user
233		if((integer) e107::getPref('allowEmailLogin') > 0)
234		{
235			// always show email when possible
236			$sql->select('user', 'user_email', "user_id=".intval($uid));
237			$tmp = $sql->fetch();
238			$loginName = $tmp['user_email'];
239			$do_log['user_email'] =  $tmp['user_email'];
240			unset($tmp);
241		}
242
243		$admin_log->user_audit(USER_AUDIT_PW_RES,$do_log,0,$do_log['user_name']);
244
245		if(getperms('0')) // Test Mode.
246		{
247			echo "<div class='alert alert-danger'>".print_a($do_log, true)."</div>";
248		}
249		else
250		{
251			// Reset login cookie/session (?)
252			cookie($pref['cookie_name'], '', (time()-2592000));
253			$_SESSION[$pref['cookie_name']] = '';
254		}
255
256		// Display success message containing new login information
257		$txt = "<div class='fpw-message'>".LAN_FPW8."</div>
258		<table class='fpw-info'>
259		<tr><td>".LAN_218."</td><td style='font-weight:bold'>{$loginName}</td></tr>
260		<tr><td>".LAN_FPW9."</td><td style='font-weight:bold'> {$newpw}</td></tr>
261		</table>
262		<br /><br />".LAN_FPW10." <a href='".e_LOGIN."'>".LAN_LOGIN."</a>. "; // .LAN_FPW12;
263
264		e107::getMessage()->addSuccess($txt);
265		e107::getRender()->tablerender(LAN_03, e107::getMessage()->render());
266		require_once(FOOTERF);
267		exit;
268	}
269	// The password reset code was not found
270	else
271	{
272		fpw_error(LAN_FPW7);
273	}
274}
275
276
277// Request to reset password
278if (!empty($_POST['pwsubmit']))
279{
280	require_once(e_HANDLER.'mail.php');
281
282	if ($pref['fpwcode'] && extension_loaded('gd'))
283	{
284		if (!$sec_img->verify_code($_POST['rand_num'], $_POST['code_verify']))
285		{
286			fpw_error(LAN_INVALID_CODE);
287		}
288	}
289
290	$email 			= $_POST['email'];
291	$clean_email 	= check_email($tp->toDB($_POST['email']));
292	$clean_username = $tp->toDB(varset($_POST['username'], ''));
293
294 	$query = "`user_email`='{$clean_email}' ";
295	// Allow admins to remove 'username' from fpw_template.php if they wish.
296	$query .= (isset($_POST['username'])) ? " AND `user_loginname`='{$clean_username}'" : "";
297
298	if($sql->select('user', '*', $query))
299	{
300		// Found user in DB
301		$row = $sql->fetch();
302
303		// Main admin expected to be competent enough to never forget password! (And its a security check - so warn them)
304		// Sending email to admin alerting them of attempted admin password reset, and redirect user to homepage.
305		if(!getperms('0')) // disabled when testing as main-admin.
306		{
307			if (($row['user_admin'] == 1) && (($row['user_perms'] == '0')  OR ($row['user_perms'] == '0.')))
308			{
309				sendemail($pref['siteadminemail'], LAN_06, LAN_07.' ['.e107::getIPHandler()->getIP(FALSE).'] '.e107::getIPHandler()->getIP(TRUE).' '.LAN_08);
310				e107::getRedirect()->redirect(SITEURL);
311			}
312		}
313		// Banned user, or not validated
314		switch($row['user_ban'])
315		{
316			case USER_BANNED:
317				e107::getRedirect()->redirect(SITEURL);
318				break;
319			case USER_VALIDATED:
320				break;
321			default:
322				fpw_error(LAN_02.':'.$row['user_ban']);		// Intentionally rather a vague message
323				exit;
324		}
325
326		// Check if password reset was already requested
327		if ($result = $sql->select('tmp', '*', "`tmp_ip` = 'pwreset' AND `tmp_info` LIKE '".$row['user_loginname'].FPW_SEPARATOR."%'"))
328		{
329			fpw_error(LAN_FPW4);
330			exit;
331		}
332
333		// Set unique reset code
334		$datekey 	= microtime(true);
335		$rcode =  e107::getUserSession()->generateRandomString( '############' );
336	//	$rcode 		= crypt(($_SERVER['HTTP_USER_AGENT'] . serialize($pref). $clean_email . $datekey), e_TOKEN);
337
338		// Prepare email
339		$link 		= SITEURL.'fpw.php?'.$rcode;
340		$message 	= LAN_FPW5.' '.SITENAME.' '.LAN_FPW14.': '.e107::getIPHandler()->getIP(TRUE).".\n\n".LAN_FPW15."\n\n".LAN_FPW16."\n\n".LAN_FPW17."\n\n{$link}";
341
342		// Set timestamp two days ahead so it doesn't get auto-deleted
343	//	$deltime = time()+86400 * 2;
344		$deltime = strtotime("+ 10 minutes");
345
346		// Insert the password reset request into the database
347
348		$insertQry = array(
349			'tmp_ip'    => 'pwreset',
350			'tmp_time'  => $deltime,
351			'tmp_info'  => ($row['user_id'].FPW_SEPARATOR.$row['user_loginname'].FPW_SEPARATOR.$rcode)
352		);
353
354		$sql->insert('tmp', $insertQry);
355
356		// Setup the information to log
357		$do_log['password_action'] 	= LAN_FPW18;
358		$do_log['user_id'] 			= $row['user_id'];
359		$do_log['user_name'] 		= $row['user_name'];
360		$do_log['user_loginname'] 	= $row['user_loginname'];
361		$do_log['activation_code'] 	= $rcode;
362
363		if(getperms('0'))
364		{
365			$message .= "\n\n<hr><strong>Caution: If you click the button below, you will follow the link the user receives in their email, and the password will actually be reset!</strong>"; // NO LAN
366			$message .= "\n\n<a class='btn btn-primary' href='".$link."'>Click to Continue with test</a>"; // NO LAN
367			$ns->tablerender("Testing Mode", nl2br($message));
368			require_once(FOOTERF);
369			exit;
370		}
371
372		// Try to send the email
373		if(sendemail($clean_email, "".LAN_09."".SITENAME, $message))
374		{
375			e107::getMessage()->addInfo(LAN_FPW6);
376			$do_log['password_result'] = LAN_FPW20;
377		}
378		else
379		{
380			//$text = "<div style='text-align:center'>".LAN_02."</div>";
381			$do_log['password_result'] = LAN_FPW19;
382		  	fpw_error(LAN_02);
383		}
384
385		// Log to user audit log
386		e107::getAdminLog()->user_audit(USER_AUDIT_PW_RES, $do_log, $row['user_id'], $row['user_name']);
387
388		$ns->tablerender(LAN_03, $text.e107::getMessage()->render());
389		require_once(FOOTERF);
390		exit;
391	}
392	else
393	{
394		//$text = LAN_213;
395		//$ns->tablerender(LAN_214, "<div style='text-align:center'>".$text."</div>");
396		//e107::getMessage()->addError(LAN_213);
397		//$ns->tablerender(LAN_214, e107::getMessage()->render());
398		fpw_error(LAN_213);
399	}
400}
401
402
403$sc = array(); // needed?
404
405
406if(deftrue('BOOTSTRAP'))
407{
408	// TODO do we want the <form> element outside the template?
409	$FPW_TABLE = "<form method='post' action='".SITEURL."fpw.php' autocomplete='off'>";
410
411	if(getperms('0'))
412	{
413		$FPW_TABLE.= "<div class='alert alert-danger'>Logged in as admin</div>";
414	}
415
416
417	$FPW_TABLE .= e107::getCoreTemplate('fpw','form');
418	$FPW_TABLE .= "</form>";
419	$caption = deftrue('LAN_FPW_100',"Forgot your password?");
420}
421elseif(!$FPW_TABLE)
422{
423	require_once (e107::coreTemplatePath('fpw')); //correct way to load a core template.
424	$caption = LAN_03;
425}
426
427$sc = new fpw_shortcodes;
428
429// New Shortcode names in v2. BC Fix.
430$bcShortcodes 	= array('{FPW_TABLE_SECIMG_LAN}', '{FPW_TABLE_SECIMG_HIDDEN}', '{FPW_TABLE_SECIMG_SECIMG}', '{FPW_TABLE_SECIMG_TEXTBOC}');
431$nwShortcodes 	= array('{FPW_CAPTCHA_LAN}', '{FPW_CAPTCHA_HIDDEN}', '{FPW_CAPTCHA_IMG}', '{FPW_CAPTCHA_INPUT}');
432$FPW_TABLE 		= str_replace($bcShortcodes,$nwShortcodes,$FPW_TABLE);
433
434$text = $tp->parseTemplate($FPW_TABLE, true, $sc);
435
436// $text = $tp->simpleParse($FPW_TABLE, $sc);
437
438$ns->tablerender($caption, $text, 'fpw');
439require_once(FOOTERF);
440
441