Файловый менеджер - Редактировать - /home/gqdcvggs/go.imators.com/andweare.tar
Назад
passkey.php 0000664 00000034363 15114741366 0006757 0 ustar 00 <?php session_start(); require_once '../db.php'; require '../vendor/autoload.php'; use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\SMTP; use PHPMailer\PHPMailer\Exception; if (!isset($_SESSION['pending_user_id']) || !isset($_SESSION['pending_username']) || !isset($_SESSION['pending_email'])) { session_destroy(); header('Location: ../index.php'); exit; } function getDeviceInfo($user_agent) { $device_info = [ 'device' => 'Unknown', 'os' => 'Unknown', 'browser' => 'Unknown' ]; if(preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i',$user_agent)) { $device_info['device'] = 'Mobile'; } elseif(preg_match('/tablet|ipad|playbook|silk/i', $user_agent)) { $device_info['device'] = 'Tablet'; } else { $device_info['device'] = 'Desktop'; } if(preg_match('/windows/i', $user_agent)) { $device_info['os'] = 'Windows'; } elseif(preg_match('/macintosh|mac os x/i', $user_agent)) { $device_info['os'] = 'MacOS / iOS'; } elseif(preg_match('/linux/i', $user_agent)) { $device_info['os'] = 'Linux'; } elseif(preg_match('/iphone|ipad|ipod/i', $user_agent)) { $device_info['os'] = 'iOS'; } elseif(preg_match('/android/i', $user_agent)) { $device_info['os'] = 'Android'; } if(preg_match('/MSIE|Trident/i', $user_agent)) { $device_info['browser'] = 'Internet Explorer'; } elseif(preg_match('/Firefox/i', $user_agent)) { $device_info['browser'] = 'Firefox'; } elseif(preg_match('/Chrome/i', $user_agent)) { $device_info['browser'] = 'Chrome'; } elseif(preg_match('/Safari/i', $user_agent)) { $device_info['browser'] = 'Safari'; } elseif(preg_match('/Opera|OPR/i', $user_agent)) { $device_info['browser'] = 'Opera'; } return $device_info; } function sendLoginNotification($email, $location, $device_info) { $mail = new PHPMailer(true); try { $mail->isSMTP(); $mail->Host = 'mail.imators.com'; $mail->SMTPAuth = true; $mail->Username = 'no-reply@imators.systems'; $mail->Password = 'imators.managements4455*#@'; $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; $mail->Port = 587; $mail->SMTPOptions = [ 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true ] ]; $mail->setFrom('no-reply@imators.systems', 'AndWeare'); $mail->addAddress($email); $mail->addReplyTo('no-reply@imators.systems', 'No Reply'); $mail->isHTML(true); $mail->Subject = 'New Login to Your AndWeare Family Hub'; $mail->Body = ' <div style="font-family: \'Noto Sans KR\', sans-serif; max-width: 600px; margin: 0 auto;"> <div style="background: #ffffff; padding: 30px; border-radius: 10px; color: black;"> <h1 style="margin-bottom: 20px;">We detected a new login to your account with the following details:</h1> <ul style="margin-bottom: 20px; list-style: none; padding: 0;"> <li style="margin-bottom: 5px;">Location: ' . ($location['location'] ?? 'Unknown') . '</li> <li style="margin-bottom: 5px;">Device: ' . $device_info['device'] . ' (' . $device_info['os'] . ')</li> <li style="margin-bottom: 5px;">Browser: ' . $device_info['browser'] . '</li> <li style="margin-bottom: 5px;">Time: ' . date('F j, Y g:i A') . '</li> <li style="margin-bottom: 5px;">Authentication Type: Passkey</li> </ul> <p style="margin-bottom: 30px;">If this wasn\'t you, please secure your account immediately.</p> <a href="https://andweare.com" style="display: inline-block; background-color: #000000; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px;"> Go to Account Settings </a> <p style="margin-top: 20px; font-size: 12px; color: #888;"> If you believe someone has unauthorized access to your account, please contact our support team immediately. </p> </div> </div>'; $mail->send(); } catch (Exception $e) { error_log("Login email error: " . $mail->ErrorInfo); } } function logSuccessfulLogin($conn, $user_id, $location, $device_info) { $ip_address = $_SERVER['REMOTE_ADDR']; $watchguard_data = [ 'user_id' => $user_id, 'ip-connected' => json_encode([ 'ip' => $ip_address, 'location' => $location['location'] ?? 'Unknown' ]), 'identified-screen' => json_encode($device_info), 'hours-of-connect' => date('H:i:s'), 'date-of-connect' => date('Y-m-d H:i:s') ]; $stmt = $conn->prepare(" INSERT INTO `connection-watchguard` (user_id, `ip-connected`, `identified-screen`, `hours-of-connect`, `date-of-connect`) VALUES (:user_id, :ip_connected, :identified_screen, :hours_of_connect, :date_of_connect) "); $stmt->execute([ ':user_id' => $watchguard_data['user_id'], ':ip_connected' => $watchguard_data['ip-connected'], ':identified_screen' => $watchguard_data['identified-screen'], ':hours_of_connect' => $watchguard_data['hours-of-connect'], ':date_of_connect' => $watchguard_data['date-of-connect'] ]); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { header('Content-Type: application/json'); try { $db = new Database(); $conn = $db->connect(); $data = json_decode(file_get_contents('php://input'), true); $stmt = $conn->prepare("SELECT * FROM passkeys WHERE user_id = ?"); $stmt->execute([$_SESSION['pending_user_id']]); $passkey = $stmt->fetch(PDO::FETCH_ASSOC); if ($passkey) { $user_id = $_SESSION['pending_user_id']; $username = $_SESSION['pending_username']; $email = $_SESSION['pending_email']; // Get device and location information $device_info = getDeviceInfo($_SERVER['HTTP_USER_AGENT']); $ip_details = json_decode(file_get_contents("http://ip-api.com/json/" . $_SERVER['REMOTE_ADDR']), true); $location = []; if($ip_details && $ip_details['status'] === 'success') { $location = [ 'country' => $ip_details['country'], 'city' => $ip_details['city'], 'region' => $ip_details['regionName'], 'location' => "{$ip_details['city']}, {$ip_details['country']}" ]; } // Log login details logSuccessfulLogin($conn, $user_id, $location, $device_info); // Send notification email sendLoginNotification($email, $location, $device_info); // Update passkey last used time $stmt = $conn->prepare("UPDATE passkeys SET last_used_at = NOW() WHERE user_id = ?"); $stmt->execute([$user_id]); // Get andweare member status $stmt = $conn->prepare("SELECT andweare_member, family_site_url, family_role FROM utilisateurs WHERE id = ?"); $stmt->execute([$user_id]); $andweare_data = $stmt->fetch(PDO::FETCH_ASSOC); // Create session session_unset(); $_SESSION['user_id'] = $user_id; $_SESSION['username'] = $username; $_SESSION['andweare_member'] = $andweare_data['andweare_member'] ?? 0; $_SESSION['family_site_url'] = $andweare_data['family_site_url'] ?? ''; $_SESSION['family_role'] = $andweare_data['family_role'] ?? ''; $redirect_url = ($_SESSION['andweare_member'] == 1 && !empty($_SESSION['family_site_url'])) ? $_SESSION['family_site_url'] : 'https://andweare.com'; echo json_encode(['success' => true, 'redirect' => $redirect_url]); exit; } else { echo json_encode(['error' => 'Invalid passkey']); } } catch (Exception $e) { echo json_encode(['error' => $e->getMessage()]); } exit; } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Passkey Authentication - AndWeare</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet"> <script src="https://cdn.tailwindcss.com"></script> <style> body { font-family: 'Noto Sans KR', sans-serif; } </style> </head> <body class="bg-white text-black min-h-screen flex items-center justify-center p-4"> <div class="w-full max-w-md"> <div class="text-center mb-8"> <img src="/images/andweare-logo.png" alt="AndWeare Logo" class="mx-auto mb-4" style="height: 60px;"> <h1 class="text-3xl font-light">Passkey Verification</h1> <p class="text-sm text-gray-600 mt-2">Complete your login with Passkey verification</p> </div> <div id="error-message" class="hidden bg-red-100 border border-red-400 text-red-700 p-4 rounded-lg mb-4 text-center"></div> <div class="bg-gray-50 border border-gray-200 rounded-xl p-8 shadow-sm"> <div class="flex justify-center mb-6"> <div id="verification-status" class="animate-pulse w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center"> <svg class="w-10 h-10 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/> </svg> </div> </div> <div class="text-center space-y-4"> <p class="text-gray-700" id="status-text">Use your passkey to complete the login...</p> <div class="text-sm text-gray-500"> <p>Completing authentication for:</p> <p class="text-gray-800 font-medium"><?php echo htmlspecialchars($_SESSION['pending_email']); ?></p> </div> <a href="index.php" class="inline-block text-sm text-gray-500 hover:text-gray-700 transition-colors mt-4"> Cancel and return to login </a> </div> </div> </div> <script> async function verifyPasskey() { try { const challenge = new Uint8Array(32); window.crypto.getRandomValues(challenge); const credential = await navigator.credentials.get({ publicKey: { challenge, rpId: window.location.hostname, timeout: 60000, userVerification: "preferred", allowCredentials: [] } }); const response = await fetch(window.location.href, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ id: credential.id, rawId: arrayBufferToBase64(credential.rawId), response: { clientDataJSON: arrayBufferToBase64(credential.response.clientDataJSON), authenticatorData: arrayBufferToBase64(credential.response.authenticatorData), signature: arrayBufferToBase64(credential.response.signature) } }) }); const result = await response.json(); if (result.success) { showSuccess(); setTimeout(() => { window.location.href = result.redirect || 'create-family.php'; }, 1000); } else { throw new Error(result.error || 'Verification failed'); } } catch (error) { showError(error.message); } } function showSuccess() { const status = document.getElementById('verification-status'); const statusText = document.getElementById('status-text'); status.classList.remove('animate-pulse', 'bg-blue-100'); status.classList.add('bg-green-100'); status.innerHTML = ` <svg class="w-10 h-10 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/> </svg>`; statusText.textContent = 'Verification successful! Redirecting...'; } function showError(message) { const status = document.getElementById('verification-status'); const statusText = document.getElementById('status-text'); const errorMessage = document.getElementById('error-message'); status.classList.remove('animate-pulse', 'bg-blue-100'); status.classList.add('bg-red-100'); status.innerHTML = ` <svg class="w-10 h-10 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/> </svg>`; statusText.textContent = 'Verification failed. Please try again.'; errorMessage.textContent = message; errorMessage.classList.remove('hidden'); } function arrayBufferToBase64(buffer) { const bytes = new Uint8Array(buffer); let binary = ''; for (let i = 0; i < bytes.byteLength; i++) { binary += String.fromCharCode(bytes[i]); } return window.btoa(binary); } window.addEventListener('load', verifyPasskey); </script> </body> </html>