.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
_helpers.py
Go to the documentation of this file.
1# SPDX-License-Identifier: AGPL-3.0-or-later
2# pylint: disable=missing-module-docstring, invalid-name
3from __future__ import annotations
4import typing as t
5
6__all__ = ["log_error_only_once", "dump_request", "get_network", "logger", "too_many_requests"]
7
8from ipaddress import (
9 IPv4Network,
10 IPv6Network,
11 IPv4Address,
12 IPv6Address,
13 ip_network,
14)
15import flask
16import werkzeug
17
18from searx import logger
19
20if t.TYPE_CHECKING:
21 from . import config
22
23logger = logger.getChild('botdetection')
24
25
26def dump_request(request: flask.Request):
27 return (
28 request.path
29 + " || X-Forwarded-For: %s" % request.headers.get('X-Forwarded-For')
30 + " || X-Real-IP: %s" % request.headers.get('X-Real-IP')
31 + " || form: %s" % request.form
32 + " || Accept: %s" % request.headers.get('Accept')
33 + " || Accept-Language: %s" % request.headers.get('Accept-Language')
34 + " || Accept-Encoding: %s" % request.headers.get('Accept-Encoding')
35 + " || Content-Type: %s" % request.headers.get('Content-Type')
36 + " || Content-Length: %s" % request.headers.get('Content-Length')
37 + " || Connection: %s" % request.headers.get('Connection')
38 + " || User-Agent: %s" % request.headers.get('User-Agent')
39 + " || Sec-Fetch-Site: %s" % request.headers.get('Sec-Fetch-Site')
40 + " || Sec-Fetch-Mode: %s" % request.headers.get('Sec-Fetch-Mode')
41 + " || Sec-Fetch-Dest: %s" % request.headers.get('Sec-Fetch-Dest')
42 )
43
44
45def too_many_requests(network: IPv4Network | IPv6Network, log_msg: str) -> werkzeug.Response | None:
46 """Returns a HTTP 429 response object and writes a ERROR message to the
47 'botdetection' logger. This function is used in part by the filter methods
48 to return the default ``Too Many Requests`` response.
49
50 """
51
52 logger.debug("BLOCK %s: %s", network.compressed, log_msg)
53 return flask.make_response(('Too Many Requests', 429))
54
55
56def get_network(real_ip: IPv4Address | IPv6Address, cfg: config.Config) -> IPv4Network | IPv6Network:
57 """Returns the (client) network of whether the ``real_ip`` is part of.
58
59 The ``ipv4_prefix`` and ``ipv6_prefix`` define the number of leading bits in
60 an address that are compared to determine whether or not an address is part
61 of a (client) network.
62
63 .. code:: toml
64
65 [botdetection]
66
67 ipv4_prefix = 32
68 ipv6_prefix = 48
69
70 """
71
72 prefix: int = cfg["botdetection.ipv4_prefix"]
73 if real_ip.version == 6:
74 prefix: int = cfg["botdetection.ipv6_prefix"]
75 network = ip_network(f"{real_ip}/{prefix}", strict=False)
76 # logger.debug("get_network(): %s", network.compressed)
77 return network
78
79
80_logged_errors: list[str] = []
81
82
83def log_error_only_once(err_msg: str):
84 if err_msg not in _logged_errors:
85 logger.error(err_msg)
86 _logged_errors.append(err_msg)
IPv4Network|IPv6Network get_network(IPv4Address|IPv6Address real_ip, config.Config cfg)
Definition _helpers.py:56
werkzeug.Response|None too_many_requests(IPv4Network|IPv6Network network, str log_msg)
Definition _helpers.py:45
dump_request(flask.Request request)
Definition _helpers.py:26
log_error_only_once(str err_msg)
Definition _helpers.py:83