kill-subscription.sh
· 4.8 KiB · Bash
Bruto
#!/usr/bin/env bash
set -Eeuo pipefail
# proxmox-subscription-popup.sh
#
# Safe-ish Proxmox VE 9 subscription popup suppressor using sed.
#
# Usage:
# sudo bash proxmox-subscription-popup.sh
# sudo bash proxmox-subscription-popup.sh --status
# sudo bash proxmox-subscription-popup.sh --undo
# sudo bash proxmox-subscription-popup.sh --repair
JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
STATE_DIR="/root/.proxmox-subscription-popup"
BACKUP_FILE="${STATE_DIR}/proxmoxlib.js.bak"
DO_STATUS=0
DO_UNDO=0
DO_REPAIR=0
for arg in "$@"; do
case "$arg" in
--status) DO_STATUS=1 ;;
--undo) DO_UNDO=1 ;;
--repair) DO_REPAIR=1 ;;
-h|--help)
cat <<'EOF'
Usage:
sudo bash proxmox-subscription-popup.sh
Apply popup suppression patch
sudo bash proxmox-subscription-popup.sh --status
Show status
sudo bash proxmox-subscription-popup.sh --undo
Restore original file
sudo bash proxmox-subscription-popup.sh --repair
Reinstall the owning package
EOF
exit 0
;;
*)
echo "Unknown argument: $arg" >&2
exit 2
;;
esac
done
if [ "$(id -u)" -ne 0 ]; then
echo "Please run as root." >&2
exit 1
fi
mkdir -p "$STATE_DIR"
if [[ -t 1 ]]; then
C_RESET=$'\033[0m'
C_BOLD=$'\033[1m'
C_RED=$'\033[1;31m'
C_GREEN=$'\033[1;32m'
C_YELLOW=$'\033[1;33m'
C_CYAN=$'\033[1;36m'
C_MAGENTA=$'\033[1;35m'
else
C_RESET=""
C_BOLD=""
C_RED=""
C_GREEN=""
C_YELLOW=""
C_CYAN=""
C_MAGENTA=""
fi
say() { printf "%b\n" "$*"; }
info() { say "${C_CYAN}▶${C_RESET} $*"; }
ok() { say "${C_GREEN}✔${C_RESET} $*"; }
warn() { say "${C_YELLOW}⚠${C_RESET} $*"; }
fail() { say "${C_RED}✖${C_RESET} $*" >&2; }
title() { say "${C_BOLD}${C_MAGENTA}$*${C_RESET}"; }
trap 'fail "Script failed on line ${LINENO}"' ERR
require_file() {
[[ -f "$JS_FILE" ]] || {
fail "Missing file: $JS_FILE"
exit 1
}
}
detect_owner_pkg() {
dpkg -S "$JS_FILE" 2>/dev/null | head -n1 | cut -d: -f1
}
restart_proxy() {
info "Restarting pveproxy..."
systemctl restart pveproxy
ok "pveproxy restarted"
}
show_hint() {
say
say "${C_BOLD}Hard refresh the browser afterwards:${C_RESET}"
say " Mac: Cmd+Shift+R"
say " Other: Ctrl+Shift+R"
say
}
is_patched() {
grep -Fq "orig_cmd();" "$JS_FILE" &&
grep -Fq "return;" "$JS_FILE"
}
has_expected_original() {
grep -Fq "checked_command: function (orig_cmd) {" "$JS_FILE" &&
grep -Fq "url: '/nodes/localhost/subscription'" "$JS_FILE" &&
grep -Fq "res.data.status.toLowerCase() !== 'active'" "$JS_FILE"
}
status() {
title "Proxmox subscription popup status"
require_file
if has_expected_original; then
ok "Expected original code pattern found"
else
warn "Expected original code pattern NOT found"
fi
if is_patched; then
ok "Patch appears to be installed"
else
warn "Patch does not appear to be installed"
fi
if [[ -f "$BACKUP_FILE" ]]; then
ok "Backup exists at $BACKUP_FILE"
else
warn "No backup exists"
fi
}
undo() {
title "Restoring original file"
[[ -f "$BACKUP_FILE" ]] || {
fail "No backup file found at $BACKUP_FILE"
exit 1
}
cp -f "$BACKUP_FILE" "$JS_FILE"
ok "Original file restored"
restart_proxy
show_hint
}
repair() {
title "Repairing Proxmox UI"
local owner
owner="$(detect_owner_pkg)"
[[ -n "$owner" ]] || {
fail "Could not determine owning package"
exit 1
}
info "Reinstalling package: $owner"
apt-get update
apt-get install --reinstall -y "$owner"
restart_proxy
ok "Repair complete"
show_hint
}
apply_patch() {
title "Applying subscription popup suppression"
require_file
if is_patched; then
ok "Patch already appears to be installed"
show_hint
return 0
fi
if ! has_expected_original; then
fail "Expected original code pattern not found."
fail "Refusing to patch because the file does not look like the expected Proxmox VE 9 file."
fail "Run with --repair first if the file is damaged."
exit 1
fi
if [[ ! -f "$BACKUP_FILE" ]]; then
info "Creating backup at $BACKUP_FILE"
cp -a "$JS_FILE" "$BACKUP_FILE"
ok "Backup created"
else
warn "Backup already exists; leaving it untouched"
fi
info "Inserting short-circuit into checked_command()"
sed -i '/checked_command: function (orig_cmd) {/a\
orig_cmd();\
return;' "$JS_FILE"
if ! is_patched; then
warn "Patch verification failed; restoring backup"
cp -f "$BACKUP_FILE" "$JS_FILE"
fail "Patch did not verify cleanly. Original restored."
exit 1
fi
ok "Patch successfully applied"
info "Snippet after patch:"
grep -A4 'checked_command: function (orig_cmd)' "$JS_FILE" || true
restart_proxy
ok "Subscription popup suppression is active"
show_hint
}
case 1 in
$DO_STATUS) status ;;
$DO_UNDO) undo ;;
$DO_REPAIR) repair ;;
*) apply_patch ;;
esac
| 1 | #!/usr/bin/env bash |
| 2 | set -Eeuo pipefail |
| 3 | |
| 4 | # proxmox-subscription-popup.sh |
| 5 | # |
| 6 | # Safe-ish Proxmox VE 9 subscription popup suppressor using sed. |
| 7 | # |
| 8 | # Usage: |
| 9 | # sudo bash proxmox-subscription-popup.sh |
| 10 | # sudo bash proxmox-subscription-popup.sh --status |
| 11 | # sudo bash proxmox-subscription-popup.sh --undo |
| 12 | # sudo bash proxmox-subscription-popup.sh --repair |
| 13 | |
| 14 | JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" |
| 15 | STATE_DIR="/root/.proxmox-subscription-popup" |
| 16 | BACKUP_FILE="${STATE_DIR}/proxmoxlib.js.bak" |
| 17 | |
| 18 | DO_STATUS=0 |
| 19 | DO_UNDO=0 |
| 20 | DO_REPAIR=0 |
| 21 | |
| 22 | for arg in "$@"; do |
| 23 | case "$arg" in |
| 24 | --status) DO_STATUS=1 ;; |
| 25 | --undo) DO_UNDO=1 ;; |
| 26 | --repair) DO_REPAIR=1 ;; |
| 27 | -h|--help) |
| 28 | cat <<'EOF' |
| 29 | Usage: |
| 30 | sudo bash proxmox-subscription-popup.sh |
| 31 | Apply popup suppression patch |
| 32 | |
| 33 | sudo bash proxmox-subscription-popup.sh --status |
| 34 | Show status |
| 35 | |
| 36 | sudo bash proxmox-subscription-popup.sh --undo |
| 37 | Restore original file |
| 38 | |
| 39 | sudo bash proxmox-subscription-popup.sh --repair |
| 40 | Reinstall the owning package |
| 41 | EOF |
| 42 | exit 0 |
| 43 | ;; |
| 44 | *) |
| 45 | echo "Unknown argument: $arg" >&2 |
| 46 | exit 2 |
| 47 | ;; |
| 48 | esac |
| 49 | done |
| 50 | |
| 51 | if [ "$(id -u)" -ne 0 ]; then |
| 52 | echo "Please run as root." >&2 |
| 53 | exit 1 |
| 54 | fi |
| 55 | |
| 56 | mkdir -p "$STATE_DIR" |
| 57 | |
| 58 | if [[ -t 1 ]]; then |
| 59 | C_RESET=$'\033[0m' |
| 60 | C_BOLD=$'\033[1m' |
| 61 | C_RED=$'\033[1;31m' |
| 62 | C_GREEN=$'\033[1;32m' |
| 63 | C_YELLOW=$'\033[1;33m' |
| 64 | C_CYAN=$'\033[1;36m' |
| 65 | C_MAGENTA=$'\033[1;35m' |
| 66 | else |
| 67 | C_RESET="" |
| 68 | C_BOLD="" |
| 69 | C_RED="" |
| 70 | C_GREEN="" |
| 71 | C_YELLOW="" |
| 72 | C_CYAN="" |
| 73 | C_MAGENTA="" |
| 74 | fi |
| 75 | |
| 76 | say() { printf "%b\n" "$*"; } |
| 77 | info() { say "${C_CYAN}▶${C_RESET} $*"; } |
| 78 | ok() { say "${C_GREEN}✔${C_RESET} $*"; } |
| 79 | warn() { say "${C_YELLOW}⚠${C_RESET} $*"; } |
| 80 | fail() { say "${C_RED}✖${C_RESET} $*" >&2; } |
| 81 | title() { say "${C_BOLD}${C_MAGENTA}$*${C_RESET}"; } |
| 82 | |
| 83 | trap 'fail "Script failed on line ${LINENO}"' ERR |
| 84 | |
| 85 | require_file() { |
| 86 | [[ -f "$JS_FILE" ]] || { |
| 87 | fail "Missing file: $JS_FILE" |
| 88 | exit 1 |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | detect_owner_pkg() { |
| 93 | dpkg -S "$JS_FILE" 2>/dev/null | head -n1 | cut -d: -f1 |
| 94 | } |
| 95 | |
| 96 | restart_proxy() { |
| 97 | info "Restarting pveproxy..." |
| 98 | systemctl restart pveproxy |
| 99 | ok "pveproxy restarted" |
| 100 | } |
| 101 | |
| 102 | show_hint() { |
| 103 | say |
| 104 | say "${C_BOLD}Hard refresh the browser afterwards:${C_RESET}" |
| 105 | say " Mac: Cmd+Shift+R" |
| 106 | say " Other: Ctrl+Shift+R" |
| 107 | say |
| 108 | } |
| 109 | |
| 110 | is_patched() { |
| 111 | grep -Fq "orig_cmd();" "$JS_FILE" && |
| 112 | grep -Fq "return;" "$JS_FILE" |
| 113 | } |
| 114 | |
| 115 | has_expected_original() { |
| 116 | grep -Fq "checked_command: function (orig_cmd) {" "$JS_FILE" && |
| 117 | grep -Fq "url: '/nodes/localhost/subscription'" "$JS_FILE" && |
| 118 | grep -Fq "res.data.status.toLowerCase() !== 'active'" "$JS_FILE" |
| 119 | } |
| 120 | |
| 121 | status() { |
| 122 | title "Proxmox subscription popup status" |
| 123 | |
| 124 | require_file |
| 125 | |
| 126 | if has_expected_original; then |
| 127 | ok "Expected original code pattern found" |
| 128 | else |
| 129 | warn "Expected original code pattern NOT found" |
| 130 | fi |
| 131 | |
| 132 | if is_patched; then |
| 133 | ok "Patch appears to be installed" |
| 134 | else |
| 135 | warn "Patch does not appear to be installed" |
| 136 | fi |
| 137 | |
| 138 | if [[ -f "$BACKUP_FILE" ]]; then |
| 139 | ok "Backup exists at $BACKUP_FILE" |
| 140 | else |
| 141 | warn "No backup exists" |
| 142 | fi |
| 143 | } |
| 144 | |
| 145 | undo() { |
| 146 | title "Restoring original file" |
| 147 | |
| 148 | [[ -f "$BACKUP_FILE" ]] || { |
| 149 | fail "No backup file found at $BACKUP_FILE" |
| 150 | exit 1 |
| 151 | } |
| 152 | |
| 153 | cp -f "$BACKUP_FILE" "$JS_FILE" |
| 154 | ok "Original file restored" |
| 155 | |
| 156 | restart_proxy |
| 157 | show_hint |
| 158 | } |
| 159 | |
| 160 | repair() { |
| 161 | title "Repairing Proxmox UI" |
| 162 | |
| 163 | local owner |
| 164 | owner="$(detect_owner_pkg)" |
| 165 | |
| 166 | [[ -n "$owner" ]] || { |
| 167 | fail "Could not determine owning package" |
| 168 | exit 1 |
| 169 | } |
| 170 | |
| 171 | info "Reinstalling package: $owner" |
| 172 | apt-get update |
| 173 | apt-get install --reinstall -y "$owner" |
| 174 | |
| 175 | restart_proxy |
| 176 | ok "Repair complete" |
| 177 | show_hint |
| 178 | } |
| 179 | |
| 180 | apply_patch() { |
| 181 | title "Applying subscription popup suppression" |
| 182 | |
| 183 | require_file |
| 184 | |
| 185 | if is_patched; then |
| 186 | ok "Patch already appears to be installed" |
| 187 | show_hint |
| 188 | return 0 |
| 189 | fi |
| 190 | |
| 191 | if ! has_expected_original; then |
| 192 | fail "Expected original code pattern not found." |
| 193 | fail "Refusing to patch because the file does not look like the expected Proxmox VE 9 file." |
| 194 | fail "Run with --repair first if the file is damaged." |
| 195 | exit 1 |
| 196 | fi |
| 197 | |
| 198 | if [[ ! -f "$BACKUP_FILE" ]]; then |
| 199 | info "Creating backup at $BACKUP_FILE" |
| 200 | cp -a "$JS_FILE" "$BACKUP_FILE" |
| 201 | ok "Backup created" |
| 202 | else |
| 203 | warn "Backup already exists; leaving it untouched" |
| 204 | fi |
| 205 | |
| 206 | info "Inserting short-circuit into checked_command()" |
| 207 | |
| 208 | sed -i '/checked_command: function (orig_cmd) {/a\ |
| 209 | orig_cmd();\ |
| 210 | return;' "$JS_FILE" |
| 211 | |
| 212 | if ! is_patched; then |
| 213 | warn "Patch verification failed; restoring backup" |
| 214 | cp -f "$BACKUP_FILE" "$JS_FILE" |
| 215 | fail "Patch did not verify cleanly. Original restored." |
| 216 | exit 1 |
| 217 | fi |
| 218 | |
| 219 | ok "Patch successfully applied" |
| 220 | |
| 221 | info "Snippet after patch:" |
| 222 | grep -A4 'checked_command: function (orig_cmd)' "$JS_FILE" || true |
| 223 | |
| 224 | restart_proxy |
| 225 | ok "Subscription popup suppression is active" |
| 226 | show_hint |
| 227 | } |
| 228 | |
| 229 | case 1 in |
| 230 | $DO_STATUS) status ;; |
| 231 | $DO_UNDO) undo ;; |
| 232 | $DO_REPAIR) repair ;; |
| 233 | *) apply_patch ;; |
| 234 | esac |