.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
searx.botdetection.link_token Namespace Reference

Functions

 is_suspicious (IPv4Network|IPv6Network network, flask.Request request, bool renew=False)
 
 ping (flask.Request request, str token)
 
str get_ping_key (IPv4Network|IPv6Network network, flask.Request request)
 
bool token_is_valid (token)
 
str get_token ()
 

Variables

int TOKEN_LIVE_TIME = 600
 
int PING_LIVE_TIME = 3600
 
str PING_KEY = 'SearXNG_limiter.ping'
 
str TOKEN_KEY = 'SearXNG_limiter.token'
 
 logger = logger.getChild('botdetection.link_token')
 

Detailed Description

Method ``link_token``
---------------------

The ``link_token`` method evaluates a request as :py:obj:`suspicious
<is_suspicious>` if the URL ``/client<token>.css`` is not requested by the
client.  By adding a random component (the token) in the URL, a bot can not send
a ping by request a static URL.

.. note::

   This method requires a redis DB and needs a HTTP X-Forwarded-For_ header.

To get in use of this method a flask URL route needs to be added:

.. code:: python

   @app.route('/client<token>.css', methods=['GET', 'POST'])
   def client_token(token=None):
       link_token.ping(request, token)
       return Response('', mimetype='text/css')

And in the HTML template from flask a stylesheet link is needed (the value of
``link_token`` comes from :py:obj:`get_token`):

.. code:: html

   <link rel="stylesheet"
         href="{{ url_for('client_token', token=link_token) }}"
         type="text/css" />

.. _X-Forwarded-For:
   https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For

Function Documentation

◆ get_ping_key()

str searx.botdetection.link_token.get_ping_key ( IPv4Network | IPv6Network network,
flask.Request request )
Generates a hashed key that fits (more or less) to a *WEB-browser
session* in a network.

Definition at line 116 of file link_token.py.

116def get_ping_key(network: IPv4Network | IPv6Network, request: flask.Request) -> str:
117 """Generates a hashed key that fits (more or less) to a *WEB-browser
118 session* in a network."""
119 return (
120 PING_KEY
121 + "["
122 + secret_hash(
123 network.compressed + request.headers.get('Accept-Language', '') + request.headers.get('User-Agent', '')
124 )
125 + "]"
126 )
127
128

Referenced by searx.botdetection.link_token.is_suspicious(), and searx.botdetection.link_token.ping().

+ Here is the caller graph for this function:

◆ get_token()

str searx.botdetection.link_token.get_token ( )
Returns current token.  If there is no currently active token a new token
is generated randomly and stored in the redis DB.

- :py:obj:`TOKEN_LIVE_TIME`
- :py:obj:`TOKEN_KEY`

Definition at line 135 of file link_token.py.

135def get_token() -> str:
136 """Returns current token. If there is no currently active token a new token
137 is generated randomly and stored in the redis DB.
138
139 - :py:obj:`TOKEN_LIVE_TIME`
140 - :py:obj:`TOKEN_KEY`
141
142 """
143 redis_client = redisdb.client()
144 if not redis_client:
145 # This function is also called when limiter is inactive / no redis DB
146 # (see render function in webapp.py)
147 return '12345678'
148 token = redis_client.get(TOKEN_KEY)
149 if token:
150 token = token.decode('UTF-8')
151 else:
152 token = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(16))
153 redis_client.set(TOKEN_KEY, token, ex=TOKEN_LIVE_TIME)
154 return token

Referenced by searx.botdetection.link_token.token_is_valid().

+ Here is the caller graph for this function:

◆ is_suspicious()

searx.botdetection.link_token.is_suspicious ( IPv4Network | IPv6Network network,
flask.Request request,
bool renew = False )
Checks whether a valid ping is exists for this (client) network, if not
this request is rated as *suspicious*.  If a valid ping exists and argument
``renew`` is ``True`` the expire time of this ping is reset to
:py:obj:`PING_LIVE_TIME`.

Definition at line 72 of file link_token.py.

72def is_suspicious(network: IPv4Network | IPv6Network, request: flask.Request, renew: bool = False):
73 """Checks whether a valid ping is exists for this (client) network, if not
74 this request is rated as *suspicious*. If a valid ping exists and argument
75 ``renew`` is ``True`` the expire time of this ping is reset to
76 :py:obj:`PING_LIVE_TIME`.
77
78 """
79 redis_client = redisdb.client()
80 if not redis_client:
81 return False
82
83 ping_key = get_ping_key(network, request)
84 if not redis_client.get(ping_key):
85 logger.info("missing ping (IP: %s) / request: %s", network.compressed, ping_key)
86 return True
87
88 if renew:
89 redis_client.set(ping_key, 1, ex=PING_LIVE_TIME)
90
91 logger.debug("found ping for (client) network %s -> %s", network.compressed, ping_key)
92 return False
93
94

References searx.botdetection.link_token.get_ping_key().

+ Here is the call graph for this function:

◆ ping()

searx.botdetection.link_token.ping ( flask.Request request,
str token )
This function is called by a request to URL ``/client<token>.css``.  If
``token`` is valid a :py:obj:`PING_KEY` for the client is stored in the DB.
The expire time of this ping-key is :py:obj:`PING_LIVE_TIME`.

Definition at line 95 of file link_token.py.

95def ping(request: flask.Request, token: str):
96 """This function is called by a request to URL ``/client<token>.css``. If
97 ``token`` is valid a :py:obj:`PING_KEY` for the client is stored in the DB.
98 The expire time of this ping-key is :py:obj:`PING_LIVE_TIME`.
99
100 """
101 from . import redis_client, cfg # pylint: disable=import-outside-toplevel, cyclic-import
102
103 if not redis_client:
104 return
105 if not token_is_valid(token):
106 return
107
108 real_ip = ip_address(get_real_ip(request))
109 network = get_network(real_ip, cfg)
110
111 ping_key = get_ping_key(network, request)
112 logger.debug("store ping_key for (client) network %s (IP %s) -> %s", network.compressed, real_ip, ping_key)
113 redis_client.set(ping_key, 1, ex=PING_LIVE_TIME)
114
115

References searx.botdetection.link_token.get_ping_key(), and searx.botdetection.link_token.token_is_valid().

+ Here is the call graph for this function:

◆ token_is_valid()

bool searx.botdetection.link_token.token_is_valid ( token)

Definition at line 129 of file link_token.py.

129def token_is_valid(token) -> bool:
130 valid = token == get_token()
131 logger.debug("token is valid --> %s", valid)
132 return valid
133
134

References searx.botdetection.link_token.get_token().

Referenced by searx.botdetection.link_token.ping().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ logger

searx.botdetection.link_token.logger = logger.getChild('botdetection.link_token')

Definition at line 69 of file link_token.py.

◆ PING_KEY

str searx.botdetection.link_token.PING_KEY = 'SearXNG_limiter.ping'

Definition at line 63 of file link_token.py.

◆ PING_LIVE_TIME

int searx.botdetection.link_token.PING_LIVE_TIME = 3600

Definition at line 60 of file link_token.py.

◆ TOKEN_KEY

str searx.botdetection.link_token.TOKEN_KEY = 'SearXNG_limiter.token'

Definition at line 66 of file link_token.py.

◆ TOKEN_LIVE_TIME

int searx.botdetection.link_token.TOKEN_LIVE_TIME = 600

Definition at line 57 of file link_token.py.