| 304 | view.query_message_id = message.id |
| 305 | |
| 306 | class MaxResultsView(discord.ui.View): |
| 307 | def __init__(self, query): |
| 308 | super().__init__() |
| 309 | self.query = query |
| 310 | self.message_id = None # Used for the MaxResultsView message |
| 311 | self.query_message_id = None |
| 312 | |
| 313 | async def handle_search(self, interaction: discord.Interaction, max_results: int): |
| 314 | shodan_client = interaction.client.shodan |
| 315 | user = interaction.user.name |
| 316 | guild_name = interaction.guild.name if interaction.guild else "Direct Message" |
| 317 | |
| 318 | logger.info(f"{user} initiated a search with query '{self.query}' in {guild_name}") |
| 319 | |
| 320 | try: |
| 321 | result = shodan_client.search(self.query) |
| 322 | matches = result.get('matches', []) |
| 323 | |
| 324 | if matches: |
| 325 | limited_matches = matches[:max_results] |
| 326 | total = result.get('total', 0) |
| 327 | info = f"{user} used /shodan to search for `{self.query}` from {guild_name} and found {total} results. Here are the top {max_results} results:\n\n" |
| 328 | |
| 329 | if self.query_message_id: |
| 330 | try: |
| 331 | message_channel = interaction.channel |
| 332 | query_message = await message_channel.fetch_message(self.query_message_id) |
| 333 | await query_message.edit(content=info, view=None) # Edit the message to display results |
| 334 | # logger.info(f"Successfully edited QueryModal message with ID: {self.query_message_id} to display results.") |
| 335 | except Exception as e: |
| 336 | logger.error(f"Error editing QueryModal message with ID {self.query_message_id}: {e}") |
| 337 | |
| 338 | await interaction.followup.send(info) |
| 339 | |
| 340 | for match in limited_matches: |
| 341 | ip = match.get('ip_str', 'No IP available.') |
| 342 | port = match.get('port', 'No port available.') |
| 343 | |
| 344 | # Extract geolocation details for easy mode |
| 345 | lat = match.get('location', {}).get('latitude') |
| 346 | long = match.get('location', {}).get('longitude') |
| 347 | google_maps_link = f"https://www.google.com/maps?q={lat},{long}" if lat and long else None |
| 348 | geolocation_text = f"([map](<{google_maps_link}>))" if google_maps_link else "" |
| 349 | |
| 350 | # Check if IP is IPv6 |
| 351 | if is_ipv6(ip): |
| 352 | clickable_link = f"{ip} (port: {port}) {geolocation_text}" |
| 353 | else: |
| 354 | clickable_link = f"[{ip}:{port}](http://{ip}:{port}) {geolocation_text}" |
| 355 | |
| 356 | await interaction.channel.send(clickable_link) |
| 357 | |
| 358 | screenshot_data = match.get('screenshot', {}).get('data') |
| 359 | if screenshot_data: |
| 360 | try: |
| 361 | screenshot_bytes = base64.b64decode(screenshot_data) |
| 362 | screenshot_file = io.BytesIO(screenshot_bytes) |
| 363 | screenshot_filename = f"screenshot_{match.get('ip_str', 'unknown')}.jpg" |