mengubah sistem menjadi lebih terfokus ke poverty
This commit is contained in:
+179
-20
@@ -49,28 +49,178 @@ function sendError(string $message, int $code = 400): void {
|
||||
}
|
||||
|
||||
function requireWriteAuth(string $method): void {
|
||||
if (!in_array($method, ['POST', 'PUT', 'DELETE'], true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$expected = (string)(getenv('API_WRITE_TOKEN') ?: '');
|
||||
if ($expected === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$provided = (string)($_SERVER['HTTP_X_API_TOKEN'] ?? '');
|
||||
if ($provided === '') {
|
||||
$auth = (string)($_SERVER['HTTP_AUTHORIZATION'] ?? '');
|
||||
if (preg_match('/Bearer\s+(.+)/i', $auth, $m)) {
|
||||
$provided = trim($m[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($provided === '' || !hash_equals($expected, $provided)) {
|
||||
sendError('Unauthorized', 401);
|
||||
}
|
||||
// Deprecated: Menggunakan checkRBAC() secara global untuk semua request.
|
||||
}
|
||||
|
||||
function checkRBAC(): void {
|
||||
if (PHP_SAPI === 'cli') {
|
||||
return;
|
||||
}
|
||||
|
||||
$script = basename($_SERVER['SCRIPT_FILENAME']);
|
||||
if (in_array($script, ['login.php', 'logout.php', 'me.php'], true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
ini_set('session.cookie_httponly', 1);
|
||||
ini_set('session.use_only_cookies', 1);
|
||||
session_start();
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
sendError('Unauthorized - Silakan login terlebih dahulu', 401);
|
||||
}
|
||||
|
||||
$role = $_SESSION['role'] ?? 'guest';
|
||||
$method = getMethod();
|
||||
|
||||
if ($method === 'GET') {
|
||||
// Semua role diizinkan membaca data (GET)
|
||||
return;
|
||||
}
|
||||
|
||||
// Operasi Tulis (POST, PUT, DELETE)
|
||||
if ($role === 'admin') {
|
||||
// Admin diizinkan melakukan semua aksi tulis
|
||||
return;
|
||||
}
|
||||
|
||||
if ($role === 'petugas_lapangan') {
|
||||
$user_ri_id = isset($_SESSION['rumah_ibadah_id']) ? (int)$_SESSION['rumah_ibadah_id'] : 0;
|
||||
if ($user_ri_id <= 0) {
|
||||
sendError('Forbidden - Akun petugas lapangan tidak dikaitkan dengan rumah ibadah manapun', 403);
|
||||
}
|
||||
|
||||
if ($method === 'DELETE') {
|
||||
sendError('Forbidden - Petugas Lapangan tidak diizinkan menghapus data', 403);
|
||||
}
|
||||
|
||||
if ($script === 'rumah_ibadah.php') {
|
||||
if ($method === 'PUT') {
|
||||
$req_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
if ($req_id !== $user_ri_id) {
|
||||
sendError('Forbidden - Petugas Lapangan hanya dapat mengedit rumah ibadah mereka sendiri', 403);
|
||||
}
|
||||
return; // Allowed
|
||||
}
|
||||
sendError('Forbidden - Aksi tidak diizinkan untuk petugas lapangan pada rumah ibadah', 403);
|
||||
}
|
||||
|
||||
if ($script === 'penduduk_miskin.php') {
|
||||
if ($method === 'POST') {
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'recalc_all') {
|
||||
sendError('Forbidden - Petugas Lapangan tidak dapat memperbarui proximity masal', 403);
|
||||
}
|
||||
|
||||
$body = getBody();
|
||||
$lat = isset($body['latitude']) ? (float)$body['latitude'] : null;
|
||||
$lng = isset($body['longitude']) ? (float)$body['longitude'] : null;
|
||||
if ($lat === null || $lng === null) {
|
||||
sendError('Field latitude dan longitude wajib diisi');
|
||||
}
|
||||
|
||||
$db = getDB();
|
||||
$stmt = $db->prepare("SELECT latitude, longitude, radius_meter FROM rumah_ibadah WHERE id = ?");
|
||||
$stmt->bind_param('i', $user_ri_id);
|
||||
$stmt->execute();
|
||||
$ri = $stmt->get_result()->fetch_assoc();
|
||||
if (!$ri) {
|
||||
sendError('Rumah ibadah petugas tidak ditemukan', 404);
|
||||
}
|
||||
|
||||
$dist = haversine_distance((float)$ri['latitude'], (float)$ri['longitude'], $lat, $lng);
|
||||
if ($dist > (int)$ri['radius_meter']) {
|
||||
sendError('Forbidden - Titik koordinat penduduk miskin di luar radius jangkauan rumah ibadah Anda', 403);
|
||||
}
|
||||
return; // Allowed
|
||||
}
|
||||
|
||||
if ($method === 'PUT') {
|
||||
$req_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
if ($req_id <= 0) {
|
||||
sendError('ID penduduk miskin wajib disertakan');
|
||||
}
|
||||
|
||||
$db = getDB();
|
||||
$stmtCheck = $db->prepare("SELECT rumah_ibadah_id FROM penduduk_miskin WHERE id = ?");
|
||||
$stmtCheck->bind_param('i', $req_id);
|
||||
$stmtCheck->execute();
|
||||
$pm = $stmtCheck->get_result()->fetch_assoc();
|
||||
if (!$pm) {
|
||||
sendError('Penduduk miskin tidak ditemukan', 404);
|
||||
}
|
||||
|
||||
if ($pm['rumah_ibadah_id'] === null || (int)$pm['rumah_ibadah_id'] !== $user_ri_id) {
|
||||
sendError('Forbidden - Penduduk miskin ini tidak berada di wilayah rumah ibadah Anda', 403);
|
||||
}
|
||||
|
||||
$body = getBody();
|
||||
$lat = isset($body['latitude']) ? (float)$body['latitude'] : null;
|
||||
$lng = isset($body['longitude']) ? (float)$body['longitude'] : null;
|
||||
if ($lat === null || $lng === null) {
|
||||
sendError('Field latitude dan longitude wajib diisi');
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("SELECT latitude, longitude, radius_meter FROM rumah_ibadah WHERE id = ?");
|
||||
$stmt->bind_param('i', $user_ri_id);
|
||||
$stmt->execute();
|
||||
$ri = $stmt->get_result()->fetch_assoc();
|
||||
if (!$ri) {
|
||||
sendError('Rumah ibadah petugas tidak ditemukan', 404);
|
||||
}
|
||||
|
||||
$dist = haversine_distance((float)$ri['latitude'], (float)$ri['longitude'], $lat, $lng);
|
||||
if ($dist > (int)$ri['radius_meter']) {
|
||||
sendError('Forbidden - Titik koordinat baru di luar radius jangkauan rumah ibadah Anda', 403);
|
||||
}
|
||||
return; // Allowed
|
||||
}
|
||||
|
||||
sendError('Forbidden - Aksi tidak diizinkan untuk petugas lapangan pada penduduk miskin', 403);
|
||||
}
|
||||
|
||||
if ($script === 'log_bantuan.php') {
|
||||
if ($method === 'POST') {
|
||||
$body = getBody();
|
||||
$req_pm_id = isset($body['penduduk_miskin_id']) ? (int)$body['penduduk_miskin_id'] : 0;
|
||||
$req_ri_id = isset($body['rumah_ibadah_id']) ? (int)$body['rumah_ibadah_id'] : 0;
|
||||
|
||||
if ($req_ri_id !== $user_ri_id) {
|
||||
sendError('Forbidden - Anda hanya dapat mencatat log bantuan dari rumah ibadah Anda sendiri', 403);
|
||||
}
|
||||
|
||||
$db = getDB();
|
||||
$stmtPm = $db->prepare("SELECT rumah_ibadah_id, status_proximity FROM penduduk_miskin WHERE id = ?");
|
||||
$stmtPm->bind_param('i', $req_pm_id);
|
||||
$stmtPm->execute();
|
||||
$pm = $stmtPm->get_result()->fetch_assoc();
|
||||
if (!$pm) {
|
||||
sendError('Penduduk miskin tidak ditemukan', 404);
|
||||
}
|
||||
|
||||
if ($pm['rumah_ibadah_id'] === null || (int)$pm['rumah_ibadah_id'] !== $user_ri_id || $pm['status_proximity'] !== 'dalam_radius') {
|
||||
sendError('Forbidden - Penduduk miskin tidak berada di dalam radius rumah ibadah Anda', 403);
|
||||
}
|
||||
return; // Allowed
|
||||
}
|
||||
sendError('Forbidden - Aksi tidak diizinkan untuk petugas lapangan pada log bantuan', 403);
|
||||
}
|
||||
|
||||
sendError('Forbidden', 403);
|
||||
}
|
||||
|
||||
if ($role === 'guest') {
|
||||
sendError('Forbidden - Guest hanya memiliki akses lihat (read-only)', 403);
|
||||
}
|
||||
|
||||
sendError('Forbidden', 403);
|
||||
}
|
||||
|
||||
// Jalankan pemeriksaan CORS dan RBAC secara global saat file di-load
|
||||
setCORSHeaders();
|
||||
checkRBAC();
|
||||
|
||||
function executeOrFail(mysqli_stmt $stmt, string $defaultMessage = 'Operasi database gagal'): void {
|
||||
if ($stmt->execute()) {
|
||||
return;
|
||||
@@ -97,4 +247,13 @@ function getBody(): array {
|
||||
|
||||
function getMethod(): string {
|
||||
return strtoupper($_SERVER['REQUEST_METHOD']);
|
||||
}
|
||||
|
||||
function haversine_distance(float $lat1, float $lng1, float $lat2, float $lng2): float {
|
||||
$R = 6371000; // radius bumi dalam meter
|
||||
$dLat = deg2rad($lat2 - $lat1);
|
||||
$dLng = deg2rad($lng2 - $lng1);
|
||||
$a = sin($dLat/2)**2
|
||||
+ cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLng/2)**2;
|
||||
return $R * 2 * atan2(sqrt($a), sqrt(1-$a));
|
||||
}
|
||||
Reference in New Issue
Block a user