From f86cda297839387a3465231991d8b5618f7bc88c Mon Sep 17 00:00:00 2001 From: salvacybersec Date: Mon, 10 Nov 2025 20:01:41 +0300 Subject: [PATCH] Domain support --- .env.example | 25 + .gitattributes | 19 + .gitignore | 77 +- DEPLOYMENT.md | 968 ++++++++++++++++++ README.md | 65 +- SECURITY.md | 454 ++++++++ backend/src/app.js | 37 +- .../src/controllers/settings.controller.js | 83 ++ backend/src/models/TrackingToken.js | 5 + backend/src/routes/settings.routes.js | 1 + backend/src/services/mail.service.js | 9 +- backend/src/services/token.service.js | 14 +- backend/src/validators/token.validator.js | 7 + deploy.sh | 562 ++++++++++ docs/DOMAIN_SETUP.md | 396 +++++++ docs/NGINX_PROXY_MANAGER.md | 438 ++++++++ frontend/src/pages/Settings.jsx | 110 +- frontend/src/pages/TokenDetail.jsx | 8 + frontend/src/pages/Tokens.jsx | 12 +- nginx/oltalama.conf | 132 +++ scripts/change-password.js | 117 +++ scripts/create-admin.js | 142 +++ systemd/oltalama-backend.service | 29 + systemd/oltalama-frontend.service | 27 + 24 files changed, 3703 insertions(+), 34 deletions(-) create mode 100644 .env.example create mode 100644 .gitattributes create mode 100644 DEPLOYMENT.md create mode 100644 SECURITY.md create mode 100755 deploy.sh create mode 100644 docs/DOMAIN_SETUP.md create mode 100644 docs/NGINX_PROXY_MANAGER.md create mode 100644 nginx/oltalama.conf create mode 100755 scripts/change-password.js create mode 100755 scripts/create-admin.js create mode 100644 systemd/oltalama-backend.service create mode 100644 systemd/oltalama-frontend.service diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..71902bb --- /dev/null +++ b/.env.example @@ -0,0 +1,25 @@ +# Backend .env örneği +# Bu dosyayı kopyalayın ve .env olarak kaydedin + +# Sunucu Ayarları +NODE_ENV=production +PORT=3000 +BASE_URL=https://yourdomain.com + +# Session Secret (güçlü bir rastgele değer kullanın) +# Oluşturmak için: node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" +SESSION_SECRET=change-this-to-a-strong-random-secret-key + +# Gmail Ayarları (panelden de girebilirsiniz) +GMAIL_USER= +GMAIL_APP_PASSWORD= + +# Telegram Bot (panelden de girebilirsiniz) +TELEGRAM_BOT_TOKEN= +TELEGRAM_CHAT_ID= + +# Database +DB_PATH=./database/oltalama.db + +# Log Seviyesi +LOG_LEVEL=info diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1fa9e36 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,19 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Shell scripts should use LF +*.sh text eol=lf + +# Windows batch files should use CRLF +*.bat text eol=crlf +*.cmd text eol=crlf + +# Binary files +*.db binary +*.sqlite binary +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.pdf binary diff --git a/.gitignore b/.gitignore index 58c51c3..a8348c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1,82 @@ # Dependencies node_modules/ package-lock.json -yarn.lock -# Environment +# Environment variables .env .env.local +.env.production +.env.*.local -# Build -dist/ -build/ +# Database +*.db +*.db-* +*.sqlite +*.sqlite3 +database/*.db +backend/database/*.db # Logs logs/ *.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* -# Database (regenerate with migrations) -*.db -*.db-journal -*.db-shm -*.db-wal +# Diagnostic reports +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json -# OS -.DS_Store -Thumbs.db +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Build directories +dist/ +build/ +.cache/ +.parcel-cache/ +frontend/dist/ +frontend/build/ + +# Coverage directory +coverage/ +*.lcov +.nyc_output # IDE .vscode/ .idea/ *.swp *.swo +*.swn +*~ +.DS_Store -# Temp -temp/ -tmp/ +# PM2 +.pm2/ +ecosystem.config.js +# Backups +backups/ +*.backup +*.bak + +# Test +.test/ +test-results/ + +# Misc +.tmp/ +.temp/ +*.tmp +*.temp +.sessions/ +sessions.db + +# OS +Thumbs.db +.DS_Store diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..56c50b7 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,968 @@ +# 🚀 Oltalama Panel - Sunucu Kurulum Dokümanı + +Bu doküman, Oltalama Test Yönetim Paneli'nin production sunucusuna kurulumu için hazırlanmıştır. + +## 📋 Gereksinimler + +### Sistem Gereksinimleri +- **İşletim Sistemi**: Ubuntu 20.04+ / Debian 11+ / CentOS 8+ (önerilen: Ubuntu 22.04 LTS) +- **RAM**: Minimum 1GB, Önerilen 2GB+ +- **Disk**: Minimum 5GB boş alan +- **CPU**: 1 core minimum, 2+ core önerilen + +### Yazılım Gereksinimleri +- Node.js 18.x veya üzeri +- npm 9.x veya üzeri +- Git +- PM2 (process manager) veya systemd +- SQLite3 + +### Opsiyonel +- Nginx Proxy Manager (reverse proxy için önerilir) +- Certbot/Let's Encrypt (SSL için) +- fail2ban (güvenlik için) + +## 🎯 Hızlı Kurulum (Otomatik) + +### 1. Kurulum Scriptini İndir ve Çalıştır + +```bash +# Projeyi klonla +git clone /opt/oltalama +cd /opt/oltalama + +# Kurulum scriptini çalıştırılabilir yap +chmod +x deploy.sh + +# Kurulumu başlat (interaktif mod) +sudo ./deploy.sh +``` + +Script otomatik olarak şunları yapacak: +- ✅ Node.js kurulumu +- ✅ Dependencies kurulumu +- ✅ Database migration ve seed +- ✅ PM2 ile process management kurulumu +- ✅ Auto-restart ve startup konfigürasyonu +- ✅ Frontend build +- ✅ Güvenlik ayarları + +## 🛠️ Yardımcı Scriptler + +Kurulum sonrası kullanabileceğiniz yardımcı scriptler: + +### Admin Kullanıcısı Oluşturma + +```bash +cd /opt/oltalama +node scripts/create-admin.js +``` + +Bu script: +- ✅ Yeni admin kullanıcısı oluşturur +- ✅ Kullanıcı adı benzersizliği kontrol eder +- ✅ Şifre güvenlik validasyonu yapar +- ✅ Şifreyi güvenli bir şekilde hash'ler + +### Şifre Değiştirme + +```bash +cd /opt/oltalama +node scripts/change-password.js +``` + +Bu script: +- ✅ Mevcut admin kullanıcısının şifresini değiştirir +- ✅ Şifre güvenlik validasyonu yapar +- ✅ Yeni şifreyi güvenli bir şekilde hash'ler + +**Şifre Gereksinimleri:** +- En az 8 karakter +- En az 1 harf (a-z, A-Z) +- En az 1 rakam (0-9) +- Önerilen: Özel karakterler (!@#$%^&*) + +## 🔧 Manuel Kurulum + +### 1. Sistem Güncellemesi + +```bash +sudo apt update && sudo apt upgrade -y +``` + +### 2. Node.js Kurulumu + +```bash +# Node.js 20.x kurulumu (önerilen) +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt-get install -y nodejs + +# Versiyonu kontrol et +node --version # v20.x.x olmalı +npm --version # 10.x.x olmalı +``` + +### 3. Proje Kurulumu + +```bash +# Proje dizinini oluştur +sudo mkdir -p /opt/oltalama +sudo chown -R $USER:$USER /opt/oltalama + +# Projeyi klonla +cd /opt/oltalama +git clone . + +# Backend dependencies +cd /opt/oltalama/backend +npm install --production + +# Frontend dependencies ve build +cd /opt/oltalama/frontend +npm install +npm run build +``` + +### 4. Çevre Değişkenlerini Ayarla + +#### Backend .env + +```bash +cd /opt/oltalama/backend +cp .env.example .env +nano .env +``` + +**Önemli ayarlar:** + +```env +# Sunucu Ayarları +NODE_ENV=production +PORT=3000 +BASE_URL=https://yourdomain.com + +# Session Secret (güçlü bir değer oluştur) +SESSION_SECRET=uzun-rastgele-gizli-anahtar-buraya-gelecek + +# Gmail Ayarları (panelden de girebilirsiniz) +GMAIL_USER=your-email@gmail.com +GMAIL_APP_PASSWORD=your-app-password + +# Telegram Bot (panelden de girebilirsiniz) +TELEGRAM_BOT_TOKEN=your-bot-token +TELEGRAM_CHAT_ID=your-chat-id + +# Database +DB_PATH=/opt/oltalama/backend/database/oltalama.db + +# Log Seviyesi +LOG_LEVEL=info +``` + +**Session Secret oluşturma:** +```bash +node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" +``` + +#### Frontend .env + +```bash +cd /opt/oltalama/frontend +cp .env.example .env +nano .env +``` + +```env +# Backend API URL (Nginx Proxy Manager ile yönlendirme yapacaksanız domain) +VITE_API_BASE_URL=https://yourdomain.com + +# Veya lokal test için +# VITE_API_BASE_URL=http://localhost:3000 +``` + +### 5. Database Kurulumu + +```bash +cd /opt/oltalama/backend + +# Migrations çalıştır +node migrations/run-migrations.js + +# Admin kullanıcısı oluştur +node -e " +const bcrypt = require('bcrypt'); +const readline = require('readline'); +const { sequelize } = require('./src/config/database'); +const AdminUser = require('./src/models/AdminUser'); + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); + +(async () => { + await sequelize.authenticate(); + + rl.question('Admin kullanıcı adı: ', async (username) => { + rl.question('Admin şifresi: ', async (password) => { + const hashedPassword = await bcrypt.hash(password, 10); + await AdminUser.create({ + username, + password_hash: hashedPassword, + email: null, + full_name: 'Administrator' + }); + console.log('Admin kullanıcısı oluşturuldu!'); + rl.close(); + process.exit(0); + }); + }); +})(); +" +``` + +**Admin Kullanıcısı:** +- Kurulum sırasında oluşturulacak +- Kullanıcı adı ve şifre: İnteraktif olarak sizden istenecek +- Şifre gereksinimleri: + - En az 8 karakter + - En az 1 harf ve 1 rakam içermeli + - Güçlü şifre kullanmanız önerilir + +### 6. PM2 ile Process Management + +#### PM2 Kurulumu + +```bash +sudo npm install -g pm2 +``` + +#### PM2 Konfigürasyonu + +`/opt/oltalama/ecosystem.config.js` dosyası: + +```javascript +module.exports = { + apps: [ + { + name: 'oltalama-backend', + cwd: '/opt/oltalama/backend', + script: 'src/app.js', + instances: 1, + exec_mode: 'cluster', + watch: false, + max_memory_restart: '500M', + env: { + NODE_ENV: 'production', + PORT: 3000, + }, + error_file: '/var/log/oltalama/backend-error.log', + out_file: '/var/log/oltalama/backend-out.log', + log_date_format: 'YYYY-MM-DD HH:mm:ss Z', + }, + { + name: 'oltalama-frontend', + cwd: '/opt/oltalama/frontend', + script: 'npm', + args: 'run preview', + instances: 1, + exec_mode: 'fork', + watch: false, + max_memory_restart: '300M', + env: { + NODE_ENV: 'production', + PORT: 4173, + }, + error_file: '/var/log/oltalama/frontend-error.log', + out_file: '/var/log/oltalama/frontend-out.log', + log_date_format: 'YYYY-MM-DD HH:mm:ss Z', + }, + ], +}; +``` + +#### PM2 Başlatma + +```bash +# Log dizini oluştur +sudo mkdir -p /var/log/oltalama +sudo chown -R $USER:$USER /var/log/oltalama + +# Frontend build (eğer henüz build etmediyseniz) +cd /opt/oltalama/frontend +npm run build + +# PM2 ile uygulamayı başlat +cd /opt/oltalama +pm2 start ecosystem.config.js + +# Durumu kontrol et +pm2 status + +# Logları izle +pm2 logs + +# Startup script oluştur (sunucu yeniden başladığında otomatik başlasın) +pm2 startup +# Komutu çıktıdaki komutu çalıştırın + +# Mevcut durumu kaydet +pm2 save +``` + +#### PM2 Komutları + +```bash +pm2 status # Durum kontrolü +pm2 logs # Tüm loglar +pm2 logs oltalama-backend # Backend logları +pm2 logs oltalama-frontend # Frontend logları +pm2 restart all # Tümünü yeniden başlat +pm2 restart oltalama-backend # Backend'i yeniden başlat +pm2 stop all # Tümünü durdur +pm2 delete all # Tümünü sil +``` + +### 7. Systemd Service Alternatifi (PM2 yerine) + +PM2 yerine systemd kullanmak isterseniz: + +#### Backend Service + +`/etc/systemd/system/oltalama-backend.service`: + +```ini +[Unit] +Description=Oltalama Backend Service +After=network.target + +[Service] +Type=simple +User=www-data +WorkingDirectory=/opt/oltalama/backend +Environment=NODE_ENV=production +ExecStart=/usr/bin/node /opt/oltalama/backend/src/app.js +Restart=always +RestartSec=10 +StandardOutput=append:/var/log/oltalama/backend.log +StandardError=append:/var/log/oltalama/backend-error.log + +[Install] +WantedBy=multi-user.target +``` + +#### Frontend Service + +`/etc/systemd/system/oltalama-frontend.service`: + +```ini +[Unit] +Description=Oltalama Frontend Service +After=network.target + +[Service] +Type=simple +User=www-data +WorkingDirectory=/opt/oltalama/frontend +Environment=NODE_ENV=production +ExecStart=/usr/bin/npm run preview +Restart=always +RestartSec=10 +StandardOutput=append:/var/log/oltalama/frontend.log +StandardError=append:/var/log/oltalama/frontend-error.log + +[Install] +WantedBy=multi-user.target +``` + +#### Servisleri Başlat + +```bash +# Servisleri yükle +sudo systemctl daemon-reload + +# Servisleri başlat +sudo systemctl start oltalama-backend +sudo systemctl start oltalama-frontend + +# Başlangıçta otomatik başlasın +sudo systemctl enable oltalama-backend +sudo systemctl enable oltalama-frontend + +# Durumu kontrol et +sudo systemctl status oltalama-backend +sudo systemctl status oltalama-frontend +``` + +## 🌐 Nginx Proxy Manager Kurulumu + +### Portlar + +- **Backend**: `http://localhost:3000` +- **Frontend**: `http://localhost:4173` + +### Nginx Proxy Manager Ayarları + +1. **Nginx Proxy Manager'a giriş yapın** +2. **Proxy Hosts** → **Add Proxy Host** + +#### Frontend Proxy Host + +``` +Domain Names: yourdomain.com +Scheme: http +Forward Hostname/IP: localhost +Forward Port: 4173 +Cache Assets: ✓ +Block Common Exploits: ✓ +Websockets Support: ✓ + +SSL: +- Force SSL: ✓ +- HTTP/2 Support: ✓ +- HSTS Enabled: ✓ +``` + +#### Backend API Proxy (Eğer ayrı subdomain kullanacaksanız) + +``` +Domain Names: api.yourdomain.com +Scheme: http +Forward Hostname/IP: localhost +Forward Port: 3000 +Block Common Exploits: ✓ +Websockets Support: ✓ + +SSL: +- Force SSL: ✓ +- HTTP/2 Support: ✓ +- HSTS Enabled: ✓ +``` + +**Custom Nginx Configuration (Advanced sekmesi):** + +```nginx +location /api { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; +} +``` + +## 🔒 Güvenlik Önerileri + +### 1. Firewall Ayarları + +```bash +# UFW kurulumu ve ayarları +sudo apt install ufw + +# SSH izin ver (bağlantınızı koparmayın!) +sudo ufw allow 22/tcp + +# Backend ve Frontend portları (sadece localhost'tan erişilebilir olmalı) +# Nginx Proxy Manager kullanıyorsanız bu portları kapatın +sudo ufw deny 3000/tcp +sudo ufw deny 4173/tcp + +# HTTP/HTTPS (Nginx Proxy Manager için) +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# Firewall'ı aktifleştir +sudo ufw enable +``` + +### 2. Admin Şifresini Değiştir (Gerekirse) + +Şifrenizi değiştirmek isterseniz: + +```bash +# Backend dizinine git +cd /opt/oltalama/backend + +# Yeni şifre oluşturma scripti +node -e " +const bcrypt = require('bcrypt'); +const readline = require('readline'); +const { sequelize } = require('./src/config/database'); +const { AdminUser } = require('./src/models'); + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); + +(async () => { + await sequelize.authenticate(); + + rl.question('Admin kullanıcı adı: ', async (username) => { + rl.question('Yeni şifre: ', async (password) => { + const hashedPassword = await bcrypt.hash(password, 10); + await AdminUser.update( + { password_hash: hashedPassword }, + { where: { username } } + ); + console.log('Şifre değiştirildi!'); + rl.close(); + process.exit(0); + }); + }); +})(); +" +``` + +### 3. Dosya İzinleri + +```bash +# Proje dizini izinleri +sudo chown -R www-data:www-data /opt/oltalama +sudo chmod -R 755 /opt/oltalama + +# .env dosyalarını koru +sudo chmod 600 /opt/oltalama/backend/.env +sudo chmod 600 /opt/oltalama/frontend/.env + +# Database izinleri +sudo chmod 600 /opt/oltalama/backend/database/oltalama.db +``` + +### 4. Fail2Ban Kurulumu (Opsiyonel) + +```bash +sudo apt install fail2ban + +# /etc/fail2ban/jail.local +sudo nano /etc/fail2ban/jail.local +``` + +```ini +[DEFAULT] +bantime = 3600 +findtime = 600 +maxretry = 5 + +[sshd] +enabled = true +``` + +```bash +sudo systemctl restart fail2ban +``` + +### 5. Düzenli Güncellemeler + +```bash +# Sistem güncellemeleri +sudo apt update && sudo apt upgrade -y + +# Node paketleri +cd /opt/oltalama/backend && npm update +cd /opt/oltalama/frontend && npm update + +# PM2 güncelleme +pm2 update +``` + +## 💾 Yedekleme + +### 1. Database Yedekleme + +```bash +# Manuel yedekleme +cp /opt/oltalama/backend/database/oltalama.db \ + /opt/oltalama/backups/oltalama-$(date +%Y%m%d-%H%M%S).db +``` + +### 2. Otomatik Yedekleme Script + +`/opt/oltalama/backup.sh`: + +```bash +#!/bin/bash + +BACKUP_DIR="/opt/oltalama/backups" +DB_PATH="/opt/oltalama/backend/database/oltalama.db" +DATE=$(date +%Y%m%d-%H%M%S) + +# Backup dizini oluştur +mkdir -p $BACKUP_DIR + +# Database yedekle +cp $DB_PATH "$BACKUP_DIR/oltalama-$DATE.db" + +# 30 günden eski yedekleri sil +find $BACKUP_DIR -name "oltalama-*.db" -mtime +30 -delete + +echo "Backup completed: oltalama-$DATE.db" +``` + +```bash +chmod +x /opt/oltalama/backup.sh + +# Crontab ekle (her gün saat 03:00'te) +crontab -e +# Ekle: +0 3 * * * /opt/oltalama/backup.sh >> /var/log/oltalama/backup.log 2>&1 +``` + +### 3. Tam Sistem Yedeği + +```bash +# Tüm projeyi yedekle +tar -czf /backup/oltalama-full-$(date +%Y%m%d).tar.gz \ + /opt/oltalama \ + /etc/systemd/system/oltalama-*.service \ + /var/log/oltalama +``` + +## 🔄 Güncelleme + +### Git ile Güncelleme + +```bash +cd /opt/oltalama + +# Değişiklikleri al +git pull origin main + +# Backend güncelleme +cd backend +npm install --production +node migrations/run-migrations.js + +# Frontend güncelleme +cd ../frontend +npm install +npm run build + +# Servisleri yeniden başlat +pm2 restart all +# veya +sudo systemctl restart oltalama-backend +sudo systemctl restart oltalama-frontend +``` + +## 📊 Monitoring ve Loglar + +### PM2 Monitoring + +```bash +# Dashboard +pm2 monit + +# Memory/CPU kullanımı +pm2 list +``` + +### Log Dosyaları + +```bash +# Backend logs +tail -f /var/log/oltalama/backend.log +tail -f /var/log/oltalama/backend-error.log + +# Frontend logs +tail -f /var/log/oltalama/frontend.log + +# PM2 logs +pm2 logs --lines 100 +``` + +### Log Rotation + +`/etc/logrotate.d/oltalama`: + +``` +/var/log/oltalama/*.log { + daily + rotate 30 + compress + delaycompress + missingok + notifempty + create 0640 www-data www-data + sharedscripts + postrotate + pm2 reloadLogs + endscript +} +``` + +## 🐛 Sorun Giderme + +### Port Zaten Kullanımda + +```bash +# Port 3000'i kullanan process'i bul +sudo lsof -i :3000 + +# Process'i öldür +sudo kill -9 +``` + +### Database Locked + +```bash +# SQLite lock'ları temizle +fuser -k /opt/oltalama/backend/database/oltalama.db +``` + +### PM2 Çalışmıyor + +```bash +# PM2'yi sıfırla +pm2 kill +pm2 start ecosystem.config.js +pm2 save +``` + +### High Memory Usage + +```bash +# Memory kullanımını kontrol et +pm2 list + +# Uygulamayı yeniden başlat +pm2 restart oltalama-backend --update-env +``` + +## 👥 Kullanıcı Yönetimi + +### Yeni Admin Kullanıcısı Ekleme + +```bash +cd /opt/oltalama +node scripts/create-admin.js +``` + +### Admin Şifresi Değiştirme + +```bash +cd /opt/oltalama +node scripts/change-password.js +``` + +### Admin Kullanıcısını Manuel Oluşturma (SQL) + +```bash +# Şifre hash'i oluştur +node -p "require('bcrypt').hashSync('YourPassword123', 10)" + +# SQLite ile kullanıcı ekle +cd /opt/oltalama/backend +sqlite3 database/oltalama.db + +INSERT INTO admin_user (username, password_hash, full_name, created_at, updated_at) +VALUES ('newadmin', '$2b$10$...', 'New Admin', datetime('now'), datetime('now')); + +.quit +``` + +### Tüm Admin Kullanıcılarını Listele + +```bash +cd /opt/oltalama/backend +sqlite3 database/oltalama.db "SELECT id, username, full_name, email, created_at FROM admin_user;" +``` + +### Admin Kullanıcısı Sil + +```bash +cd /opt/oltalama/backend +sqlite3 database/oltalama.db "DELETE FROM admin_user WHERE username='oldadmin';" +``` + +## 📝 Opsiyonel: Manuel Nginx Kurulumu + +Nginx Proxy Manager yerine klasik Nginx kullanmak isterseniz: + +### Nginx Kurulumu + +```bash +sudo apt install nginx +``` + +### Nginx Konfigürasyonu + +`/etc/nginx/sites-available/oltalama`: + +```nginx +# Upstream tanımları +upstream backend { + server localhost:3000; + keepalive 64; +} + +upstream frontend { + server localhost:4173; + keepalive 64; +} + +# HTTP to HTTPS redirect +server { + listen 80; + listen [::]:80; + server_name yourdomain.com; + return 301 https://$server_name$request_uri; +} + +# HTTPS server +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name yourdomain.com; + + # SSL sertifikaları (Let's Encrypt ile oluşturun) + ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; + ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem; + + # SSL ayarları + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # Security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Client body size + client_max_body_size 10M; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json; + + # Backend API + location /api { + proxy_pass http://backend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } + + # Tracking endpoint + location /t/ { + proxy_pass http://backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Frontend + location / { + proxy_pass http://frontend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } + + # Logs + access_log /var/log/nginx/oltalama-access.log; + error_log /var/log/nginx/oltalama-error.log; +} +``` + +### Nginx'i Aktifleştir + +```bash +# Symlink oluştur +sudo ln -s /etc/nginx/sites-available/oltalama /etc/nginx/sites-enabled/ + +# Konfigürasyonu test et +sudo nginx -t + +# Nginx'i yeniden başlat +sudo systemctl restart nginx +sudo systemctl enable nginx +``` + +### SSL Sertifikası (Let's Encrypt) + +```bash +# Certbot kurulumu +sudo apt install certbot python3-certbot-nginx + +# Sertifika oluştur +sudo certbot --nginx -d yourdomain.com + +# Otomatik yenileme +sudo certbot renew --dry-run +``` + +## ✅ Kurulum Kontrolü + +### Sistemin Çalıştığını Kontrol Et + +```bash +# Servis durumları +pm2 status +# veya +sudo systemctl status oltalama-backend +sudo systemctl status oltalama-frontend + +# Port dinleme kontrolü +sudo netstat -tulpn | grep -E ':(3000|4173)' + +# HTTP istekleri +curl http://localhost:3000/api/health +curl http://localhost:4173 + +# Domain kontrolü (Nginx Proxy Manager kurulduysa) +curl https://yourdomain.com +``` + +### Performans Testi + +```bash +# Backend response time +time curl http://localhost:3000/api/health + +# Memory kullanımı +free -h + +# Disk kullanımı +df -h +``` + +## 📞 Destek + +Sorun yaşarsanız: +1. Logları kontrol edin: `pm2 logs` veya `/var/log/oltalama/` +2. GitHub Issues'da sorun bildirin +3. Dokümanı tekrar gözden geçirin + +## 📚 Ek Kaynaklar + +- [PM2 Documentation](https://pm2.keymetrics.io/) +- [Nginx Documentation](https://nginx.org/en/docs/) +- [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices) +- [SQLite Documentation](https://www.sqlite.org/docs.html) + +--- + +**Son Güncelleme**: 2025-11-10 +**Versiyon**: 1.0.0 + diff --git a/README.md b/README.md index 128896f..efd358c 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ npm run dev # ✅ Çalışıyor (background) ``` **API:** http://localhost:3000 -**Default Admin:** admin / admin123 +**Default Admin:** Kurulum sırasında oluşturulur ### Frontend ✅ TAMAMLANDI @@ -36,7 +36,7 @@ npm run dev # ✅ Çalışıyor (background) ``` **UI:** http://localhost:5173 -**Default Admin:** admin / admin123 +**Default Admin:** Kurulum sırasında oluşturulur ## 📂 Proje Yapısı @@ -178,9 +178,70 @@ curl http://localhost:3000/api/stats/dashboard Sistem kullanıma hazır. Gmail ve Telegram ayarlarını yaparak phishing testlerinizi başlatabilirsiniz. +## 🚀 Sunucu Kurulumu (Production) + +### Otomatik Kurulum + +```bash +cd /opt/oltalama +sudo ./deploy.sh +``` + +### Manuel Kurulum + +Detaylı sunucu kurulum talimatları için: + +```bash +cat DEPLOYMENT.md +``` + +**Önemli dosyalar:** +- `DEPLOYMENT.md` - Detaylı sunucu kurulum kılavuzu +- `deploy.sh` - Otomatik kurulum scripti +- `systemd/` - Systemd servis dosyaları +- `nginx/` - Nginx konfigürasyon örneği + +**Portlar:** +- Backend: `3000` (değiştirilebilir) +- Frontend: `4173` (değiştirilebilir) + +**Domain Seçenekleri:** +- ✅ **Tek Domain** (önerilen): `yourdomain.com` - Path-based routing +- ✅ **İki Domain**: `api.yourdomain.com` + `panel.yourdomain.com` - CORS aktif + +**Process Manager:** +- ✅ PM2 (önerilen - otomatik restart, monitoring) +- ✅ Systemd (native Linux service) + +**Reverse Proxy:** +- ✅ Nginx Proxy Manager (önerilen - GUI) +- ✅ Nginx (manuel konfig: `nginx/oltalama.conf`) + +## 🛠️ Yardımcı Scriptler + +### Admin Kullanıcı Yönetimi + +```bash +# Yeni admin kullanıcısı oluştur +node scripts/create-admin.js + +# Admin şifresini değiştir +node scripts/change-password.js +``` + +**Özellikler:** +- ✅ İnteraktif kullanıcı oluşturma +- ✅ Şifre güvenlik validasyonu (min 8 karakter, harf+rakam) +- ✅ Benzersiz kullanıcı adı kontrolü +- ✅ Güvenli bcrypt hash'leme + ## 📚 Dokümantasyon - **Ana Doküman:** `README.md` (bu dosya) +- **Sunucu Kurulumu:** `DEPLOYMENT.md` 🚀 (Production kurulum) +- **Domain Yapılandırma:** `docs/DOMAIN_SETUP.md` 🌐 (Tek/İki domain) +- **Nginx Proxy Manager:** `docs/NGINX_PROXY_MANAGER.md` 🔄 (Reverse proxy) +- **Güvenlik Rehberi:** `SECURITY.md` 🔒 (Güvenlik en iyi uygulamaları) - **Hızlı Başlangıç:** `QUICKSTART.md` ⚡ (5 dakika) - **Kullanım Kılavuzu:** `KULLANIM.md` 📖 (Detaylı) - **Development Plan:** `devpan.md` 🏗️ (Teknik detay) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..62a71c5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,454 @@ +# 🔒 Güvenlik Rehberi + +Oltalama Test Yönetim Paneli için güvenlik en iyi uygulamaları ve önerileri. + +## 🎯 Temel Güvenlik Prensipleri + +### 1. Admin Kullanıcı Güvenliği + +#### Güçlü Şifre Kullanımı + +**Minimum Gereksinimler:** +- En az 8 karakter +- En az 1 büyük harf +- En az 1 küçük harf +- En az 1 rakam +- Önerilen: En az 1 özel karakter (!@#$%^&*) + +**Önerilen Şifre Uzunluğu:** 12+ karakter + +**Güçlü Şifre Örnekleri:** +- ✅ `S3cur3P@ssw0rd!` +- ✅ `MyT3st#2025!Pass` +- ✅ `Phish1ng$Test@2025` + +**Zayıf Şifreler (KULLANMAYIN):** +- ❌ `admin123` +- ❌ `password` +- ❌ `12345678` +- ❌ `qwerty123` + +#### Şifre Yönetimi + +```bash +# Şifre değiştirme (90 günde bir önerilir) +cd /opt/oltalama +node scripts/change-password.js + +# Yeni admin kullanıcısı ekleme +node scripts/create-admin.js +``` + +#### Varsayılan Kullanıcı + +- ⚠️ **ÖNEMLİ:** Sistem varsayılan kullanıcı ile gelmiyor +- ✅ Kurulum sırasında güvenli bir kullanıcı oluşturmanız gerekir +- ✅ Şifreniz bcrypt ile hash'lenmiş olarak saklanır + +### 2. Sunucu Güvenliği + +#### Firewall Konfigürasyonu + +```bash +# UFW kurulumu +sudo apt install ufw + +# Gerekli portları aç +sudo ufw allow 22/tcp # SSH +sudo ufw allow 80/tcp # HTTP +sudo ufw allow 443/tcp # HTTPS + +# Uygulama portlarını kapat (reverse proxy kullanın) +sudo ufw deny 3000/tcp # Backend +sudo ufw deny 4173/tcp # Frontend + +# Firewall'ı aktifleştir +sudo ufw enable + +# Durumu kontrol et +sudo ufw status +``` + +#### SSH Güvenliği + +```bash +# /etc/ssh/sshd_config +PermitRootLogin no +PasswordAuthentication no # SSH key kullanın +PubkeyAuthentication yes +Port 22 # Veya özel bir port + +# SSH servisini yeniden başlat +sudo systemctl restart sshd +``` + +#### Fail2Ban Kurulumu + +```bash +# Fail2Ban kurulumu +sudo apt install fail2ban + +# Konfigürasyon +sudo nano /etc/fail2ban/jail.local +``` + +```ini +[DEFAULT] +bantime = 3600 +findtime = 600 +maxretry = 5 + +[sshd] +enabled = true +port = 22 +logpath = /var/log/auth.log + +[nginx-http-auth] +enabled = true +filter = nginx-http-auth +port = http,https +logpath = /var/log/nginx/error.log +``` + +```bash +# Fail2Ban'ı başlat +sudo systemctl restart fail2ban +sudo systemctl enable fail2ban + +# Durumu kontrol et +sudo fail2ban-client status +``` + +### 3. SSL/TLS Sertifikası + +#### Let's Encrypt ile Ücretsiz SSL + +```bash +# Certbot kurulumu +sudo apt install certbot python3-certbot-nginx + +# Sertifika oluşturma +sudo certbot --nginx -d yourdomain.com + +# Otomatik yenileme testi +sudo certbot renew --dry-run +``` + +#### SSL Konfigürasyonu + +**Minimum TLS Versiyonu:** TLSv1.2 ve TLSv1.3 + +```nginx +# Nginx SSL ayarları +ssl_protocols TLSv1.2 TLSv1.3; +ssl_prefer_server_ciphers on; +ssl_ciphers HIGH:!aNULL:!MD5; + +# HSTS header +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; +``` + +### 4. Database Güvenliği + +#### Dosya İzinleri + +```bash +# Database dosya izinleri +sudo chmod 600 /opt/oltalama/backend/database/oltalama.db +sudo chown www-data:www-data /opt/oltalama/backend/database/oltalama.db + +# Backup dizini izinleri +sudo chmod 700 /opt/oltalama/backups +sudo chown www-data:www-data /opt/oltalama/backups +``` + +#### Düzenli Yedekleme + +```bash +# Otomatik yedekleme scripti +# /opt/oltalama/backup.sh + +#!/bin/bash +BACKUP_DIR="/opt/oltalama/backups" +DB_PATH="/opt/oltalama/backend/database/oltalama.db" +DATE=$(date +%Y%m%d-%H%M%S) + +# Yedek al +cp $DB_PATH "$BACKUP_DIR/oltalama-$DATE.db" + +# Eski yedekleri sil (30 günden eski) +find $BACKUP_DIR -name "oltalama-*.db" -mtime +30 -delete + +# Backup'ı şifrele (opsiyonel) +gpg --symmetric --cipher-algo AES256 "$BACKUP_DIR/oltalama-$DATE.db" +rm "$BACKUP_DIR/oltalama-$DATE.db" +``` + +```bash +# Crontab ekle +crontab -e +# Ekle: Her gün saat 03:00'te yedek al +0 3 * * * /opt/oltalama/backup.sh >> /var/log/oltalama/backup.log 2>&1 +``` + +### 5. Uygulama Güvenliği + +#### Çevre Değişkenleri + +```bash +# .env dosya izinleri +sudo chmod 600 /opt/oltalama/backend/.env +sudo chmod 600 /opt/oltalama/frontend/.env + +# Sahibi ayarla +sudo chown www-data:www-data /opt/oltalama/backend/.env +sudo chown www-data:www-data /opt/oltalama/frontend/.env +``` + +#### Session Secret + +```bash +# Güçlü session secret oluştur +node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" + +# .env dosyasına ekle +SESSION_SECRET=uzun-rastgele-gizli-anahtar-buraya +``` + +#### Rate Limiting + +Uygulama zaten rate limiting kullanıyor: +- Login endpoint: 5 istek / dakika +- API endpoints: 100 istek / 15 dakika + +#### Security Headers + +Uygulama otomatik olarak şu güvenlik başlıklarını ekliyor: +- `X-Content-Type-Options: nosniff` +- `X-Frame-Options: SAMEORIGIN` +- `X-XSS-Protection: 1; mode=block` +- `Strict-Transport-Security` (HTTPS ile) + +### 6. Gmail Güvenliği + +#### App Password Kullanımı + +✅ **Doğru:** Gmail App Password kullanın +❌ **Yanlış:** Normal Gmail şifresi kullanmayın + +**App Password Oluşturma:** +1. Google Hesabı → Güvenlik +2. 2 Adımlı Doğrulama'yı aktifleştir +3. Uygulama Şifreleri → Mail +4. Oluşturulan şifreyi panele girin + +**Güvenlik İpuçları:** +- App Password'ü asla paylaşmayın +- Düzenli olarak değiştirin (6 ayda bir) +- Kullanılmayan app password'leri silin + +### 7. Telegram Bot Güvenliği + +#### Bot Token Güvenliği + +```bash +# .env dosyasında saklayın +TELEGRAM_BOT_TOKEN=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz + +# Asla git'e commit etmeyin +echo ".env" >> .gitignore +``` + +#### Chat ID Doğrulama + +```bash +# Sadece belirli chat ID'lere bildirim gönderin +# Bot'u sadece bilinen kişilerle paylaşın +``` + +### 8. Log Yönetimi + +#### Log Dosyalarını Koruma + +```bash +# Log dizini izinleri +sudo chmod 750 /var/log/oltalama +sudo chown www-data:www-data /var/log/oltalama + +# Log dosyaları izinleri +sudo chmod 640 /var/log/oltalama/*.log +``` + +#### Log Rotation + +```bash +# /etc/logrotate.d/oltalama +/var/log/oltalama/*.log { + daily + rotate 30 + compress + delaycompress + missingok + notifempty + create 0640 www-data www-data + sharedscripts + postrotate + pm2 reloadLogs + endscript +} +``` + +#### Hassas Bilgileri Loglamayın + +- ❌ Şifreler +- ❌ Session token'lar +- ❌ API keys +- ❌ Kredi kartı bilgileri + +### 9. Düzenli Güncellemeler + +#### Sistem Güncellemeleri + +```bash +# Sistem paketlerini güncelle +sudo apt update && sudo apt upgrade -y + +# Güvenlik güncellemelerini otomatik yap +sudo apt install unattended-upgrades +sudo dpkg-reconfigure -plow unattended-upgrades +``` + +#### Uygulama Güncellemeleri + +```bash +# Backend dependencies +cd /opt/oltalama/backend +npm audit +npm audit fix + +# Frontend dependencies +cd /opt/oltalama/frontend +npm audit +npm audit fix + +# PM2 güncelleme +sudo npm update -g pm2 +pm2 update +``` + +### 10. Monitoring ve Alerting + +#### PM2 Monitoring + +```bash +# PM2 status +pm2 status + +# Memory ve CPU kullanımı +pm2 monit + +# Error logları izle +pm2 logs --err +``` + +#### Sistem Monitoring + +```bash +# Disk kullanımı +df -h + +# Memory kullanımı +free -h + +# CPU kullanımı +top + +# Network bağlantıları +sudo netstat -tulpn +``` + +## 🚨 Güvenlik Kontrol Listesi + +### Kurulum Sonrası + +- [ ] Güçlü admin şifresi oluşturuldu +- [ ] .env dosya izinleri ayarlandı (600) +- [ ] Database izinleri ayarlandı (600) +- [ ] Firewall yapılandırıldı +- [ ] SSL sertifikası kuruldu +- [ ] Fail2Ban kuruldu +- [ ] SSH key-based auth aktif +- [ ] Otomatik yedekleme ayarlandı +- [ ] Log rotation yapılandırıldı + +### Aylık Kontroller + +- [ ] Sistem güncellemeleri yapıldı +- [ ] npm audit çalıştırıldı +- [ ] Loglar gözden geçirildi +- [ ] Yedekler test edildi +- [ ] Disk kullanımı kontrol edildi + +### Üç Aylık Kontroller + +- [ ] Admin şifresi değiştirildi +- [ ] Gmail App Password yenilendi +- [ ] Kullanılmayan kullanıcılar silindi +- [ ] SSL sertifikası kontrol edildi + +### Yıllık Kontroller + +- [ ] Tam sistem denetimi yapıldı +- [ ] Güvenlik politikaları gözden geçirildi +- [ ] Yedekleme stratejisi gözden geçirildi + +## 🔍 Güvenlik Olaylarına Müdahale + +### Şüpheli Aktivite Tespiti + +```bash +# Son giriş denemeleri +sudo tail -100 /var/log/auth.log + +# Fail2Ban ban listesi +sudo fail2ban-client status sshd + +# Nginx access logları +sudo tail -100 /var/log/nginx/oltalama-access.log + +# Uygulama error logları +pm2 logs --err --lines 100 +``` + +### Güvenlik İhlali Durumunda + +1. **Hemen:** + - Tüm admin şifrelerini değiştir + - Gmail App Password'ü yenile + - Telegram Bot Token'ı yenile + - Session secret'ı değiştir ve tüm servisleri yeniden başlat + +2. **Kısa Vadede:** + - Tüm logları yedekle + - Şüpheli IP adreslerini banla + - Sistem taraması yap + +3. **Uzun Vadede:** + - Güvenlik politikalarını gözden geçir + - İhlal raporunu hazırla + - Ek güvenlik önlemleri al + +## 📚 Ek Kaynaklar + +- [OWASP Top 10](https://owasp.org/www-project-top-ten/) +- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/) +- [Express.js Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html) +- [Nginx Security Tips](https://nginx.org/en/docs/http/ngx_http_ssl_module.html) + +--- + +**Son Güncelleme:** 2025-11-10 +**Versiyon:** 1.0.0 + +⚠️ **UYARI:** Bu sistem sadece yasal ve etik phishing testleri için kullanılmalıdır. Kötü niyetli kullanım yasaktır ve suçtur. + diff --git a/backend/src/app.js b/backend/src/app.js index aad9228..06daec0 100644 --- a/backend/src/app.js +++ b/backend/src/app.js @@ -14,10 +14,41 @@ const PORT = process.env.PORT || 3000; // Security middleware app.use(helmet()); -app.use(cors({ - origin: process.env.FRONTEND_URL || 'http://localhost:3001', + +// Dynamic CORS configuration (will be updated from settings) +let corsOptions = { + origin: process.env.FRONTEND_URL || 'http://localhost:5173', credentials: true, -})); +}; + +app.use((req, res, next) => { + cors(corsOptions)(req, res, next); +}); + +// Function to update CORS from database +const updateCorsFromSettings = async () => { + try { + const { Settings } = require('./models'); + const corsEnabledSetting = await Settings.findOne({ where: { key: 'cors_enabled' } }); + const frontendUrlSetting = await Settings.findOne({ where: { key: 'frontend_url' } }); + + if (corsEnabledSetting && corsEnabledSetting.value === 'true' && frontendUrlSetting) { + corsOptions.origin = frontendUrlSetting.value; + logger.info(`CORS enabled for: ${frontendUrlSetting.value}`); + } else { + // Default: allow both frontend and backend on same origin + corsOptions.origin = process.env.FRONTEND_URL || 'http://localhost:5173'; + } + } catch (error) { + logger.warn('Could not load CORS settings from database, using defaults'); + } +}; + +// Update CORS on startup (with delay to ensure DB is ready) +setTimeout(updateCorsFromSettings, 2000); + +// Export for use in settings controller +app.updateCorsSettings = updateCorsFromSettings; // Body parsing middleware app.use(express.json()); diff --git a/backend/src/controllers/settings.controller.js b/backend/src/controllers/settings.controller.js index 0f68671..f3d7ebb 100644 --- a/backend/src/controllers/settings.controller.js +++ b/backend/src/controllers/settings.controller.js @@ -97,6 +97,89 @@ exports.updateTelegramSettings = async (req, res, next) => { } }; +// Update System settings (domain, etc.) +exports.updateSystemSettings = async (req, res, next) => { + try { + const { base_url, frontend_url, cors_enabled } = req.body; + + if (base_url !== undefined) { + if (base_url) { + // Remove trailing slash if exists + const cleanUrl = base_url.trim().replace(/\/$/, ''); + + // Basic URL validation + try { + new URL(cleanUrl); + } catch (e) { + return res.status(400).json({ + success: false, + error: 'Geçersiz Base URL formatı. Örnek: https://yourdomain.com', + }); + } + + await Settings.upsert({ + key: 'base_url', + value: cleanUrl, + is_encrypted: false, + description: 'Base URL for tracking links (backend)', + }); + + // Update process.env for immediate use + process.env.BASE_URL = cleanUrl; + } else { + await Settings.destroy({ where: { key: 'base_url' } }); + } + } + + if (frontend_url !== undefined) { + if (frontend_url) { + // Remove trailing slash if exists + const cleanUrl = frontend_url.trim().replace(/\/$/, ''); + + // Basic URL validation + try { + new URL(cleanUrl); + } catch (e) { + return res.status(400).json({ + success: false, + error: 'Geçersiz Frontend URL formatı. Örnek: https://panel.yourdomain.com', + }); + } + + await Settings.upsert({ + key: 'frontend_url', + value: cleanUrl, + is_encrypted: false, + description: 'Frontend URL (for CORS)', + }); + } else { + await Settings.destroy({ where: { key: 'frontend_url' } }); + } + } + + if (cors_enabled !== undefined) { + await Settings.upsert({ + key: 'cors_enabled', + value: cors_enabled ? 'true' : 'false', + is_encrypted: false, + description: 'Enable CORS for separate domains', + }); + } + + // Update CORS configuration if available + if (req.app && req.app.updateCorsSettings) { + await req.app.updateCorsSettings(); + } + + res.json({ + success: true, + message: 'Sistem ayarları güncellendi. CORS ayarları uygulandı.', + }); + } catch (error) { + next(error); + } +}; + // Test Gmail connection exports.testGmail = async (req, res, next) => { try { diff --git a/backend/src/models/TrackingToken.js b/backend/src/models/TrackingToken.js index 5849a94..ac13894 100644 --- a/backend/src/models/TrackingToken.js +++ b/backend/src/models/TrackingToken.js @@ -30,6 +30,11 @@ const TrackingToken = sequelize.define('TrackingToken', { type: DataTypes.STRING(50), defaultValue: 'bank', }, + from_name: { + type: DataTypes.STRING(255), + allowNull: true, + comment: 'Custom sender name for email (e.g., "HR Department", "Management")', + }, mail_subject: { type: DataTypes.STRING(500), allowNull: true, diff --git a/backend/src/routes/settings.routes.js b/backend/src/routes/settings.routes.js index 9c02d60..9f3b42c 100644 --- a/backend/src/routes/settings.routes.js +++ b/backend/src/routes/settings.routes.js @@ -9,6 +9,7 @@ router.use(requireAuth); router.get('/', settingsController.getAllSettings); router.put('/gmail', settingsController.updateGmailSettings); router.put('/telegram', settingsController.updateTelegramSettings); +router.put('/system', settingsController.updateSystemSettings); router.post('/test-gmail', settingsController.testGmail); router.post('/test-telegram', settingsController.testTelegram); diff --git a/backend/src/services/mail.service.js b/backend/src/services/mail.service.js index 530649b..2a606be 100644 --- a/backend/src/services/mail.service.js +++ b/backend/src/services/mail.service.js @@ -45,14 +45,19 @@ class MailService { } } - async sendMail(to, subject, htmlBody) { + async sendMail(to, subject, htmlBody, fromName = null) { try { if (!this.transporter) { await this.initializeTransporter(); } + // Use custom from_name if provided, otherwise use default + const from = fromName + ? `${fromName} <${this.fromAddress.match(/<(.+)>/)?.[1] || this.fromAddress}>` + : this.fromAddress; + const mailOptions = { - from: this.fromAddress, + from, to, subject, html: htmlBody, diff --git a/backend/src/services/token.service.js b/backend/src/services/token.service.js index c0f8e44..aae9414 100644 --- a/backend/src/services/token.service.js +++ b/backend/src/services/token.service.js @@ -5,7 +5,7 @@ const logger = require('../config/logger'); class TokenService { async createToken(data) { - const { company_id, target_email, employee_name, template_type } = data; + const { company_id, target_email, employee_name, template_type, from_name } = data; // Generate unique token let token = generateTrackingToken(); @@ -45,6 +45,7 @@ class TokenService { target_email, employee_name, template_type, + from_name: from_name || null, mail_subject: template.subject_template.replace('{{company_name}}', company.name), }); @@ -78,8 +79,13 @@ class TokenService { throw new Error('Mail template not found'); } + // Get base URL from settings or env + const { Settings } = require('../models'); + const baseUrlSetting = await Settings.findOne({ where: { key: 'base_url' } }); + const baseUrl = baseUrlSetting?.value || process.env.BASE_URL || 'http://localhost:3000'; + // Prepare template data - const trackingUrl = `${process.env.BASE_URL}/t/${token.token}`; + const trackingUrl = `${baseUrl}/t/${token.token}`; const currentDate = new Date().toLocaleDateString('tr-TR', { year: 'numeric', month: 'long', @@ -99,8 +105,8 @@ class TokenService { const htmlBody = mailService.renderTemplate(template.body_html, templateData); const subject = mailService.renderTemplate(template.subject_template, templateData); - // Send mail - await mailService.sendMail(token.target_email, subject, htmlBody); + // Send mail with custom from_name if provided + await mailService.sendMail(token.target_email, subject, htmlBody, token.from_name); // Update token await token.update({ diff --git a/backend/src/validators/token.validator.js b/backend/src/validators/token.validator.js index 012a9c9..10ae577 100644 --- a/backend/src/validators/token.validator.js +++ b/backend/src/validators/token.validator.js @@ -20,6 +20,13 @@ const createTokenSchema = Joi.object({ .max(255) .allow(null, '') .optional(), + from_name: Joi.string() + .max(255) + .allow(null, '') + .optional() + .messages({ + 'string.max': 'From name must be less than 255 characters', + }), template_type: Joi.string() .max(50) .default('bank') diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..8cdc406 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,562 @@ +#!/bin/bash + +############################################################################### +# Oltalama Test Yönetim Paneli - Otomatik Kurulum Scripti +# Version: 1.0.0 +# Date: 2025-11-10 +############################################################################### + +set -e # Exit on error + +# Renkli çıktılar +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Değişkenler +INSTALL_DIR="/opt/oltalama" +LOG_DIR="/var/log/oltalama" +BACKUP_DIR="${INSTALL_DIR}/backups" +USER="www-data" +NODE_VERSION="20" + +# Fonksiyonlar +print_header() { + echo -e "\n${BLUE}╔═══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${BLUE}║ ║${NC}" + echo -e "${BLUE}║ Oltalama Test Yönetim Paneli - Kurulum Scripti ║${NC}" + echo -e "${BLUE}║ Version 1.0.0 ║${NC}" + echo -e "${BLUE}║ ║${NC}" + echo -e "${BLUE}╚═══════════════════════════════════════════════════════════════╝${NC}\n" +} + +print_success() { + echo -e "${GREEN}✓ $1${NC}" +} + +print_error() { + echo -e "${RED}✗ $1${NC}" +} + +print_warning() { + echo -e "${YELLOW}⚠ $1${NC}" +} + +print_info() { + echo -e "${BLUE}ℹ $1${NC}" +} + +check_root() { + if [[ $EUID -ne 0 ]]; then + print_error "Bu script root yetkisi ile çalıştırılmalıdır." + print_info "Lütfen 'sudo ./deploy.sh' komutunu kullanın." + exit 1 + fi +} + +check_os() { + if [[ -f /etc/os-release ]]; then + . /etc/os-release + OS=$ID + VERSION=$VERSION_ID + print_success "İşletim sistemi tespit edildi: $PRETTY_NAME" + else + print_error "İşletim sistemi tespit edilemedi!" + exit 1 + fi +} + +install_nodejs() { + print_info "Node.js ${NODE_VERSION}.x kuruluyor..." + + if command -v node &> /dev/null; then + CURRENT_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1) + if [[ $CURRENT_VERSION -ge $NODE_VERSION ]]; then + print_success "Node.js $(node -v) zaten yüklü." + return + fi + fi + + # NodeSource repository ekle + curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - + apt-get install -y nodejs + + print_success "Node.js $(node -v) kuruldu." + print_success "npm $(npm -v) kuruldu." +} + +install_dependencies() { + print_info "Sistem bağımlılıkları kuruluyor..." + apt-get update + apt-get install -y git curl wget build-essential sqlite3 + print_success "Sistem bağımlılıkları kuruldu." +} + +install_pm2() { + print_info "PM2 process manager kuruluyor..." + npm install -g pm2 + print_success "PM2 $(pm2 -v) kuruldu." +} + +setup_directories() { + print_info "Dizinler oluşturuluyor..." + + mkdir -p $LOG_DIR + mkdir -p $BACKUP_DIR + mkdir -p "${INSTALL_DIR}/backend/database" + + print_success "Dizinler oluşturuldu." +} + +install_project() { + print_info "Proje dosyaları kontrol ediliyor..." + + # Eğer script zaten proje dizininde çalıştırılıyorsa + if [[ -f "$(pwd)/backend/package.json" ]]; then + CURRENT_DIR=$(pwd) + print_info "Mevcut dizinden kurulum yapılıyor: $CURRENT_DIR" + + if [[ "$CURRENT_DIR" != "$INSTALL_DIR" ]]; then + print_info "Dosyalar $INSTALL_DIR dizinine kopyalanıyor..." + rsync -av --exclude 'node_modules' --exclude '.git' \ + "$CURRENT_DIR/" "$INSTALL_DIR/" + fi + else + print_error "Proje dosyaları bulunamadı!" + print_info "Script'i proje dizininde çalıştırın veya projeyi klonlayın." + exit 1 + fi + + print_success "Proje dosyaları hazır." +} + +install_backend() { + print_info "Backend dependencies kuruluyor..." + cd "${INSTALL_DIR}/backend" + + npm install --production + + print_success "Backend dependencies kuruldu." +} + +install_frontend() { + print_info "Frontend dependencies kuruluyor..." + cd "${INSTALL_DIR}/frontend" + + npm install + + print_success "Frontend dependencies kuruldu." +} + +setup_env_files() { + print_info "Çevre değişkenleri ayarlanıyor..." + + # Backend .env + if [[ ! -f "${INSTALL_DIR}/backend/.env" ]]; then + cp "${INSTALL_DIR}/backend/.env.example" "${INSTALL_DIR}/backend/.env" + + # Session secret oluştur + SESSION_SECRET=$(node -e "console.log(require('crypto').randomBytes(64).toString('hex'))") + + # .env dosyasını güncelle + sed -i "s|NODE_ENV=development|NODE_ENV=production|g" "${INSTALL_DIR}/backend/.env" + sed -i "s|SESSION_SECRET=.*|SESSION_SECRET=${SESSION_SECRET}|g" "${INSTALL_DIR}/backend/.env" + sed -i "s|DB_PATH=.*|DB_PATH=${INSTALL_DIR}/backend/database/oltalama.db|g" "${INSTALL_DIR}/backend/.env" + + print_success "Backend .env dosyası oluşturuldu." + print_warning "Gmail ve Telegram ayarlarını panelden yapabilirsiniz." + else + print_info "Backend .env dosyası zaten mevcut." + fi + + # Frontend .env + if [[ ! -f "${INSTALL_DIR}/frontend/.env" ]]; then + cp "${INSTALL_DIR}/frontend/.env.example" "${INSTALL_DIR}/frontend/.env" + print_success "Frontend .env dosyası oluşturuldu." + else + print_info "Frontend .env dosyası zaten mevcut." + fi +} + +setup_admin_user() { + print_info "Admin kullanıcısı oluşturuluyor..." + + # Check if admin already exists + ADMIN_COUNT=$(sqlite3 "${INSTALL_DIR}/backend/database/oltalama.db" "SELECT COUNT(*) FROM admin_user;" 2>/dev/null || echo "0") + + if [[ "$ADMIN_COUNT" -gt 0 ]]; then + print_info "Admin kullanıcısı zaten mevcut, atlanıyor." + return + fi + + echo "" + print_warning "╔═══════════════════════════════════════════════════════════════╗" + print_warning "║ Admin Kullanıcı Bilgilerini Oluşturun ║" + print_warning "╚═══════════════════════════════════════════════════════════════╝" + echo "" + + # Username + while true; do + read -p "Admin kullanıcı adı (en az 3 karakter): " ADMIN_USERNAME + if [[ ${#ADMIN_USERNAME} -ge 3 ]]; then + break + else + print_error "Kullanıcı adı en az 3 karakter olmalıdır!" + fi + done + + # Password with validation + while true; do + read -sp "Admin şifresi (en az 8 karakter, harf ve rakam içermeli): " ADMIN_PASSWORD + echo "" + + # Password length check + if [[ ${#ADMIN_PASSWORD} -lt 8 ]]; then + print_error "Şifre en az 8 karakter olmalıdır!" + continue + fi + + # Check for letters and numbers + if ! [[ "$ADMIN_PASSWORD" =~ [a-zA-Z] ]] || ! [[ "$ADMIN_PASSWORD" =~ [0-9] ]]; then + print_error "Şifre hem harf hem de rakam içermelidir!" + continue + fi + + # Confirm password + read -sp "Şifreyi tekrar girin: " ADMIN_PASSWORD_CONFIRM + echo "" + + if [[ "$ADMIN_PASSWORD" == "$ADMIN_PASSWORD_CONFIRM" ]]; then + break + else + print_error "Şifreler eşleşmiyor! Tekrar deneyin." + fi + done + + # Create admin user using Node.js + cd "${INSTALL_DIR}/backend" + + cat > /tmp/create_admin.js << EOF +const bcrypt = require('bcrypt'); +const { sequelize } = require('./src/config/database'); +const AdminUser = require('./src/models/AdminUser'); + +(async () => { + try { + await sequelize.authenticate(); + + const hashedPassword = await bcrypt.hash('${ADMIN_PASSWORD}', 10); + + await AdminUser.create({ + username: '${ADMIN_USERNAME}', + password_hash: hashedPassword, + email: null, + full_name: 'Administrator', + }); + + console.log('✓ Admin kullanıcısı oluşturuldu'); + process.exit(0); + } catch (error) { + console.error('✗ Hata:', error.message); + process.exit(1); + } +})(); +EOF + + node /tmp/create_admin.js + rm -f /tmp/create_admin.js + + print_success "Admin kullanıcısı oluşturuldu: ${ADMIN_USERNAME}" + echo "" +} + +setup_database() { + print_info "Database oluşturuluyor..." + cd "${INSTALL_DIR}/backend" + + # Migrations + node migrations/run-migrations.js + print_success "Database migrations tamamlandı." + + # Seed sample data (companies and templates only, not admin user) + ADMIN_COUNT=$(sqlite3 "${INSTALL_DIR}/backend/database/oltalama.db" "SELECT COUNT(*) FROM admin_user;" 2>/dev/null || echo "0") + + if [[ "$ADMIN_COUNT" -eq 0 ]]; then + # Seed only non-admin data + cat > /tmp/seed_data.js << 'EOF' +const { sequelize } = require('./src/config/database'); +const { Company, MailTemplate } = require('./src/models'); + +(async () => { + try { + await sequelize.authenticate(); + + // Seed companies + const companies = [ + { name: 'Türk Telekom', domain: 'turktelekom.com.tr', description: 'Türkiye\'nin lider telekomünikasyon şirketi' }, + { name: 'İş Bankası', domain: 'isbank.com.tr', description: 'Türkiye\'nin en büyük özel sermayeli bankası' }, + { name: 'PTT', domain: 'ptt.gov.tr', description: 'Posta ve Telgraf Teşkilatı' }, + ]; + + for (const company of companies) { + await Company.findOrCreate({ where: { name: company.name }, defaults: company }); + } + + // Seed templates + const templates = [ + { + name: 'Banka Güvenlik Uyarısı', + template_type: 'bank', + subject_template: '🔒 {{company_name}} - Hesap Güvenlik Uyarısı', + body_html: '

🔒 Güvenlik Uyarısı

Sayın {{employee_name}},

{{company_name}} hesabınızda şüpheli bir aktivite tespit edildi. Hesabınızın güvenliğini sağlamak için lütfen aşağıdaki bağlantıya tıklayarak kimlik doğrulaması yapın.

Hesabımı Doğrula

Bu işlemi 24 saat içinde yapmazsanız hesabınız geçici olarak askıya alınabilir.

Tarih: {{current_date}}


Bu bir phishing testidir. Gerçek bir güvenlik tehdidi değildir.

', + description: 'Banka hesap güvenliği temalı phishing test maili', + active: true, + }, + { + name: 'E-Devlet Sistem Güncellemesi', + template_type: 'edevlet', + subject_template: '⚠️ E-Devlet - Sistem Güncellemesi Gerekli', + body_html: '

E-DEVLET KAPISI

Sayın {{employee_name}},

E-Devlet sistemimizde önemli bir güvenlik güncellemesi yapılmaktadır. Hesabınıza erişiminizi sürdürebilmek için lütfen kimlik bilgilerinizi güncelleyin.

Bilgilerimi Güncelle

⚠️ Bu işlemi 48 saat içinde tamamlamazsanız E-Devlet hesabınız askıya alınacaktır.

İşlem Tarihi: {{current_date}}

Bu bir phishing farkındalık testidir.

© {{current_year}} E-Devlet Kapısı

', + description: 'E-Devlet sistem güncellemesi temalı phishing test maili', + active: true, + }, + ]; + + for (const template of templates) { + await MailTemplate.findOrCreate({ where: { template_type: template.template_type }, defaults: template }); + } + + console.log('✓ Örnek veriler oluşturuldu'); + process.exit(0); + } catch (error) { + console.error('✗ Hata:', error.message); + process.exit(1); + } +})(); +EOF + + node /tmp/seed_data.js + rm -f /tmp/seed_data.js + print_success "Örnek veriler oluşturuldu (şirketler ve mail şablonları)." + else + print_info "Database zaten veri içeriyor, seed atlanıyor." + fi +} + +build_frontend() { + print_info "Frontend build ediliyor..." + cd "${INSTALL_DIR}/frontend" + + npm run build + + print_success "Frontend build tamamlandı." +} + +setup_pm2() { + print_info "PM2 konfigürasyonu yapılıyor..." + + # ecosystem.config.js oluştur + cat > "${INSTALL_DIR}/ecosystem.config.js" << 'EOF' +module.exports = { + apps: [ + { + name: 'oltalama-backend', + cwd: '/opt/oltalama/backend', + script: 'src/app.js', + instances: 1, + exec_mode: 'cluster', + watch: false, + max_memory_restart: '500M', + env: { + NODE_ENV: 'production', + PORT: 3000, + }, + error_file: '/var/log/oltalama/backend-error.log', + out_file: '/var/log/oltalama/backend-out.log', + log_date_format: 'YYYY-MM-DD HH:mm:ss Z', + }, + { + name: 'oltalama-frontend', + cwd: '/opt/oltalama/frontend', + script: 'npm', + args: 'run preview', + instances: 1, + exec_mode: 'fork', + watch: false, + max_memory_restart: '300M', + env: { + NODE_ENV: 'production', + PORT: 4173, + }, + error_file: '/var/log/oltalama/frontend-error.log', + out_file: '/var/log/oltalama/frontend-out.log', + log_date_format: 'YYYY-MM-DD HH:mm:ss Z', + }, + ], +}; +EOF + + print_success "PM2 konfigürasyon dosyası oluşturuldu." +} + +start_services() { + print_info "Servisler başlatılıyor..." + + cd "${INSTALL_DIR}" + + # PM2 ile başlat + pm2 start ecosystem.config.js + + # Startup script oluştur + pm2 startup systemd -u root --hp /root + pm2 save + + print_success "Servisler başlatıldı." + + # Durum göster + sleep 2 + pm2 status +} + +setup_permissions() { + print_info "Dosya izinleri ayarlanıyor..." + + # Dizin sahipliği + chown -R ${USER}:${USER} ${INSTALL_DIR} + chown -R ${USER}:${USER} ${LOG_DIR} + + # .env dosyaları + chmod 600 "${INSTALL_DIR}/backend/.env" + chmod 600 "${INSTALL_DIR}/frontend/.env" + + # Database + chmod 600 "${INSTALL_DIR}/backend/database/oltalama.db" + + print_success "Dosya izinleri ayarlandı." +} + +setup_firewall() { + print_info "Firewall ayarlanıyor..." + + if command -v ufw &> /dev/null; then + # SSH izin ver + ufw allow 22/tcp comment 'SSH' + + # HTTP/HTTPS izin ver + ufw allow 80/tcp comment 'HTTP' + ufw allow 443/tcp comment 'HTTPS' + + # Backend ve Frontend portlarını engelle (sadece localhost'tan erişilebilir) + ufw deny 3000/tcp comment 'Oltalama Backend (use reverse proxy)' + ufw deny 4173/tcp comment 'Oltalama Frontend (use reverse proxy)' + + # UFW'yi aktifleştir (sadece henüz aktif değilse) + if ! ufw status | grep -q "Status: active"; then + print_warning "UFW firewall aktifleştiriliyor..." + print_warning "SSH bağlantınız kopmayacak (port 22 açık)." + read -p "Devam etmek için ENTER'a basın..." + echo "y" | ufw enable + fi + + print_success "Firewall ayarlandı." + else + print_warning "UFW bulunamadı, firewall ayarları atlanıyor." + fi +} + +setup_backup_cron() { + print_info "Otomatik yedekleme ayarlanıyor..." + + # Backup script oluştur + cat > "${INSTALL_DIR}/backup.sh" << 'EOF' +#!/bin/bash +BACKUP_DIR="/opt/oltalama/backups" +DB_PATH="/opt/oltalama/backend/database/oltalama.db" +DATE=$(date +%Y%m%d-%H%M%S) + +mkdir -p $BACKUP_DIR +cp $DB_PATH "$BACKUP_DIR/oltalama-$DATE.db" +find $BACKUP_DIR -name "oltalama-*.db" -mtime +30 -delete + +echo "Backup completed: oltalama-$DATE.db" +EOF + + chmod +x "${INSTALL_DIR}/backup.sh" + + # Crontab ekle + CRON_JOB="0 3 * * * ${INSTALL_DIR}/backup.sh >> ${LOG_DIR}/backup.log 2>&1" + (crontab -l 2>/dev/null | grep -v "backup.sh"; echo "$CRON_JOB") | crontab - + + print_success "Otomatik yedekleme ayarlandı (her gün saat 03:00)." +} + +print_completion() { + echo -e "\n${GREEN}╔═══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${GREEN}║ ║${NC}" + echo -e "${GREEN}║ 🎉 Kurulum Tamamlandı! 🎉 ║${NC}" + echo -e "${GREEN}║ ║${NC}" + echo -e "${GREEN}╚═══════════════════════════════════════════════════════════════╝${NC}\n" + + print_info "Servis Bilgileri:" + echo -e " Backend: ${BLUE}http://localhost:3000${NC}" + echo -e " Frontend: ${BLUE}http://localhost:4173${NC}" + + print_info "\nAdmin Hesabı:" + echo -e " ${GREEN}✓${NC} Kurulum sırasında oluşturuldu" + echo -e " ${GREEN}✓${NC} Güvenli şifre kullanıldı" + + print_info "\nYapılması Gerekenler:" + echo " 1. Nginx Proxy Manager'da reverse proxy ayarları yapın" + echo " 2. Frontend için: yourdomain.com → localhost:4173" + echo " 3. Backend API için path: /api → localhost:3000" + echo " 4. SSL sertifikası ekleyin" + echo " 5. Panele giriş yapın ve Gmail/Telegram ayarlarını yapın" + + print_info "\nYararlı Komutlar:" + echo " Servis durumu: pm2 status" + echo " Logları izle: pm2 logs" + echo " Servis yeniden başlat: pm2 restart all" + echo " Servis durdur: pm2 stop all" + + print_info "\nDokümantasyon:" + echo " Detaylı kurulum kılavuzu: ${INSTALL_DIR}/DEPLOYMENT.md" + echo " Kullanım kılavuzu: ${INSTALL_DIR}/KULLANIM.md" + echo " Hızlı başlangıç: ${INSTALL_DIR}/QUICKSTART.md" + + print_success "\nKurulum başarıyla tamamlandı!" +} + +# Ana kurulum fonksiyonu +main() { + print_header + + check_root + check_os + + print_info "Kurulum başlıyor...\n" + + install_dependencies + install_nodejs + install_pm2 + setup_directories + install_project + install_backend + install_frontend + setup_env_files + setup_database + setup_admin_user + build_frontend + setup_pm2 + setup_permissions + start_services + setup_firewall + setup_backup_cron + + print_completion +} + +# Script'i çalıştır +main "$@" + diff --git a/docs/DOMAIN_SETUP.md b/docs/DOMAIN_SETUP.md new file mode 100644 index 0000000..318f015 --- /dev/null +++ b/docs/DOMAIN_SETUP.md @@ -0,0 +1,396 @@ +# 🌐 Domain Yapılandırma Rehberi + +Oltalama Panel için domain yapılandırma seçenekleri ve kurulum rehberi. + +## 📋 İki Seçenek + +### Seçenek 1: Tek Domain (Önerilen) ⭐ + +**Yapı:** +``` +yourdomain.com/ → Frontend +yourdomain.com/api/ → Backend API +yourdomain.com/t/ → Tracking Links +``` + +**Avantajları:** +- ✅ CORS sorunu yok +- ✅ Tek SSL sertifikası +- ✅ Kolay kurulum +- ✅ Basit yönetim + +**Dezavantajları:** +- ⚠️ Reverse proxy gerekli (Nginx Proxy Manager) + +### Seçenek 2: İki Ayrı Domain + +**Yapı:** +``` +panel.yourdomain.com → Frontend +api.yourdomain.com → Backend API & Tracking +``` + +**Avantajları:** +- ✅ Servisler birbirinden izole +- ✅ Bağımsız ölçeklendirme +- ✅ Farklı sunucularda çalışabilir + +**Dezavantajları:** +- ⚠️ CORS yapılandırması gerekli +- ⚠️ İki SSL sertifikası +- ⚠️ Daha karmaşık kurulum + +## 🚀 Seçenek 1: Tek Domain Kurulumu + +### 1. DNS Ayarları + +``` +yourdomain.com A 123.456.789.10 +www.yourdomain.com CNAME yourdomain.com +``` + +### 2. Nginx Proxy Manager Kurulumu + +**Proxy Host Ekle:** + +``` +Domain: yourdomain.com, www.yourdomain.com +Scheme: http +Forward Hostname: localhost +Forward Port: 4173 +SSL: ✓ Force SSL, HTTP/2, HSTS +``` + +**Advanced Config:** + +```nginx +location /api { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; +} + +location /t/ { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; +} +``` + +### 3. Oltalama Panel Ayarları + +Panele giriş yapın → **Ayarlar** → **Genel Ayarlar** + +``` +☐ İki Ayrı Domain Kullan (kapalı bırakın) +Domain (Base URL): https://yourdomain.com +``` + +### 4. Test + +```bash +# Frontend +curl https://yourdomain.com + +# Backend API +curl https://yourdomain.com/api/health + +# Tracking +curl -I https://yourdomain.com/t/test-token +``` + +## 🔀 Seçenek 2: İki Domain Kurulumu + +### 1. DNS Ayarları + +``` +api.yourdomain.com A 123.456.789.10 +panel.yourdomain.com A 123.456.789.10 +``` + +### 2. Nginx Proxy Manager - Backend + +**Proxy Host Ekle (Backend):** + +``` +Domain: api.yourdomain.com +Scheme: http +Forward Hostname: localhost +Forward Port: 3000 +SSL: ✓ Force SSL, HTTP/2, HSTS +``` + +### 3. Nginx Proxy Manager - Frontend + +**Proxy Host Ekle (Frontend):** + +``` +Domain: panel.yourdomain.com +Scheme: http +Forward Hostname: localhost +Forward Port: 4173 +SSL: ✓ Force SSL, HTTP/2, HSTS +``` + +### 4. Oltalama Panel Ayarları + +Panele giriş yapın → **Ayarlar** → **Genel Ayarlar** + +``` +☑ İki Ayrı Domain Kullan (aktif et) +Backend Domain: https://api.yourdomain.com +Frontend Domain: https://panel.yourdomain.com +``` + +**Kaydet** butonuna tıklayın. CORS otomatik olarak yapılandırılacaktır. + +### 5. Frontend Ortam Değişkenleri + +`/opt/oltalama/frontend/.env`: + +```env +VITE_API_URL=https://api.yourdomain.com +``` + +Frontend'i yeniden build edin: + +```bash +cd /opt/oltalama/frontend +npm run build +pm2 restart oltalama-frontend +``` + +### 6. Test + +```bash +# Frontend +curl https://panel.yourdomain.com + +# Backend API +curl https://api.yourdomain.com/api/health + +# Tracking +curl -I https://api.yourdomain.com/t/test-token + +# CORS test +curl -I -X OPTIONS https://api.yourdomain.com/api/health \ + -H "Origin: https://panel.yourdomain.com" \ + -H "Access-Control-Request-Method: GET" +``` + +## 🔧 Port Ayarları + +### Varsayılan Portlar + +- **Backend**: `3000` +- **Frontend**: `4173` +- **Nginx Proxy Manager**: `80` (HTTP), `443` (HTTPS) + +### Farklı Portlar Kullanma + +Eğer backend veya frontend'i farklı portlarda çalıştırmak isterseniz: + +#### Backend Port Değiştirme + +**1. Backend .env:** +```env +PORT=8080 +``` + +**2. PM2 Ecosystem Config:** +```javascript +{ + name: 'oltalama-backend', + env: { + PORT: 8080, + }, +} +``` + +**3. Nginx Proxy Manager:** +``` +Forward Port: 8080 +``` + +**4. Restart:** +```bash +pm2 restart oltalama-backend +``` + +#### Frontend Port Değiştirme + +**1. Frontend package.json:** +```json +{ + "scripts": { + "preview": "vite preview --port 5000" + } +} +``` + +**2. PM2 Ecosystem Config:** +```javascript +{ + name: 'oltalama-frontend', + env: { + PORT: 5000, + }, +} +``` + +**3. Nginx Proxy Manager:** +``` +Forward Port: 5000 +``` + +**4. Restart:** +```bash +pm2 restart oltalama-frontend +``` + +## 🔒 SSL/TLS Sertifikaları + +### Let's Encrypt (Otomatik) + +Nginx Proxy Manager üzerinden otomatik: + +1. Proxy Host ayarlarına girin +2. **SSL** sekmesine gidin +3. **Request a new SSL Certificate** seçin +4. **Force SSL**, **HTTP/2**, **HSTS** aktif edin +5. Email girin ve **I Agree** işaretleyin +6. **Save** + +Sertifika otomatik olarak yenilenecektir. + +### Manuel SSL (Opsiyonel) + +```bash +# Certbot kurulumu +sudo apt install certbot + +# Sertifika oluşturma +sudo certbot certonly --standalone -d yourdomain.com + +# Sertifikalar +/etc/letsencrypt/live/yourdomain.com/fullchain.pem +/etc/letsencrypt/live/yourdomain.com/privkey.pem +``` + +## 🐛 Sorun Giderme + +### Problem: "Failed to load resource: net::ERR_BLOCKED_BY_CLIENT" + +**Sebep:** AdBlock/uBlock Origin tracking URL'lerini engelliyor + +**Çözüm:** +- Test için AdBlock'u devre dışı bırakın +- Veya tracking URL pattern'ini değiştirin + +### Problem: CORS hatası + +**Semptomlar:** +``` +Access to XMLHttpRequest at 'https://api.yourdomain.com/api/...' +from origin 'https://panel.yourdomain.com' has been blocked by CORS policy +``` + +**Çözüm:** +1. Panelden CORS ayarlarını kontrol edin +2. **İki Ayrı Domain Kullan** aktif mi? +3. Frontend ve Backend URL'leri doğru mu? +4. Backend'i restart edin: `pm2 restart oltalama-backend` + +### Problem: 502 Bad Gateway + +**Çözüm:** +```bash +# Backend çalışıyor mu? +pm2 status + +# Port dinleniyor mu? +sudo netstat -tulpn | grep 3000 + +# Firewall açık mı? +sudo ufw status +``` + +### Problem: Tracking linkleri çalışmıyor + +**Çözüm:** +1. Panelde Base URL doğru ayarlanmış mı? +2. `/t/` route Nginx'de tanımlı mı? +3. Backend loglarını kontrol edin: +```bash +pm2 logs oltalama-backend --lines 50 +``` + +## 📊 Karşılaştırma Tablosu + +| Özellik | Tek Domain | İki Domain | +|---------|------------|------------| +| **Kurulum Süresi** | 15 dakika | 30 dakika | +| **CORS** | Gerekli değil | Gerekli | +| **SSL Sertifikası** | 1 tane | 2 tane | +| **Reverse Proxy** | Gerekli | Opsiyonel | +| **DNS Kaydı** | 1 domain | 2 subdomain | +| **Güvenlik** | Yüksek | Yüksek | +| **Ölçeklenebilirlik** | Orta | Yüksek | +| **Bakım** | Kolay | Orta | +| **Maliyet** | Düşük | Düşük | +| **Önerilen** | ✅ **Evet** | Özel durumlar | + +## 🎯 Hangi Seçeneği Seçmeliyim? + +### Tek Domain Seçin Eğer: +- ✅ Basit kurulum istiyorsanız +- ✅ CORS ile uğraşmak istemiyorsanız +- ✅ Tek sunucuda çalışacaksanız +- ✅ Yeni başlıyorsanız + +### İki Domain Seçin Eğer: +- ✅ Frontend ve backend'i farklı sunucularda çalıştıracaksanız +- ✅ Servislerinizi izole etmek istiyorsanız +- ✅ Farklı takımlar frontend/backend'i yönetecekse +- ✅ Bağımsız ölçeklendirme gerekiyorsa + +## 📝 Özet: Hızlı Kurulum + +### Tek Domain (5 Adım) + +```bash +# 1. Sunucu başlatın +pm2 start ecosystem.config.js + +# 2. Nginx Proxy Manager'a domain ekleyin +# 3. SSL sertifikası alın (Let's Encrypt) +# 4. Panelde domain ayarlayın +# 5. Test edin +``` + +### İki Domain (8 Adım) + +```bash +# 1. Sunucu başlatın +pm2 start ecosystem.config.js + +# 2. Nginx Proxy Manager'a backend domain ekleyin +# 3. Nginx Proxy Manager'a frontend domain ekleyin +# 4. SSL sertifikaları alın (Let's Encrypt) +# 5. Frontend .env dosyasını güncelleyin +# 6. Frontend'i yeniden build edin +# 7. Panelde CORS ve domain ayarlarını yapın +# 8. Test edin +``` + +--- + +**Son Güncelleme:** 2025-11-10 +**Versiyon:** 1.0.0 + +**İpucu:** İlk kurulumda **Tek Domain** kullanmanızı öneririz. İhtiyaç duyduğunuzda daha sonra **İki Domain**'e geçebilirsiniz. + diff --git a/docs/NGINX_PROXY_MANAGER.md b/docs/NGINX_PROXY_MANAGER.md new file mode 100644 index 0000000..cc60a06 --- /dev/null +++ b/docs/NGINX_PROXY_MANAGER.md @@ -0,0 +1,438 @@ +# 🌐 Nginx Proxy Manager Kurulum Rehberi + +Oltalama Panel için Nginx Proxy Manager (NPM) ile reverse proxy kurulumu. + +## 📋 Neden Tek Domain? + +**Önerilen Yapı:** Tek domain, path-based routing + +### Avantajları: +- ✅ **CORS Sorunu Yok**: Frontend ve backend aynı origin'de +- ✅ **Tek SSL Sertifikası**: Sadece bir domain için sertifika +- ✅ **Basit Yönetim**: Tek entry point +- ✅ **Kolay Kurulum**: Daha az konfigürasyon + +### Alternatif: İki Subdomain + +Eğer iki ayrı subdomain kullanmak isterseniz: +- `panel.yourdomain.com` → Frontend +- `api.yourdomain.com` → Backend + +**Not:** Bu durumda CORS ayarları gerekir ve iki SSL sertifikası gerekir. + +## 🚀 Nginx Proxy Manager Kurulumu + +### 1. Docker ile NPM Kurulumu + +```bash +# Docker ve Docker Compose kurulumu (eğer yoksa) +sudo apt update +sudo apt install docker.io docker-compose -y + +# NPM dizini oluştur +mkdir -p ~/nginx-proxy-manager +cd ~/nginx-proxy-manager +``` + +**docker-compose.yml:** + +```yaml +version: '3' +services: + app: + image: 'jc21/nginx-proxy-manager:latest' + restart: unless-stopped + ports: + - '80:80' # HTTP + - '443:443' # HTTPS + - '81:81' # Admin Panel + volumes: + - ./data:/data + - ./letsencrypt:/etc/letsencrypt +``` + +```bash +# NPM başlat +docker-compose up -d + +# Logları izle +docker-compose logs -f +``` + +### 2. NPM Admin Paneline Giriş + +1. Tarayıcıdan `http://sunucu-ip:81` adresine gidin +2. İlk giriş bilgileri: + - Email: `admin@example.com` + - Şifre: `changeme` +3. Giriş yaptıktan sonra **mutlaka** email ve şifreyi değiştirin + +## 🔧 Tek Domain Konfigürasyonu (Önerilen) + +### Adım 1: Proxy Host Ekle + +NPM Admin Panel → **Hosts** → **Proxy Hosts** → **Add Proxy Host** + +#### Details Sekmesi: + +``` +Domain Names: yourdomain.com + www.yourdomain.com + +Scheme: http +Forward Hostname: localhost (veya Oltalama sunucusunun IP'si) +Forward Port: 4173 + +☑ Cache Assets +☑ Block Common Exploits +☑ Websockets Support +``` + +#### SSL Sekmesi: + +``` +SSL Certificate: Request a new SSL Certificate + +☑ Force SSL +☑ HTTP/2 Support +☑ HSTS Enabled +☑ HSTS Subdomains + +Email Address: youremail@example.com +☑ I Agree to the Let's Encrypt Terms of Service +``` + +#### Advanced Sekmesi: + +**Custom Nginx Configuration:** + +```nginx +# Backend API routing +location /api { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; +} + +# Tracking endpoint +location /t/ { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # No cache for tracking + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires "0"; +} + +# Health check endpoint +location /health { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Host $host; +} + +# Frontend static files +location / { + proxy_pass http://localhost:4173; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; +} +``` + +### Adım 2: Oltalama Panel Ayarları + +Panele giriş yapın → **Ayarlar** → **Genel Ayarlar** + +``` +Domain (Base URL): https://yourdomain.com +``` + +**Önemli:** +- Protokolü ekleyin: `https://` +- Sondaki `/` karakterini eklemeyin +- Subdomain kullanıyorsanız: `https://panel.yourdomain.com` + +## 🔀 İki Domain Konfigürasyonu (Alternatif) + +### Oltalama Panel Ayarları + +Panele giriş yapın → **Ayarlar** → **Genel Ayarlar** + +``` +☑ İki Ayrı Domain Kullan (CORS Aktif Et) +Backend Domain: https://api.yourdomain.com +Frontend Domain: https://panel.yourdomain.com +``` + +**Önemli:** +- CORS checkbox'ını işaretleyin +- Her iki domain'i de `https://` ile girin +- Sondaki `/` karakterini eklemeyin + +## 🔀 Nginx Proxy Manager - İki Domain Kurulumu + +Eğer backend ve frontend'i ayırmak isterseniz: + +### Backend Proxy Host + +``` +Domain Names: api.yourdomain.com +Scheme: http +Forward Hostname: localhost +Forward Port: 3000 + +SSL: ✓ Force SSL, HTTP/2, HSTS +``` + +### Frontend Proxy Host + +``` +Domain Names: panel.yourdomain.com +Scheme: http +Forward Hostname: localhost +Forward Port: 4173 + +SSL: ✓ Force SSL, HTTP/2, HSTS +``` + +**Advanced (Frontend):** + +```nginx +# Proxy backend API calls +location /api { + proxy_pass https://api.yourdomain.com; + proxy_ssl_server_name on; + proxy_set_header Host api.yourdomain.com; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; +} +``` + +### CORS Ayarları + +İki domain kullanıyorsanız CORS otomatik olarak ayarlanır. Sadece panelden ayarları yapın: + +**Panelden Ayarlama (Önerilen):** + +1. Giriş yapın → **Ayarlar** → **Genel Ayarlar** +2. **☑ İki Ayrı Domain Kullan** checkbox'ını işaretleyin +3. **Backend Domain**: `https://api.yourdomain.com` +4. **Frontend Domain**: `https://panel.yourdomain.com` +5. **Kaydet** butonuna tıklayın + +CORS ayarları otomatik olarak uygulanacaktır. + +**Manuel .env Ayarları (Opsiyonel):** + +Backend `.env` (varsayılan): +```env +FRONTEND_URL=http://localhost:5173 +``` + +Production'da panel ayarları bu değeri override edecektir. + +## ✅ Test ve Doğrulama + +### 1. DNS Kontrolü + +```bash +# Domain çözümleniyor mu? +nslookup yourdomain.com + +# Ping testi +ping yourdomain.com +``` + +### 2. SSL Sertifikası Kontrolü + +```bash +# SSL sertifikası geçerli mi? +curl -I https://yourdomain.com + +# Detaylı SSL testi +openssl s_client -connect yourdomain.com:443 -servername yourdomain.com +``` + +### 3. Endpoint Testleri + +```bash +# Frontend erişilebilir mi? +curl https://yourdomain.com + +# Backend API erişilebilir mi? +curl https://yourdomain.com/api/health + +# Tracking endpoint çalışıyor mu? +curl -I https://yourdomain.com/t/test-token +``` + +### 4. Tarayıcı Testleri + +1. `https://yourdomain.com` adresine gidin +2. Login sayfası açılmalı +3. Developer Console'da hata olmamalı +4. Network sekmesinde: + - Frontend dosyaları (JS, CSS) yüklenmeli + - API istekleri `/api/*` başarılı olmalı + - CORS hatası olmamalı + +## 🐛 Sorun Giderme + +### Problem: 502 Bad Gateway + +**Çözüm:** +```bash +# Backend çalışıyor mu? +pm2 status + +# Port dinleniyor mu? +sudo netstat -tulpn | grep -E ':(3000|4173)' + +# Firewall açık mı? +sudo ufw status +``` + +### Problem: SSL Sertifikası Alınamıyor + +**Çözüm:** +1. DNS kayıtlarının doğru olduğundan emin olun +2. 80 ve 443 portlarının açık olduğunu kontrol edin +3. Domain'in sunucuyu gösterdiğinden emin olun + +```bash +# Port 80 ve 443 dinleniyor mu? +sudo netstat -tulpn | grep -E ':(80|443)' + +# Firewall kuralları +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp +``` + +### Problem: CORS Hatası + +**İki subdomain kullanıyorsanız:** + +1. Backend `.env` dosyasında `CORS_ORIGIN` ayarlayın +2. Frontend'den API URL'i doğru mu kontrol edin +3. Backend'i yeniden başlatın + +```bash +cd /opt/oltalama/backend +pm2 restart oltalama-backend +``` + +### Problem: Tracking Linkleri Çalışmıyor + +**Çözüm:** + +1. Panelde doğru domain ayarlandığından emin olun +2. `/t/` route'unun proxy'de tanımlı olduğunu kontrol edin +3. Backend loglarını kontrol edin: + +```bash +pm2 logs oltalama-backend --lines 50 +``` + +## 📊 Performans Optimizasyonu + +### NPM Cache Ayarları + +**Advanced Nginx Config:** + +```nginx +# Static dosyalar için cache +location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + proxy_pass http://localhost:4173; + expires 1y; + add_header Cache-Control "public, immutable"; +} + +# API istekleri için cache yok +location /api { + proxy_pass http://localhost:3000; + add_header Cache-Control "no-cache, no-store, must-revalidate"; +} +``` + +### Rate Limiting + +```nginx +# Rate limit tanımı +limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; + +location /api { + limit_req zone=api_limit burst=20 nodelay; + limit_req_status 429; + + proxy_pass http://localhost:3000; + # ... diğer ayarlar +} +``` + +## 🔒 Güvenlik İpuçları + +1. **NPM Admin Paneli Güvenliği:** + - Port 81'i firewall'dan kapatın (sadece lokal erişim) + - Güçlü şifre kullanın + - 2FA aktif edin (eğer varsa) + +```bash +# NPM admin paneline sadece lokal erişim +sudo ufw deny 81/tcp +``` + +2. **SSL/TLS:** + - Her zaman Let's Encrypt kullanın + - Force SSL aktif edin + - HSTS etkinleştirin + +3. **Headers:** + - NPM otomatik güvenlik başlıkları ekler + - Ek başlıklar için Advanced Nginx Config kullanın + +## 📝 Özet Karşılaştırma + +| Özellik | Tek Domain | İki Subdomain | +|---------|------------|---------------| +| CORS | ✅ Yok | ⚠️ Gerekli | +| SSL | ✅ 1 Sertifika | ⚠️ 2 Sertifika | +| Kurulum | ✅ Kolay | ⚠️ Orta | +| Yönetim | ✅ Basit | ⚠️ Karmaşık | +| DNS | ✅ 1 Kayıt | ⚠️ 2 Kayıt | +| Önerilen | ✅ **Evet** | ⚠️ İhtiyaç varsa | + +## 🎯 Sonuç + +**Önerimiz:** Tek domain kullanın (`yourdomain.com`) + +- Frontend: `yourdomain.com/` +- Backend: `yourdomain.com/api/` +- Tracking: `yourdomain.com/t/` + +Bu yapı en kolay ve en sorunsuz çözümdür. + +--- + +**Son Güncelleme:** 2025-11-10 +**Versiyon:** 1.0.0 + diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx index ffb12f5..60e709e 100644 --- a/frontend/src/pages/Settings.jsx +++ b/frontend/src/pages/Settings.jsx @@ -11,14 +11,19 @@ import { Divider, } from '@mui/material'; import { Save, Send } from '@mui/icons-material'; +import { FormControlLabel, Checkbox } from '@mui/material'; import axios from 'axios'; const API_URL = import.meta.env.VITE_API_URL; function Settings() { const [settings, setSettings] = useState({ + base_url: '', + frontend_url: '', + cors_enabled: false, gmail_user: '', gmail_app_password: '', + gmail_from_name: '', telegram_bot_token: '', telegram_chat_id: '', }); @@ -36,11 +41,24 @@ function Settings() { withCredentials: true, }); const data = response.data.data || {}; + + // Convert array to object + const settingsObj = {}; + if (Array.isArray(data)) { + data.forEach(item => { + settingsObj[item.key] = item.value === '********' ? '' : item.value; + }); + } + setSettings({ - gmail_user: data.gmail_user || '', - gmail_app_password: data.gmail_app_password || '', - telegram_bot_token: data.telegram_bot_token || '', - telegram_chat_id: data.telegram_chat_id || '', + base_url: settingsObj.base_url || '', + frontend_url: settingsObj.frontend_url || '', + cors_enabled: settingsObj.cors_enabled === 'true', + gmail_user: settingsObj.gmail_user || '', + gmail_app_password: settingsObj.gmail_password || '', + gmail_from_name: settingsObj.gmail_from_name || '', + telegram_bot_token: settingsObj.telegram_bot_token || '', + telegram_chat_id: settingsObj.telegram_chat_id || '', }); } catch (error) { console.error('Failed to load settings:', error); @@ -52,9 +70,15 @@ function Settings() { const handleSave = async () => { try { await Promise.all([ + axios.put(`${API_URL}/api/settings/system`, { + base_url: settings.base_url, + frontend_url: settings.frontend_url, + cors_enabled: settings.cors_enabled, + }, { withCredentials: true }), axios.put(`${API_URL}/api/settings/gmail`, { gmail_user: settings.gmail_user, gmail_app_password: settings.gmail_app_password, + gmail_from_name: settings.gmail_from_name, }, { withCredentials: true }), axios.put(`${API_URL}/api/settings/telegram`, { telegram_bot_token: settings.telegram_bot_token, @@ -64,7 +88,7 @@ function Settings() { alert('Ayarlar kaydedildi!'); } catch (error) { console.error('Failed to save settings:', error); - alert('Ayarlar kaydedilemedi'); + alert('Ayarlar kaydedilemedi: ' + (error.response?.data?.error || error.message)); } }; @@ -124,10 +148,72 @@ function Settings() { + {/* System Settings */} + + + + 🌐 Genel Ayarlar + + + Domain ve genel sistem ayarları + + + + Tek Domain (Önerilen): Frontend ve backend aynı domainde, path ile ayrılır
+ İki Domain: Frontend ve backend farklı domainlerde (CORS gerekir) +
+ + + setSettings({ ...settings, cors_enabled: e.target.checked }) + } + /> + } + label="İki Ayrı Domain Kullan (CORS Aktif Et)" + /> + + + setSettings({ ...settings, base_url: e.target.value }) + } + helperText={ + settings.cors_enabled + ? "Backend API domain'i. Örnek: https://api.yourdomain.com" + : "Hem frontend hem backend için kullanılacak domain. Örnek: https://yourdomain.com" + } + /> + + {settings.cors_enabled && ( + + setSettings({ ...settings, frontend_url: e.target.value }) + } + helperText="Frontend panel domain'i. CORS için gerekli." + /> + )} +
+
+ + {/* Gmail Settings */} - Gmail Ayarları + 📧 Gmail Ayarları Gmail App Password kullanın (2FA aktif olmalı) @@ -152,6 +238,18 @@ function Settings() { onChange={(e) => setSettings({ ...settings, gmail_app_password: e.target.value }) } + helperText="Google Hesap → Güvenlik → 2FA → Uygulama Şifreleri" + /> + + setSettings({ ...settings, gmail_from_name: e.target.value }) + } + placeholder="Güvenlik Ekibi" + helperText="Mail gönderirken görünecek varsayılan isim" /> {alerts.mail && ( diff --git a/frontend/src/pages/TokenDetail.jsx b/frontend/src/pages/TokenDetail.jsx index 63e28c1..010a6e9 100644 --- a/frontend/src/pages/TokenDetail.jsx +++ b/frontend/src/pages/TokenDetail.jsx @@ -247,6 +247,14 @@ function TokenDetail() { {token.company?.name} + + + Gönderen Adı + + + {token.from_name || 'Varsayılan'} + +
diff --git a/frontend/src/pages/Tokens.jsx b/frontend/src/pages/Tokens.jsx index b07ceb2..f6c6acf 100644 --- a/frontend/src/pages/Tokens.jsx +++ b/frontend/src/pages/Tokens.jsx @@ -37,6 +37,7 @@ function Tokens() { company_id: '', target_email: '', employee_name: '', + from_name: '', template_type: 'bank', }); @@ -65,7 +66,7 @@ function Tokens() { try { await tokenService.createAndSend(formData); setOpenDialog(false); - setFormData({ company_id: '', target_email: '', employee_name: '', template_type: 'bank' }); + setFormData({ company_id: '', target_email: '', employee_name: '', from_name: '', template_type: 'bank' }); loadData(); alert('Token oluşturuldu ve mail gönderildi!'); } catch (error) { @@ -170,6 +171,15 @@ function Tokens() { value={formData.employee_name} onChange={(e) => setFormData({ ...formData, employee_name: e.target.value })} /> + setFormData({ ...formData, from_name: e.target.value })} + placeholder="Ör: X Şirketi İnsan Kaynakları, MGT Yönetici" + helperText="Belirtilmezse varsayılan gönderen adı kullanılır" + /> new Promise((resolve) => rl.question(query, resolve)); + +const validatePassword = (password) => { + if (password.length < 8) { + return 'Şifre en az 8 karakter olmalıdır!'; + } + if (!/[a-zA-Z]/.test(password)) { + return 'Şifre en az bir harf içermelidir!'; + } + if (!/[0-9]/.test(password)) { + return 'Şifre en az bir rakam içermelidir!'; + } + return null; +}; + +(async () => { + try { + console.log('\n╔═══════════════════════════════════════════════════════════════╗'); + console.log('║ Oltalama Panel - Admin Şifre Değiştir ║'); + console.log('╚═══════════════════════════════════════════════════════════════╝\n'); + + // Connect to database + await sequelize.authenticate(); + console.log('✓ Database bağlantısı başarılı\n'); + + // Get username + const username = await question('Admin kullanıcı adı: '); + + // Check if user exists + const user = await AdminUser.findOne({ where: { username } }); + if (!user) { + console.log('✗ Kullanıcı bulunamadı!'); + rl.close(); + process.exit(1); + } + + // Get new password + let password; + while (true) { + // Disable echo for password input + const originalWrite = rl._writeToOutput; + rl._writeToOutput = function (stringToWrite) { + if (stringToWrite.charCodeAt(0) === 13) { + rl.output.write('\n'); + } else { + rl.output.write('*'); + } + }; + + password = await question('Yeni şifre (en az 8 karakter, harf ve rakam): '); + console.log(); // New line after hidden input + + const validationError = validatePassword(password); + if (validationError) { + console.log(`✗ ${validationError}\n`); + continue; + } + + const passwordConfirm = await question('Şifreyi tekrar girin: '); + console.log(); // New line after hidden input + + // Restore echo + rl._writeToOutput = originalWrite; + + if (password !== passwordConfirm) { + console.log('✗ Şifreler eşleşmiyor!\n'); + continue; + } + + break; + } + + // Update password + console.log('\n⏳ Şifre güncelleniyor...'); + + const hashedPassword = await bcrypt.hash(password, 10); + + await user.update({ + password_hash: hashedPassword, + }); + + console.log('\n✓ Şifre başarıyla değiştirildi!'); + console.log(`\nKullanıcı: ${username}`); + console.log('Yeni şifre: ********** (güvenli bir şekilde saklandı)'); + console.log('\n✓ Artık yeni şifrenizle giriş yapabilirsiniz.\n'); + + rl.close(); + process.exit(0); + } catch (error) { + console.error('\n✗ Hata:', error.message); + rl.close(); + process.exit(1); + } +})(); + diff --git a/scripts/create-admin.js b/scripts/create-admin.js new file mode 100755 index 0000000..7f58655 --- /dev/null +++ b/scripts/create-admin.js @@ -0,0 +1,142 @@ +#!/usr/bin/env node + +/** + * Admin User Creation Script + * Usage: node scripts/create-admin.js + */ + +const bcrypt = require('bcrypt'); +const readline = require('readline'); +const path = require('path'); + +// Set correct path for database config +process.chdir(path.join(__dirname, '../backend')); + +const { sequelize } = require('../backend/src/config/database'); +const AdminUser = require('../backend/src/models/AdminUser'); + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, +}); + +const question = (query) => new Promise((resolve) => rl.question(query, resolve)); +const questionHidden = (query) => { + return new Promise((resolve) => { + rl.question(query, (answer) => { + resolve(answer); + }); + rl._writeToOutput = () => {}; // Hide input + }); +}; + +const validatePassword = (password) => { + if (password.length < 8) { + return 'Şifre en az 8 karakter olmalıdır!'; + } + if (!/[a-zA-Z]/.test(password)) { + return 'Şifre en az bir harf içermelidir!'; + } + if (!/[0-9]/.test(password)) { + return 'Şifre en az bir rakam içermelidir!'; + } + return null; +}; + +(async () => { + try { + console.log('\n╔═══════════════════════════════════════════════════════════════╗'); + console.log('║ Oltalama Panel - Admin Kullanıcı Oluştur ║'); + console.log('╚═══════════════════════════════════════════════════════════════╝\n'); + + // Connect to database + await sequelize.authenticate(); + console.log('✓ Database bağlantısı başarılı\n'); + + // Get username + let username; + while (true) { + username = await question('Admin kullanıcı adı (en az 3 karakter): '); + if (username.length >= 3) { + // Check if username exists + const existing = await AdminUser.findOne({ where: { username } }); + if (existing) { + console.log('✗ Bu kullanıcı adı zaten kullanılıyor!\n'); + continue; + } + break; + } else { + console.log('✗ Kullanıcı adı en az 3 karakter olmalıdır!\n'); + } + } + + // Get password + let password; + while (true) { + // Disable echo for password input + const originalWrite = rl._writeToOutput; + rl._writeToOutput = function (stringToWrite) { + if (stringToWrite.charCodeAt(0) === 13) { + rl.output.write('\n'); + } else { + rl.output.write('*'); + } + }; + + password = await question('Admin şifresi (en az 8 karakter, harf ve rakam): '); + console.log(); // New line after hidden input + + const validationError = validatePassword(password); + if (validationError) { + console.log(`✗ ${validationError}\n`); + continue; + } + + const passwordConfirm = await question('Şifreyi tekrar girin: '); + console.log(); // New line after hidden input + + // Restore echo + rl._writeToOutput = originalWrite; + + if (password !== passwordConfirm) { + console.log('✗ Şifreler eşleşmiyor!\n'); + continue; + } + + break; + } + + // Get optional details + const fullName = await question('Tam ad (opsiyonel, ENTER ile geç): '); + const email = await question('E-posta (opsiyonel, ENTER ile geç): '); + + // Create admin user + console.log('\n⏳ Admin kullanıcısı oluşturuluyor...'); + + const hashedPassword = await bcrypt.hash(password, 10); + + await AdminUser.create({ + username, + password_hash: hashedPassword, + email: email || null, + full_name: fullName || 'Administrator', + }); + + console.log('\n✓ Admin kullanıcısı başarıyla oluşturuldu!'); + console.log(`\nKullanıcı adı: ${username}`); + console.log('Şifre: ********** (güvenli bir şekilde saklandı)'); + + if (fullName) console.log(`Tam ad: ${fullName}`); + if (email) console.log(`E-posta: ${email}`); + + console.log('\n✓ Artık panele giriş yapabilirsiniz.\n'); + + rl.close(); + process.exit(0); + } catch (error) { + console.error('\n✗ Hata:', error.message); + rl.close(); + process.exit(1); + } +})(); + diff --git a/systemd/oltalama-backend.service b/systemd/oltalama-backend.service new file mode 100644 index 0000000..0142c97 --- /dev/null +++ b/systemd/oltalama-backend.service @@ -0,0 +1,29 @@ +[Unit] +Description=Oltalama Backend Service +Documentation=https://github.com/yourusername/oltalama +After=network.target + +[Service] +Type=simple +User=www-data +Group=www-data +WorkingDirectory=/opt/oltalama/backend +Environment=NODE_ENV=production +Environment=PORT=3000 +ExecStart=/usr/bin/node /opt/oltalama/backend/src/app.js +Restart=always +RestartSec=10 +StandardOutput=append:/var/log/oltalama/backend.log +StandardError=append:/var/log/oltalama/backend-error.log + +# Security settings +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ReadWritePaths=/opt/oltalama/backend/database +ReadWritePaths=/var/log/oltalama + +[Install] +WantedBy=multi-user.target + diff --git a/systemd/oltalama-frontend.service b/systemd/oltalama-frontend.service new file mode 100644 index 0000000..013cdb1 --- /dev/null +++ b/systemd/oltalama-frontend.service @@ -0,0 +1,27 @@ +[Unit] +Description=Oltalama Frontend Service +Documentation=https://github.com/yourusername/oltalama +After=network.target oltalama-backend.service + +[Service] +Type=simple +User=www-data +Group=www-data +WorkingDirectory=/opt/oltalama/frontend +Environment=NODE_ENV=production +Environment=PORT=4173 +ExecStart=/usr/bin/npm run preview +Restart=always +RestartSec=10 +StandardOutput=append:/var/log/oltalama/frontend.log +StandardError=append:/var/log/oltalama/frontend-error.log + +# Security settings +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true + +[Install] +WantedBy=multi-user.target +