Add Google Login
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@ node_modules/
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.pgpass
|
.pgpass
|
||||||
.log
|
.log
|
||||||
|
.sh
|
||||||
@@ -307,3 +307,68 @@ body {
|
|||||||
font-size: 0.8rem;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
// Toggle between login and register forms
|
||||||
function toggleForm() {
|
function toggleForm() {
|
||||||
const loginForm = document.getElementById('loginForm');
|
const loginForm = document.getElementById('loginForm');
|
||||||
@@ -65,6 +91,9 @@ function setLoading(show) {
|
|||||||
|
|
||||||
// Event Listeners Setup
|
// Event Listeners Setup
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
|
// Handle Google OAuth
|
||||||
|
document.getElementById('googleSignInBtn').addEventListener('click', signInWithGoogle);
|
||||||
|
|
||||||
// Handle login
|
// Handle login
|
||||||
document.getElementById('loginFormElement').addEventListener('submit', async (e) => {
|
document.getElementById('loginFormElement').addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -27,6 +27,23 @@
|
|||||||
<!-- Login Form -->
|
<!-- Login Form -->
|
||||||
<div id="loginForm" class="form-container active">
|
<div id="loginForm" class="form-container active">
|
||||||
<h2 style="text-align: center; margin-bottom: 1.5rem; color: #e2e8f0; font-weight: 600;">Welcome Back</h2>
|
<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">
|
<form id="loginFormElement">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="loginEmail">Email</label>
|
<label for="loginEmail">Email</label>
|
||||||
|
|||||||
10
server.js
10
server.js
@@ -165,6 +165,16 @@ app.get('/adminlogin.html', (req, res) => {
|
|||||||
res.sendFile(path.join(__dirname, 'public', 'adminlogin.html'));
|
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
|
// STATIC FILE SERVING
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
24
server.log
24
server.log
@@ -1,18 +1,8 @@
|
|||||||
nohup: ignoring input
|
nohup: ignoring input
|
||||||
Uncaught Exception: Error: listen EADDRINUSE: address already in use :::3000
|
🚀 Server läuft auf http://ninja.reptilfpv.de:3000
|
||||||
at Server.setupListenHandle [as _listen2] (node:net:1940:16)
|
📊 Datenbank: localhost:5432/ninjacross
|
||||||
at listenInCluster (node:net:1997:12)
|
🔐 API-Key Authentifizierung aktiviert
|
||||||
at Server.listen (node:net:2102:7)
|
🔌 WebSocket-Server aktiviert
|
||||||
at Object.<anonymous> (/root/ninjaserver/server.js:229:8)
|
📁 Static files: /public
|
||||||
at Module._compile (node:internal/modules/cjs/loader:1688:14)
|
🌐 Public API: /public-api
|
||||||
at Object..js (node:internal/modules/cjs/loader:1820:10)
|
🔑 Private API: /api
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user