diff --git a/backend/server.js b/backend/server.js index 7bb1ebd..cd5cbb0 100644 --- a/backend/server.js +++ b/backend/server.js @@ -11,9 +11,15 @@ const fs = require('fs'); const app = express(); const PORT = 3001; +// Log all incoming requests +app.use((req, res, next) => { + console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`); + next(); +}); + // Middleware app.use(cors({ - origin: ['http://localhost:3000', 'http://71.85.90.6:3000'], + origin: ['http://localhost:3000', 'http://192.168.2.117:3000'], credentials: true })); app.use(express.json()); @@ -163,15 +169,24 @@ app.get('/api/cves/:cveId/vendors', (req, res) => { // Create new CVE entry - ALLOW MULTIPLE VENDORS app.post('/api/cves', (req, res) => { - const { cve_id, vendor, severity, description, published_date } = req.body; + console.log('=== ADD CVE REQUEST ==='); + console.log('Body:', req.body); + console.log('======================='); + const { cve_id, vendor, severity, description, published_date } = req.body; + const query = ` INSERT INTO cves (cve_id, vendor, severity, description, published_date) VALUES (?, ?, ?, ?, ?) `; - + + console.log('Query:', query); + console.log('Values:', [cve_id, vendor, severity, description, published_date]); + db.run(query, [cve_id, vendor, severity, description, published_date], function(err) { if (err) { + console.error('DATABASE ERROR:', err); // Make sure this is here + // ... rest of error handling // Check if it's a duplicate CVE_ID + Vendor combination if (err.message.includes('UNIQUE constraint failed')) { return res.status(409).json({ @@ -196,7 +211,8 @@ app.patch('/api/cves/:cveId/status', (req, res) => { const query = `UPDATE cves SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE cve_id = ?`; - db.run(query, [status, cveId], function(err) { + db.run(query, [ + vendor,status, cveId], function(err) { if (err) { return res.status(500).json({ error: err.message }); } @@ -229,66 +245,82 @@ app.get('/api/cves/:cveId/documents', (req, res) => { }); }); -// Upload document -app.post('/api/cves/:cveId/documents', upload.single('file'), (req, res) => { - const { cveId } = req.params; - const { type, notes, vendor } = req.body; - const file = req.file; - - if (!file) { - return res.status(400).json({ error: 'No file uploaded' }); - } - - if (!vendor) { - return res.status(400).json({ error: 'Vendor is required' }); - } - - // Move file from temp to proper location - const finalDir = path.join('uploads', cveId, vendor); - if (!fs.existsSync(finalDir)) { - fs.mkdirSync(finalDir, { recursive: true }); - } - - const finalPath = path.join(finalDir, file.filename); - - // Move file from temp to final location - fs.renameSync(file.path, finalPath); - - const query = ` - INSERT INTO documents (cve_id, name, type, file_path, file_size, mime_type, notes) - VALUES (?, ?, ?, ?, ?, ?, ?) - `; - - const fileSizeKB = (file.size / 1024).toFixed(2) + ' KB'; - - db.run(query, [ - cveId, - file.originalname, - type, - finalPath, - fileSizeKB, - file.mimetype, - notes - ], function(err) { +// Upload document - ADD ERROR HANDLING FOR MULTER +app.post('/api/cves/:cveId/documents', (req, res, next) => { + upload.single('file')(req, res, (err) => { if (err) { - // If database insert fails, delete the file - if (fs.existsSync(finalPath)) { - fs.unlinkSync(finalPath); - } - return res.status(500).json({ error: err.message }); + console.error('MULTER ERROR:', err); + return res.status(500).json({ error: 'File upload failed: ' + err.message }); } - res.json({ - id: this.lastID, - message: 'Document uploaded successfully', - file: { - name: file.originalname, - path: finalPath, - size: fileSizeKB + + console.log('=== UPLOAD REQUEST RECEIVED ==='); + console.log('CVE ID:', req.params.cveId); + console.log('Body:', req.body); + console.log('File:', req.file); + console.log('================================'); + + const { cveId } = req.params; + const { type, notes, vendor } = req.body; + const file = req.file; + + if (!file) { + console.error('ERROR: No file uploaded'); + return res.status(400).json({ error: 'No file uploaded' }); + } + + if (!vendor) { + console.error('ERROR: Vendor is required'); + return res.status(400).json({ error: 'Vendor is required' }); + } + + // Move file from temp to proper location + const finalDir = path.join('uploads', cveId, vendor); + if (!fs.existsSync(finalDir)) { + fs.mkdirSync(finalDir, { recursive: true }); + } + + const finalPath = path.join(finalDir, file.filename); + + // Move file from temp to final location + fs.renameSync(file.path, finalPath); + + const query = ` + INSERT INTO documents (cve_id, vendor, name, type, file_path, file_size, mime_type, notes) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + `; + + const fileSizeKB = (file.size / 1024).toFixed(2) + ' KB'; + + db.run(query, [ + cveId, + vendor, + file.originalname, + type, + finalPath, + fileSizeKB, + file.mimetype, + notes + ], function(err) { + if (err) { + console.error('DATABASE ERROR:', err); + // If database insert fails, delete the file + if (fs.existsSync(finalPath)) { + fs.unlinkSync(finalPath); + } + return res.status(500).json({ error: err.message }); } + res.json({ + id: this.lastID, + message: 'Document uploaded successfully', + file: { + name: file.originalname, + path: finalPath, + size: fileSizeKB + } + }); }); }); }); - // Delete document app.delete('/api/documents/:id', (req, res) => { const { id } = req.params; diff --git a/backend/setup.js b/backend/setup.js index 7b62398..9e38cc8 100644 --- a/backend/setup.js +++ b/backend/setup.js @@ -1,5 +1,5 @@ // Setup Script for CVE Database -// This creates a fresh database ready for new CVE entries +// This creates a fresh database with multi-vendor support built-in const sqlite3 = require('sqlite3').verbose(); const fs = require('fs'); @@ -18,19 +18,21 @@ function initializeDatabase() { const schema = ` CREATE TABLE IF NOT EXISTS cves ( id INTEGER PRIMARY KEY AUTOINCREMENT, - cve_id VARCHAR(20) UNIQUE NOT NULL, + cve_id VARCHAR(20) NOT NULL, vendor VARCHAR(100) NOT NULL, severity VARCHAR(20) NOT NULL, description TEXT, published_date DATE, status VARCHAR(50) DEFAULT 'Open', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(cve_id, vendor) ); CREATE TABLE IF NOT EXISTS documents ( id INTEGER PRIMARY KEY AUTOINCREMENT, cve_id VARCHAR(20) NOT NULL, + vendor VARCHAR(100) NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(50) NOT NULL, file_path VARCHAR(500) NOT NULL, @@ -54,6 +56,7 @@ function initializeDatabase() { CREATE INDEX IF NOT EXISTS idx_severity ON cves(severity); CREATE INDEX IF NOT EXISTS idx_status ON cves(status); CREATE INDEX IF NOT EXISTS idx_doc_cve_id ON documents(cve_id); + CREATE INDEX IF NOT EXISTS idx_doc_vendor ON documents(vendor); CREATE INDEX IF NOT EXISTS idx_doc_type ON documents(type); INSERT OR IGNORE INTO required_documents (vendor, document_type, is_mandatory, description) VALUES @@ -66,6 +69,7 @@ function initializeDatabase() { CREATE VIEW IF NOT EXISTS cve_document_status AS SELECT + c.id as record_id, c.cve_id, c.vendor, c.severity, @@ -80,8 +84,8 @@ function initializeDatabase() { ELSE 'Missing Required Docs' END as compliance_status FROM cves c - LEFT JOIN documents d ON c.cve_id = d.cve_id - GROUP BY c.cve_id, c.vendor, c.severity, c.status; + LEFT JOIN documents d ON c.cve_id = d.cve_id AND c.vendor = d.vendor + GROUP BY c.id, c.cve_id, c.vendor, c.severity, c.status; `; db.exec(schema, (err) => { @@ -107,17 +111,21 @@ function createUploadsDirectory() { // Add sample CVE data (optional - for testing) async function addSampleData(db) { - console.log('\nš Would you like to add sample CVE data for testing? (y/n)'); + console.log('\nš Adding sample CVE data for testing...'); - // For automated setup, we'll skip this. Uncomment the code below if you want samples. - - /* const sampleCVEs = [ { cve_id: 'CVE-2024-SAMPLE-1', vendor: 'Microsoft', severity: 'Critical', - description: 'Sample vulnerability for testing', + description: 'Sample remote code execution vulnerability', + published_date: '2024-01-15' + }, + { + cve_id: 'CVE-2024-SAMPLE-1', + vendor: 'Cisco', + severity: 'High', + description: 'Sample remote code execution vulnerability', published_date: '2024-01-15' } ]; @@ -131,16 +139,37 @@ async function addSampleData(db) { (err) => { if (err) reject(err); else { - console.log(` ā Added sample CVE: ${cve.cve_id}`); + console.log(` ā Added sample: ${cve.cve_id} / ${cve.vendor}`); resolve(); } } ); }); } - */ - console.log('ā¹ļø Skipping sample data - you can add CVEs through the API or dashboard'); + console.log('ā¹ļø Sample data added - demonstrates multi-vendor support'); +} + +// Verify database structure +async function verifySetup(db) { + return new Promise((resolve) => { + db.get('SELECT sql FROM sqlite_master WHERE type="table" AND name="cves"', (err, row) => { + if (err) { + console.error('Warning: Could not verify setup:', err); + } else { + console.log('\nš CVEs table structure:'); + console.log(row.sql); + + // Check if UNIQUE constraint is correct + if (row.sql.includes('UNIQUE(cve_id, vendor)')) { + console.log('\nā Multi-vendor support: ENABLED'); + } else { + console.log('\nā ļø Warning: Multi-vendor constraint may not be set correctly'); + } + } + resolve(); + }); + }); } // Display setup summary @@ -151,33 +180,37 @@ function displaySummary() { console.log('\nš What was created:'); console.log(' ā SQLite database (cve_database.db)'); console.log(' ā Tables: cves, documents, required_documents'); + console.log(' ā Multi-vendor support with UNIQUE(cve_id, vendor)'); + console.log(' ā Vendor column in documents table'); console.log(' ā Indexes for fast queries'); console.log(' ā Document compliance view'); console.log(' ā Uploads directory for file storage'); console.log('\nš File structure will be:'); console.log(' uploads/'); console.log(' āāā CVE-XXXX-XXXX/'); - console.log(' āāā VendorName/'); - console.log(' āāā advisory.pdf'); - console.log(' āāā email.pdf'); - console.log(' āāā screenshot.png'); + console.log(' āāā Vendor1/'); + console.log(' ā āāā advisory.pdf'); + console.log(' ā āāā screenshot.png'); + console.log(' āāā Vendor2/'); + console.log(' āāā advisory.pdf'); console.log('\nš Next steps:'); console.log(' 1. Start the backend API:'); console.log(' ā cd backend && node server.js'); console.log(' 2. Start the frontend:'); console.log(' ā cd frontend && npm start'); console.log(' 3. Open http://localhost:3000'); - console.log(' 4. Start adding CVEs and uploading documents!'); - console.log('\nš” Tips:'); - console.log(' ⢠Use the Quick Check to verify CVE status'); - console.log(' ⢠Upload documents through the dashboard'); - console.log(' ⢠Documents are auto-organized by CVE ID ā Vendor'); + console.log(' 4. Start adding CVEs with multiple vendors!'); + console.log('\nš” Key Features:'); + console.log(' ⢠Add same CVE-ID with different vendors'); + console.log(' ⢠Each vendor has separate document storage'); + console.log(' ⢠Quick Check shows all vendors for a CVE'); + console.log(' ⢠Document compliance tracking per vendor'); console.log(' ⢠Required docs: Advisory (mandatory for most vendors)\n'); } // Main execution async function main() { - console.log('š CVE Database Setup\n'); + console.log('š CVE Database Setup (Multi-Vendor Support)\n'); console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'); try { @@ -187,13 +220,16 @@ async function main() { // Initialize database const db = await initializeDatabase(); - // Optionally add sample data + // Add sample data await addSampleData(db); + // Verify setup + await verifySetup(db); + // Close database connection db.close((err) => { if (err) console.error('Error closing database:', err); - else console.log('ā Database connection closed'); + else console.log('\nā Database connection closed'); // Display summary displaySummary(); @@ -206,4 +242,4 @@ async function main() { } // Run the setup -main(); \ No newline at end of file +main(); diff --git a/frontend/src/App.js b/frontend/src/App.js index 3cef783..78fcf91 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Search, FileText, AlertCircle, Download, Upload, Eye, Filter, CheckCircle, XCircle, Loader, Trash2, Plus } from 'lucide-react'; -const API_BASE = 'http://71.85.90.6:3001/api'; +const API_BASE = 'http://192.168.2.117:3001/api'; const severityLevels = ['All Severities', 'Critical', 'High', 'Medium', 'Low']; @@ -626,7 +626,7 @@ export default function App() {