Major improvements: - Created startup orchestration system with health monitoring and graceful shutdown - Fixed user registration and login with simplified authentication flow - Rebuilt authentication forms from scratch with direct API integration - Implemented comprehensive debugging and error handling - Added Redis fallback functionality for disabled environments - Fixed CORS configuration for cross-origin frontend requests - Simplified password validation to 6+ characters (removed complexity requirements) - Added toast notifications at app level for better UX feedback - Created comprehensive startup/shutdown scripts with OODA methodology - Fixed database validation and connection issues - Implemented TokenService memory fallback when Redis is disabled Technical details: - New SimpleLoginForm.tsx and SimpleRegisterForm.tsx components - Enhanced CORS middleware with additional allowed origins - Simplified auth validators and removed strict password requirements - Added extensive logging and diagnostic capabilities - Fixed authentication middleware token validation - Implemented graceful Redis error handling throughout the stack - Created modular startup system with configurable health checks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
244 lines
No EOL
10 KiB
HTML
244 lines
No EOL
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Test Registration - Shattered Void MMO</title>
|
|
<style>
|
|
body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }
|
|
.form-group { margin-bottom: 15px; }
|
|
label { display: block; margin-bottom: 5px; font-weight: bold; }
|
|
input { width: 100%; padding: 8px; font-size: 14px; border: 1px solid #ccc; border-radius: 4px; }
|
|
button { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; }
|
|
button:hover { background: #0056b3; }
|
|
button:disabled { background: #ccc; cursor: not-allowed; }
|
|
.result { margin-top: 20px; padding: 10px; border-radius: 4px; }
|
|
.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
|
.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
|
.info { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
|
|
pre { background: #f8f9fa; padding: 10px; border-radius: 4px; overflow-x: auto; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>🎮 Shattered Void MMO - Registration Test</h1>
|
|
|
|
<form id="registrationForm">
|
|
<div class="form-group">
|
|
<label for="email">Email:</label>
|
|
<input type="email" id="email" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="username">Username:</label>
|
|
<input type="text" id="username" required minlength="3" maxlength="20">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="password">Password:</label>
|
|
<input type="password" id="password" required minlength="8">
|
|
<small>Must contain uppercase, lowercase, number, and special character</small>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="confirmPassword">Confirm Password:</label>
|
|
<input type="password" id="confirmPassword" required>
|
|
</div>
|
|
|
|
<button type="submit" id="registerBtn">Register</button>
|
|
</form>
|
|
|
|
<div id="result"></div>
|
|
|
|
<hr style="margin: 40px 0;">
|
|
|
|
<h2>Login Test</h2>
|
|
<form id="loginForm">
|
|
<div class="form-group">
|
|
<label for="loginEmail">Email:</label>
|
|
<input type="email" id="loginEmail" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="loginPassword">Password:</label>
|
|
<input type="password" id="loginPassword" required>
|
|
</div>
|
|
|
|
<button type="submit" id="loginBtn">Login</button>
|
|
</form>
|
|
|
|
<div id="loginResult"></div>
|
|
|
|
<script>
|
|
const API_BASE = 'http://0.0.0.0:3000/api';
|
|
|
|
// Registration form handler
|
|
document.getElementById('registrationForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const registerBtn = document.getElementById('registerBtn');
|
|
const resultDiv = document.getElementById('result');
|
|
|
|
registerBtn.disabled = true;
|
|
registerBtn.textContent = 'Registering...';
|
|
|
|
const email = document.getElementById('email').value;
|
|
const username = document.getElementById('username').value;
|
|
const password = document.getElementById('password').value;
|
|
const confirmPassword = document.getElementById('confirmPassword').value;
|
|
|
|
// Basic validation
|
|
if (password !== confirmPassword) {
|
|
resultDiv.innerHTML = '<div class="error">Passwords do not match!</div>';
|
|
registerBtn.disabled = false;
|
|
registerBtn.textContent = 'Register';
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/auth/register`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
email,
|
|
username,
|
|
password
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.ok && data.success) {
|
|
resultDiv.innerHTML = `
|
|
<div class="success">
|
|
<h3>✅ Registration Successful!</h3>
|
|
<p><strong>User ID:</strong> ${data.data.user.id}</p>
|
|
<p><strong>Username:</strong> ${data.data.user.username}</p>
|
|
<p><strong>Email:</strong> ${data.data.user.email}</p>
|
|
<p><strong>Token received:</strong> ${data.data.token ? 'Yes' : 'No'}</p>
|
|
${data.data.token ? '<p><strong>Token:</strong> ' + data.data.token.substring(0, 50) + '...</p>' : ''}
|
|
<details>
|
|
<summary>Full Response</summary>
|
|
<pre>${JSON.stringify(data, null, 2)}</pre>
|
|
</details>
|
|
</div>
|
|
`;
|
|
|
|
// Store token for login test
|
|
if (data.data.token) {
|
|
localStorage.setItem('auth_token', data.data.token);
|
|
}
|
|
|
|
// Auto-fill login form
|
|
document.getElementById('loginEmail').value = email;
|
|
document.getElementById('loginPassword').value = password;
|
|
|
|
} else {
|
|
resultDiv.innerHTML = `
|
|
<div class="error">
|
|
<h3>❌ Registration Failed</h3>
|
|
<p><strong>Error:</strong> ${data.message || 'Unknown error'}</p>
|
|
<details>
|
|
<summary>Full Response</summary>
|
|
<pre>${JSON.stringify(data, null, 2)}</pre>
|
|
</details>
|
|
</div>
|
|
`;
|
|
}
|
|
} catch (error) {
|
|
resultDiv.innerHTML = `
|
|
<div class="error">
|
|
<h3>❌ Network Error</h3>
|
|
<p><strong>Error:</strong> ${error.message}</p>
|
|
<p>Make sure the server is running on ${API_BASE}</p>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
registerBtn.disabled = false;
|
|
registerBtn.textContent = 'Register';
|
|
});
|
|
|
|
// Login form handler
|
|
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const loginBtn = document.getElementById('loginBtn');
|
|
const resultDiv = document.getElementById('loginResult');
|
|
|
|
loginBtn.disabled = true;
|
|
loginBtn.textContent = 'Logging in...';
|
|
|
|
const email = document.getElementById('loginEmail').value;
|
|
const password = document.getElementById('loginPassword').value;
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/auth/login`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
email,
|
|
password
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.ok && data.success) {
|
|
resultDiv.innerHTML = `
|
|
<div class="success">
|
|
<h3>✅ Login Successful!</h3>
|
|
<p><strong>User ID:</strong> ${data.data.user.id}</p>
|
|
<p><strong>Username:</strong> ${data.data.user.username}</p>
|
|
<p><strong>Email:</strong> ${data.data.user.email}</p>
|
|
<p><strong>Token received:</strong> ${data.data.token ? 'Yes' : 'No'}</p>
|
|
${data.data.token ? '<p><strong>Token:</strong> ' + data.data.token.substring(0, 50) + '...</p>' : ''}
|
|
<details>
|
|
<summary>Full Response</summary>
|
|
<pre>${JSON.stringify(data, null, 2)}</pre>
|
|
</details>
|
|
</div>
|
|
`;
|
|
|
|
// Store token
|
|
if (data.data.token) {
|
|
localStorage.setItem('auth_token', data.data.token);
|
|
}
|
|
|
|
} else {
|
|
resultDiv.innerHTML = `
|
|
<div class="error">
|
|
<h3>❌ Login Failed</h3>
|
|
<p><strong>Error:</strong> ${data.message || 'Unknown error'}</p>
|
|
<details>
|
|
<summary>Full Response</summary>
|
|
<pre>${JSON.stringify(data, null, 2)}</pre>
|
|
</details>
|
|
</div>
|
|
`;
|
|
}
|
|
} catch (error) {
|
|
resultDiv.innerHTML = `
|
|
<div class="error">
|
|
<h3>❌ Network Error</h3>
|
|
<p><strong>Error:</strong> ${error.message}</p>
|
|
<p>Make sure the server is running on ${API_BASE}</p>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
loginBtn.disabled = false;
|
|
loginBtn.textContent = 'Login';
|
|
});
|
|
|
|
// Auto-fill test data
|
|
document.getElementById('email').value = 'test' + Date.now() + '@example.com';
|
|
document.getElementById('username').value = 'testuser' + Date.now().toString().slice(-4);
|
|
document.getElementById('password').value = 'TestPass1@';
|
|
document.getElementById('confirmPassword').value = 'TestPass1@';
|
|
</script>
|
|
</body>
|
|
</html> |