adding functionalitiy to send login messages via telegram and password reset links via telegram/email

This commit is contained in:
Janis Steiner
2024-12-27 20:36:44 +01:00
parent 9e16e6b29a
commit 8be17ce8df
12 changed files with 616 additions and 18 deletions

View File

@@ -15,16 +15,18 @@ include "../../config/config.php";
$conn = new mysqli($DB_SERVERNAME, $DB_USERNAME, $DB_PASSWORD, $DB_DATABASE);
$username=$_SESSION["username"];
$sql="SELECT id, email, telegram_id, auth_method_enabled_2fa FROM users WHERE username = ?";
$sql="SELECT id, email, telegram_id, auth_method_enabled_2fa, user_token, login_message FROM users WHERE username = ?";
$id=0;
$email="";
$telegram_id="";
$twofa_enabled="";
$user_token="";
$login_message=0;
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 's', $username);
mysqli_stmt_execute($stmt);
mysqli_stmt_store_result($stmt);
mysqli_stmt_bind_result($stmt, $id,$email,$telegram_id,$twofa_enabled);
mysqli_stmt_bind_result($stmt, $id,$email,$telegram_id,$twofa_enabled,$user_token,$login_message);
mysqli_stmt_fetch($stmt);
$_SESSION["id"]=$id;
@@ -33,7 +35,10 @@ $user_data = [
"name" => $username,
"email" => $email,
"telegram_id" => $telegram_id,
"twofa_enabled" => $twofa_enabled
"twofa_enabled" => $twofa_enabled,
"user_token"=>$user_token,
"last_login"=>$_SESSION["last_login"],
"login_message"=>$login_message
];
// Send JSON response

View File

@@ -0,0 +1,67 @@
<?php
session_start();
header('Content-Type: application/json');
// Check if the user is logged in
if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) {
echo json_encode([
'success' => false,
'message' => 'Not logged in'
]);
exit();
}
// Include database configuration
include "../../config/config.php";
// Create a new database connection
$conn = new mysqli($DB_SERVERNAME, $DB_USERNAME, $DB_PASSWORD, $DB_DATABASE);
// Check for database connection errors
if ($conn->connect_error) {
echo json_encode([
'success' => false,
'message' => 'Database connection failed: ' . $conn->connect_error
]);
exit();
}
// Get the logged-in user's ID and username from the session
$id = $_SESSION["id"];
$username = $_SESSION["username"];
// Get the raw POST data (JSON)
$data = json_decode(file_get_contents("php://input"));
if($data->enable_message==true){
$sql="UPDATE users SET login_message=1 WHERE id = ?";
if ($update_stmt = $conn->prepare($sql)) {
$update_stmt->bind_param("i", $id);
if ($update_stmt->execute()) {
echo json_encode(['success' => true, 'message' => 'Login messages enabled.']);
} else {
echo json_encode(['success' => false, 'message' => 'Failed to enable login messages.']);
}
$update_stmt->close();
} else {
echo json_encode(['success' => false, 'message' => 'Database error.']);
}
}
if($data->enable_message==false){
//create 2fa secret key
$sql="UPDATE users SET login_message=0 WHERE id = ?";
if ($update_stmt = $conn->prepare($sql)) {
$update_stmt->bind_param("i",$id);
if ($update_stmt->execute()) {
echo json_encode(['success' => true, 'message' => 'Login messages disabled.']);
} else {
echo json_encode(['success' => false, 'message' => 'Failed to disable login messages.']);
}
$update_stmt->close();
} else {
echo json_encode(['success' => false, 'message' => 'Database error.']);
}
}
?>

View File

@@ -1,6 +1,33 @@
<?php
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
}
$send_to=$_SESSION["end_url"];
include "../../config/config.php";
@@ -32,7 +59,6 @@ else if($_SESSION["needs_auth"]===false && $_SESSION["mfa_required"]==1 && $_SES
echo(json_encode($data));
}*/else if ($_SESSION["needs_auth"]===false && $_SESSION["mfa_authenticated"]==1 && $_SESSION["pw_authenticated"]==1){
//fully authenticated
$_SESSION["logged_in"]=true;
//create auth token which other services can then use to check if user logged in
$user_id=$_SESSION["id"];
$auth_token=bin2hex(random_bytes(128));
@@ -49,9 +75,56 @@ else if($_SESSION["needs_auth"]===false && $_SESSION["mfa_required"]==1 && $_SES
}else{
$data=[
'message' => 'done',
'redirect' => ''
'redirect' => '/account/'
];
}
//update last login
$ip=$_SERVER["REMOTE_ADDR"];
$date=date('Y-m-d H:i:s');
$last_login_msg=$date." from ".$ip;
$sql="UPDATE users SET last_login = ? WHERE id = ?";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 'si', $last_login_msg,$user_id);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
//send login message
if($_SESSION["login_message"] && $_SESSION["logged_in"]!==true){
$device = $_SERVER['HTTP_USER_AGENT'];
$location=get_location_from_ip($ip);
$message = "⚠️ *Login Warning*\n\n"
. "We noticed a login attempt with your account.\n\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 ignore this message. If not, please secure your account immediately.";
// Telegram API URL
$url = "https://api.telegram.org/$TELEGRAM_BOT_API/sendMessage";
// Data to be sent in the POST request
$telegram_id=$_SESSION["telegram_id"];
$message_data = [
'chat_id' => $telegram_id,
'text' => $message,
'parse_mode' => 'Markdown', // Use Markdown for formatting
];
// Use cURL to send the request
$ch = curl_init();
// Construct the GET request URL
$query_string = http_build_query($message_data); // Converts the array to URL-encoded query string
$get_url = $url . '?' . $query_string; // Append query string to the base URL
curl_setopt($ch, CURLOPT_URL, $get_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Still retrieve the response if needed
curl_exec($ch);
curl_close($ch);
}
$_SESSION["logged_in"]=true;
echo(json_encode($data));
}
else{
@@ -60,7 +133,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 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 FROM users WHERE username = ?";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 's', $username);
mysqli_stmt_execute($stmt);
@@ -69,8 +142,11 @@ else{
$mfa=0;
$passkey=0;
$user_token="";
$last_login="";
$login_message=0;
$telegram_id="";
if(mysqli_stmt_num_rows($stmt) == 1){
mysqli_stmt_bind_result($stmt, $pw,$mfa,$passkey,$user_id,$user_token);
mysqli_stmt_bind_result($stmt, $pw,$mfa,$passkey,$user_id,$user_token,$last_login,$login_message,$telegram_id);
mysqli_stmt_fetch($stmt);
$_SESSION["pw_required"] = $pw;
$_SESSION["pw_authenticated"] = ($pw == 0) ? 1 : 0; // If $pw is 0, set pw_authenticated to 1
@@ -80,6 +156,9 @@ else{
$_SESSION["passkey_authenticated"] = ($passkey == 0) ? 1 : 0;
$_SESSION["id"]=$user_id;
$_SESSION["user_token"]=$user_token;
$_SESSION["last_login"]=$last_login;
$_SESSION["telegram_id"]=$telegram_id;
$_SESSION["login_message"]=$login_message;
$data=[
'message' => 'prepared_start_auth',
'redirect' => '/login/'

View File

@@ -0,0 +1,70 @@
<?php
// Check if the POST request contains 'token' and 'password'
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['token']) || !isset($_POST['password']) || !isset($_POST['confirm_password'])) {
echo json_encode(['status' => 'error', 'message' => 'Missing required fields.']);
exit;
}
include "../../config/config.php";
// Create a new database connection
$conn = new mysqli($DB_SERVERNAME, $DB_USERNAME, $DB_PASSWORD, $DB_DATABASE);
$token = $_POST['token'];
$user_id="";
$valid_until=0;
$password = $_POST['password'];
$confirmPassword = $_POST['confirm_password'];
$sql="SELECT user_id, valid_until FROM reset_tokens WHERE auth_token=?;";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 's', $token);
mysqli_stmt_execute($stmt);
mysqli_stmt_store_result($stmt);
mysqli_stmt_bind_result($stmt, $user_id,$valid_until);
mysqli_stmt_fetch($stmt);
if(mysqli_stmt_num_rows($stmt) > 0 && time()<$valid_until){
mysqli_stmt_close($stmt);
// Check if passwords match
if ($password !== $confirmPassword) {
echo json_encode(['status' => 'error', 'message' => 'Passwords do not match.']);
exit;
}
if (strlen($password)<12) {
echo json_encode(['status' => 'error', 'message' => 'Password must be at least 12 characters.']);
exit;
}
$new_pepper=bin2hex(random_bytes(32));
// Hash the password / a salt is added automaticly
$hashed_password = password_hash($password.$new_pepper, PASSWORD_BCRYPT);
// Update the password in the database
$update_sql = "UPDATE users SET password = ?, pepper = ? WHERE id = ?";
if ($update_stmt = $conn->prepare($update_sql)) {
$update_stmt->bind_param("ssi", $hashed_password, $new_pepper, $user_id);
if ($update_stmt->execute()) {
echo json_encode(['status' => 'success','success' => true, 'message' => 'Password updated successfully.']);
} else {
echo json_encode(['success' => false, 'message' => 'Failed to update password.']);
}
$update_stmt->close();
} else {
echo json_encode(['success' => false, 'message' => 'Database error.']);
}
}else {
mysqli_stmt_close($stmt);
echo json_encode(['success' => false, 'message' => 'Ivalid auth token']);
}
//remove token
$sql="DELETE FROM reset_tokens WHERE auth_token = ?;";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 's', $token);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
} else {
// If it's not a POST request, show error
echo json_encode(['status' => 'error', 'message' => 'Invalid request method.']);
}
?>

View File

@@ -0,0 +1,192 @@
<?php
session_start();
header('Content-Type: application/json');
include "../../config/config.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);
$mail="";
$id="";
$telegram_id="";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 's', $username);
mysqli_stmt_execute($stmt);
mysqli_stmt_store_result($stmt);
mysqli_stmt_bind_result($stmt,$id, $mail,$telegram_id);
mysqli_stmt_fetch($stmt);
mysqli_stmt_close($stmt);
//send telegram message
$device = $_SERVER['HTTP_USER_AGENT'];
$ip=$_SERVER["REMOTE_ADDR"];
$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";
$message = "*Password reset token*\n\n"
. "You have requested the reset of your password here is your reset link.\n\n"
. "*Link*: [click here]($link)\n\n"
. "*Details of this request:*\n"
. "• *Date&Time*: $date\n"
. "• *Device&Browser*: $device\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"
. "*Thank you for using Jakach login!*";
// Telegram API URL
$url = "https://api.telegram.org/$TELEGRAM_BOT_API/sendMessage";
$message_data = [
'chat_id' => $telegram_id,
'text' => $message,
'parse_mode' => 'Markdown', // Use Markdown for formatting
];
// Use cURL to send the request
$ch = curl_init();
// Construct the GET request URL
$query_string = http_build_query($message_data); // Converts the array to URL-encoded query string
$get_url = $url . '?' . $query_string; // Append query string to the base URL
curl_setopt($ch, CURLOPT_URL, $get_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Still retrieve the response if needed
curl_exec($ch);
curl_close($ch);
//send mail
if(!empty($mail)){
$content = "
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>Password Reset</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.email-container {
width: 100%;
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333;
font-size: 24px;
}
p {
color: #666;
font-size: 16px;
line-height: 1.5;
}
a {
color: #ffffff;
background-color: #007bff;
padding: 12px 20px;
text-decoration: none;
border-radius: 5px;
font-weight: bold;
display: inline-block;
}
a:hover {
background-color: #0056b3;
}
.footer {
font-size: 14px;
color: #888;
text-align: center;
margin-top: 20px;
}
.footer a {
color: #888;
text-decoration: none;
}
</style>
</head>
<body>
<div class='email-container'>
<h1>Password Reset Request</h1>
<p>Hi $mail,</p>
<p>You have requested a password reset link. Here it is:</p>
<p><a href='$link'>Click here to reset your password</a></p>
<p>If you did not request this, please ignore this email. If you did, you can reset your password using the link above.</p>
<p><strong>Request Details:</strong></p>
<ul>
<li><strong>Date & Time:</strong> $date</li>
<li><strong>Device & Browser:</strong> $device</li>
<li><strong>Account:</strong> $mail</li>
<li><strong>IP Address:</strong> $ip</li>
</ul>
<p>If this was you, you can reset your password. If this was not you, someone else may have tried to reset your password.</p>
<div class='footer'>
<p>Thanks for using our service!</p>
</div>
</div>
</body>
</html>
";
$message = [
"personalizations" => [
[
"to" => [
[
"email" => $mail
]
]
]
],
"from" => [
"email" => $SENDGRID_MAIL
],
"subject" => "Jakach login password reset",
"content" => [
[
"type" => "text/html",
"value" => $content
]
]
];
$url = "https://api.sendgrid.com/v3/mail/send";
// Initialize cURL
$ch = curl_init($url);
// Set cURL options
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $SENDGRID_KEY",
"Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($message));
// Execute the cURL request
curl_exec($ch);
curl_close($ch);
}
//insert the token into our db
$valid_until=time()+8600;
$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);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
?>