feat(activity-log): integrate logging across all endpoints (Phase 3)

Added comprehensive activity logging to 14 integration points:

Auth Controller (4 actions):
- AUTH_REGISTER: User registration
- AUTH_LOGIN: User login
- AUTH_VERIFY_EMAIL: Email verification (token & code)
- AUTH_PASSWORD_RESET: Password reset

Events Routes (2 actions):
- EVENT_CHECKIN: User checks into event
- EVENT_LEAVE: User leaves event

Socket Handlers (3 actions):
- EVENT_JOIN_CHAT: User joins event chat room
- EVENT_LEAVE_CHAT: User leaves event chat room
- CHAT_JOIN_ROOM: User joins private match chat

Matches Routes (3 actions):
- MATCH_CREATE: Match request created
- MATCH_ACCEPT: Match request accepted
- MATCH_REJECT: Match request rejected/cancelled

Admin Routes (1 action + security):
- ADMIN_MATCHING_RUN: Admin runs matching algorithm
- Added requireAdmin middleware to all admin routes

All logs include:
- User ID and username (denormalized)
- IP address (X-Forwarded-For aware)
- Action type and resource ID
- HTTP method and path (or SOCKET for WebSocket)
- Contextual metadata (event slugs, match IDs, etc.)

Fire-and-forget pattern ensures logging never blocks requests.
This commit is contained in:
Radosław Gierwiało
2025-12-02 20:07:10 +01:00
parent 0466ef9e5c
commit d83e4163e5
5 changed files with 217 additions and 3 deletions

View File

@@ -10,6 +10,8 @@ const {
const { sendVerificationEmail, sendWelcomeEmail, sendPasswordResetEmail } = require('../emails');
const { sanitizeForEmail, timingSafeEqual } = require('../utils/sanitize');
const securityConfig = require('../config/security');
const { ACTIONS, log: activityLog } = require('../services/activityLog');
const { getClientIP } = require('../utils/request');
// Register new user (Phase 1.5 - with WSDC support and email verification)
async function register(req, res, next) {
@@ -92,6 +94,20 @@ async function register(req, res, next) {
// Generate JWT token
const token = generateToken({ userId: user.id });
// Log registration activity
activityLog({
userId: user.id,
username: user.username,
ipAddress: getClientIP(req),
action: ACTIONS.AUTH_REGISTER,
method: req.method,
path: req.path,
metadata: {
email: user.email,
hasWsdcId: !!user.wsdcId,
},
});
res.status(201).json({
success: true,
message: 'User registered successfully. Please check your email to verify your account.',
@@ -199,6 +215,20 @@ async function login(req, res, next) {
// Return user without password
const { passwordHash, ...userWithoutPassword } = user;
// Log login activity
activityLog({
userId: user.id,
username: user.username,
ipAddress: getClientIP(req),
action: ACTIONS.AUTH_LOGIN,
method: req.method,
path: req.path,
metadata: {
email: user.email,
emailVerified: user.emailVerified,
},
});
res.json({
success: true,
message: 'Login successful',
@@ -276,6 +306,19 @@ async function verifyEmailByToken(req, res, next) {
// Remove sensitive data
const { passwordHash, verificationToken, verificationCode, verificationTokenExpiry, resetToken, resetTokenExpiry, ...userWithoutPassword } = updatedUser;
// Log email verification activity
activityLog({
userId: updatedUser.id,
username: updatedUser.username,
ipAddress: getClientIP(req),
action: ACTIONS.AUTH_VERIFY_EMAIL,
method: req.method,
path: req.path,
metadata: {
verificationMethod: 'token',
},
});
res.status(200).json({
success: true,
message: 'Email verified successfully!',
@@ -356,6 +399,19 @@ async function verifyEmailByCode(req, res, next) {
// Remove sensitive data
const { passwordHash, verificationToken, verificationCode, verificationTokenExpiry, resetToken, resetTokenExpiry, ...userWithoutPassword } = updatedUser;
// Log email verification activity
activityLog({
userId: updatedUser.id,
username: updatedUser.username,
ipAddress: getClientIP(req),
action: ACTIONS.AUTH_VERIFY_EMAIL,
method: req.method,
path: req.path,
metadata: {
verificationMethod: 'code',
},
});
res.status(200).json({
success: true,
message: 'Email verified successfully!',
@@ -543,6 +599,19 @@ async function resetPassword(req, res, next) {
},
});
// Log password reset activity
activityLog({
userId: user.id,
username: user.username,
ipAddress: getClientIP(req),
action: ACTIONS.AUTH_PASSWORD_RESET,
method: req.method,
path: req.path,
metadata: {
email: user.email,
},
});
res.status(200).json({
success: true,
message: 'Password reset successfully',