mengubah sistem menjadi lebih terfokus ke poverty

This commit is contained in:
Abimanyu Ridho
2026-06-11 01:50:37 +07:00
parent 739e360018
commit 468541b1c8
46 changed files with 5753 additions and 2805 deletions
+179 -20
View File
@@ -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));
}