type !== 'ip') { throw new RunnerException('ip-api.com only supports "ip" targets.'); } $response = Http::timeout((int) config('osint.run_timeout')) ->get("http://ip-api.com/json/{$target->value}", [ 'fields' => 'status,message,country,regionName,city,zip,lat,lon,timezone,isp,org,as,query', ]); if (! $response->successful()) { throw new RunnerException('ip-api.com request failed with status '.$response->status().'.'); } $data = $response->json(); if (($data['status'] ?? null) !== 'success') { throw new RunnerException('ip-api.com lookup failed: '.($data['message'] ?? 'unknown error')); } $summary = sprintf( '%s, %s, %s (%s)', $data['city'] ?? 'Unknown city', $data['regionName'] ?? 'Unknown region', $data['country'] ?? 'Unknown country', $data['isp'] ?? $data['org'] ?? 'Unknown ISP' ); return new RunnerResult(raw: $data, summary: $summary); } }