diff options
author | Brock Vojkovic <github@vojk.au> | 2024-08-11 08:39:46 +0000 |
---|---|---|
committer | Markus Heiser <markus.heiser@darmarIT.de> | 2024-10-05 08:18:28 +0200 |
commit | e17d7632d0ed8284c218f65604ab5fa5d4b8ff81 (patch) | |
tree | 720692ebe4c8087f6c928d28f79bae5040a85605 /searx/webapp.py | |
parent | 3e747d0491b23f9431ce6ccc79875233614e165a (diff) | |
download | searxng-e17d7632d0ed8284c218f65604ab5fa5d4b8ff81.tar.gz searxng-e17d7632d0ed8284c218f65604ab5fa5d4b8ff81.zip |
[feat] add favicons to result urls
Diffstat (limited to 'searx/webapp.py')
-rwxr-xr-x | searx/webapp.py | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/searx/webapp.py b/searx/webapp.py index dd79defcb..8046dc392 100755 --- a/searx/webapp.py +++ b/searx/webapp.py @@ -123,6 +123,7 @@ from searx.locales import ( # renaming names from searx imports ... from searx.autocomplete import search_autocomplete, backends as autocomplete_backends +from searx.favicon_resolver import search_favicon, backends as favicon_backends from searx.redisdb import initialize as redis_initialize from searx.sxng_locales import sxng_locales from searx.search import SearchWithPlugins, initialize as search_initialize @@ -297,6 +298,24 @@ def morty_proxify(url: str): return '{0}?{1}'.format(settings['result_proxy']['url'], urlencode(url_params)) +def favicon_proxify(url: str): + # url is a FQDN (e.g. example.com, en.wikipedia.org) + + resolver = request.preferences.get_value('favicon_resolver') + + # if resolver is empty, just return nothing + if not resolver: + return "" + + # check resolver is valid + if resolver not in favicon_backends: + return "" + + h = new_hmac(settings['server']['secret_key'], url.encode()) + + return '{0}?{1}'.format(url_for('favicon_proxy'), urlencode(dict(q=url.encode(), h=h))) + + def image_proxify(url: str): if url.startswith('//'): @@ -358,6 +377,7 @@ def get_client_settings(): return { 'autocomplete_provider': req_pref.get_value('autocomplete'), 'autocomplete_min': get_setting('search.autocomplete_min'), + 'favicon_resolver': req_pref.get_value('favicon_resolver'), 'http_method': req_pref.get_value('method'), 'infinite_scroll': req_pref.get_value('infinite_scroll'), 'translations': get_translations(), @@ -388,6 +408,7 @@ def render(template_name: str, **kwargs): # values from the preferences kwargs['preferences'] = request.preferences kwargs['autocomplete'] = request.preferences.get_value('autocomplete') + kwargs['favicon_resolver'] = request.preferences.get_value('favicon_resolver') kwargs['infinite_scroll'] = request.preferences.get_value('infinite_scroll') kwargs['search_on_category_select'] = request.preferences.get_value('search_on_category_select') kwargs['hotkeys'] = request.preferences.get_value('hotkeys') @@ -431,6 +452,7 @@ def render(template_name: str, **kwargs): # helpers to create links to other pages kwargs['url_for'] = custom_url_for # override url_for function in templates kwargs['image_proxify'] = image_proxify + kwargs['favicon_proxify'] = favicon_proxify kwargs['proxify'] = morty_proxify if settings['result_proxy']['url'] is not None else None kwargs['proxify_results'] = settings['result_proxy']['proxify_results'] kwargs['cache_url'] = settings['ui']['cache_url'] @@ -873,6 +895,42 @@ def autocompleter(): return Response(suggestions, mimetype=mimetype) +@app.route('/favicon', methods=['GET']) +def favicon_proxy(): + """Return proxied favicon results""" + url = request.args.get('q') + + # malformed request + if not url: + return '', 400 + + # malformed request / does not have authorisation + if not is_hmac_of(settings['server']['secret_key'], url.encode(), request.args.get('h', '')): + return '', 400 + + resolver = request.preferences.get_value('favicon_resolver') + + # check if the favicon resolver is valid + if not resolver or resolver not in favicon_backends: + return '', 400 + + # parse query + raw_text_query = RawTextQuery(url, []) + + resp = search_favicon(resolver, raw_text_query) + + # return 404 if the favicon is not found + if not resp: + theme = request.preferences.get_value("theme") + # return favicon from /static/themes/simple/img/empty_favicon.svg + # we can't rely on an onerror event in the img tag to display a default favicon as this violates the CSP. + # using redirect to save network bandwidth (user will have this location cached). + return redirect(url_for('static', filename='themes/' + theme + '/img/empty_favicon.svg')) + + # will always return a PNG image + return Response(resp, mimetype='image/png') + + @app.route('/preferences', methods=['GET', 'POST']) def preferences(): """Render preferences page && save user preferences""" @@ -1020,6 +1078,7 @@ def preferences(): ], disabled_engines = disabled_engines, autocomplete_backends = autocomplete_backends, + favicon_backends = favicon_backends, shortcuts = {y: x for x, y in engine_shortcuts.items()}, themes = themes, plugins = plugins, |