From 5214c96b90a6d7a1a4b924393dfe5da7620cb2c8 Mon Sep 17 00:00:00 2001 From: Janis Steiner Date: Sat, 28 Dec 2024 17:15:57 +0100 Subject: [PATCH] adding keepmeloggedin --- README.md | 2 +- app-code/account/index.php | 12 +++- app-code/api/login/delete_keepmeloggedin.php | 15 ++++ app-code/api/login/keepmeloggedin.php | 36 ++++++++++ app-code/api/login/redirect.php | 44 +++++------- app-code/api/login/reset_pw.php | 2 +- app-code/api/login/send_reset_link.php | 9 ++- app-code/api/utils/check_keepmeloggedin.php | 65 +++++++++++++++++ app-code/api/utils/get_location.php | 27 ++++++++ app-code/index.php | 14 +++- app-code/install/create_db.php | 20 +++++- app-code/jakach_logo.ico | Bin 0 -> 25642 bytes app-code/login/keepmeloggedin.php | 69 +++++++++++++++++++ app-code/login/logout.php | 1 + app-code/login/passkey.php | 13 +++- app-code/plugins/auth.php | 2 +- 16 files changed, 293 insertions(+), 38 deletions(-) create mode 100644 app-code/api/login/delete_keepmeloggedin.php create mode 100644 app-code/api/login/keepmeloggedin.php create mode 100644 app-code/api/utils/check_keepmeloggedin.php create mode 100644 app-code/api/utils/get_location.php create mode 100644 app-code/jakach_logo.ico create mode 100644 app-code/login/keepmeloggedin.php diff --git a/README.md b/README.md index 9f6bf19..1059003 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ To integrate Jakach Login into your application: 4. **Add login button:** In your app/login page add a button like: ```html - Log in using Jakach login + Log in using Jakach login ``` --- diff --git a/app-code/account/index.php b/app-code/account/index.php index 5e3dc2a..2abd82d 100644 --- a/app-code/account/index.php +++ b/app-code/account/index.php @@ -54,6 +54,13 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) { + + people + '); + } + ?> @@ -96,6 +103,7 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) { + Delete all "remember me" sessions @@ -566,7 +574,9 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) { location.href = location.href.replace('http', 'https'); } } - + function delete_all_logmein(){ + fetch("/api/login/delete_keepmeloggedin.php"); + } diff --git a/app-code/api/login/delete_keepmeloggedin.php b/app-code/api/login/delete_keepmeloggedin.php new file mode 100644 index 0000000..800a08d --- /dev/null +++ b/app-code/api/login/delete_keepmeloggedin.php @@ -0,0 +1,15 @@ + diff --git a/app-code/api/login/keepmeloggedin.php b/app-code/api/login/keepmeloggedin.php new file mode 100644 index 0000000..c014627 --- /dev/null +++ b/app-code/api/login/keepmeloggedin.php @@ -0,0 +1,36 @@ + 'success' + ]; + echo(json_encode($data)); + +}else{ + $_SESSION["keepmeloggedin_asked"]=true; + $data = [ + 'status' => 'success' + ]; + echo(json_encode($data)); +} + + +?> diff --git a/app-code/api/login/redirect.php b/app-code/api/login/redirect.php index 29e536c..20f1e99 100644 --- a/app-code/api/login/redirect.php +++ b/app-code/api/login/redirect.php @@ -2,31 +2,7 @@ session_start(); header('Content-Type: application/json'); - -function get_location_from_ip($ip) { - // Use ip-api.com to fetch geolocation data - $url = "http://ip-api.com/json/$ip"; - - // Initialize curl - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - // Execute curl and decode the JSON response - $response = curl_exec($ch); - curl_close($ch); - - // Convert JSON response to PHP array - $data = json_decode($response, true); - - // Check for a successful response - if ($data && $data['status'] === 'success') { - return $data; // Return the geolocation data - } - - return null; // Return null if API call fails -} - +include "../utils/get_location.php"; $send_to=$_SESSION["end_url"]; @@ -57,7 +33,16 @@ else if($_SESSION["needs_auth"]===false && $_SESSION["mfa_required"]==1 && $_SES 'redirect' => '/login/passkey.php' ]; echo(json_encode($data)); -}*/else if ($_SESSION["needs_auth"]===false && $_SESSION["mfa_authenticated"]==1 && $_SESSION["pw_authenticated"]==1){ +}*/ +else if ($_SESSION["needs_auth"]===false && $_SESSION["mfa_authenticated"]==1 && $_SESSION["pw_authenticated"]==1 && $_SESSION["keepmeloggedin_asked"]==false){ + //send to keepmelogged in question + $data=[ + 'message' => 'ask_keepmeloggedin', + 'redirect' => '/login/keepmeloggedin.php' + ]; + echo(json_encode($data)); +} +else if ($_SESSION["needs_auth"]===false && $_SESSION["mfa_authenticated"]==1 && $_SESSION["pw_authenticated"]==1){ //fully authenticated //create auth token which other services can then use to check if user logged in $user_id=$_SESSION["id"]; @@ -133,7 +118,7 @@ else{ $username=$_SESSION["username"]; $_SESSION["needs_auth"]=false; $_SESSION["logged_in"]=false; - $sql="SELECT auth_method_required_pw, auth_method_required_2fa, auth_method_required_passkey, id, user_token,last_login, login_message,telegram_id FROM users WHERE username = ?"; + $sql="SELECT auth_method_required_pw, auth_method_required_2fa, auth_method_required_passkey, id, user_token,last_login, login_message,telegram_id, permissions FROM users WHERE username = ?"; $stmt = mysqli_prepare($conn, $sql); mysqli_stmt_bind_param($stmt, 's', $username); mysqli_stmt_execute($stmt); @@ -145,8 +130,9 @@ else{ $last_login=""; $login_message=0; $telegram_id=""; + $permissions=""; if(mysqli_stmt_num_rows($stmt) == 1){ - mysqli_stmt_bind_result($stmt, $pw,$mfa,$passkey,$user_id,$user_token,$last_login,$login_message,$telegram_id); + mysqli_stmt_bind_result($stmt, $pw,$mfa,$passkey,$user_id,$user_token,$last_login,$login_message,$telegram_id,$permissions); mysqli_stmt_fetch($stmt); $_SESSION["pw_required"] = $pw; $_SESSION["pw_authenticated"] = ($pw == 0) ? 1 : 0; // If $pw is 0, set pw_authenticated to 1 @@ -159,6 +145,8 @@ else{ $_SESSION["last_login"]=$last_login; $_SESSION["telegram_id"]=$telegram_id; $_SESSION["login_message"]=$login_message; + $_SESSION["permissions"]=$permissions; + $_SESSION["keepmeloggedin_asked"]=false; $data=[ 'message' => 'prepared_start_auth', 'redirect' => '/login/' diff --git a/app-code/api/login/reset_pw.php b/app-code/api/login/reset_pw.php index 3981fcd..be1ba6b 100644 --- a/app-code/api/login/reset_pw.php +++ b/app-code/api/login/reset_pw.php @@ -53,7 +53,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } }else { mysqli_stmt_close($stmt); - echo json_encode(['success' => false, 'message' => 'Ivalid auth token']); + echo json_encode(['success' => false, 'message' => 'Invalid auth token']); } //remove token $sql="DELETE FROM reset_tokens WHERE auth_token = ?;"; diff --git a/app-code/api/login/send_reset_link.php b/app-code/api/login/send_reset_link.php index 0821ae5..d543fdf 100644 --- a/app-code/api/login/send_reset_link.php +++ b/app-code/api/login/send_reset_link.php @@ -2,6 +2,7 @@ session_start(); header('Content-Type: application/json'); include "../../config/config.php"; +include "../utils/get_location.php"; $username=$_SESSION["username"]; $sql="SELECT id, email, telegram_id FROM users WHERE username = ?;"; $conn = new mysqli($DB_SERVERNAME, $DB_USERNAME, $DB_PASSWORD, $DB_DATABASE); @@ -18,9 +19,10 @@ mysqli_stmt_close($stmt); //send telegram message $device = $_SERVER['HTTP_USER_AGENT']; $ip=$_SERVER["REMOTE_ADDR"]; +$location=get_location_from_ip($ip); $date=date('Y-m-d H:i:s'); $token=bin2hex(random_bytes(128)); -$link="https://jakach.duckdns.org:444/login/reset_pw.php?token=$token"; +$link="https://jakach-auth.duckdns.org:444/login/reset_pw.php?token=$token"; $message = "*Password reset token*\n\n" . "You have requested the reset of your password here is your reset link.\n\n" @@ -28,6 +30,7 @@ $message = "*Password reset token*\n\n" . "*Details of this request:*\n" . "• *Date&Time*: $date\n" . "• *Device&Browser*: $device\n" + . "*Location*: ".$location["country"].", ".$location["state"].", ".$location["city"]."\n" . "• *Account*: ".$_SESSION["username"]."\n" . "• *IP*: $ip\n\n" ."If this was you, you can reset your password. If this was not you somebody else tried to reset your password!\n" @@ -54,6 +57,7 @@ curl_exec($ch); curl_close($ch); //send mail if(!empty($mail)){ + $loc=$location["country"].", ".$location["state"].", ".$location["city"]; $content = " @@ -125,6 +129,7 @@ if(!empty($mail)){
  • Device & Browser: $device
  • Account: $mail
  • IP Address: $ip
  • +
  • Location: $loc
  • If this was you, you can reset your password. If this was not you, someone else may have tried to reset your password.

    @@ -182,7 +187,7 @@ if(!empty($mail)){ //insert the token into our db -$valid_until=time()+8600; +$valid_until=time()+(8600/2); $sql="INSERT INTO reset_tokens (auth_token, user_id,valid_until) VALUES (?,?,?);"; $stmt = mysqli_prepare($conn, $sql); mysqli_stmt_bind_param($stmt, 'sii', $token,$id,$valid_until); diff --git a/app-code/api/utils/check_keepmeloggedin.php b/app-code/api/utils/check_keepmeloggedin.php new file mode 100644 index 0000000..8e60d54 --- /dev/null +++ b/app-code/api/utils/check_keepmeloggedin.php @@ -0,0 +1,65 @@ + diff --git a/app-code/api/utils/get_location.php b/app-code/api/utils/get_location.php new file mode 100644 index 0000000..a14b824 --- /dev/null +++ b/app-code/api/utils/get_location.php @@ -0,0 +1,27 @@ + diff --git a/app-code/index.php b/app-code/index.php index 519399c..522c3cd 100644 --- a/app-code/index.php +++ b/app-code/index.php @@ -8,12 +8,20 @@ Jakach Login @@ -41,6 +49,8 @@ Account Erstellen +
    + @@ -77,7 +87,7 @@ // Get the username input value const usernameInput = document.getElementById('username'); const username = usernameInput.value; - + // Check if username is empty (just in case) if (!username) { alert('Please enter a username.'); diff --git a/app-code/install/create_db.php b/app-code/install/create_db.php index 18a91b2..2e38536 100644 --- a/app-code/install/create_db.php +++ b/app-code/install/create_db.php @@ -74,7 +74,6 @@ permissions VARCHAR(255), color_profile INT, auth_key VARCHAR(255), - keepmeloggedin_token VARCHAR(255), auth_method_keepmeloggedin_enabled INT, auth_method_enabled_2fa INT, auth_method_enabled_pw INT, @@ -135,6 +134,25 @@ '; } + $sql="CREATE TABLE IF NOT EXISTS keepmeloggedin ( + id INT AUTO_INCREMENT PRIMARY KEY, + auth_token VARCHAR(256), + user_id INT, + agent VARCHAR(255) + );"; + + + if ($conn->query($sql) === TRUE) { + echo '
    '; + } else { + $success=0; + echo '
    '; + } + if($success!==1){ diff --git a/app-code/jakach_logo.ico b/app-code/jakach_logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..9bad3de48a98039af26184d058a91a8f3d7e76fc GIT binary patch literal 25642 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�RUvLP4bw{q%7`rj+bV0 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 + + + + + Jakach Login + + + +
    +
    +
    + +
    +
    +

    Jakach Login

    + +
    + + +
    +
    +
    +
    +
    +
    + + + + + + diff --git a/app-code/login/logout.php b/app-code/login/logout.php index 361dbd3..a3efd04 100644 --- a/app-code/login/logout.php +++ b/app-code/login/logout.php @@ -2,5 +2,6 @@ session_start(); session_unset(); session_destroy(); + setcookie("auth_token", "", time() - 3600, "/"); header("LOCATION:/"); ?> diff --git a/app-code/login/passkey.php b/app-code/login/passkey.php index 53addcc..d49c7ad 100644 --- a/app-code/login/passkey.php +++ b/app-code/login/passkey.php @@ -22,7 +22,9 @@
    - +
    @@ -58,6 +60,15 @@ function showErrorModal(message) { errorModal.show(); } async function checkRegistration() { + const button = document.getElementById("loginButton"); + const buttonText = document.getElementById("buttonText"); + + // Disable the button to prevent multiple clicks + button.disabled = true; + + // Change the button text and add a loading spinner + buttonText.innerHTML = 'Loading...'; + button.innerHTML += '
    Loading...
    '; try { if (!window.fetch || !navigator.credentials || !navigator.credentials.create) { diff --git a/app-code/plugins/auth.php b/app-code/plugins/auth.php index b44f0cf..0f2e739 100644 --- a/app-code/plugins/auth.php +++ b/app-code/plugins/auth.php @@ -6,7 +6,7 @@ This file can be installed in any service. If done so a user can authenticate wi $auth_token = $_GET["auth"]; // Check the auth token against Jakach login API -$check_url = "https://jakach.duckdns.org:444/api/auth/check_auth_key.php?auth_token=" . $auth_token; +$check_url = "https://jakach-auth.duckdns.org:444/api/auth/check_auth_key.php?auth_token=" . $auth_token; // Initialize cURL $ch = curl_init();