Compare commits

...

22 Commits

Author SHA1 Message Date
Jamesits
31cd2b8746
bump version to 0.0.11 2024-10-26 16:05:05 +08:00
Jamesits
499d00a81a
bump release to 0.0.10-2 2024-10-26 16:04:35 +08:00
Jamesits
d80468779e
fix #14 2024-10-26 16:04:12 +08:00
Jamesits
945b9247ef
update doc 2024-10-25 16:08:08 +08:00
Jamesits
bcb1fe671c
update doc 2024-10-25 16:05:35 +08:00
Jamesits
6a5aa2f026
update doc 2024-10-25 16:03:39 +08:00
Jamesits
21a8e7eb5f
update doc 2024-10-25 15:59:09 +08:00
Jamesits
b4dd87c236
make the script compatible with Python 2.7 and 3.18 2024-10-25 15:53:01 +08:00
Jamesits
2414d822ee
Update support status for PBS 3.x 2024-10-09 15:59:57 +08:00
Jamesits
380c479f24
update doc for #10 2023-07-28 01:40:20 +08:00
James Swineson
7a7048a575
fix typo 2023-06-11 01:47:03 +08:00
James Swineson
7f8200b83a doc: binary is now automatically invoked during post install, so no need to wait 2022-12-19 17:35:35 +08:00
James Swineson
6168590598
Update README.md 2022-12-19 17:33:04 +08:00
James Swineson
82850c151b ditch fpm and use nfpm from now on (as per #3 and #9) 2022-12-19 17:21:24 +08:00
James Swineson
68fe060029 fix line ending issue 2022-09-16 09:11:36 +08:00
James Swineson
c83063441d fix compatibility issue on PVE 7.2-11 (#4) 2022-09-16 09:05:14 +08:00
James Swineson
7fb0674976 update doc 2021-06-25 21:11:16 +08:00
James Swineson
698f2ca45f update 2021-06-25 20:43:02 +08:00
James Swineson
e709acc4c2 update doc 2021-06-25 20:01:55 +08:00
James Swineson
de21f2ae32 update doc 2021-06-25 20:01:09 +08:00
James Swineson
a9d3405893 update doc 2021-06-25 19:52:59 +08:00
James Swineson
c6623dff1a fix it not auto starting after installation 2021-06-25 07:37:41 +08:00
13 changed files with 311 additions and 67 deletions

2
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.deb *.deb
/out/
# Created by https://www.gitignore.io/api/macos,python,windows,visualstudiocode # Created by https://www.gitignore.io/api/macos,python,windows,visualstudiocode
# Edit at https://www.gitignore.io/?templates=macos,python,windows,visualstudiocode # Edit at https://www.gitignore.io/?templates=macos,python,windows,visualstudiocode
@ -193,4 +194,3 @@ $RECYCLE.BIN/
*.lnk *.lnk
# End of https://www.gitignore.io/api/macos,python,windows,visualstudiocode # End of https://www.gitignore.io/api/macos,python,windows,visualstudiocode

View File

@ -1,22 +1,46 @@
I am really poor and I really can't afford a license. I just want to get rid of the annoying dialog on every login. # pve-fake-subscription
![JavaScript free](https://img.shields.io/badge/JavaScript-free-%09%23f7df1e "No JavaScript is involved in this project. ")
Disables the "No valid subscription" dialog on all Proxmox products.
> I am really poor and I can't afford a license. I just want to get rid of the annoying dialog.
## Features ## Features
* Works for: Works for:
- Proxmox VE (5.x or later, tested up to 7.0)
- Proxmox VE (5.x or later; 3.x and 4.x [require some manual actions](#compatibility-information-for-old-proxmox-ve-versions))
- Proxmox Mail Gateway (5.x or later) - Proxmox Mail Gateway (5.x or later)
- Proxmox Backup Server (1.x) - Proxmox Backup Server (1.x or later)
* Non-intrusive, no changes to any system file, persists between system updates
* Comes with standard Debian package, easy to manage and automate
* You can uninstall at any time, hassle-free
* **No JavaScript is involved** in the whole process
## Installation Highlights:
* Go to [release](https://github.com/Jamesits/pve-fake-subscription/releases/latest) to download the latest release - Non-intrusive: zero modification of any system file
* Run `dpkg -i pve-fake-subscription_*.deb` as root on every Proxmox VE node - Future-proof: persists between system updates & major upgrades
- Hassle-free: you can uninstall at any time
- Comes with standard Debian package, easy to manage and automate
- **No JavaScript is involved** in the whole process, as I believe JavaScript is harmful to developers
## Uninstallation ## Usage
### Installation
1. [Download the latest release](https://github.com/Jamesits/pve-fake-subscription/releases/latest)
1. Install: run `dpkg -i pve-fake-subscription_*.deb` as root on every node
1. (Optional) `echo "127.0.0.1 shop.maurer-it.com" | sudo tee -a /etc/hosts` to prevent fake keys from being checked against the Proxmox servers
Notes:
After installation, please refrain yourself from clicking the "check" button on the "Subscription" page. It will invalidate the cache and temporary revert your instance into an unlicensed status.
The fake subscription status doesn't grant you free access to the enterprise repository. You should switch to the no-subscription repository if not already done. Use the following method:
- [Proxmox VE (PVE)](https://pve.proxmox.com/wiki/Package_Repositories#sysadmin_no_subscription_repo)
- [Proxmox Mail Gateway (PMG)](https://pmg.proxmox.com/pmg-docs/pmg-admin-guide.html#pmg_package_repositories)
- [Proxmox Backup Server (PBS)](https://pbs.proxmox.com/docs/installation.html#proxmox-backup-no-subscription-repository)
### Uninstallation
Run as root: Run as root:
@ -26,12 +50,49 @@ apt purge pve-fake-subscription
This will revert your system to a "no subscription key" status. This will revert your system to a "no subscription key" status.
## Building the Package ## Development Notes
Run everything as root on a Debian 10 system: ### Building the Package
Install [nFPM](https://nfpm.goreleaser.com/install/), then:
```shell ```shell
apt-get install ruby ruby-dev rubygems build-essential
gem install --no-ri --no-rdoc fpm
./package.sh ./package.sh
``` ```
### Compatibility Information for Old Proxmox VE Versions
#### PVE 4.x
After installation or updates, run:
```shell
sed -i'' -e's/pve8p/pve4p/g' /usr/bin/pve-fake-subscription
pve-fake-subscription
```
#### PVE 3.x
Installation with `dpkg -i` will not work because of missing dependencies. Use the following script to install manually:
```shell
# extract the deb package
mkdir -p /tmp/pve-fake-subscription
dpkg-deb -x pve-fake-subscription_*.deb /tmp/pve-fake-subscription
# patch and install the script
sed -i'' -e's/python3/python/g' -e's/pve8p/pve4p/g' /tmp/pve-fake-subscription/usr/bin/pve-fake-subscription
mv /tmp/pve-fake-subscription/usr/bin/pve-fake-subscription /usr/local/bin/
# install the timer
ln -sf /usr/local/bin/pve-fake-subscription /etc/cron.hourly/pve-fake-subscription
# invoke it once
/usr/local/bin/pve-fake-subscription
# remove temporary files
rm -rf /tmp/pve-fake-subscription
```
Removal:
```shell
rm -f /usr/local/bin/pve-fake-subscription /etc/cron.hourly/pve-fake-subscription /etc/subscription
```

40
nfpm.yaml Normal file
View File

@ -0,0 +1,40 @@
name: "pve-fake-subscription"
arch: "all"
platform: "linux"
version: "0.0.11"
version_schema: "semver"
version_metadata: "git"
epoch: 0
release: 1
section: "admin"
priority: "optional"
maintainer: "Nobody <nobody@example.com>"
depends:
- python3
description: |
Pollute the subscription cache of Proxmox VE (>=5.0), Proxmox Mail Gateway (>=5.0) & Proxmox Backup Server (>=1.0) so it won't alert you on dashboard login
vendor: "none"
homepage: "https://github.com/Jamesits/pve-fake-subscription"
license: "GLWTS(Good Luck With That Shit) Public License"
contents:
- src: "./usr/bin/pve-fake-subscription"
dst: "/usr/bin/pve-fake-subscription"
file_info:
mode: 0755
- src: "./usr/lib/systemd"
dst: "/usr/lib/systemd"
file_info:
mode: 0644
- src: "./usr/share/doc/pve-fake-subscription"
dst: "/usr/share/doc/pve-fake-subscription"
file_info:
mode: 0644
scripts:
postinstall: "./scripts/postinst"
preremove: "./scripts/prerm"
postremove: "./scripts/postrm"

View File

@ -1,20 +1,16 @@
#!/bin/bash #!/bin/bash
set -Eeuo pipefail
cd "$( dirname "${BASH_SOURCE[0]}" )" || exit 1
cd "$( dirname "${BASH_SOURCE[0]}" )" OUT_DIR="out"
fpm -s dir -t deb --force \ rm -rf "${OUT_DIR}"
-n pve-fake-subscription \ mkdir -p "${OUT_DIR}"
--description "Pollute the subscription cache of Proxmox VE (>=5.0), Proxmox Mail Gateway (>=5.0) & Proxmox Backup Server (>=1.0) so it won't alert you on dashboard login" \
--url "https://github.com/Jamesits/pve-fake-subscription" \
-v 0.0.6 \
--license "GLWTS(Good Luck With That Shit) Public License" \
--depends "python3" \
--architecture all \
--deb-dist "unstable" \
--deb-priority "optional" \
--deb-systemd "usr/lib/systemd/system/pve-fake-subscription.timer" \
--after-remove "scripts/purge" \
./usr
# temporary removed as of https://github.com/jordansissel/fpm/issues/1472 # build package
#--deb-after-purge "scripts/purge" \ nfpm pkg --packager deb --target "${OUT_DIR}"
# generate checksum
pushd "${OUT_DIR}" >/dev/null
sha256sum -b -- * > sha256sum.txt
popd >/dev/null

56
scripts/postinst Executable file
View File

@ -0,0 +1,56 @@
#!/bin/sh
after_upgrade() {
:
if command -v systemctl >/dev/null; then
systemctl --system daemon-reload >/dev/null || true
debsystemctl=$(command -v deb-systemd-invoke || echo systemctl)
if ! systemctl is-enabled pve-fake-subscription.timer >/dev/null
then
: # Ensure this if-clause is not empty. If it were empty, and we had an 'else', then it is an error in shell syntax
systemctl preset pve-fake-subscription.timer >/dev/null || true
$debsystemctl start pve-fake-subscription.timer >/dev/null || true
else
$debsystemctl restart pve-fake-subscription.timer >/dev/null || true
fi
else
ln -sf /usr/bin/pve-fake-subscription /etc/cron.hourly/pve-fake-subscription
fi
pve-fake-subscription
}
after_install() {
:
if command -v systemctl >/dev/null; then
systemctl --system daemon-reload >/dev/null || true
debsystemctl=$(command -v deb-systemd-invoke || echo systemctl)
systemctl preset pve-fake-subscription.timer >/dev/null || true
$debsystemctl start pve-fake-subscription.timer >/dev/null || true
else
ln -sf /usr/bin/pve-fake-subscription /etc/cron.hourly/pve-fake-subscription
fi
pve-fake-subscription
}
if { [ "${1}" = "configure" ] && [ -z "${2}" ]; } || [ "${1}" = "abort-remove" ]; then
# "after install" here
# "abort-remove" happens when the pre-removal script failed.
# In that case, this script, which should be idemptoent, is run
# to ensure a clean roll-back of the removal.
after_install
elif [ "${1}" = "configure" ] && [ -n "${2}" ]; then
upgradeFromVersion="${2}"
# "after upgrade" here
# NOTE: This slot is also used when deb packages are removed,
# but their config files aren't, but a newer version of the
# package is installed later, called "Config-Files" state.
# basically, that still looks a _lot_ like an upgrade to me.
after_upgrade "${2}"
elif echo "${1}" | grep -E -q "(abort|fail)"; then
echo "Failed to install before the post-installation script was run." >&2
exit 1
fi

43
scripts/postrm Executable file
View File

@ -0,0 +1,43 @@
#!/bin/sh
after_remove() {
:
rm -f /etc/subscription
rm -f /etc/pmg/subscription
rm -f /etc/proxmox-backup/subscription
rm -f /etc/cron.hourly/pve-fake-subscription
}
after_purge() {
:
}
dummy() {
:
}
if [ "${1}" = "remove" ] || [ "${1}" = "abort-install" ]; then
# "after remove" goes here
# "abort-install" happens when the pre-installation script failed.
# In that case, this script, which should be idemptoent, is run
# to ensure a clean roll-back of the installation.
after_remove
elif [ "${1}" = "purge" ] && [ -z "${2}" ]; then
# like "on remove", but executes after dpkg deletes config files
# 'apt-get purge' runs 'on remove' section, then this section.
# There is no equivalent in RPM or ARCH.
after_purge
elif [ "${1}" = "upgrade" ]; then
# This represents the case where the old package's postrm is called after
# the 'preinst' script is called.
# We should ignore this and just use 'preinst upgrade' and
# 'postinst configure'. The newly installed package should do the
# upgrade, not the uninstalled one, since it can't anticipate what new
# things it will have to do to upgrade for the new version.
dummy
elif echo "${1}" | grep -E -q '(fail|abort)'; then
echo "Failed to install before the post-removal script was run." >&2
exit 1
fi

29
scripts/prerm Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
before_remove() {
:
debsystemctl=$(command -v deb-systemd-invoke || echo systemctl)
$debsystemctl stop pve-fake-subscription.timer >/dev/null || true
systemctl disable pve-fake-subscription.timer >/dev/null || true
systemctl --system daemon-reload >/dev/null || true
}
dummy() {
:
}
if [ "${1}" = "remove" ] && [ -z "${2}" ]; then
# "before remove" goes here
before_remove
elif [ "${1}" = "upgrade" ]; then
# Executed before the old version is removed
# upon upgrade.
# We should generally not do anything here. The newly installed package
# should do the upgrade, not the uninstalled one, since it can't anticipate
# what new things it will have to do to upgrade for the new version.
dummy
elif echo "${1}" | grep -E -q "(fail|abort)"; then
echo "Failed to install before the pre-removal script was run." >&2
exit 1
fi

View File

@ -1,3 +0,0 @@
rm -f /etc/subscription
rm -f /etc/pmg/subscription
rm -f /etc/proxmox-backup/subscription

View File

@ -1,7 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Pollute Proxmox VE 5.x subscription cache so it won't alert you on dashboard login # Pollute Proxmox software subscription cache so it won't alert you on dashboard login
# If you need to prevent it checking keys against a server, please block "shop.maurer-it.com" # Should be scheduled to run every few hours with a timer to prevent cache from expiring
# If you need to prevent it checking keys against a server, please block "shop.maurer-it.com" in your hosts file
from __future__ import print_function
import hashlib import hashlib
import base64 import base64
import json import json
@ -9,7 +12,6 @@ import time
import re import re
import sys import sys
import os import os
from typing import List
from datetime import datetime, timedelta from datetime import datetime, timedelta
# PVE & PMG: /usr/share/perl5/PVE/Subscription.pm # PVE & PMG: /usr/share/perl5/PVE/Subscription.pm
@ -17,29 +19,42 @@ from datetime import datetime, timedelta
shared_key_data = "kjfdlskfhiuewhfk947368" shared_key_data = "kjfdlskfhiuewhfk947368"
server_key_file = "/etc/ssh/ssh_host_rsa_key.pub" server_key_file = "/etc/ssh/ssh_host_rsa_key.pub"
def get_timestamp() -> int: # Default license keys
lic_pve = "pve8p-1145141919"
lic_pmg = "pmgp-1145141919"
lic_pbs = "pbst-1145141919"
# UI customization
ui_product_name = "YajuuSenpai"
ui_message = "Yajuu Senpai has got your back"
ui_url = "https://github.com/Jamesits/pve-fake-subscription"
def get_timestamp():
return int(time.time()) return int(time.time())
# Perl's md5_base64 implementation # Perl's md5_base64 implementation
def md5_base64_perl(x: str) -> str: def md5_base64_perl(x):
return base64.b64encode(hashlib.md5(x.encode()).digest()).strip(b'=').decode() return base64.b64encode(hashlib.md5(x.encode()).digest()).strip(b'=').decode()
# Rust's `base64::encode(tools::md5sum("something")?);` # Rust's `base64::encode(tools::md5sum("something")?);`
def md5_base64_rs(x: str) -> str: def md5_base64_rs(x):
return base64.b64encode(hashlib.md5(x.encode()).digest()).decode() return base64.b64encode(hashlib.md5(x.encode()).digest()).decode()
def generate_server_id(key: str) -> str: def generate_server_id(key):
return hashlib.md5(key.encode()).hexdigest().upper() return hashlib.md5(key.encode()).hexdigest().upper()
def generate_subscription_pve_pmg(key: str, server_ids: List[str]) -> str: def dt_string(format, offset_secs=0):
return (datetime.now() + timedelta(seconds=offset_secs)).strftime(format)
def generate_subscription_pve_pmg(key, server_ids, product_name=ui_product_name):
localinfo = { localinfo = {
"checktime": get_timestamp(), "checktime": get_timestamp(),
"status": "Active", # PBS: `new`, `notfound`, `active`, `invalid` "status": "Active",
"key": key, "key": key,
"validdirectory": ",".join(server_ids), "validdirectory": ",".join(server_ids),
"productname": "YajuuSenpai", "productname": product_name,
"regdate": get_timestamp(), "regdate": dt_string("%Y-%m-%d %H:%M:%S"),
"nextduedate": 2147483647, "nextduedate": dt_string("%Y-%m-%d", 1296000),
} }
data = base64.standard_b64encode(json.dumps(localinfo).encode()).decode() data = base64.standard_b64encode(json.dumps(localinfo).encode()).decode()
@ -49,9 +64,10 @@ def generate_subscription_pve_pmg(key: str, server_ids: List[str]) -> str:
return key + "\n" + csum + "\n" + data + "\n" return key + "\n" + csum + "\n" + data + "\n"
# key_pattern can be find in /usr/share/perl5/{PVE,PMG}/API2/Subscription.pm # key_pattern can be find in /usr/share/perl5/{PVE,PMG}/API2/Subscription.pm
# PVE: r'pve([1248])([cbsp])-[0-9a-f]{10}' # PVE5+: r'pve([1248])([cbsp])-[0-9a-f]{10}'
# PVE3/4: r'pve([124])([cbsp])-[0-9a-f]{10}'
# PMG: r'pmg([cbsp])-[0-9a-f]{10}' # PMG: r'pmg([cbsp])-[0-9a-f]{10}'
def activate_pve_pmg(key: str, subscription_file: str) -> None: def activate_pve_pmg(key, subscription_file, *args, **kwargs):
# check if the key format is correct # check if the key format is correct
# pattern = re.compile(key_pattern) # pattern = re.compile(key_pattern)
# if not pattern.match(key): # if not pattern.match(key):
@ -64,23 +80,23 @@ def activate_pve_pmg(key: str, subscription_file: str) -> None:
server_id = generate_server_id(f.read()) server_id = generate_server_id(f.read())
# generate a license file # generate a license file
subscription = generate_subscription_pve_pmg(key, [server_id]) subscription = generate_subscription_pve_pmg(key, [server_id], *args, **kwargs)
# write license file # write license file
with open(subscription_file, "w") as f: with open(subscription_file, "w") as f:
f.write(subscription) f.write(subscription)
def generate_subscription_pbs(key: str, server_ids: List[str]) -> str: def generate_subscription_pbs(key, server_ids, product_name=ui_product_name, message=ui_message, url=ui_url):
localinfo = { localinfo = {
"status": "active", # PBS: `new`, `notfound`, `active`, `invalid` "status": "active", # PBS: `new`, `notfound`, `active`, `invalid`
"serverid": ",".join(server_ids), "serverid": ",".join(server_ids),
"checktime": get_timestamp(), "checktime": get_timestamp(),
"key": key, "key": key,
"message": "Yajuu Senpai has got your back", "message": message,
"productname": "YajuuSenpai", "productname": product_name,
"regdate": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "regdate": dt_string("%Y-%m-%d %H:%M:%S"),
"nextduedate": (datetime.now() + timedelta(seconds=1296000)).strftime("%Y-%m-%d"), # 1296000: MAX_LOCAL_KEY_AGE in src/tools/subscription.rs "nextduedate": dt_string("%Y-%m-%d", 1296000), # 1296000: MAX_LOCAL_KEY_AGE in src/tools/subscription.rs
"url": "https://github.com/Jamesits/pve-fake-subscription", "url": url,
} }
data = base64.standard_b64encode(json.dumps(localinfo).encode()).decode() data = base64.standard_b64encode(json.dumps(localinfo).encode()).decode()
@ -90,14 +106,14 @@ def generate_subscription_pbs(key: str, server_ids: List[str]) -> str:
return key + "\n" + csum + "\n" + data + "\n" return key + "\n" + csum + "\n" + data + "\n"
# Key pattern: pbst-xxxxxxxxxx # Key pattern: pbst-xxxxxxxxxx
def activate_pbs(key: str, subscription_file: str) -> None: def activate_pbs(key, subscription_file, *args, **kwargs):
# get machine ID # get machine ID
server_id = "" server_id = ""
with open(server_key_file, "r") as f: with open(server_key_file, "r") as f:
server_id = generate_server_id(f.read()) server_id = generate_server_id(f.read())
# generate a license file # generate a license file
subscription = generate_subscription_pbs(key, [server_id]) subscription = generate_subscription_pbs(key, [server_id], *args, **kwargs)
# write license file # write license file
with open(subscription_file, "w") as f: with open(subscription_file, "w") as f:
@ -107,14 +123,14 @@ if __name__ == "__main__":
# Proxmox VE # Proxmox VE
if os.path.exists("/etc/pve"): if os.path.exists("/etc/pve"):
print("Activating Proxmox VE...") print("Activating Proxmox VE...")
activate_pve_pmg("pve8p-1145141919", "/etc/subscription") activate_pve_pmg(lic_pve, "/etc/subscription")
# Proxmox Mail Gateway # Proxmox Mail Gateway
if os.path.exists("/etc/pmg"): if os.path.exists("/etc/pmg"):
print("Activating Proxmox Mail Gateway...") print("Activating Proxmox Mail Gateway...")
activate_pve_pmg("pmgp-1145141919", "/etc/pmg/subscription") activate_pve_pmg(lic_pmg, "/etc/pmg/subscription")
# Proxmox Backup Server (not working yet) # Proxmox Backup Server
if os.path.exists("/etc/proxmox-backup"): if os.path.exists("/etc/proxmox-backup"):
print("Activating Proxmox Backup Server...") print("Activating Proxmox Backup Server...")
activate_pbs("pbst-1145141919", "/etc/proxmox-backup/subscription") activate_pbs(lic_pbs, "/etc/proxmox-backup/subscription")

View File

@ -0,0 +1 @@
enable pve-fake-subscription.timer

View File

@ -4,4 +4,3 @@ Description=Fake a Proxmox VE subscription
[Service] [Service]
Type=oneshot Type=oneshot
ExecStart=/usr/bin/pve-fake-subscription ExecStart=/usr/bin/pve-fake-subscription

View File

@ -10,4 +10,3 @@ Persistent=true
[Install] [Install]
WantedBy=timers.target WantedBy=timers.target

View File

@ -0,0 +1,7 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: pve-fake-subscription
Source: https://github.com/Jamesits/pve-fake-subscription
Files: *
Copyright: 2019 Nobody
License: GLWTS(Good Luck With That Shit) Public License