Compare commits
25 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
7fb0674976 | |
|
|
698f2ca45f | |
|
|
e709acc4c2 | |
|
|
de21f2ae32 | |
|
|
a9d3405893 | |
|
|
c6623dff1a | |
|
|
d46e6b308e | |
|
|
170ea8fb0e | |
|
|
52888f4557 | |
|
|
ec12e99343 | |
|
|
2b7cb482ab | |
|
|
12b98d61c9 | |
|
|
86e774ab19 | |
|
|
d75f6d908d | |
|
|
c57e470557 | |
|
|
e039945235 | |
|
|
8336ba4728 | |
|
|
29ad652669 | |
|
|
670b7227e4 | |
|
|
a8d8ede0cd | |
|
|
13c8922195 | |
|
|
b919db6876 | |
|
|
c110f2ab84 | |
|
|
db8214a59d | |
|
|
cdbf08f354 |
54
README.md
54
README.md
|
|
@ -1,6 +1,54 @@
|
|||
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.
|
||||
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
|
||||
|
||||
Works for:
|
||||
- Proxmox VE (5.x or later, tested up to 7.0)
|
||||
- Proxmox Mail Gateway (5.x or later)
|
||||
- Proxmox Backup Server (1.x)
|
||||
|
||||
Highlights:
|
||||
- Non-intrusive: zero modification of any system file
|
||||
- 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
|
||||
|
||||
## Installation
|
||||
|
||||
* Go to [release](https://github.com/Jamesits/pve-fake-subscription/releases/latest) to download the latest release
|
||||
* Run `dpkg -i pve-fake-subscription_*.deb` on every Proxmox VE node
|
||||
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:
|
||||
|
||||
The initial run will be scheduled within 1 minute of the installation. If you don't want to wait, you can invoke it immediately by executing `pve-fake-subscription`.
|
||||
|
||||
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:
|
||||
|
||||
```shell
|
||||
apt purge pve-fake-subscription
|
||||
```
|
||||
|
||||
This will revert your system to a "no subscription key" status.
|
||||
|
||||
## Building the Package
|
||||
|
||||
Run everything as root on a Debian 10 system:
|
||||
|
||||
```shell
|
||||
apt-get install ruby ruby-dev rubygems build-essential
|
||||
gem install --no-ri --no-rdoc fpm
|
||||
./package.sh
|
||||
```
|
||||
|
|
|
|||
12
package.sh
12
package.sh
|
|
@ -2,16 +2,20 @@
|
|||
|
||||
cd "$( dirname "${BASH_SOURCE[0]}" )"
|
||||
|
||||
fpm -s dir -t deb \
|
||||
fpm -s dir -t deb --force \
|
||||
-n pve-fake-subscription \
|
||||
--description "Pollute Proxmox VE 5.x subscription cache so it won't alert you on dashboard login" \
|
||||
--url "https://github.com/Jamesits/proxmox-ve-i-really-have-no-money-to-buy-a-subscription" \
|
||||
-v 0.0.1 \
|
||||
--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.7 \
|
||||
--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" \
|
||||
--deb-systemd-enable --deb-systemd-auto-start --deb-systemd-restart-after-upgrade \
|
||||
--after-remove "scripts/purge" \
|
||||
./usr
|
||||
|
||||
# temporary removed as of https://github.com/jordansissel/fpm/issues/1472
|
||||
#--deb-after-purge "scripts/purge" \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
rm -f /etc/subscription
|
||||
rm -f /etc/pmg/subscription
|
||||
rm -f /etc/proxmox-backup/subscription
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Pollute Proxmox software subscription cache so it won't alert you on dashboard login
|
||||
# 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
|
||||
import hashlib
|
||||
import base64
|
||||
import json
|
||||
import time
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
from typing import List
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# PVE & PMG: /usr/share/perl5/PVE/Subscription.pm
|
||||
# PBS: /usr/lib/x86_64-linux-gnu/proxmox-backup/* (source code at `https://git.proxmox.com/git/proxmox-backup.git`)
|
||||
shared_key_data = "kjfdlskfhiuewhfk947368"
|
||||
server_key_file = "/etc/ssh/ssh_host_rsa_key.pub"
|
||||
|
||||
def get_timestamp() -> int:
|
||||
return int(time.time())
|
||||
|
||||
# Perl's md5_base64 implementation
|
||||
def md5_base64_perl(x: str) -> str:
|
||||
return base64.b64encode(hashlib.md5(x.encode()).digest()).strip(b'=').decode()
|
||||
|
||||
# Rust's `base64::encode(tools::md5sum("something")?);`
|
||||
def md5_base64_rs(x: str) -> str:
|
||||
return base64.b64encode(hashlib.md5(x.encode()).digest()).decode()
|
||||
|
||||
def generate_server_id(key: str) -> str:
|
||||
return hashlib.md5(key.encode()).hexdigest().upper()
|
||||
|
||||
def generate_subscription_pve_pmg(key: str, server_ids: List[str]) -> str:
|
||||
localinfo = {
|
||||
"checktime": get_timestamp(),
|
||||
"status": "Active",
|
||||
"key": key,
|
||||
"validdirectory": ",".join(server_ids),
|
||||
"productname": "YajuuSenpai",
|
||||
"regdate": get_timestamp(),
|
||||
"nextduedate": 2147483647,
|
||||
}
|
||||
|
||||
data = base64.standard_b64encode(json.dumps(localinfo).encode()).decode()
|
||||
cat = str(localinfo["checktime"]) + data + "\n" + shared_key_data
|
||||
csum = md5_base64_perl(cat)
|
||||
|
||||
return key + "\n" + csum + "\n" + data + "\n"
|
||||
|
||||
# key_pattern can be find in /usr/share/perl5/{PVE,PMG}/API2/Subscription.pm
|
||||
# PVE: r'pve([1248])([cbsp])-[0-9a-f]{10}'
|
||||
# PMG: r'pmg([cbsp])-[0-9a-f]{10}'
|
||||
def activate_pve_pmg(key: str, subscription_file: str) -> None:
|
||||
# check if the key format is correct
|
||||
# pattern = re.compile(key_pattern)
|
||||
# if not pattern.match(key):
|
||||
# print("key format error", file=sys.stderr)
|
||||
# sys.exit(1)
|
||||
|
||||
# get machine ID
|
||||
server_id = ""
|
||||
with open(server_key_file, "r") as f:
|
||||
server_id = generate_server_id(f.read())
|
||||
|
||||
# generate a license file
|
||||
subscription = generate_subscription_pve_pmg(key, [server_id])
|
||||
|
||||
# write license file
|
||||
with open(subscription_file, "w") as f:
|
||||
f.write(subscription)
|
||||
|
||||
def generate_subscription_pbs(key: str, server_ids: List[str]) -> str:
|
||||
localinfo = {
|
||||
"status": "active", # PBS: `new`, `notfound`, `active`, `invalid`
|
||||
"serverid": ",".join(server_ids),
|
||||
"checktime": get_timestamp(),
|
||||
"key": key,
|
||||
"message": "Yajuu Senpai has got your back",
|
||||
"productname": "YajuuSenpai",
|
||||
"regdate": datetime.now().strftime("%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
|
||||
"url": "https://github.com/Jamesits/pve-fake-subscription",
|
||||
}
|
||||
|
||||
data = base64.standard_b64encode(json.dumps(localinfo).encode()).decode()
|
||||
cat = str(localinfo["checktime"]) + data + shared_key_data
|
||||
csum = md5_base64_rs(cat)
|
||||
|
||||
return key + "\n" + csum + "\n" + data + "\n"
|
||||
|
||||
# Key pattern: pbst-xxxxxxxxxx
|
||||
def activate_pbs(key: str, subscription_file: str) -> None:
|
||||
# get machine ID
|
||||
server_id = ""
|
||||
with open(server_key_file, "r") as f:
|
||||
server_id = generate_server_id(f.read())
|
||||
|
||||
# generate a license file
|
||||
subscription = generate_subscription_pbs(key, [server_id])
|
||||
|
||||
# write license file
|
||||
with open(subscription_file, "w") as f:
|
||||
f.write(subscription)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Proxmox VE
|
||||
if os.path.exists("/etc/pve"):
|
||||
print("Activating Proxmox VE...")
|
||||
activate_pve_pmg("pve8p-1145141919", "/etc/subscription")
|
||||
|
||||
# Proxmox Mail Gateway
|
||||
if os.path.exists("/etc/pmg"):
|
||||
print("Activating Proxmox Mail Gateway...")
|
||||
activate_pve_pmg("pmgp-1145141919", "/etc/pmg/subscription")
|
||||
|
||||
# Proxmox Backup Server
|
||||
if os.path.exists("/etc/proxmox-backup"):
|
||||
print("Activating Proxmox Backup Server...")
|
||||
activate_pbs("pbst-1145141919", "/etc/proxmox-backup/subscription")
|
||||
|
|
@ -3,5 +3,5 @@ Description=Fake a Proxmox VE subscription
|
|||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/pve-fake-subscription
|
||||
ExecStart=/usr/bin/pve-fake-subscription
|
||||
|
||||
|
|
|
|||
|
|
@ -10,4 +10,3 @@ Persistent=true
|
|||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Pollute Proxmox VE 5.x 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"
|
||||
import hashlib
|
||||
import base64
|
||||
import json
|
||||
import time
|
||||
import re
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
# a 8-socket fake key which should be good for all situations
|
||||
key = "pve8p-1145141919"
|
||||
|
||||
# key format
|
||||
# /usr/share/perl5/PVE/API2/Subscription.pm
|
||||
subscription_pattern = r'pve([1248])([cbsp])-[0-9a-f]{10}'
|
||||
|
||||
# /usr/share/perl5/PVE/Subscription.pm
|
||||
shared_key_data = "kjfdlskfhiuewhfk947368"
|
||||
|
||||
server_key_file = "/etc/ssh/ssh_host_rsa_key.pub"
|
||||
subscription_file = "/etc/subscription"
|
||||
|
||||
def get_timestamp() -> int:
|
||||
return int(time.time())
|
||||
|
||||
# perl's md5_base64 implementation
|
||||
def md5_base64(x: str) -> str:
|
||||
return base64.b64encode(hashlib.md5(x.encode()).digest()).strip(b'=')
|
||||
|
||||
def generate_server_id(key: str) -> str:
|
||||
return hashlib.md5(key.encode()).hexdigest().upper()
|
||||
|
||||
def generate_subscription(key: str, server_ids: List[str]) -> str:
|
||||
localinfo = {
|
||||
"checktime": get_timestamp(),
|
||||
"status": "Active",
|
||||
"key": key,
|
||||
"validdirectory": ",".join(server_ids),
|
||||
"productname": "YajuuSenpai",
|
||||
"regdate": get_timestamp(),
|
||||
"nextduedate": 2147483647,
|
||||
}
|
||||
|
||||
data = base64.standard_b64encode(json.dumps(localinfo).encode()).decode()
|
||||
cat = str(localinfo["checktime"]) + data + "\n" + shared_key_data
|
||||
csum = md5_base64(cat).decode()
|
||||
|
||||
return key + "\n" + csum + "\n" + data + "\n"
|
||||
|
||||
if __name__ == "__main__":
|
||||
# check if the key format is correct
|
||||
pattern = re.compile(subscription_pattern)
|
||||
if not pattern.match(key):
|
||||
print("key format error", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# get machine ID
|
||||
server_id = ""
|
||||
with open(server_key_file, "r") as f:
|
||||
server_id = generate_server_id(f.read())
|
||||
|
||||
# generate a license file
|
||||
subscription = generate_subscription(key, [server_id])
|
||||
|
||||
# write license file
|
||||
with open(subscription_file, "w") as f:
|
||||
f.write(subscription)
|
||||
|
||||
Loading…
Reference in New Issue