PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/website/account/user.inc

https://bitbucket.org/matthewsomerville/publicwhip-v1
PHP | 542 lines | 451 code | 48 blank | 43 comment | 116 complexity | 8ccefea3b7a85ff247f563e48c750507 MD5 | raw file
Possible License(s): AGPL-1.0, BSD-3-Clause
  1. <?php
  2. require_once $toppath . 'auth.inc';
  3. $feedback = '';
  4. if (!defined('HIDDEN_HASH_VAR')) {
  5. trigger_error("ERROR: include config.php first, and make sure it has values in", E_USER_ERROR);
  6. }
  7. if (!function_exists("user_isloggedin"))
  8. {
  9. unset($LOGGED_IN);
  10. function user_isloggedin() {
  11. global $user_name,$id_hash,$LOGGED_IN;
  12. if (!$user_name) {
  13. $user_name=mysql_real_escape_string($_COOKIE["user_name"]);
  14. }
  15. $id_hash=mysql_real_escape_string($_COOKIE["id_hash"]);
  16. //have we already run the hash checks?
  17. //If so, return the pre-set var
  18. if (isset($LOGGED_IN)) {
  19. if ($LOGGED_IN) {
  20. return $LOGGED_IN;
  21. }
  22. }
  23. if ($user_name && $id_hash) {
  24. $hash=md5($user_name.HIDDEN_HASH_VAR);
  25. # print "hash $hash idhash $id_hash";
  26. if ($hash == $id_hash) {
  27. $LOGGED_IN=true;
  28. return true;
  29. } else {
  30. $LOGGED_IN=false;
  31. return false;
  32. }
  33. } else {
  34. $LOGGED_IN=false;
  35. return false;
  36. }
  37. }
  38. }
  39. function user_login($user_name,$password) {
  40. global $feedback, $LOGGED_IN;
  41. if (!$user_name || !$password) {
  42. $feedback .= ' Please enter your user name and password. ';
  43. return false;
  44. } else {
  45. $user_name=strtolower($user_name);
  46. $password=strtolower($password);
  47. $sql="SELECT * FROM pw_dyn_user WHERE user_name='$user_name' AND password='". md5($password) ."'";
  48. $result=db_query($sql);
  49. if (!$result || db_numrows($result) < 1){
  50. $feedback .= ' User not found or password incorrect. ';
  51. return false;
  52. } else {
  53. if (db_result($result,0,'is_confirmed') == '1') {
  54. user_set_tokens($user_name);
  55. $LOGGED_IN = true;
  56. $feedback .= ' You are now logged in.';
  57. return true;
  58. } else {
  59. $feedback .= ' You haven\'t confirmed your account yet. Please check your email. ';
  60. return false;
  61. }
  62. }
  63. }
  64. }
  65. function user_logout() {
  66. global $LOGGED_IN;
  67. $LOGGED_IN = false;
  68. setcookie('user_name','',(time()+2592000),'/','',0);
  69. setcookie('id_hash','',(time()+2592000),'/','',0);
  70. }
  71. function user_set_tokens($user_name_in) {
  72. global $user_name,$id_hash;
  73. if (!$user_name_in) {
  74. $feedback .= ' User name missing when setting tokens. ';
  75. return false;
  76. }
  77. $user_name=strtolower($user_name_in);
  78. $id_hash= md5($user_name.HIDDEN_HASH_VAR);
  79. setcookie('user_name',$user_name,(time()+2592000),'/','',0);
  80. setcookie('id_hash',$id_hash,(time()+2592000),'/','',0);
  81. }
  82. function user_confirm($hash,$email) {
  83. /*
  84. Call this function on the user confirmation page,
  85. which they arrive at when the click the link in the
  86. account confirmation email
  87. */
  88. global $feedback;
  89. //verify that they didn't tamper with the email address
  90. $new_hash=md5($email.HIDDEN_HASH_VAR);
  91. if ($new_hash && ($new_hash==$hash)) {
  92. //find this record in the db
  93. $sql="SELECT * FROM pw_dyn_user WHERE confirm_hash='$hash' order by is_confirmed";
  94. $result=db_query($sql);
  95. $return_url = db_result($result,0,'confirm_return_url');
  96. if (!$result || db_numrows($result) < 1) {
  97. $feedback .= ' Hash not found. Found: ' . db_numrows($result);
  98. return false;
  99. } else {
  100. //confirm the email and set account to active
  101. $feedback .= ' New user account ' . db_result($result,0,'user_name') . ' confirmed - you are now logged in. ';
  102. user_set_tokens(db_result($result,0,'user_name'));
  103. $sql="UPDATE pw_dyn_user SET email='$email',is_confirmed='1' WHERE confirm_hash='$hash'";
  104. $result=db_query($sql);
  105. $result=db_query("DELETE FROM pw_dyn_newsletter WHERE email='" . $email . "'");
  106. $result=db_query("INSERT INTO pw_dyn_newsletter (email, confirm, subscribed, token) values('" . $email . "', 1, now(), '".auth_random_token()."')");
  107. audit_log("Confirmed account email " . $email . " valid");
  108. return $return_url;
  109. }
  110. } else {
  111. $feedback .= ' Hash invalid - update failed. ';
  112. return false;
  113. }
  114. }
  115. function user_change_password ($new_password1,$new_password2,$change_user_name,$old_password) {
  116. global $feedback;
  117. //new passwords present and match?
  118. if ($new_password1 && ($new_password1==$new_password2)) {
  119. //is this password long enough?
  120. if (account_pwvalid($new_password1)) {
  121. //all vars are present?
  122. if ($change_user_name && $old_password) {
  123. //lower case everything
  124. $change_user_name=strtolower($change_user_name);
  125. $old_password=strtolower($old_password);
  126. $new_password1=strtolower($new_password1);
  127. $sql="SELECT * FROM pw_dyn_user WHERE user_name='$change_user_name' AND password='". md5($old_password) ."'";
  128. $result=db_query($sql);
  129. if (!$result || db_numrows($result) < 1) {
  130. $feedback .= ' User not found or bad password. '.db_error();
  131. return false;
  132. } else {
  133. $sql="UPDATE pw_dyn_user SET password='". md5($new_password1). "' ".
  134. "WHERE user_name='$change_user_name' AND password='". md5($old_password). "'";
  135. $result=db_query($sql);
  136. if (!$result || db_affected_rows($result) < 1) {
  137. $feedback .= ' Nothing changed! '.db_error();
  138. return false;
  139. } else {
  140. audit_log("Changed password");
  141. $feedback .= ' Password changed.';
  142. return true;
  143. }
  144. }
  145. } else {
  146. $feedback .= ' You must provide both your user name and old password. ';
  147. return false;
  148. }
  149. } else {
  150. $feedback .= ' New passwords doesn\'t meet criteria. ';
  151. return false;
  152. }
  153. } else {
  154. $feedback .= ' New passwords must match. ';
  155. return false;
  156. }
  157. }
  158. function user_lost_password ($email,$user_name) {
  159. global $feedback;
  160. if ($email && $user_name) {
  161. $user_name=strtolower($user_name);
  162. $sql="SELECT * FROM pw_dyn_user WHERE user_name='$user_name' AND email='$email'";
  163. $result=db_query($sql);
  164. if (!$result || db_numrows($result) < 1) {
  165. //no matching user found
  166. $feedback .= ' Incorrect user name or email address. ';
  167. return false;
  168. } else {
  169. //create a secure, new password
  170. $new_pass=strtolower(substr(md5(time().$user_name.HIDDEN_HASH_VAR),1,14));
  171. //update the database to include the new password
  172. $sql="UPDATE pw_dyn_user SET password='". md5($new_pass) ."' WHERE user_name='$user_name'";
  173. $result=db_query($sql);
  174. //send a simple email with the new password
  175. $message =
  176. "Your password has been changed to: $new_pass".
  177. "\nYour username is $user_name, email address $email.".
  178. "\n\nLogin here: http://www.publicwhip.org.uk/account/settings.php".
  179. "\n\nAfter login you can change your password to something memorable.";
  180. mail ($email,'Public Whip Password Reset',$message,'From: auto@publicwhip.org.uk');
  181. $feedback .= ' Your new password has been emailed to you. ';
  182. audit_log("Reset password, new one emailed to user " . $user_name);
  183. return true;
  184. }
  185. } else {
  186. $feedback .= ' Enter a user name and email address. ';
  187. return false;
  188. }
  189. }
  190. function user_change_email ($password1,$new_email,$user_name) {
  191. global $feedback;
  192. if (pw_validate_email($new_email)) {
  193. $hash=md5($new_email.HIDDEN_HASH_VAR);
  194. //change the confirm hash in the db but not the email -
  195. //send out a new confirm email with a new hash
  196. $user_name=strtolower($user_name);
  197. $password1=strtolower($password1);
  198. # print "user $user_name pw $password1 em $new_email";
  199. $sql="UPDATE pw_dyn_user SET confirm_hash='$hash' WHERE user_name='$user_name' AND password='". md5($password1) ."'";
  200. $result=db_query($sql);
  201. if (!$result || db_affected_rows($result) < 1) {
  202. $feedback .= ' Incorrect user name or password. ' . db_error();
  203. return false;
  204. } else {
  205. $feedback .= ' Confirmation email sent. Check your new email address, and follow the link to complete the change.';
  206. user_send_confirm_email($new_email,$hash,$user_name);
  207. audit_log("Sent confirm new email " . $new_email);
  208. return true;
  209. }
  210. } else {
  211. $feedback .= ' New email address appears invalid. ';
  212. return false;
  213. }
  214. }
  215. function user_send_confirm_email($email,$hash, $user) {
  216. /*
  217. Used in the initial registration function
  218. as well as the change email address function
  219. */
  220. $message = "Thank you for registering with the Public Whip!".
  221. "\nSimply follow this link to confirm your registration: ".
  222. "\n\nhttp://www.publicwhip.org.uk/account/confirm.php?hash=$hash&email=". urlencode($email).
  223. "\n\nOnce you have confirmed, you will in future receive the".
  224. "\nat most monthly Public Whip newsletter and be able".
  225. "\nto access extra features on the website.".
  226. "\n\nYour username is $user, email address $email.".
  227. "\nIf you would not like to receive the newsletter, you can".
  228. "\nlog in and stop the newsletter, but still access other".
  229. "\nfeatures. You can do this after confirming." .
  230. "\n\nFor more information on the project visit www.publicwhip.org.uk";
  231. mail ($email,'Public Whip registration confirmation',$message,'From: auto@publicwhip.org.uk');
  232. }
  233. function user_register($user_name,$password1,$password2,$email,$real_name) {
  234. global $feedback;
  235. //all vars present and passwords match?
  236. if (!$user_name )
  237. {
  238. $feedback .= ' Please fill in your user name.';
  239. return false;
  240. }
  241. else if (!$password1 )
  242. {
  243. $feedback .= ' Please fill in your password.';
  244. return false;
  245. }
  246. else if ($password1 != $password2 )
  247. {
  248. $feedback .= ' Please enter matching passwords.';
  249. return false;
  250. }
  251. else if (!$email)
  252. {
  253. $feedback .= ' Please fill in your email address.';
  254. return false;
  255. }
  256. else if (!pw_validate_email($email) )
  257. {
  258. $feedback .= ' Please fill in a valid email address.';
  259. return false;
  260. }
  261. else {
  262. //password and name are valid?
  263. if (account_namevalid($user_name) && account_pwvalid($password1)) {
  264. $user_name=strtolower($user_name);
  265. $password1=strtolower($password1);
  266. //does the name exist in the database?
  267. $sql="SELECT * FROM pw_dyn_user WHERE user_name='$user_name'";
  268. $result=db_query($sql);
  269. if ($result && db_numrows($result) > 0) {
  270. $feedback .= 'Sorry, that user name has already been used.';
  271. return false;
  272. } else {
  273. //create a new hash to insert into the db and the confirmation email
  274. $hash=md5($email.HIDDEN_HASH_VAR);
  275. $sql="INSERT INTO pw_dyn_user
  276. (user_name,real_name,password,email,remote_addr,confirm_hash,is_confirmed, reg_date, confirm_return_url) ".
  277. "VALUES ('$user_name','$real_name','". md5($password1) ."','$email','" . getenv('REMOTE_ADDR') . "','$hash','0',NOW(),'".mysql_real_escape_string($_POST['r'])."')";
  278. $result=db_query($sql);
  279. if (!$result) {
  280. $feedback .= ' Trouble with the database. '.db_error();
  281. return false;
  282. } else {
  283. //send the confirm email
  284. user_send_confirm_email($email,$hash,$user_name);
  285. $feedback .= ' You have successfully registered. <b>Check your email<b> for a confirmation message. Follow the link in the email to confirm your account.';
  286. audit_log("Registered new user " . $user_name . ", real " . $real_name . ", " . $email);
  287. return true;
  288. }
  289. }
  290. } else {
  291. $feedback .= ' Your account name or password are not valid. ';
  292. return false;
  293. }
  294. }
  295. }
  296. function user_getid() {
  297. global $G_USER_RESULT;
  298. //see if we have already fetched this user from the db, if not, fetch it
  299. if (!$G_USER_RESULT) {
  300. $G_USER_RESULT=db_query("SELECT * FROM pw_dyn_user WHERE user_name='" . user_getname() . "'");
  301. }
  302. if ($G_USER_RESULT && db_numrows($G_USER_RESULT) > 0) {
  303. return db_result($G_USER_RESULT,0,'user_id');
  304. } else {
  305. return false;
  306. }
  307. }
  308. function user_getrealname() {
  309. global $G_USER_RESULT;
  310. //see if we have already fetched this user from the db, if not, fetch it
  311. if (!$G_USER_RESULT) {
  312. $G_USER_RESULT=db_query("SELECT * FROM pw_dyn_user WHERE user_name='" . user_getname() . "'");
  313. }
  314. if ($G_USER_RESULT && db_numrows($G_USER_RESULT) > 0) {
  315. return db_result($G_USER_RESULT,0,'real_name');
  316. } else {
  317. return false;
  318. }
  319. }
  320. function user_getemail() {
  321. global $G_USER_RESULT;
  322. //see if we have already fetched this user from the db, if not, fetch it
  323. if (!$G_USER_RESULT) {
  324. $G_USER_RESULT=db_query("SELECT * FROM pw_dyn_user WHERE user_name='" . user_getname() . "'");
  325. }
  326. if ($G_USER_RESULT && db_numrows($G_USER_RESULT) > 0) {
  327. return db_result($G_USER_RESULT,0,'email');
  328. } else {
  329. return false;
  330. }
  331. }
  332. function user_getactivepolicy() {
  333. global $G_USER_RESULT;
  334. //see if we have already fetched this user from the db, if not, fetch it
  335. if (!$G_USER_RESULT) {
  336. $G_USER_RESULT=db_query("SELECT * FROM pw_dyn_user WHERE user_name='" . user_getname() . "'");
  337. }
  338. if ($G_USER_RESULT && db_numrows($G_USER_RESULT) > 0) {
  339. return db_result($G_USER_RESULT,0,'active_policy_id');
  340. } else {
  341. return false;
  342. }
  343. }
  344. function user_getnewsletter() {
  345. global $G_NEWSL_RESULT;
  346. //see if we have already fetched this user from the db, if not, fetch it
  347. if (!$G_NEWSL_RESULT) {
  348. $G_NEWSL_RESULT=db_query("SELECT * FROM pw_dyn_newsletter WHERE confirm AND email='" . user_getemail() . "'");
  349. }
  350. if ($G_NEWSL_RESULT && db_numrows($G_NEWSL_RESULT) > 0) {
  351. return true;
  352. } else {
  353. return false;
  354. }
  355. }
  356. function user_changenewsletter($newsletter) {
  357. global $feedback;
  358. if ($newsletter)
  359. $newsletter = 1;
  360. else
  361. $newsletter = 0;
  362. $result=db_query("DELETE FROM pw_dyn_newsletter WHERE email='" . user_getemail() . "'");
  363. if ($result && $newsletter)
  364. $result=db_query("INSERT INTO pw_dyn_newsletter (email, confirm, subscribed, token) values('" . user_getemail() . "', 1, now(), '".auth_random_token()."')");
  365. if ($result) {
  366. $feedback .= " Newsletter setting changed. ";
  367. audit_log("Changed newsletter to " . $newsletter);
  368. return true;
  369. } else {
  370. $feedback .= " Error writing to database. ". db_error();
  371. return false;
  372. }
  373. }
  374. function user_getname() {
  375. if (user_isloggedin()) {
  376. return mysql_real_escape_string($GLOBALS['user_name']);
  377. } else {
  378. //look up the user some day when we need it
  379. return ' Not logged in. ';
  380. }
  381. }
  382. function account_pwvalid($pw) {
  383. global $feedback;
  384. if (strlen($pw) < 6) {
  385. $feedback .= " Password must be at least 6 characters. ";
  386. return false;
  387. }
  388. return true;
  389. }
  390. function account_namevalid($name) {
  391. global $feedback;
  392. // no spaces
  393. if (strrpos($name,' ') > 0) {
  394. $feedback .= " There cannot be any spaces in the user name. ";
  395. return false;
  396. }
  397. // must have at least one character
  398. if (strspn($name,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == 0) {
  399. $feedback .= "There must be at least one character.";
  400. return false;
  401. }
  402. // must contain all legal characters
  403. if (strspn($name,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")
  404. != strlen($name)) {
  405. $feedback .= " Please only use the alphabet, dash and underscore in your username. ";
  406. return false;
  407. }
  408. // min and max length
  409. if (strlen($name) < 5) {
  410. $feedback .= " Name is too short. It must be at least 5 characters. ";
  411. return false;
  412. }
  413. if (strlen($name) > 15) {
  414. $feedback .= "Name is too long. It must be less than 15 characters.";
  415. return false;
  416. }
  417. // illegal names
  418. if (preg_match("/^((root)|(bin)|(daemon)|(adm)|(lp)|(sync)|(shutdown)|(halt)|(mail)|(news)"
  419. . "|(uucp)|(operator)|(games)|(mysql)|(httpd)|(nobody)|(dummy)"
  420. . "|(www)|(cvs)|(shell)|(ftp)|(irc)|(debian)|(ns)|(download))$/i",$name)) {
  421. $feedback .= "Name is reserved.";
  422. return 0;
  423. }
  424. if (preg_match("/^(anoncvs_)/i",$name)) {
  425. $feedback .= "Name is reserved for CVS.";
  426. return false;
  427. }
  428. return true;
  429. }
  430. function pw_validate_email ($address) {
  431. // using > as delimiter as not in string http://uk2.php.net/manual/en/regexp.reference.delimiters.php
  432. return (preg_match('>^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'. '@'. '[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.' . '[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$>', $address));
  433. }
  434. function login_screen()
  435. {
  436. global $feedback, $toppath, $onload, $title;
  437. $onload = "givefocus('user_name')";
  438. $title = "Login to Public Whip";
  439. pw_header();
  440. if ($feedback) {
  441. print "<div class=\"error\"><h2>Login not correct,
  442. please try again</h2><p>$feedback</div>";
  443. }
  444. global $this_place;
  445. print '
  446. <P>
  447. Enter your user name and password and we\'ll set a cookie so we know you\'re logged in.
  448. <p>Not got a login? <A HREF="/account/register.php?r='.
  449. ($_GET['r']?urlencode($_GET['r']):urlencode($this_place)).
  450. '">Register a new
  451. account</A>. You will also receive a free email newsletter.
  452. <br>Lost your password? <a href="lostpass.php">Reset your password here</a>.
  453. <P>
  454. <FORM ACTION="'. $PHP_SELF .'" METHOD="POST" name=pw>
  455. <B>User name:</B><BR>
  456. <INPUT TYPE="TEXT" NAME="user_name" id="user_name" VALUE="" SIZE="15" MAXLENGTH="15">
  457. <P>
  458. <B>Password:</B><BR>
  459. <INPUT TYPE="password" NAME="password" VALUE="" SIZE="15" MAXLENGTH="15">
  460. <P>';
  461. if ($_GET['r']) {
  462. print '<INPUT TYPE="hidden" NAME="r" VALUE="'.htmlspecialchars($_GET['r']).'">';
  463. }
  464. print '<INPUT TYPE="SUBMIT" NAME="submit" VALUE="Login to Public Whip">
  465. </FORM>
  466. <P>';
  467. pw_footer();
  468. }
  469. function do_login_screen()
  470. {
  471. if (!user_isloggedin())
  472. {
  473. $user_name=mysql_real_escape_string($_POST["user_name"]);
  474. $password=mysql_real_escape_string($_POST["password"]);
  475. $submit=mysql_real_escape_string($_POST["submit"]);
  476. if ($submit) {
  477. if (user_login($user_name,$password))
  478. {
  479. $feedback = "";
  480. return true;
  481. }
  482. }
  483. }
  484. return false;
  485. }
  486. function audit_log($text)
  487. {
  488. $sql = "insert into pw_dyn_auditlog (user_id, event_date, event, remote_addr)
  489. values ('" . user_getid() . "', NOW(), '" . mysql_real_escape_string($text) . "', '" . getenv('REMOTE_ADDR') . "')";
  490. $result=db_query($sql);
  491. if (!$result)
  492. print "Error writing to audit log: " . db_error();
  493. }
  494. ?>