# Güvenlik Düzeltme Planı — Markamama Kariyer

## Kapsam

Local ortamı etkilemeyen, kod seviyesindeki tüm güvenlik açıklarını kapatmak.
`.env` değişkenleri (APP_ENV, DB_PASSWORD, SESSION_SECURE_COOKIE vb.) production'a özel olduğundan dokunulmaz — bunlar KURULUM.md'de zaten belgelenmiş.

---

## [Overview]

Projedeki kod seviyesi güvenlik açıklarını kapatmak ve production öncesi kurulum rehberini güncellemek.

Bu plan 8 ayrı güvenlik düzeltmesini kapsar:

1. **InterviewController::getInterviewsByDate()** — `date` parametresi `date_format:Y-m-d` ile validate edilmeli; geçersiz format DB hatasına yol açabilir.
2. **JobPostingController::store() / update()** — `getClientOriginalName()` ile alınan dosya adları `Content-Disposition` header'ında kullanılıyor; header injection riski var. Sanitize edilmeli.
3. **SiteSettingController::googleSave()** — `ALLOWED_SETTING_KEYS` whitelist'ini atlıyor; izin verilmeyen key'ler kaydedilebilir. Whitelist kontrolü eklenmeli.
4. **SiteSettingController::index()** — KVKK `$allActiveApplications` için `->get()` kullanılıyor; büyük veri setinde bellek taşması riski. `->limit(500)->get()` ile sınırlanmalı.
5. **JobPosting modeli** — `->logAll()` ile `description`, `requirements` gibi büyük metin alanları activity_log'a yazılıyor; tablo şişer. `->logOnly()` ile sadece önemli alanlar loglanmalı.
6. **AdminUserSeeder** — Admin e-postası `admin@markamama.com` hardcoded; saldırganlar bu adresi bilerek brute-force deneyebilir. `env('ADMIN_EMAIL', 'admin@markamama.com')` ile okunmalı.
7. **FullCalendar CDN** — `calendar.blade.php` içindeki FullCalendar CSS ve JS yüklemeleri SRI (Subresource Integrity) hash'i olmadan yükleniyor; CDN ele geçirilirse zararlı kod yüklenebilir. `integrity` ve `crossorigin` attribute'ları eklenmeli.
8. **KURULUM.md** — Production checklist'e `ADMIN_EMAIL` env değişkeni ve SRI hash notu eklenmeli.

---

## [Files]

Değiştirilecek dosyalar:

- `app/Http/Controllers/Admin/InterviewController.php` — `getInterviewsByDate()` tarih validate
- `app/Http/Controllers/Admin/JobPostingController.php` — `store()` ve `update()` dosya adı sanitize + `sanitizeFilename()` private metodu
- `app/Http/Controllers/Admin/SiteSettingController.php` — `googleSave()` whitelist + `index()` KVKK limit
- `app/Models/JobPosting.php` — `logAll()` → `logOnly()`
- `database/seeders/AdminUserSeeder.php` — e-posta env'den okunacak
- `resources/views/admin/gorusmeler/calendar.blade.php` — FullCalendar SRI hash ekleme
- `KURULUM.md` — production checklist güncelleme

---

## [Functions]

### Değiştirilecek fonksiyonlar:

**`InterviewController::getInterviewsByDate()`**
- Dosya: `app/Http/Controllers/Admin/InterviewController.php`
- Satır 92-119
- Mevcut: `$date = $request->input('date');` — sadece boş kontrol var
- Yeni: `$request->validate(['date' => 'required|date_format:Y-m-d']);` eklenecek
- Geçersiz format gelirse 422 dönecek

**`JobPostingController::store()`**
- Dosya: `app/Http/Controllers/Admin/JobPostingController.php`
- Satır 85-97
- Mevcut: `$file->getClientOriginalName()` doğrudan kullanılıyor
- Yeni: `$this->sanitizeFilename($file->getClientOriginalName())` ile sanitize edilecek
- Hem `custom_application_form_name` hem `conditions_pdf_name` için

**`JobPostingController::update()`**
- Dosya: `app/Http/Controllers/Admin/JobPostingController.php`
- Satır 177-211
- Aynı sanitize işlemi `update()` içindeki dosya yükleme bloklarına da uygulanacak

**`JobPostingController` — yeni private metod: `sanitizeFilename()`**
- `preg_replace('/[^\w\-.]/', '_', basename($filename))` ile güvenli dosya adı üretir
- Path traversal karakterlerini (`../`, `/`, `\`) temizler
- Uzantıyı korur

**`SiteSettingController::googleSave()`**
- Dosya: `app/Http/Controllers/Admin/SiteSettingController.php`
- Satır 567-585
- Mevcut: `$keys` dizisi hardcoded ama whitelist kontrolü yok
- Yeni: `protected const ALLOWED_GOOGLE_KEYS` sabit dizisi tanımlanacak, sadece bu key'ler kaydedilecek

**`SiteSettingController::index()`**
- Dosya: `app/Http/Controllers/Admin/SiteSettingController.php`
- Satır 72-90
- Mevcut: `$allActiveApplications = JobApplication::...->get()`
- Yeni: `->limit(500)->get()` eklenecek

**`JobPosting::getActivitylogOptions()`**
- Dosya: `app/Models/JobPosting.php`
- Satır 50-56
- Mevcut: `->logAll()`
- Yeni: `->logOnly(['title', 'slug', 'status', 'published_at', 'closes_at', 'department', 'employment_type', 'location', 'created_by', 'is_featured', 'sort_order'])`

**`AdminUserSeeder::run()`**
- Dosya: `database/seeders/AdminUserSeeder.php`
- Satır 69-76
- Mevcut: `'email' => 'admin@markamama.com'` hardcoded
- Yeni: `'email' => env('ADMIN_EMAIL', 'admin@markamama.com')`

---

## [Classes]

**`JobPostingController`** — `sanitizeFilename(string $filename): string` private metodu eklenir.

**`SiteSettingController`** — `ALLOWED_GOOGLE_KEYS` protected const eklenir:
```php
protected const ALLOWED_GOOGLE_KEYS = [
    'google_calendar_enabled',
    'google_calendar_client_id',
    'google_calendar_client_secret',
    'google_calendar_id',
];
```

---

## [Dependencies]

Yeni bağımlılık gerekmez.

SRI hash'leri için kullanılan CDN versiyonları:
- FullCalendar v6.1.11 CSS: `https://cdn.jsdelivr.net/npm/fullcalendar@6.1.11/index.global.min.css`
- FullCalendar v6.1.11 JS: `https://cdn.jsdelivr.net/npm/fullcalendar@6.1.11/index.global.min.js`

SRI hash'leri `openssl dgst -sha384 -binary <file> | openssl base64 -A` ile hesaplanacak veya https://www.srihash.org/ kullanılacak.

Not: html2canvas (`ilanlar/show.blade.php`) zaten `integrity` attribute'u ile yükleniyor — bu dosyaya dokunulmayacak.

---

## [Testing]

Manuel test adımları:
1. `getInterviewsByDate?date=invalid` — 422 dönmeli
2. `getInterviewsByDate?date=2026-07-20` — normal JSON dönmeli
3. Özel karakterli dosya adı (`../../etc/passwd.pdf`) yükle — sanitize edilmeli
4. `googleSave` — izin verilmeyen key gönder, kaydedilmemeli
5. JobPosting güncelle — activity_log'da `description` alanı görünmemeli
6. Seeder `ADMIN_EMAIL=test@test.com` ile çalıştır — doğru e-posta kullanılmalı

---

## [Implementation Order]

Bağımlılık sırasına göre uygulama:

1. `InterviewController::getInterviewsByDate()` — tarih doğrulama (bağımsız, kolay)
2. `JobPostingController` — `sanitizeFilename()` metodu + store/update düzeltmesi
3. `SiteSettingController::googleSave()` — whitelist ekleme
4. `SiteSettingController::index()` — KVKK listesi limit
5. `JobPosting` modeli — `logOnly()` geçişi
6. `AdminUserSeeder` — env'den e-posta okuma
7. `calendar.blade.php` — FullCalendar SRI hash ekleme
8. `KURULUM.md` — production checklist güncelleme