From 1f083b335f1a075d66a47fc4eb75f46659aa6baa Mon Sep 17 00:00:00 2001 From: MacRimi Date: Sun, 2 Nov 2025 00:37:59 +0100 Subject: [PATCH] Update remove banner v3 --- scripts/global/remove-banner-pve-v3.sh | 131 +++++++++-- scripts/global/remove-banner-pve-v3_.sh | 277 ++++++++++++++++++++++++ 2 files changed, 385 insertions(+), 23 deletions(-) create mode 100644 scripts/global/remove-banner-pve-v3_.sh diff --git a/scripts/global/remove-banner-pve-v3.sh b/scripts/global/remove-banner-pve-v3.sh index f5b80e3..56d4d2b 100644 --- a/scripts/global/remove-banner-pve-v3.sh +++ b/scripts/global/remove-banner-pve-v3.sh @@ -100,8 +100,16 @@ verify_js_integrity() { patch_checked_command() { [ -f "$JS_FILE" ] || return 0 - # Check if already patched - grep -q "$MARK" "$JS_FILE" && return 0 + # Check if already patched - look for our marker + if grep -q "$MARK" "$JS_FILE"; then + # Verify the patch is actually applied by checking if function is simplified + if grep -A 2 "checked_command: function" "$JS_FILE" | grep -q "orig_cmd();"; then + return 0 + else + # Marker exists but patch not applied - remove marker and try again + sed -i "/$MARK/d" "$JS_FILE" + fi + fi # Create backup mkdir -p "$BACKUP_DIR" @@ -111,27 +119,105 @@ patch_checked_command() { # Set trap to restore on error trap "cp -a '$backup' '$JS_FILE' 2>/dev/null || true" ERR + # Use Python to replace the entire checked_command function using brace counting + python3 <<'PYTHON_END' +import sys + +js_file = "/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" + +try: + with open(js_file, 'r', encoding='utf-8') as f: + lines = f.readlines() + + # Find the line with checked_command + start_line = -1 + for i, line in enumerate(lines): + if 'checked_command: function' in line or 'checked_command:function' in line: + start_line = i + break + + if start_line == -1: + print("checked_command function not found", file=sys.stderr) + sys.exit(1) + + # Count braces to find the end of the function + brace_count = 0 + end_line = -1 + started_counting = False + + for i in range(start_line, len(lines)): + line = lines[i] + + # Count opening and closing braces + for char in line: + if char == '{': + brace_count += 1 + started_counting = True + elif char == '}': + brace_count -= 1 + + # When we reach 0 and we've started counting, we found the end + if started_counting and brace_count == 0: + # Check if this line ends with "}," which is the function closure + if '},' in line or '},\n' in line: + end_line = i + break + + if end_line == -1: + print("Could not find end of checked_command function", file=sys.stderr) + sys.exit(1) + + # Get the indentation of the original function + indent = len(lines[start_line]) - len(lines[start_line].lstrip()) + indent_str = ' ' * indent + + # Create the replacement function (simple version that just calls orig_cmd) + replacement = [ + f"{indent_str}checked_command: function (orig_cmd) {{\n", + f"{indent_str} orig_cmd();\n", + f"{indent_str}}},\n" + ] + + # Replace the function + new_lines = lines[:start_line] + replacement + lines[end_line+1:] + + # Write the modified content + with open(js_file, 'w', encoding='utf-8') as f: + f.writelines(new_lines) + + #print(f"Successfully replaced lines {start_line+1} to {end_line+1}") + sys.exit(0) + +except Exception as e: + print(f"Python patch error: {e}", file=sys.stderr) + import traceback + traceback.print_exc(file=sys.stderr) + sys.exit(1) +PYTHON_END + + local python_result=$? + + if [ $python_result -ne 0 ]; then + # Python failed, restore backup + cp -a "$backup" "$JS_FILE" + trap - ERR + return 1 + fi + + # Verify the patch was applied + if ! grep -A 2 "checked_command: function" "$JS_FILE" | grep -q "orig_cmd();"; then + cp -a "$backup" "$JS_FILE" + trap - ERR + return 1 + fi + # Add patch marker at the beginning sed -i "1s|^|$MARK\n|" "$JS_FILE" - # Surgical patch: Change the condition in checked_command function - # This changes the if condition to 'if (false)' making the banner never show - if grep -q "res\.data\.status\.toLowerCase() !== 'active'" "$JS_FILE"; then - # Pattern for newer versions (8.4.5+) - sed -i "/checked_command: function/,/},$/s/res === null || res === undefined || !res || res\.data\.status\.toLowerCase() !== 'active'/false/g" "$JS_FILE" - elif grep -q "res\.data\.status !== 'Active'" "$JS_FILE"; then - # Pattern for older versions - sed -i "/checked_command: function/,/},$/s/res === null || res === undefined || !res || res\.data\.status !== 'Active'/false/g" "$JS_FILE" - fi - - # Also handle the NoMoreNagging pattern if present - if grep -q "res\.data\.status\.toLowerCase() !== 'NoMoreNagging'" "$JS_FILE"; then - sed -i "/checked_command: function/,/},$/s/res === null || res === undefined || !res || res\.data\.status\.toLowerCase() !== 'NoMoreNagging'/false/g" "$JS_FILE" - fi - # Verify integrity after patch if ! verify_js_integrity "$JS_FILE"; then cp -a "$backup" "$JS_FILE" + trap - ERR return 1 fi @@ -217,6 +303,7 @@ EOFAPT # Verify APT hook syntax apt-config dump >/dev/null 2>&1 || { + msg_warn "APT hook syntax issue, removing..." rm -f "$APT_HOOK" } } @@ -226,7 +313,7 @@ remove_subscription_banner_v3() { local pve_version pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1 || echo "unknown") - msg_info "$(translate "Detected Proxmox VE") ${pve_version} - $(translate "applying banner patch")" + msg_info "$(translate "Detected Proxmox VE") ${pve_version} - $(translate "applying minimal banner patch")" @@ -239,16 +326,14 @@ remove_subscription_banner_v3() { local backup_file backup_file=$(create_backup "$JS_FILE") if [ -n "$backup_file" ]; then - # msg_ok "$(translate "Desktop UI backup created"): $backup_file" - : + msg_ok "$(translate "Desktop UI backup created")" fi if [ -f "$MOBILE_UI_FILE" ]; then local mobile_backup mobile_backup=$(create_backup "$MOBILE_UI_FILE") if [ -n "$mobile_backup" ]; then - # msg_ok "$(translate "Mobile UI backup created"): $mobile_backup" - : + msg_ok "$(translate "Mobile UI backup created")" fi fi @@ -263,7 +348,7 @@ remove_subscription_banner_v3() { fi # Register tool as applied - register_tool "subscription_banner" true + register_tool "subscription_banner_v3" true msg_ok "$(translate "Subscription banner removed successfully")" msg_ok "$(translate "Desktop and Mobile UI patched")" diff --git a/scripts/global/remove-banner-pve-v3_.sh b/scripts/global/remove-banner-pve-v3_.sh new file mode 100644 index 0000000..f5b80e3 --- /dev/null +++ b/scripts/global/remove-banner-pve-v3_.sh @@ -0,0 +1,277 @@ +#!/bin/bash +# ========================================================== +# Remove Subscription Banner - Proxmox VE (v3 - Minimal Intrusive) +# ========================================================== +# This version makes a surgical change to the checked_command function +# by changing the condition to 'if (false)' and commenting out the banner logic. +# Also patches the mobile UI to remove the subscription dialog. +# ========================================================== + +set -euo pipefail + +# Source utilities if available +BASE_DIR="/usr/local/share/proxmenux" +UTILS_FILE="$BASE_DIR/utils.sh" +TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json" + +if [[ -f "$UTILS_FILE" ]]; then + source "$UTILS_FILE" +fi + +load_language +initialize_cache + +# File paths +JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" +GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz" +MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js" +MOBILE_UI_FILE="/usr/share/pve-yew-mobile-gui/index.html.tpl" +BACKUP_DIR="$BASE_DIR/backups" +APT_HOOK="/etc/apt/apt.conf.d/no-nag-script" +PATCH_BIN="/usr/local/bin/pve-remove-nag-v3.sh" +MARK="/* PROXMENUX_NAG_PATCH_V3 */" +MOBILE_MARK="" + +# Ensure tools JSON exists +ensure_tools_json() { + [ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON" +} + +# Register tool in JSON +register_tool() { + command -v jq >/dev/null 2>&1 || return 0 + local tool="$1" state="$2" + ensure_tools_json + jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" \ + > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON" +} + +# Verify JS file integrity +verify_js_integrity() { + local file="$1" + [ -f "$file" ] || return 1 + [ -s "$file" ] || return 1 + grep -Eq 'Ext|function|var|const|let' "$file" || return 1 + if LC_ALL=C grep -qP '\x00' "$file" 2>/dev/null; then + return 1 + fi + return 0 +} + +# Create timestamped backup +create_backup() { + local file="$1" + local timestamp + timestamp=$(date +%Y%m%d_%H%M%S) + local backup_file="$BACKUP_DIR/$(basename "$file").backup.$timestamp" + + mkdir -p "$BACKUP_DIR" + + if [ -f "$file" ]; then + rm -f "$BACKUP_DIR"/"$(basename "$file")".backup.* 2>/dev/null || true + + cp -a "$file" "$backup_file" + echo "$backup_file" + fi +} + +# Create the patch script that will be called by APT hook +create_patch_script() { + cat > "$PATCH_BIN" <<'EOFPATCH' +#!/usr/bin/env bash +# ========================================================== +# Proxmox Subscription Banner Patch (v3 - Minimal) +# ========================================================== +set -euo pipefail + +JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" +GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz" +MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js" +MOBILE_UI_FILE="/usr/share/pve-yew-mobile-gui/index.html.tpl" +BACKUP_DIR="/usr/local/share/proxmenux/backups" +MARK="/* PROXMENUX_NAG_PATCH_V3 */" +MOBILE_MARK="" + +verify_js_integrity() { + local file="$1" + [ -f "$file" ] && [ -s "$file" ] && grep -Eq 'Ext|function' "$file" && ! LC_ALL=C grep -qP '\x00' "$file" 2>/dev/null +} + +patch_checked_command() { + [ -f "$JS_FILE" ] || return 0 + + # Check if already patched + grep -q "$MARK" "$JS_FILE" && return 0 + + # Create backup + mkdir -p "$BACKUP_DIR" + local backup="$BACKUP_DIR/$(basename "$JS_FILE").backup.$(date +%Y%m%d_%H%M%S)" + cp -a "$JS_FILE" "$backup" + + # Set trap to restore on error + trap "cp -a '$backup' '$JS_FILE' 2>/dev/null || true" ERR + + # Add patch marker at the beginning + sed -i "1s|^|$MARK\n|" "$JS_FILE" + + # Surgical patch: Change the condition in checked_command function + # This changes the if condition to 'if (false)' making the banner never show + if grep -q "res\.data\.status\.toLowerCase() !== 'active'" "$JS_FILE"; then + # Pattern for newer versions (8.4.5+) + sed -i "/checked_command: function/,/},$/s/res === null || res === undefined || !res || res\.data\.status\.toLowerCase() !== 'active'/false/g" "$JS_FILE" + elif grep -q "res\.data\.status !== 'Active'" "$JS_FILE"; then + # Pattern for older versions + sed -i "/checked_command: function/,/},$/s/res === null || res === undefined || !res || res\.data\.status !== 'Active'/false/g" "$JS_FILE" + fi + + # Also handle the NoMoreNagging pattern if present + if grep -q "res\.data\.status\.toLowerCase() !== 'NoMoreNagging'" "$JS_FILE"; then + sed -i "/checked_command: function/,/},$/s/res === null || res === undefined || !res || res\.data\.status\.toLowerCase() !== 'NoMoreNagging'/false/g" "$JS_FILE" + fi + + # Verify integrity after patch + if ! verify_js_integrity "$JS_FILE"; then + cp -a "$backup" "$JS_FILE" + return 1 + fi + + # Clean up generated files + rm -f "$MIN_JS_FILE" "$GZ_FILE" 2>/dev/null || true + find /var/cache/pve-manager/ -name "*.js*" -delete 2>/dev/null || true + find /var/lib/pve-manager/ -name "*.js*" -delete 2>/dev/null || true + find /var/cache/nginx/ -type f -delete 2>/dev/null || true + + trap - ERR + return 0 +} + +patch_mobile_ui() { + [ -f "$MOBILE_UI_FILE" ] || return 0 + + # Check if already patched + grep -q "$MOBILE_MARK" "$MOBILE_UI_FILE" && return 0 + + # Create backup + mkdir -p "$BACKUP_DIR" + local backup="$BACKUP_DIR/$(basename "$MOBILE_UI_FILE").backup.$(date +%Y%m%d_%H%M%S)" + cp -a "$MOBILE_UI_FILE" "$backup" + + # Set trap to restore on error + trap "cp -a '$backup' '$MOBILE_UI_FILE' 2>/dev/null || true" ERR + + # Insert the script before tag + sed -i "/<\/head>/i\\ +$MOBILE_MARK\\ + \\ + " "$MOBILE_UI_FILE" + + trap - ERR + return 0 +} + +reload_services() { + systemctl is-active --quiet pveproxy 2>/dev/null && { + systemctl reload pveproxy 2>/dev/null || systemctl restart pveproxy 2>/dev/null || true + } + systemctl is-active --quiet nginx 2>/dev/null && { + systemctl reload nginx 2>/dev/null || true + } + systemctl is-active --quiet pvedaemon 2>/dev/null && { + systemctl reload pvedaemon 2>/dev/null || true + } +} + +main() { + patch_checked_command || return 1 + patch_mobile_ui || true + reload_services +} + +main +EOFPATCH + + chmod 755 "$PATCH_BIN" +} + +# Create APT hook to reapply patch after updates +create_apt_hook() { + cat > "$APT_HOOK" <<'EOFAPT' +/* ProxMenux: reapply minimal nag patch after upgrades */ +DPkg::Post-Invoke { "/usr/local/bin/pve-remove-nag-v3.sh || true"; }; +EOFAPT + + chmod 644 "$APT_HOOK" + + # Verify APT hook syntax + apt-config dump >/dev/null 2>&1 || { + rm -f "$APT_HOOK" + } +} + +# Main function to remove subscription banner +remove_subscription_banner_v3() { + local pve_version + pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1 || echo "unknown") + + msg_info "$(translate "Detected Proxmox VE") ${pve_version} - $(translate "applying banner patch")" + + + + # Remove old APT hooks + for f in /etc/apt/apt.conf.d/*nag*; do + [[ -e "$f" ]] && rm -f "$f" + done + + # Create backup for desktop UI + local backup_file + backup_file=$(create_backup "$JS_FILE") + if [ -n "$backup_file" ]; then + # msg_ok "$(translate "Desktop UI backup created"): $backup_file" + : + fi + + if [ -f "$MOBILE_UI_FILE" ]; then + local mobile_backup + mobile_backup=$(create_backup "$MOBILE_UI_FILE") + if [ -n "$mobile_backup" ]; then + # msg_ok "$(translate "Mobile UI backup created"): $mobile_backup" + : + fi + fi + + # Create patch script and APT hook + create_patch_script + create_apt_hook + + # Apply the patch + if ! "$PATCH_BIN"; then + msg_error "$(translate "Error applying patch. Backups preserved at"): $BACKUP_DIR" + return 1 + fi + + # Register tool as applied + register_tool "subscription_banner" true + + msg_ok "$(translate "Subscription banner removed successfully")" + msg_ok "$(translate "Desktop and Mobile UI patched")" + msg_ok "$(translate "Refresh your browser (Ctrl+Shift+R) to see changes")" + +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + remove_subscription_banner_v3 +fi