Files
copydev-imposing-tool/main.py
Jules bd309a07aa Systeme de licence via Vision — remplace le mot de passe
Cote Vision (LXC 112) :
- Table licenses (cle, client, produit, actif, timeout hors-ligne, expiration)
- API api/license.php (verification publique + CRUD admin)
- Onglet Licences dans le dashboard avec modal creation/edition

Cote Imposing Tool :
- Au lancement, verifie la licence en ligne via vision.copydev.fr
- Cache local (.license) pour le mode hors-ligne
- Timeout configurable dans Vision (defaut 72h)
- Passe le timeout → message "contactez CopyDev contact@copydev.fr"
- Premiere activation necessite une connexion internet
- Plus de mot de passe

Licence de test : COPYDEV-IMPOS-TEST-2026

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:23:54 +01:00

176 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""Copydev Imposing Tool — Point d'entree."""
import sys
import os
import json
import time
import urllib.request
import urllib.error
import urllib.parse
# Support PyInstaller (chemin des resources)
if getattr(sys, 'frozen', False):
BASE_DIR = os.path.dirname(sys.executable)
BUNDLE_DIR = sys._MEIPASS
else:
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
BUNDLE_DIR = BASE_DIR
sys.path.insert(0, BUNDLE_DIR)
from PyQt6.QtWidgets import QApplication, QInputDialog, QMessageBox, QLineEdit
LICENSE_API = "https://vision.copydev.fr/api/license.php"
LICENSE_FILE = os.path.join(BASE_DIR, ".license")
def _load_license_cache():
"""Charger le cache de licence local."""
if not os.path.exists(LICENSE_FILE):
return None
try:
with open(LICENSE_FILE, "r") as f:
return json.load(f)
except Exception:
return None
def _save_license_cache(data):
"""Sauvegarder le cache de licence local."""
try:
with open(LICENSE_FILE, "w") as f:
json.dump(data, f)
except Exception:
pass
def _check_license_online(key):
"""Verifier la licence aupres du serveur Vision."""
try:
url = f"{LICENSE_API}?key={urllib.parse.quote(key)}"
req = urllib.request.Request(url, headers={"User-Agent": "CopydevImposingTool/1.0"})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode())
if data.get("valid"):
cache = {
"key": key,
"client": data.get("client", ""),
"product": data.get("product", ""),
"offline_timeout_hours": data.get("offline_timeout_hours", 72),
"last_validated": time.time(),
}
_save_license_cache(cache)
return True, data.get("client", "")
return False, "Licence invalide"
except urllib.error.HTTPError as e:
try:
body = json.loads(e.read().decode())
return False, body.get("error", "Erreur serveur")
except Exception:
return False, f"Erreur HTTP {e.code}"
except Exception as e:
return None, str(e) # None = hors-ligne
def _check_license():
"""Verifier la licence au lancement."""
cache = _load_license_cache()
# Si on a un cache, essayer de valider en ligne
if cache and cache.get("key"):
key = cache["key"]
result, msg = _check_license_online(key)
if result is True:
# Licence valide en ligne
return True
if result is False:
# Licence refusee par le serveur
QMessageBox.critical(
None, "Licence invalide",
f"Votre licence a ete refusee :\n{msg}\n\n"
"Contactez CopyDev : contact@copydev.fr"
)
return False
# result is None = hors-ligne, verifier le timeout
timeout_hours = cache.get("offline_timeout_hours", 72)
last_validated = cache.get("last_validated", 0)
elapsed_hours = (time.time() - last_validated) / 3600
if elapsed_hours < timeout_hours:
remaining = timeout_hours - elapsed_hours
return True
# Timeout depasse
QMessageBox.critical(
None, "Licence expiree hors-ligne",
f"Impossible de verifier votre licence depuis {int(elapsed_hours)}h.\n"
f"Le delai hors-ligne autorise est de {timeout_hours}h.\n\n"
"Connectez-vous a internet ou contactez CopyDev :\n"
"contact@copydev.fr"
)
return False
# Pas de cache — demander la cle de licence
key, ok = QInputDialog.getText(
None,
"Copydev Imposing Tool — Activation",
"Entrez votre cle de licence :",
QLineEdit.EchoMode.Normal,
)
if not ok or not key.strip():
return False
key = key.strip()
result, msg = _check_license_online(key)
if result is True:
QMessageBox.information(
None, "Licence activee",
f"Bienvenue, {msg} !\nVotre licence est activee."
)
return True
if result is False:
QMessageBox.critical(
None, "Licence invalide",
f"{msg}\n\nContactez CopyDev : contact@copydev.fr"
)
return False
# Hors-ligne a la premiere activation
QMessageBox.critical(
None, "Connexion requise",
"Impossible de contacter le serveur de licences.\n"
"Une connexion internet est necessaire pour la premiere activation.\n\n"
"Contactez CopyDev : contact@copydev.fr"
)
return False
def main():
app = QApplication(sys.argv)
app.setApplicationName("Copydev Imposing Tool")
app.setOrganizationName("Copydev")
# Icone application
from PyQt6.QtGui import QIcon
icon_path = os.path.join(BUNDLE_DIR, "resources", "logo.png")
if os.path.exists(icon_path):
app.setWindowIcon(QIcon(icon_path))
if not _check_license():
sys.exit(1)
from app.main_window import MainWindow
window = MainWindow()
window.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()