Add email verification system for user registration
All checks were successful
Build And Push Image / docker (push) Successful in 3m1s

- Add SMTP configuration UI in admin panel with test functionality
- Implement email verification workflow with tokens and templates
- Add verification success/expired pages for user feedback
- Include nodemailer, handlebars, and JWT dependencies
- Create API endpoints for email config, testing, and verification
This commit is contained in:
2025-08-08 22:51:14 +02:00
parent 7b72d7a565
commit 4ec05e29dc
20 changed files with 2501 additions and 227 deletions

View File

@@ -0,0 +1,46 @@
export default defineEventHandler(async (event) => {
console.log('[api/admin/smtp-config.get] =========================');
console.log('[api/admin/smtp-config.get] GET /api/admin/smtp-config - Get SMTP configuration');
try {
// Validate session and require admin privileges
const sessionManager = createSessionManager();
const cookieHeader = getCookie(event, 'monacousa-session') ? getHeader(event, 'cookie') : undefined;
const session = sessionManager.getSession(cookieHeader);
if (!session?.user) {
throw createError({
statusCode: 401,
statusMessage: 'Authentication required'
});
}
if (session.user.tier !== 'admin') {
throw createError({
statusCode: 403,
statusMessage: 'Admin privileges required'
});
}
console.log('[api/admin/smtp-config.get] Authorized admin:', session.user.email);
// Get SMTP configuration
const { getSMTPConfig } = await import('~/server/utils/admin-config');
const config = getSMTPConfig();
// Hide password for security
const safeConfig = {
...config,
password: config.password ? '••••••••••••••••' : ''
};
return {
success: true,
data: safeConfig
};
} catch (error: any) {
console.error('[api/admin/smtp-config.get] ❌ Error getting SMTP config:', error);
throw error;
}
});

View File

@@ -0,0 +1,91 @@
export default defineEventHandler(async (event) => {
console.log('[api/admin/smtp-config.post] =========================');
console.log('[api/admin/smtp-config.post] POST /api/admin/smtp-config - Save SMTP configuration');
try {
// Validate session and require admin privileges
const sessionManager = createSessionManager();
const cookieHeader = getCookie(event, 'monacousa-session') ? getHeader(event, 'cookie') : undefined;
const session = sessionManager.getSession(cookieHeader);
if (!session?.user) {
throw createError({
statusCode: 401,
statusMessage: 'Authentication required'
});
}
if (session.user.tier !== 'admin') {
throw createError({
statusCode: 403,
statusMessage: 'Admin privileges required'
});
}
console.log('[api/admin/smtp-config.post] Authorized admin:', session.user.email);
// Parse request body
const body = await readBody(event);
console.log('[api/admin/smtp-config.post] Request body:', {
...body,
password: body.password ? '••••••••••••••••' : ''
});
// Validate required fields
if (!body.host || !body.port || !body.fromAddress || !body.fromName) {
throw createError({
statusCode: 400,
statusMessage: 'Missing required SMTP configuration fields'
});
}
// Validate email format
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(body.fromAddress)) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid from address email format'
});
}
// Validate port is a number
const port = parseInt(body.port, 10);
if (isNaN(port) || port < 1 || port > 65535) {
throw createError({
statusCode: 400,
statusMessage: 'Port must be a valid number between 1 and 65535'
});
}
// Prepare configuration object
const smtpConfig = {
host: body.host.trim(),
port: port,
secure: Boolean(body.secure),
username: body.username?.trim() || '',
password: body.password?.trim() || '',
fromAddress: body.fromAddress.trim(),
fromName: body.fromName.trim()
};
console.log('[api/admin/smtp-config.post] Saving SMTP config:', {
...smtpConfig,
password: smtpConfig.password ? '••••••••••••••••' : ''
});
// Save SMTP configuration
const { saveSMTPConfig } = await import('~/server/utils/admin-config');
await saveSMTPConfig(smtpConfig, session.user.email);
console.log('[api/admin/smtp-config.post] ✅ SMTP configuration saved successfully');
return {
success: true,
message: 'SMTP configuration saved successfully'
};
} catch (error: any) {
console.error('[api/admin/smtp-config.post] ❌ Error saving SMTP config:', error);
throw error;
}
});

View File

@@ -0,0 +1,92 @@
export default defineEventHandler(async (event) => {
console.log('[api/admin/test-email.post] =========================');
console.log('[api/admin/test-email.post] POST /api/admin/test-email - Send test email');
try {
// Validate session and require admin privileges
const sessionManager = createSessionManager();
const cookieHeader = getCookie(event, 'monacousa-session') ? getHeader(event, 'cookie') : undefined;
const session = sessionManager.getSession(cookieHeader);
if (!session?.user) {
throw createError({
statusCode: 401,
statusMessage: 'Authentication required'
});
}
if (session.user.tier !== 'admin') {
throw createError({
statusCode: 403,
statusMessage: 'Admin privileges required'
});
}
console.log('[api/admin/test-email.post] Authorized admin:', session.user.email);
// Parse request body
const body = await readBody(event);
console.log('[api/admin/test-email.post] Request body:', body);
// Validate required fields
if (!body.testEmail) {
throw createError({
statusCode: 400,
statusMessage: 'Test email address is required'
});
}
// Validate email format
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(body.testEmail)) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid email address format'
});
}
console.log('[api/admin/test-email.post] Sending test email to:', body.testEmail);
// Get email service and send test email
const { getEmailService } = await import('~/server/utils/email');
const emailService = getEmailService();
// Verify connection first
const connectionOk = await emailService.verifyConnection();
if (!connectionOk) {
throw createError({
statusCode: 500,
statusMessage: 'SMTP connection verification failed. Please check your SMTP configuration.'
});
}
// Send test email
await emailService.sendTestEmail(body.testEmail);
console.log('[api/admin/test-email.post] ✅ Test email sent successfully');
return {
success: true,
message: `Test email sent successfully to ${body.testEmail}`
};
} catch (error: any) {
console.error('[api/admin/test-email.post] ❌ Error sending test email:', error);
// Provide more specific error messages for common SMTP issues
let errorMessage = error.message || 'Failed to send test email';
if (error.code === 'EAUTH') {
errorMessage = 'SMTP authentication failed. Please check your username and password.';
} else if (error.code === 'ECONNECTION' || error.code === 'ETIMEDOUT') {
errorMessage = 'Could not connect to SMTP server. Please check your host and port settings.';
} else if (error.code === 'ESOCKET') {
errorMessage = 'Socket error. Please check your network connection and SMTP settings.';
}
throw createError({
statusCode: error.statusCode || 500,
statusMessage: errorMessage
});
}
});