192 lines
5.6 KiB
PHP
192 lines
5.6 KiB
PHP
<?PHP
|
|
/**
|
|
* Login script.
|
|
*
|
|
* @author Joshua Ramon Enslin <joshua@jrenslin.de>
|
|
*/
|
|
|
|
// Load settings
|
|
|
|
// Demand HTTPS
|
|
if (!isset($_SERVER['HTTPS']) or $_SERVER['HTTPS'] != 'on') {
|
|
header("Location: ../"); exit;
|
|
}
|
|
|
|
// Ensure file for user settings is 0644.
|
|
if (substr(sprintf('%o', fileperms(__DIR__ . '/../data/users.json')), -4) != 0600) chmod(__DIR__ . '/../data/users.json', 0600);
|
|
|
|
// Get available login information
|
|
|
|
$loginInformation = json_decode(file_get_contents(__DIR__ . '/../data/users.json'), True);
|
|
define("loginLogFile", __DIR__ . "/../data/logins.csv");
|
|
|
|
/**
|
|
* Function for printing the login page
|
|
*
|
|
* @param string $error_msg Error message to print. Optional.
|
|
* @param string $cssFile CSS file.
|
|
*
|
|
* @return void
|
|
*/
|
|
function showLoginPasswordProtect($error_msg = "", $cssFile = "themes/default/theme.css") {
|
|
|
|
echo '<!DOCTYPE html>
|
|
<html id="loginPage">
|
|
<head>
|
|
<meta http-equiv="Content-Security-Policy" content="default-src \'none\'; script-src \'none\'; connect-src \'none\'; style-src \'self\'; font-src \'self\';" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
|
|
<meta charset="UTF-8" />
|
|
<title>Log In</title>
|
|
<link rel="stylesheet" type="text/css" href="' . $cssFile . '" />
|
|
</head>
|
|
<body>
|
|
<h1>Log In</h1>';
|
|
if ($error_msg) echo '<p id="errorMsg">'.$error_msg.'</p>';
|
|
echo '
|
|
<form action="" method="POST">
|
|
<input type="text" name="username" placeholder="Username" required autofocus />
|
|
<input type="password" name="password" placeholder="Password" required />
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
</body>
|
|
</html>
|
|
';
|
|
|
|
die();
|
|
|
|
}
|
|
|
|
/**
|
|
* Logout function: Unsets all relevant session variables.
|
|
*
|
|
* @return void
|
|
*/
|
|
function logout() {
|
|
$loginVariables = array("username", "userlevel", "userLastLogin", "userLang");
|
|
foreach ($loginVariables as $var) {
|
|
if (isset($_SESSION[$var])) unset($_SESSION[$var]);
|
|
}
|
|
header("Location: ../");
|
|
}
|
|
|
|
/**
|
|
* Function for Logging logins.
|
|
*
|
|
* @return void
|
|
*/
|
|
function logLogin() {
|
|
file_put_contents(loginLogFile, $_SESSION['username'].'|'.date("Y-m-d H:i:s").PHP_EOL, FILE_APPEND | LOCK_EX);
|
|
// Ensure file for user settings is 0644.
|
|
if (substr(sprintf('%o', fileperms(loginLogFile)), -4) != 0600) chmod(loginLogFile, 0600);
|
|
}
|
|
|
|
/**
|
|
* Prevent brute force attacks
|
|
*
|
|
* @return void
|
|
*/
|
|
function preventBruteForce() {
|
|
|
|
if (!isset($_SESSION['loginattempt'])) $_SESSION['loginattempt'] = array();
|
|
|
|
$_SESSION['loginattempt'][] = date("Y-m-d H:i:s");
|
|
|
|
if (count($_SESSION['loginattempt']) > 3) {
|
|
|
|
$secondtolastattempt = strtotime($_SESSION['loginattempt'][count($_SESSION['loginattempt']) - 3]);
|
|
$lastattempt = strtotime($_SESSION['loginattempt'][count($_SESSION['loginattempt']) - 2]);
|
|
|
|
$logindelay = (intval(count($_SESSION['loginattempt'])) * 20);
|
|
$sincelastlogin = strtotime(date("Y-m-d H:i:s")) - $lastattempt;
|
|
|
|
if ($sincelastlogin < $logindelay) showLoginPasswordProtect("You failed logging in too often, try again in $logindelay seconds.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Check for validity of username / password combination.
|
|
*
|
|
* @param mixed[] $loginInformation Array containing all login information.
|
|
* @param string $username Username to check.
|
|
*
|
|
* @return void
|
|
*/
|
|
function checkLoginValidity(array $loginInformation, $username) {
|
|
if (!isset($loginInformation[$username])) showLoginPasswordProtect("Incorrect username");
|
|
}
|
|
|
|
// Main part of the script
|
|
|
|
if (isset($_GET['logout'])) logout(); // Log out if so requested
|
|
|
|
// Check for expiry
|
|
|
|
else if (isset($_SESSION['username'])) {
|
|
|
|
checkLoginValidity($loginInformation, $_SESSION["username"]);
|
|
|
|
// Check for expiry of login
|
|
if (isset($_SESSION["userLastLogin"]) and strtotime(date("Y-m-d H:i:s")) - strtotime($_SESSION["userLastLogin"]) > 3600) logout();
|
|
|
|
// Renew last login time
|
|
$_SESSION["userLastLogin"] = date("Y-m-d H:i:s");
|
|
|
|
}
|
|
|
|
// If the corresponding POST vars are set, check for
|
|
|
|
else if (isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW'])) {
|
|
|
|
preventBruteForce();
|
|
checkLoginValidity($loginInformation, $_SERVER['PHP_AUTH_USER']);
|
|
|
|
if (password_verify($loginInformation[$_SERVER['PHP_AUTH_USER']]['password'], $_SERVER['PHP_AUTH_PW'])) showLoginPasswordProtect("Incorrect password");
|
|
|
|
// Set username
|
|
$_SESSION["username"] = $_SERVER['PHP_AUTH_USER'];
|
|
|
|
// Set last access time
|
|
$_SESSION["userLastLogin"] = date("Y-m-d H:i:s");
|
|
|
|
if (isset($_SESSION['loginattempt'])) unset($_SESSION['loginattempt']);
|
|
|
|
// Log login time
|
|
logLogin();
|
|
|
|
}
|
|
else if (isset($_POST['username']) and isset($_POST['password'])) {
|
|
|
|
preventBruteForce();
|
|
checkLoginValidity($loginInformation, $_POST['username']);
|
|
if (password_verify($loginInformation[$_POST['username']]['password'], $_POST['username'])) showLoginPasswordProtect("Incorrect password");
|
|
|
|
// Set username
|
|
$_SESSION["username"] = $_POST['username'];
|
|
|
|
// Set last access time
|
|
$_SESSION["userLastLogin"] = date("Y-m-d H:i:s");
|
|
if ($loginInformation[$_POST['username']]['admin'] or count($loginInformation) == 1) {
|
|
$_SESSION['admin'] = true;
|
|
}
|
|
else $_SESSION['admin'] = false;
|
|
|
|
if (isset($_SESSION['loginattempt'])) unset($_SESSION['loginattempt']);
|
|
|
|
// Log login time
|
|
logLogin();
|
|
|
|
}
|
|
|
|
// If nothing happens, offer login page
|
|
|
|
else showLoginPasswordProtect();
|
|
|
|
// End script
|
|
|
|
unset($loginInformation); // Unset array containing login information
|
|
|
|
?>
|