255 lines
8.4 KiB
PHP
255 lines
8.4 KiB
PHP
<?php
|
|
|
|
class Auth {
|
|
private static $instance = null;
|
|
private $isLoggedIn = false;
|
|
|
|
private function __construct(){
|
|
session_start();
|
|
}
|
|
|
|
public static function getInstance(): Auth {
|
|
if(self::$instance == null){
|
|
self::$instance = new Auth();
|
|
}
|
|
|
|
return self::$instance;
|
|
}
|
|
|
|
public static function loginWithCredentials($email, $pass, bool $stayLoggedIn = false){
|
|
session_destroy();
|
|
self::$instance = null;
|
|
$Auth = Auth::getInstance();
|
|
|
|
$err = [];
|
|
|
|
if(strlen($email) < 3){
|
|
$err[] = __("Please enter a valid email.");
|
|
}
|
|
if(strlen($pass) < 3){
|
|
$err[] = __("Please enter a valid password. Hint: The passwords need to have at least 6 characters.");
|
|
}
|
|
|
|
if(!empty($err)){ return $err; }
|
|
|
|
// get user from database
|
|
$getUserSQL = "SELECT pwd, user_id, user_email FROM user WHERE user_email = ? LIMIT 1;";
|
|
$getUserRes = DB::query($getUserSQL, $email);
|
|
|
|
$dbPass = "missingPassword";
|
|
$dbUserId = 0;
|
|
$dbUserName = "Unknown";
|
|
|
|
if($getUserRes->num_rows == 1){
|
|
// Verify password
|
|
list($dbPass, $dbUserId, $dbUserName) = $getUserRes->fetch_row();
|
|
}
|
|
|
|
if(password_verify(PwdGen($pass), $dbPass)){
|
|
session_regenerate_id();
|
|
|
|
$md5agent = md5($_SERVER['HTTP_USER_AGENT']);
|
|
$userKey = GenKey();
|
|
$shaUserKey = sha1($userKey);
|
|
$expire = $stayLoggedIn?30:0; // if "stay logged in", stay logged in for 30 days.
|
|
$ctime = time();
|
|
|
|
$updateUserSQL = "INSERT INTO user_login (user_id, ckey, ctime, expire, agent) VALUES (?, ?, ?, ?, ?);";
|
|
try {
|
|
DB::query($updateUserSQL, $dbUserId, $userKey, $ctime, $expire, $md5agent);
|
|
$_SESSION['user_id'] = $dbUserId;
|
|
$_SESSION['user_name'] = $dbUserName;
|
|
$_SESSION['user_agent'] = $md5agent;
|
|
$_SESSION['user_key'] = $shaUserKey;
|
|
$_SESSION['user_ctime'] = $ctime;
|
|
|
|
if($stayLoggedIn){
|
|
setcookie("auth", $shaUserKey.".".$dbUserId, time() + (30 * 24*60*60), "/", $_SERVER['HTTP_HOST'], isset($_SERVER['HTTPS']), true );
|
|
}
|
|
return true;
|
|
}
|
|
catch(DatabaseException $e){
|
|
$err[] = __("Failed to login.")."\n".$e;
|
|
}
|
|
}
|
|
else {
|
|
$err[] = __("The provided combination of username and password is not recognized in the system. Verify your details or create an account.");
|
|
}
|
|
|
|
return $err;
|
|
}
|
|
|
|
|
|
public static function loginFromAuthKey(): bool {
|
|
if(isset($_COOKIE['auth'])){
|
|
$md5agent = md5($_SERVER['HTTP_USER_AGENT']);
|
|
|
|
$cookieSplode = explode('.', $_COOKIE['auth']);
|
|
if(count($cookieSplode) == 2){
|
|
$tkey = $cookieSplode[0];
|
|
$tuid = $cookieSplode[1];
|
|
$verifyLoginCookieRes = DB::query("
|
|
SELECT ul.user_id, ul.ckey, ul.ctime, ul.expire, ul.agent, u.full_name
|
|
FROM user_login ul
|
|
INNER JOIN user u ON ul.user_id = u.user_id
|
|
WHERE ul.user_id = ?
|
|
ORDER BY ctime DESC", $tuid);
|
|
while($row = $verifyLoginCookieRes->fetch_assoc()){
|
|
if($row['expire'] == 0){ $row['expire'] = 1; }
|
|
if(
|
|
sha1($row['ckey']) == $tkey &&
|
|
$row['agent'] == $md5agent &&
|
|
($row['ctime']+($row['expire']*24*60*60) > time())
|
|
){
|
|
session_regenerate_id();
|
|
$_SESSION['user_id'] = $row['user_id'];
|
|
$_SESSION['user_name'] = $row['full_name'];
|
|
$_SESSION['user_agent'] = $md5agent;
|
|
$_SESSION['user_key'] = sha1($row['ckey']);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static function logout($everywhere = false){
|
|
if(Auth::checkLogin()){
|
|
$logoutSql = "DELETE FROM user_login WHERE user_id = ?";
|
|
$sqlparams[] = $_SESSION['user_id'];
|
|
if(!$everywhere){
|
|
// $logoutSql .= " AND agent = ?";
|
|
// $sqlparams[] = md5($_SERVER['HTTP_USER_AGENT']);
|
|
$logoutSql .= " AND ctime = ?";
|
|
$sqlparams[] = $_SESSION['user_ctime'];
|
|
}
|
|
|
|
DB::query($logoutSql, $sqlparams);
|
|
}
|
|
|
|
// Delete session-cookie
|
|
$params = session_get_cookie_params();
|
|
setcookie(session_name(), '', time() - 42000,
|
|
$params["path"], $params["domain"],
|
|
$params["secure"], $params["httponly"]
|
|
);
|
|
|
|
setcookie('auth', '', time() - 42000, "/", $_SERVER['HTTP_HOST'], isset($_SERVER['HTTPS']), true );
|
|
|
|
// Finally, destroy the session.
|
|
session_destroy();
|
|
}
|
|
|
|
|
|
public static function register($userEmail, $userPass, $metadata = []){
|
|
$err = [];
|
|
|
|
$userName = $metadata['newName'] ?? '';
|
|
|
|
if(strlen($userPass) < 6){
|
|
$err[] = __("Password is too short. Password needs to be at least 6 characters!");
|
|
}
|
|
else if(strlen($userPass) > 30){
|
|
$err[] = __("Password is too long. Max length is set to 30 characters. If you believe it should be higher please contact the developers.");
|
|
}
|
|
|
|
if(strlen($userEmail) > 220){
|
|
$err[] = __("Your email-address is too long. Can you please register with another email?");
|
|
}
|
|
|
|
if(strlen($userName) > 200){
|
|
$err[] = __("Your name seems to be too long to fit this system. Maybe you can short it down somehow?");
|
|
}
|
|
|
|
if(empty($err)){
|
|
// HASH PASSWORD
|
|
$newPass = PwdGen($userPass, true);
|
|
|
|
$createUserSQL = "INSERT INTO user SET user_email = ?, pwd = ?, full_name = ?;";
|
|
try {
|
|
DB::query($createUserSQL, $userEmail, $newPass, $userName);
|
|
$newID = DB::insert_id();
|
|
|
|
if(empty($newID)){ return false; }
|
|
|
|
$updateUserSQL = "UPDATE user SET md5_id = ? WHERE user_id = ?;";
|
|
DB::query($updateUserSQL, md5($newID), $newID);
|
|
|
|
return true;
|
|
} catch (DatabaseException $e) {
|
|
$err[] = __("Something went wrong").":<br>" . $e;
|
|
}
|
|
}
|
|
|
|
return $err;
|
|
}
|
|
|
|
public static function checkLogin($strict = false): bool {
|
|
$Auth = Auth::getInstance();
|
|
|
|
if(
|
|
($Auth->isLoggedIn && !$strict) ||
|
|
$Auth->checkSessionLogin() ||
|
|
$Auth->loginFromAuthKey()
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
unset($_SESSION['user_id']);
|
|
return false;
|
|
}
|
|
|
|
private function checkSessionLogin(): bool {
|
|
if(isset($_SESSION['user_id'])){
|
|
$md5agent = md5($_SERVER['HTTP_USER_AGENT']);
|
|
if($md5agent == @$_SESSION['user_agent']){
|
|
$verifyLoginSessionRes = DB::query("
|
|
SELECT expire, ctime, ckey
|
|
FROM `user_login`
|
|
WHERE user_id = ?
|
|
AND agent = ?",
|
|
$_SESSION['user_id'], $md5agent);
|
|
|
|
while ($row = $verifyLoginSessionRes->fetch_assoc()){
|
|
if(
|
|
(sha1($row['ckey']) == $_SESSION['user_key']) &&
|
|
($row['expire'] == 0 || $row['ctime']+($row['expire']*24*60*60) > time())
|
|
){
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function PwdGen($pass, $returnHashed = false): string {
|
|
$pepper = Config::get('security', 'pepper', 'IAmBadAtSecurity');
|
|
$pwd_peppered = hash_hmac("sha256", $pass, $pepper);
|
|
if(!$returnHashed){
|
|
return $pwd_peppered;
|
|
}
|
|
|
|
return password_hash($pwd_peppered, PASSWORD_ARGON2ID, ['threads' => 2]);
|
|
}
|
|
|
|
function GenKey($length = 21): string{
|
|
$password = "";
|
|
$possible = "0123456789abcdefghijkmnopqrstuvwxyz";
|
|
|
|
$i = 0;
|
|
|
|
while($i < $length){
|
|
$char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
|
|
|
|
if(!strstr($password, $char)){
|
|
$password .= $char;
|
|
$i++;
|
|
}
|
|
}
|
|
|
|
return $password;
|
|
} |