Initial commit: Shattered Void MMO foundation
- Complete PostgreSQL database schema with 21+ tables - Express.js server with dual authentication (player/admin) - WebSocket support for real-time features - Comprehensive middleware (auth, validation, logging, security) - Game systems: colonies, resources, fleets, research, factions - Plugin-based combat architecture - Admin panel foundation - Production-ready logging and error handling - Docker support and CI/CD ready - Complete project structure following CLAUDE.md patterns 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
commit
1a60cf55a3
69 changed files with 24471 additions and 0 deletions
298
src/controllers/api/auth.controller.js
Normal file
298
src/controllers/api/auth.controller.js
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
/**
|
||||
* Player Authentication Controller
|
||||
* Handles player registration, login, and authentication-related endpoints
|
||||
*/
|
||||
|
||||
const PlayerService = require('../../services/user/PlayerService');
|
||||
const { asyncHandler } = require('../../middleware/error.middleware');
|
||||
const logger = require('../../utils/logger');
|
||||
|
||||
const playerService = new PlayerService();
|
||||
|
||||
/**
|
||||
* Register a new player
|
||||
* POST /api/auth/register
|
||||
*/
|
||||
const register = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const { email, username, password } = req.body;
|
||||
|
||||
logger.info('Player registration request received', {
|
||||
correlationId,
|
||||
email,
|
||||
username
|
||||
});
|
||||
|
||||
const player = await playerService.registerPlayer({
|
||||
email,
|
||||
username,
|
||||
password
|
||||
}, correlationId);
|
||||
|
||||
logger.info('Player registration successful', {
|
||||
correlationId,
|
||||
playerId: player.id,
|
||||
email: player.email,
|
||||
username: player.username
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: 'Player registered successfully',
|
||||
data: {
|
||||
player
|
||||
},
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Player login
|
||||
* POST /api/auth/login
|
||||
*/
|
||||
const login = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const { email, password } = req.body;
|
||||
|
||||
logger.info('Player login request received', {
|
||||
correlationId,
|
||||
email
|
||||
});
|
||||
|
||||
const authResult = await playerService.authenticatePlayer({
|
||||
email,
|
||||
password
|
||||
}, correlationId);
|
||||
|
||||
logger.info('Player login successful', {
|
||||
correlationId,
|
||||
playerId: authResult.player.id,
|
||||
email: authResult.player.email,
|
||||
username: authResult.player.username
|
||||
});
|
||||
|
||||
// Set refresh token as httpOnly cookie
|
||||
res.cookie('refreshToken', authResult.tokens.refreshToken, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'strict',
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Login successful',
|
||||
data: {
|
||||
player: authResult.player,
|
||||
accessToken: authResult.tokens.accessToken
|
||||
},
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Player logout
|
||||
* POST /api/auth/logout
|
||||
*/
|
||||
const logout = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user?.playerId;
|
||||
|
||||
logger.info('Player logout request received', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
// Clear refresh token cookie
|
||||
res.clearCookie('refreshToken');
|
||||
|
||||
// TODO: Add token to blacklist if implementing token blacklisting
|
||||
|
||||
logger.info('Player logout successful', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Logout successful',
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Refresh access token
|
||||
* POST /api/auth/refresh
|
||||
*/
|
||||
const refresh = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const refreshToken = req.cookies.refreshToken;
|
||||
|
||||
if (!refreshToken) {
|
||||
logger.warn('Token refresh request without refresh token', {
|
||||
correlationId
|
||||
});
|
||||
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: 'Refresh token not provided',
|
||||
correlationId
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Implement refresh token validation and new token generation
|
||||
// For now, return error indicating feature not implemented
|
||||
logger.warn('Token refresh requested but not implemented', {
|
||||
correlationId
|
||||
});
|
||||
|
||||
res.status(501).json({
|
||||
success: false,
|
||||
message: 'Token refresh feature not yet implemented',
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Get current player profile
|
||||
* GET /api/auth/me
|
||||
*/
|
||||
const getProfile = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
|
||||
logger.info('Player profile request received', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
|
||||
logger.info('Player profile retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
username: profile.username
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Profile retrieved successfully',
|
||||
data: {
|
||||
player: profile
|
||||
},
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Update current player profile
|
||||
* PUT /api/auth/me
|
||||
*/
|
||||
const updateProfile = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const updateData = req.body;
|
||||
|
||||
logger.info('Player profile update request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
updateFields: Object.keys(updateData)
|
||||
});
|
||||
|
||||
const updatedProfile = await playerService.updatePlayerProfile(
|
||||
playerId,
|
||||
updateData,
|
||||
correlationId
|
||||
);
|
||||
|
||||
logger.info('Player profile updated successfully', {
|
||||
correlationId,
|
||||
playerId,
|
||||
username: updatedProfile.username
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Profile updated successfully',
|
||||
data: {
|
||||
player: updatedProfile
|
||||
},
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify player token (for testing/debugging)
|
||||
* GET /api/auth/verify
|
||||
*/
|
||||
const verifyToken = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const user = req.user;
|
||||
|
||||
logger.info('Token verification request received', {
|
||||
correlationId,
|
||||
playerId: user.playerId,
|
||||
username: user.username
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Token is valid',
|
||||
data: {
|
||||
user: {
|
||||
playerId: user.playerId,
|
||||
email: user.email,
|
||||
username: user.username,
|
||||
type: user.type,
|
||||
tokenIssuedAt: new Date(user.iat * 1000),
|
||||
tokenExpiresAt: new Date(user.exp * 1000)
|
||||
}
|
||||
},
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Change player password
|
||||
* POST /api/auth/change-password
|
||||
*/
|
||||
const changePassword = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { currentPassword, newPassword } = req.body;
|
||||
|
||||
logger.info('Password change request received', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
// TODO: Implement password change functionality
|
||||
// This would involve:
|
||||
// 1. Verify current password
|
||||
// 2. Validate new password strength
|
||||
// 3. Hash new password
|
||||
// 4. Update in database
|
||||
// 5. Optionally invalidate existing tokens
|
||||
|
||||
logger.warn('Password change requested but not implemented', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
res.status(501).json({
|
||||
success: false,
|
||||
message: 'Password change feature not yet implemented',
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
register,
|
||||
login,
|
||||
logout,
|
||||
refresh,
|
||||
getProfile,
|
||||
updateProfile,
|
||||
verifyToken,
|
||||
changePassword
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue