diff --git a/nixos/tests/powerdns-admin.nix b/nixos/tests/powerdns-admin.nix index 9165fb15de81..b5a703e9d8da 100644 --- a/nixos/tests/powerdns-admin.nix +++ b/nixos/tests/powerdns-admin.nix @@ -132,13 +132,13 @@ let # Login # Outputs 'Redirecting' if successful - curl -sSfb session http://127.0.0.1:8000/login \ + curl -sSf -b session -c session http://127.0.0.1:8000/login \ -F "_csrf_token=$csrf_token" \ -F "username=user" \ -F "password=password" | grep Redirecting # Check that we are logged in, this redirects to /admin/setting/pdns if we are - curl -sSfb session http://127.0.0.1:8000/dashboard/ | grep /admin/setting + curl -sSf -b session -c session http://127.0.0.1:8000/dashboard/ | grep /admin/setting ''; }; unix = { diff --git a/pkgs/by-name/po/powerdns-admin/0001-Fix-flask-2.3-issue.patch b/pkgs/by-name/po/powerdns-admin/0001-Fix-flask-2.3-issue.patch deleted file mode 100644 index 8645e0dbfa7d..000000000000 --- a/pkgs/by-name/po/powerdns-admin/0001-Fix-flask-2.3-issue.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 29b58e29c813d9bf0b31139a19b556614c28638e Mon Sep 17 00:00:00 2001 -From: Flakebi -Date: Sat, 2 Dec 2023 16:26:22 +0100 -Subject: [PATCH 1/6] Fix flask 2.3 issue - -'Blueprint' object has no attribute 'before_app_first_request' ---- - powerdnsadmin/routes/index.py | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/powerdnsadmin/routes/index.py b/powerdnsadmin/routes/index.py -index d56ce61..2176bd6 100644 ---- a/powerdnsadmin/routes/index.py -+++ b/powerdnsadmin/routes/index.py -@@ -46,7 +46,6 @@ index_bp = Blueprint('index', - url_prefix='/') - - --@index_bp.before_app_first_request - def register_modules(): - global google - global github --- -2.42.0 - diff --git a/pkgs/by-name/po/powerdns-admin/0002-Remove-cssrewrite-filter.patch b/pkgs/by-name/po/powerdns-admin/0002-Remove-cssrewrite-filter.patch index 9b442d5f3d7d..93085ba0375a 100644 --- a/pkgs/by-name/po/powerdns-admin/0002-Remove-cssrewrite-filter.patch +++ b/pkgs/by-name/po/powerdns-admin/0002-Remove-cssrewrite-filter.patch @@ -1,34 +1,25 @@ -From c60a9658fe2ca429327680fbffb86f609d98c52c Mon Sep 17 00:00:00 2001 -From: Flakebi -Date: Sat, 2 Dec 2023 16:27:49 +0100 -Subject: [PATCH 2/6] Remove cssrewrite filter - ---- - powerdnsadmin/assets.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - diff --git a/powerdnsadmin/assets.py b/powerdnsadmin/assets.py -index d46d431..3c582be 100644 +index b339c0e..6cf8087 100644 --- a/powerdnsadmin/assets.py +++ b/powerdnsadmin/assets.py -@@ -13,7 +13,7 @@ css_login = Bundle( +@@ -50,7 +50,7 @@ class ModernBrowserCssFilter(Filter): + css_login = Bundle( 'node_modules/@fortawesome/fontawesome-free/css/all.css', - 'node_modules/icheck/skins/square/blue.css', 'node_modules/admin-lte/dist/css/adminlte.css', -- filters=('rcssmin', 'cssrewrite'), -+ filters=('rcssmin'), +- filters=(ModernBrowserCssFilter, 'rcssmin', 'cssrewrite'), ++ filters=(ModernBrowserCssFilter, 'rcssmin'), output='generated/login.css') js_login = Bundle( -@@ -37,7 +37,7 @@ css_main = Bundle( +@@ -66,7 +66,7 @@ css_main = Bundle( 'node_modules/admin-lte/dist/css/adminlte.css', + 'node_modules/datatables.net-bs5/css/dataTables.bootstrap5.css', 'custom/css/custom.css', - 'node_modules/bootstrap-datepicker/dist/css/bootstrap-datepicker.css', -- filters=('rcssmin', 'cssrewrite'), -+ filters=('rcssmin'), +- filters=(ModernBrowserCssFilter, 'rcssmin', 'cssrewrite'), ++ filters=(ModernBrowserCssFilter, 'rcssmin'), output='generated/main.css') js_main = Bundle( -- -2.42.0 +2.43.0 diff --git a/pkgs/by-name/po/powerdns-admin/0003-Fix-flask-migrate-4.0-compatibility.patch b/pkgs/by-name/po/powerdns-admin/0003-Fix-flask-migrate-4.0-compatibility.patch deleted file mode 100644 index c9956ae22f75..000000000000 --- a/pkgs/by-name/po/powerdns-admin/0003-Fix-flask-migrate-4.0-compatibility.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 8c320a34bcca6dc2c1b423a1445235bf178b653e Mon Sep 17 00:00:00 2001 -From: Flakebi -Date: Sat, 2 Dec 2023 16:31:02 +0100 -Subject: [PATCH 3/6] Fix flask-migrate 4.0 compatibility - -See https://github.com/PowerDNS-Admin/PowerDNS-Admin/issues/1376 ---- - migrations/env.py | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/migrations/env.py b/migrations/env.py -index 4742e14..739d753 100755 ---- a/migrations/env.py -+++ b/migrations/env.py -@@ -73,7 +73,6 @@ def run_migrations_online(): - context.configure(connection=connection, - target_metadata=target_metadata, - process_revision_directives=process_revision_directives, -- render_as_batch=config.get_main_option('sqlalchemy.url').startswith('sqlite:'), - **current_app.extensions['migrate'].configure_args) - - try: --- -2.42.0 - diff --git a/pkgs/by-name/po/powerdns-admin/0004-Fix-flask-session-and-powerdns-admin-compatibility.patch b/pkgs/by-name/po/powerdns-admin/0004-Fix-flask-session-and-powerdns-admin-compatibility.patch deleted file mode 100644 index b1aaa8c531d1..000000000000 --- a/pkgs/by-name/po/powerdns-admin/0004-Fix-flask-session-and-powerdns-admin-compatibility.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 4b4ac26ef1cbb0b5b2354c251b216498325d0411 Mon Sep 17 00:00:00 2001 -From: Flakebi -Date: Sat, 2 Dec 2023 16:31:50 +0100 -Subject: [PATCH 4/6] Fix flask-session and powerdns-admin compatibility - -flask-session and powerdns-admin both try to add sqlalchemy to flask. -Reuse the database for flask-session. ---- - powerdnsadmin/__init__.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/powerdnsadmin/__init__.py b/powerdnsadmin/__init__.py -index d447a00..653af33 100755 ---- a/powerdnsadmin/__init__.py -+++ b/powerdnsadmin/__init__.py -@@ -60,6 +60,7 @@ def create_app(config=None): - if 'SESSION_TYPE' in os.environ: - app.config['SESSION_TYPE'] = os.environ.get('SESSION_TYPE') - -+ app.config['SESSION_SQLALCHEMY'] = models.base.db - sess = Session(app) - - # create sessions table if using sqlalchemy backend --- -2.42.0 - diff --git a/pkgs/by-name/po/powerdns-admin/0005-Fix-app-context-and-register-modules.patch b/pkgs/by-name/po/powerdns-admin/0005-Fix-app-context-and-register-modules.patch deleted file mode 100644 index 3004134a0ac4..000000000000 --- a/pkgs/by-name/po/powerdns-admin/0005-Fix-app-context-and-register-modules.patch +++ /dev/null @@ -1,58 +0,0 @@ -diff --git a/powerdnsadmin/__init__.py b/powerdnsadmin/__init__.py -index 660f96b..4d45c36 100755 ---- a/powerdnsadmin/__init__.py -+++ b/powerdnsadmin/__init__.py -@@ -72,10 +72,16 @@ def create_app(config=None): - # SMTP - app.mail = Mail(app) - -+ from powerdnsadmin.routes.index import register_modules -+ - # Load app's components - assets.init_app(app) - models.init_app(app) -- routes.init_app(app) -+ -+ with app.app_context(): -+ register_modules() -+ routes.init_app(app) -+ - services.init_app(app) - - # Register filters -diff --git a/powerdnsadmin/routes/index.py b/powerdnsadmin/routes/index.py -index 0918261..870d824 100644 ---- a/powerdnsadmin/routes/index.py -+++ b/powerdnsadmin/routes/index.py -@@ -52,11 +52,16 @@ def register_modules(): - global azure - global oidc - global saml -- google = google_oauth() -- github = github_oauth() -- azure = azure_oauth() -- oidc = oidc_oauth() -- saml = SAML() -+ -+ try: -+ google = google_oauth() -+ github = github_oauth() -+ azure = azure_oauth() -+ oidc = oidc_oauth() -+ saml = SAML() -+ except Exception: -+ # Database not ready yet, will initialize on first request -+ pass - - - @index_bp.before_request -@@ -65,6 +70,9 @@ def before_request(): - g.user = current_user - login_manager.anonymous_user = Anonymous - -+ if google is None: -+ register_modules() -+ - # Check site is in maintenance mode - maintenance = Setting().get('maintenance') - if maintenance and current_user.is_authenticated and current_user.role.name not in [ diff --git a/pkgs/by-name/po/powerdns-admin/0006-Fix-regex.patch b/pkgs/by-name/po/powerdns-admin/0006-Fix-regex.patch deleted file mode 100644 index 2906d3709b04..000000000000 --- a/pkgs/by-name/po/powerdns-admin/0006-Fix-regex.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/powerdnsadmin/lib/utils.py b/powerdnsadmin/lib/utils.py -index f8cc997..0de4c5c 100644 ---- a/powerdnsadmin/lib/utils.py -+++ b/powerdnsadmin/lib/utils.py -@@ -121,7 +121,7 @@ def display_record_name(data): - if record_name == domain_name: - return '@' - else: -- return re.sub('\.{}$'.format(domain_name), '', record_name) -+ return re.sub(r'\.{}$'.format(domain_name), '', record_name) - - - def display_master_name(data): -diff --git a/powerdnsadmin/models/domain.py b/powerdnsadmin/models/domain.py -index f0b9a30..84c6d1b 100644 ---- a/powerdnsadmin/models/domain.py -+++ b/powerdnsadmin/models/domain.py -@@ -482,24 +482,24 @@ class Domain(db.Model): - if re.search('ip6.arpa', reverse_host_address): - for i in range(1, 32, 1): - address = re.search( -- '((([a-f0-9]\.){' + str(i) + '})(?P.+6.arpa)\.?)', -+ r'((([a-f0-9]\.){' + str(i) + r'})(?P.+6\.arpa)\.?)', - reverse_host_address) - if None != self.get_id_by_name(address.group('ipname')): - c = i - break - return re.search( -- '((([a-f0-9]\.){' + str(c) + '})(?P.+6.arpa)\.?)', -+ r'((([a-f0-9]\.){' + str(c) + r'})(?P.+6\.arpa)\.?)', - reverse_host_address).group('ipname') - else: - for i in range(1, 4, 1): - address = re.search( -- '((([0-9]+\.){' + str(i) + '})(?P.+r.arpa)\.?)', -+ r'((([0-9]+\.){' + str(i) + r'})(?P.+r\.arpa)\.?)', - reverse_host_address) - if None != self.get_id_by_name(address.group('ipname')): - c = i - break - return re.search( -- '((([0-9]+\.){' + str(c) + '})(?P.+r.arpa)\.?)', -+ r'((([0-9]+\.){' + str(c) + r'})(?P.+r\.arpa)\.?)', - reverse_host_address).group('ipname') - - def delete(self, domain_name): diff --git a/pkgs/by-name/po/powerdns-admin/0007-Fix-oidc.patch b/pkgs/by-name/po/powerdns-admin/0007-Fix-oidc.patch deleted file mode 100644 index 39623650cd9d..000000000000 --- a/pkgs/by-name/po/powerdns-admin/0007-Fix-oidc.patch +++ /dev/null @@ -1,48 +0,0 @@ -diff --git a/powerdnsadmin/routes/index.py b/powerdnsadmin/routes/index.py -index 23d88bb..edfab3f 100644 ---- a/powerdnsadmin/routes/index.py -+++ b/powerdnsadmin/routes/index.py -@@ -392,11 +392,38 @@ def login(): - return authenticate_user(user, 'Azure OAuth') - - if 'oidc_token' in session: -- user_data = json.loads(oidc.get('userinfo').text) -- oidc_username = user_data[Setting().get('oidc_oauth_username')] -- oidc_first_name = user_data[Setting().get('oidc_oauth_firstname')] -- oidc_last_name = user_data[Setting().get('oidc_oauth_last_name')] -- oidc_email = user_data[Setting().get('oidc_oauth_email')] -+ try: -+ oidc_metadata = oidc.load_server_metadata() -+ except Exception as e: -+ current_app.logger.warning( -+ 'OIDC: unable to load server metadata ({}); ' -+ 'falling back to relative userinfo endpoint'.format(e)) -+ oidc_metadata = {} -+ -+ userinfo_endpoint = oidc_metadata.get('userinfo_endpoint') -+ try: -+ if userinfo_endpoint: -+ userinfo_resp = oidc.get(userinfo_endpoint, timeout=15) -+ else: -+ userinfo_resp = oidc.get('userinfo', timeout=15) -+ userinfo_resp.raise_for_status() -+ user_data = userinfo_resp.json() -+ except Exception as e: -+ current_app.logger.error('OIDC: failed to fetch userinfo: {}'.format(e)) -+ session.pop('oidc_token', None) -+ return redirect(url_for('index.login')) -+ -+ oidc_username = user_data.get(Setting().get('oidc_oauth_username')) -+ oidc_first_name = user_data.get(Setting().get('oidc_oauth_firstname'), '') -+ oidc_last_name = user_data.get(Setting().get('oidc_oauth_last_name'), '') -+ oidc_email = user_data.get(Setting().get('oidc_oauth_email'), '') -+ -+ if not oidc_username: -+ current_app.logger.error( -+ 'OIDC: username claim "{}" not present in userinfo'.format( -+ Setting().get('oidc_oauth_username'))) -+ session.pop('oidc_token', None) -+ return redirect(url_for('index.login')) - - user = User.query.filter_by(username=oidc_username).first() - if not user: diff --git a/pkgs/by-name/po/powerdns-admin/0008-Fix-profile-save-overwriting-password-with-empty-val.patch b/pkgs/by-name/po/powerdns-admin/0008-Fix-profile-save-overwriting-password-with-empty-val.patch deleted file mode 100644 index 22479605cd90..000000000000 --- a/pkgs/by-name/po/powerdns-admin/0008-Fix-profile-save-overwriting-password-with-empty-val.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/powerdnsadmin/models/user.py b/powerdnsadmin/models/user.py -index 42f894f..f9d845e 100644 ---- a/powerdnsadmin/models/user.py -+++ b/powerdnsadmin/models/user.py -@@ -435,7 +435,7 @@ class User(db.Model): - name='Administrator').first().id - - if hasattr(self, "plain_text_password"): -- if self.plain_text_password != None: -+ if self.plain_text_password: - self.password = self.get_hashed_password( - self.plain_text_password) - else: -@@ -476,7 +476,7 @@ class User(db.Model): - - # store new password hash (only if changed) - if hasattr(self, "plain_text_password"): -- if self.plain_text_password != None: -+ if self.plain_text_password: - user.password = self.get_hashed_password( - self.plain_text_password).decode("utf-8") - -@@ -495,7 +495,7 @@ class User(db.Model): - user.lastname = self.lastname if self.lastname else user.lastname - - if hasattr(self, "plain_text_password"): -- if self.plain_text_password != None: -+ if self.plain_text_password: - user.password = self.get_hashed_password( - self.plain_text_password).decode("utf-8") diff --git a/pkgs/by-name/po/powerdns-admin/package.nix b/pkgs/by-name/po/powerdns-admin/package.nix index 424fc71278cd..8c680e97449c 100644 --- a/pkgs/by-name/po/powerdns-admin/package.nix +++ b/pkgs/by-name/po/powerdns-admin/package.nix @@ -2,23 +2,29 @@ lib, stdenv, fetchFromGitHub, - fetchYarnDeps, - yarnConfigHook, + yarn-berry_4-fetcher, nixosTests, writeText, + runCommand, python3, }: let pname = "powerdns-admin"; - version = "0.4.2"; + version = "0.6.1"; src = fetchFromGitHub { owner = "PowerDNS-Admin"; repo = "PowerDNS-Admin"; tag = "v${version}"; - hash = "sha256-q9mt8wjSNFb452Xsg+qhNOWa03KJkYVGAeCWVSzZCyk="; + hash = "sha256-VhUz3Uw2MKN7rJgCrFd5nSN8FVTHM6LHCc01scMNjbc="; }; + inherit (yarn-berry_4-fetcher) fetchYarnBerryDeps yarnBerryConfigHook; + + yarnLock = runCommand "yarn-v9.lock" { } '' + sed -e 's/^ version: 8$/ version: 9/' ${src}/yarn.lock > $out + ''; + python = python3; pythonDeps = with python.pkgs; [ @@ -69,36 +75,50 @@ let standard-imghdr ]; - all_patches = [ - ./0001-Fix-flask-2.3-issue.patch - ]; - assets = stdenv.mkDerivation { pname = "${pname}-assets"; inherit version src; - offlineCache = fetchYarnDeps { - yarnLock = "${src}/yarn.lock"; - hash = "sha256-rXIts+dgOuZQGyiSke1NIG7b4lFlR/Gfu3J6T3wP3aY="; + offlineCache = fetchYarnBerryDeps { + inherit yarnLock; + hash = "sha256-VVew6/rjc0Uz6xM2komL9Sceym3vFrGnAqrdLtGxQVI="; }; + postPatch = '' + cp ${yarnLock} yarn.lock + # flask-assets needs a real node_modules tree + printf 'nodeLinker: node-modules\n' >> .yarnrc.yml + ''; + nativeBuildInputs = [ - yarnConfigHook + yarnBerryConfigHook ] ++ pythonDeps; - patches = all_patches ++ [ + + patches = [ ./0002-Remove-cssrewrite-filter.patch ]; buildPhase = '' + runHook preBuild + + if [ -d node_modules ] && [ ! -d powerdnsadmin/static/node_modules ]; then + mv node_modules powerdnsadmin/static/node_modules + fi + SESSION_TYPE=filesystem FLASK_APP=./powerdnsadmin/__init__.py flask assets build + + runHook postBuild ''; installPhase = '' + runHook preInstall + # https://github.com/PowerDNS-Admin/PowerDNS-Admin/blob/54b257768f600c5548a1c7e50eac49c40df49f92/docker/Dockerfile#L43 mkdir $out cp -r powerdnsadmin/static/{generated,assets,img} $out find powerdnsadmin/static/node_modules -name webfonts -exec cp -r {} $out \; -printf "Copying %P\n" find powerdnsadmin/static/node_modules -name fonts -exec cp -r {} $out \; -printf "Copying %P\n" - find powerdnsadmin/static/node_modules/icheck/skins/square -name '*.png' -exec cp {} $out/generated \; + + runHook postInstall ''; }; @@ -128,15 +148,6 @@ stdenv.mkDerivation { exec python -m gunicorn.app.wsgiapp "powerdnsadmin:create_app()" "$@" ''; - patches = all_patches ++ [ - ./0003-Fix-flask-migrate-4.0-compatibility.patch - ./0004-Fix-flask-session-and-powerdns-admin-compatibility.patch - ./0005-Fix-app-context-and-register-modules.patch - ./0006-Fix-regex.patch - ./0007-Fix-oidc.patch - ./0008-Fix-profile-save-overwriting-password-with-empty-val.patch - ]; - postPatch = '' rm -r powerdnsadmin/static powerdnsadmin/assets.py ''; @@ -162,6 +173,8 @@ stdenv.mkDerivation { runHook postInstall ''; + __darwinAllowLocalNetworking = true; + passthru = { # PYTHONPATH of all dependencies used by the package pythonPath = python3.pkgs.makePythonPath pythonDeps;