- Updated all component headers and documentation
- Changed navbar and footer branding
- Updated homepage hero badge
- Modified page title in index.html
- Simplified footer text to 'Built with ❤️'
- Consistent V2 capitalization across all references
316 lines
12 KiB
JavaScript
316 lines
12 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const express_1 = __importDefault(require("express"));
|
|
const zod_1 = require("zod");
|
|
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
const ssl_analyzer_service_1 = require("../services/ssl-analyzer.service");
|
|
const seo_analyzer_service_1 = require("../services/seo-analyzer.service");
|
|
const security_analyzer_service_1 = require("../services/security-analyzer.service");
|
|
const auth_middleware_1 = require("../middleware/auth.middleware");
|
|
const logger_1 = require("../lib/logger");
|
|
const prisma_1 = require("../lib/prisma");
|
|
const router = express_1.default.Router();
|
|
const sslAnalyzer = new ssl_analyzer_service_1.SSLAnalyzerService();
|
|
const seoAnalyzer = new seo_analyzer_service_1.SEOAnalyzerService();
|
|
const securityAnalyzer = new security_analyzer_service_1.SecurityAnalyzerService();
|
|
const analysisLimiter = (0, express_rate_limit_1.default)({
|
|
windowMs: 60 * 60 * 1000,
|
|
max: 100,
|
|
message: {
|
|
success: false,
|
|
error: 'Analysis rate limit exceeded',
|
|
message: 'Too many analysis requests. Please try again later.'
|
|
},
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
keyGenerator: (req) => {
|
|
return req.user ? `user:${req.user.id}` : `ip:${req.ip}`;
|
|
},
|
|
});
|
|
const analyzeUrlSchema = zod_1.z.object({
|
|
url: zod_1.z.string().url('Invalid URL format'),
|
|
});
|
|
router.post('/ssl', auth_middleware_1.optionalAuth, analysisLimiter, async (req, res) => {
|
|
try {
|
|
const { url } = analyzeUrlSchema.parse(req.body);
|
|
let analyzeUrl = url;
|
|
if (!analyzeUrl.startsWith('http://') && !analyzeUrl.startsWith('https://')) {
|
|
analyzeUrl = 'https://' + analyzeUrl;
|
|
}
|
|
if (!analyzeUrl.startsWith('https://')) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Invalid URL for SSL analysis',
|
|
message: 'SSL analysis requires HTTPS URLs'
|
|
});
|
|
}
|
|
const result = await sslAnalyzer.analyzeSSL(analyzeUrl);
|
|
logger_1.logger.info(`SSL analysis completed for: ${analyzeUrl}`, {
|
|
userId: req.user?.id,
|
|
securityScore: result.securityScore,
|
|
warningsCount: result.warnings.length
|
|
});
|
|
res.json({
|
|
success: true,
|
|
status: 200,
|
|
data: {
|
|
analysis: result,
|
|
url: analyzeUrl,
|
|
},
|
|
meta: {
|
|
version: 'v2',
|
|
analysisType: 'ssl',
|
|
timestamp: new Date().toISOString(),
|
|
}
|
|
});
|
|
}
|
|
catch (error) {
|
|
logger_1.logger.error('SSL analysis failed:', error);
|
|
if (error instanceof zod_1.z.ZodError) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Validation error',
|
|
message: error.errors[0]?.message || 'Invalid input',
|
|
details: error.errors
|
|
});
|
|
}
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'SSL analysis failed',
|
|
message: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
});
|
|
}
|
|
});
|
|
router.post('/seo', auth_middleware_1.optionalAuth, analysisLimiter, async (req, res) => {
|
|
try {
|
|
const { url } = analyzeUrlSchema.parse(req.body);
|
|
let analyzeUrl = url;
|
|
if (!analyzeUrl.startsWith('http://') && !analyzeUrl.startsWith('https://')) {
|
|
analyzeUrl = 'https://' + analyzeUrl;
|
|
}
|
|
const result = await seoAnalyzer.analyzeSEO(analyzeUrl);
|
|
logger_1.logger.info(`SEO analysis completed for: ${analyzeUrl}`, {
|
|
userId: req.user?.id,
|
|
score: result.score,
|
|
robotsStatus: result.flags.robotsTxtStatus,
|
|
noindex: result.flags.noindex
|
|
});
|
|
res.json({
|
|
success: true,
|
|
status: 200,
|
|
data: {
|
|
analysis: result,
|
|
url: analyzeUrl,
|
|
},
|
|
meta: {
|
|
version: 'v2',
|
|
analysisType: 'seo',
|
|
timestamp: new Date().toISOString(),
|
|
}
|
|
});
|
|
}
|
|
catch (error) {
|
|
logger_1.logger.error('SEO analysis failed:', error);
|
|
if (error instanceof zod_1.z.ZodError) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Validation error',
|
|
message: error.errors[0]?.message || 'Invalid input',
|
|
details: error.errors
|
|
});
|
|
}
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'SEO analysis failed',
|
|
message: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
});
|
|
}
|
|
});
|
|
router.post('/security', auth_middleware_1.optionalAuth, analysisLimiter, async (req, res) => {
|
|
try {
|
|
const { url } = analyzeUrlSchema.parse(req.body);
|
|
let analyzeUrl = url;
|
|
if (!analyzeUrl.startsWith('http://') && !analyzeUrl.startsWith('https://')) {
|
|
analyzeUrl = 'https://' + analyzeUrl;
|
|
}
|
|
const result = await securityAnalyzer.analyzeSecurity(analyzeUrl);
|
|
logger_1.logger.info(`Security analysis completed for: ${analyzeUrl}`, {
|
|
userId: req.user?.id,
|
|
securityScore: result.securityScore,
|
|
safeBrowsing: result.safeBrowsing.status,
|
|
vulnerabilityCount: result.vulnerabilities.length
|
|
});
|
|
res.json({
|
|
success: true,
|
|
status: 200,
|
|
data: {
|
|
analysis: result,
|
|
url: analyzeUrl,
|
|
},
|
|
meta: {
|
|
version: 'v2',
|
|
analysisType: 'security',
|
|
timestamp: new Date().toISOString(),
|
|
}
|
|
});
|
|
}
|
|
catch (error) {
|
|
logger_1.logger.error('Security analysis failed:', error);
|
|
if (error instanceof zod_1.z.ZodError) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Validation error',
|
|
message: error.errors[0]?.message || 'Invalid input',
|
|
details: error.errors
|
|
});
|
|
}
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Security analysis failed',
|
|
message: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
});
|
|
}
|
|
});
|
|
router.post('/comprehensive', auth_middleware_1.optionalAuth, analysisLimiter, async (req, res) => {
|
|
try {
|
|
const { url } = analyzeUrlSchema.parse(req.body);
|
|
let analyzeUrl = url;
|
|
if (!analyzeUrl.startsWith('http://') && !analyzeUrl.startsWith('https://')) {
|
|
analyzeUrl = 'https://' + analyzeUrl;
|
|
}
|
|
logger_1.logger.info(`Starting comprehensive analysis for: ${analyzeUrl}`, {
|
|
userId: req.user?.id
|
|
});
|
|
const [sslResult, seoResult, securityResult] = await Promise.allSettled([
|
|
analyzeUrl.startsWith('https://') ? sslAnalyzer.analyzeSSL(analyzeUrl) : Promise.resolve(null),
|
|
seoAnalyzer.analyzeSEO(analyzeUrl),
|
|
securityAnalyzer.analyzeSecurity(analyzeUrl),
|
|
]);
|
|
const analysis = {
|
|
ssl: sslResult.status === 'fulfilled' ? sslResult.value : {
|
|
error: sslResult.status === 'rejected' ? sslResult.reason?.message : 'SSL analysis failed'
|
|
},
|
|
seo: seoResult.status === 'fulfilled' ? seoResult.value : {
|
|
error: seoResult.status === 'rejected' ? seoResult.reason?.message : 'SEO analysis failed'
|
|
},
|
|
security: securityResult.status === 'fulfilled' ? securityResult.value : {
|
|
error: securityResult.status === 'rejected' ? securityResult.reason?.message : 'Security analysis failed'
|
|
},
|
|
};
|
|
const scores = [
|
|
analysis.ssl && 'securityScore' in analysis.ssl ? analysis.ssl.securityScore : 0,
|
|
analysis.seo && 'score' in analysis.seo ? analysis.seo.score : 0,
|
|
analysis.security && 'securityScore' in analysis.security ? analysis.security.securityScore : 0,
|
|
].filter(score => score > 0);
|
|
const overallScore = scores.length > 0 ? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length) : 0;
|
|
logger_1.logger.info(`Comprehensive analysis completed for: ${analyzeUrl}`, {
|
|
userId: req.user?.id,
|
|
overallScore,
|
|
sslSuccess: sslResult.status === 'fulfilled',
|
|
seoSuccess: seoResult.status === 'fulfilled',
|
|
securitySuccess: securityResult.status === 'fulfilled'
|
|
});
|
|
res.json({
|
|
success: true,
|
|
status: 200,
|
|
data: {
|
|
analysis,
|
|
summary: {
|
|
overallScore,
|
|
analysesCompleted: scores.length,
|
|
totalAnalyses: 3,
|
|
},
|
|
url: analyzeUrl,
|
|
},
|
|
meta: {
|
|
version: 'v2',
|
|
analysisType: 'comprehensive',
|
|
timestamp: new Date().toISOString(),
|
|
}
|
|
});
|
|
}
|
|
catch (error) {
|
|
logger_1.logger.error('Comprehensive analysis failed:', error);
|
|
if (error instanceof zod_1.z.ZodError) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Validation error',
|
|
message: error.errors[0]?.message || 'Invalid input',
|
|
details: error.errors
|
|
});
|
|
}
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Comprehensive analysis failed',
|
|
message: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
});
|
|
}
|
|
});
|
|
router.get('/check/:checkId', auth_middleware_1.optionalAuth, async (req, res) => {
|
|
try {
|
|
const { checkId } = req.params;
|
|
if (!checkId) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Check ID required'
|
|
});
|
|
}
|
|
const check = await prisma_1.prisma.check.findUnique({
|
|
where: { id: checkId },
|
|
include: {
|
|
hops: {
|
|
orderBy: { hopIndex: 'asc' }
|
|
},
|
|
sslInspections: true,
|
|
seoFlags: true,
|
|
securityFlags: true,
|
|
}
|
|
});
|
|
if (!check) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
error: 'Check not found',
|
|
message: 'The requested check does not exist or you do not have access to it'
|
|
});
|
|
}
|
|
res.json({
|
|
success: true,
|
|
status: 200,
|
|
data: {
|
|
check: {
|
|
id: check.id,
|
|
inputUrl: check.inputUrl,
|
|
finalUrl: check.finalUrl,
|
|
status: check.status,
|
|
startedAt: check.startedAt,
|
|
finishedAt: check.finishedAt,
|
|
totalTimeMs: check.totalTimeMs,
|
|
},
|
|
analysis: {
|
|
ssl: check.sslInspections,
|
|
seo: check.seoFlags,
|
|
security: check.securityFlags,
|
|
},
|
|
hops: check.hops,
|
|
},
|
|
meta: {
|
|
version: 'v2',
|
|
checkId: check.id,
|
|
timestamp: new Date().toISOString(),
|
|
}
|
|
});
|
|
}
|
|
catch (error) {
|
|
logger_1.logger.error('Failed to retrieve check analysis:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to retrieve analysis',
|
|
message: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
});
|
|
}
|
|
});
|
|
exports.default = router;
|
|
//# sourceMappingURL=analysis.routes.js.map
|