# 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> |
<a href="https://www.tarikvardar.com.tr" style="color:#33b5e5; text-decoration:none;">🌐 Web Site</a> |
<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())