mirror of
https://github.com/myronblair/tomsjavajive
synced 2026-06-30 17:50:32 -05:00
Add Google OAuth admin login; fix header comment; both auth methods active
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* Google OAuth callback — exchange code for token, verify admin, create session
|
||||
*/
|
||||
require_once __DIR__ . '/../../../includes/auth.php';
|
||||
|
||||
function googleOAuthError(string $msg): void {
|
||||
$_SESSION['admin_login_error'] = $msg;
|
||||
header('Location: /admin/login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Verify state to prevent CSRF
|
||||
if (empty($_GET['state']) || $_GET['state'] !== ($_SESSION['google_oauth_state'] ?? '')) {
|
||||
googleOAuthError('Invalid OAuth state. Please try again.');
|
||||
}
|
||||
unset($_SESSION['google_oauth_state']);
|
||||
|
||||
if (!empty($_GET['error'])) {
|
||||
googleOAuthError('Google sign-in was cancelled or denied.');
|
||||
}
|
||||
|
||||
if (empty($_GET['code'])) {
|
||||
googleOAuthError('No authorization code received from Google.');
|
||||
}
|
||||
|
||||
// Exchange code for access token
|
||||
$tokenResp = json_decode(file_get_contents('https://oauth2.googleapis.com/token', false, stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'POST',
|
||||
'header' => 'Content-Type: application/x-www-form-urlencoded',
|
||||
'content' => http_build_query([
|
||||
'code' => $_GET['code'],
|
||||
'client_id' => GOOGLE_CLIENT_ID,
|
||||
'client_secret' => GOOGLE_CLIENT_SECRET,
|
||||
'redirect_uri' => GOOGLE_REDIRECT_URI,
|
||||
'grant_type' => 'authorization_code',
|
||||
]),
|
||||
'timeout' => 15,
|
||||
],
|
||||
])), true);
|
||||
|
||||
if (empty($tokenResp['access_token'])) {
|
||||
error_log('[Google OAuth] token exchange failed: ' . json_encode($tokenResp));
|
||||
googleOAuthError('Failed to complete Google sign-in. Please try again.');
|
||||
}
|
||||
|
||||
// Fetch Google user info
|
||||
$userInfo = json_decode(file_get_contents('https://www.googleapis.com/oauth2/v3/userinfo', false, stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'GET',
|
||||
'header' => 'Authorization: Bearer ' . $tokenResp['access_token'],
|
||||
'timeout' => 10,
|
||||
],
|
||||
])), true);
|
||||
|
||||
if (empty($userInfo['email'])) {
|
||||
googleOAuthError('Could not retrieve email from Google. Please try again.');
|
||||
}
|
||||
|
||||
$googleEmail = strtolower($userInfo['email']);
|
||||
|
||||
// Look up admin by email
|
||||
$admin = db()->fetch(
|
||||
"SELECT * FROM admin_users WHERE email = :email",
|
||||
['email' => $googleEmail]
|
||||
);
|
||||
|
||||
if (!$admin) {
|
||||
error_log('[Google OAuth] login attempt by non-admin: ' . $googleEmail);
|
||||
googleOAuthError('No admin account found for ' . htmlspecialchars($googleEmail) . '. Contact the site administrator.');
|
||||
}
|
||||
|
||||
// Store google_id on first Google login
|
||||
if (empty($admin['google_id'])) {
|
||||
try {
|
||||
db()->query(
|
||||
"UPDATE admin_users SET google_id = :gid, last_login = NOW() WHERE user_id = :id",
|
||||
['gid' => $userInfo['sub'], 'id' => $admin['user_id']]
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
// google_id column may not exist yet — update last_login only
|
||||
db()->query(
|
||||
"UPDATE admin_users SET last_login = NOW() WHERE user_id = :id",
|
||||
['id' => $admin['user_id']]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
db()->query(
|
||||
"UPDATE admin_users SET last_login = NOW() WHERE user_id = :id",
|
||||
['id' => $admin['user_id']]
|
||||
);
|
||||
}
|
||||
|
||||
// Create session
|
||||
$_SESSION['admin'] = [
|
||||
'user_id' => $admin['user_id'],
|
||||
'email' => $admin['email'],
|
||||
'name' => $admin['name'],
|
||||
'is_master' => (bool)$admin['is_master'],
|
||||
'permissions' => json_decode($admin['permissions'] ?? '[]', true),
|
||||
'auth_method' => 'google',
|
||||
];
|
||||
session_regenerate_id(true);
|
||||
|
||||
$redirect = $_SESSION['admin_redirect'] ?? '/admin/';
|
||||
unset($_SESSION['admin_redirect']);
|
||||
header('Location: ' . $redirect);
|
||||
exit;
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* Redirect to Google OAuth — admin login entry point
|
||||
*/
|
||||
require_once __DIR__ . '/../../../includes/auth.php';
|
||||
|
||||
if (AdminAuth::isLoggedIn()) {
|
||||
header('Location: /admin/');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!defined('GOOGLE_CLIENT_ID') || !GOOGLE_CLIENT_ID) {
|
||||
die('Google OAuth is not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in config.');
|
||||
}
|
||||
|
||||
$state = bin2hex(random_bytes(16));
|
||||
$_SESSION['google_oauth_state'] = $state;
|
||||
|
||||
$params = http_build_query([
|
||||
'client_id' => GOOGLE_CLIENT_ID,
|
||||
'redirect_uri' => GOOGLE_REDIRECT_URI,
|
||||
'response_type' => 'code',
|
||||
'scope' => 'openid email profile',
|
||||
'state' => $state,
|
||||
'access_type' => 'online',
|
||||
'prompt' => 'select_account',
|
||||
]);
|
||||
|
||||
header('Location: https://accounts.google.com/o/oauth2/v2/auth?' . $params);
|
||||
exit;
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Tom's Java Jive - Admin Header
|
||||
* Authentication temporarily disabled
|
||||
* Requires AdminAuth::require() — redirects to login.php
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../includes/auth.php';
|
||||
@@ -105,10 +105,10 @@ $currentPage = basename($_SERVER['PHP_SELF'], '.php');
|
||||
<a href="/admin/campaigns.php" class="nav-item <?= $currentPage === 'campaigns' ? 'active' : '' ?>">
|
||||
<i class="fas fa-envelope"></i> Email Campaigns
|
||||
</a>
|
||||
<a href="/admin/email-log.php" class="nav-item <?= $currentPage === 'email-log' ? 'active' : '' ?>"><i class="fas fa-envelope-open-text"></i> Email Log</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-group">
|
||||
<span class="nav-group-title">Settings</span>
|
||||
<a href="/admin/settings.php" class="nav-item <?= $currentPage === 'settings' ? 'active' : '' ?>">
|
||||
<i class="fas fa-cog"></i> Store Settings
|
||||
</a>
|
||||
|
||||
+26
-1
@@ -9,7 +9,11 @@ if (AdminAuth::isLoggedIn()) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$error = '';
|
||||
$googleEnabled = defined('GOOGLE_CLIENT_ID') && GOOGLE_CLIENT_ID;
|
||||
|
||||
$error = $_SESSION['admin_login_error'] ?? '';
|
||||
unset($_SESSION['admin_login_error']);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$password = trim($_POST['password'] ?? '');
|
||||
@@ -41,6 +45,12 @@ input{width:100%;background:#111;border:1.5px solid #2a2a2a;border-radius:8px;pa
|
||||
input:focus{border-color:#FF5E1A}
|
||||
.btn{width:100%;padding:14px;border:none;border-radius:8px;background:#FF5E1A;color:#fff;font-family:Inter,sans-serif;font-weight:600;font-size:15px;cursor:pointer;transition:background .2s;margin-top:4px}
|
||||
.btn:hover{background:#e54d0f}
|
||||
.btn-google{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;padding:13px;border:1.5px solid #333;border-radius:8px;background:#111;color:#e0e0e0;font-family:Inter,sans-serif;font-weight:500;font-size:15px;cursor:pointer;text-decoration:none;transition:border-color .2s,background .2s}
|
||||
.btn-google:hover{border-color:#555;background:#1a1a1a}
|
||||
.btn-google svg{width:20px;height:20px;flex-shrink:0}
|
||||
.divider{display:flex;align-items:center;gap:12px;margin:22px 0}
|
||||
.divider::before,.divider::after{content:'';flex:1;height:1px;background:#2a2a2a}
|
||||
.divider span{font-size:12px;color:#444}
|
||||
.error{background:rgba(220,38,38,.1);border:1px solid rgba(220,38,38,.3);color:#f87171;padding:12px 15px;border-radius:8px;font-size:14px;margin-bottom:20px;display:flex;align-items:center;gap:8px}
|
||||
.back{display:block;text-align:center;margin-top:20px;color:#555;font-size:13px;text-decoration:none;transition:color .2s}
|
||||
.back:hover{color:#FF5E1A}
|
||||
@@ -52,9 +62,24 @@ input:focus{border-color:#FF5E1A}
|
||||
<h1>☕ Tom's Java Jive</h1>
|
||||
<p>Admin Panel</p>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="error">⚠ <?= htmlspecialchars($error) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($googleEnabled): ?>
|
||||
<a href="/admin/auth/google/login.php" class="btn-google">
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v8.51h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.14z"/>
|
||||
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"/>
|
||||
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"/>
|
||||
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"/>
|
||||
</svg>
|
||||
Sign in with Google
|
||||
</a>
|
||||
<div class="divider"><span>or sign in with email</span></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<label>Email Address</label>
|
||||
<input type="email" name="email" placeholder="admin@tomsjavajive.com" required autocomplete="email">
|
||||
|
||||
Reference in New Issue
Block a user