From a0e9d3e2a07ee881d4cd5fee1bfa99299112bfb2 Mon Sep 17 00:00:00 2001 From: admingit Date: Mon, 23 Feb 2026 20:54:55 +0100 Subject: [PATCH] Update App --- .DS_Store | Bin 6148 -> 8196 bytes .gitignore | 1 + apps/.DS_Store | Bin 8196 -> 8196 bytes .../pusher_app_prem/README.md | 766 ++++++++++ .../appserver/static/git_pusher.js | 1055 ++++++++++++++ .../appserver/static/git_pusher.js_old | 0 .../appserver/static/git_pusher_config.js | 391 +++++ .../static/license_file_management.js | 613 ++++++++ .../appserver/static/license_validation.js | 1291 +++++++++++++++++ .../static/license_validation.js_old | 0 .../static/license_validation.js_old2 | 0 .../static/license_validation.js_old3 | 0 .../pusher_app_prem/bin/README | 1 + .../license_validator.cpython-39.pyc | Bin 0 -> 9715 bytes .../bin/credentials_manager.py | 271 ++++ .../pusher_app_prem/bin/git_pusher.pid | 1 + .../pusher_app_prem/bin/git_pusher.py | 984 +++++++++++++ .../pusher_app_prem/bin/git_pusher.py_old | 0 .../pusher_app_prem/bin/license_endpoints.py | 191 +++ .../pusher_app_prem/bin/license_validator.py | 468 ++++++ .../bin/license_validator.py_old | 0 .../pusher_app_prem/bin/start_git_pusher.sh | 354 +++++ .../bin/start_git_pusher.sh.V1 | 0 .../pusher_app_prem/certs/server.crt | 19 + .../pusher_app_prem/certs/server.key | 28 + .../pusher_app_prem/default/app.conf | 16 + .../default/data/ui/nav/default.xml | 4 + .../default/data/ui/views/README | 1 + .../pusher_app_prem/local/.credentials | 1 + .../pusher_app_prem/local/.key | 1 + .../pusher_app_prem/local/.usage_stats | 6 + .../pusher_app_prem/local/app.conf | 6 + .../pusher_app_prem/local/certs/server.crt | 49 + .../local/certs/server.crt.bak | 29 + .../pusher_app_prem/local/certs/server.key | 6 + .../local/certs/server.key.bak | 52 + .../pusher_app_prem/local/config.json | 22 + .../git_pusher_-_deploy_applicationsV1.xml | 572 ++++++++ .../git_pusher_-_push_applications_to_git.xml | 256 ++++ .../git_pusher_-_push_dashboards_to_git.xml | 254 ++++ .../local/data/ui/views/git_pusher_config.xml | 0 .../data/ui/views/git_pusher_dashboard.xml | 0 .../pusher_app_prem/local/usage_stats.json | 1 + .../pusher_app_prem/metadata/default.meta | 35 + .../pusher_app_prem/metadata/local.meta | 30 + apps/pusher_app_prem/default/app.conf | 6 +- .../data/ui/views/git_pusher_config.xml | 311 ++++ .../data/ui/views/git_pusher_dashboard.xml | 661 +++++++++ 48 files changed, 8750 insertions(+), 3 deletions(-) create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/README.md create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher.js rename apps/{ => Version git_pusheravant_nettoyage}/pusher_app_prem/appserver/static/git_pusher.js_old (100%) create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher_config.js create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_file_management.js create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js rename apps/{ => Version git_pusheravant_nettoyage}/pusher_app_prem/appserver/static/license_validation.js_old (100%) rename apps/{ => Version git_pusheravant_nettoyage}/pusher_app_prem/appserver/static/license_validation.js_old2 (100%) rename apps/{ => Version git_pusheravant_nettoyage}/pusher_app_prem/appserver/static/license_validation.js_old3 (100%) create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/README create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/__pycache__/license_validator.cpython-39.pyc create mode 100755 apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/credentials_manager.py create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/git_pusher.pid create mode 100755 apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/git_pusher.py rename apps/{ => Version git_pusheravant_nettoyage}/pusher_app_prem/bin/git_pusher.py_old (100%) create mode 100755 apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/license_endpoints.py create mode 100755 apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/license_validator.py rename apps/{ => Version git_pusheravant_nettoyage}/pusher_app_prem/bin/license_validator.py_old (100%) create mode 100755 apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/start_git_pusher.sh rename apps/{ => Version git_pusheravant_nettoyage}/pusher_app_prem/bin/start_git_pusher.sh.V1 (100%) create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/certs/server.crt create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/certs/server.key create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/app.conf create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/data/ui/nav/default.xml create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/data/ui/views/README create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.credentials create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.key create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.usage_stats create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/app.conf create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.crt create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.crt.bak create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.key create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.key.bak create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/config.json create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_-_deploy_applicationsV1.xml create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_-_push_applications_to_git.xml create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_-_push_dashboards_to_git.xml rename apps/{ => Version git_pusheravant_nettoyage}/pusher_app_prem/local/data/ui/views/git_pusher_config.xml (100%) rename apps/{ => Version git_pusheravant_nettoyage}/pusher_app_prem/local/data/ui/views/git_pusher_dashboard.xml (100%) create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/usage_stats.json create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/metadata/default.meta create mode 100644 apps/Version git_pusheravant_nettoyage/pusher_app_prem/metadata/local.meta create mode 100644 apps/pusher_app_prem/default/data/ui/views/git_pusher_config.xml create mode 100644 apps/pusher_app_prem/default/data/ui/views/git_pusher_dashboard.xml diff --git a/.DS_Store b/.DS_Store index ca6b235e446b97594b81e0aa99f66e64cc97d37e..d2ba66c777d9cbb996d4bb3f3120bdf567888549 100644 GIT binary patch delta 803 zcmZoMXmOBWU|?W$DortDU;r^WfEYvza8E20o2aKKDhQGX@)T4n*}+< zST-wg^fE7I=ir#wz@iCK#=?-uPymF*$V!3YPC%^p9}E~6CiAfL3R{}$D41GW*6Ju! zTNqjBC>R?XZC=A-##En^ZWx@LpIZRb!NAPh-U+1Orsn3mxIi7i@$7eFb>Xt(j;Qh} zc;yQ+kj!>j0Mv>wyDYdUFDF0GHXSGk^eqDqLkiF{B@C%RoXL<2r1cmofOHO;*ERvw zBE0sFO-Tk-0izO{0=;?;UXraY830Vh_&B+kN;L700;KJYwr1gM~ zNI|uOi3v@I5JNH0+(d>Vpe-2;K0sC;(56y|ef8LV!c>ICkOGDrptd}qQ+0u?L@*m< zq#n@Ve4uz5szbmLJr5SqK=b&34ndfq$4~}zmU0nLFcYL5O*1Gcp_(@qZebE+2J(SG wf*VM7Z)Vu3^o!3b6Gx9!S>D_6OJAlKS?2e1ZQdI!k`TngUD zZTrs9G>KQ}z%aw`e9t%EyBq8V`%$|NKmau$z?j>^1lDEoiBZ^d6UdjJ>)+#t6yyXn5A}kJhIq%Q#vEpw+{`-TeSUi1|O^78Yaa7BI z?=GC8OY>Nt&)_BJ>Zh`R5*f;bO~y(ogSR-iU(~5cf9E)_Zz3^X?|Qs!b^hV>SMdXE CD!o|% delta 64 zcmZp1XmOa}FUrNhz`)4BAi%(o%231*&ydJaz)-NUa2or>2Hwr=94s7+T$|?z)U!;U UB9pnXLYR3oyTmt^jTP+70N|AnkpKVy diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/README.md b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/README.md new file mode 100644 index 00000000..da92895d --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/README.md @@ -0,0 +1,766 @@ +# 🚀 Git Pusher for Splunk + +**Version 2.1** | Application Splunk pour déployer vos applications vers Git et le Search Head Cluster + +--- + +## 📋 Table des matières + +- [Présentation](#-présentation) +- [Fonctionnalités](#-fonctionnalités) +- [Architecture](#-architecture) +- [Installation - Serveur Source](#-installation---serveur-source) +- [Installation - SH Deployer Agent](#-installation---sh-deployer-agent) +- [Configuration](#-configuration) +- [Configuration HTTPS](#-configuration-https) +- [Système de Licence](#-système-de-licence) +- [Utilisation](#-utilisation) +- [Sécurité](#-sécurité) +- [Personnalisation du Dashboard](#-personnalisation-du-dashboard) +- [Dépannage](#-dépannage) +- [API Reference](#-api-reference) +- [Changelog](#-changelog) +- [Support](#-support) + +--- + +## 🎯 Présentation + +**Git Pusher** est une application Splunk Enterprise qui permet de : +1. **Versionner** vos applications Splunk dans un repository Git +2. **Déployer automatiquement** vers un Search Head Cluster via le SH Deployer + +Le workflow complet en un clic : +``` +Splunk Source → Push Git → Pull SH Deployer → Apply Bundle → Search Head Cluster +``` + +Idéal pour : +- 📦 Sauvegarder vos configurations Splunk +- 🔄 Versionner vos dashboards et applications +- 👥 Collaborer en équipe sur les développements Splunk +- 🚀 Mettre en place un workflow CI/CD pour Splunk +- 🎯 Déployer automatiquement vers votre Search Head Cluster + +--- + +## ✨ Fonctionnalités + +| Fonctionnalité | Description | +|----------------|-------------| +| **Push vers Git** | Déployez une ou plusieurs applications Splunk vers votre repository Git | +| **Déploiement SH Cluster** | Déploiement automatique vers le Search Head Cluster après le push Git | +| **Interface moderne** | Dashboard intuitif avec sélection visuelle des applications | +| **Multi-repository** | Support de GitHub, GitLab, Gitea, Bitbucket et tout serveur Git | +| **Support HTTPS** | Communication sécurisée avec certificats SSL | +| **Système de licence** | Gestion par fichier `.lic` sécurisé | +| **Credentials sécurisés** | Chiffrement des mots de passe Splunk | +| **Logs détaillés** | Traçabilité complète des opérations | + +--- + +## 🏗 Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ SERVEUR SOURCE │ +│ ┌─────────────┐ ┌─────────────────────────────────────┐ │ +│ │ Splunk │────▶│ Git Pusher Server (:9999) │ │ +│ │ Dashboard │ │ 1. Push apps vers Git │ │ +│ │ (HTTPS) │ │ 2. Appelle le SH Deployer Agent │ │ +│ └─────────────┘ └──────────────────┬──────────────────┘ │ +└─────────────────────────────────────────┼───────────────────────┘ + │ HTTPS (:9998) + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ SH DEPLOYER │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ Deployer Agent (:9998) │ │ +│ │ 1. Git pull dans /opt/splunk/etc/shcluster/apps/ │ │ +│ │ 2. Exécute: splunk apply shcluster-bundle │ │ +│ └─────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ SEARCH HEAD CLUSTER │ +│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ +│ │ SH1 │ │ SH2 │ │ SH3 │ │ +│ └───────────┘ └───────────┘ └───────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Structure des fichiers + +``` +SERVEUR SOURCE - pusher_app_prem/ +├── bin/ +│ ├── git_pusher.py # Serveur HTTP/HTTPS principal (port 9999) +│ ├── license_validator.py # Validation des licences +│ ├── license_generator.py # Génération des licences (vendeur) +│ ├── credentials_manager.py # Gestion sécurisée des credentials +│ └── start_git_pusher.sh # Script de démarrage +├── appserver/static/ +│ ├── git_pusher.js # Logique JavaScript principale +│ └── license_validation.js # Interface de gestion des licences +├── default/data/ui/views/ +│ └── git_pusher_-_deploy_applications.xml # Dashboard principal +├── local/ +│ ├── license.lic # Fichier de licence (après activation) +│ ├── .credentials # Credentials chiffrés +│ ├── .key # Clé de chiffrement +│ └── certs/ # Certificats SSL +│ ├── server.crt +│ └── server.key +└── README.md + +SH DEPLOYER - deployer_agent/ +├── bin/ +│ ├── deployer_agent.py # Agent de déploiement (port 9998) +│ └── start_deployer_agent.sh # Script de démarrage +└── local/ + └── certs/ # Certificats SSL + ├── server.crt + └── server.key +``` + +--- + +## 📥 Installation - Serveur Source + +### Prérequis + +- Splunk Enterprise 8.x ou supérieur +- Python 3.7+ +- Git installé sur le serveur (`yum install git` ou `apt install git`) +- OpenSSL (pour la génération des certificats HTTPS) +- Accès réseau vers votre repository Git + +### Étapes d'installation + +#### 1. Extraire l'application + +```bash +# Copier l'application dans Splunk +cp -r pusher_app_prem /opt/splunk/etc/apps/ + +# Définir les permissions +chown -R splunk:splunk /opt/splunk/etc/apps/pusher_app_prem +chmod +x /opt/splunk/etc/apps/pusher_app_prem/bin/*.sh +``` + +#### 2. Configurer les credentials Splunk + +```bash +cd /opt/splunk/etc/apps/pusher_app_prem/bin/ +./start_git_pusher.sh credentials setup +``` + +``` +================================================== +Git Pusher - Credentials Setup +================================================== + +Splunk Username [admin]: admin +Splunk Password: ******** +Confirm Password: ******** + +✓ Credentials saved securely! +``` + +#### 3. Configurer HTTPS (si Splunk est en HTTPS) + +```bash +# Créer le dossier des certificats +mkdir -p /opt/splunk/etc/apps/pusher_app_prem/local/certs + +# Générer un certificat auto-signé (valide 365 jours) +openssl req -x509 -newkey rsa:4096 \ + -keyout /opt/splunk/etc/apps/pusher_app_prem/local/certs/server.key \ + -out /opt/splunk/etc/apps/pusher_app_prem/local/certs/server.crt \ + -days 365 -nodes -subj "/CN=git-pusher" + +# Définir les permissions +chmod 600 /opt/splunk/etc/apps/pusher_app_prem/local/certs/server.key +chown -R splunk:splunk /opt/splunk/etc/apps/pusher_app_prem/local/certs/ +``` + +#### 4. Démarrer le serveur Git Pusher + +```bash +./start_git_pusher.sh start +``` + +#### 5. Ouvrir le firewall (si nécessaire) + +```bash +# FirewallD +sudo firewall-cmd --add-port=9999/tcp --permanent +sudo firewall-cmd --reload + +# UFW +sudo ufw allow 9999/tcp +``` + +#### 6. Redémarrer Splunk + +```bash +/opt/splunk/bin/splunk restart +``` + +#### 7. Accepter le certificat dans le navigateur + +1. Ouvrir : `https://VOTRE_IP_SPLUNK:9999/health` +2. Accepter le certificat auto-signé +3. Rafraîchir le dashboard (Ctrl+Shift+R) + +--- + +## 📥 Installation - SH Deployer Agent + +### Sur le serveur SH Deployer + +#### 1. Créer l'application + +```bash +# Créer les dossiers +mkdir -p /opt/splunk/etc/apps/deployer_agent/bin +mkdir -p /opt/splunk/etc/apps/deployer_agent/local/certs + +# Copier les fichiers +cp deployer_agent.py /opt/splunk/etc/apps/deployer_agent/bin/ +cp start_deployer_agent.sh /opt/splunk/etc/apps/deployer_agent/bin/ + +# Rendre exécutable +chmod +x /opt/splunk/etc/apps/deployer_agent/bin/start_deployer_agent.sh +``` + +#### 2. Configurer le token d'authentification + +```bash +nano /opt/splunk/etc/apps/deployer_agent/bin/deployer_agent.py +``` + +Modifier la ligne `AUTH_TOKEN` : +```python +AUTH_TOKEN = "votre_token_secret_personnalise" +``` + +#### 3. Configurer le Search Head Captain + +Dans le même fichier, trouver la fonction `apply_shcluster_bundle` et modifier l'IP du captain : +```python +target_uri = "https://IP_DU_CAPTAIN:8089" +``` + +#### 4. Générer les certificats SSL + +```bash +cd /opt/splunk/etc/apps/deployer_agent/bin/ +./start_deployer_agent.sh gencerts +``` + +#### 5. Définir les permissions + +```bash +chown -R splunk:splunk /opt/splunk/etc/apps/deployer_agent +``` + +#### 6. Ouvrir le firewall + +```bash +sudo firewall-cmd --add-port=9998/tcp --permanent +sudo firewall-cmd --reload +``` + +#### 7. Démarrer l'agent + +```bash +./start_deployer_agent.sh start +``` + +#### 8. Vérifier le statut + +```bash +./start_deployer_agent.sh status +``` + +#### 9. Accepter le certificat + +Ouvrir dans un navigateur : `https://IP_SH_DEPLOYER:9998/health` +Accepter le certificat auto-signé. + +--- + +## ⚙️ Configuration + +### Commandes Git Pusher (Serveur Source) + +```bash +cd /opt/splunk/etc/apps/pusher_app_prem/bin/ + +# Démarrer le serveur +./start_git_pusher.sh start + +# Arrêter le serveur +./start_git_pusher.sh stop + +# Redémarrer le serveur +./start_git_pusher.sh restart + +# Voir le statut +./start_git_pusher.sh status + +# Voir les logs +./start_git_pusher.sh logs +./start_git_pusher.sh logs -f # Mode follow + +# Gestion des credentials +./start_git_pusher.sh credentials setup +./start_git_pusher.sh credentials status +./start_git_pusher.sh credentials delete +``` + +### Commandes Deployer Agent (SH Deployer) + +```bash +cd /opt/splunk/etc/apps/deployer_agent/bin/ + +# Démarrer l'agent +./start_deployer_agent.sh start + +# Arrêter l'agent +./start_deployer_agent.sh stop + +# Redémarrer l'agent +./start_deployer_agent.sh restart + +# Voir le statut +./start_deployer_agent.sh status + +# Voir les logs +./start_deployer_agent.sh logs +./start_deployer_agent.sh logs -f + +# Générer les certificats SSL +./start_deployer_agent.sh gencerts + +# Tester la connexion +./start_deployer_agent.sh test +``` + +### Configuration du SH Deployer dans l'interface + +1. Ouvrir le dashboard Git Pusher +2. Cliquer sur **⚙️ Configure** dans la section "Deploy to Search Head Cluster" +3. Remplir : + - **Host** : IP du SH Deployer (ex: 10.10.40.14) + - **Port** : 9998 + - **Token** : Le même token que dans `deployer_agent.py` +4. Cliquer sur **Save & Test** + +--- + +## 🔒 Configuration HTTPS + +### Git Pusher Server (Port 9999) + +```bash +mkdir -p /opt/splunk/etc/apps/pusher_app_prem/local/certs + +openssl req -x509 -newkey rsa:4096 \ + -keyout /opt/splunk/etc/apps/pusher_app_prem/local/certs/server.key \ + -out /opt/splunk/etc/apps/pusher_app_prem/local/certs/server.crt \ + -days 365 -nodes -subj "/CN=git-pusher" + +chmod 600 /opt/splunk/etc/apps/pusher_app_prem/local/certs/server.key +chown -R splunk:splunk /opt/splunk/etc/apps/pusher_app_prem/local/certs/ +``` + +### Deployer Agent (Port 9998) + +```bash +mkdir -p /opt/splunk/etc/apps/deployer_agent/local/certs + +openssl req -x509 -newkey rsa:4096 \ + -keyout /opt/splunk/etc/apps/deployer_agent/local/certs/server.key \ + -out /opt/splunk/etc/apps/deployer_agent/local/certs/server.crt \ + -days 365 -nodes -subj "/CN=deployer-agent" + +chmod 600 /opt/splunk/etc/apps/deployer_agent/local/certs/server.key +chown -R splunk:splunk /opt/splunk/etc/apps/deployer_agent/local/certs/ +``` + +### Vérifier HTTPS + +```bash +# Git Pusher +curl -k https://localhost:9999/health + +# Deployer Agent +curl -k https://localhost:9998/health +``` + +--- + +## 🔐 Système de Licence + +Git Pusher utilise un système de licence par fichier `.lic` pour activer les fonctionnalités. + +### Types de licences + +| Type | Durée | Apps max | Pushes/jour | Fonctionnalités | +|------|-------|----------|-------------|-----------------| +| **Trial** | 14 jours | 3 | 5 | Push basique | +| **Starter** | 1 an | 10 | 50 | + Push programmé | +| **Professional** | 1 an | Illimité | Illimité | + Multi-repo, Support prioritaire | +| **Enterprise** | 1 an | Illimité | Illimité | + SH Cluster deployment, API | + +### Activer une licence + +1. Ouvrir le dashboard Git Pusher +2. Glisser-déposer le fichier `.lic` +3. Cliquer sur "Activer" + +--- + +## 📖 Utilisation + +### Workflow complet : Push Git + Déploiement SH Cluster + +1. **Ouvrir le dashboard** Git Pusher + +2. **Sélectionner les applications** à déployer + +3. **Configurer Git** : + - Repository URL : `https://github.com/user/repo.git` + - Branch : `main` + - Token : Personal Access Token + +4. **Activer le déploiement SH Cluster** : + - Cocher "Enable automatic deployment" + - (Optionnel) Remplir les credentials Splunk si différents de l'admin par défaut + +5. **Cliquer sur "Deploy to Git"** + +Le processus automatique : +``` +✅ Push vers Git +✅ Pull sur le SH Deployer +✅ Apply shcluster-bundle +✅ Mise à jour du Search Head Cluster +``` + +### Obtenir un token Git + +#### GitHub +1. Settings → Developer settings → Personal access tokens +2. Generate new token +3. Cocher : `repo` (Full control) + +#### GitLab +1. Preferences → Access Tokens +2. Create personal access token +3. Scopes : `write_repository` + +#### Gitea +1. Settings → Applications → Generate New Token +2. Permissions : `repository: write` + +--- + +## 🔒 Sécurité + +### Credentials Splunk + +- **Chiffrés** avec une clé dérivée de l'ID machine +- **Stockés** dans un fichier avec permissions `600` +- **Jamais visibles** en clair + +### Communication HTTPS + +- SSL/TLS entre tous les composants +- Certificats auto-signés supportés +- Validation du token d'authentification + +### Token Deployer Agent + +- Authentification par token entre Git Pusher et Deployer Agent +- Token configurable dans les deux composants +- Doit être identique des deux côtés + +### Bonnes pratiques + +1. ✅ Utiliser HTTPS pour tous les composants +2. ✅ Changer le token par défaut du Deployer Agent +3. ✅ Utiliser des tokens Git avec permissions minimales +4. ✅ Restreindre l'accès réseau au port 9998/9999 +5. ✅ Renouveler les certificats régulièrement + +--- + +## 🎨 Personnalisation du Dashboard + +### Masquer les boutons d'édition + +```bash +nano /opt/splunk/etc/apps/pusher_app_prem/default/data/ui/views/git_pusher_-_deploy_applications.xml +``` + +Modifier la première ligne : +```xml + +``` + +### Options disponibles + +| Attribut | Description | +|----------|-------------| +| `hideEdit="true"` | Masque le bouton "Modifier" | +| `hideExport="true"` | Masque le bouton "Exporter" | +| `hideTitle="true"` | Masque le titre du dashboard | +| `hideSplunkBar="true"` | Masque la barre Splunk en haut | +| `hideAppBar="true"` | Masque la barre de l'application | +| `hideFooter="true"` | Masque le footer | + +### Appliquer les changements + +```bash +rm -rf /opt/splunk/var/run/splunk/appserver/* +/opt/splunk/bin/splunk restart +``` + +--- + +## 🔧 Dépannage + +### Les boutons ne fonctionnent pas + +Le fichier JavaScript doit exposer les fonctions globalement. Vérifier que le bloc suivant est présent à la fin de `git_pusher.js` : + +```javascript +// Exposer les fonctions globalement +window.showDeployerConfigModal = showDeployerConfigModal; +window.closeDeployerConfigModal = closeDeployerConfigModal; +window.saveDeployerConfigFromModal = saveDeployerConfigFromModal; +window.toggleDeployerAuth = toggleDeployerAuth; + +// Attacher les événements aux boutons +(function attachButtonEvents() { + function tryAttach() { + var pushBtn = document.getElementById('push-btn'); + if (pushBtn) { + pushBtn.addEventListener('click', function(e) { + e.preventDefault(); + pushDashboards(); + }); + } + + var buttons = document.querySelectorAll('button.btn'); + buttons.forEach(function(btn) { + if (btn.textContent.includes('Reset')) { + btn.addEventListener('click', function(e) { + e.preventDefault(); + resetForm(true); + }); + } + }); + + var configBtn = document.querySelector('.deployer-config-btn'); + if (configBtn) { + configBtn.addEventListener('click', function(e) { + e.preventDefault(); + showDeployerConfigModal(); + }); + } + + if (!pushBtn) setTimeout(tryAttach, 500); + } + + if (document.readyState === 'complete') { + setTimeout(tryAttach, 1000); + } else { + window.addEventListener('load', function() { + setTimeout(tryAttach, 1000); + }); + } +})(); +``` + +Puis vider le cache : +```bash +rm -rf /opt/splunk/var/run/splunk/appserver/* +/opt/splunk/bin/splunk restart +``` + +Et dans le navigateur : **Ctrl+Shift+R** + +### Erreur 401 Unauthorized (Deployer) + +Le token ne correspond pas entre les deux composants. + +1. Vérifier le token sur le SH Deployer : +```bash +grep "AUTH_TOKEN" /opt/splunk/etc/apps/deployer_agent/bin/deployer_agent.py +``` + +2. Configurer le même token dans l'interface (⚙️ Configure) + +3. Tester : +```bash +curl -k -H "X-Auth-Token: VOTRE_TOKEN" https://IP_DEPLOYER:9998/status +``` + +### Erreur "tcsetattr: Inappropriate ioctl for device" + +La commande `splunk apply shcluster-bundle` attend une entrée interactive. + +Solution : Modifier la fonction `apply_shcluster_bundle` dans `deployer_agent.py` pour utiliser `echo 'y' |` : + +```python +shell_cmd = f"echo 'y' | {SPLUNK_BIN} apply shcluster-bundle -target {target_uri} -auth {auth_user}:'{escaped_pass}' -preserve-lookups true" +``` + +### Erreur CORS + +Vider le cache Splunk et navigateur : +```bash +rm -rf /opt/splunk/var/run/splunk/appserver/* +/opt/splunk/bin/splunk restart +``` +Puis **Ctrl+Shift+R** dans le navigateur. + +### Le SH Deployer ne répond pas + +```bash +# Vérifier le statut +./start_deployer_agent.sh status + +# Voir les logs +tail -50 /opt/splunk/var/log/splunk/deployer_agent.log + +# Redémarrer +./start_deployer_agent.sh restart +``` + +### Le bundle ne s'applique pas + +1. Vérifier que le pull a fonctionné : +```bash +ls -la /opt/splunk/etc/shcluster/apps/ +``` + +2. Vérifier les logs : +```bash +grep -i "bundle\|error" /opt/splunk/var/log/splunk/deployer_agent.log | tail -30 +``` + +3. Tester manuellement : +```bash +echo 'y' | /opt/splunk/bin/splunk apply shcluster-bundle -target https://CAPTAIN_IP:8089 -auth admin:'password' -preserve-lookups true +``` + +### Vider le cache Splunk + +```bash +rm -rf /opt/splunk/var/run/splunk/appserver/* +/opt/splunk/bin/splunk restart +``` + +--- + +## 📡 API Reference + +### Git Pusher Server (Port 9999) + +| Méthode | Endpoint | Description | +|---------|----------|-------------| +| `GET` | `/health` | Health check | +| `GET` | `/license` | Statut de la licence | +| `GET` | `/license/hostname` | Hostname Splunk | +| `GET` | `/deployer/health` | Santé du SH Deployer | +| `GET` | `/deployer/status` | Statut du SH Deployer | +| `GET` | `/deployer/config` | Configuration du SH Deployer | +| `POST` | `/license/upload` | Uploader une licence | +| `POST` | `/push` | Pousser les applications | + +### Deployer Agent (Port 9998) + +| Méthode | Endpoint | Description | +|---------|----------|-------------| +| `GET` | `/health` | Health check (pas d'auth) | +| `GET` | `/status` | Statut du déploiement | +| `GET` | `/apps` | Liste des apps | +| `GET` | `/history` | Historique des déploiements | +| `POST` | `/pull` | Git pull | +| `POST` | `/deploy` | Apply shcluster-bundle | +| `POST` | `/pull-and-deploy` | Pull + Deploy en une opération | + +### Exemple : Push avec déploiement SH Cluster + +```bash +curl -k -X POST "https://localhost:9999/push?git_url=https://github.com/user/repo.git&git_branch=main&git_token=TOKEN&commit_message=Update&apps=[{\"id\":\"my_app\"}]&user=admin&deploy_to_shcluster=true" +``` + +--- + +## 📝 Changelog + +### Version 2.1.0 (Février 2026) +- 🚀 **Nouveau** : Déploiement automatique vers Search Head Cluster +- 🔧 **Nouveau** : Agent Deployer pour le SH Deployer +- ⚙️ **Nouveau** : Interface de configuration du SH Deployer +- 🔐 **Amélioration** : Gestion des caractères spéciaux dans les mots de passe +- 🛠️ **Correction** : Mode non-interactif pour shcluster-bundle + +### Version 2.0.0 (Février 2026) +- ✨ Nouveau système de licence par fichier `.lic` +- 🔐 Credentials Splunk chiffrés +- 🔒 Support HTTPS avec certificats SSL +- 🎨 Interface utilisateur modernisée +- 📊 Badge de licence en temps réel +- 🔧 Script de gestion amélioré +- 🛡️ Options pour masquer les boutons d'édition du dashboard +- 📝 Logs détaillés +- 🐛 Correction des problèmes CORS + +### Version 1.0.0 +- 🚀 Version initiale +- Push d'applications vers Git +- Interface basique + +--- + +## 📞 Support + +### Obtenir de l'aide + +- 📧 Email : support@gitpusher.com +- 🌐 Site web : https://gitpusher.com +- 📖 Documentation : https://docs.gitpusher.com + +### Signaler un bug + +Incluez dans votre rapport : +1. Version de Git Pusher +2. Version de Splunk +3. Configuration (HTTP/HTTPS) +4. Architecture (standalone, SH Cluster) +5. Logs Git Pusher (`/opt/splunk/var/log/splunk/git_pusher.log`) +6. Logs Deployer Agent (`/opt/splunk/var/log/splunk/deployer_agent.log`) +7. Erreurs de la console navigateur (F12) +8. Étapes pour reproduire le problème + +--- + +## 📄 Licence + +Git Pusher est un logiciel propriétaire. Une licence valide est requise pour son utilisation. + +© 2026 Git Pusher - Tous droits réservés + +--- + +

+ Made with ❤️ for Splunk administrators +

diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher.js b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher.js new file mode 100644 index 00000000..74e7881c --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher.js @@ -0,0 +1,1055 @@ +// ============================================ +// GIT PUSHER - MAIN JAVASCRIPT +// Version 2.1 avec déploiement vers SH Cluster +// ============================================ + +// Configuration par défaut +const DEFAULT_CONFIG = { + api: { + url: '', + port: 9999, + useProxy: true + }, + deployer: { + enabled: false, + host: '', + port: 9998, + token: '', + useSSL: true + } +}; + +// Charger la configuration +function loadAppConfig() { + try { + const stored = localStorage.getItem('git_pusher_config'); + if (stored) { + return JSON.parse(stored); + } + } catch (e) { + console.warn('Erreur chargement config localStorage:', e); + } + return DEFAULT_CONFIG; +} + +// Déterminer l'URL du serveur API +function getServerUrl() { + const config = loadAppConfig(); + const hostname = window.location.hostname; + const protocol = window.location.protocol; + + // Si une URL est configurée, l'utiliser + if (config.api && config.api.url) { + let url = config.api.url; + // Ajouter le port si pas de proxy + if (!config.api.useProxy && config.api.port) { + url = url.replace(/\/$/, '') + ':' + config.api.port; + } + return url; + } + + // Auto-détection basée sur le hostname + // Si accès via le domaine Splunk principal, utiliser le domaine API + if (hostname === 'myprivspldev.jp-engineering.fr') { + return protocol + '//myprivspldev-api.jp-engineering.fr'; + } + + // Si déjà sur le domaine API + if (hostname === 'myprivspldev-api.jp-engineering.fr') { + return protocol + '//' + hostname; + } + + // Si c'est une IP ou localhost, ajouter le port 9999 + if (/^(\d{1,3}\.){3}\d{1,3}$/.test(hostname) || hostname === 'localhost') { + return protocol + '//' + hostname + ':9999'; + } + + // Par défaut, ajouter le port 9999 + return protocol + '//' + hostname + ':9999'; +} + +// Configuration +const GIT_PUSHER_CONFIG = { + serverUrl: getServerUrl(), + credentialsKey: 'git_pusher_credentials', + deployerConfigKey: 'git_pusher_deployer_config', + version: '2.1.0' +}; + +// Configuration SH Deployer (peut être modifiée via l'interface) +let SH_DEPLOYER_CONFIG = { + enabled: false, + host: '10.10.40.14', + port: 9998, + token: '' +}; + +// État global +let selectedApps = []; +let selectedShClusterApps = []; // Apps sélectionnées pour le SH Cluster +let isProcessing = false; +let deployerAvailable = false; + +// ============================================ +// INITIALISATION +// ============================================ + +require([ + 'jquery', + 'splunkjs/mvc', + 'splunkjs/mvc/searchmanager', + 'splunkjs/mvc/simplexml/ready!' +], function($, mvc, SearchManager) { + + console.log("Git Pusher v2.1 initializing..."); + + // Initialiser le système de licence + if (typeof initializeLicense === 'function') { + initializeLicense(); + } else { + console.warn("License system not loaded"); + } + + // Charger les credentials sauvegardés + loadSavedCredentials(); + + // Charger la config du deployer + loadDeployerConfig(); + + // Vérifier la disponibilité du SH Deployer + checkDeployerHealth(); + + // Récupérer les résultats de recherche pour les apps + const searchManager = mvc.Components.get('dsearch'); + + if (searchManager) { + searchManager.on('search:done', function() { + const results = searchManager.data('results'); + if (results) { + results.on('data', function() { + const rows = results.data().rows; + const fields = results.data().fields; + renderAppsList(rows, fields); + }); + } + }); + } + + // Exposer les fonctions globalement + window.pushDashboards = pushDashboards; + window.resetForm = resetForm; + window.toggleSelectAll = toggleSelectAll; + window.toggleShClusterAllApps = toggleShClusterAllApps; + window.updateSelectedShClusterApps = updateSelectedShClusterApps; + + // Attacher les événements pour la section SH Cluster + setTimeout(function() { + // Checkbox "Deploy to SH Cluster" + const deployCheckbox = document.getElementById('deploy-to-shcluster'); + if (deployCheckbox) { + deployCheckbox.addEventListener('change', function() { + toggleDeployerOptions(); + }); + } + + // Checkbox "All apps" + const allAppsCheckbox = document.getElementById('shcluster-all-apps'); + if (allAppsCheckbox) { + allAppsCheckbox.addEventListener('change', function() { + toggleShClusterAllApps(); + }); + } + + // Bouton configure + const configBtn = document.getElementById('deployer-config-btn'); + if (configBtn) { + configBtn.addEventListener('click', function() { + showDeployerConfigModal(); + }); + } + }, 500); +}); + +// Afficher/masquer les options du deployer +function toggleDeployerOptions() { + const checkbox = document.getElementById('deploy-to-shcluster'); + const appsSection = document.getElementById('deployer-apps-section'); + const authSection = document.getElementById('deployer-auth'); + + if (checkbox && checkbox.checked) { + if (appsSection) appsSection.classList.add('visible'); + if (authSection) authSection.classList.add('visible'); + } else { + if (appsSection) appsSection.classList.remove('visible'); + if (authSection) authSection.classList.remove('visible'); + } +} + +// ============================================ +// RENDU DE LA LISTE DES APPLICATIONS +// ============================================ + +function renderAppsList(rows, fields) { + const container = document.getElementById('dashboard-list'); + if (!container) return; + + // Trouver les index des colonnes + const nameIdx = fields.indexOf('name'); + const labelIdx = fields.indexOf('label'); + const descIdx = fields.indexOf('description'); + + // Générer le HTML + let html = ` +
+
+ + +
+ ${rows.length} apps +
+ `; + + rows.forEach((row, index) => { + const name = row[nameIdx] || ''; + const label = row[labelIdx] || name; + const desc = row[descIdx] || ''; + + // Ignorer certaines apps système + if (name.startsWith('splunk_') || name === 'learned' || name === 'launcher') { + return; + } + + html += ` +
+ + +
+ `; + }); + + container.innerHTML = html; + + console.log(`Rendered ${rows.length} applications`); +} + +// ============================================ +// GESTION DE LA SÉLECTION +// ============================================ + +function updateSelectedApps() { + const checkboxes = document.querySelectorAll('#dashboard-list input[type="checkbox"][data-app-id]'); + selectedApps = []; + + checkboxes.forEach(cb => { + if (cb.checked) { + selectedApps.push({ + id: cb.getAttribute('data-app-id'), + label: cb.getAttribute('data-app-label') + }); + } + }); + + // Mettre à jour le "Select All" + const selectAll = document.getElementById('select-all'); + if (selectAll) { + const allChecked = Array.from(checkboxes).every(cb => cb.checked); + const someChecked = Array.from(checkboxes).some(cb => cb.checked); + selectAll.checked = allChecked; + selectAll.indeterminate = someChecked && !allChecked; + } + + // Mettre à jour la liste des apps pour le SH Cluster + updateShClusterAppsList(); + + console.log(`Selected ${selectedApps.length} apps`); +} + +function updateShClusterAppsList() { + const container = document.getElementById('shcluster-apps-container'); + if (!container) return; + + if (selectedApps.length === 0) { + container.innerHTML = '

Select apps from the left panel first

'; + selectedShClusterApps = []; + return; + } + + // Sauvegarder l'état actuel des checkboxes + const currentState = {}; + const existingCheckboxes = container.querySelectorAll('input[type="checkbox"][data-app-id]'); + existingCheckboxes.forEach(cb => { + currentState[cb.getAttribute('data-app-id')] = cb.checked; + }); + + // Vérifier si la liste a changé (nouvelles apps ajoutées ou apps retirées) + const currentAppIds = Array.from(existingCheckboxes).map(cb => cb.getAttribute('data-app-id')); + const newAppIds = selectedApps.map(app => app.id); + const listChanged = currentAppIds.length !== newAppIds.length || + !currentAppIds.every(id => newAppIds.includes(id)); + + // Ne recréer le HTML que si la liste a changé + if (listChanged || existingCheckboxes.length === 0) { + let html = ''; + selectedApps.forEach((app, index) => { + // Préserver l'état si l'app existait, sinon cocher par défaut + const isChecked = currentState.hasOwnProperty(app.id) ? currentState[app.id] : true; + html += ` +
+ + +
+ `; + }); + + container.innerHTML = html; + } + + // Mettre à jour la liste des apps SH Cluster sélectionnées (sans recréer le HTML) + updateSelectedShClusterApps(); +} + +function updateSelectedShClusterApps() { + const allAppsCheckbox = document.getElementById('shcluster-all-apps'); + + if (allAppsCheckbox && allAppsCheckbox.checked) { + // Toutes les apps sélectionnées pour Git + selectedShClusterApps = [...selectedApps]; + } else { + // Seulement les apps cochées dans la liste SH Cluster + const checkboxes = document.querySelectorAll('#shcluster-apps-container input[type="checkbox"][data-app-id]'); + selectedShClusterApps = []; + + checkboxes.forEach(cb => { + if (cb.checked) { + selectedShClusterApps.push({ + id: cb.getAttribute('data-app-id'), + label: cb.getAttribute('data-app-label') + }); + } + }); + } + + console.log(`Selected ${selectedShClusterApps.length} apps for SH Cluster`); +} + +function toggleShClusterAllApps() { + const allAppsCheckbox = document.getElementById('shcluster-all-apps'); + const appsList = document.getElementById('shcluster-apps-list'); + + if (allAppsCheckbox && appsList) { + if (allAppsCheckbox.checked) { + // Masquer la liste et utiliser toutes les apps + appsList.style.display = 'none'; + selectedShClusterApps = [...selectedApps]; + console.log('SH Cluster: Using all selected apps'); + } else { + // Afficher la liste pour permettre la sélection manuelle + appsList.style.display = 'block'; + // Ne PAS appeler updateSelectedShClusterApps() ici + // L'utilisateur va faire sa sélection manuellement + // La liste garde son état actuel (tous cochés par défaut) + console.log('SH Cluster: Manual selection enabled'); + } + } +} + +function toggleSelectAll(checked) { + const checkboxes = document.querySelectorAll('#dashboard-list input[type="checkbox"][data-app-id]'); + checkboxes.forEach(cb => { + cb.checked = checked; + }); + updateSelectedApps(); +} + +// ============================================ +// PUSH VERS GIT +// ============================================ + +async function pushDashboards() { + console.log("Starting push process..."); + + // Vérifier si déjà en cours + if (isProcessing) { + console.log("Push already in progress"); + return; + } + + // Vérifier la licence AVANT tout + if (typeof checkLicenseBeforePush === 'function') { + const licenseOk = await checkLicenseBeforePush(); + if (!licenseOk) { + console.log("License check failed"); + return; + } + } + + // Récupérer les valeurs du formulaire + const gitUrl = document.getElementById('git-url')?.value?.trim(); + const gitBranch = document.getElementById('git-branch')?.value?.trim() || 'main'; + const gitToken = document.getElementById('git-token')?.value?.trim(); + const commitMessage = document.getElementById('commit-message')?.value?.trim(); + const saveCredentials = document.getElementById('save-credentials')?.checked; + + // Ne PAS rappeler updateSelectedApps() ici car cela réinitialiserait la liste SH Cluster + // La liste selectedApps est déjà à jour grâce aux événements onchange + + // Validation + if (!gitUrl) { + showMessage('error', 'Please enter a Git repository URL'); + return; + } + + if (!gitToken) { + showMessage('error', 'Please enter a Git token or password'); + return; + } + + if (!commitMessage) { + showMessage('error', 'Please enter a commit message'); + return; + } + + if (selectedApps.length === 0) { + showMessage('error', 'Please select at least one application to deploy'); + return; + } + + // Sauvegarder les credentials si demandé + if (saveCredentials) { + saveCredentialsToStorage(gitUrl, gitBranch, gitToken); + } + + // Vérifier si le déploiement vers SH Cluster est activé + const deployToSHCluster = document.getElementById('deploy-to-shcluster')?.checked || false; + const shAuthUser = document.getElementById('sh-auth-user')?.value?.trim() || ''; + const shAuthPass = document.getElementById('sh-auth-pass')?.value?.trim() || ''; + + // La liste selectedShClusterApps est déjà à jour via les événements onchange + // Ne pas rappeler updateSelectedShClusterApps() pour éviter de réinitialiser la sélection + + // Validation des apps SH Cluster si déploiement activé + if (deployToSHCluster && selectedShClusterApps.length === 0) { + showMessage('error', 'Please select at least one application to deploy to SH Cluster'); + return; + } + + // Démarrer le push + isProcessing = true; + showLoading(true, deployToSHCluster); + hideMessages(); + + try { + // Récupérer l'utilisateur courant + const currentUser = await getCurrentUser(); + + // Récupérer les infos de licence depuis le localStorage + const licenseInfo = getLicenseInfo ? getLicenseInfo() : null; + const licenseType = licenseInfo?.type_name || ''; + const licenseId = licenseInfo?.license_id || ''; + + // Construire les paramètres + const params = new URLSearchParams({ + git_url: gitUrl, + git_branch: gitBranch, + git_token: gitToken, + commit_message: commitMessage, + apps: JSON.stringify(selectedApps), + shcluster_apps: JSON.stringify(selectedShClusterApps), // Apps pour le SH Cluster + user: currentUser, + deploy_to_shcluster: deployToSHCluster.toString(), + deployer_host: SH_DEPLOYER_CONFIG.host, + deployer_token: SH_DEPLOYER_CONFIG.token, + license_type: licenseType, + license_id: licenseId + }); + + // Ajouter les credentials SH si fournis + if (shAuthUser) params.append('sh_auth_user', shAuthUser); + if (shAuthPass) params.append('sh_auth_pass', shAuthPass); + + console.log(`Pushing ${selectedApps.length} apps to Git${deployToSHCluster ? `, ${selectedShClusterApps.length} apps to SH Cluster` : ''}`); + + // Appeler le serveur + const response = await fetch(`${GIT_PUSHER_CONFIG.serverUrl}/push?${params.toString()}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } + }); + + const result = await response.json(); + console.log("Push result:", result); + + if (result.status === 'success') { + // Incrémenter le compteur d'utilisation côté client + console.log("=== INCREMENT USAGE ==="); + console.log("typeof incrementUsage:", typeof incrementUsage); + console.log("typeof window.incrementUsage:", typeof window.incrementUsage); + + try { + if (typeof window.incrementUsage === 'function') { + const stats = window.incrementUsage(); + console.log("✓ Usage incremented successfully:", stats); + } else if (typeof incrementUsage === 'function') { + const stats = incrementUsage(); + console.log("✓ Usage incremented (local):", stats); + } else { + console.warn("✗ incrementUsage function not available"); + } + } catch (e) { + console.error("✗ Error incrementing usage:", e); + } + + let message = `✅ Successfully deployed ${result.apps_pushed || selectedApps.length} application(s) to Git!`; + + // Ajouter le statut du déploiement SH Cluster + if (deployToSHCluster && result.shcluster_deployment) { + if (result.shcluster_deployment.success) { + message += '\n🚀 SH Cluster deployment triggered successfully!'; + } else { + message += `\n⚠️ SH Cluster deployment failed: ${result.shcluster_deployment.message}`; + } + } + + showMessage('success', message); + + // Reset la sélection après succès + setTimeout(() => { + toggleSelectAll(false); + }, 2000); + } else if (result.error_code === 'LICENSE_ERROR') { + showMessage('error', `🔐 ${result.message}`); + + // Afficher le modal de licence + if (typeof showLicenseModal === 'function') { + showLicenseModal(result.message, result.error_code); + } + } else if (result.error_code === 'APP_LIMIT') { + showMessage('error', `📦 ${result.message}`); + } else { + showMessage('error', result.message || 'Unknown error occurred'); + } + + } catch (error) { + console.error("Push error:", error); + showMessage('error', `Connection error: ${error.message}. Is the Git Pusher server running?`); + } finally { + isProcessing = false; + showLoading(false); + } +} + +// ============================================ +// UTILITAIRES UI +// ============================================ + +function showLoading(show, deployToSHCluster = false) { + const loading = document.getElementById('loading'); + const pushBtn = document.getElementById('push-btn'); + const loadingText = document.querySelector('.loading-text'); + + if (loading) { + loading.classList.toggle('active', show); + } + + if (loadingText && show) { + if (deployToSHCluster) { + loadingText.textContent = 'Deploying to Git and SH Cluster... Please wait'; + } else { + loadingText.textContent = 'Deploying applications to Git... Please wait'; + } + } + + if (pushBtn) { + pushBtn.disabled = show; + if (show) { + pushBtn.textContent = deployToSHCluster ? '⏳ Deploying to Git + SH...' : '⏳ Deploying...'; + } else { + pushBtn.textContent = '✈️ Deploy to Git'; + } + } +} + +function showMessage(type, text) { + hideMessages(); + + const successMsg = document.getElementById('success-msg'); + const errorMsg = document.getElementById('error-msg'); + const successText = document.getElementById('success-text'); + const errorText = document.getElementById('error-text'); + + if (type === 'success' && successMsg && successText) { + successText.textContent = text; + successMsg.classList.add('active'); + + // Auto-hide après 5 secondes + setTimeout(() => { + successMsg.classList.remove('active'); + }, 5000); + } else if (type === 'error' && errorMsg && errorText) { + errorText.textContent = text; + errorMsg.classList.add('active'); + } +} + +function hideMessages() { + const successMsg = document.getElementById('success-msg'); + const errorMsg = document.getElementById('error-msg'); + + if (successMsg) successMsg.classList.remove('active'); + if (errorMsg) errorMsg.classList.remove('active'); +} + +function resetForm(clearCredentials = false) { + // Reset les champs + const commitMessage = document.getElementById('commit-message'); + if (commitMessage) commitMessage.value = ''; + + if (clearCredentials) { + const gitUrl = document.getElementById('git-url'); + const gitToken = document.getElementById('git-token'); + const saveCredentials = document.getElementById('save-credentials'); + + if (gitUrl) gitUrl.value = ''; + if (gitToken) gitToken.value = ''; + if (saveCredentials) saveCredentials.checked = false; + + // Supprimer les credentials sauvegardés + localStorage.removeItem(GIT_PUSHER_CONFIG.credentialsKey); + } + + // Reset la sélection + toggleSelectAll(false); + + // Cacher les messages + hideMessages(); + + console.log("Form reset" + (clearCredentials ? " (with credentials)" : "")); +} + +// ============================================ +// GESTION DES CREDENTIALS +// ============================================ + +function saveCredentialsToStorage(gitUrl, gitBranch, gitToken) { + try { + const credentials = { + gitUrl: gitUrl, + gitBranch: gitBranch, + // Note: En production, envisager une solution plus sécurisée + gitToken: btoa(gitToken), // Encodage basique (pas sécurisé, juste pour l'obfuscation) + savedAt: new Date().toISOString() + }; + + localStorage.setItem(GIT_PUSHER_CONFIG.credentialsKey, JSON.stringify(credentials)); + console.log("Credentials saved"); + } catch (error) { + console.error("Error saving credentials:", error); + } +} + +function loadSavedCredentials() { + try { + const saved = localStorage.getItem(GIT_PUSHER_CONFIG.credentialsKey); + if (!saved) return; + + const credentials = JSON.parse(saved); + + const gitUrl = document.getElementById('git-url'); + const gitBranch = document.getElementById('git-branch'); + const gitToken = document.getElementById('git-token'); + const saveCredentials = document.getElementById('save-credentials'); + + if (gitUrl && credentials.gitUrl) { + gitUrl.value = credentials.gitUrl; + } + + if (gitBranch && credentials.gitBranch) { + gitBranch.value = credentials.gitBranch; + } + + if (gitToken && credentials.gitToken) { + gitToken.value = atob(credentials.gitToken); + } + + if (saveCredentials) { + saveCredentials.checked = true; + } + + console.log("Credentials loaded from storage"); + } catch (error) { + console.error("Error loading credentials:", error); + } +} + +// ============================================ +// RÉCUPÉRATION DE L'UTILISATEUR SPLUNK +// ============================================ + +async function getCurrentUser() { + try { + const response = await fetch('/en-US/splunkd/__raw/services/authentication/current-context?output_mode=json'); + const data = await response.json(); + return data.entry?.[0]?.content?.username || 'unknown'; + } catch (error) { + console.error("Error getting current user:", error); + return 'unknown'; + } +} + +// ============================================ +// VÉRIFICATION DU SERVEUR +// ============================================ + +async function checkServerHealth() { + try { + const response = await fetch(`${GIT_PUSHER_CONFIG.serverUrl}/health`, { + method: 'GET', + timeout: 5000 + }); + const data = await response.json(); + return data.status === 'ok'; + } catch (error) { + console.error("Server health check failed:", error); + return false; + } +} + +// ============================================ +// SH DEPLOYER FUNCTIONS +// ============================================ + +async function checkDeployerHealth() { + try { + const response = await fetch(`${GIT_PUSHER_CONFIG.serverUrl}/deployer/health`, { + method: 'GET', + timeout: 5000 + }); + const data = await response.json(); + + deployerAvailable = data.status === 'ok'; + + // Mettre à jour l'UI + updateDeployerUI(); + + console.log("SH Deployer status:", deployerAvailable ? "Available" : "Unavailable"); + return deployerAvailable; + } catch (error) { + console.error("Deployer health check failed:", error); + deployerAvailable = false; + updateDeployerUI(); + return false; + } +} + +function updateDeployerUI() { + const deployerCheckbox = document.getElementById('deploy-to-shcluster'); + const deployerStatus = document.getElementById('deployer-status'); + const deployerSection = document.getElementById('deployer-section'); + + if (deployerCheckbox) { + deployerCheckbox.disabled = !deployerAvailable; + } + + if (deployerStatus) { + if (deployerAvailable) { + deployerStatus.innerHTML = '● Connected'; + } else { + deployerStatus.innerHTML = '● Disconnected'; + } + } + + if (deployerSection && !deployerAvailable) { + deployerSection.style.opacity = '0.6'; + } +} + +function loadDeployerConfig() { + try { + const saved = localStorage.getItem(GIT_PUSHER_CONFIG.deployerConfigKey); + if (saved) { + const config = JSON.parse(saved); + SH_DEPLOYER_CONFIG = { ...SH_DEPLOYER_CONFIG, ...config }; + console.log("Deployer config loaded"); + } + } catch (error) { + console.error("Error loading deployer config:", error); + } +} + +function saveDeployerConfig() { + try { + localStorage.setItem(GIT_PUSHER_CONFIG.deployerConfigKey, JSON.stringify(SH_DEPLOYER_CONFIG)); + console.log("Deployer config saved"); + } catch (error) { + console.error("Error saving deployer config:", error); + } +} + +function showDeployerConfigModal() { + const modal = document.createElement('div'); + modal.id = 'deployer-config-modal'; + modal.style.cssText = ` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + `; + + modal.innerHTML = ` +
+

⚙️ SH Deployer Configuration

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ `; + + document.body.appendChild(modal); +} + +function closeDeployerConfigModal() { + const modal = document.getElementById('deployer-config-modal'); + if (modal) modal.remove(); +} + +async function saveDeployerConfigFromModal() { + const host = document.getElementById('deployer-config-host')?.value?.trim(); + const port = parseInt(document.getElementById('deployer-config-port')?.value) || 9998; + const token = document.getElementById('deployer-config-token')?.value?.trim(); + const msgEl = document.getElementById('deployer-config-message'); + + if (!host) { + if (msgEl) { + msgEl.style.display = 'block'; + msgEl.style.background = '#ffebee'; + msgEl.style.color = '#c62828'; + msgEl.textContent = 'Please enter a host'; + } + return; + } + + // Mettre à jour la config + SH_DEPLOYER_CONFIG.host = host; + SH_DEPLOYER_CONFIG.port = port; + SH_DEPLOYER_CONFIG.token = token; + + // Sauvegarder + saveDeployerConfig(); + + // Tester la connexion + if (msgEl) { + msgEl.style.display = 'block'; + msgEl.style.background = '#e3f2fd'; + msgEl.style.color = '#1565c0'; + msgEl.textContent = 'Testing connection...'; + } + + const isHealthy = await checkDeployerHealth(); + + if (isHealthy) { + if (msgEl) { + msgEl.style.background = '#e8f5e9'; + msgEl.style.color = '#2e7d32'; + msgEl.textContent = '✓ Connected successfully!'; + } + setTimeout(closeDeployerConfigModal, 1500); + } else { + if (msgEl) { + msgEl.style.background = '#ffebee'; + msgEl.style.color = '#c62828'; + msgEl.textContent = '✗ Connection failed. Check host and port.'; + } + } +} + +// Vérifier la santé du serveur au démarrage +setTimeout(async () => { + const healthy = await checkServerHealth(); + if (!healthy) { + console.warn("Git Pusher server may not be running"); + } else { + console.log("Git Pusher server is healthy"); + } +}, 1000); + +// ============================================ +// EXPORT FONCTIONS GLOBALES +// ============================================ + +// Exposer les fonctions du deployer globalement pour les onclick du HTML +window.showDeployerConfigModal = showDeployerConfigModal; +window.closeDeployerConfigModal = closeDeployerConfigModal; +window.saveDeployerConfigFromModal = saveDeployerConfigFromModal; + +// Exposer les fonctions principales +window.pushDashboards = pushDashboards; +window.resetForm = resetForm; +window.toggleSelectAll = toggleSelectAll; +window.updateSelectedApps = updateSelectedApps; + +// Fonction toggle pour le HTML +window.toggleDeployerAuth = function() { + var checkbox = document.getElementById('deploy-to-shcluster'); + var authSection = document.getElementById('deployer-auth'); + if (checkbox && authSection) { + authSection.classList.toggle('visible', checkbox.checked); + } +}; + +// ============================================ +// ATTACHEMENT DES ÉVÉNEMENTS AUX BOUTONS +// ============================================ + +(function attachButtonEvents() { + function tryAttach() { + console.log("Trying to attach button events..."); + + // Bouton Deploy to Git + var pushBtn = document.getElementById('push-btn'); + if (pushBtn) { + // Supprimer les anciens listeners + pushBtn.replaceWith(pushBtn.cloneNode(true)); + pushBtn = document.getElementById('push-btn'); + + pushBtn.addEventListener('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + console.log("Deploy button clicked!"); + pushDashboards(); + }); + console.log("✓ Deploy button event attached"); + } else { + console.log("✗ Deploy button not found yet"); + } + + // Bouton Reset - chercher par classe ou contenu + var buttons = document.querySelectorAll('button.btn, button.btn-secondary'); + buttons.forEach(function(btn) { + if (btn.textContent.includes('Reset') || btn.textContent.includes('🔄')) { + // Supprimer les anciens listeners + var newBtn = btn.cloneNode(true); + btn.parentNode.replaceChild(newBtn, btn); + + newBtn.addEventListener('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + console.log("Reset button clicked!"); + resetForm(true); + }); + console.log("✓ Reset button event attached"); + } + }); + + // Bouton Configure Deployer + var configBtn = document.querySelector('.deployer-config-btn'); + if (configBtn) { + // Supprimer les anciens listeners + var newConfigBtn = configBtn.cloneNode(true); + configBtn.parentNode.replaceChild(newConfigBtn, configBtn); + + newConfigBtn.addEventListener('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + console.log("Configure button clicked!"); + showDeployerConfigModal(); + }); + console.log("✓ Configure button event attached"); + } + + // Checkbox deploy to shcluster + var deployCheckbox = document.getElementById('deploy-to-shcluster'); + if (deployCheckbox) { + deployCheckbox.addEventListener('change', function() { + var authSection = document.getElementById('deployer-auth'); + if (authSection) { + authSection.classList.toggle('visible', this.checked); + } + }); + console.log("✓ Deploy checkbox event attached"); + } + + // Si le bouton principal n'est pas encore là, réessayer + if (!pushBtn) { + console.log("Retrying in 500ms..."); + setTimeout(tryAttach, 500); + } else { + console.log("=== All button events attached successfully ==="); + } + } + + // Démarrer après un délai pour laisser le DOM se charger + if (document.readyState === 'complete') { + console.log("Document ready, attaching events in 1s..."); + setTimeout(tryAttach, 1000); + } else { + window.addEventListener('load', function() { + console.log("Window loaded, attaching events in 1s..."); + setTimeout(tryAttach, 1000); + }); + } +})(); + +// ============================================ +// EXPORT POUR DEBUG +// ============================================ + +window.GitPusher = { + config: GIT_PUSHER_CONFIG, + deployerConfig: SH_DEPLOYER_CONFIG, + getSelectedApps: () => selectedApps, + checkServer: checkServerHealth, + checkDeployer: checkDeployerHealth, + version: GIT_PUSHER_CONFIG.version +}; \ No newline at end of file diff --git a/apps/pusher_app_prem/appserver/static/git_pusher.js_old b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher.js_old similarity index 100% rename from apps/pusher_app_prem/appserver/static/git_pusher.js_old rename to apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher.js_old diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher_config.js b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher_config.js new file mode 100644 index 00000000..3e763d33 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/git_pusher_config.js @@ -0,0 +1,391 @@ +// ============================================ +// GIT PUSHER - CONFIGURATION PAGE +// Version 2.1 - Compatible Splunk +// ============================================ + +require([ + 'jquery', + 'splunkjs/mvc', + 'splunkjs/mvc/simplexml/ready!' +], function($, mvc) { + + console.log('Git Pusher Config v2.1 initializing...'); + + // Configuration par défaut + var DEFAULT_CONFIG = { + api: { + url: '', + port: 9999, + useProxy: true + }, + deployer: { + enabled: false, + host: '', + port: 9998, + token: '', + useSSL: true + }, + license: { + checkInterval: 24 + }, + advanced: { + logLevel: 'INFO', + timeout: 30, + gitTimeout: 120 + } + }; + + // URL de l'API pour la config + function getConfigApiUrl() { + var hostname = window.location.hostname; + var protocol = window.location.protocol; + + // Essayer de charger depuis localStorage + try { + var stored = localStorage.getItem('git_pusher_config'); + if (stored) { + var config = JSON.parse(stored); + if (config.api && config.api.url) { + var url = config.api.url; + if (!config.api.useProxy && config.api.port) { + url = url.replace(/\/$/, '') + ':' + config.api.port; + } + return url; + } + } + } catch(e) {} + + // Auto-détection + if (hostname === 'myprivspldev.jp-engineering.fr') { + return protocol + '//myprivspldev-api.jp-engineering.fr'; + } + if (hostname === 'myprivspldev-api.jp-engineering.fr') { + return protocol + '//' + hostname; + } + if (/^(\d{1,3}\.){3}\d{1,3}$/.test(hostname) || hostname === 'localhost') { + return protocol + '//' + hostname + ':9999'; + } + return protocol + '//' + hostname + ':9999'; + } + + // ============================================ + // CHARGEMENT DE LA CONFIGURATION + // ============================================ + + function loadConfig() { + console.log('Loading configuration...'); + var apiUrl = getConfigApiUrl(); + + $.ajax({ + url: apiUrl + '/config', + method: 'GET', + dataType: 'json', + success: function(config) { + console.log('Config loaded:', config); + applyConfigToForm(config); + showMessage('Configuration chargée', 'success'); + }, + error: function(xhr, status, error) { + console.log('No server config, using defaults:', error); + applyConfigToForm(DEFAULT_CONFIG); + } + }); + + loadLicenseStatus(); + } + + function applyConfigToForm(config) { + // API + $('#api-url').val(config.api ? config.api.url || '' : ''); + $('#api-port').val(config.api ? config.api.port || 9999 : 9999); + $('#use-proxy').prop('checked', config.api ? config.api.useProxy !== false : true); + + // Deployer + $('#deployer-enabled').prop('checked', config.deployer ? config.deployer.enabled || false : false); + $('#deployer-host').val(config.deployer ? config.deployer.host || '' : ''); + $('#deployer-port').val(config.deployer ? config.deployer.port || 9998 : 9998); + $('#deployer-token').val(config.deployer ? config.deployer.token || '' : ''); + $('#deployer-use-ssl').prop('checked', config.deployer ? config.deployer.useSSL !== false : true); + + // Licence + $('#license-check-interval').val(config.license ? config.license.checkInterval || 24 : 24); + + // Avancé + $('#log-level').val(config.advanced ? config.advanced.logLevel || 'INFO' : 'INFO'); + $('#timeout').val(config.advanced ? config.advanced.timeout || 30 : 30); + $('#git-timeout').val(config.advanced ? config.advanced.gitTimeout || 120 : 120); + } + + function getConfigFromForm() { + return { + api: { + url: $('#api-url').val().trim(), + port: parseInt($('#api-port').val()) || 9999, + useProxy: $('#use-proxy').is(':checked') + }, + deployer: { + enabled: $('#deployer-enabled').is(':checked'), + host: $('#deployer-host').val().trim(), + port: parseInt($('#deployer-port').val()) || 9998, + token: $('#deployer-token').val(), + useSSL: $('#deployer-use-ssl').is(':checked') + }, + license: { + checkInterval: parseInt($('#license-check-interval').val()) || 24 + }, + advanced: { + logLevel: $('#log-level').val(), + timeout: parseInt($('#timeout').val()) || 30, + gitTimeout: parseInt($('#git-timeout').val()) || 120 + } + }; + } + + // ============================================ + // SAUVEGARDE DE LA CONFIGURATION + // ============================================ + + function saveConfig() { + console.log('Saving configuration...'); + var config = getConfigFromForm(); + var apiUrl = getConfigApiUrl(); + + $.ajax({ + url: apiUrl + '/config', + method: 'POST', + contentType: 'application/json', + data: JSON.stringify(config), + dataType: 'json', + success: function(result) { + console.log('Save result:', result); + if (result.success) { + showMessage('✅ Configuration sauvegardée avec succès !', 'success'); + // Sauvegarder aussi dans localStorage + localStorage.setItem('git_pusher_config', JSON.stringify(config)); + } else { + showMessage('❌ Erreur: ' + (result.error || 'Échec de la sauvegarde'), 'error'); + } + }, + error: function(xhr, status, error) { + console.error('Save error:', error); + showMessage('❌ Erreur de connexion au serveur: ' + error, 'error'); + } + }); + } + + function resetConfig() { + if (confirm('Voulez-vous vraiment réinitialiser la configuration ?')) { + applyConfigToForm(DEFAULT_CONFIG); + showMessage('Configuration réinitialisée (non sauvegardée)', 'success'); + } + } + + // ============================================ + // TESTS DE CONNEXION + // ============================================ + + function testApiConnection() { + console.log('Testing API connection...'); + var $status = $('#api-status'); + $status.removeClass('connected disconnected').text('● Test en cours...'); + + var apiUrl = $('#api-url').val().trim(); + + if (!apiUrl) { + apiUrl = getConfigApiUrl(); + } else if (!$('#use-proxy').is(':checked')) { + var port = $('#api-port').val() || 9999; + if (apiUrl.indexOf(':' + port) === -1) { + apiUrl = apiUrl.replace(/\/$/, '') + ':' + port; + } + } + + console.log('Testing URL:', apiUrl); + + $.ajax({ + url: apiUrl + '/health', + method: 'GET', + dataType: 'json', + timeout: 10000, + success: function(data) { + console.log('API health:', data); + $status.addClass('connected').text('● Connecté'); + }, + error: function(xhr, status, error) { + console.error('API test failed:', error); + $status.addClass('disconnected').text('● Échec connexion'); + } + }); + } + + function testDeployerConnection() { + console.log('Testing Deployer connection...'); + var $status = $('#deployer-status'); + $status.removeClass('connected disconnected').text('● Test en cours...'); + + var host = $('#deployer-host').val().trim(); + var port = $('#deployer-port').val() || 9998; + var useSSL = $('#deployer-use-ssl').is(':checked'); + var token = $('#deployer-token').val(); + + if (!host) { + $status.addClass('disconnected').text('● Adresse manquante'); + return; + } + + var protocol = useSSL ? 'https' : 'http'; + var url; + + // Si c'est un nom de domaine (contient des lettres et des points, pas une IP) + // Ne pas ajouter le port (le proxy gère) + if (/^[a-zA-Z]/.test(host) && host.indexOf('.') > -1 && !/^(\d{1,3}\.){3}\d{1,3}$/.test(host)) { + // C'est un domaine, pas de port + url = protocol + '://' + host + '/health'; + } else { + // C'est une IP ou localhost, ajouter le port + url = protocol + '://' + host + ':' + port + '/health'; + } + + console.log('Testing Deployer URL:', url); + + $.ajax({ + url: url, + method: 'GET', + dataType: 'json', + timeout: 10000, + headers: { + 'X-Auth-Token': token + }, + success: function(data) { + console.log('Deployer health:', data); + $status.addClass('connected').text('● Connecté'); + }, + error: function(xhr, status, error) { + console.error('Deployer test failed:', error); + $status.addClass('disconnected').text('● Échec connexion'); + } + }); + } + + // ============================================ + // STATUT DE LA LICENCE + // ============================================ + + function loadLicenseStatus() { + var $status = $('#license-status'); + + try { + var stored = localStorage.getItem('git_pusher_license'); + + if (stored) { + var parsed = JSON.parse(stored); + var licenseData = parsed.licenseData; + + if (licenseData) { + var expires = new Date(licenseData.expires); + var now = new Date(); + var daysRemaining = Math.ceil((expires - now) / (1000 * 60 * 60 * 24)); + + if (daysRemaining > 0) { + $status.html( + '● Active' + + '
Type: ' + licenseData.type_name + ' | Expire: ' + licenseData.expires + ' (' + daysRemaining + 'j)' + ); + } else { + $status.html( + '● Expirée' + + '
Expirée le ' + licenseData.expires + '' + ); + } + return; + } + } + + $status.html('● Non installée'); + + } catch (error) { + console.error('Erreur lecture licence:', error); + $status.html('● Erreur'); + } + } + + // ============================================ + // UTILITAIRES + // ============================================ + + function showMessage(message, type) { + var $msg = $('#config-message'); + $msg.text(message).removeClass('success error').addClass(type).show(); + + setTimeout(function() { + $msg.fadeOut(); + }, 5000); + } + + // ============================================ + // ATTACHER LES ÉVÉNEMENTS + // ============================================ + + function attachEvents() { + console.log('Attaching events...'); + + // Bouton Test API + $('#test-api-btn').on('click', function(e) { + e.preventDefault(); + console.log('Test API clicked'); + testApiConnection(); + }); + + // Bouton Test Deployer + $('#test-deployer-btn').on('click', function(e) { + e.preventDefault(); + console.log('Test Deployer clicked'); + testDeployerConnection(); + }); + + // Bouton Sauvegarder + $('#save-btn').on('click', function(e) { + e.preventDefault(); + console.log('Save clicked'); + saveConfig(); + }); + + // Bouton Réinitialiser + $('#reset-btn').on('click', function(e) { + e.preventDefault(); + console.log('Reset clicked'); + resetConfig(); + }); + + console.log('Events attached to buttons'); + } + + // ============================================ + // INITIALISATION + // ============================================ + + // Attendre que le DOM soit complètement prêt + function init() { + if ($('#api-url').length > 0) { + console.log('DOM ready, initializing...'); + attachEvents(); + loadConfig(); + } else { + console.log('DOM not ready, retrying...'); + setTimeout(init, 300); + } + } + + setTimeout(init, 500); + + // Exposer globalement pour le debug + window.gitPusherConfig = { + saveConfig: saveConfig, + resetConfig: resetConfig, + testApiConnection: testApiConnection, + testDeployerConnection: testDeployerConnection, + loadConfig: loadConfig + }; + + console.log('Git Pusher Config module loaded'); +}); \ No newline at end of file diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_file_management.js b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_file_management.js new file mode 100644 index 00000000..f59a6676 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_file_management.js @@ -0,0 +1,613 @@ +// ============================================ +// SYSTÈME DE GESTION DE LICENCE FICHIER .LIC +// ============================================ + +const LICENSE_FILE_KEY = 'git_pusher_license_file'; +const LICENSE_STATUS_ENDPOINT = '/custom/git_pusher/license_status'; + +let currentLicenseStatus = null; + +function initializeLicenseSystem() { + console.log("Initializing file-based license system..."); + + // Vérifier le statut de la licence + checkLicenseStatus(); +} + +function checkLicenseStatus() { + console.log("Checking license status..."); + + // Appeler le backend pour vérifier la licence + fetch(LICENSE_STATUS_ENDPOINT) + .then(response => response.json()) + .then(data => { + console.log("License status:", data); + currentLicenseStatus = data; + + if (data.licensed) { + // Licence valide + displayLicenseBadge(data.license_info, data.warnings); + } else { + // Pas de licence ou invalide + showLicenseUploadModal(data.errors); + } + }) + .catch(error => { + console.error("Error checking license:", error); + // En cas d'erreur, afficher le modal + showLicenseUploadModal(["Impossible de vérifier la licence"]); + }); +} + +function displayLicenseBadge(licenseInfo, warnings) { + console.log("Displaying license badge..."); + + const container = document.getElementById('license-badge-container'); + if (!container) { + console.error("license-badge-container not found"); + return; + } + + // Créer le badge + const badge = document.createElement('div'); + badge.id = 'license-badge'; + badge.style.cssText = ` + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 12px 20px; + border-radius: 8px; + font-size: 12px; + font-weight: 600; + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); + cursor: pointer; + transition: all 0.3s ease; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + text-align: center; + min-width: 200px; + `; + + // Déterminer le texte et la couleur selon le type + let badgeText = '✓ Licence Activée'; + let badgeColor = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'; + + if (licenseInfo.type === 'trial') { + badgeText = `⏱️ Essai: ${licenseInfo.days_remaining} jours`; + badgeColor = 'linear-gradient(135deg, #ff9800 0%, #f57c00 100%)'; + } else if (licenseInfo.type === 'standard') { + badgeText = `✓ Standard (${licenseInfo.days_remaining}j)`; + } else if (licenseInfo.type === 'enterprise') { + badgeText = `✓ Enterprise (${licenseInfo.days_remaining}j)`; + badgeColor = 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)'; + } + + // Avertissement si expire bientôt + if (licenseInfo.days_remaining < 30) { + badgeColor = 'linear-gradient(135deg, #ff9800 0%, #f57c00 100%)'; + badgeText = `⚠️ Expire dans ${licenseInfo.days_remaining}j`; + } + + badge.style.background = badgeColor; + badge.textContent = badgeText; + + // Clic pour afficher les détails + badge.onclick = function() { + showLicenseDetailsModal(licenseInfo, warnings); + }; + + container.appendChild(badge); + + // Hover effect + badge.addEventListener('mouseenter', function() { + this.style.transform = 'translateY(-3px)'; + this.style.boxShadow = '0 6px 25px rgba(102, 126, 234, 0.5)'; + }); + + badge.addEventListener('mouseleave', function() { + this.style.transform = 'translateY(0)'; + this.style.boxShadow = '0 4px 15px rgba(102, 126, 234, 0.3)'; + }); +} + +function showLicenseUploadModal(errors = []) { + console.log("Showing license upload modal"); + + // Créer le modal + const modal = document.createElement('div'); + modal.id = 'license-modal'; + modal.style.cssText = ` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + `; + + const content = document.createElement('div'); + content.style.cssText = ` + background: white; + border-radius: 16px; + padding: 40px; + max-width: 550px; + width: 90%; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); + animation: slideIn 0.3s ease; + `; + + let errorsHtml = ''; + if (errors.length > 0) { + errorsHtml = ` +
+

+ ⚠️ Problèmes détectés: +

+
    + ${errors.map(e => `
  • ${e}
  • `).join('')} +
+
+ `; + } + + content.innerHTML = ` +
+

🔐 Git Pusher

+

Activation de licence requise

+
+ + ${errorsHtml} + +
+

+ 📋 Hostname détecté: Chargement... +

+
+ +
+ + +
+
📄
+

+ Glissez votre fichier .lic ici +

+

+ ou cliquez pour parcourir +

+ +
+ + + + + 💡 Vous n'avez pas de licence? Contactez-nous pour obtenir votre fichier .lic personnalisé + +
+ + + +
+ + + +
+ `; + + modal.appendChild(content); + document.body.appendChild(modal); + + // Ajouter l'animation CSS + const style = document.createElement('style'); + style.textContent = ` + @keyframes slideIn { + from { + opacity: 0; + transform: translateY(-20px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + `; + document.head.appendChild(style); + + // Récupérer et afficher le hostname + getHostname().then(hostname => { + document.getElementById('detected-hostname').textContent = hostname; + }); + + // Configurer le drag & drop et file input + setupFileUpload(); +} + +function setupFileUpload() { + const dropZone = document.getElementById('drop-zone'); + const fileInput = document.getElementById('license-file-input'); + const fileInfo = document.getElementById('file-info'); + const uploadBtn = document.getElementById('upload-btn'); + + let selectedFile = null; + + // Clic sur la zone pour ouvrir le sélecteur + dropZone.onclick = () => fileInput.click(); + + // Hover effect + dropZone.addEventListener('mouseenter', function() { + this.style.background = '#eef1ff'; + this.style.borderColor = '#5568d3'; + }); + + dropZone.addEventListener('mouseleave', function() { + this.style.background = '#f8f9ff'; + this.style.borderColor = '#667eea'; + }); + + // Drag & drop + dropZone.addEventListener('dragover', (e) => { + e.preventDefault(); + dropZone.style.background = '#e3e7ff'; + dropZone.style.borderColor = '#5568d3'; + }); + + dropZone.addEventListener('dragleave', () => { + dropZone.style.background = '#f8f9ff'; + dropZone.style.borderColor = '#667eea'; + }); + + dropZone.addEventListener('drop', (e) => { + e.preventDefault(); + dropZone.style.background = '#f8f9ff'; + dropZone.style.borderColor = '#667eea'; + + const files = e.dataTransfer.files; + if (files.length > 0) { + handleFileSelection(files[0]); + } + }); + + // Sélection de fichier + fileInput.addEventListener('change', (e) => { + if (e.target.files.length > 0) { + handleFileSelection(e.target.files[0]); + } + }); + + function handleFileSelection(file) { + selectedFile = file; + + // Vérifier l'extension + if (!file.name.endsWith('.lic')) { + showLicenseMessage('⚠️ Veuillez sélectionner un fichier .lic', 'warning'); + return; + } + + // Afficher les infos du fichier + document.getElementById('file-name').textContent = file.name; + document.getElementById('file-size').textContent = formatFileSize(file.size); + fileInfo.style.display = 'block'; + + // Activer le bouton + uploadBtn.disabled = false; + uploadBtn.style.cursor = 'pointer'; + uploadBtn.style.opacity = '1'; + + // Stocker le fichier pour l'upload + window.selectedLicenseFile = file; + + showLicenseMessage('✓ Fichier prêt à être installé', 'success'); + } +} + +function formatFileSize(bytes) { + if (bytes < 1024) return bytes + ' B'; + if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; + return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; +} + +function uploadLicenseFile() { + const file = window.selectedLicenseFile; + + if (!file) { + showLicenseMessage('❌ Aucun fichier sélectionné', 'error'); + return; + } + + showLicenseMessage('⏳ Installation de la licence...', 'info'); + + // Lire le fichier + const reader = new FileReader(); + + reader.onload = function(e) { + const fileContent = e.target.result; + + // Envoyer au backend pour validation et installation + fetch('/custom/git_pusher/install_license', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + license_file: fileContent, + filename: file.name + }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showLicenseMessage('✅ Licence installée avec succès !', 'success'); + + setTimeout(() => { + closeLicenseModal(); + // Recharger pour afficher le badge + checkLicenseStatus(); + }, 1500); + } else { + showLicenseMessage('❌ ' + (data.message || 'Erreur d\'installation'), 'error'); + + if (data.errors && data.errors.length > 0) { + const errorList = data.errors.map(e => `• ${e}`).join('\n'); + console.error('License errors:', errorList); + } + } + }) + .catch(error => { + console.error('Upload error:', error); + showLicenseMessage('❌ Erreur de connexion au serveur', 'error'); + }); + }; + + reader.onerror = function() { + showLicenseMessage('❌ Erreur de lecture du fichier', 'error'); + }; + + reader.readAsText(file); +} + +function requestTrial() { + showLicenseMessage('⏳ Demande d\'essai en cours...', 'info'); + + // Appeler le backend pour créer une licence d'essai + fetch('/custom/git_pusher/request_trial', { + method: 'POST' + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showLicenseMessage('✅ Licence d\'essai activée (7 jours) !', 'success'); + + setTimeout(() => { + closeLicenseModal(); + checkLicenseStatus(); + }, 1500); + } else { + showLicenseMessage('❌ ' + (data.message || 'Erreur'), 'error'); + } + }) + .catch(error => { + console.error('Trial request error:', error); + showLicenseMessage('❌ Erreur de connexion', 'error'); + }); +} + +function showLicenseDetailsModal(licenseInfo, warnings) { + // Créer un modal pour afficher les détails de la licence + const modal = document.createElement('div'); + modal.id = 'license-details-modal'; + modal.style.cssText = ` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + display: flex; + align-items: center; + justify-content: center; + z-index: 10001; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + `; + + const content = document.createElement('div'); + content.style.cssText = ` + background: white; + border-radius: 16px; + padding: 40px; + max-width: 500px; + width: 90%; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); + `; + + let warningsHtml = ''; + if (warnings && warnings.length > 0) { + warningsHtml = ` +
+ ${warnings.map(w => `

${w}

`).join('')} +
+ `; + } + + const featuresHtml = Object.entries(licenseInfo.features || {}) + .map(([feature, enabled]) => { + const icon = enabled ? '✅' : '❌'; + return `
${icon} ${feature}
`; + }).join(''); + + content.innerHTML = ` +
+

🔐 Informations de licence

+
+ +
+
+ 🆔 ID de licence: +
${licenseInfo.license_id}
+
+ +
+ 👤 Client: +
${licenseInfo.customer}
+
+ +
+ 🏷️ Type: +
${licenseInfo.type.toUpperCase()}
+
+ +
+ 📅 Expire le: +
${new Date(licenseInfo.expires).toLocaleDateString('fr-FR')}
+
+ +
+ ⏰ Jours restants: +
${licenseInfo.days_remaining} jours
+
+
+ +
+ ✨ Fonctionnalités: +
+ ${featuresHtml} +
+
+ + ${warningsHtml} + +
+ + + +
+ `; + + modal.appendChild(content); + document.body.appendChild(modal); +} + +function closeDetailsModal() { + const modal = document.getElementById('license-details-modal'); + if (modal) { + modal.remove(); + } +} + +function showLicenseMessage(message, type) { + const messageEl = document.getElementById('license-message'); + if (!messageEl) return; + + messageEl.style.display = 'block'; + messageEl.textContent = message; + + if (type === 'success') { + messageEl.style.background = '#d4edda'; + messageEl.style.color = '#155724'; + messageEl.style.border = '1px solid #c3e6cb'; + } else if (type === 'error') { + messageEl.style.background = '#f8d7da'; + messageEl.style.color = '#721c24'; + messageEl.style.border = '1px solid #f5c6cb'; + } else if (type === 'warning') { + messageEl.style.background = '#fff3cd'; + messageEl.style.color = '#856404'; + messageEl.style.border = '1px solid #ffeaa7'; + } else if (type === 'info') { + messageEl.style.background = '#d1ecf1'; + messageEl.style.color = '#0c5460'; + messageEl.style.border = '1px solid #bee5eb'; + } +} + +function closeLicenseModal() { + const modal = document.getElementById('license-modal'); + if (modal) { + modal.remove(); + } +} + +function getHostname() { + return new Promise((resolve) => { + fetch('/en-US/splunkd/__raw/services/server/info?output_mode=json') + .then(r => r.json()) + .then(d => { + const hostname = d.entry?.[0]?.content?.host || 'unknown'; + resolve(hostname); + }) + .catch(() => resolve('unknown')); + }); +} + +function checkLicenseBeforePush() { + if (!currentLicenseStatus || !currentLicenseStatus.licensed) { + alert('⚠️ Aucune licence valide détectée. Veuillez installer une licence.'); + showLicenseUploadModal([]); + return false; + } + + return true; +} + +// Initialiser au chargement de la page +document.addEventListener('DOMContentLoaded', function() { + initializeLicenseSystem(); +}); diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js new file mode 100644 index 00000000..3be600dc --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js @@ -0,0 +1,1291 @@ +// ============================================ +// GIT PUSHER - LICENSE VALIDATION (RSA) +// Version 2.1 - 100% Client-Side Validation +// ============================================ + +// Configuration par défaut +const DEFAULT_APP_CONFIG = { + api: { + url: '', + port: 9999, + useProxy: true + } +}; + +// Charger la configuration +function loadAppConfigForLicense() { + try { + const stored = localStorage.getItem('git_pusher_config'); + if (stored) { + return JSON.parse(stored); + } + } catch (e) { + console.warn('Erreur chargement config localStorage:', e); + } + return DEFAULT_APP_CONFIG; +} + +// Déterminer l'URL du serveur API +function getLicenseServerUrl() { + const config = loadAppConfigForLicense(); + const hostname = window.location.hostname; + const protocol = window.location.protocol; + + // Si une URL est configurée, l'utiliser + if (config.api && config.api.url) { + let url = config.api.url; + // Ajouter le port si pas de proxy + if (!config.api.useProxy && config.api.port) { + url = url.replace(/\/$/, '') + ':' + config.api.port; + } + return url; + } + + // Auto-détection basée sur le hostname + if (hostname === 'myprivspldev.jp-engineering.fr') { + return protocol + '//myprivspldev-api.jp-engineering.fr'; + } + + if (hostname === 'myprivspldev-api.jp-engineering.fr') { + return protocol + '//' + hostname; + } + + if (/^(\d{1,3}\.){3}\d{1,3}$/.test(hostname) || hostname === 'localhost') { + return protocol + '//' + hostname + ':9999'; + } + + return protocol + '//' + hostname + ':9999'; +} + +// Configuration +const LICENSE_CONFIG = { + storageKey: 'git_pusher_license', + usageKey: 'git_pusher_usage', + version: '2.1.0', + serverUrl: getLicenseServerUrl() +}; + +// ============================================ +// CLÉ PUBLIQUE RSA +// ============================================ +// Cette clé est générée par le vendeur avec license_generator_rsa.py +// Commande: python3 license_generator_rsa.py export-key + +const PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7H8v243PKpy4ZcGUI3YX +EiAZaK+VwWSDywCwBOMOJBA5slWorP78cME0bIphrNRvTlA9xpuo0a+8V+VFMb3+ +Uw9AhDtuJKRIEgwJixm/mkKcbjwqSHPmnyBBHPBBX7lO/q2wsEX0y3O/NujByqc3 +dVsB0VVhMFJmgyR3dVy6ZQITgEu/NGs9v/jUc5IT1YzVmOCcL8BZrjlGiF0AXeS3 +/U8khq7wEx5OilhXC7i8w6urd9c4Djjg583WsGtDKk0aZ6xvnfYpmgfTzaFIrUkS +afTxbcZ1h0N3lN9MBvaLbgAui5RgdlbJlbGsgl3uAa9R9xZk+rqTh8VBLVq+KW5I +a6aYOVterUf2hz/hUkNjM8Rolv4/3PQX0mGu6fa4fwoxmjlSUEVxVFh7TdCE/WHj +3kAOybZXWJnws/++urqijP5SmYxyCaVlYAoutdWmz1tTrSXOh74qrou2wv3C8Dmo +8ccVznAhdhHcVs7MSl9Qbyw1fsi1117WigUGkPE5Cxjlrl8EcBQg3G5x91ER95JM +O0SjyhDborT+oMq9947ZL35VllzkKbBELbhDnogXmDMrI3Ij1UBmCtSOZzOLhyHD +FmGf5AB1LWbxcgrzOMcTLoAHduaDalZCzmW4WdV4313CqeawEfqJVj8BJ+0VEFdb +RDk4ZzHpOaGAuCJjN3AuxO8CAwEAAQ== +-----END PUBLIC KEY-----`; + +// ============================================ +// UTILITAIRES CRYPTO +// ============================================ + +/** + * Convertir une chaîne PEM en ArrayBuffer + */ +function pemToArrayBuffer(pem) { + const b64 = pem + .replace(/-----BEGIN PUBLIC KEY-----/, '') + .replace(/-----END PUBLIC KEY-----/, '') + .replace(/\s/g, ''); + const binary = atob(b64); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return bytes.buffer; +} + +/** + * Importer la clé publique RSA + */ +async function importPublicKey() { + try { + const keyData = pemToArrayBuffer(PUBLIC_KEY_PEM); + const key = await crypto.subtle.importKey( + 'spki', + keyData, + { + name: 'RSASSA-PKCS1-v1_5', + hash: 'SHA-256' + }, + false, + ['verify'] + ); + return key; + } catch (error) { + console.error('Erreur import clé publique:', error); + return null; + } +} + +/** + * Vérifier la signature RSA PKCS#1 v1.5 + */ +async function verifySignature(data, signatureB64, publicKey) { + try { + const signature = Uint8Array.from(atob(signatureB64), c => c.charCodeAt(0)); + const dataBuffer = new TextEncoder().encode(data); + + const isValid = await crypto.subtle.verify( + 'RSASSA-PKCS1-v1_5', + publicKey, + signature, + dataBuffer + ); + + return isValid; + } catch (error) { + console.error('Erreur vérification signature:', error); + return false; + } +} + +// ============================================ +// FONCTIONS UTILITAIRES +// ============================================ + +/** + * Décoder Base64 + */ +function base64Decode(str) { + try { + return decodeURIComponent(atob(str).split('').map(function(c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); + }).join('')); + } catch (e) { + return atob(str); + } +} + +/** + * Obtenir le hostname actuel (depuis l'URL) + */ +function getCurrentHostname() { + return window.location.hostname.toLowerCase(); +} + +/** + * Obtenir le vrai hostname Splunk via l'API REST + */ +async function getSplunkHostname() { + try { + // Méthode 1: Via server/info + const response = await fetch('/en-US/splunkd/__raw/services/server/info?output_mode=json', { + credentials: 'include' + }); + if (response.ok) { + const data = await response.json(); + const serverName = data.entry?.[0]?.content?.serverName; + if (serverName) { + console.log('Hostname Splunk (server/info):', serverName); + return serverName.toLowerCase(); + } + } + } catch (e) { + console.log('Méthode server/info échouée:', e); + } + + try { + // Méthode 2: Via server/settings + const response2 = await fetch('/en-US/splunkd/__raw/services/server/settings?output_mode=json', { + credentials: 'include' + }); + if (response2.ok) { + const data2 = await response2.json(); + const serverName = data2.entry?.[0]?.content?.serverName; + if (serverName) { + console.log('Hostname Splunk (server/settings):', serverName); + return serverName.toLowerCase(); + } + } + } catch (e) { + console.log('Méthode server/settings échouée:', e); + } + + // Fallback: hostname de l'URL (pas idéal) + console.warn('Impossible de récupérer le hostname Splunk, utilisation URL:', getCurrentHostname()); + return getCurrentHostname(); +} + +/** + * Calculer les jours restants + */ +function daysRemaining(expiryDate) { + const expiry = new Date(expiryDate); + const now = new Date(); + const diff = expiry - now; + return Math.ceil(diff / (1000 * 60 * 60 * 24)); +} + +// ============================================ +// PARSING DE LICENCE +// ============================================ + +/** + * Parser le contenu d'un fichier .lic + */ +function parseLicenseFile(content) { + try { + const lines = content.trim().split('\n'); + let payloadB64 = null; + + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed && !trimmed.startsWith('#')) { + payloadB64 = trimmed; + break; + } + } + + if (!payloadB64) { + return { error: 'Payload non trouvé dans le fichier' }; + } + + // Décoder le payload + const payloadJson = base64Decode(payloadB64); + const payload = JSON.parse(payloadJson); + + if (!payload.license || !payload.signature) { + return { error: 'Format de licence invalide' }; + } + + // Décoder les données de licence + const licenseJson = base64Decode(payload.license); + const licenseData = JSON.parse(licenseJson); + + return { + success: true, + licenseJson: licenseJson, + licenseData: licenseData, + signatureB64: payload.signature, + rawPayload: payloadB64 + }; + } catch (error) { + console.error('Erreur parsing licence:', error); + return { error: 'Erreur de lecture du fichier de licence' }; + } +} + +// ============================================ +// VALIDATION DE LICENCE +// ============================================ + +/** + * Valider une licence complète (signature RSA + hostname + expiration) + */ +async function validateLicense(licenseContent = null) { + try { + // Si pas de contenu fourni, charger depuis le localStorage + let parsed; + if (licenseContent) { + parsed = parseLicenseFile(licenseContent); + } else { + const stored = localStorage.getItem(LICENSE_CONFIG.storageKey); + if (!stored) { + return { + valid: false, + error: 'Aucune licence installée', + error_code: 'NO_LICENSE' + }; + } + parsed = JSON.parse(stored); + } + + if (parsed.error) { + return { + valid: false, + error: parsed.error, + error_code: 'PARSE_ERROR' + }; + } + + const { licenseJson, licenseData, signatureB64 } = parsed; + + // DEBUG: Afficher les données + console.log('=== DEBUG VALIDATION LICENCE ==='); + console.log('License JSON:', licenseJson); + console.log('License JSON length:', licenseJson.length); + console.log('Signature B64:', signatureB64.substring(0, 50) + '...'); + console.log('Signature B64 length:', signatureB64.length); + + // 1. Vérifier la signature RSA + console.log('Vérification de la signature RSA...'); + const publicKey = await importPublicKey(); + + if (!publicKey) { + console.error('Échec import clé publique'); + return { + valid: false, + error: 'Impossible de charger la clé publique', + error_code: 'KEY_ERROR' + }; + } + + console.log('Clé publique importée avec succès'); + + const signatureValid = await verifySignature(licenseJson, signatureB64, publicKey); + + console.log('Résultat vérification signature:', signatureValid); + + if (!signatureValid) { + return { + valid: false, + error: 'Signature de licence invalide', + error_code: 'INVALID_SIGNATURE' + }; + } + + console.log('✓ Signature RSA valide'); + + // 2. Vérifier le hostname + const expectedHostname = (licenseData.hostname || '').toLowerCase(); + const currentHostname = await getSplunkHostname(); + + console.log(`Hostname attendu: "${expectedHostname}", actuel: "${currentHostname}"`); + + // Permettre une correspondance partielle ou exacte + if (expectedHostname && expectedHostname !== currentHostname) { + // Vérifier si c'est une correspondance partielle (le hostname peut être un FQDN) + if (!currentHostname.includes(expectedHostname) && !expectedHostname.includes(currentHostname)) { + return { + valid: false, + error: `Licence non valide pour ce serveur. Attendu: ${expectedHostname}, Actuel: ${currentHostname}`, + error_code: 'HOSTNAME_MISMATCH', + expected_hostname: expectedHostname, + current_hostname: currentHostname + }; + } + console.log('✓ Hostname valide (correspondance partielle)'); + } else { + console.log('✓ Hostname valide (exact)'); + } + + // 3. Vérifier la date d'expiration + const expiryDate = licenseData.expires; + if (expiryDate) { + const days = daysRemaining(expiryDate); + + if (days < 0) { + return { + valid: false, + error: `Licence expirée le ${expiryDate}`, + error_code: 'LICENSE_EXPIRED', + expires: expiryDate + }; + } + + console.log(`✓ Licence valide (${days} jours restants)`); + } + + // Licence valide ! + return { + valid: true, + license_id: licenseData.license_id, + type: licenseData.type, + type_name: licenseData.type_name, + customer: licenseData.customer, + hostname: expectedHostname, + issued: licenseData.issued, + expires: expiryDate, + days_remaining: daysRemaining(expiryDate), + limits: licenseData.limits || {}, + features: licenseData.features || [] + }; + + } catch (error) { + console.error('Erreur validation licence:', error); + return { + valid: false, + error: error.message, + error_code: 'VALIDATION_ERROR' + }; + } +} + +/** + * Vérifier si une fonctionnalité est disponible + */ +async function hasFeature(featureName) { + const validation = await validateLicense(); + if (!validation.valid) return false; + return validation.features.includes(featureName); +} + +// ============================================ +// GESTION DU STOCKAGE +// ============================================ + +/** + * Sauvegarder une licence validée (localStorage + serveur) + */ +async function saveLicense(licenseContent) { + try { + // Parser le fichier + const parsed = parseLicenseFile(licenseContent); + + if (parsed.error) { + return { + success: false, + error: parsed.error + }; + } + + // Valider la licence avant de sauvegarder + const validation = await validateLicense(licenseContent); + + if (!validation.valid) { + return { + success: false, + error: validation.error, + error_code: validation.error_code + }; + } + + // 1. Sauvegarder dans localStorage + localStorage.setItem(LICENSE_CONFIG.storageKey, JSON.stringify(parsed)); + console.log('✓ Licence sauvegardée dans localStorage'); + + // 2. Sauvegarder sur le serveur (pour persistance après vidage cache) + try { + const response = await fetch(`${LICENSE_CONFIG.serverUrl}/license/save`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + license_content: licenseContent + }) + }); + + const serverResult = await response.json(); + + if (serverResult.success) { + console.log('✓ Licence sauvegardée sur le serveur'); + } else { + console.warn('⚠ Échec sauvegarde serveur:', serverResult.error); + // On continue quand même car localStorage fonctionne + } + } catch (serverError) { + console.warn('⚠ Impossible de sauvegarder sur le serveur:', serverError); + // On continue quand même car localStorage fonctionne + } + + return { + success: true, + license: validation + }; + + } catch (error) { + console.error('Erreur sauvegarde licence:', error); + return { + success: false, + error: error.message + }; + } +} + +/** + * Charger la licence depuis le serveur (si localStorage vide) + */ +async function loadLicenseFromServer() { + try { + const response = await fetch(`${LICENSE_CONFIG.serverUrl}/license/file`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); + + const result = await response.json(); + + if (result.success && result.content) { + console.log('Licence trouvée sur le serveur, validation en cours...'); + + // Parser et valider la licence + const parsed = parseLicenseFile(result.content); + + if (parsed.error) { + console.warn('Erreur parsing licence serveur:', parsed.error); + return false; + } + + // Valider la signature + const validation = await validateLicense(result.content); + + if (validation.valid) { + // Sauvegarder dans localStorage pour les prochaines fois + localStorage.setItem(LICENSE_CONFIG.storageKey, JSON.stringify(parsed)); + console.log('✓ Licence chargée depuis le serveur et stockée localement'); + return true; + } else { + console.warn('Licence serveur invalide:', validation.error); + return false; + } + } else { + console.log('Aucune licence sur le serveur'); + return false; + } + } catch (error) { + console.log('Impossible de charger la licence depuis le serveur:', error.message); + return false; + } +} + +/** + * Supprimer la licence (localStorage + serveur) + */ +async function removeLicense() { + // Supprimer du localStorage + localStorage.removeItem(LICENSE_CONFIG.storageKey); + localStorage.removeItem(LICENSE_CONFIG.usageKey); + + // Supprimer du serveur + try { + await fetch(`${LICENSE_CONFIG.serverUrl}/license/delete`, { + method: 'POST' + }); + console.log('Licence supprimée du serveur'); + } catch (e) { + console.warn('Impossible de supprimer la licence du serveur:', e); + } + + console.log('Licence supprimée'); +} + +/** + * Récupérer les infos de licence (sans revalider la signature) + */ +function getLicenseInfo() { + try { + const stored = localStorage.getItem(LICENSE_CONFIG.storageKey); + if (!stored) return null; + + const parsed = JSON.parse(stored); + return parsed.licenseData; + } catch { + return null; + } +} + +// ============================================ +// GESTION DES LIMITES D'UTILISATION +// ============================================ + +/** + * Obtenir les stats d'utilisation + */ +function getUsageStats() { + try { + const stored = localStorage.getItem(LICENSE_CONFIG.usageKey); + if (stored) { + return JSON.parse(stored); + } + } catch {} + + return { + total_pushes: 0, + pushes_today: 0, + last_push_date: null + }; +} + +/** + * Incrémenter le compteur d'utilisation + */ +function incrementUsage() { + const stats = getUsageStats(); + const today = new Date().toISOString().split('T')[0]; + + // Reset si nouveau jour + if (stats.last_push_date !== today) { + stats.pushes_today = 0; + stats.last_push_date = today; + } + + stats.total_pushes = (stats.total_pushes || 0) + 1; + stats.pushes_today = (stats.pushes_today || 0) + 1; + + localStorage.setItem(LICENSE_CONFIG.usageKey, JSON.stringify(stats)); + return stats; +} + +/** + * Vérifier les limites avant un push + */ +async function checkLimits() { + const validation = await validateLicense(); + + if (!validation.valid) { + return { + allowed: false, + error: validation.error, + error_code: validation.error_code + }; + } + + const limits = validation.limits || {}; + const maxPushes = limits.max_pushes_per_day || -1; + + if (maxPushes > 0) { + const stats = getUsageStats(); + const today = new Date().toISOString().split('T')[0]; + + // Reset si nouveau jour + let pushesToday = stats.pushes_today || 0; + if (stats.last_push_date !== today) { + pushesToday = 0; + } + + if (pushesToday >= maxPushes) { + return { + allowed: false, + error: `Limite quotidienne atteinte (${maxPushes} pushes/jour)`, + error_code: 'DAILY_LIMIT_REACHED' + }; + } + } + + return { + allowed: true, + license_type: validation.type_name, + remaining_today: maxPushes > 0 ? maxPushes - getUsageStats().pushes_today : -1 + }; +} + +// ============================================ +// INTERFACE UTILISATEUR +// ============================================ + +/** + * Afficher le badge de licence + */ +async function updateLicenseBadge() { + const container = document.getElementById('license-badge-container'); + if (!container) return; + + const validation = await validateLicense(); + + let badgeHtml = ''; + + if (validation.valid) { + const daysLeft = validation.days_remaining; + let badgeClass = 'license-badge-valid'; + let icon = '✓'; + + if (daysLeft <= 7) { + badgeClass = 'license-badge-expiring'; + icon = '⚠️'; + } else if (daysLeft <= 30) { + badgeClass = 'license-badge-warning'; + icon = '⏳'; + } + + badgeHtml = ` +
+ ${icon} + ${validation.type_name} + ${daysLeft}j +
+ `; + } else { + badgeHtml = ` +
+ 🔐 + Activer +
+ `; + } + + container.innerHTML = badgeHtml; +} + +/** + * Afficher le modal de licence + */ +function showLicenseModal(message = null, errorCode = null) { + // Supprimer l'ancien modal s'il existe + const existingModal = document.getElementById('license-modal'); + if (existingModal) existingModal.remove(); + + const modal = document.createElement('div'); + modal.id = 'license-modal'; + modal.className = 'license-modal-overlay'; + + let errorMessage = ''; + if (message) { + errorMessage = `
${message}
`; + } + + modal.innerHTML = ` +
+
+

🔐 Activation de Licence

+ +
+ +
+ ${errorMessage} + +
+
📄
+
+ Glissez-déposez votre fichier .lic ici +
ou cliquez pour sélectionner +
+ +
+ +
+ Hostname du serveur: + Chargement... +
Communiquez ce hostname pour obtenir votre licence +
+ +
+
+ + +
+ `; + + document.body.appendChild(modal); + + // Afficher le hostname + getSplunkHostname().then(hostname => { + const hostnameDisplay = document.getElementById('current-hostname-display'); + if (hostnameDisplay) { + hostnameDisplay.textContent = hostname; + } + }); + + // Configurer le drag & drop + setupLicenseUpload(); +} + +/** + * Configurer l'upload de licence + */ +function setupLicenseUpload() { + const dropZone = document.getElementById('license-upload-zone'); + const fileInput = document.getElementById('license-file-input'); + + if (!dropZone || !fileInput) return; + + // Clic pour sélectionner + dropZone.addEventListener('click', () => fileInput.click()); + + // Drag & drop + dropZone.addEventListener('dragover', (e) => { + e.preventDefault(); + dropZone.classList.add('dragover'); + }); + + dropZone.addEventListener('dragleave', () => { + dropZone.classList.remove('dragover'); + }); + + dropZone.addEventListener('drop', (e) => { + e.preventDefault(); + dropZone.classList.remove('dragover'); + + const files = e.dataTransfer.files; + if (files.length > 0) { + handleLicenseFile(files[0]); + } + }); + + // Sélection de fichier + fileInput.addEventListener('change', (e) => { + if (e.target.files.length > 0) { + handleLicenseFile(e.target.files[0]); + } + }); +} + +/** + * Traiter le fichier de licence uploadé + */ +async function handleLicenseFile(file) { + const resultDiv = document.getElementById('license-validation-result'); + if (!resultDiv) return; + + // Vérifier l'extension + if (!file.name.endsWith('.lic')) { + resultDiv.innerHTML = ` +
+ ❌ Le fichier doit avoir l'extension .lic +
+ `; + return; + } + + resultDiv.innerHTML = ` +
+ ⏳ Validation en cours... +
+ `; + + try { + // Lire le fichier + const content = await file.text(); + + // Sauvegarder et valider + const result = await saveLicense(content); + + if (result.success) { + const license = result.license; + resultDiv.innerHTML = ` +
+
+
+ Licence activée avec succès !
+ Type: ${license.type_name}
+ Expire: ${license.expires} (${license.days_remaining} jours)
+ Client: ${license.customer?.name || 'N/A'} +
+
+ `; + + // Mettre à jour le badge + updateLicenseBadge(); + + // Fermer le modal après 3 secondes + setTimeout(() => { + closeLicenseModal(); + }, 3000); + + } else { + resultDiv.innerHTML = ` +
+ ❌ ${result.error} +
+ `; + } + + } catch (error) { + resultDiv.innerHTML = ` +
+ ❌ Erreur: ${error.message} +
+ `; + } +} + +/** + * Fermer le modal de licence + */ +function closeLicenseModal() { + const modal = document.getElementById('license-modal'); + if (modal) modal.remove(); +} + +/** + * Afficher les détails de la licence + */ +async function showLicenseDetails() { + const validation = await validateLicense(); + + if (!validation.valid) { + showLicenseModal(validation.error, validation.error_code); + return; + } + + // Supprimer l'ancien modal s'il existe + const existingModal = document.getElementById('license-details-modal'); + if (existingModal) existingModal.remove(); + + const modal = document.createElement('div'); + modal.id = 'license-details-modal'; + modal.className = 'license-modal-overlay'; + + const features = validation.features.map(f => `${f}`).join(' '); + const limits = validation.limits; + const maxApps = limits.max_apps === -1 ? '∞' : limits.max_apps; + const maxPushes = limits.max_pushes_per_day === -1 ? '∞' : limits.max_pushes_per_day; + + const usage = getUsageStats(); + + modal.innerHTML = ` +
+
+

📋 Détails de la Licence

+ +
+ +
+ + + + + + + + + + + +
ID${validation.license_id}
Type${validation.type_name}
Client${validation.customer?.name || 'N/A'}
Email${validation.customer?.email || 'N/A'}
Hostname${validation.hostname}
Émise le${validation.issued}
Expire le${validation.expires}
Jours restants${validation.days_remaining}
Apps max${maxApps}
Pushes/jour${maxPushes}
+ +
+ Fonctionnalités:
+
${features}
+
+ +
+ Utilisation:
+ Total pushes: ${usage.total_pushes} | Aujourd'hui: ${usage.pushes_today} +
+
+ + +
+ `; + + document.body.appendChild(modal); +} + +/** + * Confirmer la suppression de licence + */ +function confirmRemoveLicense() { + if (confirm('Êtes-vous sûr de vouloir supprimer cette licence ?')) { + removeLicense(); + + // Fermer le modal des détails + const detailsModal = document.getElementById('license-details-modal'); + if (detailsModal) detailsModal.remove(); + + // Mettre à jour le badge + updateLicenseBadge(); + + alert('Licence supprimée.'); + } +} + +/** + * Vérifier la licence avant un push (appelé par git_pusher.js) + */ +async function checkLicenseBeforePush() { + const result = await checkLimits(); + + if (!result.allowed) { + showLicenseModal(result.error, result.error_code); + return false; + } + + return true; +} + +// ============================================ +// STYLES CSS +// ============================================ + +const licenseStyles = ` + +`; + +// ============================================ +// INITIALISATION +// ============================================ + +/** + * Initialiser le système de licence + */ +async function initializeLicense() { + console.log('Git Pusher License System v' + LICENSE_CONFIG.version + ' (RSA)'); + + // Injecter les styles + if (!document.getElementById('license-styles')) { + const styleEl = document.createElement('div'); + styleEl.id = 'license-styles'; + styleEl.innerHTML = licenseStyles; + document.head.appendChild(styleEl); + } + + // Vérifier si une licence existe dans localStorage + const stored = localStorage.getItem(LICENSE_CONFIG.storageKey); + + if (!stored) { + console.log('Aucune licence en cache, tentative de chargement depuis le serveur...'); + + // Essayer de charger depuis le serveur + const loadedFromServer = await loadLicenseFromServer(); + + if (loadedFromServer) { + console.log('✓ Licence restaurée depuis le serveur'); + } else { + console.log('Aucune licence disponible'); + } + } else { + console.log('Licence trouvée dans le cache local'); + } + + // Mettre à jour le badge + updateLicenseBadge(); +} + +// Exposer les fonctions globalement +window.initializeLicense = initializeLicense; +window.validateLicense = validateLicense; +window.saveLicense = saveLicense; +window.removeLicense = removeLicense; +window.loadLicenseFromServer = loadLicenseFromServer; +window.checkLicenseBeforePush = checkLicenseBeforePush; +window.showLicenseModal = showLicenseModal; +window.closeLicenseModal = closeLicenseModal; +window.showLicenseDetails = showLicenseDetails; +window.confirmRemoveLicense = confirmRemoveLicense; +window.updateLicenseBadge = updateLicenseBadge; +window.hasFeature = hasFeature; +window.incrementUsage = incrementUsage; +window.getUsageStats = getUsageStats; +window.getLicenseInfo = getLicenseInfo; + +// Auto-initialiser après le chargement +if (document.readyState === 'complete') { + setTimeout(initializeLicense, 100); +} else { + window.addEventListener('load', function() { + setTimeout(initializeLicense, 100); + }); +} \ No newline at end of file diff --git a/apps/pusher_app_prem/appserver/static/license_validation.js_old b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js_old similarity index 100% rename from apps/pusher_app_prem/appserver/static/license_validation.js_old rename to apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js_old diff --git a/apps/pusher_app_prem/appserver/static/license_validation.js_old2 b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js_old2 similarity index 100% rename from apps/pusher_app_prem/appserver/static/license_validation.js_old2 rename to apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js_old2 diff --git a/apps/pusher_app_prem/appserver/static/license_validation.js_old3 b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js_old3 similarity index 100% rename from apps/pusher_app_prem/appserver/static/license_validation.js_old3 rename to apps/Version git_pusheravant_nettoyage/pusher_app_prem/appserver/static/license_validation.js_old3 diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/README b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/README new file mode 100644 index 00000000..9a70db09 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/README @@ -0,0 +1 @@ +This is where you put any scripts you want to add to this app. diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/__pycache__/license_validator.cpython-39.pyc b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/__pycache__/license_validator.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..759b4da72ed06914e60d26178b46ee068819d80f GIT binary patch literal 9715 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 expires_date: + return { + "valid": False, + "error": f"Licence expirée le {expires_str}", + "error_code": "LICENSE_EXPIRED" + } + + days_remaining = (expires_date - now).days + except ValueError: + days_remaining = 0 + else: + days_remaining = 999 # Pas d'expiration + + # Licence valide ! + return { + "valid": True, + "license_id": license_data.get("license_id"), + "type": license_data.get("type"), + "type_name": license_data.get("type_name"), + "customer": license_data.get("customer", {}), + "hostname": expected_hostname, + "issued": license_data.get("issued"), + "expires": expires_str, + "days_remaining": days_remaining, + "limits": license_data.get("limits", {}), + "features": license_data.get("features", []) + } + + except json.JSONDecodeError: + return { + "valid": False, + "error": "Données de licence corrompues", + "error_code": "CORRUPTED_DATA" + } + except Exception as e: + return { + "valid": False, + "error": f"Erreur de validation: {str(e)}", + "error_code": "VALIDATION_ERROR" + } + + +# ============================================ +# SAUVEGARDE DE LICENCE +# ============================================ + +def save_license_file(content): + """Sauvegarder un fichier de licence uploadé""" + try: + # Créer le dossier local si nécessaire + local_dir = os.path.join(APP_HOME, 'local') + os.makedirs(local_dir, exist_ok=True) + + # Valider le contenu avant de sauvegarder + parsed = parse_license_content(content) + if not parsed: + return { + "success": False, + "error": "Format de licence invalide" + } + + # Valider la licence + # Sauvegarder temporairement pour valider + temp_file = LICENSE_FILE + '.tmp' + with open(temp_file, 'w') as f: + f.write(content) + + validation = validate_license(temp_file) + + if not validation.get("valid"): + os.remove(temp_file) + return { + "success": False, + "error": validation.get("error"), + "error_code": validation.get("error_code") + } + + # Renommer le fichier temporaire + os.rename(temp_file, LICENSE_FILE) + os.chmod(LICENSE_FILE, 0o600) + + return { + "success": True, + "license": validation + } + + except Exception as e: + return { + "success": False, + "error": str(e) + } + + +# ============================================ +# GESTION DES LIMITES D'UTILISATION +# ============================================ + +def get_usage_stats(): + """Récupérer les statistiques d'utilisation""" + try: + if os.path.exists(USAGE_FILE): + with open(USAGE_FILE, 'r') as f: + return json.load(f) + except: + pass + + return { + "total_pushes": 0, + "pushes_today": 0, + "last_push_date": None, + "apps_pushed": [] + } + + +def save_usage_stats(stats): + """Sauvegarder les statistiques d'utilisation""" + try: + local_dir = os.path.join(APP_HOME, 'local') + os.makedirs(local_dir, exist_ok=True) + + with open(USAGE_FILE, 'w') as f: + json.dump(stats, f, indent=2) + os.chmod(USAGE_FILE, 0o600) + except Exception as e: + print(f"Erreur sauvegarde stats: {e}") + + +def increment_usage(): + """Incrémenter le compteur d'utilisation""" + stats = get_usage_stats() + today = datetime.now().strftime("%Y-%m-%d") + + # Reset compteur quotidien si nouveau jour + if stats.get("last_push_date") != today: + stats["pushes_today"] = 0 + stats["last_push_date"] = today + + stats["total_pushes"] = stats.get("total_pushes", 0) + 1 + stats["pushes_today"] = stats.get("pushes_today", 0) + 1 + + save_usage_stats(stats) + return stats + + +def check_limits(): + """Vérifier si les limites de la licence sont respectées""" + license_info = validate_license() + + if not license_info.get("valid"): + return { + "allowed": False, + "error": license_info.get("error"), + "error_code": license_info.get("error_code") + } + + limits = license_info.get("limits", {}) + max_pushes = limits.get("max_pushes_per_day", -1) + + if max_pushes > 0: + stats = get_usage_stats() + today = datetime.now().strftime("%Y-%m-%d") + + # Reset si nouveau jour + if stats.get("last_push_date") != today: + stats["pushes_today"] = 0 + + if stats.get("pushes_today", 0) >= max_pushes: + return { + "allowed": False, + "error": f"Limite quotidienne atteinte ({max_pushes} pushes/jour)", + "error_code": "DAILY_LIMIT_REACHED" + } + + return { + "allowed": True, + "license_type": license_info.get("type_name"), + "remaining_today": max_pushes - get_usage_stats().get("pushes_today", 0) if max_pushes > 0 else -1 + } + + +def has_feature(feature_name): + """Vérifier si une fonctionnalité est disponible dans la licence""" + license_info = validate_license() + + if not license_info.get("valid"): + return False + + features = license_info.get("features", []) + return feature_name in features + + +# ============================================ +# CLI POUR TESTS +# ============================================ + +if __name__ == "__main__": + if len(sys.argv) > 1: + if sys.argv[1] == "status": + result = validate_license() + if result.get("valid"): + print("✅ Licence valide") + print(f" ID: {result.get('license_id')}") + print(f" Type: {result.get('type_name')}") + print(f" Hostname: {result.get('hostname')}") + print(f" Expire: {result.get('expires')} ({result.get('days_remaining')} jours)") + print(f" Features: {', '.join(result.get('features', []))}") + else: + print(f"❌ Licence invalide: {result.get('error')}") + + elif sys.argv[1] == "hostname": + print(f"Hostname: {get_splunk_hostname()}") + + elif sys.argv[1] == "usage": + stats = get_usage_stats() + print(f"Total pushes: {stats.get('total_pushes', 0)}") + print(f"Pushes aujourd'hui: {stats.get('pushes_today', 0)}") + + elif sys.argv[1] == "check": + result = check_limits() + if result.get("allowed"): + print(f"✅ Push autorisé ({result.get('license_type')})") + else: + print(f"❌ Push refusé: {result.get('error')}") + + else: + print("Usage: python license_validator.py [status|hostname|usage|check]") + else: + result = validate_license() + print(json.dumps(result, indent=2)) diff --git a/apps/pusher_app_prem/bin/license_validator.py_old b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/license_validator.py_old similarity index 100% rename from apps/pusher_app_prem/bin/license_validator.py_old rename to apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/license_validator.py_old diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/start_git_pusher.sh b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/start_git_pusher.sh new file mode 100755 index 00000000..5f700770 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/start_git_pusher.sh @@ -0,0 +1,354 @@ +#!/bin/bash +# ============================================ +# Git Pusher - Start Script +# Version 2.0 avec credentials sécurisés +# ============================================ + +# Configuration +SPLUNK_HOME=${SPLUNK_HOME:-/opt/splunk} +APP_NAME="pusher_app_prem" +APP_HOME="${SPLUNK_HOME}/etc/apps/${APP_NAME}" +BIN_DIR="${APP_HOME}/bin" +LOG_DIR="${SPLUNK_HOME}/var/log/splunk" +PID_FILE="${BIN_DIR}/git_pusher.pid" +CREDENTIALS_MANAGER="${BIN_DIR}/credentials_manager.py" + +# Couleurs pour les logs +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Fonction de logging +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_debug() { + echo -e "${BLUE}[DEBUG]${NC} $1" +} + +# Charger les credentials de manière sécurisée +load_credentials() { + # Méthode 1: Utiliser le credentials manager (recommandé) + if [ -f "$CREDENTIALS_MANAGER" ]; then + CREDS=$(python3 "$CREDENTIALS_MANAGER" get 2>/dev/null) + if [ $? -eq 0 ]; then + export SPLUNK_USERNAME=$(echo "$CREDS" | head -1) + export SPLUNK_PASSWORD=$(echo "$CREDS" | tail -1) + log_info "Credentials loaded from secure storage" + return 0 + fi + fi + + # Méthode 2: Variables d'environnement déjà définies + if [ -n "$SPLUNK_USERNAME" ] && [ -n "$SPLUNK_PASSWORD" ]; then + log_info "Using credentials from environment variables" + return 0 + fi + + # Méthode 3: Fichier .env (moins sécurisé mais pratique) + ENV_FILE="${APP_HOME}/local/.env" + if [ -f "$ENV_FILE" ]; then + source "$ENV_FILE" + if [ -n "$SPLUNK_USERNAME" ] && [ -n "$SPLUNK_PASSWORD" ]; then + log_warn "Using credentials from .env file (consider using 'credentials setup' for better security)" + return 0 + fi + fi + + # Aucune credential trouvée + log_error "No credentials found!" + log_error "Please run: $0 credentials setup" + return 1 +} + +# Vérifier si le serveur est déjà en cours d'exécution +check_running() { + if [ -f "$PID_FILE" ]; then + PID=$(cat "$PID_FILE") + if ps -p $PID > /dev/null 2>&1; then + return 0 # Running + fi + fi + return 1 # Not running +} + +# Configurer les credentials +setup_credentials() { + if [ -f "$CREDENTIALS_MANAGER" ]; then + python3 "$CREDENTIALS_MANAGER" setup + else + log_error "Credentials manager not found at $CREDENTIALS_MANAGER" + exit 1 + fi +} + +# Afficher le statut des credentials +credentials_status() { + if [ -f "$CREDENTIALS_MANAGER" ]; then + python3 "$CREDENTIALS_MANAGER" status + else + log_error "Credentials manager not found" + fi +} + +# Supprimer les credentials +delete_credentials() { + if [ -f "$CREDENTIALS_MANAGER" ]; then + python3 "$CREDENTIALS_MANAGER" delete + else + log_error "Credentials manager not found" + fi +} + +# Démarrer le serveur +start_server() { + log_info "Starting Git Pusher server..." + + # Vérifier si déjà en cours + if check_running; then + log_warn "Git Pusher is already running (PID: $(cat $PID_FILE))" + return 1 + fi + + # Charger les credentials + if ! load_credentials; then + exit 1 + fi + + # Créer le répertoire de logs + mkdir -p "$LOG_DIR" + + # Démarrer le serveur Python + cd "$BIN_DIR" + python3 git_pusher.py > "${LOG_DIR}/git_pusher_startup.log" 2>&1 & + + # Sauvegarder le PID + echo $! > "$PID_FILE" + + # Attendre un peu et vérifier + sleep 2 + + if check_running; then + log_info "Git Pusher started successfully (PID: $(cat $PID_FILE))" + log_info "Server listening on port 9999" + + # Vérifier le statut de la licence + HOSTNAME=$(hostname) + log_info "Hostname: $HOSTNAME" + + if [ -f "${APP_HOME}/local/license.lic" ]; then + log_info "License file found" + else + log_warn "No license file found - activation required" + fi + + return 0 + else + log_error "Failed to start Git Pusher" + log_error "Check logs at ${LOG_DIR}/git_pusher.log" + return 1 + fi +} + +# Arrêter le serveur +stop_server() { + log_info "Stopping Git Pusher server..." + + if [ -f "$PID_FILE" ]; then + PID=$(cat "$PID_FILE") + + if ps -p $PID > /dev/null 2>&1; then + kill $PID + sleep 2 + + # Force kill si nécessaire + if ps -p $PID > /dev/null 2>&1; then + log_warn "Force killing process..." + kill -9 $PID + fi + + rm -f "$PID_FILE" + log_info "Git Pusher stopped" + return 0 + else + log_warn "Process not running, cleaning up PID file" + rm -f "$PID_FILE" + return 0 + fi + else + log_warn "PID file not found, Git Pusher may not be running" + return 1 + fi +} + +# Redémarrer le serveur +restart_server() { + log_info "Restarting Git Pusher server..." + stop_server + sleep 1 + start_server +} + +# Afficher le statut +show_status() { + echo "============================================" + echo "Git Pusher Status" + echo "============================================" + + if check_running; then + PID=$(cat "$PID_FILE") + echo -e "Server Status: ${GREEN}RUNNING${NC}" + echo "PID: $PID" + echo "Port: 9999" + else + echo -e "Server Status: ${RED}STOPPED${NC}" + fi + + echo "" + echo "Paths:" + echo " App Home: $APP_HOME" + echo " Bin Dir: $BIN_DIR" + echo " Log Dir: $LOG_DIR" + echo "" + + # Statut des credentials + echo "Credentials:" + if [ -f "${APP_HOME}/local/.credentials" ]; then + echo -e " Secure storage: ${GREEN}Configured${NC}" + else + echo -e " Secure storage: ${YELLOW}Not configured${NC}" + fi + + echo "" + + # Statut de la licence + echo "License:" + if [ -f "${APP_HOME}/local/license.lic" ]; then + echo -e " File: ${GREEN}Present${NC}" + # Essayer de lire quelques infos + if command -v python3 &> /dev/null; then + python3 -c " +import sys +sys.path.insert(0, '$BIN_DIR') +try: + from license_validator import validate_license + result = validate_license() + if result.get('valid'): + print(f\" Type: {result.get('type_name', 'N/A')}\") + print(f\" Expires: {result.get('expires', 'N/A')}\") + print(f\" Days remaining: {result.get('days_remaining', 'N/A')}\") + else: + print(f\" Status: Invalid - {result.get('error', 'Unknown error')}\") +except Exception as e: + print(f' Unable to read license: {e}') +" 2>/dev/null || echo " Unable to read license details" + fi + else + echo -e " File: ${YELLOW}Not found${NC}" + fi + + echo "" + echo "Hostname: $(hostname)" + echo "============================================" +} + +# Afficher les logs +show_logs() { + LOG_FILE="${LOG_DIR}/git_pusher.log" + + if [ -f "$LOG_FILE" ]; then + if [ "$1" == "-f" ]; then + tail -f "$LOG_FILE" + else + tail -n 50 "$LOG_FILE" + fi + else + log_warn "Log file not found at $LOG_FILE" + fi +} + +# Menu d'aide +show_help() { + echo "Git Pusher - Server Management Script v2.0" + echo "" + echo "Usage: $0 {command} [options]" + echo "" + echo "Server Commands:" + echo " start Start the Git Pusher server" + echo " stop Stop the Git Pusher server" + echo " restart Restart the Git Pusher server" + echo " status Show the current status" + echo " logs [-f] Show recent logs (-f for follow)" + echo "" + echo "Credentials Commands:" + echo " credentials setup Configure Splunk credentials securely" + echo " credentials status Show credentials status" + echo " credentials delete Delete stored credentials" + echo "" + echo "Other:" + echo " help Show this help message" + echo "" + echo "Examples:" + echo " $0 credentials setup # First time setup" + echo " $0 start # Start server" + echo " $0 logs -f # Follow logs" +} + +# Main +case "$1" in + start) + start_server + ;; + stop) + stop_server + ;; + restart) + restart_server + ;; + status) + show_status + ;; + logs) + show_logs "$2" + ;; + credentials) + case "$2" in + setup) + setup_credentials + ;; + status) + credentials_status + ;; + delete) + delete_credentials + ;; + *) + echo "Usage: $0 credentials {setup|status|delete}" + ;; + esac + ;; + help|--help|-h) + show_help + ;; + *) + if [ -z "$1" ]; then + show_help + else + echo "Unknown command: $1" + echo "" + show_help + exit 1 + fi + ;; +esac \ No newline at end of file diff --git a/apps/pusher_app_prem/bin/start_git_pusher.sh.V1 b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/start_git_pusher.sh.V1 similarity index 100% rename from apps/pusher_app_prem/bin/start_git_pusher.sh.V1 rename to apps/Version git_pusheravant_nettoyage/pusher_app_prem/bin/start_git_pusher.sh.V1 diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/certs/server.crt b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/certs/server.crt new file mode 100644 index 00000000..11fa39a7 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/certs/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCTCCAfGgAwIBAgIUCuKo8SLloS5cjBOR04+X6ayZ40cwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI2MDEyMzIyMTIxOFoXDTI3MDEy +MzIyMTIxOFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAs0vF6sFTseKgZC1nZ6CVZdw45yk1Ni0W9Mc24KZ9NKCJ +rP0tHy0hs6mME/sq8DV1fh0YtqIvBCxcKEE84/cVXmUfZF9JRXO95734+JGPmo07 +zpiu7p3r4WyIWmCXX5VB0UkMEXsPQmonqG1Kwtz+R1cfgis2lUk+xsC2zSjER8l4 +2UODjHvtD25usgxKjpwPrCuZt43miArnVnwfB8OLbAqpwQeYIf18bPt/TrnQsdgd +ZZiQdE6UTaJ5xhqztwpYJO9pvZA24Bi3bGNfBciITds5RCGY2wQo8yxbeJsidTuW +7Z64DK9t33oVnB2PqlP6hVGD5Agthsv9ehRPxdd3MwIDAQABo1MwUTAdBgNVHQ4E +FgQUy0dni+ogqC7YuvfD/Pn0AuebsXQwHwYDVR0jBBgwFoAUy0dni+ogqC7YuvfD +/Pn0AuebsXQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAlyxg +vR15lsYp4TxJPi1WPzLZl1e6ewTl8GhyE1saxS8LRtyTyr8sa9EFRLQ0OIsqYrUw +zZi7FIDoDPZDKpd0/+U94UKlhUuPUyufQwl5vNu0A+SEpwKeznUMaj4Y98tHvVGd +1SCndZBWn/v2U4nXqHoTd6Y0xEOga0jUEsUMBckNC236BTo88Zk65/oa9Gncyb27 +9vGVCbmPyzE70H4KFoVtxkoZrKywn+0ajHhgH5gqZNRPWpe6i8xTbMAeIXkCjmWL +LmOA7MkjeQBBEWewu4vMOXsvf+gCtxUj5owsAcOQlZ3g72Sng4MeMjuVx4ZRVxX9 +fj+vCP9EFI8rX48tjQ== +-----END CERTIFICATE----- diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/certs/server.key b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/certs/server.key new file mode 100644 index 00000000..8b790585 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/certs/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQCzS8XqwVOx4qBk +LWdnoJVl3DjnKTU2LRb0xzbgpn00oIms/S0fLSGzqYwT+yrwNXV+HRi2oi8ELFwo +QTzj9xVeZR9kX0lFc73nvfj4kY+ajTvOmK7unevhbIhaYJdflUHRSQwRew9Caieo +bUrC3P5HVx+CKzaVST7GwLbNKMRHyXjZQ4OMe+0Pbm6yDEqOnA+sK5m3jeaICudW +fB8Hw4tsCqnBB5gh/Xxs+39OudCx2B1lmJB0TpRNonnGGrO3Clgk72m9kDbgGLds +Y18FyIhN2zlEIZjbBCjzLFt4myJ1O5btnrgMr23fehWcHY+qU/qFUYPkCC2Gy/16 +FE/F13czAgMBAAECggEAMrEMrvej0xpQ4KHZp3nGY3sk9242JjAPWntsb42CvrtY +0XjvJe5bpfEcspWDqVBj/Jj7YL9v7Y0hLRxsu8Mi3oJWoskx7RnxKjES0CxPXpHp +w9p1Mu+hPiWyU2MVySdo6WPuro6NXOiod70WswtKNR9TwDi5gPGpdwYLaOvKusSp +Rncm0m0H3IBhgVA691X0AUIomAW3Wmh+5If1XHfjrNHTB8cjcNf6koPMkCqHCEZ9 +wtINxOJior+gGkjMXaDszqzNlicVBXFEFjaXWcp38xAif1uimpqKsRzZEF6RAUzi +H7cI3aF2dXG3C9l6Byi7OSgd8X4JUnE0dlCpC7qweQKBgQDgvoavo8G0kYruCUIQ +6vcSs1YBByOkl6yZBCZWk10NgRpU1wyu9zmlvEwNVlUfALs5eoLxnhe8Wklq0ckQ +r/Rl+r/lj/MZUFn49TgUCsUOIi/G7nWQG0bPo4bCB2QXsAiKdY+KZeC56620uyom +1VY+nS3y8O4EP0YHX0qHFfmIZwKBgQDMOywO0DSrZMDyvmbwL0ISzHRcNpRn0jk7 +pEtzM/VOx+v0O93E+5OygzmXlBKjF0MwMXBidf8IZu4xO8qWqAM4EP2DD0cpoS1Z +WiHHkc5NZhjgeG6C4XaCXR++7CuY25VKKe01yz/+j51linDD8OAibKUspkjVufEN +R/AT0GFLVQKBgBxMYTEkcXOHD/NA/yyaKVoVcrLWb0p+PqFVwG4OSB03MFWWbmZp +gry3pOvY/wbUVL68CljaCysQQ0ZL/AE55pAgrqD9KyL41xtd5R3A7WcGLvXheLQY +eyYR9RnhTF0fMTQd8WD/yvgeENU86+XP3vgrWmnIpG+sd+jdusifn7fpAn9QkwfO +0FX3SMjW/EegewSWZhOCTgY+77Gk1izuRpGBg16T/QqBrL+Yri0KoGC593OKj/bG +4ca8id9vjSdgSOj8NbfO/TgWNICvv9+T3PKHlsA5z0nKWSloRVVA/ew1YmyD1gbA +MnAM/pwac4QJyf6jljmUZAZYTAPOOZN+PbglAoGBAJ9cOGDgT+BCOoNc0T1GJDAk +xOR8d+tD+j4JH5IVxB51DXjJOZxw9U3XhNH1OcE0x3fRzKJOtlQLxP6fHYVtMVFq +VpeekmTtJ9OfMg68ELOlf7ykA3GhMJ3FarM6e8+X+KliGf6ND4HBMb112FlMgIi6 +yYi7sfSL53Dzp1Q2DxXV +-----END PRIVATE KEY----- diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/app.conf b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/app.conf new file mode 100644 index 00000000..d2212d20 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/app.conf @@ -0,0 +1,16 @@ +# +# Splunk app configuration file +# + +[install] +is_configured = 0 + +[ui] +is_visible = true +label = Pusher Premium + +[launcher] +author = +description = +version = 2.0.0 + diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/data/ui/nav/default.xml b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/data/ui/nav/default.xml new file mode 100644 index 00000000..b95a0b8e --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/data/ui/nav/default.xml @@ -0,0 +1,4 @@ + diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/data/ui/views/README b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/data/ui/views/README new file mode 100644 index 00000000..6cf74f0b --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/default/data/ui/views/README @@ -0,0 +1 @@ +Add all the views that your app needs in this directory diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.credentials b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.credentials new file mode 100644 index 00000000..388185fd --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.credentials @@ -0,0 +1 @@ +{"username": "admin", "password": "VgNoQiAmDzgUO3NQ"} \ No newline at end of file diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.key b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.key new file mode 100644 index 00000000..1da59971 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.key @@ -0,0 +1 @@ +d0YpjIlHuVRowV+y4yQh+VuqDhq7QikC3qepdfLE9+o= \ No newline at end of file diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.usage_stats b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.usage_stats new file mode 100644 index 00000000..e029a484 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/.usage_stats @@ -0,0 +1,6 @@ +{ + "total_pushes": 21, + "pushes_today": 6, + "last_push_date": "2026-02-21", + "apps_pushed": [] +} \ No newline at end of file diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/app.conf b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/app.conf new file mode 100644 index 00000000..c82e287e --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/app.conf @@ -0,0 +1,6 @@ +[ui] + +[launcher] + +[install] +state = enabled diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.crt b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.crt new file mode 100644 index 00000000..a477884e --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.crt @@ -0,0 +1,49 @@ +-----BEGIN CERTIFICATE----- +MIIDxTCCA0ugAwIBAgISBXu55+97HBg/V5v9p1wKdygbMAoGCCqGSM49BAMDMDIx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF +ODAeFw0yNjAyMTcxMzU5MDRaFw0yNjA1MTgxMzU5MDNaMCkxJzAlBgNVBAMTHm15 +cHJpdnNwbGRldi5qcC1lbmdpbmVlcmluZy5mcjB2MBAGByqGSM49AgEGBSuBBAAi +A2IABOLi1mN0uYVlBILGpDZDyk1wmGPgXklxm7E2Zn/Nswn54qsHJcSW8gSJDHyE +GbqFcc3wTomzFHa73aPxF+/8bTX281VkKjABfNPFSu83qmVcDZ35VT4bF1zbDOES +280Kq6OCAiswggInMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD +ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTq3jD3pSEI3y4olRyu1I/aK5sGDDAf +BgNVHSMEGDAWgBSPDROi9i5+0VBsMxg4XVmOI3KRyjAyBggrBgEFBQcBAQQmMCQw +IgYIKwYBBQUHMAKGFmh0dHA6Ly9lOC5pLmxlbmNyLm9yZy8wKQYDVR0RBCIwIIIe +bXlwcml2c3BsZGV2LmpwLWVuZ2luZWVyaW5nLmZyMBMGA1UdIAQMMAowCAYGZ4EM +AQIBMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly9lOC5jLmxlbmNyLm9yZy8yOC5j +cmwwggENBgorBgEEAdZ5AgQCBIH+BIH7APkAfwBxfpXzwjiKbbHjhEk9MeFaqWII +di1CAOAFDNBntaZh4gAAAZxsG05YAAgAAAUACa6ZQgQDAEgwRgIhAIichDr9Q2CB +AXzXmEbKjiO9qSAUXE7s8IgBXw8BfjluAiEAyjAyAc2I4hCjco4FLp7+y0nmeElH +yl4BBAaCEsOFK3AAdgAWgy2r8KklDw/wOqVF/8i/yCPQh0v2BCkn+OcfMxP1+gAA +AZxsG1XXAAAEAwBHMEUCIE7uCd4jXwCcTGuqR3ThJm0Zms0U7tAJcuhnR2F0syZJ +AiEAj06LtXnMoYEN6wvfgFUVd4zekUUaNJlJ1TK0HcMMlNQwCgYIKoZIzj0EAwMD +aAAwZQIwZaVb5NEYfUrGirhaFV9eohbjDY7YLzaJ5dIxH+Jt78o+GMfypoFc6Rc1 +S2FPNCJsAjEAphAhfBmVN1ASp3JENib1t12TuEVaTNHdNlzzuFE4s3z+z0cp6je4 +MmgQpu/hgcn3 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy +Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa +Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF +bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c +S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb +R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB +9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j +cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB +BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE +DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j +ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0 +RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d +AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8 +otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA +aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm +Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2 +HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1 +Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR +xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d +tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/ +jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS +u1igv3OefnWjSQ== +-----END CERTIFICATE----- diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.crt.bak b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.crt.bak new file mode 100644 index 00000000..72166c19 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.crt.bak @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFCzCCAvOgAwIBAgIUIkJeLpRn6wfN8VbsMrPdFAl/x7swDQYJKoZIhvcNAQEL +BQAwFTETMBEGA1UEAwwKZ2l0LXB1c2hlcjAeFw0yNjAyMDExOTM1MzNaFw0yNzAy +MDExOTM1MzNaMBUxEzARBgNVBAMMCmdpdC1wdXNoZXIwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDsTH5H+OD27yXIFz4MvNrpmpNgYly6QYUukJO8FI/f +unBe4N5mfOTZ/WrBeR5KoBOS3FV8VWIH7ShXIzWBpollmIz9+jlPyftawXyiSnSX +rwLBdHc8gjVRZf1H2U0E191v9z0oaXApy8d7E0Pw+i4odoGHOX5Ix89s0DJrG5UP +LrLr9OHlyMCC0D2QVp0wqFGkIXXv/cyYwlcGPACvFhE/fWUazC4AEImJhXypOfQZ +h57SoldKQWwW7BZdGmnbSqeG2lq7KFUow0sie4KzRPLPXrIGdKQbPAKDKcQ7MYlG +9bfgsmM1Rr6klRAmO/e4w1HRHSHUetmFBYDJ5MYNdeddYDfIVwjgwfDvy1i+ojRl +/viywW3ONXR9rUcx/nGGc8UJTjJAAaAaTj6UMzn40ltLYmiymhj6mWFNiuGwDxas +YTxA/3i62pGlbC8s1ZSXtdCYsEN4+W3N5CSadHdVtAIIEc6OyQ2mRa3v4oeZlyzt +1mk9j9oChxi5r74ujUmjNHxpawWG5wmnRy3b9ABxcivESEuXIbjBXrQ+RCmuQ8Dp +5Asa7iede7iEPkhGw3Es3uVdk4s3/OlS6o+1F+rG9qZr3aTtJrciVSLofbrSNtFF +MERip+VBwIdBofVzS6GUhnLjjdhfu/kdzsqrTDDFan4NX1IyC+zBL90DPQ8SoIOg +owIDAQABo1MwUTAdBgNVHQ4EFgQUe6KibB+U4yTq9/pwf6C4JeoPQo0wHwYDVR0j +BBgwFoAUe6KibB+U4yTq9/pwf6C4JeoPQo0wDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEA12Y7N6iLOtRAt+xD3B5eIdJtPnFclhmy8FCd2+SdnF/K +zWVdzTsWYKzZ4TZ08aMOh2+H2vDf/ZTG+gryCob28QVy0sRxbpA4WJMI6zBfZSKr +Raudh5Gql/CO28gN4k6EGgNAn1S02NkvhZP4FokfXwkY4CIReRECJzws0gCyMZto +wLfYEVyvN9NYQf1xoJHaozGghA0FADQrr6pQsl1Ek4bkrvb8/L8gWeT6lgny0ZcI +1UEW9lkx7pc0dRDOjUjVzlHYzAf53xEslontihQcOoE/Uj3Wsmi1V/lPm+Pi0Ml0 +msMUkvMZP6Y8lnvRT4625YKR6L3ibuQxlXGtKHvu7eJdcOnW5IeVmg5vsH2xoVaF +4L0zBPpA6CBzsfZPgLJ9odD10nRVx8bh0b555/CUP5WIVHvLkPgp+NptJAoKah7Q +PkI5OKZWGjrJGiV7BWx5HIB5TX/w0PCjMA4ce3yVRNs7poUzR4PKgohrp94cIDFa +m+K4rfBmeMwVuuJZIuYpye80dcdsiFPrIZuA+hbP7tGlrwBKKMzpB3BEDIFTPb2b +hUq1TJCcHffFqxpRia+L/MMI8RpaEwzW9hghQB/LiPG0UqJycNpuo8cnggx+bsop +0ZXB68cW6K1UWLo1qLSz7/0+65PrWRkJisbjtmpKRDJlB72yIxlsZmBucxBy3II= +-----END CERTIFICATE----- diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.key b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.key new file mode 100644 index 00000000..a9b00593 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.key @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDQfw7eesJcJWzoV0AL +EJtevZRBdfNTKjceiNAfFoc/2bKN5pKU3n17/ZuJGGWFGNOhZANiAATi4tZjdLmF +ZQSCxqQ2Q8pNcJhj4F5JcZuxNmZ/zbMJ+eKrByXElvIEiQx8hBm6hXHN8E6JsxR2 +u92j8Rfv/G019vNVZCowAXzTxUrvN6plXA2d+VU+Gxdc2wzhEtvNCqs= +-----END PRIVATE KEY----- diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.key.bak b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.key.bak new file mode 100644 index 00000000..465e812b --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/certs/server.key.bak @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +eiDRzM4++dQGm7osCy1NRbPGxdUyhw== +-----END PRIVATE KEY----- diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/config.json b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/config.json new file mode 100644 index 00000000..41802687 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/config.json @@ -0,0 +1,22 @@ +{ + "api": { + "url": "https://myprivspldev-api.jp-engineering.fr", + "port": 9999, + "useProxy": true + }, + "deployer": { + "enabled": true, + "host": "myprivspldev-shdp-api.jp-engineering.fr", + "port": 9998, + "token": "bc2564e5a885d49ac3811dc946ca5620da24da19b8a8f5c5fdfcd7c07a241688", + "useSSL": true + }, + "license": { + "checkInterval": 24 + }, + "advanced": { + "logLevel": "INFO", + "timeout": 30, + "gitTimeout": 120 + } +} \ No newline at end of file diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_-_deploy_applicationsV1.xml b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_-_deploy_applicationsV1.xml new file mode 100644 index 00000000..b44287f2 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_-_deploy_applicationsV1.xml @@ -0,0 +1,572 @@ + + + Push Splunk applications to Git repository and deploy to SH Cluster + + + | rest /services/apps/local | search disabled=0 | table title, label, description | rename title as name | sort label + -1m + now + + + + + + + +
+ +
+
+

🚀 Git Pusher

+ v2.2 +
+
+ +
+
+ + +
+ +
+

📦 Applications

+
+ +

Loading applications...

+
+
+ + +
+

⚙️ Git Configuration

+ +
+ + +
HTTPS URL of your Git repository
+
+ +
+ + +
+ +
+ + +
Personal access token with write permissions
+
+ +
+ + +
+ +
+ + +
+ + +
+
+
+ 🎯 Deploy to Search Head Cluster + + ● Checking... + +
+ +
+ +
+ + +
+ +
+
+ Splunk credentials for applying shcluster-bundle (optional if using default) +
+
+ + +
+
+
+ + +
+ + +
+ + +
+
+ Deploying applications to Git... Please wait +
+ +
+
+
+
+
+ + + +
+
+
\ No newline at end of file diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_-_push_applications_to_git.xml b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_-_push_applications_to_git.xml new file mode 100644 index 00000000..eca8b17e --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_-_push_applications_to_git.xml @@ -0,0 +1,256 @@ + + + + Push Splunk applications to Git repository + + + | rest /services/apps/local | search disabled=0 | fields name, label, description | sort label + -4h@h + now + + + + Configuration & Application Selection + + + +
+
+ ℹ️ Configure your Git settings and select the applications you want to push to your repository. +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+ Loading applications... +
+
+ Select one or more applications to push +
+ +
+ + +
+ +
+ + +
+ +
+
+ Pushing dashboards to Git... +
+ +
+ ✓ Dashboards successfully pushed to Git! +
+ +
+ ✗ Error occurred while pushing dashboards +
+
+ + + + + + + Push History + + + index=_internal source=*git_pusher* action=push_attempt | table _time, user, dashboards, commit_message, status, error_msg | reverse | rename _time as "Timestamp", user as "User", dashboards as "Dashboards", commit_message as "Message", status as "Status", error_msg as "Error" | head 20 + -30d@d + now + + + + {"success": "#28a745", "error": "#dc3545", "pending": "#ffc107"} + +
+
+
+ + \ No newline at end of file diff --git a/apps/pusher_app_prem/local/data/ui/views/git_pusher_config.xml b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_config.xml similarity index 100% rename from apps/pusher_app_prem/local/data/ui/views/git_pusher_config.xml rename to apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_config.xml diff --git a/apps/pusher_app_prem/local/data/ui/views/git_pusher_dashboard.xml b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_dashboard.xml similarity index 100% rename from apps/pusher_app_prem/local/data/ui/views/git_pusher_dashboard.xml rename to apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/data/ui/views/git_pusher_dashboard.xml diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/usage_stats.json b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/usage_stats.json new file mode 100644 index 00000000..bcf35e59 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/local/usage_stats.json @@ -0,0 +1 @@ +{"pushes_today": 1, "pushes_total": 47, "last_push_date": "2026-02-14", "apps_pushed": []} \ No newline at end of file diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/metadata/default.meta b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/metadata/default.meta new file mode 100644 index 00000000..b77b8cb9 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/metadata/default.meta @@ -0,0 +1,35 @@ + +# Application-level permissions + +[] +access = read : [ * ], write : [ admin, power ] + +### EVENT TYPES + +[eventtypes] +export = system + + +### PROPS + +[props] +export = system + + +### TRANSFORMS + +[transforms] +export = system + + +### LOOKUPS + +[lookups] +export = system + + +### VIEWSTATES: even normal users should be able to create shared viewstates + +[viewstates] +access = read : [ * ], write : [ * ] +export = system diff --git a/apps/Version git_pusheravant_nettoyage/pusher_app_prem/metadata/local.meta b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/metadata/local.meta new file mode 100644 index 00000000..76aeeb15 --- /dev/null +++ b/apps/Version git_pusheravant_nettoyage/pusher_app_prem/metadata/local.meta @@ -0,0 +1,30 @@ +[app/ui] +version = 10.0.2 +modtime = 1769115948.043388000 + +[app/launcher] +version = 10.0.2 +modtime = 1769115948.046389000 + +[views/git_pusher_-_push_dashboards_to_git] +access = read : [ admin ], write : [ admin ] +export = system +owner = admin +version = 10.0.2 +modtime = 1769276443.812957000 + +[views/git_pusher_-_push_applications_to_git] +owner = admin +version = 10.0.2 +modtime = 1769361925.808816000 + +[views/git_pusher_-_deploy_applications] +access = read : [ * ], write : [ * ] +export = none +owner = admin +version = 10.0.2 +modtime = 1769976365.099941000 + +[app/install/state] +version = 10.0.2 +modtime = 1771702401.801159000 diff --git a/apps/pusher_app_prem/default/app.conf b/apps/pusher_app_prem/default/app.conf index d2212d20..5d7d315c 100644 --- a/apps/pusher_app_prem/default/app.conf +++ b/apps/pusher_app_prem/default/app.conf @@ -10,7 +10,7 @@ is_visible = true label = Pusher Premium [launcher] -author = -description = -version = 2.0.0 +author = Jocelyn PAMPHILE +description = Application Splunk pour déployer vos applications vers Git et le Search Head Cluster +version = 2.1.0 diff --git a/apps/pusher_app_prem/default/data/ui/views/git_pusher_config.xml b/apps/pusher_app_prem/default/data/ui/views/git_pusher_config.xml new file mode 100644 index 00000000..b1fde3b1 --- /dev/null +++ b/apps/pusher_app_prem/default/data/ui/views/git_pusher_config.xml @@ -0,0 +1,311 @@ + + + Configuration de l'application Git Pusher + + + + + + +
+
+

⚙️ Configuration Git Pusher

+

Configurez les paramètres de l'application

+
+ +
+ + +
+

🌐 Configuration API

+
+ + + L'URL du serveur Git Pusher (sans le port si proxy) + + + + Port utilisé si accès direct par IP (ignoré si URL de domaine) + + + + Coché si vous utilisez un reverse proxy (Nginx, etc.) + + +
+ + ● Non testé +
+
+
+ + +
+

🚀 Configuration SH Deployer

+
+ + + Activer le déploiement automatique vers le Search Head Cluster + + + + Adresse IP ou hostname du serveur SH Deployer + + + + + + + Token configuré dans deployer_agent.py + + + + + +
+ + ● Non testé +
+
+
+ + +
+

🔐 Configuration Licence

+
+ +
Chargement...
+ + + + Fréquence de revalidation de la licence +
+
+ + +
+

🔧 Paramètres avancés

+
+ + + + + + + + +
+
+ + +
+ + +
+
+ +
Git Pusher v2.1
+ +
+
+
\ No newline at end of file diff --git a/apps/pusher_app_prem/default/data/ui/views/git_pusher_dashboard.xml b/apps/pusher_app_prem/default/data/ui/views/git_pusher_dashboard.xml new file mode 100644 index 00000000..aba9d9e5 --- /dev/null +++ b/apps/pusher_app_prem/default/data/ui/views/git_pusher_dashboard.xml @@ -0,0 +1,661 @@ + + + Push Splunk applications to Git repository and deploy to SH Cluster + + + | rest /services/apps/local | search disabled=0 | table title, label, description | rename title as name | sort label + -1m + now + + + + + + + +
+ +
+
+

🚀 Git Pusher

+ v2.2 +
+
+ +
+
+ + +
+ +
+

📦 Applications

+
+ +

Loading applications...

+
+
+ + +
+

⚙️ Git Configuration

+ +
+ + +
HTTPS URL of your Git repository
+
+ +
+ + +
+ +
+ + +
Personal access token with write permissions
+
+ +
+ + +
+ +
+ + +
+ + +
+
+
+ 🎯 Deploy to Search Head Cluster + + ● Checking... + +
+ +
+ +
+ + +
+ + +
+
+ +
+ + +
+ +
+
+ Splunk credentials for applying shcluster-bundle (optional if using default) +
+
+ + +
+
+
+ + +
+ + +
+ + +
+
+ Deploying applications to Git... Please wait +
+ +
+
+
+
+
+ + + +
+
+