mirror of
https://github.com/mblanke/ThreatHunt.git
synced 2026-03-01 14:00:20 -05:00
CLAUDE branch
i made have screwed the pooch with this
This commit is contained in:
70
README.md
70
README.md
@@ -1 +1,69 @@
|
|||||||
# ThreatHunt
|
<<<<<<< Updated upstream
|
||||||
|
# ThreatHunt
|
||||||
|
=======
|
||||||
|
# Cyber Threat Hunter
|
||||||
|
|
||||||
|
A modern web application for threat hunting and security analysis, built with React frontend and Flask backend.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Security Tools Detection**: Identify running security tools (AV, EDR, VPN)
|
||||||
|
- **CSV Processing**: Upload and analyze security logs
|
||||||
|
- **Baseline Analysis**: System baseline comparison
|
||||||
|
- **Network Analysis**: Network traffic and connection analysis
|
||||||
|
- **VirusTotal Integration**: File and URL reputation checking
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
ThreatHunt/
|
||||||
|
├── frontend/ # React application
|
||||||
|
├── backend/ # Flask API server
|
||||||
|
├── uploaded/ # File upload storage
|
||||||
|
└── output/ # Analysis results
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Backend Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
chmod +x setup_backend.sh
|
||||||
|
./setup_backend.sh
|
||||||
|
source venv/bin/activate
|
||||||
|
python app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
- `GET /` - Serve React app
|
||||||
|
- `GET /api/health` - Health check
|
||||||
|
- `POST /api/upload` - File upload
|
||||||
|
- `GET /api/analysis/<id>` - Get analysis results
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
- File upload validation
|
||||||
|
- Input sanitization
|
||||||
|
- Rate limiting
|
||||||
|
- CORS configuration
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Create feature branch
|
||||||
|
3. Submit pull request
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
>>>>>>> Stashed changes
|
||||||
|
|||||||
9
backend/.env
Normal file
9
backend/.env
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FLASK_ENV=development
|
||||||
|
FLASK_DEBUG=True
|
||||||
|
SECRET_KEY=development-secret-key-change-in-production
|
||||||
|
MAX_CONTENT_LENGTH=104857600
|
||||||
|
UPLOAD_FOLDER=uploaded
|
||||||
|
OUTPUT_FOLDER=output
|
||||||
|
VIRUSTOTAL_API_KEY=
|
||||||
|
DATABASE_URL=sqlite:///threat_hunter.db
|
||||||
|
REDIS_URL=redis://localhost:6379/0
|
||||||
277
backend/app.py
Normal file
277
backend/app.py
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from flask import Flask, request, jsonify, send_from_directory
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# Try to import flask-cors
|
||||||
|
try:
|
||||||
|
from flask_cors import CORS
|
||||||
|
CORS_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
CORS_AVAILABLE = False
|
||||||
|
print("Warning: flask-cors not available")
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
app = Flask(__name__, static_folder="../frontend/dist")
|
||||||
|
|
||||||
|
# Enable CORS
|
||||||
|
if CORS_AVAILABLE:
|
||||||
|
CORS(app)
|
||||||
|
else:
|
||||||
|
@app.after_request
|
||||||
|
def after_request(response):
|
||||||
|
response.headers.add('Access-Control-Allow-Origin', '*')
|
||||||
|
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
|
||||||
|
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
|
||||||
|
return response
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
|
||||||
|
app.config['UPLOAD_FOLDER'] = 'uploaded'
|
||||||
|
app.config['ALLOWED_EXTENSIONS'] = {'csv', 'json', 'txt', 'log'}
|
||||||
|
|
||||||
|
# Ensure upload directory exists
|
||||||
|
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
||||||
|
|
||||||
|
@app.route('/api/health')
|
||||||
|
def health_check():
|
||||||
|
return jsonify({
|
||||||
|
'status': 'healthy',
|
||||||
|
'timestamp': datetime.utcnow().isoformat(),
|
||||||
|
'version': '1.0.0',
|
||||||
|
'service': 'Cyber Threat Hunter API'
|
||||||
|
})
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return jsonify({'message': 'Cyber Threat Hunter API', 'status': 'running'})
|
||||||
|
|
||||||
|
@app.route('/api/test')
|
||||||
|
def test():
|
||||||
|
return jsonify({'message': 'API is working', 'timestamp': datetime.now().isoformat()})
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("=" * 50)
|
||||||
|
print("Starting Cyber Threat Hunter Backend...")
|
||||||
|
print("API available at: http://localhost:5000")
|
||||||
|
print("Health check: http://localhost:5000/api/health")
|
||||||
|
print("=" * 50)
|
||||||
|
app.run(host="0.0.0.0", port=5000, debug=True)
|
||||||
|
@app.errorhandler(RequestEntityTooLarge)
|
||||||
|
def handle_file_too_large(e):
|
||||||
|
return jsonify({'error': 'File too large. Maximum size is 100MB.'}), 413
|
||||||
|
|
||||||
|
@app.errorhandler(Exception)
|
||||||
|
def handle_exception(e):
|
||||||
|
logger.error(f"Unhandled exception: {e}")
|
||||||
|
return jsonify({'error': 'Internal server error'}), 500
|
||||||
|
|
||||||
|
# Security analysis functions
|
||||||
|
def analyze_security_tools(csv_path):
|
||||||
|
"""Analyze CSV for security tools based on process names."""
|
||||||
|
try:
|
||||||
|
df = pd.read_csv(csv_path)
|
||||||
|
|
||||||
|
# Load security tools list
|
||||||
|
tools_file = os.path.join('lists', 'security-tools.md')
|
||||||
|
if not os.path.exists(tools_file):
|
||||||
|
return {'error': 'Security tools list not found'}
|
||||||
|
|
||||||
|
with open(tools_file, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
# Extract tool names (simplified)
|
||||||
|
tools = set()
|
||||||
|
for line in content.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
if line and not line.startswith('#') and not line.endswith(':'):
|
||||||
|
if line.lower().endswith('.exe') or '.' not in line:
|
||||||
|
tools.add(line.lower())
|
||||||
|
|
||||||
|
# Analyze CSV for tools
|
||||||
|
process_col = None
|
||||||
|
for col in df.columns:
|
||||||
|
if any(keyword in col.lower() for keyword in ['process', 'image', 'executable']):
|
||||||
|
process_col = col
|
||||||
|
break
|
||||||
|
|
||||||
|
if not process_col:
|
||||||
|
return {'error': 'No process column found in CSV'}
|
||||||
|
|
||||||
|
found_tools = {}
|
||||||
|
for _, row in df.iterrows():
|
||||||
|
process_name = str(row[process_col]).lower()
|
||||||
|
for tool in tools:
|
||||||
|
if tool in process_name:
|
||||||
|
host = row.get('host', row.get('hostname', 'unknown'))
|
||||||
|
if tool not in found_tools:
|
||||||
|
found_tools[tool] = set()
|
||||||
|
found_tools[tool].add(host)
|
||||||
|
|
||||||
|
# Convert sets to lists for JSON serialization
|
||||||
|
result = {tool: list(hosts) for tool, hosts in found_tools.items()}
|
||||||
|
return {'tools_found': result, 'total_tools': len(result)}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Security tools analysis error: {e}")
|
||||||
|
return {'error': str(e)}
|
||||||
|
|
||||||
|
# API Routes
|
||||||
|
@app.route('/api/health')
|
||||||
|
def health_check():
|
||||||
|
return jsonify({
|
||||||
|
'status': 'healthy',
|
||||||
|
'timestamp': datetime.utcnow().isoformat(),
|
||||||
|
'version': '1.0.0'
|
||||||
|
})
|
||||||
|
|
||||||
|
@app.route('/api/upload', methods=['POST'])
|
||||||
|
def upload_file():
|
||||||
|
try:
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return jsonify({'error': 'No file provided'}), 400
|
||||||
|
|
||||||
|
file = request.files['file']
|
||||||
|
if file.filename == '':
|
||||||
|
return jsonify({'error': 'No file selected'}), 400
|
||||||
|
|
||||||
|
if not allowed_file(file.filename):
|
||||||
|
return jsonify({'error': 'File type not allowed'}), 400
|
||||||
|
|
||||||
|
filename = secure_filename(file.filename)
|
||||||
|
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||||
|
filename = f"{timestamp}_{filename}"
|
||||||
|
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||||
|
|
||||||
|
file.save(filepath)
|
||||||
|
|
||||||
|
logger.info(f"File uploaded successfully: {filename}")
|
||||||
|
return jsonify({
|
||||||
|
'message': 'File uploaded successfully',
|
||||||
|
'filename': filename,
|
||||||
|
'size': os.path.getsize(filepath)
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Upload error: {e}")
|
||||||
|
return jsonify({'error': 'Upload failed'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/files')
|
||||||
|
def list_files():
|
||||||
|
try:
|
||||||
|
files = []
|
||||||
|
upload_dir = app.config['UPLOAD_FOLDER']
|
||||||
|
|
||||||
|
for filename in os.listdir(upload_dir):
|
||||||
|
filepath = os.path.join(upload_dir, filename)
|
||||||
|
if os.path.isfile(filepath):
|
||||||
|
stat = os.stat(filepath)
|
||||||
|
files.append({
|
||||||
|
'name': filename,
|
||||||
|
'size': stat.st_size,
|
||||||
|
'modified': datetime.fromtimestamp(stat.st_mtime).isoformat()
|
||||||
|
})
|
||||||
|
|
||||||
|
return jsonify({'files': files})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"List files error: {e}")
|
||||||
|
return jsonify({'error': 'Failed to list files'}), 500
|
||||||
|
|
||||||
|
# Security tools analysis endpoint
|
||||||
|
@app.route('/api/analyze/security-tools/<filename>')
|
||||||
|
def analyze_security_tools_endpoint(filename):
|
||||||
|
try:
|
||||||
|
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||||
|
if not os.path.exists(filepath):
|
||||||
|
return jsonify({'error': 'File not found'}), 404
|
||||||
|
|
||||||
|
result = analyze_security_tools(filepath)
|
||||||
|
return jsonify(result)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Security tools analysis endpoint error: {e}")
|
||||||
|
return jsonify({'error': 'Analysis failed'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/analyze/<filename>')
|
||||||
|
def analyze_file(filename):
|
||||||
|
try:
|
||||||
|
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||||
|
if not os.path.exists(filepath):
|
||||||
|
return jsonify({'error': 'File not found'}), 404
|
||||||
|
|
||||||
|
# Basic file analysis
|
||||||
|
file_stats = os.stat(filepath)
|
||||||
|
analysis = {
|
||||||
|
'filename': filename,
|
||||||
|
'size': file_stats.st_size,
|
||||||
|
'created': datetime.fromtimestamp(file_stats.st_ctime).isoformat(),
|
||||||
|
'modified': datetime.fromtimestamp(file_stats.st_mtime).isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
# CSV specific analysis (only if pandas is available)
|
||||||
|
if filename.lower().endswith('.csv') and PANDAS_AVAILABLE:
|
||||||
|
try:
|
||||||
|
df = pd.read_csv(filepath)
|
||||||
|
analysis.update({
|
||||||
|
'rows': len(df),
|
||||||
|
'columns': len(df.columns),
|
||||||
|
'column_names': df.columns.tolist(),
|
||||||
|
'preview': df.head().to_dict('records')
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
analysis['csv_error'] = str(e)
|
||||||
|
elif filename.lower().endswith('.csv'):
|
||||||
|
# Basic CSV analysis without pandas
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r', encoding='utf-8') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
analysis.update({
|
||||||
|
'rows': len(lines) - 1, # Subtract header
|
||||||
|
'columns': len(lines[0].split(',')) if lines else 0,
|
||||||
|
'preview': lines[:6] if lines else []
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
analysis['csv_error'] = str(e)
|
||||||
|
|
||||||
|
return jsonify(analysis)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Analysis error: {e}")
|
||||||
|
return jsonify({'error': 'Analysis failed'}), 500
|
||||||
|
|
||||||
|
# Stats endpoint
|
||||||
|
@app.route('/api/stats')
|
||||||
|
def get_stats():
|
||||||
|
try:
|
||||||
|
upload_dir = app.config['UPLOAD_FOLDER']
|
||||||
|
files_count = len([f for f in os.listdir(upload_dir) if os.path.isfile(os.path.join(upload_dir, f))])
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'filesUploaded': files_count,
|
||||||
|
'analysesCompleted': files_count, # Simplified
|
||||||
|
'threatsDetected': 0 # Placeholder
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Stats error: {e}")
|
||||||
|
return jsonify({'error': 'Failed to get stats'}), 500
|
||||||
|
|
||||||
|
# Static file serving
|
||||||
|
@app.route("/assets/<path:path>")
|
||||||
|
def send_assets(path):
|
||||||
|
return send_from_directory(os.path.join(app.static_folder, "assets"), path)
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
return send_from_directory(app.static_folder, "index.html")
|
||||||
|
|
||||||
|
# Catch-all route for React Router
|
||||||
|
@app.route("/<path:path>")
|
||||||
|
def catch_all(path):
|
||||||
|
return send_from_directory(app.static_folder, "index.html")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(host="0.0.0.0", port=5000, debug=True)
|
||||||
12
frontend/index.html
Normal file
12
frontend/index.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Cyber Threat Hunter</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.jsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
34
frontend/package.json
Normal file
34
frontend/package.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "cyber-threat-hunter",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"react-router-dom": "^6.26.1",
|
||||||
|
"lucide-react": "^0.515.0",
|
||||||
|
"axios": "^1.7.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^18.3.3",
|
||||||
|
"@types/react-dom": "^18.3.0",
|
||||||
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
|
"eslint": "^8.57.0",
|
||||||
|
"eslint-plugin-react": "^7.34.3",
|
||||||
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.7",
|
||||||
|
"vite": "^5.3.4",
|
||||||
|
"tailwindcss": "^3.4.4",
|
||||||
|
"autoprefixer": "^10.4.19",
|
||||||
|
"postcss": "^8.4.39"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
frontend/src/App.jsx
Normal file
47
frontend/src/App.jsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||||
|
import { CssBaseline } from "@mui/material";
|
||||||
|
import { createTheme, ThemeProvider } from "@mui/material/styles";
|
||||||
|
|
||||||
|
import Sidebar from "./components/Sidebar";
|
||||||
|
import HomePage from "./pages/HomePage";
|
||||||
|
|
||||||
|
const theme = createTheme({
|
||||||
|
palette: {
|
||||||
|
mode: "dark",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<CssBaseline />
|
||||||
|
<Router>
|
||||||
|
<div className="flex h-screen bg-zinc-900 text-white">
|
||||||
|
<Sidebar />
|
||||||
|
<main className="flex-1 p-6 overflow-auto">
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={<HomePage />} />
|
||||||
|
</Routes>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</Router>
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
<Route path="/applications" element={<Applications />} />
|
||||||
|
<Route path="/csv-processing" element={<CSVProcessing />} />
|
||||||
|
<Route path="/settings" element={<SettingsConfig />} />
|
||||||
|
<Route path="/virus-total" element={<VirusTotal />} />
|
||||||
|
<Route path="/security-tools" element={<SecurityTools />} />
|
||||||
|
</Routes>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</Router>
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
76
frontend/src/components/Sidebar.jsx
Normal file
76
frontend/src/components/Sidebar.jsx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { ShieldCheck } from 'lucide-react';
|
||||||
|
|
||||||
|
const Sidebar = () => {
|
||||||
|
return (
|
||||||
|
<div className="w-56 h-full bg-zinc-950 p-4 flex flex-col space-y-2 rounded-r-xl shadow-md">
|
||||||
|
<Link to="/" className="flex items-center cursor-pointer px-4 py-2 rounded-xl hover:bg-zinc-800 transition-all">
|
||||||
|
<ShieldCheck className="w-5 h-5 mr-3 text-cyan-400" />
|
||||||
|
<span>Home</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Sidebar;
|
||||||
|
const location = useLocation();
|
||||||
|
const hasChildren = !!children;
|
||||||
|
const isActive = location.pathname === to;
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
if (hasChildren) {
|
||||||
|
setIsOpen(!isOpen);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemContent = (
|
||||||
|
<div
|
||||||
|
className={`sidebar-item ${isActive ? 'bg-zinc-800' : ''}`}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
<Icon className="sidebar-icon" />
|
||||||
|
<span className="flex-grow">{label}</span>
|
||||||
|
{hasChildren && (isOpen ? <ChevronDown className="w-4 h-4" /> : <ChevronRight className="w-4 h-4" />)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="text-sm">
|
||||||
|
{to && !hasChildren ? (
|
||||||
|
<Link to={to}>{itemContent}</Link>
|
||||||
|
) : (
|
||||||
|
itemContent
|
||||||
|
)}
|
||||||
|
{hasChildren && isOpen && (
|
||||||
|
<div className="ml-8 mt-1 space-y-1 text-zinc-400">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Sidebar = () => {
|
||||||
|
return (
|
||||||
|
<div className="w-56 h-full bg-zinc-950 p-4 flex flex-col space-y-2 rounded-r-xl shadow-md">
|
||||||
|
<SidebarItem icon={ShieldCheck} label="HomePage" to="/" />
|
||||||
|
<SidebarItem icon={Server} label="Baseline" to="/baseline" />
|
||||||
|
<SidebarItem icon={Bug} label="Networking" to="/networking" />
|
||||||
|
<SidebarItem icon={Folder} label="Applications" to="/applications" />
|
||||||
|
<SidebarItem icon={Globe} label="CSV Processing" to="/csv-processing" />
|
||||||
|
<SidebarItem
|
||||||
|
icon={Settings}
|
||||||
|
label="Tools / Configs"
|
||||||
|
children={
|
||||||
|
<>
|
||||||
|
<Link to="/security-tools" className="block hover:text-white">Security Tools</Link>
|
||||||
|
<Link to="/settings" className="block hover:text-white">Configuration</Link>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<SidebarItem icon={Globe} label="Virus Total" to="/virus-total" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Sidebar;
|
||||||
203
frontend/src/index.css
Normal file
203
frontend/src/index.css
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
||||||
|
background-color: #18181b;
|
||||||
|
color: white;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.sidebar-item {
|
||||||
|
@apply flex items-center cursor-pointer px-4 py-2 rounded-xl hover:bg-zinc-800 transition-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-icon {
|
||||||
|
@apply w-5 h-5 mr-3 text-cyan-400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
@apply bg-zinc-800 rounded-lg p-6 shadow-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
@apply bg-cyan-600 hover:bg-cyan-700 text-white px-4 py-2 rounded-lg transition-colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
@apply bg-zinc-700 hover:bg-zinc-600 text-white px-4 py-2 rounded-lg transition-colors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-screen {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-zinc-900 {
|
||||||
|
background-color: #18181b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-zinc-950 {
|
||||||
|
background-color: #09090b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-zinc-800 {
|
||||||
|
background-color: #27272a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-white {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-zinc-400 {
|
||||||
|
color: #a1a1aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-cyan-400 {
|
||||||
|
color: #22d3ee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-1 {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-6 {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-4 {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overflow-auto {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-56 {
|
||||||
|
width: 14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-y-6 > * + * {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-y-2 > * + * {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded-r-xl {
|
||||||
|
border-top-right-radius: 0.75rem;
|
||||||
|
border-bottom-right-radius: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shadow-md {
|
||||||
|
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-3xl {
|
||||||
|
font-size: 1.875rem;
|
||||||
|
line-height: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-bold {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-2 {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-lg {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-semibold {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-2xl {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-8 {
|
||||||
|
width: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-8 {
|
||||||
|
height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr-4 {
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded-lg {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.px-4 {
|
||||||
|
padding-left: 1rem;
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py-2 {
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded-xl {
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover\:bg-zinc-800:hover {
|
||||||
|
background-color: #27272a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition-all {
|
||||||
|
transition: all 0.15s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-5 {
|
||||||
|
width: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-5 {
|
||||||
|
height: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr-3 {
|
||||||
|
margin-right: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
105
frontend/src/pages/HomePage.jsx
Normal file
105
frontend/src/pages/HomePage.jsx
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Activity, Upload, FileText, Shield } from 'lucide-react';
|
||||||
|
|
||||||
|
const HomePage = () => {
|
||||||
|
const [stats, setStats] = useState({
|
||||||
|
filesUploaded: 0,
|
||||||
|
analysesCompleted: 0,
|
||||||
|
threatsDetected: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Fetch dashboard stats
|
||||||
|
fetch('/api/health')
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => console.log('Backend connected:', data))
|
||||||
|
.catch(err => console.error('Backend connection failed:', err));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-3xl font-bold mb-2">Cyber Threat Hunter</h1>
|
||||||
|
<p className="text-zinc-400">
|
||||||
|
Advanced threat hunting and security analysis platform
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
<div className="card">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Upload className="w-8 h-8 text-cyan-400 mr-4" />
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold">Files Uploaded</h3>
|
||||||
|
<p className="text-2xl font-bold text-cyan-400">{stats.filesUploaded}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="card">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Activity className="w-8 h-8 text-green-400 mr-4" />
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold">Analyses Completed</h3>
|
||||||
|
<p className="text-2xl font-bold text-green-400">{stats.analysesCompleted}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="card">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Shield className="w-8 h-8 text-red-400 mr-4" />
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold">Threats Detected</h3>
|
||||||
|
<p className="text-2xl font-bold text-red-400">{stats.threatsDetected}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="card">
|
||||||
|
<h2 className="text-xl font-bold mb-4">Quick Actions</h2>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<button className="btn-primary flex items-center justify-center">
|
||||||
|
<Upload className="w-5 h-5 mr-2" />
|
||||||
|
Upload File for Analysis
|
||||||
|
</button>
|
||||||
|
<button className="btn-secondary flex items-center justify-center">
|
||||||
|
<FileText className="w-5 h-5 mr-2" />
|
||||||
|
View Recent Reports
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="card">
|
||||||
|
<h2 className="text-xl font-bold mb-4">System Health</h2>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span>Backend Status</span>
|
||||||
|
<span className="text-green-400">✓ Healthy</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span>Database Connection</span>
|
||||||
|
<span className="text-green-400">✓ Connected</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span>Storage Available</span>
|
||||||
|
<span className="text-yellow-400">⚠ 75% Used</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-zinc-800 rounded-lg p-6 shadow-lg">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Shield className="w-8 h-8 text-cyan-400 mr-4" />
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold">System Status</h3>
|
||||||
|
<p className="text-2xl font-bold text-cyan-400">Ready</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HomePage;
|
||||||
20
frontend/vite.config.js
Normal file
20
frontend/vite.config.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
server: {
|
||||||
|
port: 3000,
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:5000',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: 'dist',
|
||||||
|
sourcemap: true
|
||||||
|
}
|
||||||
|
})
|
||||||
22
quick-start.bat
Normal file
22
quick-start.bat
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
@echo off
|
||||||
|
echo Quick Start - Velo Threat Hunter
|
||||||
|
|
||||||
|
cd backend
|
||||||
|
call venv\Scripts\activate
|
||||||
|
pip install flask flask-cors python-dotenv requests werkzeug
|
||||||
|
start "Backend" cmd /k "python app.py"
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
timeout /t 3 /nobreak >nul
|
||||||
|
|
||||||
|
cd frontend
|
||||||
|
if exist package.json (
|
||||||
|
start "Frontend" cmd /k "npm run dev"
|
||||||
|
) else (
|
||||||
|
echo Frontend not configured yet
|
||||||
|
)
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Servers starting...
|
||||||
|
pause
|
||||||
6
run-backend.bat
Normal file
6
run-backend.bat
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@echo off
|
||||||
|
title Cyber Threat Hunter - Backend
|
||||||
|
cd /d "%~dp0\backend"
|
||||||
|
call venv\Scripts\activate.bat
|
||||||
|
python app.py
|
||||||
|
pause
|
||||||
55
run-frontend.bat
Normal file
55
run-frontend.bat
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
@echo off
|
||||||
|
title Cyber Threat Hunter - Frontend
|
||||||
|
cd /d "%~dp0\frontend"
|
||||||
|
|
||||||
|
echo Checking Node.js installation...
|
||||||
|
node --version >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Error: Node.js not found
|
||||||
|
echo Please install Node.js from https://nodejs.org
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Installing dependencies...
|
||||||
|
npm install
|
||||||
|
|
||||||
|
echo Starting development server...
|
||||||
|
npm run dev
|
||||||
|
pause
|
||||||
|
echo "dependencies": {>> package.json
|
||||||
|
echo "react": "^18.3.1",>> package.json
|
||||||
|
echo "react-dom": "^18.3.1",>> package.json
|
||||||
|
echo "react-router-dom": "^6.26.1",>> package.json
|
||||||
|
echo "lucide-react": "^0.515.0">> package.json
|
||||||
|
echo },>> package.json
|
||||||
|
echo "devDependencies": {>> package.json
|
||||||
|
echo "@vitejs/plugin-react": "^4.3.1",>> package.json
|
||||||
|
echo "vite": "^5.3.4">> package.json
|
||||||
|
echo }>> package.json
|
||||||
|
echo }>> package.json
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Check if Node.js is available
|
||||||
|
node --version >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Error: Node.js not found
|
||||||
|
echo Please install Node.js from https://nodejs.org
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Install dependencies if node_modules doesn't exist
|
||||||
|
if not exist "node_modules" (
|
||||||
|
echo Installing npm dependencies...
|
||||||
|
npm install
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Error: Failed to install npm dependencies
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Starting Cyber Threat Hunter Frontend...
|
||||||
|
npm run dev
|
||||||
|
pause
|
||||||
30
setup-backend.bat
Normal file
30
setup-backend.bat
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
@echo off
|
||||||
|
title Setup Backend
|
||||||
|
echo Setting up Cyber Threat Hunter Backend...
|
||||||
|
|
||||||
|
cd backend
|
||||||
|
|
||||||
|
REM Create virtual environment if it doesn't exist
|
||||||
|
if not exist "venv" (
|
||||||
|
echo Creating virtual environment...
|
||||||
|
python -m venv venv
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Error: Failed to create virtual environment
|
||||||
|
echo Make sure Python is installed
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Activating virtual environment...
|
||||||
|
call venv\Scripts\activate.bat
|
||||||
|
|
||||||
|
echo Installing Flask and dependencies...
|
||||||
|
pip install flask==3.0.0
|
||||||
|
pip install flask-cors==4.0.0
|
||||||
|
pip install python-dotenv==1.0.0
|
||||||
|
pip install requests==2.31.0
|
||||||
|
pip install werkzeug==3.0.1
|
||||||
|
|
||||||
|
echo Backend setup complete!
|
||||||
|
pause
|
||||||
41
setup-frontend.bat
Normal file
41
setup-frontend.bat
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
@echo off
|
||||||
|
title Setup Frontend
|
||||||
|
echo Setting up Cyber Threat Hunter Frontend...
|
||||||
|
|
||||||
|
cd frontend
|
||||||
|
|
||||||
|
REM Clean up corrupted files
|
||||||
|
if exist "package-lock.json" del /f "package-lock.json"
|
||||||
|
if exist "node_modules" rmdir /s /q "node_modules" 2>nul
|
||||||
|
|
||||||
|
echo Creating clean package.json...
|
||||||
|
(
|
||||||
|
echo {
|
||||||
|
echo "name": "cyber-threat-hunter",
|
||||||
|
echo "private": true,
|
||||||
|
echo "version": "1.0.0",
|
||||||
|
echo "type": "module",
|
||||||
|
echo "scripts": {
|
||||||
|
echo "dev": "vite",
|
||||||
|
echo "build": "vite build",
|
||||||
|
echo "preview": "vite preview"
|
||||||
|
echo },
|
||||||
|
echo "dependencies": {
|
||||||
|
echo "react": "^18.3.1",
|
||||||
|
echo "react-dom": "^18.3.1",
|
||||||
|
echo "react-router-dom": "^6.26.1",
|
||||||
|
echo "lucide-react": "^0.515.0"
|
||||||
|
echo },
|
||||||
|
echo "devDependencies": {
|
||||||
|
echo "@vitejs/plugin-react": "^4.3.1",
|
||||||
|
echo "vite": "^5.3.4"
|
||||||
|
echo }
|
||||||
|
echo }
|
||||||
|
) > package.json
|
||||||
|
|
||||||
|
echo Installing npm dependencies...
|
||||||
|
npm cache clean --force
|
||||||
|
npm install
|
||||||
|
|
||||||
|
echo Frontend setup complete!
|
||||||
|
pause
|
||||||
8
start-backend.bat
Normal file
8
start-backend.bat
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
@echo off
|
||||||
|
title Cyber Threat Hunter - Backend
|
||||||
|
cd /d "%~dp0\backend"
|
||||||
|
|
||||||
|
echo Starting Backend Server...
|
||||||
|
call venv\Scripts\activate.bat
|
||||||
|
python app.py
|
||||||
|
pause
|
||||||
22
start-clean.bat
Normal file
22
start-clean.bat
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
@echo off
|
||||||
|
title Cyber Threat Hunter - Clean Start
|
||||||
|
echo ========================================
|
||||||
|
echo Cyber Threat Hunter - Clean Startup
|
||||||
|
echo ========================================
|
||||||
|
|
||||||
|
REM Clean backend
|
||||||
|
echo Cleaning backend...
|
||||||
|
cd backend
|
||||||
|
if exist "__pycache__" rmdir /s /q "__pycache__" 2>nul
|
||||||
|
if exist "*.pyc" del /f "*.pyc" 2>nul
|
||||||
|
|
||||||
|
REM Clean frontend
|
||||||
|
echo Cleaning frontend...
|
||||||
|
cd ..\frontend
|
||||||
|
if exist "node_modules" rmdir /s /q "node_modules" 2>nul
|
||||||
|
if exist "package-lock.json" del /f "package-lock.json" 2>nul
|
||||||
|
if exist "dist" rmdir /s /q "dist" 2>nul
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Clean complete. Run start.bat to restart.
|
||||||
|
pause
|
||||||
7
start-frontend.bat
Normal file
7
start-frontend.bat
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
@echo off
|
||||||
|
title Cyber Threat Hunter - Frontend
|
||||||
|
cd /d "%~dp0\frontend"
|
||||||
|
|
||||||
|
echo Starting Frontend Server...
|
||||||
|
npm run dev
|
||||||
|
pause
|
||||||
43
start.bat
Normal file
43
start.bat
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
@echo off
|
||||||
|
title Cyber Threat Hunter
|
||||||
|
echo ========================================
|
||||||
|
echo Cyber Threat Hunter
|
||||||
|
echo ========================================
|
||||||
|
|
||||||
|
REM Check if setup is needed
|
||||||
|
if not exist "backend\venv" (
|
||||||
|
echo Backend not set up. Running setup...
|
||||||
|
call setup-backend.bat
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist "frontend\node_modules" (
|
||||||
|
echo Frontend not set up. Running setup...
|
||||||
|
call setup-frontend.bat
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Starting servers...
|
||||||
|
|
||||||
|
REM Start Backend
|
||||||
|
start "Backend" cmd /k "start-backend.bat"
|
||||||
|
|
||||||
|
REM Wait a moment
|
||||||
|
timeout /t 3 /nobreak >nul
|
||||||
|
|
||||||
|
REM Start Frontend
|
||||||
|
start "Frontend" cmd /k "start-frontend.bat"
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ========================================
|
||||||
|
echo Servers are starting...
|
||||||
|
echo Backend: http://localhost:5000
|
||||||
|
echo Frontend: http://localhost:3000
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
echo Press any key to exit...
|
||||||
|
pause >nul
|
||||||
|
echo Backend: http://localhost:5000
|
||||||
|
echo Frontend: http://localhost:3000
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
echo Press any key to exit...
|
||||||
|
pause >nul
|
||||||
73
troubleshoot.md
Normal file
73
troubleshoot.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# Troubleshooting Guide
|
||||||
|
|
||||||
|
## Common Issues
|
||||||
|
|
||||||
|
### 1. Package.json Corruption
|
||||||
|
|
||||||
|
**Symptoms:** JSON parse errors, unexpected characters
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
del package.json
|
||||||
|
# Run run-frontend.bat to recreate
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Node Modules Issues
|
||||||
|
|
||||||
|
**Symptoms:** Module not found errors
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
rmdir /s /q node_modules
|
||||||
|
del package-lock.json
|
||||||
|
npm cache clean --force
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Backend Python Issues
|
||||||
|
|
||||||
|
**Symptoms:** Module import errors
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
pip install flask flask-cors python-dotenv requests werkzeug
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Port Conflicts
|
||||||
|
|
||||||
|
**Symptoms:** EADDRINUSE errors
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
- Frontend (3000): Vite will auto-select next port
|
||||||
|
- Backend (5000): Change port in app.py
|
||||||
|
|
||||||
|
### 5. CORS Issues
|
||||||
|
|
||||||
|
**Symptoms:** Cross-origin request blocked
|
||||||
|
**Solution:** Install flask-cors: `pip install flask-cors`
|
||||||
|
|
||||||
|
## Quick Fixes
|
||||||
|
|
||||||
|
1. **Complete Clean Start:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
start-clean.bat
|
||||||
|
start.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Backend Only:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Frontend Only:**
|
||||||
|
```bash
|
||||||
|
run-frontend.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure Check
|
||||||
Reference in New Issue
Block a user