first commit: Complete phishing test management panel with Node.js backend and React frontend
This commit is contained in:
146
backend/src/services/token.service.js
Normal file
146
backend/src/services/token.service.js
Normal file
@@ -0,0 +1,146 @@
|
||||
const { TrackingToken, Company, MailTemplate } = require('../models');
|
||||
const { generateTrackingToken } = require('../utils/tokenGenerator');
|
||||
const mailService = require('./mail.service');
|
||||
const logger = require('../config/logger');
|
||||
|
||||
class TokenService {
|
||||
async createToken(data) {
|
||||
const { company_id, target_email, employee_name, template_type } = data;
|
||||
|
||||
// Generate unique token
|
||||
let token = generateTrackingToken();
|
||||
let isUnique = false;
|
||||
let attempts = 0;
|
||||
|
||||
// Ensure token is unique
|
||||
while (!isUnique && attempts < 5) {
|
||||
const existing = await TrackingToken.findOne({ where: { token } });
|
||||
if (!existing) {
|
||||
isUnique = true;
|
||||
} else {
|
||||
token = generateTrackingToken();
|
||||
attempts++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isUnique) {
|
||||
throw new Error('Failed to generate unique token');
|
||||
}
|
||||
|
||||
// Get company and template
|
||||
const company = await Company.findByPk(company_id);
|
||||
if (!company) {
|
||||
throw new Error('Company not found');
|
||||
}
|
||||
|
||||
const template = await MailTemplate.findOne({ where: { template_type } });
|
||||
if (!template) {
|
||||
throw new Error('Mail template not found');
|
||||
}
|
||||
|
||||
// Create tracking token
|
||||
const trackingToken = await TrackingToken.create({
|
||||
token,
|
||||
company_id,
|
||||
target_email,
|
||||
employee_name,
|
||||
template_type,
|
||||
mail_subject: template.subject_template.replace('{{company_name}}', company.name),
|
||||
});
|
||||
|
||||
// Update company stats
|
||||
await company.increment('total_tokens');
|
||||
|
||||
logger.info(`Token created: ${token} for ${target_email}`);
|
||||
|
||||
return trackingToken;
|
||||
}
|
||||
|
||||
async sendMail(tokenId) {
|
||||
const token = await TrackingToken.findByPk(tokenId, {
|
||||
include: [{ model: Company, as: 'company' }],
|
||||
});
|
||||
|
||||
if (!token) {
|
||||
throw new Error('Token not found');
|
||||
}
|
||||
|
||||
if (token.mail_sent) {
|
||||
throw new Error('Mail already sent for this token');
|
||||
}
|
||||
|
||||
// Get mail template
|
||||
const template = await MailTemplate.findOne({
|
||||
where: { template_type: token.template_type },
|
||||
});
|
||||
|
||||
if (!template) {
|
||||
throw new Error('Mail template not found');
|
||||
}
|
||||
|
||||
// Prepare template data
|
||||
const trackingUrl = `${process.env.BASE_URL}/t/${token.token}`;
|
||||
const currentDate = new Date().toLocaleDateString('tr-TR', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
});
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
const templateData = {
|
||||
company_name: token.company.name,
|
||||
employee_name: token.employee_name,
|
||||
tracking_url: trackingUrl,
|
||||
current_date: currentDate,
|
||||
current_year: currentYear,
|
||||
};
|
||||
|
||||
// Render mail body
|
||||
const htmlBody = mailService.renderTemplate(template.body_html, templateData);
|
||||
const subject = mailService.renderTemplate(template.subject_template, templateData);
|
||||
|
||||
// Send mail
|
||||
await mailService.sendMail(token.target_email, subject, htmlBody);
|
||||
|
||||
// Update token
|
||||
await token.update({
|
||||
mail_sent: true,
|
||||
sent_at: new Date(),
|
||||
});
|
||||
|
||||
logger.info(`Mail sent for token: ${token.token} to ${token.target_email}`);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
async updateCompanyStats(companyId) {
|
||||
const company = await Company.findByPk(companyId);
|
||||
if (!company) return;
|
||||
|
||||
// Count tokens
|
||||
const totalTokens = await TrackingToken.count({
|
||||
where: { company_id: companyId },
|
||||
});
|
||||
|
||||
const clickedTokens = await TrackingToken.count({
|
||||
where: { company_id: companyId, clicked: true },
|
||||
});
|
||||
|
||||
const totalClicks = await TrackingToken.sum('click_count', {
|
||||
where: { company_id: companyId },
|
||||
});
|
||||
|
||||
const clickRate = totalTokens > 0 ? ((clickedTokens / totalTokens) * 100).toFixed(2) : 0;
|
||||
|
||||
await company.update({
|
||||
total_tokens: totalTokens,
|
||||
total_clicks: totalClicks || 0,
|
||||
click_rate: clickRate,
|
||||
});
|
||||
|
||||
logger.info(`Company stats updated for: ${company.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new TokenService();
|
||||
|
||||
Reference in New Issue
Block a user