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
| Data | Sumber | Keterangan |
|---|---|---|
latitude | GPS Device | Koordinat lintang |
longitude | GPS Device | Koordinat bujur |
accuracy | GPS Device | Akurasi dalam meter (harus < 30m) |
timestamp | System | Waktu pengambilan koordinat |
Radius Persetujuan per Lokasi
| Jenis Lokasi | Radius Maksimum |
|---|---|
| Perpustakaan | 50 meter |
| Laboratorium | 30 meter |
| Ruang Kelas | 20 meter |
| Aula / Ruang Besar | 80 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 kmlat1, lng1= koordinat lokasi yang disepakatilat2, 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
| Ancaman | Mitigasi |
|---|---|
| Mock Location | Deteksi via is_mock flag di Flutter |
| GPS Spoofing | Bandingkan dengan IP geolocation (soft check) |
| Replay Attack | Timestamp check — GPS data tidak boleh > 30 detik |
| Accuracy Fraud | Tolak jika accuracy > 30 meter |
| Device ID | Catat 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(),
);
}
}