tor_check.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. # SPDX-License-Identifier: AGPL-3.0-or-later
  2. """A plugin to check if the ip address of the request is a Tor exit-node if the
  3. user searches for ``tor-check``. It fetches the tor exit node list from
  4. :py:obj:`url_exit_list` and parses all the IPs into a list, then checks if the
  5. user's IP address is in it.
  6. Enable in ``settings.yml``:
  7. .. code:: yaml
  8. enabled_plugins:
  9. ..
  10. - 'Tor check plugin'
  11. """
  12. from __future__ import annotations
  13. import re
  14. from flask_babel import gettext
  15. from httpx import HTTPError
  16. from searx.network import get
  17. from searx.result_types import EngineResults
  18. from searx.botdetection import get_real_ip
  19. default_on = False
  20. name = gettext("Tor check plugin")
  21. '''Translated name of the plugin'''
  22. description = gettext(
  23. "This plugin checks if the address of the request is a Tor exit-node, and"
  24. " informs the user if it is; like check.torproject.org, but from SearXNG."
  25. )
  26. '''Translated description of the plugin.'''
  27. preference_section = 'query'
  28. '''The preference section where the plugin is shown.'''
  29. query_keywords = ['tor-check']
  30. '''Query keywords shown in the preferences.'''
  31. query_examples = ''
  32. '''Query examples shown in the preferences.'''
  33. # Regex for exit node addresses in the list.
  34. reg = re.compile(r"(?<=ExitAddress )\S+")
  35. url_exit_list = "https://check.torproject.org/exit-addresses"
  36. """URL to load Tor exit list from."""
  37. def post_search(request, search) -> EngineResults:
  38. results = EngineResults()
  39. if search.search_query.pageno > 1:
  40. return results
  41. if search.search_query.query.lower() == "tor-check":
  42. # Request the list of tor exit nodes.
  43. try:
  44. resp = get(url_exit_list)
  45. node_list = re.findall(reg, resp.text) # type: ignore
  46. except HTTPError:
  47. # No answer, return error
  48. msg = gettext("Could not download the list of Tor exit-nodes from")
  49. results.add(results.types.Answer(answer=f"{msg} {url_exit_list}"))
  50. return results
  51. real_ip = get_real_ip(request)
  52. if real_ip in node_list:
  53. msg = gettext("You are using Tor and it looks like you have the external IP address")
  54. results.add(results.types.Answer(answer=f"{msg} {real_ip}"))
  55. else:
  56. msg = gettext("You are not using Tor and you have the external IP address")
  57. results.add(results.types.Answer(answer=f"{msg} {real_ip}"))
  58. return results