Browse Source

Add login and common files

Frans Bergman 5 years ago
parent
commit
8e4d2c45b6
12 changed files with 502 additions and 2 deletions
  1. 1 0
      .gitignore
  2. 1 1
      admin/index.php
  3. 1 1
      admin/pageparts/sidemenu.php
  4. 211 0
      app.php
  5. 14 0
      config.php.sample
  6. 43 0
      login/check_login.php
  7. 64 0
      login/create.php
  8. BIN
      login/favicon-lock.ico
  9. 44 0
      login/index.php
  10. 35 0
      login/login.php
  11. 5 0
      login/logout.php
  12. 83 0
      login/reset.php

+ 1 - 0
.gitignore

@@ -1,2 +1,3 @@
 download/
 images/
+config.php

+ 1 - 1
admin/index.php

@@ -19,7 +19,7 @@
 				include "pages/dashboard.php";
 			echo '</div>';
 		} else {
-			header("Location: https://login.tankernn.eu?redirect=https://tankernn.eu/admin");
+			header("Location: /login?redirect=https://tankernn.eu/admin");
 		}
 	?>
 	</body>

+ 1 - 1
admin/pageparts/sidemenu.php

@@ -17,7 +17,7 @@
       <ul class="dropdown-menu dropdown-user">
         <li><a href="?p=account_settings"><i class="fa fa-cog"></i> Account Settings</a></li>
         <li class="divider"></li>
-        <li><a href="http://login.tankernn.eu/logout.php"><i class="fa fa-sign-out fa-fw"></i> Logout</a></li>
+        <li><a href="/login/logout.php"><i class="fa fa-sign-out fa-fw"></i> Logout</a></li>
       </ul>
     </li>
   </ul>

+ 211 - 0
app.php

@@ -0,0 +1,211 @@
+<?php
+  session_name('default');
+  session_set_cookie_params(0, '/', '.tankernn.eu');
+  session_start();
+  require_once('config.php');
+
+  class App {
+    function __construct($silent = false) {
+      global $conn;
+
+      //Get username
+      $this->user = 'guest';
+      if(isset($_SESSION['user']))
+          $this->user = htmlspecialchars($_SESSION['user']);
+
+      //Get page name
+      $this->pagename = "Start";
+      if(isset($_GET['p']))
+        $this->pagename = htmlspecialchars($conn->escape_string($_GET['p']));
+
+      //Get page
+      $query=$conn->query("SELECT * FROM Page WHERE name='$this->pagename'");
+      $this->pageRow=$query->fetch_array() or print($silent ? "" : "<i>Couldn't find page: ".$this->pagename."</i>"); /*header("Location: /?p=error")*/
+
+      //Import scripts
+      $this->scripts = "";
+      foreach (glob("scripts/*.js") as $filename)
+        $this->scripts .= "<script src='$filename'></script>";
+
+      //Import stylesheets
+      $this->styles = "";
+      foreach (glob("stylesheets/*.css") as $filename)
+         $this->styles .= "<link rel='Stylesheet' type='text/css' href='$filename'/>";
+
+       //Setup variables
+       $this_year = getdate()['year'];
+
+       $loginbuttons = <<<EOT
+          <a class="btn btn-primary" href="/login">Log in</a>
+          or
+          <a class="btn btn-default" href="/login?signup">Sign up</a>
+EOT;
+
+       $this->vars = array(
+         '{$year}' => $this_year,
+         '{$user}' => $this->user,
+         '{$sitename}' => Config::$sitename,
+         '{$menuitems}' => $this->getMenuItems(),
+         '{$login}' => isset($_SESSION['user']) ? "<a href='/admin' class='btn btn-primary' target='_blank'>Control panel <i class='fa fa-external-link'></i></a>" : $loginbuttons
+        );
+
+      //Get components
+      $this->components = array();
+      $query=$conn->query("SELECT * FROM Component");
+      while ($compRow = $query->fetch_array()) {
+        $this->components[$compRow['name']] = strtr($compRow['content'], $this->vars);
+      }
+    }
+
+    function addSection($sectionName) {
+      global $conn;
+      $query=$conn->query("SELECT * FROM Section WHERE name='$sectionName' OR UID='$sectionName'");
+      $sectionrow=$query->fetch_array();
+      echo "<section class=".strtolower($sectionrow["name"])." id=". $sectionrow["UID"] ."><div class='container'>";
+      echo strtr($sectionrow['content'], $this->vars);
+      echo '</div></section>';
+    }
+
+    function printPage() {
+      $sections = json_decode($this->pageRow['sections']);
+      if ($sections === NULL)
+        $sections = explode(',', $this->pageRow['sections']);
+
+      foreach ($sections as $section) {
+        $this->addSection($section);
+      }
+    }
+
+    function getMenuItems() {
+      global $conn;
+      $menuquery = $conn->query("SELECT * FROM Menu ORDER BY listId");
+      $menuString = "";
+
+      while($menurow = $menuquery->fetch_array()) {
+        $selected = "";
+        if ($this->pagename == $menurow['value'])
+          $selected = "active";
+
+        if ($menurow['valuetype'] == "page") {
+          $link = "/" . $menurow['value'];
+        } else {
+          $link = $menurow['value'];
+        }
+        $menuString .= "<li class='$selected'><a href='$link'>".$menurow['name']."</a></li>";
+      }
+      return $menuString;
+    }
+  }
+
+  class Message {
+    public $text;
+    public $type;
+    function __construct($message, $messtype) {
+      $this->text = $message;
+      $this->type = $messtype;
+    }
+  }
+
+  function display_message($message) {
+    ?>
+    <div class="alert alert-<?php echo $message->type ?> alert-dismissable fade in">
+        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
+        <?php echo $message->text ?>
+    </div>
+    <?php
+  }
+
+  function list_messages() {
+    if (isset($_SESSION['message'])) {
+      $messages = json_decode($_SESSION['message']);
+      foreach ($messages as $message)
+        display_message($message);
+      unset($_SESSION['message']);
+    }
+  }
+
+  function queue_message($message) {
+    $messages = array();
+    if (isset($_SESSION['message'])) {
+      $messages = json_decode($_SESSION['message']);
+    }
+    array_push($messages, $message);
+    $_SESSION['message'] = json_encode($messages);
+  }
+
+  function generateKey($length) {
+    return bin2hex(openssl_random_pseudo_bytes($length));
+  }
+
+  function new_activation($user, $type, $value) {
+    global $conn;
+    if ($type === "Email") {
+      $mail = $value;
+    } else {
+      $mail = $conn->query("SELECT Email FROM Users WHERE User='$user'")->fetch_array()['Email'];
+    }
+
+    $key = generateKey(16);
+    if ($conn->query("INSERT INTO Activations (User,Type,Val,Activation_key) VALUES ('$user','$type','$value','$key')")) {
+      mail($mail, Config::$sitename . " $type confirmation", "To activate your new $type, navigate to this address: http://tankernn.eu/admin/actions/activate.php?key=" . $key);
+      return new Message("Activation E-mail sent to " . $mail, "success");
+    } else {
+      return new Message("Failed to update database. Error: " . $conn->error, "danger");
+    }
+  }
+
+  function changePassword($userid, $newPass, $newPassRepeat, $oldPass = false) {
+    global $conn;
+    if ($newPass === $newPassRepeat) {
+      if (strlen($newPass) < 8) {
+        queue_message(new Message("Your password must be at least 8 characters long.", "danger"));
+        return false;
+      }
+      $query = $conn->query("SELECT * FROM Users WHERE UID='$userid'");
+      $row = $query->fetch_array();
+      if ($oldPass === false || password_verify($oldPass, $row['Password'])) {
+        $pass_hashed = password_hash($newPass, PASSWORD_DEFAULT);
+        if($conn->query("UPDATE Users SET Password='$pass_hashed' WHERE UID='$userid'")) {
+          queue_message(new Message("Successfully updated password.", "success"));
+          return true;
+        } else {
+          queue_message(new Message("SQL error: " . $conn->error, "danger"));
+          return false;
+        }
+      } else {
+        queue_message(new Message("Password incorrect.", "danger"));
+        return false;
+      }
+    } else {
+      queue_message(new Message("Passwords do not match.", "danger"));
+      return false;
+    }
+  }
+
+  function hasPermission($permission = 2) {
+    if (!isset($_SESSION['user']) or !isset($_SESSION['permissions']))
+      return false;
+
+    $myPermissions = json_decode($_SESSION['permissions']);
+
+    if ($myPermissions->permission_level >= 2)
+      return true;
+
+    switch (gettype($permission)) {
+      case "string":
+        return in_array($permission, $myPermissions->custom_permissions);
+        break;
+      case "integer":
+        return $myPermissions->permission_level >= $permission;
+        break;
+      default:
+        throw new InvalidArgumentException("Permission type must be integer or string.", 1);
+    }
+  }
+
+  function admin_check() {
+    if (!hasPermission(2)) {
+      die("Not enough permissions.");
+    }
+  }
+?>

+ 14 - 0
config.php.sample

@@ -0,0 +1,14 @@
+<?php
+	class Config {
+		public static $sitename = "Tankernn.eu";
+		public static $webmaster = "frans@tankernn.eu";
+
+		//Database Settings
+		public static $hostname = "localhost";
+		public static $dbuser = "USER_HERE";
+		public static $dbpass = "PASS_HERE";
+		public static $dbname = "DB_NAME_HERE";
+	}
+
+	$conn = new mysqli(Config::$hostname, Config::$dbuser, Config::$dbpass, Config::$dbname) or die("Error " . $conn->error);
+?>

+ 43 - 0
login/check_login.php

@@ -0,0 +1,43 @@
+<?php
+	require "app.php";
+	if (isset($_POST['user'])) {
+		$username = $_POST['user'];
+		$query = $conn->query("SELECT * FROM Users WHERE User='$username'") or header("Location: ../?wronglogin");
+		$row = $query->fetch_array();
+		if (password_verify($_POST['pass'], $row['Password'])) {
+			if (empty($row['Email'])) { // Unconfirmed E-mail
+				$mess = new Message("You have not confirmed your e-mail address yet. Please do so before logging in.", "warning");
+				queue_message($mess);
+			} else {
+				$ips = json_decode($row['Addresses'], true);
+				if (in_array($_SERVER["REMOTE_ADDR"], $ips)) {
+					// Everything is fine, log in
+					$_SESSION['user'] = $row['User'];
+					$_SESSION['permissions'] = $row['Permissions'];
+					$_SESSION['userid'] = $row['UID'];
+					queue_message(new Message("Successfully logged in.", "success"));
+				} else { // New IP
+					$mess = new_activation($username, "Addresses", $_SERVER["REMOTE_ADDR"]);
+					queue_message($mess);
+				}
+			}
+		} else { // Password incorrect
+			$message = "Someone has failed to login to your account on " . Config::$sitename . ". They were using the password: " . htmlspecialchars($_POST['pass'] . "Their IP: " . $_SERVER['REMOTE_ADDR']);
+			mail($row['Email'], "Failed login attempt", $message);
+			queue_message(new Message("Incorrect password, the account owner has been notified.", "danger"));
+		}
+		if (isset($_POST['redirect'])) {
+			$redirect = $_POST['redirect'];
+			if (preg_match("/^https?:\/\/(\w*\.)?tankernn\.eu/i", $redirect) === 1 or preg_match("/^\.?\.?\//i", $redirect) === 1) {
+				header("Location: $redirect");
+			}
+			echo "Invalid redirect URL: " . htmlspecialchars($redirect);
+		} else {
+			echo "Successfully logged in.";
+		}
+	}
+	else {
+		echo "No login data present.";
+	}
+
+?>

+ 64 - 0
login/create.php

@@ -0,0 +1,64 @@
+<?php
+  require 'app.php';
+
+  function check_captcha($response) {
+    $url = 'https://www.google.com/recaptcha/api/siteverify';
+    $data = array('secret' => '6Ldd1SUTAAAAAClOiQ45MFW7j6FxUjmdG57a9Aqk', 'response' => $response);
+
+    // use key 'http' even if you send the request to https://...
+    $options = array(
+        'http' => array(
+            'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
+            'method'  => 'POST',
+            'content' => http_build_query($data)
+        )
+    );
+    $context  = stream_context_create($options);
+    $result = file_get_contents($url, false, $context);
+    if ($result === FALSE) {
+      /* Handle error */
+      queue_message(new Message("Error checking recaptcha.", "danger"));
+      return false;
+    }
+
+    $json_result = json_decode($result);
+
+    return $json_result->{'success'};
+  }
+
+  function create_user() {
+    global $conn;
+
+    $fields = array('g-recaptcha-response', 'user', 'pass', 'mail');
+
+    foreach ($fields as $field)
+      if (!(isset($field))) {
+        queue_message(new Message("Missing field: $field", "danger"));
+        return;
+      }
+
+    // Handle captcha
+    if (!check_captcha($_POST['g-recaptcha-response'])) {
+      queue_message(new Message("Incorrect recaptcha answer, try again!", "warning"));
+      return;
+    }
+
+    // Hash password
+    $pass_hashed = password_hash($_POST['pass'], PASSWORD_DEFAULT);
+    $user = $_POST['user'];
+    $mail = $_POST['mail'];
+
+    // Create user
+    $sql = "INSERT INTO Users (User, Password) VALUES ('$user', '$pass_hashed')";
+
+    if ($conn->query($sql)) {
+      // Send activation e-mail
+      new_activation($user, "Email", $mail);
+      queue_message(new Message("User created successfully.", "success"));
+      header("Location: ../index.php");
+    } else {
+      queue_message(new Message("Error inserting into database, please contact site administrator.<br /> " . $conn->error, "danger"));
+    }
+  }
+  create_user();
+?>

BIN
login/favicon-lock.ico


+ 44 - 0
login/index.php

@@ -0,0 +1,44 @@
+<?php
+	require_once('app.php');
+?>
+<!DOCTYPE html>
+<html>
+	<head>
+		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/>
+		<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous"/>
+		<link rel="shortcut icon" href="favicon-lock.ico"/>
+		<meta charset='utf-8'/>
+		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+		<script type="text/javascript" src='https://www.google.com/recaptcha/api.js'></script>
+		<title><?php echo Config::$sitename ?> Login</title>
+	</head>
+
+	<body style="padding-top: 200px;">
+		<div class="container" style="">
+			<div class="row">
+			  <div class="col-md-6 col-md-offset-3">
+					<?php
+						list_messages();
+						$signup = isset($_GET['signup']);
+						$reset = isset($_GET['reset']);
+
+						if (isset($_GET['redirect']))
+							$redirect = $_GET['redirect'];
+						else if (!empty($_SERVER['HTTP_REFERER']))
+							$redirect = $_SERVER['HTTP_REFERER'];
+						else
+							$redirect =  "/";
+
+						if (isset($_SESSION['user'])) {
+							echo 'Already logged in.<a href="logout.php">Log out</a>';
+						} else if ($reset) {
+							include "reset.php";
+						} else {
+							include "login.php";
+						}
+					?>
+				</div>
+			</div>
+		</div>
+	</body>
+</html>

+ 35 - 0
login/login.php

@@ -0,0 +1,35 @@
+<div class="login-panel panel panel-default">
+    <div class="panel-heading">
+        <h3 class="panel-title"><i class="fa fa-lock"></i> <?php echo Config::$sitename . ($signup ? " account signup" : " login") ?></h3>
+    </div>
+    <div class="panel-body">
+        <form role="form" action="<?php echo ($signup ? "create.php" : "check_login.php") ?>" method="post">
+            <fieldset>
+                <div class="form-group">
+                    <input class="form-control" placeholder="Username" name="user" autofocus="" type="text">
+                </div>
+                <div class="form-group">
+                    <input class="form-control" placeholder="Password" name="pass" value="" type="password">
+                </div>
+								<input type="hidden" name="redirect" value="<?php echo $redirect ?>"/>
+								<?php
+									if ($signup) {
+										?>
+											<div class="form-group">
+													<input class="form-control" placeholder="E-mail" name="mail" autofocus="" type="email">
+											</div>
+											<div class="g-recaptcha" data-sitekey="6Ldd1SUTAAAAAGd4iI227uAD2GcRwjWcKSa2lQaJ"></div>
+											<input class="btn btn-primary btn-lg btn-block" type="submit" value="Sign up"/>
+										<?php
+									} else {
+										?>
+                    	<input class="btn btn-primary btn-lg btn-block" type="submit" value="Log in"/>
+											<br />
+											<a href="?signup&redirect=<?php echo $redirect ?>">Need an account?</a><a class="pull-right" href="?reset">Forgot your password?</a>
+										<?php
+									}
+								?>
+            </fieldset>
+        </form>
+    </div>
+</div>

+ 5 - 0
login/logout.php

@@ -0,0 +1,5 @@
+<?php
+	require 'app.php';
+	session_destroy();
+	header("Location: ../index.php");
+?>

+ 83 - 0
login/reset.php

@@ -0,0 +1,83 @@
+<?php
+  require_once('app.php');
+
+  if (isset($_POST['key'])) {
+    $key = $conn->escape_string($_POST['key']);
+    $sql = "SELECT userid FROM PasswordReset WHERE `key`='$key'";
+    if ($query = $conn->query($sql)) {
+      $userid = $query->fetch_array()['userid'];
+    } else {
+      queue_message(new Message("SQL error: " . $conn->error, "danger"));
+      header('Location: /');
+    }
+
+    $rawPass = $_POST['pass'];
+    $rawRepeat = $_POST['pass_repeat'];
+
+    if (changePassword($userid, $rawPass, $rawRepeat)) {
+      $conn->query("DELETE FROM PasswordReset WHERE `key`='$key'");
+    }
+  } else if (isset($_POST['email'])) {
+    $email = $conn->escape_string($_POST['email']);
+    $sql = "SELECT UID FROM Users WHERE Email='$email'";
+    if ($query = $conn->query($sql)) {
+      $userid = $query->fetch_array()['UID'];
+    } else {
+      queue_message(new Message("No account has that e-mail address registered.", "danger"));
+      header('Location: /');
+    }
+    $key = generateKey(32);
+    $sql = "INSERT INTO PasswordReset VALUES ('$userid', '$key')";
+    if ($conn->query($sql)) {
+      $external_url = Config::$external_url;
+      mail($email, Config::$sitename . " password reset", "To reset your password, navigate to this address: $external_url/login/?reset&key=$key");
+    } else {
+      echo $conn->error;
+    }
+  } else {
+    if (isset($_GET['key'])) {
+      $key = $_GET['key'];
+      ?>
+      <div class="login-panel panel panel-default">
+          <div class="panel-heading">
+              <h3 class="panel-title"><i class="fa fa-lock"></i> <?php echo Config::$sitename . " password reset" ?></h3>
+          </div>
+          <div class="panel-body">
+              <form role="form" action="" method="post">
+                  <fieldset>
+                      <div class="form-group">
+                          <input class="form-control" placeholder="New password" name="pass" autofocus="" type="password">
+                      </div>
+                      <div class="form-group">
+                          <input class="form-control" placeholder="Repeat password" name="pass_repeat" value="" type="password">
+                      </div>
+                      <input type="hidden" name="key" value="<?php echo $key ?>" />
+                      <input class="btn btn-primary btn-lg btn-block" type="submit" value="Reset password"/>
+                  </fieldset>
+              </form>
+          </div>
+      </div>
+      <?php
+    } else {
+      ?>
+      <div class="login-panel panel panel-default">
+          <div class="panel-heading">
+              <h3 class="panel-title"><i class="fa fa-lock"></i> <?php echo Config::$sitename . " password reset" ?></h3>
+          </div>
+          <div class="panel-body">
+              <form role="form" action="" method="post">
+                  <fieldset>
+                      <div class="form-group">
+                          <input class="form-control" placeholder="Account E-mail address" name="email" autofocus="" type="email">
+                      </div>
+                      <input class="btn btn-primary btn-lg btn-block" type="submit" value="Send reset link"/>
+                  </fieldset>
+              </form>
+          </div>
+      </div>
+      <?php
+    }
+    die();
+  }
+  header('Location: /');
+?>