from flask import Flask, render_template, request, jsonify from flask_sqlalchemy import SQLAlchemy from datetime import datetime from utils import predict_url import re app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///scans.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) # ── Database Model ───────────────────────────────────────────── class ScanHistory(db.Model): id = db.Column(db.Integer, primary_key=True) url = db.Column(db.String(2000), nullable=False) verdict = db.Column(db.String(20), nullable=False) label = db.Column(db.String(20), nullable=False) confidence = db.Column(db.Float, nullable=False) scanned_at = db.Column(db.DateTime, default=datetime.utcnow) with app.app_context(): db.create_all() # ── Routes ───────────────────────────────────────────────────── @app.route('/') def index(): stats = { 'total': ScanHistory.query.count(), 'safe': ScanHistory.query.filter_by(verdict='SAFE').count(), 'phishing': ScanHistory.query.filter_by(label='phishing').count(), 'malware': ScanHistory.query.filter_by(label='malware').count(), } return render_template('index.html', stats=stats) @app.route('/history') def history(): scans = ScanHistory.query.order_by(ScanHistory.scanned_at.desc()).limit(100).all() return render_template('history.html', scans=scans) @app.route('/api/predict', methods=['POST']) def predict(): data = request.get_json() url = (data.get('url') or '').strip() if not url: return jsonify({'error': 'Please enter a URL'}) if not re.match(r'https?://', url): url = 'https://' + url try: result = predict_url(url) scan = ScanHistory( url = url, verdict = result['verdict'], label = result['ensemble']['label'], confidence = result['ensemble']['confidence'], ) db.session.add(scan) db.session.commit() return jsonify({'url': url, **result}) except Exception as e: return jsonify({'error': f'Prediction failed: {str(e)}'}) @app.route('/api/predict/bulk', methods=['POST']) def predict_bulk(): data = request.get_json() urls = (data.get('urls') or '').strip().split('\n') urls = [u.strip() for u in urls if u.strip()][:20] if not urls: return jsonify({'error': 'No URLs provided'}) results = [] for url in urls: if not re.match(r'https?://', url): url = 'https://' + url try: result = predict_url(url) scan = ScanHistory( url = url, verdict = result['verdict'], label = result['ensemble']['label'], confidence = result['ensemble']['confidence'], ) db.session.add(scan) results.append({'url': url, **result}) except Exception as e: results.append({'url': url, 'error': str(e)}) db.session.commit() return jsonify({'results': results}) @app.route('/api/history/clear', methods=['POST']) def clear_history(): ScanHistory.query.delete() db.session.commit() return jsonify({'status': 'cleared'}) if __name__ == "__main__": app.run(host="0.0.0.0", port=7860, debug=False)