
    i6                     >   d Z ddlmZmZmZ ddlZddlZddlZddlm	Z	 ddl
mZmZ ddlmZ ddlmZ d	Z	 d
Z	 dZ	 dZ	  ej(                  d      Zddeez  dej*                  defdZdej*                  defdZdeez  dej*                  defdZdefdZdefdZy)a  
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 valkey 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

    )IPv4NetworkIPv6Network
ip_addressN)secret_hash   )get_networklogger)config)valkeydbiX  i  zSearXNG_limiter.pingzSearXNG_limiter.tokenzbotdetection.link_tokennetworkrequestrenewc                     t        j                         }t        | |      }|j                  |      s"t	        j
                  d| j                  |       y|r|j                  |dt               t	        j                  d| j                  |       y)zChecks 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`.

    z#missing ping (IP: %s) / request: %sTr   exz(found ping for (client) network %s -> %sF)
r   get_valkey_clientget_ping_keygetr	   info
compressedsetPING_LIVE_TIMEdebug)r   r   r   valkey_clientping_keys        ./root/searxng/searx/botdetection/link_token.pyis_suspiciousr   I   sy     ..0MGW-HX&97;M;MxX(A.9
LL;W=O=OQYZ    tokenc                 N   t        j                         }t        j                         }t	        |      syt        | j                        }t        ||      }t        ||       }t        j                  d|j                  |j                  |       |j                  |dt               y)zThis 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`.

    Nz4store ping_key for (client) network %s (IP %s) -> %sr   r   )r   r   r
   get_global_cfgtoken_is_validr   remote_addrr   r   r	   r   r   r   r   )r   r   r   cfgreal_ipr   r   s          r   pingr&   ]   s     ..0M



!C% ,,-G'3'GGW-H
LL>@R@RT[TfTfhp hn5r   returnc                     t         dz   t        | j                  |j                  j	                  dd      z   |j                  j	                  dd      z         z   dz   S )z\Generates a hashed key that fits (more or less) to a *WEB-browser
    session* in a network.[zAccept-Language z
User-Agent])PING_KEYr   r   headersr   )r   r   s     r   r   r   s   sc     	
	
!4!45F!KKgooNaNabnprNss
	

 	r   c                 L    | t               k(  }t        j                  d|       |S )Nztoken is valid --> %s)	get_tokenr	   r   )r   valids     r   r"   r"      s"    Y[ E
LL(%0Lr   c                     	 t        j                         } | j                  t              }|r|j                  d      }|S dj                  d t        d      D              }| j                  t        |t               |S # t        $ r Y yw xY w)a  Returns current token.  If there is no currently active token a new token
    is generated randomly and stored in the Valkey DB.  Without without a
    database connection, string "12345678" is returned.

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

    12345678zUTF-8r*   c              3      K   | ]8  }t        j                  t        j                  t        j                  z          : y w)N)randomchoicestringascii_lowercasedigits).0_s     r   	<genexpr>zget_token.<locals>.<genexpr>   s)     aRSf&<&<v}}&LMas   >A    r   )
r   r   
ValueErrorr   	TOKEN_KEYdecodejoinranger   TOKEN_LIVE_TIME)r   r   s     r   r/   r/      s     224 i(EW% L aW\]_W`aa)U?L   s   A? ?	B
B)F)__doc__	ipaddressr   r   r   r6   r4   flasksearx.valkeylibr   _helpersr   r	   r*   r
   r   rB   r   r,   r>   getChildRequestboolr   strr&   r   r"   r/    r   r   <module>rM      s   "H     '
   , <! A#	 9	2	3;4 u}} UY (6%-- 6 6,
+3 
emm 
PS 
T 3 r   