Web Site Pentester (Web Site Güvenlik Analiz Aracı) / SitePenTest/main.py
main.py 354 satır • 13.83 KB
# main.py - SitePenTest v1.0
import sys
import os
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QLineEdit, QPushButton, QProgressBar, QTextBrowser,
    QFrame, QMessageBox, QDialog
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal, QUrl
from PyQt6.QtGui import QFont, QIcon, QDesktopServices, QPixmap

from scanner import WebScanner


# PyInstaller ve Geliştirme ortamı için dosya yolu bulucu
def resource_path(relative_path):
    """ PyInstaller için mutlak yolu bulur """
    try:
        # PyInstaller geçici klasörü
        base_path = sys._MEIPASS
    except Exception:
        # Normal çalışma yolu
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)


class AboutDialog(QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Hakkında")
        self.setFixedSize(480, 580)  # Uyarı metni uzadığı için boyutu biraz artırdık

        # Pencere İkonunu Ekle (YENİ)
        icon_path = resource_path("assets/logo.png")
        if os.path.exists(icon_path):
            self.setWindowIcon(QIcon(icon_path))

        # Koyu Tema (Dark Mode)
        self.setStyleSheet("""
            QDialog { background-color: #1e1e1e; }
            QLabel { color: #e0e0e0; font-family: 'Segoe UI'; }
        """)

        layout = QVBoxLayout(self)
        layout.setSpacing(10)
        layout.setContentsMargins(20, 30, 20, 20)

        # --- 1. Logo ---
        logo_label = QLabel()
        pixmap = QPixmap(resource_path("assets/logo.png"))
        if not pixmap.isNull():
            # Logoyu ortala ve boyutlandır
            scaled = pixmap.scaled(100, 100, Qt.AspectRatioMode.KeepAspectRatio,
                                   Qt.TransformationMode.SmoothTransformation)
            logo_label.setPixmap(scaled)
        logo_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(logo_label)

        # --- 2. Başlık ve Versiyon ---
        title_label = QLabel("SitePenTest")
        title_label.setFont(QFont("Segoe UI", 24, QFont.Weight.Bold))
        title_label.setStyleSheet("color: #33b5e5; margin-top: 10px;")  # Mavi başlık
        title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(title_label)

        version_label = QLabel("Sürüm v1.0 (Stable)")
        version_label.setFont(QFont("Segoe UI", 10, QFont.Weight.Bold))
        version_label.setStyleSheet("color: #ffffff;")
        version_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(version_label)

        # --- 3. Açıklama ---
        desc_label = QLabel(
            "Linux (Pardus/Debian) sistemler için geliştirilmiş;\n"
            "WAF bypass özellikli web güvenlik tarama aracı."
        )
        desc_label.setWordWrap(True)
        desc_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        desc_label.setStyleSheet("color: #bbbbbb; font-size: 13px; margin: 10px 0;")
        layout.addWidget(desc_label)

        # --- 4. Yasal Uyarı (GÜNCELLENDİ) ---
        warning_text = (
            "<b>⚠️ YASAL UYARI:</b> Kendinize ait olmayan ya da yazılı izin almadığınız "
            "web site ve sistemleri taramak kanunen suçtur.<br><br>"
            "Tüm sorumluluk kullanana aittir."
        )
        warning_label = QLabel(warning_text)
        warning_label.setWordWrap(True)
        warning_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        warning_label.setStyleSheet("color: #ff4444; font-size: 12px; font-weight: bold;")  # Kırmızı ve kalın
        layout.addWidget(warning_label)

        # --- 5. Geliştirici Bilgileri ---
        dev_label = QLabel("Geliştirici: <b>Tarık Vardar</b>")
        dev_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        dev_label.setStyleSheet("color: #ffffff; font-size: 13px; margin-top: 15px;")
        layout.addWidget(dev_label)

        # Linkler
        links_browser = QTextBrowser()
        links_browser.setOpenExternalLinks(True)
        links_browser.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        links_browser.setStyleSheet("border: none; background: transparent;")
        links_browser.setFixedHeight(40)

        links_html = """
        <div style="text-align:center; font-family: 'Segoe UI'; font-size: 13px;">
            <a href="mailto:info@tarikvardar.com.tr" style="color:#33b5e5; text-decoration:none;">📧 İletişim</a> &nbsp;|&nbsp; 
            <a href="https://www.tarikvardar.com.tr" style="color:#33b5e5; text-decoration:none;">🌐 Web Site</a> &nbsp;|&nbsp; 
            <a href="https://github.com/tvardar" style="color:#33b5e5; text-decoration:none;">💻 GitHub</a>
        </div>
        """
        links_browser.setHtml(links_html)
        layout.addWidget(links_browser)

        layout.addStretch()

        # --- 6. Lisans Kutusu ---
        license_frame = QFrame()
        license_frame.setStyleSheet("background-color: #2d2d2d; border-radius: 6px;")
        lic_layout = QVBoxLayout(license_frame)
        lic_layout.setContentsMargins(10, 10, 10, 10)

        lic_title = QLabel("MIT License")
        lic_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
        lic_title.setFont(QFont("Segoe UI", 9, QFont.Weight.Bold))
        lic_title.setStyleSheet("color: #e0e0e0;")
        lic_layout.addWidget(lic_title)

        lic_text = QLabel(
            "Bu yazılım özgürdür; MIT Lisansı koşulları altında\n"
            "değiştirebilir ve/veya dağıtabilirsiniz."
        )
        lic_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
        lic_text.setStyleSheet("color: #aaaaaa; font-size: 10px;")
        lic_layout.addWidget(lic_text)

        layout.addWidget(license_frame)

        # Copyright
        copy_label = QLabel("© 2025 - Tüm Hakları Saklıdır")
        copy_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        copy_label.setStyleSheet("color: #666666; font-size: 10px; margin-top: 5px;")
        layout.addWidget(copy_label)


class ScanThread(QThread):
    progress = pyqtSignal(int, str)
    finished = pyqtSignal(str, int, int, int)

    def __init__(self, url):
        super().__init__()
        self.url = url

    def run(self):
        scanner = WebScanner(self.url)
        scanner.scan(lambda p, msg: self.progress.emit(int(p), msg))
        report_path = scanner.generate_report()

        kritik = len([f for f in scanner.findings if f["risk"] in ["KRİTİK", "YÜKSEK"]])
        self.finished.emit(os.path.abspath(report_path), len(scanner.findings), kritik, len(scanner.goods))


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("SitePenTest v1.0 - Security Scanner")
        self.resize(750, 580)
        self.center_window()

        # Uygulama İkonu (Sol Üst)
        icon_path = resource_path("assets/logo.png")
        if os.path.exists(icon_path):
            self.setWindowIcon(QIcon(icon_path))

        central = QWidget()
        self.setCentralWidget(central)
        layout = QVBoxLayout(central)
        layout.setContentsMargins(30, 30, 30, 30)
        layout.setSpacing(15)

        # --- Header (Logo ve Başlık) ---
        header_layout = QHBoxLayout()

        # Header Logosu
        logo_label = QLabel()
        pixmap = QPixmap(icon_path)
        if not pixmap.isNull():
            # Logo büyütüldü (100x100)
            scaled = pixmap.scaled(100, 100, Qt.AspectRatioMode.KeepAspectRatio,
                                   Qt.TransformationMode.SmoothTransformation)
            logo_label.setPixmap(scaled)
        header_layout.addWidget(logo_label)

        # Başlık Yazısı
        title_box = QVBoxLayout()
        title_box.setSpacing(0)
        title_box.setAlignment(Qt.AlignmentFlag.AlignVCenter)  # Dikey ortalama

        title_text = QLabel("SitePenTest")
        title_text.setFont(QFont("Segoe UI", 32, QFont.Weight.Bold))  # Font biraz daha büyütüldü
        title_text.setStyleSheet("color: #0f172a;")
        title_box.addWidget(title_text)

        # Alt başlık kaldırıldı

        header_layout.addLayout(title_box)
        header_layout.addStretch()

        # Hakkında Butonu
        about_btn = QPushButton("Hakkında")
        about_btn.setCursor(Qt.CursorShape.PointingHandCursor)
        about_btn.setStyleSheet("""
            QPushButton { background: #f1f5f9; color: #334155; border: 1px solid #e2e8f0; border-radius: 6px; padding: 6px 15px; font-weight: 600; font-size: 12px;}
            QPushButton:hover { background: #e2e8f0; color: #0f172a; }
        """)
        about_btn.clicked.connect(self.show_about)
        header_layout.addWidget(about_btn)
        layout.addLayout(header_layout)

        # --- URL Input Alanı ---
        input_frame = QFrame()
        input_frame.setStyleSheet("background: #f8fafc; border-radius: 12px; border: 1px solid #e2e8f0;")
        input_layout = QHBoxLayout(input_frame)
        input_layout.setContentsMargins(8, 8, 8, 8)

        self.url_input = QLineEdit()
        self.url_input.setPlaceholderText("https://ornek-site.com")
        self.url_input.setFont(QFont("Consolas", 12))
        self.url_input.setStyleSheet("border: none; background: transparent; color: #334155;")
        input_layout.addWidget(self.url_input)

        self.scan_btn = QPushButton(" Analizi Başlat ")
        self.scan_btn.setFont(QFont("Segoe UI", 11, QFont.Weight.Bold))
        self.scan_btn.setCursor(Qt.CursorShape.PointingHandCursor)
        self.scan_btn.setStyleSheet("""
            QPushButton { background: #4f46e5; color: white; padding: 10px 20px; border-radius: 8px; }
            QPushButton:hover { background: #4338ca; }
            QPushButton:disabled { background: #94a3b8; }
        """)
        self.scan_btn.clicked.connect(self.start_scan)
        input_layout.addWidget(self.scan_btn)
        layout.addWidget(input_frame)

        # --- Progress Bar ---
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setFixedHeight(6)
        self.progress_bar.setStyleSheet("""
            QProgressBar { border-radius: 3px; background: #e2e8f0; border: none; }
            QProgressBar::chunk { background: #22c55e; border-radius: 3px; }
        """)
        layout.addWidget(self.progress_bar)

        self.status_label = QLabel("Taramaya hazır")
        self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.status_label.setStyleSheet("color: #64748b; font-size: 11px;")
        layout.addWidget(self.status_label)

        # --- Sonuç Ekranı ---
        self.result_text = QTextBrowser()
        self.result_text.setOpenExternalLinks(False)
        self.result_text.anchorClicked.connect(self.open_link)
        self.result_text.setStyleSheet("""
            QTextBrowser { 
                border: 1px solid #e2e8f0; 
                border-radius: 12px; 
                padding: 15px; 
                background: #ffffff; 
                color: #334155;
                font-family: 'Segoe UI';
                font-size: 13px;
            }
        """)
        layout.addWidget(self.result_text)

    def center_window(self):
        screen = QApplication.primaryScreen().geometry()
        window = self.frameGeometry()
        window.moveCenter(screen.center())
        self.move(window.topLeft())

    def show_about(self):
        dialog = AboutDialog()
        dialog.exec()

    def start_scan(self):
        url = self.url_input.text().strip()
        if not url:
            QMessageBox.warning(self, "Uyarı", "Lütfen geçerli bir URL giriniz.")
            return

        self.scan_btn.setEnabled(False)
        self.url_input.setEnabled(False)
        self.progress_bar.setValue(0)
        self.result_text.clear()
        self.status_label.setText("Bağlantı kuruluyor...")
        self.result_text.setHtml(
            "<h3 style='color:#64748b; text-align:center; margin-top:40px;'>Analiz Başlatılıyor...</h3>")

        self.thread = ScanThread(url)
        self.thread.progress.connect(self.update_progress)
        self.thread.finished.connect(self.scan_finished)
        self.thread.start()

    def update_progress(self, value: int, message: str):
        self.progress_bar.setValue(value)
        self.status_label.setText(message)

    def scan_finished(self, report_path: str, total: int, critical: int, good: int):
        self.scan_btn.setEnabled(True)
        self.url_input.setEnabled(True)
        self.progress_bar.setValue(100)
        self.status_label.setText("Tamamlandı.")

        report_url = QUrl.fromLocalFile(report_path).toString()

        color = "#ef4444" if critical > 0 else "#22c55e"
        title_text = "Riskler Tespit Edildi" if critical > 0 else "Sistem Güvenli"

        html = f"""
        <div style="text-align:center; font-family: 'Segoe UI';">
            <h2 style="color:{color}; margin: 0;">{title_text}</h2>
            <p style="color: #64748b; margin-top:5px;">Toplam <b>{total}</b> bulgu</p>

            <div style="background:#f8fafc; border:1px dashed #cbd5e1; padding:20px; border-radius:10px; margin: 20px 0;">
                <b style="color:#0f172a; font-size:14px;">📄 Rapor Oluşturuldu</b><br><br>
                <a href="{report_url}" style="background-color:{color}; color:white; text-decoration:none; padding:10px 20px; border-radius:6px; font-weight:bold;">
                   Raporu Görüntüle / Aç
                </a>
                <br><br>
                <span style="font-size:11px; color:#94a3b8;">Dosya Yolu: {report_path}</span>
            </div>

            <p style="color:#94a3b8; font-size:11px;">
                PDF kaydetmek için açılan raporda "PDF Olarak Kaydet" butonunu kullanın.
            </p>
        </div>
        """
        self.result_text.setHtml(html)

    def open_link(self, url):
        QDesktopServices.openUrl(url)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setStyle("Fusion")
    window = MainWindow()
    window.show()
    sys.exit(app.exec())