Penyimpanan Formulir Aman & Pemeriksaan Gambar Asli
Memastikan pesan kesalahan saat mengisi formulir muncul tepat di bawah kolom input, serta memeriksa file gambar yang diunggah benar-benar foto asli bukan virus.
Memastikan pesan kesalahan saat mengisi formulir muncul tepat di bawah kolom input, serta memeriksa file gambar yang diunggah benar-benar foto asli bukan virus.
Tantangan & Kebutuhan Pengguna
Di Next.js App Router, Server Action membuat pemanggilan fungsi server terasa seperti memanggil fungsi lokal biasa. Kemudahan ini sering menjebak developer: lupa memeriksa izin akses di baris pertama, melempar error database mentah yang membocorkan struktur tabel ke browser, atau tidak sengaja menangkap sinyal internal `redirect()` milik Next.js di dalam blok `try/catch`. Selain itu, pada fitur unggah foto profil, mengandalkan pemeriksaan `file.type` atau ekstensi nama file saja sangat mudah dikelabui oleh penyerang yang mengganti ekstensi skrip berbahaya menjadi `.jpg`.
Jangan pernah memercayai klaim tipe konten dari browser maupun menangkap seluruh exception secara membabi buta di dalam Server Action.
Solusi & Cara Kerja
Seluruh Server Action di proyek ini dibungkus dengan utilitas `handleAction` (`common/utils/handle-action.ts`). Di dalamnya, setiap error pertama-tama dilewatkan ke `unstable_rethrow(e)` dari `next/navigation` agar alur `redirect()` atau `notFound()` internal Next.js tidak tertelan. Error validasi Zod (`ValidationError`) dan error bisnis (`AppError`) dikonversi menjadi kontrak seragam `{ ok: false, message, fieldErrors }` yang langsung memetakan pesan kesalahan ke field form terkait di UI, sementara error tak terduga disamarkan menjadi pesan generik yang aman. Untuk unggahan berkas, fungsi `saveAvatarFile` membaca 12 byte pertama dari `ArrayBuffer` untuk memverifikasi signature biner (magic bytes) JPEG (`FF D8 FF`), PNG (`89 50 4E 47`), dan WebP (`RIFF....WEBP`) sebelum menulis berkas dengan nama UUID acak.
Berikut adalah implementasi pembungkus `handleAction` di `common/utils/handle-action.ts` dan pemeriksaan magic bytes di `modules/dashboard/user/user.service.ts`:
Detail & Hal yang Diperhatikan
- Penanganan `unstable_rethrow`: Tanpa memanggil `unstable_rethrow(e)`, pemanggilan `redirect('/login')` di dalam action akan tertangkap sebagai error biasa dan gagal mengarahkan pengguna.
- Pencegahan Path Traversal pada Hapus Foto: Fungsi `deleteAvatarFile` menggunakan `path.basename(photoUrl)` sebelum menggabungkannya dengan `AVATAR_DIR`, menutup celah manipulasi path `../../`.
- Fail-Safe Audit Trail: Fungsi `recordAudit` di `common/lib/audit.ts` membungkus penulisan log di dalam `try/catch` terpisah dan memotong panjang string sesuai batas kolom (`slice`), sehingga kegagalan tulis log tidak pernah membatalkan transaksi bisnis utama yang sudah sukses.