Lewati ke konten utama

BAB 49. GPS VALIDATION FLOW

Tujuan

Mencegah check-in palsu (fake check-in) dengan memverifikasi bahwa peserta benar-benar berada di lokasi pertemuan yang disepakati menggunakan koordinat GPS perangkat.


Data GPS yang Dikumpulkan

DataSumberKeterangan
latitudeGPS DeviceKoordinat lintang
longitudeGPS DeviceKoordinat bujur
accuracyGPS DeviceAkurasi dalam meter (harus < 30m)
timestampSystemWaktu pengambilan koordinat

Radius Persetujuan per Lokasi

Jenis LokasiRadius Maksimum
Perpustakaan50 meter
Laboratorium30 meter
Ruang Kelas20 meter
Aula / Ruang Besar80 meter
Default (umum)100 meter

Alur Validasi GPS

flowchart TD
A["📍 Ambil Koordinat GPS"] --> B{{"Akurasi GPS\n< 30 meter?"}}
B -->|Tidak| C["⚠️ Minta ulang GPS\n(sinyal lemah)"]
C --> A
B -->|Ya| D["📡 Kirim ke API\n(lat, lng, accuracy)"]
D --> E["⚙️ Hitung jarak\nHaversine Formula"]
E --> F{{"Jarak <= Radius\nyang diizinkan?"}}
F -->|Tidak| G["❌ Reject:\nDiluar Radius"]
F -->|Ya| H{{"Deteksi\nMock Location?"}}
H -->|Ya| I["❌ Reject:\nFake GPS Detected"]
H -->|Tidak| J["✅ GPS Valid!\nLanjut Check-In"]

style G fill:#dc2626,color:#fff
style I fill:#dc2626,color:#fff
style J fill:#059669,color:#fff

Rumus Jarak — Haversine Formula

Jarak antara dua titik koordinat dihitung menggunakan Haversine Formula:

d = 2R × arcsin( sqrt(
sin²((lat2 - lat1) / 2) +
cos(lat1) × cos(lat2) × sin²((lng2 - lng1) / 2)
))

Di mana:

  • R = radius bumi = 6371 km
  • lat1, lng1 = koordinat lokasi yang disepakati
  • lat2, lng2 = koordinat pengguna saat check-in

Implementasi Laravel

// app/Core/GPS/GpsValidator.php

class GpsValidator
{
public function validate(
float $userLat,
float $userLng,
float $meetingLat,
float $meetingLng,
int $maxRadius = 100
): bool {
$distance = $this->haversine($userLat, $userLng, $meetingLat, $meetingLng);
return $distance <= $maxRadius;
}

private function haversine(
float $lat1, float $lng1,
float $lat2, float $lng2
): float {
$earthRadius = 6371000; // meter

$dLat = deg2rad($lat2 - $lat1);
$dLng = deg2rad($lng2 - $lng1);

$a = sin($dLat / 2) ** 2
+ cos(deg2rad($lat1)) * cos(deg2rad($lat2))
* sin($dLng / 2) ** 2;

$c = 2 * atan2(sqrt($a), sqrt(1 - $a));

return $earthRadius * $c; // meter
}
}

Anti-Fraud Measures

AncamanMitigasi
Mock LocationDeteksi via is_mock flag di Flutter
GPS SpoofingBandingkan dengan IP geolocation (soft check)
Replay AttackTimestamp check — GPS data tidak boleh > 30 detik
Accuracy FraudTolak jika accuracy > 30 meter
Device IDCatat device ID saat check-in

Flutter — Implementasi GPS

// core/services/gps_service.dart

class GpsService {
Future<GpsData> getCurrentLocation() async {
final permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
await Geolocator.requestPermission();
}

final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);

// Tolak jika akurasi terlalu rendah
if (position.accuracy > 30) {
throw GpsAccuracyException('Sinyal GPS terlalu lemah.');
}

return GpsData(
latitude: position.latitude,
longitude: position.longitude,
accuracy: position.accuracy,
isMock: position.isMocked,
timestamp: DateTime.now(),
);
}
}