Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions backend/routes/emailIntegrationRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const express = require('express');
const router = express.Router();
const { protect } = require('../middleware/authMiddleware');
const headerAnalyzer = require('../services/headerAnalyzer');
const emailAuthValidator = require('../services/emailAuthValidator');


const {
gmailAuthUrl,
Expand All @@ -16,6 +18,21 @@ const {
scanEmails
} = require('../controllers/emailController');

router.post('/validate-email-auth', protect, async (req, res) => {
try {
const { domain } = req.body;

if (!domain) {
return res.status(400).json({ error: 'Domain is required' });
}

const result = await emailAuthValidator.validateDomain(domain);
res.json(result);
} catch (error) {
res.status(500).json({ error: 'Failed to validate email authentication' });
}
});

router.post('/analyze-headers', protect, async (req, res) => {
try {
const { headers } = req.body;
Expand Down
123 changes: 123 additions & 0 deletions backend/services/emailAuthValidator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
const dns = require('dns');

class EmailAuthValidator {
async validateDomain(domain) {
const results = {
domain,
spf: await this.checkSPF(domain),
dkim: await this.checkDKIM(domain),
dmarc: await this.checkDMARC(domain),
overall: 'warning'
};

// Calculate overall status
const scores = [results.spf.pass, results.dkim.pass, results.dmarc.pass];
const passCount = scores.filter(Boolean).length;
results.overall = passCount >= 2 ? 'pass' : passCount >= 1 ? 'warning' : 'fail';

return results;
}

async checkSPF(domain) {
return new Promise((resolve) => {
dns.resolveTxt(domain, (err, records) => {
if (err) {
resolve({
pass: false,
status: 'fail',
details: 'No SPF record found. Domain is vulnerable to spoofing.',
fix: 'Add an SPF record: v=spf1 include:spf.protection.outlook.com -all'
});
return;
}
const spf = records.flat().find(r => r.includes('v=spf1'));
if (spf) {
resolve({
pass: true,
status: 'pass',
details: 'SPF record found and configured correctly.',
record: spf,
fix: 'Your SPF record looks good. No changes needed.'
});
} else {
resolve({
pass: false,
status: 'fail',
details: 'No SPF record found. Domain is vulnerable to spoofing.',
fix: 'Add an SPF record: v=spf1 include:spf.protection.outlook.com -all'
});
}
});
});
}

async checkDKIM(domain) {
const selectors = ['default', 'google', 'microsoft', 'selector1', 'selector2', 'dkim'];
let found = false;

for (const selector of selectors) {
const record = `${selector}._domainkey.${domain}`;
try {
const result = await this.resolveTXT(record);
if (result) {
found = true;
return {
pass: true,
status: 'pass',
details: `DKIM record found (${selector})`,
record: result,
fix: 'DKIM configuration looks good.'
};
}
} catch (e) {
// Continue to next selector
}
}

return {
pass: false,
status: 'fail',
details: 'No DKIM record found. Emails may be marked as spam.',
fix: 'Add DKIM records for your email provider. Contact your email hosting provider for DKIM keys.'
};
}

async checkDMARC(domain) {
try {
const record = `_dmarc.${domain}`;
const result = await this.resolveTXT(record);
if (result) {
return {
pass: true,
status: 'pass',
details: 'DMARC record found',
record: result,
fix: 'DMARC configuration looks good.'
};
}
} catch (e) {
// No DMARC record
}

return {
pass: false,
status: 'fail',
details: 'No DMARC record found. Domain is vulnerable to spoofing.',
fix: 'Add a DMARC record: v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com'
};
}

resolveTXT(record) {
return new Promise((resolve, reject) => {
dns.resolveTxt(record, (err, records) => {
if (err) {
reject(err);
} else {
resolve(records.flat().join(''));
}
});
});
}
}

module.exports = new EmailAuthValidator();
5 changes: 5 additions & 0 deletions frontend/src/pages/Dashboard.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState, useEffect, useCallback } from "react";
import { useNavigate } from "react-router-dom";
import { EmailAuthValidator } from '../components/EmailAuthValidator';
import {
ResponsiveContainer,
LineChart,
Expand Down Expand Up @@ -270,6 +271,10 @@ export default function Dashboard() {
)}
</div>

<div className="dashboard-grid">
<EmailAuthValidator />
</div>

{/* Breakdown chart */}
<div
className={`rounded-2xl p-4 sm:p-6 shadow-lg border ${
Expand Down
Loading