From f195733c0d66a191d7cdb783af525bda350023be Mon Sep 17 00:00:00 2001 From: master3395 Date: Thu, 26 Mar 2026 15:09:03 +0100 Subject: [PATCH] pluginHolder: auto-persist activation keys from plugin settings pages. Inject a lightweight fetch hook into settings pages to call store-activation after successful plugin activation responses, reducing premium relock risk after upgrades. --- pluginHolder/views.py | 81 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/pluginHolder/views.py b/pluginHolder/views.py index c4eb092bf..07545cc56 100644 --- a/pluginHolder/views.py +++ b/pluginHolder/views.py @@ -2106,7 +2106,8 @@ def plugin_settings_proxy(request, plugin_name): for candidate in ('settings', 'settings_view', 'settings_simple', 'unified_settings'): settings_view = getattr(views_mod, candidate, None) if callable(settings_view): - return settings_view(request) + response = settings_view(request) + return _inject_activation_store_hook(response, plugin_name) except ModuleNotFoundError as e: last_err = str(e) continue @@ -2123,6 +2124,84 @@ def plugin_settings_proxy(request, plugin_name): return HttpResponseNotFound('Plugin not found.') +def _inject_activation_store_hook(response, plugin_name): + """ + Tiny safety hook for plugin settings pages: + if a plugin activation request succeeds client-side, persist the key in + CyberPanel DB via /plugins/api/store-activation//. + """ + try: + content_type = (response.get('Content-Type', '') or '').lower() + if 'text/html' not in content_type: + return response + body = response.content.decode('utf-8', errors='ignore') + hook_script = """ + +""" % json.dumps(plugin_name) + if '' in body: + body = body.replace('', hook_script + '') + else: + body += hook_script + response.content = body.encode('utf-8') + return response + except Exception: + return response + + def plugin_help(request, plugin_name): """Plugin-specific help page - shows plugin information, version history, and help content""" mailUtilities.checkHome()