Files
proxmox-nag-remover/proxmox-nag-remover.sh
mike d2e04a4730 Fix apt hook logic to properly persist nag removal after updates
1. Fixed the apt hook logic
The original script used dpkg -V with backwards logic. The new version directly checks if nag patterns are present in the files using grep, which is much more reliable:

2. More robust pattern matching
Added multiple sed patterns to catch different variations of how the subscription check might be written:

data.status !== 'active'
data.status!=='active'
data.status != 'active'
data.status!='active'

3. Better testing and validation
The script now includes a test_current_fix() function that verifies whether nags are actually present and whether the fix is working.

4. Improved error handling
Better feedback about what's happening and whether the fix is working correctly.
2025-08-13 21:24:13 +00:00

381 lines
13 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Universal Proxmox Subscription Nag Remover - Improved Version
# Works with PVE (Proxmox VE), PBS (Proxmox Backup Server), and PMG (Proxmox Mail Gateway)
#
# Based on community-scripts by tteck and contributors
# Original scripts: https://community-scripts.github.io/ProxmoxVE/
# License: MIT
# Copyright (c) 2021-2025 community-scripts contributors
set -euo pipefail
# Colors for output
RD=$(echo "\033[01;31m")
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
BL=$(echo "\033[94m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
CROSS="${RD}${CL}"
INFO="${BL}${CL}"
# Output functions
msg_info() {
local msg="$1"
echo -ne " ${HOLD} ${YW}${msg}..."
}
msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}
msg_error() {
local msg="$1"
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
}
msg_note() {
local msg="$1"
echo -e " ${INFO} ${BL}${msg}${CL}"
}
# Header
header_info() {
clear
cat <<"EOF"
╔═════════════════════════════════════════════════════════════════════════════╗
║ Universal Proxmox Nag Remover - Improved ║
║ PVE • PBS • PMG Support ║
╚═════════════════════════════════════════════════════════════════════════════╝
EOF
echo -e "${BL}Universal Subscription Nag Remover for All Proxmox Products${CL}"
echo -e "${YW}Based on community-scripts: https://community-scripts.github.io/ProxmoxVE/${CL}"
echo ""
}
# Detect Proxmox product
detect_proxmox() {
local product=""
local version=""
if command -v pveversion >/dev/null 2>&1; then
product="PVE"
version=$(pveversion | head -1)
elif command -v proxmox-backup-manager >/dev/null 2>&1; then
product="PBS"
version=$(proxmox-backup-manager version 2>/dev/null | head -1 || echo "PBS detected")
elif command -v pmgversion >/dev/null 2>&1; then
product="PMG"
version=$(pmgversion | head -1)
elif [ -f /usr/bin/pmg-admin ]; then
product="PMG"
version="PMG detected"
else
msg_error "No supported Proxmox product detected"
echo ""
echo "This script supports:"
echo " • Proxmox VE (PVE)"
echo " • Proxmox Backup Server (PBS)"
echo " • Proxmox Mail Gateway (PMG)"
exit 1
fi
echo "$product|$version"
}
# Function to apply nag removal to files
apply_nag_patch() {
local file="$1"
local backup_file="${file}.backup-$(date +%s)"
if [ -f "$file" ]; then
# Create backup
cp "$file" "$backup_file"
# Apply multiple patterns to catch different variations
sed -i.tmp \
-e "s/data\.status !== 'active'/false/g" \
-e "s/data\.status!=='active'/false/g" \
-e "s/data\.status != 'active'/false/g" \
-e "s/data\.status!='active'/false/g" \
-e "s/checked_command: 'subscription'/checked_command: 'no-subscription'/g" \
-e "/getNoSubKeyHtml.*{/,/},/{s/text: gettext('No valid subscription')/text: ''/g}" \
-e "s/'No valid subscription'/''/g" \
-e "/.*data\.status.*{/{s/\!//g; s/active/NoMoreNagging/g}" \
"$file"
# Clean up tmp file
rm -f "${file}.tmp"
echo "Patched: $file"
return 0
else
echo "File not found: $file"
return 1
fi
}
# Check if nag is present in file
check_nag_present() {
local file="$1"
if [ -f "$file" ]; then
grep -q "No valid subscription\|data\.status.*active" "$file" 2>/dev/null
else
return 1
fi
}
# Apply nag removal based on product
apply_nag_removal() {
local product="$1"
case $product in
PVE)
msg_info "Applying PVE subscription nag removal"
# More robust apt hook for PVE
cat > /etc/apt/apt.conf.d/no-nag-script << 'EOF'
DPkg::Post-Invoke {
"if [ -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ]; then
if grep -q 'No valid subscription\\|data\\.status.*active' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js 2>/dev/null; then
echo 'Reapplying PVE subscription nag removal...';
sed -i \
-e 's/data\\.status !== '\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status!==='\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status != '\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status!='\"'\"'active'\"'\"'/false/g' \
-e 's/checked_command: '\"'\"'subscription'\"'\"'/checked_command: '\"'\"'no-subscription'\"'\"'/g' \
-e '/getNoSubKeyHtml.*{/,/},/{s/text: gettext('\"'\"'No valid subscription'\"'\"')/text: '\"'\"''\"'\"'/g}' \
-e 's/'\"'\"'No valid subscription'\"'\"'/'\"'\"''\"'\"'/g' \
-e '/.*data\\.status.*{/{s/\\!//g; s/active/NoMoreNagging/g}' \
/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js;
echo 'PVE nag removal reapplied successfully.';
fi;
fi";
};
EOF
# Apply initial patch
apply_nag_patch "/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
msg_ok "PVE subscription nag removal applied"
;;
PBS)
msg_info "Applying PBS subscription nag removal"
# More robust apt hook for PBS
cat > /etc/apt/apt.conf.d/no-nag-script << 'EOF'
DPkg::Post-Invoke {
"if [ -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ]; then
if grep -q 'No valid subscription\\|data\\.status.*active' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js 2>/dev/null; then
echo 'Reapplying PBS subscription nag removal...';
sed -i \
-e 's/data\\.status !== '\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status!==='\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status != '\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status!='\"'\"'active'\"'\"'/false/g' \
-e '/data\\.status.*{/{s/\\!//g; s/active/NoMoreNagging/g}' \
/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js;
echo 'PBS nag removal reapplied successfully.';
fi;
fi";
};
EOF
# Apply initial patch
apply_nag_patch "/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
msg_ok "PBS subscription nag removal applied"
;;
PMG)
msg_info "Applying PMG subscription nag removal"
# More robust apt hook for PMG (both desktop and mobile)
cat > /etc/apt/apt.conf.d/no-nag-script << 'EOF'
DPkg::Post-Invoke {
"if [ -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ]; then
if grep -q 'No valid subscription\\|data\\.status.*active' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js 2>/dev/null; then
echo 'Reapplying PMG subscription nag removal (desktop)...';
sed -i \
-e 's/data\\.status !== '\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status!==='\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status != '\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status!='\"'\"'active'\"'\"'/false/g' \
-e '/.*data\\.status.*{/{s/\\!//g; s/active/NoMoreNagging/g}' \
/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js;
echo 'PMG desktop nag removal reapplied successfully.';
fi;
fi;
if [ -f /usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js ]; then
if grep -q 'No valid subscription\\|data\\.status.*active' /usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js 2>/dev/null; then
echo 'Reapplying PMG subscription nag removal (mobile)...';
sed -i \
-e 's/data\\.status !== '\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status!==='\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status != '\"'\"'active'\"'\"'/false/g' \
-e 's/data\\.status!='\"'\"'active'\"'\"'/false/g' \
-e '/data\\.status.*{/{s/\\!//g; s/active/NoMoreNagging/g}' \
/usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js;
echo 'PMG mobile nag removal reapplied successfully.';
fi;
fi";
};
EOF
# Apply initial patches
apply_nag_patch "/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
apply_nag_patch "/usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js"
msg_ok "PMG subscription nag removal applied (desktop & mobile)"
;;
esac
}
# Test if the current fix is working
test_current_fix() {
local product="$1"
local files_to_check=()
case $product in
PVE|PBS)
files_to_check=("/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js")
;;
PMG)
files_to_check=(
"/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
"/usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js"
)
;;
esac
local nag_found=false
for file in "${files_to_check[@]}"; do
if check_nag_present "$file"; then
nag_found=true
echo "⚠ Nag still present in: $file"
fi
done
if [ "$nag_found" = false ]; then
echo "✓ No subscription nags detected in relevant files"
return 0
else
return 1
fi
}
# Main execution
main() {
# Check if running as root
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root (use sudo)"
exit 1
fi
header_info
# Detect Proxmox product
msg_info "Detecting Proxmox product"
detection_result=$(detect_proxmox)
IFS='|' read -r PRODUCT VERSION <<< "$detection_result"
msg_ok "Detected $PRODUCT"
msg_note "$VERSION"
echo ""
# Check current status
msg_info "Checking current nag status"
if test_current_fix "$PRODUCT"; then
msg_ok "No subscription nags currently present"
if [[ -f /etc/apt/apt.conf.d/no-nag-script ]]; then
echo ""
echo "✓ Apt hook is installed and nags are already removed"
echo "✓ The fix should persist through updates"
echo ""
echo "If nags return after updates, there may be a new pattern to patch."
echo "Run this script again to update the fix."
exit 0
fi
else
msg_ok "Subscription nags detected - fix needed"
fi
# Check if hook exists but isn't working
if [[ -f /etc/apt/apt.conf.d/no-nag-script ]]; then
msg_info "Updating existing apt hook"
rm -f /etc/apt/apt.conf.d/no-nag-script
msg_ok "Old hook removed"
fi
echo ""
# Show subscription support message
echo -e "${YW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}"
echo -e "${BL} Support Subscriptions${CL}"
echo -e "${YW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}"
echo ""
echo "Supporting the software's development team is essential. Check their official"
echo "website's Support Subscriptions for pricing. Without their dedicated work,"
echo "we wouldn't have this exceptional software."
echo ""
echo -e "${YW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}"
echo ""
# Confirm installation
echo "This will disable the subscription nag message that appears when logging"
echo "into the web interface. The fix will automatically reapply after updates."
echo ""
while true; do
read -p "Continue with subscription nag removal? (y/n): " yn
case $yn in
[Yy]*) break ;;
[Nn]*)
echo "Aborted."
exit 0
;;
*) echo "Please answer yes or no." ;;
esac
done
echo ""
# Apply the fix
apply_nag_removal "$PRODUCT"
echo ""
# Test the fix
msg_info "Testing nag removal"
if test_current_fix "$PRODUCT"; then
msg_ok "Nag removal test passed"
else
msg_error "Nag removal test failed - manual intervention may be needed"
fi
echo ""
echo -e "${GN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}"
echo -e "${GN} Installation Complete${CL}"
echo -e "${GN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}"
echo ""
echo "✓ The subscription nag has been disabled for $PRODUCT"
echo "✓ The fix will automatically reapply after Proxmox updates"
echo "✓ Clear your browser cache and refresh the web interface"
echo ""
if [[ "$PRODUCT" == "PMG" ]]; then
echo "✓ Both desktop and mobile interfaces have been patched"
echo ""
fi
echo "To test the apt hook manually, run:"
echo " apt --reinstall install proxmox-widget-toolkit"
echo ""
echo -e "${YW}Original community-scripts: https://community-scripts.github.io/ProxmoxVE/${CL}"
echo ""
}
# Run main function
main "$@"