Name: shiva-pulse Version: 1.0 Release: 2.fc44 Summary: ShivaOS — Heartbeat anonyme vers shivaos.com License: MIT URL: https://shivaos.com BuildArch: noarch Requires: python3 %description Envoie un ping anonyme quotidien à shivaos.com pour afficher le nombre d'utilisateurs actifs. Aucune donnée personnelle transmise — seul un hash anonyme de la machine, la version OS et le pays. %prep # no sources %build # no compilation %install # --- script python --- mkdir -p %{buildroot}/usr/lib/shiva cat > %{buildroot}/usr/lib/shiva/shiva-pulse.py << 'PYEOF' #!/usr/bin/env python3 import hashlib, json, os, datetime, sys, socket import urllib.request, urllib.error SALT = "SHIVA_GENESIS_PRIME" PULSE_URL = "https://shivaos.com/pulse.php" STATE_FILE = "/var/lib/shiva-pulse/state.json" def get_machine_hash(): try: with open("/etc/machine-id") as f: machine_id = f.read().strip() except Exception: machine_id = "fallback" return hashlib.sha256((machine_id + SALT).encode()).hexdigest() def get_version(): for path in ("/etc/os-release", "/usr/lib/os-release"): try: with open(path) as f: for line in f: if line.startswith("VERSION="): return line.strip().split("=", 1)[1].strip('"') except Exception: continue return "unknown" def already_pulsed_today(): today = datetime.date.today().isoformat() try: with open(STATE_FILE) as f: return json.load(f).get("last_pulse") == today except Exception: return False def save_pulse_state(): os.makedirs(os.path.dirname(STATE_FILE), exist_ok=True) with open(STATE_FILE, "w") as f: json.dump({"last_pulse": datetime.date.today().isoformat()}, f) def send_pulse(): payload = json.dumps({ "machine_hash": get_machine_hash(), "version": get_version(), "hostname": socket.gethostname() }).encode() req = urllib.request.Request( PULSE_URL, data=payload, headers={"Content-Type": "application/json", "User-Agent": "ShivaOS-Pulse/2.0"} ) try: with urllib.request.urlopen(req, timeout=15) as r: data = json.loads(r.read().decode()) if data.get("status") == "PULSE_RECEIVED": save_pulse_state() print(f"Pulse OK — {data.get('users', '?')} utilisateurs actifs.") else: print(f"Réponse inattendue: {data}") sys.exit(1) except urllib.error.URLError as e: print(f"Erreur réseau: {e}") sys.exit(1) if __name__ == "__main__": if already_pulsed_today(): print("Pulse déjà envoyé aujourd'hui.") sys.exit(0) send_pulse() PYEOF # --- service systemd --- mkdir -p %{buildroot}/usr/lib/systemd/system cat > %{buildroot}/usr/lib/systemd/system/shiva-pulse.service << 'EOF' [Unit] Description=ShivaOS Pulse — heartbeat anonyme vers shivaos.com After=network-online.target Wants=network-online.target [Service] Type=oneshot ExecStart=/usr/bin/python3 /usr/lib/shiva/shiva-pulse.py User=nobody EOF # --- timer systemd --- cat > %{buildroot}/usr/lib/systemd/system/shiva-pulse.timer << 'EOF' [Unit] Description=Run ShivaOS Pulse Daily [Timer] OnCalendar=daily RandomizedDelaySec=4h Persistent=true [Install] WantedBy=timers.target EOF %post systemctl daemon-reload systemctl enable --now shiva-pulse.timer 2>/dev/null || true %preun if [ $1 -eq 0 ]; then systemctl disable --now shiva-pulse.timer 2>/dev/null || true fi %files /usr/lib/shiva/shiva-pulse.py /usr/lib/systemd/system/shiva-pulse.service /usr/lib/systemd/system/shiva-pulse.timer %changelog * Tue May 05 2026 ShivaOS Team - 1.0-2.fc44 - Fix dist tag explicite fc44 - Déplacer service/timer vers /usr/lib/systemd/system/ (standard RPM) - Lire version depuis /etc/os-release au lieu de /etc/shivaos-release * Sun May 03 2026 ShivaOS Team - 1.0-1 - Release initiale shiva-pulse