Add Google Login

This commit is contained in:
2025-09-05 06:51:31 +02:00
parent 54353e06f2
commit b0b5149069
6 changed files with 130 additions and 18 deletions

3
.gitignore vendored
View File

@@ -3,4 +3,5 @@ node_modules/
.vscode/
.DS_Store
.pgpass
.log
.log
.sh

View File

@@ -307,3 +307,68 @@ body {
font-size: 0.8rem;
}
}
/* OAuth Container */
.oauth-container {
margin-bottom: 20px;
}
.btn-google {
width: 100%;
background: white;
color: #333;
border: 1px solid #dadce0;
padding: 12px 16px;
border-radius: 8px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
font-size: 0.95rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.btn-google:hover {
background: #f8f9fa;
border-color: #c1c7cd;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.btn-google:active {
transform: translateY(0);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.btn-google svg {
flex-shrink: 0;
}
/* Divider */
.divider {
position: relative;
text-align: center;
margin: 20px 0;
color: #64748b;
font-size: 0.9rem;
}
.divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(to right, transparent, #334155, transparent);
}
.divider span {
background: #0a0a0f;
padding: 0 16px;
position: relative;
z-index: 1;
}

View File

@@ -13,6 +13,32 @@ async function checkAuth() {
}
}
// Google OAuth Sign In
async function signInWithGoogle() {
try {
setLoading(true);
clearMessage();
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
});
if (error) {
console.error('Google OAuth error:', error);
showMessage('Fehler bei der Google-Anmeldung: ' + error.message, 'error');
}
// Note: OAuth redirects the page, so we don't need to handle success here
} catch (error) {
console.error('Google OAuth error:', error);
showMessage('Fehler bei der Google-Anmeldung: ' + error.message, 'error');
} finally {
setLoading(false);
}
}
// Toggle between login and register forms
function toggleForm() {
const loginForm = document.getElementById('loginForm');
@@ -65,6 +91,9 @@ function setLoading(show) {
// Event Listeners Setup
function setupEventListeners() {
// Handle Google OAuth
document.getElementById('googleSignInBtn').addEventListener('click', signInWithGoogle);
// Handle login
document.getElementById('loginFormElement').addEventListener('submit', async (e) => {
e.preventDefault();

View File

@@ -27,6 +27,23 @@
<!-- Login Form -->
<div id="loginForm" class="form-container active">
<h2 style="text-align: center; margin-bottom: 1.5rem; color: #e2e8f0; font-weight: 600;">Welcome Back</h2>
<!-- Google OAuth Button -->
<div class="oauth-container">
<button type="button" id="googleSignInBtn" class="btn btn-google">
<svg width="20" height="20" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
</svg>
Continue with Google
</button>
</div>
<div class="divider">
<span>or</span>
</div>
<form id="loginFormElement">
<div class="form-group">
<label for="loginEmail">Email</label>

View File

@@ -165,6 +165,16 @@ app.get('/adminlogin.html', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'adminlogin.html'));
});
/**
* OAuth Callback Route
* Handles OAuth redirects from Supabase (Google, etc.)
*/
app.get('/auth/callback', (req, res) => {
// Redirect to the main page after OAuth callback
// Supabase handles the OAuth flow and redirects here
res.redirect('/');
});
// ============================================================================
// STATIC FILE SERVING
// ============================================================================

View File

@@ -1,18 +1,8 @@
nohup: ignoring input
Uncaught Exception: Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (node:net:1940:16)
at listenInCluster (node:net:1997:12)
at Server.listen (node:net:2102:7)
at Object.<anonymous> (/root/ninjaserver/server.js:229:8)
at Module._compile (node:internal/modules/cjs/loader:1688:14)
at Object..js (node:internal/modules/cjs/loader:1820:10)
at Module.load (node:internal/modules/cjs/loader:1423:32)
at Function._load (node:internal/modules/cjs/loader:1246:12)
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:235:24) {
code: 'EADDRINUSE',
errno: -98,
syscall: 'listen',
address: '::',
port: 3000
}
🚀 Server läuft auf http://ninja.reptilfpv.de:3000
📊 Datenbank: localhost:5432/ninjacross
🔐 API-Key Authentifizierung aktiviert
🔌 WebSocket-Server aktiviert
📁 Static files: /public
🌐 Public API: /public-api
🔑 Private API: /api