mirror of https://github.com/searxng/searxng.git
Compare commits
5 Commits
06b4637332
...
53e85309f9
Author | SHA1 | Date |
---|---|---|
Markus Heiser | 53e85309f9 | |
dependabot[bot] | cd384a8a60 | |
Markus Heiser | c4055e449f | |
Markus Heiser | 2fdbf2622b | |
Markus Heiser | 1c9b28968d |
|
@ -1,5 +1,5 @@
|
||||||
name: "Checker"
|
name: "Checker"
|
||||||
on:
|
on: # yamllint disable-line rule:truthy
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 4 * * 5"
|
- cron: "0 4 * * 5"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: "Update searx.data"
|
name: "Update searx.data"
|
||||||
on:
|
on: # yamllint disable-line rule:truthy
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "59 23 28 * *"
|
- cron: "59 23 28 * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: Integration
|
name: Integration
|
||||||
|
|
||||||
on:
|
on: # yamllint disable-line rule:truthy
|
||||||
push:
|
push:
|
||||||
branches: ["master"]
|
branches: ["master"]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
@ -16,7 +16,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-20.04]
|
os: [ubuntu-20.04]
|
||||||
python-version: ["3.9", "3.10", "3.11", "3.12",]
|
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
@ -111,7 +111,7 @@ jobs:
|
||||||
BRANCH: gh-pages
|
BRANCH: gh-pages
|
||||||
FOLDER: dist/docs
|
FOLDER: dist/docs
|
||||||
CLEAN: true # Automatically remove deleted files from the deploy branch
|
CLEAN: true # Automatically remove deleted files from the deploy branch
|
||||||
SINGLE_COMMIT: True
|
SINGLE_COMMIT: true
|
||||||
COMMIT_MESSAGE: '[doc] build from commit ${{ github.sha }}'
|
COMMIT_MESSAGE: '[doc] build from commit ${{ github.sha }}'
|
||||||
|
|
||||||
babel:
|
babel:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: "Security checks"
|
name: "Security checks"
|
||||||
on:
|
on: # yamllint disable-line rule:truthy
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "42 05 * * *"
|
- cron: "42 05 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: "Update translations"
|
name: "Update translations"
|
||||||
on:
|
on: # yamllint disable-line rule:truthy
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "05 07 * * 5"
|
- cron: "05 07 * * 5"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
|
@ -53,6 +53,9 @@ Probe HTTP headers
|
||||||
.. automodule:: searx.botdetection.http_user_agent
|
.. automodule:: searx.botdetection.http_user_agent
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
.. automodule:: searx.botdetection.sec_fetch
|
||||||
|
:members:
|
||||||
|
|
||||||
.. _botdetection config:
|
.. _botdetection config:
|
||||||
|
|
||||||
Config
|
Config
|
||||||
|
|
2
manage
2
manage
|
@ -57,7 +57,7 @@ while IFS= read -r line; do
|
||||||
if [ "$line" != "tests/unit/settings/syntaxerror_settings.yml" ]; then
|
if [ "$line" != "tests/unit/settings/syntaxerror_settings.yml" ]; then
|
||||||
YAMLLINT_FILES+=("$line")
|
YAMLLINT_FILES+=("$line")
|
||||||
fi
|
fi
|
||||||
done <<< "$(git ls-files './tests/*.yml' './searx/*.yml' './utils/templates/etc/searxng/*.yml')"
|
done <<< "$(git ls-files './tests/*.yml' './searx/*.yml' './utils/templates/etc/searxng/*.yml' '.github/*.yml' '.github/*/*.yml')"
|
||||||
|
|
||||||
RST_FILES=(
|
RST_FILES=(
|
||||||
'README.rst'
|
'README.rst'
|
||||||
|
|
|
@ -4,7 +4,7 @@ cov-core==1.15.0
|
||||||
black==24.3.0
|
black==24.3.0
|
||||||
pylint==3.3.1
|
pylint==3.3.1
|
||||||
splinter==0.21.0
|
splinter==0.21.0
|
||||||
selenium==4.25.0
|
selenium==4.26.1
|
||||||
Pallets-Sphinx-Themes==2.3.0
|
Pallets-Sphinx-Themes==2.3.0
|
||||||
Sphinx==7.4.7
|
Sphinx==7.4.7
|
||||||
sphinx-issues==5.0.0
|
sphinx-issues==5.0.0
|
||||||
|
|
|
@ -31,6 +31,9 @@ def dump_request(request: flask.Request):
|
||||||
+ " || Content-Length: %s" % request.headers.get('Content-Length')
|
+ " || Content-Length: %s" % request.headers.get('Content-Length')
|
||||||
+ " || Connection: %s" % request.headers.get('Connection')
|
+ " || Connection: %s" % request.headers.get('Connection')
|
||||||
+ " || User-Agent: %s" % request.headers.get('User-Agent')
|
+ " || User-Agent: %s" % request.headers.get('User-Agent')
|
||||||
|
+ " || Sec-Fetch-Site: %s" % request.headers.get('Sec-Fetch-Site')
|
||||||
|
+ " || Sec-Fetch-Mode: %s" % request.headers.get('Sec-Fetch-Mode')
|
||||||
|
+ " || Sec-Fetch-Dest: %s" % request.headers.get('Sec-Fetch-Dest')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
"""
|
||||||
|
Method ``http_sec_fetch``
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
The ``http_sec_fetch`` method protect resources from web attacks with `Fetch
|
||||||
|
Metadata`_. A request is filtered out in case of:
|
||||||
|
|
||||||
|
- http header Sec-Fetch-Mode_ is invalid
|
||||||
|
- http header Sec-Fetch-Dest_ is invalid
|
||||||
|
|
||||||
|
.. _Fetch Metadata:
|
||||||
|
https://developer.mozilla.org/en-US/docs/Glossary/Fetch_metadata_request_header
|
||||||
|
|
||||||
|
.. Sec-Fetch-Dest:
|
||||||
|
https://developer.mozilla.org/en-US/docs/Web/API/Request/destination
|
||||||
|
|
||||||
|
.. Sec-Fetch-Mode:
|
||||||
|
https://developer.mozilla.org/en-US/docs/Web/API/Request/mode
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
from ipaddress import (
|
||||||
|
IPv4Network,
|
||||||
|
IPv6Network,
|
||||||
|
)
|
||||||
|
|
||||||
|
import flask
|
||||||
|
import werkzeug
|
||||||
|
|
||||||
|
from . import config
|
||||||
|
from ._helpers import logger
|
||||||
|
|
||||||
|
|
||||||
|
def filter_request(
|
||||||
|
network: IPv4Network | IPv6Network,
|
||||||
|
request: flask.Request,
|
||||||
|
cfg: config.Config,
|
||||||
|
) -> werkzeug.Response | None:
|
||||||
|
|
||||||
|
val = request.headers.get("Sec-Fetch-Mode", "")
|
||||||
|
if val != "navigate":
|
||||||
|
logger.debug("invalid Sec-Fetch-Mode '%s'", val)
|
||||||
|
return flask.redirect(flask.url_for('index'), code=302)
|
||||||
|
|
||||||
|
val = request.headers.get("Sec-Fetch-Site", "")
|
||||||
|
if val not in ('same-origin', 'same-site', 'none'):
|
||||||
|
logger.debug("invalid Sec-Fetch-Site '%s'", val)
|
||||||
|
flask.redirect(flask.url_for('index'), code=302)
|
||||||
|
|
||||||
|
val = request.headers.get("Sec-Fetch-Dest", "")
|
||||||
|
if val != "document":
|
||||||
|
logger.debug("invalid Sec-Fetch-Dest '%s'", val)
|
||||||
|
flask.redirect(flask.url_for('index'), code=302)
|
||||||
|
|
||||||
|
return None
|
|
@ -111,6 +111,7 @@ from searx.botdetection import (
|
||||||
http_accept_encoding,
|
http_accept_encoding,
|
||||||
http_accept_language,
|
http_accept_language,
|
||||||
http_user_agent,
|
http_user_agent,
|
||||||
|
http_sec_fetch,
|
||||||
ip_limit,
|
ip_limit,
|
||||||
ip_lists,
|
ip_lists,
|
||||||
get_network,
|
get_network,
|
||||||
|
@ -178,16 +179,17 @@ def filter_request(request: flask.Request) -> werkzeug.Response | None:
|
||||||
logger.error("BLOCK %s: matched BLOCKLIST - %s", network.compressed, msg)
|
logger.error("BLOCK %s: matched BLOCKLIST - %s", network.compressed, msg)
|
||||||
return flask.make_response(('IP is on BLOCKLIST - %s' % msg, 429))
|
return flask.make_response(('IP is on BLOCKLIST - %s' % msg, 429))
|
||||||
|
|
||||||
# methods applied on /
|
# methods applied on all requests
|
||||||
|
|
||||||
for func in [
|
for func in [
|
||||||
http_user_agent,
|
http_user_agent,
|
||||||
]:
|
]:
|
||||||
val = func.filter_request(network, request, cfg)
|
val = func.filter_request(network, request, cfg)
|
||||||
if val is not None:
|
if val is not None:
|
||||||
|
logger.debug(f"NOT OK ({func.__name__}): {network}: %s", dump_request(flask.request))
|
||||||
return val
|
return val
|
||||||
|
|
||||||
# methods applied on /search
|
# methods applied on /search requests
|
||||||
|
|
||||||
if request.path == '/search':
|
if request.path == '/search':
|
||||||
|
|
||||||
|
@ -196,12 +198,15 @@ def filter_request(request: flask.Request) -> werkzeug.Response | None:
|
||||||
http_accept_encoding,
|
http_accept_encoding,
|
||||||
http_accept_language,
|
http_accept_language,
|
||||||
http_user_agent,
|
http_user_agent,
|
||||||
|
http_sec_fetch,
|
||||||
ip_limit,
|
ip_limit,
|
||||||
]:
|
]:
|
||||||
val = func.filter_request(network, request, cfg)
|
val = func.filter_request(network, request, cfg)
|
||||||
if val is not None:
|
if val is not None:
|
||||||
|
logger.debug(f"NOT OK ({func.__name__}): {network}: %s", dump_request(flask.request))
|
||||||
return val
|
return val
|
||||||
logger.debug(f"OK {network}: %s", dump_request(flask.request))
|
logger.debug(f"OK: {network}: %s", dump_request(flask.request))
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue