From 57ddd3e47ec081d80b2df127989c12647f2b6b1f Mon Sep 17 00:00:00 2001 From: LeXofLeviafan Date: Thu, 7 Mar 2024 03:27:27 +0100 Subject: [PATCH] [jarun#685] included flask-reverse-proxy-fix into the package --- buku | 8 +-- bukuserver/middleware/__init__.py | 3 + .../middleware/flask_reverse_proxy_fix.py | 60 +++++++++++++++++++ bukuserver/requirements.txt | 1 - bukuserver/server.py | 9 +-- setup.py | 10 +--- tests/.pylintrc | 1 + 7 files changed, 71 insertions(+), 21 deletions(-) create mode 100644 bukuserver/middleware/__init__.py create mode 100644 bukuserver/middleware/flask_reverse_proxy_fix.py diff --git a/buku b/buku index 947e21b0..2a264218 100755 --- a/buku +++ b/buku @@ -1127,8 +1127,7 @@ class BukuDb: processed['value'] += count cond.notify() - if recs < threads: - threads = recs + threads = min(threads, recs) for i in range(threads): thread = threading.Thread(target=refresh, args=(i, cond)) @@ -2307,12 +2306,11 @@ class BukuDb: for item in sublist: if item['type'] == 'folder': next_folder_name = folder_name + DELIM + strip_delim(item['name']) - for i in self.traverse_bm_folder( + yield from self.traverse_bm_folder( item['children'], unique_tag, next_folder_name, - add_parent_folder_as_tag): - yield i + add_parent_folder_as_tag) elif item['type'] == 'url': try: if is_nongeneric_url(item['url']): diff --git a/bukuserver/middleware/__init__.py b/bukuserver/middleware/__init__.py new file mode 100644 index 00000000..6a43d181 --- /dev/null +++ b/bukuserver/middleware/__init__.py @@ -0,0 +1,3 @@ +from .flask_reverse_proxy_fix import ReverseProxyPrefixFix + +__all__ = ['ReverseProxyPrefixFix'] diff --git a/bukuserver/middleware/flask_reverse_proxy_fix.py b/bukuserver/middleware/flask_reverse_proxy_fix.py new file mode 100644 index 00000000..4ac1f636 --- /dev/null +++ b/bukuserver/middleware/flask_reverse_proxy_fix.py @@ -0,0 +1,60 @@ +# clone of flask-reverse-proxy-fix with github fixes from @rachmadaniHaryono and @Glocktober + +from flask import Flask as App +# noinspection PyPackageRequirements +try: + from werkzeug.contrib.fixers import ProxyFix +except ModuleNotFoundError: + from werkzeug.middleware.proxy_fix import ProxyFix + + +class ReverseProxyPrefixFix: # pylint: disable=too-few-public-methods + """ + Flask middleware to ensure correct URLs are generated by Flask.url_for() where an application is under a reverse + proxy. Specifically this middleware corrects URLs where a common prefix needs to be added to all URLs. + + For example: If client requests for an application are reverse proxied such that: + `example.com/some-service/v1/foo` becomes `some-service-v1.internal/foo`, where `/foo` is a route within a Flask + application `foo()`. + + Without this middleware, a call to `Flask.url_for('.foo')` would give: `/foo`. If returned to the client, as a + 'self' link for example, this would cause a request to `example.com/foo`, which would be invalid as the + `/some-service/v1` prefix is missing. + + With this middleware, a call to `Flask.url_for('.foo')` would give: '/some-service/v1/foo', which will work if used + by a client. + + This middleware is compatible with both relative and absolute URLs (i.e. `Flask.url_for('.foo')` and + `Flask.url_for('.foo', _external=True)`. + + This middleware incorporates the `werkzeug.contrib.fixers.ProxyFix` middleware [1] and is based on the + 'Fixing SCRIPT_NAME/url_scheme when behind reverse proxy' Flask snippet [2]. + + Note: Ensure the prefix value includes a preceding slash, but not a trailing slash (i.e. use `/foo` not `/foo/`). + + [1] http://werkzeug.pocoo.org/docs/0.14/contrib/fixers/#werkzeug.contrib.fixers.ProxyFix + [2] http://flask.pocoo.org/snippets/35/ + """ + def __init__(self, app: App, **kwargs): + """ + :type app: App + :param app: Flask application + """ + self.app = app.wsgi_app + self.prefix = None + + if 'REVERSE_PROXY_PATH' in app.config: + self.prefix = app.config['REVERSE_PROXY_PATH'] + + self.app = ProxyFix(self.app, **kwargs) + + app.wsgi_app = self + + def __call__(self, environ, start_response): + if self.prefix is not None: + environ['SCRIPT_NAME'] = self.prefix + path_info = environ['PATH_INFO'] + if path_info.startswith(self.prefix): + environ['PATH_INFO'] = path_info[len(self.prefix):] + + return self.app(environ, start_response) diff --git a/bukuserver/requirements.txt b/bukuserver/requirements.txt index cfc2a93e..51b93258 100644 --- a/bukuserver/requirements.txt +++ b/bukuserver/requirements.txt @@ -3,7 +3,6 @@ Flask-Admin>=1.6.1 Flask-API>=3.0.post1 Flask-Bootstrap>=3.3.7.1 flask-paginate>=2022.1.8 -flask-reverse-proxy-fix @ https://github.com/rachmadaniHaryono/flask-reverse-proxy-fix/archive/refs/tags/v0.2.3.zip Flask-WTF>=1.0.1 Flask>=2.2.2,<2.3 werkzeug<2.4 diff --git a/bukuserver/server.py b/bukuserver/server.py index 7978a78b..594f8149 100644 --- a/bukuserver/server.py +++ b/bukuserver/server.py @@ -14,9 +14,9 @@ from buku import BukuDb, __version__, network_handler try: - from flask_reverse_proxy_fix.middleware import ReverseProxyPrefixFix + from .middleware import ReverseProxyPrefixFix except ImportError: - ReverseProxyPrefixFix = None + from bukuserver.middleware import ReverseProxyPrefixFix import click import flask from flask import __version__ as flask_version # type: ignore @@ -99,10 +99,7 @@ def create_app(db_file=None): if reverse_proxy_path.endswith('/'): print('Warning: reverse proxy path should not include trailing slash') app.config['REVERSE_PROXY_PATH'] = reverse_proxy_path - if ReverseProxyPrefixFix: - ReverseProxyPrefixFix(app) - else: - raise ImportError('Failed to import ReverseProxyPrefixFix') + ReverseProxyPrefixFix(app) bukudb = BukuDb(dbfile=app.config['BUKUSERVER_DB_FILE']) app.config['FLASK_ADMIN_SWATCH'] = (os.getenv('BUKUSERVER_THEME') or 'default').lower() app.config['BUKUSERVER_LOCALE'] = os.getenv('BUKUSERVER_LOCALE') or 'en' diff --git a/setup.py b/setup.py index e3cc33c6..4c769960 100644 --- a/setup.py +++ b/setup.py @@ -45,13 +45,6 @@ "Flask>=2.2.2,<2.3", "werkzeug<2.4", ] -reverse_proxy = " ".join( - [ - "flask-reverse-proxy-fix", - "@", - "https://github.com/rachmadaniHaryono/flask-reverse-proxy-fix/archive/refs/tags/v0.2.3.zip", - ] -) install_requires = [ 'beautifulsoup4>=4.4.1', 'certifi', @@ -82,9 +75,8 @@ 'console_scripts': ['buku=buku:main', 'bukuserver=bukuserver.server:cli'] }, extras_require={ - "tests": tests_require + server_require + [reverse_proxy], + "tests": tests_require + server_require, "server": server_require, - "reverse_proxy": [reverse_proxy], "docs": [ "myst-parser>=0.17.0", "sphinx-rtd-theme>=1.0.0", diff --git a/tests/.pylintrc b/tests/.pylintrc index 327a12ae..a4011132 100644 --- a/tests/.pylintrc +++ b/tests/.pylintrc @@ -2,6 +2,7 @@ disable= assigning-non-slot, broad-except, + c-extension-no-member, consider-using-f-string, consider-using-with, dangerous-default-value,