feat: Add comprehensive permission management system (v0.3.1)
Implement three-tier permission management across all SecuBox modules: **1. Package-Level Permissions (PKG_FILE_MODES)** - Add PKG_FILE_MODES to all 15 module Makefiles - RPCD scripts: 755 (executable) - CSS/JS/JSON files: 644 (default, no config needed) - Ensures correct permissions at installation time **2. Runtime Permission Fix** - New script: /usr/libexec/secubox/fix-permissions.sh - RPCD method: luci.secubox fix_permissions - UI control: "🔧 Fix Perms" button in Quick Actions - Fixes all permissions and restarts services **3. Automation & Documentation** - secubox-tools/add-pkg-file-modes.sh: Auto-configure PKG_FILE_MODES - PERMISSIONS-GUIDE.md: Comprehensive permissions guide - MODULE-ENABLE-DISABLE-DESIGN.md: Enable/disable system design doc - Updated Makefile template with PKG_FILE_MODES pattern **Modules Updated:** - luci-app-auth-guardian - luci-app-bandwidth-manager - luci-app-cdn-cache - luci-app-client-guardian - luci-app-crowdsec-dashboard - luci-app-ksm-manager - luci-app-media-flow - luci-app-netdata-dashboard - luci-app-netifyd-dashboard - luci-app-network-modes - luci-app-secubox (+ fix-permissions.sh script) - luci-app-system-hub - luci-app-traffic-shaper - luci-app-vhost-manager - luci-app-wireguard-dashboard **Benefits:** - No more manual permission fixes after installation - Users can fix permissions from UI without SSH access - Proper OpenWrt package management compliance - Automated detection and configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
33f3b89393
commit
a53e5f7068
356
MODULE-ENABLE-DISABLE-DESIGN.md
Normal file
356
MODULE-ENABLE-DISABLE-DESIGN.md
Normal file
@ -0,0 +1,356 @@
|
||||
# Module Enable/Disable Design Document
|
||||
|
||||
**Version:** 0.3.1
|
||||
**Date:** 2025-12-27
|
||||
**Author:** Claude Code + CyberMind
|
||||
|
||||
## 🎯 Objectif
|
||||
|
||||
Remplacer la logique **start/stop** des modules SecuBox par une logique **enable/disable** (activé/désactivé), car les modules sont des **plugins installés** qu'on souhaite activer ou désactiver, plutôt que des services qu'on démarre ou arrête ponctuellement.
|
||||
|
||||
## 📋 Changements Conceptuels
|
||||
|
||||
### Avant (v0.2.x)
|
||||
|
||||
```
|
||||
Module installé → peut être "Running" ou "Stopped"
|
||||
Actions: Start / Stop / Restart
|
||||
État affiché: "Running" (vert) ou "Stopped" (gris)
|
||||
```
|
||||
|
||||
### Après (v0.3.1+)
|
||||
|
||||
```
|
||||
Module installé → peut être "Enabled" ou "Disabled"
|
||||
Actions: Enable / Disable
|
||||
État affiché: "Activé" (vert) ou "Désactivé" (gris)
|
||||
Info complémentaire: "Service running" (si enabled + running)
|
||||
```
|
||||
|
||||
## 🏗️ Architecture Technique
|
||||
|
||||
### 1. Configuration UCI
|
||||
|
||||
Chaque module dans `/etc/config/secubox` aura un champ `enabled`:
|
||||
|
||||
```uci
|
||||
config module 'crowdsec'
|
||||
option name 'CrowdSec Dashboard'
|
||||
option package 'luci-app-crowdsec-dashboard'
|
||||
option config 'crowdsec'
|
||||
option category 'security'
|
||||
option enabled '1' # NEW: 1 = activé, 0 = désactivé
|
||||
option icon '🛡️'
|
||||
option color '#ef4444'
|
||||
```
|
||||
|
||||
### 2. Méthodes RPCD (`luci.secubox`)
|
||||
|
||||
#### Anciennes méthodes (DEPRECATED)
|
||||
- ❌ `start_module(module_id)` → démarre le service
|
||||
- ❌ `stop_module(module_id)` → arrête le service
|
||||
- ❌ `restart_module(module_id)` → redémarre le service
|
||||
|
||||
#### Nouvelles méthodes (v0.3.1+)
|
||||
|
||||
```javascript
|
||||
// Active un module (config UCI + démarrage service)
|
||||
enable_module(module_id)
|
||||
→ uci set secubox.${module}.enabled='1'
|
||||
→ uci commit secubox
|
||||
→ /etc/init.d/${service} enable
|
||||
→ /etc/init.d/${service} start
|
||||
→ return { success: true, message: "Module activé" }
|
||||
|
||||
// Désactive un module (config UCI + arrêt service)
|
||||
disable_module(module_id)
|
||||
→ uci set secubox.${module}.enabled='0'
|
||||
→ uci commit secubox
|
||||
→ /etc/init.d/${service} disable
|
||||
→ /etc/init.d/${service} stop
|
||||
→ return { success: true, message: "Module désactivé" }
|
||||
|
||||
// Vérifie si un module est activé
|
||||
check_module_enabled(module_id)
|
||||
→ return uci get secubox.${module}.enabled == '1'
|
||||
|
||||
// Vérifie si le service tourne (info complémentaire)
|
||||
check_service_running(module_id)
|
||||
→ return pgrep -f ${service} > /dev/null
|
||||
```
|
||||
|
||||
### 3. Structure de données retournée
|
||||
|
||||
```json
|
||||
{
|
||||
"modules": [
|
||||
{
|
||||
"id": "crowdsec",
|
||||
"name": "CrowdSec Dashboard",
|
||||
"category": "security",
|
||||
"installed": true,
|
||||
"enabled": true, // État principal (config UCI)
|
||||
"running": true, // État du service (info)
|
||||
"status": "active", // enabled + running = "active"
|
||||
"icon": "🛡️",
|
||||
"color": "#ef4444"
|
||||
},
|
||||
{
|
||||
"id": "netdata",
|
||||
"name": "Netdata Monitoring",
|
||||
"category": "monitoring",
|
||||
"installed": true,
|
||||
"enabled": false, // Module désactivé
|
||||
"running": false,
|
||||
"status": "disabled", // Status affiché
|
||||
"icon": "📊",
|
||||
"color": "#22c55e"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4. États Possibles
|
||||
|
||||
| enabled | running | status | Badge UI | Description |
|
||||
|---------|---------|----------|---------------|-------------|
|
||||
| `true` | `true` | `active` | ✓ Activé | Module activé et service tourne |
|
||||
| `true` | `false` | `error` | ⚠️ Erreur | Module activé mais service arrêté (problème) |
|
||||
| `false` | `false` | `disabled` | ○ Désactivé | Module désactivé (état normal) |
|
||||
| `false` | `true` | `unknown` | ? Inconnu | État incohérent (rare) |
|
||||
|
||||
## 🎨 Interface Utilisateur
|
||||
|
||||
### Dashboard Principal (SecuBox Hub)
|
||||
|
||||
**Avant:**
|
||||
```
|
||||
[CrowdSec Dashboard] ● Running [Stop] [Restart]
|
||||
[Netdata Monitor] ○ Stopped [Start]
|
||||
```
|
||||
|
||||
**Après:**
|
||||
```
|
||||
[CrowdSec Dashboard] ✓ Activé [Désactiver]
|
||||
[Netdata Monitor] ○ Désactivé [Activer]
|
||||
```
|
||||
|
||||
### Module Individual Card
|
||||
|
||||
```html
|
||||
<div class="module-card enabled">
|
||||
<div class="module-header">
|
||||
<span class="module-icon">🛡️</span>
|
||||
<span class="module-name">CrowdSec Dashboard</span>
|
||||
<span class="module-badge enabled">✓ Activé</span>
|
||||
</div>
|
||||
<div class="module-status">
|
||||
<span class="status-dot running"></span>
|
||||
<span>Service en cours d'exécution</span>
|
||||
</div>
|
||||
<div class="module-actions">
|
||||
<button class="btn-disable">Désactiver</button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Classes CSS
|
||||
|
||||
```css
|
||||
/* Module states */
|
||||
.module-badge.enabled {
|
||||
background: linear-gradient(135deg, #22c55e, #16a34a);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.module-badge.disabled {
|
||||
background: var(--sh-bg-secondary);
|
||||
color: var(--sh-text-muted);
|
||||
}
|
||||
|
||||
.module-badge.error {
|
||||
background: linear-gradient(135deg, #f59e0b, #d97706);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Status indicators */
|
||||
.status-dot.running {
|
||||
background: #22c55e;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
.status-dot.stopped {
|
||||
background: #94a3b8;
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 API JavaScript
|
||||
|
||||
### Fichier: `secubox/api.js`
|
||||
|
||||
```javascript
|
||||
// Anciennes méthodes (DEPRECATED - à supprimer)
|
||||
startModule: callStartModule, // DEPRECATED
|
||||
stopModule: callStopModule, // DEPRECATED
|
||||
restartModule: callRestartModule, // DEPRECATED
|
||||
|
||||
// Nouvelles méthodes (v0.3.1+)
|
||||
enableModule: callEnableModule, // NEW
|
||||
disableModule: callDisableModule, // NEW
|
||||
|
||||
// Déclarations RPC
|
||||
var callEnableModule = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'enable_module',
|
||||
params: ['module_id'],
|
||||
expect: { success: false, message: '' }
|
||||
});
|
||||
|
||||
var callDisableModule = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'disable_module',
|
||||
params: ['module_id'],
|
||||
expect: { success: false, message: '' }
|
||||
});
|
||||
```
|
||||
|
||||
## 🔄 Migration des Données
|
||||
|
||||
### Script de migration (à exécuter une fois)
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
# migrate-to-enable-disable.sh
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
migrate_module() {
|
||||
local module="$1"
|
||||
local running=$(pgrep -f "$module" > /dev/null && echo "1" || echo "0")
|
||||
|
||||
# Si le service tourne actuellement, on l'active
|
||||
if [ "$running" = "1" ]; then
|
||||
uci set secubox.${module}.enabled='1'
|
||||
else
|
||||
# Sinon, on le désactive par défaut
|
||||
uci set secubox.${module}.enabled='0'
|
||||
fi
|
||||
}
|
||||
|
||||
# Migrer tous les modules
|
||||
config_load secubox
|
||||
config_foreach migrate_module module
|
||||
|
||||
uci commit secubox
|
||||
echo "Migration completed"
|
||||
```
|
||||
|
||||
## 📚 Documentation Utilisateur
|
||||
|
||||
### README.md (à ajouter)
|
||||
|
||||
```markdown
|
||||
## Gestion des Modules
|
||||
|
||||
Les modules SecuBox sont des plugins installés qui peuvent être **activés** ou **désactivés**.
|
||||
|
||||
### Activer un module
|
||||
- Cliquez sur le bouton **"Activer"** sur la carte du module
|
||||
- Le module sera configuré pour démarrer automatiquement au boot
|
||||
- Le service associé démarrera immédiatement
|
||||
|
||||
### Désactiver un module
|
||||
- Cliquez sur le bouton **"Désactiver"** sur la carte du module
|
||||
- Le module ne démarrera plus automatiquement au boot
|
||||
- Le service associé s'arrêtera immédiatement
|
||||
|
||||
### États des modules
|
||||
|
||||
| Badge | Signification |
|
||||
|-------|---------------|
|
||||
| ✓ Activé | Module activé et service en cours d'exécution |
|
||||
| ⚠️ Erreur | Module activé mais service arrêté (vérifier les logs) |
|
||||
| ○ Désactivé | Module désactivé (normal) |
|
||||
|
||||
**Note:** Les modules restent installés même lorsqu'ils sont désactivés. Pour les supprimer complètement, utilisez le gestionnaire de paquets APK.
|
||||
```
|
||||
|
||||
## 🧪 Tests à Effectuer
|
||||
|
||||
### Tests Unitaires RPCD
|
||||
|
||||
```bash
|
||||
# Test enable_module
|
||||
ubus call luci.secubox enable_module '{"module_id":"crowdsec"}'
|
||||
# Expected: {"success":true,"message":"Module activé"}
|
||||
|
||||
# Vérifier config UCI
|
||||
uci get secubox.crowdsec.enabled
|
||||
# Expected: 1
|
||||
|
||||
# Vérifier service
|
||||
/etc/init.d/crowdsec enabled && echo "OK" || echo "FAIL"
|
||||
pgrep crowdsec && echo "Running" || echo "Not running"
|
||||
|
||||
# Test disable_module
|
||||
ubus call luci.secubox disable_module '{"module_id":"crowdsec"}'
|
||||
# Expected: {"success":true,"message":"Module désactivé"}
|
||||
|
||||
# Vérifier
|
||||
uci get secubox.crowdsec.enabled
|
||||
# Expected: 0
|
||||
```
|
||||
|
||||
### Tests Interface
|
||||
|
||||
1. ✅ Ouvrir le dashboard SecuBox
|
||||
2. ✅ Vérifier que les modules affichent "Activé" ou "Désactivé"
|
||||
3. ✅ Cliquer sur "Désactiver" → badge passe à "○ Désactivé"
|
||||
4. ✅ Cliquer sur "Activer" → badge passe à "✓ Activé"
|
||||
5. ✅ Vérifier que le service démarre/s'arrête réellement
|
||||
6. ✅ Rafraîchir la page → état persiste (UCI)
|
||||
|
||||
## 📦 Modules Affectés
|
||||
|
||||
### SecuBox Hub (`luci-app-secubox`)
|
||||
|
||||
**Fichiers à modifier:**
|
||||
- ✅ `root/usr/libexec/rpcd/luci.secubox` - Backend RPCD
|
||||
- ✅ `htdocs/luci-static/resources/secubox/api.js` - API JS
|
||||
- ✅ `htdocs/luci-static/resources/view/secubox/dashboard.js` - Dashboard
|
||||
- ✅ `htdocs/luci-static/resources/view/secubox/modules.js` - Module list
|
||||
- ✅ `htdocs/luci-static/resources/secubox/dashboard.css` - Styles
|
||||
- ✅ `root/usr/share/rpcd/acl.d/luci-app-secubox.json` - ACL permissions
|
||||
- ✅ `README.md` - Documentation
|
||||
|
||||
### System Hub (`luci-app-system-hub`)
|
||||
|
||||
**Fichiers à modifier:**
|
||||
- ✅ `htdocs/luci-static/resources/view/system-hub/components.js` - Vue composants
|
||||
- ✅ `htdocs/luci-static/resources/view/system-hub/services.js` - Vue services
|
||||
- ✅ `README.md` - Documentation
|
||||
|
||||
## 🎯 Bénéfices
|
||||
|
||||
1. **Clarté conceptuelle**: "Activer/Désactiver" est plus clair que "Démarrer/Arrêter" pour des plugins
|
||||
2. **Persistance**: L'état persiste après redémarrage (UCI + init.d enable/disable)
|
||||
3. **Cohérence**: Tous les modules suivent la même logique
|
||||
4. **Meilleure UX**: L'utilisateur comprend qu'il active/désactive des fonctionnalités
|
||||
5. **Alignement OpenWrt**: Utilise les mécanismes natifs (`/etc/init.d/${service} enable/disable`)
|
||||
|
||||
## 🔜 Prochaines Étapes
|
||||
|
||||
- [x] Créer ce document de design
|
||||
- [ ] Implémenter les modifications RPCD
|
||||
- [ ] Mettre à jour l'API JavaScript
|
||||
- [ ] Mettre à jour les interfaces UI
|
||||
- [ ] Mettre à jour les ACL permissions
|
||||
- [ ] Créer script de migration UCI
|
||||
- [ ] Mettre à jour la documentation
|
||||
- [ ] Tester sur router de test
|
||||
- [ ] Déployer en production
|
||||
|
||||
---
|
||||
|
||||
**Maintainer:** CyberMind <contact@cybermind.fr>
|
||||
**License:** Apache-2.0
|
||||
229
PERMISSIONS-GUIDE.md
Normal file
229
PERMISSIONS-GUIDE.md
Normal file
@ -0,0 +1,229 @@
|
||||
# OpenWrt Package Permissions Guide
|
||||
|
||||
**Version:** 0.3.1
|
||||
**Date:** 2025-12-28
|
||||
**Author:** CyberMind
|
||||
|
||||
## 🎯 Objectif
|
||||
|
||||
Assurer que tous les fichiers des packages SecuBox ont les **bonnes permissions** dès l'installation, sans nécessiter de correction manuelle.
|
||||
|
||||
## 📋 Permissions Requises
|
||||
|
||||
### Fichiers Exécutables (755)
|
||||
|
||||
Ces fichiers **DOIVENT** avoir les permissions d'exécution:
|
||||
|
||||
```
|
||||
-rwxr-xr-x (755)
|
||||
```
|
||||
|
||||
**Liste des fichiers:**
|
||||
- `/usr/libexec/rpcd/luci.*` - Scripts RPCD backend
|
||||
- `/usr/libexec/secubox/*.sh` - Scripts utilitaires
|
||||
- `/etc/init.d/*` - Scripts d'initialisation
|
||||
- `/etc/uci-defaults/*` - Scripts de configuration initiale
|
||||
|
||||
### Fichiers Non-Exécutables (644)
|
||||
|
||||
Ces fichiers **NE DOIVENT PAS** être exécutables:
|
||||
|
||||
```
|
||||
-rw-r--r-- (644)
|
||||
```
|
||||
|
||||
**Liste des fichiers:**
|
||||
- `/www/luci-static/resources/**/*.js` - Fichiers JavaScript
|
||||
- `/www/luci-static/resources/**/*.css` - Fichiers CSS
|
||||
- `/usr/share/rpcd/acl.d/*.json` - Permissions ACL
|
||||
- `/usr/share/luci/menu.d/*.json` - Définitions de menu
|
||||
- `/etc/config/*` - Fichiers de configuration UCI
|
||||
|
||||
## 🔧 Configuration dans le Makefile
|
||||
|
||||
### Méthode Recommandée: PKG_FILE_MODES
|
||||
|
||||
OpenWrt supporte la variable `PKG_FILE_MODES` pour définir les permissions des fichiers lors de l'installation du package.
|
||||
|
||||
**Syntaxe:**
|
||||
```makefile
|
||||
PKG_FILE_MODES:=/path/to/file:permissions
|
||||
```
|
||||
|
||||
**Exemple complet:**
|
||||
```makefile
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-example
|
||||
PKG_VERSION:=0.3.1
|
||||
PKG_RELEASE:=1
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
||||
|
||||
LUCI_TITLE:=LuCI - Example Module
|
||||
LUCI_DESCRIPTION:=Example SecuBox module
|
||||
LUCI_DEPENDS:=+luci-base +rpcd
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.example:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
```
|
||||
|
||||
### Plusieurs Fichiers Exécutables
|
||||
|
||||
Si vous avez plusieurs fichiers exécutables:
|
||||
|
||||
```makefile
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.example:755 \
|
||||
/usr/libexec/example/helper.sh:755 \
|
||||
/etc/init.d/example:755
|
||||
```
|
||||
|
||||
**Note:** Utilisez `\` pour continuer sur la ligne suivante.
|
||||
|
||||
## 📦 Modules SecuBox avec PKG_FILE_MODES
|
||||
|
||||
### luci-app-secubox
|
||||
```makefile
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.secubox:755 \
|
||||
/usr/libexec/secubox/fix-permissions.sh:755
|
||||
```
|
||||
|
||||
### luci-app-system-hub
|
||||
```makefile
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.system-hub:755
|
||||
```
|
||||
|
||||
### luci-app-network-modes
|
||||
```makefile
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.network-modes:755
|
||||
```
|
||||
|
||||
## 🧪 Vérification
|
||||
|
||||
### Lors du Développement
|
||||
|
||||
Avant de déployer un package, vérifiez les permissions:
|
||||
|
||||
```bash
|
||||
# Vérifier les scripts RPCD
|
||||
ls -l root/usr/libexec/rpcd/luci.*
|
||||
|
||||
# Vérifier les scripts helper
|
||||
ls -l root/usr/libexec/*/
|
||||
|
||||
# Vérifier les fichiers web
|
||||
find root/www -type f -name "*.js" -o -name "*.css" | xargs ls -l
|
||||
```
|
||||
|
||||
### Après Installation du Package
|
||||
|
||||
Vérifiez que les permissions sont correctes sur le routeur:
|
||||
|
||||
```bash
|
||||
# RPCD scripts doivent être 755
|
||||
ls -l /usr/libexec/rpcd/luci.*
|
||||
|
||||
# Fichiers web doivent être 644
|
||||
ls -l /www/luci-static/resources/secubox/*.js
|
||||
ls -l /www/luci-static/resources/secubox/*.css
|
||||
```
|
||||
|
||||
## 🛠️ Script de Vérification Automatique
|
||||
|
||||
Un script de vérification est inclus dans `luci-app-secubox`:
|
||||
|
||||
```bash
|
||||
# Vérifier et corriger toutes les permissions
|
||||
/usr/libexec/secubox/fix-permissions.sh
|
||||
|
||||
# Via ubus
|
||||
ubus call luci.secubox fix_permissions
|
||||
|
||||
# Via l'interface web
|
||||
Dashboard → Quick Actions → "🔧 Fix Perms"
|
||||
```
|
||||
|
||||
## ⚠️ Erreurs Communes
|
||||
|
||||
### 1. RPCD Script Non-Exécutable
|
||||
|
||||
**Symptôme:**
|
||||
```bash
|
||||
ubus call luci.example status
|
||||
# Command failed: Permission denied
|
||||
```
|
||||
|
||||
**Cause:** Le script RPCD n'a pas les permissions 755
|
||||
|
||||
**Solution:**
|
||||
```makefile
|
||||
# Ajouter dans le Makefile
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.example:755
|
||||
```
|
||||
|
||||
### 2. Fichiers Web Exécutables
|
||||
|
||||
**Symptôme:** Fichiers JavaScript/CSS avec permissions 755
|
||||
|
||||
**Cause:** Mauvaise manipulation ou script mal configuré
|
||||
|
||||
**Solution:** Les fichiers web sont 644 par défaut avec LuCI, pas besoin de les spécifier dans PKG_FILE_MODES
|
||||
|
||||
### 3. Script Helper Non-Exécutable
|
||||
|
||||
**Symptôme:**
|
||||
```bash
|
||||
/usr/libexec/example/helper.sh
|
||||
# -bash: /usr/libexec/example/helper.sh: Permission denied
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
```makefile
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.example:755 \
|
||||
/usr/libexec/example/helper.sh:755
|
||||
```
|
||||
|
||||
## 📚 Références
|
||||
|
||||
- **LuCI Build System:** `$(TOPDIR)/feeds/luci/luci.mk`
|
||||
- **OpenWrt Package Build:** https://openwrt.org/docs/guide-developer/packages
|
||||
- **PKG_FILE_MODES:** https://openwrt.org/docs/guide-developer/build-system/use-buildsystem#build_system_variables
|
||||
|
||||
## ✅ Checklist Pré-Déploiement
|
||||
|
||||
Avant de créer un package `.ipk` ou `.apk`:
|
||||
|
||||
- [ ] Tous les scripts RPCD ont 755 dans PKG_FILE_MODES
|
||||
- [ ] Tous les scripts helper ont 755 dans PKG_FILE_MODES
|
||||
- [ ] Les fichiers web (JS/CSS) ne sont PAS dans PKG_FILE_MODES (ils sont 644 par défaut)
|
||||
- [ ] Les fichiers ACL/Menu ne sont PAS dans PKG_FILE_MODES (ils sont 644 par défaut)
|
||||
- [ ] Le Makefile utilise `include $(TOPDIR)/feeds/luci/luci.mk`
|
||||
- [ ] PKG_FILE_MODES est défini AVANT le `include $(TOPDIR)/feeds/luci/luci.mk`
|
||||
|
||||
## 🔄 Migration des Modules Existants
|
||||
|
||||
Pour ajouter PKG_FILE_MODES à un module existant:
|
||||
|
||||
```bash
|
||||
cd luci-app-mymodule
|
||||
|
||||
# Éditer le Makefile
|
||||
vi Makefile
|
||||
|
||||
# Ajouter avant 'include $(TOPDIR)/feeds/luci/luci.mk'
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.mymodule:755
|
||||
|
||||
# Reconstruire le package
|
||||
make package/luci-app-mymodule/clean
|
||||
make package/luci-app-mymodule/compile
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Maintainer:** CyberMind <contact@cybermind.fr>
|
||||
**License:** Apache-2.0
|
||||
@ -11,6 +11,10 @@ LUCI_DESCRIPTION:=Comprehensive authentication and session management with capti
|
||||
LUCI_DEPENDS:=+luci-base +rpcd +nodogsplash
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.auth-guardian:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@ -11,6 +11,10 @@ LUCI_DESCRIPTION:=Advanced bandwidth management with QoS rules, client quotas, a
|
||||
LUCI_DEPENDS:=+luci-base +rpcd +tc +kmod-sched-core +kmod-sched-cake +kmod-ifb +sqm-scripts +iptables +iptables-mod-conntrack-extra +ip-full
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.bandwidth-manager:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@ -11,6 +11,10 @@ LUCI_DESCRIPTION:=Dashboard for managing local CDN caching proxy on OpenWrt
|
||||
LUCI_DEPENDS:=+luci-base +rpcd
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.cdn-cache:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@ -20,6 +20,10 @@ LUCI_DEPENDS:=+luci-base +luci-app-secubox +luci-lib-jsonc +rpcd +rpcd-mod-luci
|
||||
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.client-guardian:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
|
||||
@ -20,6 +20,10 @@ LUCI_DEPENDS:=+luci-base +luci-app-secubox +crowdsec +luci-lib-jsonc +rpcd +rpcd
|
||||
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.crowdsec-dashboard:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
|
||||
@ -16,6 +16,10 @@ LUCI_PKGARCH:=all
|
||||
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.ksm-manager:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@ -14,6 +14,10 @@ LUCI_DESCRIPTION:=Real-time detection and monitoring of streaming services (Netf
|
||||
LUCI_DEPENDS:=+luci-base +rpcd +netifyd +luci-app-netifyd-dashboard
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.media-flow:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@ -20,6 +20,10 @@ LUCI_DEPENDS:=+luci-base +luci-app-secubox +luci-lib-jsonc +rpcd +rpcd-mod-luci
|
||||
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.netdata-dashboard:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
|
||||
@ -20,6 +20,10 @@ LUCI_DEPENDS:=+luci-base +luci-app-secubox +luci-lib-jsonc +rpcd +rpcd-mod-luci
|
||||
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.netifyd-dashboard:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
|
||||
@ -20,6 +20,9 @@ LUCI_DEPENDS:=+luci-base +luci-app-secubox +luci-lib-jsonc +rpcd +rpcd-mod-luci
|
||||
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.network-modes:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
|
||||
@ -63,12 +63,102 @@ return baseclass.extend({
|
||||
callGetAvailableModes(),
|
||||
callGetInterfaces()
|
||||
]).then(function(results) {
|
||||
var status = results[0] || {};
|
||||
var currentMode = results[1] || {};
|
||||
|
||||
// Merge current_mode into status for compatibility
|
||||
status.current_mode = currentMode.mode || 'router';
|
||||
status.interfaces = (results[3] || {}).interfaces || [];
|
||||
|
||||
return {
|
||||
status: results[0] || {},
|
||||
current_mode: results[1] || { mode: '' },
|
||||
available_modes: results[2] || { modes: [] },
|
||||
interfaces: results[3] || { interfaces: [] }
|
||||
status: status,
|
||||
modes: results[2] || { modes: [] }
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
// Get static information about a mode
|
||||
getModeInfo: function(mode) {
|
||||
var modeInfo = {
|
||||
router: {
|
||||
id: 'router',
|
||||
name: 'Router Mode',
|
||||
icon: '🏠',
|
||||
description: 'Traditional home/office router with NAT, firewall, and DHCP server. Ideal for connecting multiple devices to the internet.',
|
||||
features: [
|
||||
'NAT and firewall enabled',
|
||||
'DHCP server for LAN clients',
|
||||
'Port forwarding and DMZ',
|
||||
'QoS and traffic shaping'
|
||||
]
|
||||
},
|
||||
bridge: {
|
||||
id: 'bridge',
|
||||
name: 'Bridge Mode',
|
||||
icon: '🌉',
|
||||
description: 'Transparent layer-2 forwarding without NAT. All devices appear on the same network segment.',
|
||||
features: [
|
||||
'Layer-2 transparent bridging',
|
||||
'No NAT or routing',
|
||||
'STP/RSTP support',
|
||||
'VLAN tagging support'
|
||||
]
|
||||
},
|
||||
accesspoint: {
|
||||
id: 'accesspoint',
|
||||
name: 'Access Point',
|
||||
icon: '📡',
|
||||
description: 'WiFi access point with wired uplink. Extends your existing network wirelessly.',
|
||||
features: [
|
||||
'WiFi hotspot functionality',
|
||||
'Wired uplink to main router',
|
||||
'Multiple SSID support',
|
||||
'Fast roaming (802.11r/k/v)'
|
||||
]
|
||||
},
|
||||
relay: {
|
||||
id: 'relay',
|
||||
name: 'Repeater/Extender',
|
||||
icon: '🔁',
|
||||
description: 'WiFi to WiFi repeating to extend wireless coverage. Connects wirelessly to upstream network.',
|
||||
features: [
|
||||
'WiFi range extension',
|
||||
'Wireless uplink (WDS/Relay)',
|
||||
'Rebroadcast on same or different SSID',
|
||||
'Signal amplification'
|
||||
]
|
||||
},
|
||||
sniffer: {
|
||||
id: 'sniffer',
|
||||
name: 'Sniffer Mode',
|
||||
icon: '🔍',
|
||||
description: 'Network monitoring and packet capture mode for security analysis and troubleshooting.',
|
||||
features: [
|
||||
'Promiscuous mode capture',
|
||||
'WiFi monitor mode',
|
||||
'pcap/pcapng output',
|
||||
'Integration with Wireshark'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
return modeInfo[mode] || {
|
||||
id: mode,
|
||||
name: mode.charAt(0).toUpperCase() + mode.slice(1),
|
||||
icon: '⚙️',
|
||||
description: 'Unknown mode',
|
||||
features: []
|
||||
};
|
||||
},
|
||||
|
||||
// Format uptime seconds to human readable
|
||||
formatUptime: function(seconds) {
|
||||
if (!seconds || seconds < 0) return '0d 0h 0m';
|
||||
|
||||
var days = Math.floor(seconds / 86400);
|
||||
var hours = Math.floor((seconds % 86400) / 3600);
|
||||
var minutes = Math.floor((seconds % 3600) / 60);
|
||||
|
||||
return days + 'd ' + hours + 'h ' + minutes + 'm';
|
||||
}
|
||||
});
|
||||
|
||||
@ -11,6 +11,10 @@ LUCI_DESCRIPTION:=Central control hub for all SecuBox modules. Provides unified
|
||||
LUCI_DEPENDS:=+luci-base +rpcd +curl +jq
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.secubox:755 \
|
||||
/usr/libexec/secubox/fix-permissions.sh:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
* RPCD object: luci.secubox
|
||||
*/
|
||||
|
||||
// Version: 0.2.2
|
||||
// Version: 0.3.1
|
||||
|
||||
var callStatus = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
@ -54,6 +54,28 @@ var callRestartModule = rpc.declare({
|
||||
params: ['module']
|
||||
});
|
||||
|
||||
// NEW v0.3.1: Enable/Disable module methods
|
||||
var callEnableModule = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'enable_module',
|
||||
params: ['module'],
|
||||
expect: { success: false, message: '' }
|
||||
});
|
||||
|
||||
var callDisableModule = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'disable_module',
|
||||
params: ['module'],
|
||||
expect: { success: false, message: '' }
|
||||
});
|
||||
|
||||
var callCheckModuleEnabled = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'check_module_enabled',
|
||||
params: ['module'],
|
||||
expect: { enabled: false }
|
||||
});
|
||||
|
||||
var callHealth = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'health',
|
||||
@ -110,6 +132,12 @@ var callClearAlerts = rpc.declare({
|
||||
expect: { }
|
||||
});
|
||||
|
||||
var callFixPermissions = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'fix_permissions',
|
||||
expect: { success: false, message: '', output: '' }
|
||||
});
|
||||
|
||||
function formatUptime(seconds) {
|
||||
if (!seconds) return '0s';
|
||||
var d = Math.floor(seconds / 86400);
|
||||
@ -133,9 +161,15 @@ return baseclass.extend({
|
||||
getModules: callModules,
|
||||
getModulesByCategory: callModulesByCategory,
|
||||
getModuleInfo: callModuleInfo,
|
||||
// DEPRECATED: Use enable/disable instead
|
||||
startModule: callStartModule,
|
||||
stopModule: callStopModule,
|
||||
restartModule: callRestartModule,
|
||||
// NEW v0.3.1: Enable/Disable methods
|
||||
enableModule: callEnableModule,
|
||||
disableModule: callDisableModule,
|
||||
checkModuleEnabled: callCheckModuleEnabled,
|
||||
// Health & diagnostics
|
||||
getHealth: callHealth,
|
||||
getDiagnostics: callDiagnostics,
|
||||
getSystemHealth: callSystemHealth,
|
||||
@ -145,6 +179,8 @@ return baseclass.extend({
|
||||
getTheme: callGetTheme,
|
||||
dismissAlert: callDismissAlert,
|
||||
clearAlerts: callClearAlerts,
|
||||
fixPermissions: callFixPermissions,
|
||||
// Utilities
|
||||
formatUptime: formatUptime,
|
||||
formatBytes: formatBytes
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/* SecuBox Dashboard Styles * Version: 0.3.0
|
||||
/* SecuBox Dashboard Styles
|
||||
* Version: 0.3.1
|
||||
*/
|
||||
|
||||
.secubox-dashboard {
|
||||
@ -301,6 +302,28 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Module Status Indicators (v0.3.1) */
|
||||
.secubox-status-dot.secubox-status-active {
|
||||
background: #22c55e;
|
||||
box-shadow: 0 0 8px rgba(34, 197, 94, 0.5);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
.secubox-status-dot.secubox-status-disabled {
|
||||
background: #94a3b8;
|
||||
}
|
||||
|
||||
.secubox-status-dot.secubox-status-error {
|
||||
background: #f59e0b;
|
||||
box-shadow: 0 0 8px rgba(245, 158, 11, 0.5);
|
||||
}
|
||||
|
||||
.secubox-status-dot.secubox-status-unknown {
|
||||
background: #94a3b8;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* DEPRECATED: Keeping for backward compatibility */
|
||||
.secubox-status-dot.secubox-status-running {
|
||||
background: #22c55e;
|
||||
box-shadow: 0 0 8px rgba(34, 197, 94, 0.5);
|
||||
@ -334,6 +357,27 @@
|
||||
color: var(--sb-text-muted);
|
||||
}
|
||||
|
||||
/* Module Status Colors (v0.3.1) */
|
||||
.secubox-module-active .secubox-module-mini-status {
|
||||
color: #22c55e;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.secubox-module-disabled .secubox-module-mini-status {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.secubox-module-error .secubox-module-mini-status {
|
||||
color: #f59e0b;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.secubox-module-unknown .secubox-module-mini-status {
|
||||
color: #94a3b8;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* DEPRECATED: Keeping for backward compatibility */
|
||||
.secubox-module-running .secubox-module-mini-status {
|
||||
color: #22c55e;
|
||||
}
|
||||
|
||||
@ -256,10 +256,20 @@ return view.extend({
|
||||
};
|
||||
|
||||
var moduleCards = filteredModules.map(function(module) {
|
||||
var isRunning = module.running;
|
||||
var statusClass = isRunning ? 'running' : 'stopped';
|
||||
var status = module.status || 'unknown';
|
||||
var statusClass = status;
|
||||
var dashboardPath = modulePaths[module.id] || ('admin/secubox/' + module.id);
|
||||
|
||||
// Status label mapping (v0.3.1)
|
||||
var statusLabels = {
|
||||
'active': '✓ Activé',
|
||||
'disabled': '○ Désactivé',
|
||||
'error': '⚠️ Erreur',
|
||||
'unknown': '? Inconnu'
|
||||
};
|
||||
|
||||
var statusLabel = statusLabels[status] || '○ Désactivé';
|
||||
|
||||
return E('a', {
|
||||
'href': L.url(dashboardPath),
|
||||
'class': 'secubox-module-link secubox-module-' + statusClass
|
||||
@ -272,13 +282,12 @@ return view.extend({
|
||||
E('span', { 'class': 'secubox-module-mini-icon' }, module.icon || '📦'),
|
||||
E('span', {
|
||||
'class': 'secubox-status-dot secubox-status-' + statusClass,
|
||||
'title': isRunning ? 'Running' : 'Stopped'
|
||||
'title': statusLabel
|
||||
})
|
||||
]),
|
||||
E('div', { 'class': 'secubox-module-mini-body' }, [
|
||||
E('div', { 'class': 'secubox-module-mini-name' }, module.name || module.id),
|
||||
E('div', { 'class': 'secubox-module-mini-status' },
|
||||
isRunning ? '● Running' : '○ Stopped')
|
||||
E('div', { 'class': 'secubox-module-mini-status' }, statusLabel)
|
||||
])
|
||||
])
|
||||
]);
|
||||
@ -367,10 +376,20 @@ return view.extend({
|
||||
};
|
||||
|
||||
var moduleCards = filteredModules.map(function(module) {
|
||||
var isRunning = module.running;
|
||||
var statusClass = isRunning ? 'running' : 'stopped';
|
||||
var status = module.status || 'unknown';
|
||||
var statusClass = status;
|
||||
var dashboardPath = modulePaths[module.id] || ('admin/secubox/' + module.id);
|
||||
|
||||
// Status label mapping (v0.3.1)
|
||||
var statusLabels = {
|
||||
'active': '✓ Activé',
|
||||
'disabled': '○ Désactivé',
|
||||
'error': '⚠️ Erreur',
|
||||
'unknown': '? Inconnu'
|
||||
};
|
||||
|
||||
var statusLabel = statusLabels[status] || '○ Désactivé';
|
||||
|
||||
return E('a', {
|
||||
'href': L.url(dashboardPath),
|
||||
'class': 'secubox-module-link secubox-module-' + statusClass
|
||||
@ -383,13 +402,12 @@ return view.extend({
|
||||
E('span', { 'class': 'secubox-module-mini-icon' }, module.icon || '📦'),
|
||||
E('span', {
|
||||
'class': 'secubox-status-dot secubox-status-' + statusClass,
|
||||
'title': isRunning ? 'Running' : 'Stopped'
|
||||
'title': statusLabel
|
||||
})
|
||||
]),
|
||||
E('div', { 'class': 'secubox-module-mini-body' }, [
|
||||
E('div', { 'class': 'secubox-module-mini-name' }, module.name || module.id),
|
||||
E('div', { 'class': 'secubox-module-mini-status' },
|
||||
isRunning ? '● Running' : '○ Stopped')
|
||||
E('div', { 'class': 'secubox-module-mini-status' }, statusLabel)
|
||||
])
|
||||
])
|
||||
]);
|
||||
@ -443,6 +461,20 @@ return view.extend({
|
||||
]);
|
||||
});
|
||||
|
||||
// Add Fix Permissions button (v0.3.1)
|
||||
buttons.push(
|
||||
E('button', {
|
||||
'class': 'secubox-action-btn',
|
||||
'style': 'border-color: #f97316',
|
||||
'click': function() {
|
||||
self.executeFixPermissions();
|
||||
}
|
||||
}, [
|
||||
E('span', { 'class': 'secubox-action-icon' }, '🔧'),
|
||||
E('span', { 'class': 'secubox-action-label' }, 'Fix Perms')
|
||||
])
|
||||
);
|
||||
|
||||
return E('div', { 'class': 'secubox-card' }, [
|
||||
E('h3', { 'class': 'secubox-card-title' }, '⚡ Quick Actions'),
|
||||
E('div', { 'class': 'secubox-actions-grid' }, buttons)
|
||||
@ -474,6 +506,38 @@ return view.extend({
|
||||
});
|
||||
},
|
||||
|
||||
executeFixPermissions: function() {
|
||||
var self = this;
|
||||
ui.showModal(_('Fixing Permissions'), [
|
||||
E('p', { 'class': 'spinning' }, _('Fixing file permissions and restarting services...'))
|
||||
]);
|
||||
|
||||
API.fixPermissions().then(function(result) {
|
||||
ui.hideModal();
|
||||
if (result && result.success) {
|
||||
ui.addNotification(null, E('p', '✓ Permissions fixed successfully'), 'info');
|
||||
// Show output in console
|
||||
if (result.output) {
|
||||
console.log('Fix Permissions Output:\n' + result.output);
|
||||
}
|
||||
// Refresh data after fixing permissions
|
||||
setTimeout(function() {
|
||||
self.refreshData().then(function() {
|
||||
self.updateDynamicElements();
|
||||
});
|
||||
}, 2000);
|
||||
} else {
|
||||
ui.addNotification(null, E('p', '✗ ' + (result.message || 'Failed to fix permissions')), 'error');
|
||||
if (result.output) {
|
||||
console.error('Fix Permissions Error:\n' + result.output);
|
||||
}
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', 'Error: ' + err.message), 'error');
|
||||
});
|
||||
},
|
||||
|
||||
renderAlerts: function(alerts) {
|
||||
if (!alerts || alerts.length === 0) {
|
||||
return E('div', { 'class': 'secubox-card' }, [
|
||||
|
||||
@ -66,8 +66,8 @@ return view.extend({
|
||||
renderHeader: function(modules) {
|
||||
var total = modules.length;
|
||||
var installed = modules.filter(function(m) { return m.installed; }).length;
|
||||
var running = modules.filter(function(m) { return m.running; }).length;
|
||||
var stopped = installed - running;
|
||||
var enabled = modules.filter(function(m) { return m.enabled; }).length;
|
||||
var disabled = installed - enabled;
|
||||
|
||||
return E('div', { 'class': 'secubox-page-header' }, [
|
||||
E('div', {}, [
|
||||
@ -81,12 +81,12 @@ return view.extend({
|
||||
E('span', { 'class': 'secubox-stat-label' }, 'Total')
|
||||
]),
|
||||
E('div', { 'class': 'secubox-stat-badge secubox-stat-success' }, [
|
||||
E('span', { 'class': 'secubox-stat-value' }, running),
|
||||
E('span', { 'class': 'secubox-stat-label' }, 'Running')
|
||||
E('span', { 'class': 'secubox-stat-value' }, enabled),
|
||||
E('span', { 'class': 'secubox-stat-label' }, 'Activés')
|
||||
]),
|
||||
E('div', { 'class': 'secubox-stat-badge secubox-stat-warning' }, [
|
||||
E('span', { 'class': 'secubox-stat-value' }, stopped),
|
||||
E('span', { 'class': 'secubox-stat-label' }, 'Stopped')
|
||||
E('span', { 'class': 'secubox-stat-value' }, disabled),
|
||||
E('span', { 'class': 'secubox-stat-label' }, 'Désactivés')
|
||||
]),
|
||||
E('div', { 'class': 'secubox-stat-badge secubox-stat-muted' }, [
|
||||
E('span', { 'class': 'secubox-stat-value' }, total - installed),
|
||||
@ -144,9 +144,20 @@ return view.extend({
|
||||
|
||||
renderModuleCard: function(module) {
|
||||
var self = this;
|
||||
var isRunning = module.running;
|
||||
var status = module.status || 'unknown';
|
||||
var isInstalled = module.installed;
|
||||
var statusClass = isRunning ? 'running' : (isInstalled ? 'stopped' : 'not-installed');
|
||||
var statusClass = isInstalled ? status : 'not-installed';
|
||||
|
||||
// Status label mapping (v0.3.1)
|
||||
var statusLabels = {
|
||||
'active': '✓ Activé',
|
||||
'disabled': '○ Désactivé',
|
||||
'error': '⚠️ Erreur',
|
||||
'unknown': '? Inconnu',
|
||||
'not-installed': '- Not Installed'
|
||||
};
|
||||
|
||||
var statusLabel = isInstalled ? (statusLabels[status] || '○ Désactivé') : statusLabels['not-installed'];
|
||||
|
||||
return E('div', {
|
||||
'class': 'secubox-module-card secubox-module-' + statusClass,
|
||||
@ -166,7 +177,7 @@ return view.extend({
|
||||
]),
|
||||
E('div', {
|
||||
'class': 'secubox-status-indicator secubox-status-' + statusClass,
|
||||
'title': isRunning ? 'Running' : (isInstalled ? 'Stopped' : 'Not Installed')
|
||||
'title': statusLabel
|
||||
})
|
||||
]),
|
||||
|
||||
@ -184,7 +195,7 @@ return view.extend({
|
||||
E('span', { 'class': 'secubox-detail-label' }, 'Status:'),
|
||||
E('span', {
|
||||
'class': 'secubox-detail-value secubox-status-text-' + statusClass
|
||||
}, isRunning ? '● Running' : (isInstalled ? '○ Stopped' : '- Not Installed'))
|
||||
}, statusLabel)
|
||||
])
|
||||
])
|
||||
]),
|
||||
@ -207,36 +218,24 @@ return view.extend({
|
||||
}, '📥 Install')
|
||||
);
|
||||
} else {
|
||||
// Start/Stop button
|
||||
if (module.running) {
|
||||
// Enable/Disable button (v0.3.1)
|
||||
if (module.enabled) {
|
||||
actions.push(
|
||||
E('button', {
|
||||
'class': 'secubox-btn secubox-btn-danger secubox-btn-sm',
|
||||
'click': function() {
|
||||
self.stopModule(module);
|
||||
self.disableModule(module);
|
||||
}
|
||||
}, '⏹️ Stop')
|
||||
}, '⏹️ Désactiver')
|
||||
);
|
||||
} else {
|
||||
actions.push(
|
||||
E('button', {
|
||||
'class': 'secubox-btn secubox-btn-success secubox-btn-sm',
|
||||
'click': function() {
|
||||
self.startModule(module);
|
||||
self.enableModule(module);
|
||||
}
|
||||
}, '▶️ Start')
|
||||
);
|
||||
}
|
||||
|
||||
// Restart button (only if running)
|
||||
if (module.running) {
|
||||
actions.push(
|
||||
E('button', {
|
||||
'class': 'secubox-btn secubox-btn-warning secubox-btn-sm',
|
||||
'click': function() {
|
||||
self.restartModule(module);
|
||||
}
|
||||
}, '🔄 Restart')
|
||||
}, '▶️ Activer')
|
||||
);
|
||||
}
|
||||
|
||||
@ -286,69 +285,65 @@ return view.extend({
|
||||
return icons[category] || icons['other'];
|
||||
},
|
||||
|
||||
startModule: function(module) {
|
||||
// Enable module (v0.3.1)
|
||||
enableModule: function(module) {
|
||||
var self = this;
|
||||
ui.showModal(_('Starting Module'), [
|
||||
E('p', {}, _('Starting') + ' ' + module.name + '...')
|
||||
ui.showModal(_('Activation du module'), [
|
||||
E('p', {}, 'Activation de ' + module.name + '...')
|
||||
]);
|
||||
|
||||
API.startModule(module.id).then(function(result) {
|
||||
API.enableModule(module.id).then(function(result) {
|
||||
ui.hideModal();
|
||||
if (result && result.success !== false) {
|
||||
ui.addNotification(null, E('p', module.name + ' started successfully'), 'info');
|
||||
ui.addNotification(null, E('p', module.name + ' activé avec succès'), 'info');
|
||||
self.refreshData().then(function() {
|
||||
self.updateModulesGrid();
|
||||
});
|
||||
} else {
|
||||
ui.addNotification(null, E('p', 'Failed to start ' + module.name), 'error');
|
||||
ui.addNotification(null, E('p', 'Échec de l\'activation de ' + module.name), 'error');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', 'Error: ' + err.message), 'error');
|
||||
ui.addNotification(null, E('p', 'Erreur: ' + err.message), 'error');
|
||||
});
|
||||
},
|
||||
|
||||
stopModule: function(module) {
|
||||
// Disable module (v0.3.1)
|
||||
disableModule: function(module) {
|
||||
var self = this;
|
||||
ui.showModal(_('Stopping Module'), [
|
||||
E('p', {}, _('Stopping') + ' ' + module.name + '...')
|
||||
ui.showModal(_('Désactivation du module'), [
|
||||
E('p', {}, 'Désactivation de ' + module.name + '...')
|
||||
]);
|
||||
|
||||
API.stopModule(module.id).then(function(result) {
|
||||
API.disableModule(module.id).then(function(result) {
|
||||
ui.hideModal();
|
||||
if (result && result.success !== false) {
|
||||
ui.addNotification(null, E('p', module.name + ' stopped successfully'), 'info');
|
||||
ui.addNotification(null, E('p', module.name + ' désactivé avec succès'), 'info');
|
||||
self.refreshData().then(function() {
|
||||
self.updateModulesGrid();
|
||||
});
|
||||
} else {
|
||||
ui.addNotification(null, E('p', 'Failed to stop ' + module.name), 'error');
|
||||
ui.addNotification(null, E('p', 'Échec de la désactivation de ' + module.name), 'error');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', 'Error: ' + err.message), 'error');
|
||||
ui.addNotification(null, E('p', 'Erreur: ' + err.message), 'error');
|
||||
});
|
||||
},
|
||||
|
||||
// DEPRECATED: Keeping for backward compatibility
|
||||
startModule: function(module) {
|
||||
return this.enableModule(module);
|
||||
},
|
||||
|
||||
stopModule: function(module) {
|
||||
return this.disableModule(module);
|
||||
},
|
||||
|
||||
restartModule: function(module) {
|
||||
var self = this;
|
||||
ui.showModal(_('Restarting Module'), [
|
||||
E('p', {}, _('Restarting') + ' ' + module.name + '...')
|
||||
]);
|
||||
|
||||
API.restartModule(module.id).then(function(result) {
|
||||
ui.hideModal();
|
||||
if (result && result.success !== false) {
|
||||
ui.addNotification(null, E('p', module.name + ' restarted successfully'), 'info');
|
||||
self.refreshData().then(function() {
|
||||
self.updateModulesGrid();
|
||||
});
|
||||
} else {
|
||||
ui.addNotification(null, E('p', 'Failed to restart ' + module.name), 'error');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', 'Error: ' + err.message), 'error');
|
||||
return this.disableModule(module).then(function() {
|
||||
return self.enableModule(module);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@ -44,14 +44,25 @@ check_module_installed() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if a module is enabled (UCI config)
|
||||
check_module_enabled() {
|
||||
local module="$1"
|
||||
local enabled
|
||||
|
||||
config_load secubox
|
||||
config_get enabled "$module" enabled "1"
|
||||
|
||||
echo "$enabled"
|
||||
}
|
||||
|
||||
# Check if a module service is running
|
||||
check_module_running() {
|
||||
local module="$1"
|
||||
local config
|
||||
|
||||
|
||||
config_load secubox
|
||||
config_get config "$module" config ""
|
||||
|
||||
|
||||
case "$module" in
|
||||
crowdsec)
|
||||
pgrep -f crowdsec > /dev/null 2>&1 && echo "1" || echo "0"
|
||||
@ -79,6 +90,22 @@ check_module_running() {
|
||||
esac
|
||||
}
|
||||
|
||||
# Determine module status based on enabled + running
|
||||
get_module_status() {
|
||||
local enabled="$1"
|
||||
local running="$2"
|
||||
|
||||
if [ "$enabled" = "1" ] && [ "$running" = "1" ]; then
|
||||
echo "active"
|
||||
elif [ "$enabled" = "1" ] && [ "$running" = "0" ]; then
|
||||
echo "error"
|
||||
elif [ "$enabled" = "0" ] && [ "$running" = "0" ]; then
|
||||
echo "disabled"
|
||||
else
|
||||
echo "unknown"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get overall system status
|
||||
get_status() {
|
||||
local total=0
|
||||
@ -159,7 +186,9 @@ get_modules() {
|
||||
config_get version "$module" version "0.0.9"
|
||||
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_enabled=$(check_module_enabled "$module")
|
||||
local is_running=$(check_module_running "$module")
|
||||
local status=$(get_module_status "$is_enabled" "$is_running")
|
||||
|
||||
# Get real version from opkg if installed
|
||||
if [ "$is_installed" = "1" ] && [ -n "$package" ]; then
|
||||
@ -178,7 +207,9 @@ get_modules() {
|
||||
json_add_string "config" "$config"
|
||||
json_add_string "version" "$version"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
json_add_boolean "enabled" "$is_enabled"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_add_string "status" "$status"
|
||||
json_add_boolean "in_uci" "1"
|
||||
json_close_object
|
||||
|
||||
@ -213,7 +244,9 @@ get_modules() {
|
||||
esac
|
||||
|
||||
local clean_module=$(echo "$module_id" | sed 's/_/-/g')
|
||||
local is_enabled=$(check_module_enabled "$module_id")
|
||||
local is_running=$(check_module_running "$module_id")
|
||||
local status=$(get_module_status "$is_enabled" "$is_running")
|
||||
|
||||
json_add_object ""
|
||||
json_add_string "id" "$module_id"
|
||||
@ -226,7 +259,9 @@ get_modules() {
|
||||
json_add_string "config" "$clean_module"
|
||||
json_add_string "version" "$version"
|
||||
json_add_boolean "installed" "1"
|
||||
json_add_boolean "enabled" "$is_enabled"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_add_string "status" "$status"
|
||||
json_add_boolean "in_uci" "0"
|
||||
json_close_object
|
||||
done
|
||||
@ -265,7 +300,9 @@ get_modules_by_category() {
|
||||
config_get version "$module" version "0.0.9"
|
||||
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_enabled=$(check_module_enabled "$module")
|
||||
local is_running=$(check_module_running "$module")
|
||||
local status=$(get_module_status "$is_enabled" "$is_running")
|
||||
|
||||
# Get real version from opkg if installed
|
||||
if [ "$is_installed" = "1" ] && [ -n "$package" ]; then
|
||||
@ -282,7 +319,9 @@ get_modules_by_category() {
|
||||
json_add_string "version" "$version"
|
||||
json_add_string "package" "$package"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
json_add_boolean "enabled" "$is_enabled"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_add_string "status" "$status"
|
||||
json_add_boolean "in_uci" "1"
|
||||
json_close_object
|
||||
|
||||
@ -321,7 +360,9 @@ get_modules_by_category() {
|
||||
name=$(echo "$package" | sed 's/^luci-app-//' | sed 's/-dashboard$//' | sed 's/-/ /g' | sed 's/\b\(.\)/\u\1/g')
|
||||
|
||||
local is_installed="1" # Must be installed if detected
|
||||
local is_enabled=$(check_module_enabled "$module_id")
|
||||
local is_running=$(check_module_running "$module_id")
|
||||
local status=$(get_module_status "$is_enabled" "$is_running")
|
||||
|
||||
json_add_object ""
|
||||
json_add_string "id" "$module_id"
|
||||
@ -333,7 +374,9 @@ get_modules_by_category() {
|
||||
json_add_string "package" "$package"
|
||||
json_add_string "category" "$mod_category"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
json_add_boolean "enabled" "$is_enabled"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_add_string "status" "$status"
|
||||
json_add_boolean "in_uci" "0"
|
||||
json_close_object
|
||||
fi
|
||||
@ -361,7 +404,9 @@ get_module_info() {
|
||||
config_get version "$module" version "0.0.9"
|
||||
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_enabled=$(check_module_enabled "$module")
|
||||
local is_running=$(check_module_running "$module")
|
||||
local status=$(get_module_status "$is_enabled" "$is_running")
|
||||
|
||||
json_init
|
||||
json_add_string "id" "$module"
|
||||
@ -374,7 +419,9 @@ get_module_info() {
|
||||
json_add_string "config" "$config"
|
||||
json_add_string "version" "$version"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
json_add_boolean "enabled" "$is_enabled"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_add_string "status" "$status"
|
||||
json_dump
|
||||
}
|
||||
|
||||
@ -422,14 +469,14 @@ stop_module() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Restart a module
|
||||
# Restart a module (DEPRECATED - use disable/enable instead)
|
||||
restart_module() {
|
||||
local module="$1"
|
||||
local config
|
||||
|
||||
|
||||
config_load secubox
|
||||
config_get config "$module" config ""
|
||||
|
||||
|
||||
if [ -x "/etc/init.d/${config}" ]; then
|
||||
/etc/init.d/${config} restart
|
||||
json_init
|
||||
@ -444,6 +491,64 @@ restart_module() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Enable a module (NEW v0.3.1)
|
||||
enable_module() {
|
||||
local module="$1"
|
||||
local config
|
||||
|
||||
config_load secubox
|
||||
config_get config "$module" config ""
|
||||
|
||||
# Set enabled flag in UCI
|
||||
uci set secubox.${module}.enabled='1'
|
||||
uci commit secubox
|
||||
|
||||
# Enable and start service if init script exists
|
||||
if [ -x "/etc/init.d/${config}" ]; then
|
||||
/etc/init.d/${config} enable
|
||||
/etc/init.d/${config} start
|
||||
|
||||
json_init
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Module activé"
|
||||
json_dump
|
||||
else
|
||||
json_init
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "message" "Init script not found"
|
||||
json_dump
|
||||
fi
|
||||
}
|
||||
|
||||
# Disable a module (NEW v0.3.1)
|
||||
disable_module() {
|
||||
local module="$1"
|
||||
local config
|
||||
|
||||
config_load secubox
|
||||
config_get config "$module" config ""
|
||||
|
||||
# Set disabled flag in UCI
|
||||
uci set secubox.${module}.enabled='0'
|
||||
uci commit secubox
|
||||
|
||||
# Disable and stop service if init script exists
|
||||
if [ -x "/etc/init.d/${config}" ]; then
|
||||
/etc/init.d/${config} stop
|
||||
/etc/init.d/${config} disable
|
||||
|
||||
json_init
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Module désactivé"
|
||||
json_dump
|
||||
else
|
||||
json_init
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "message" "Init script not found"
|
||||
json_dump
|
||||
fi
|
||||
}
|
||||
|
||||
# Get health report
|
||||
get_health() {
|
||||
json_init
|
||||
@ -752,12 +857,16 @@ get_dashboard_data() {
|
||||
config_get color "$module" color "#64748b"
|
||||
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_enabled="0"
|
||||
local is_running="0"
|
||||
local status="disabled"
|
||||
|
||||
total=$((total + 1))
|
||||
|
||||
if [ "$is_installed" = "1" ]; then
|
||||
is_enabled=$(check_module_enabled "$module")
|
||||
is_running=$(check_module_running "$module")
|
||||
status=$(get_module_status "$is_enabled" "$is_running")
|
||||
installed=$((installed + 1))
|
||||
[ "$is_running" = "1" ] && running=$((running + 1))
|
||||
fi
|
||||
@ -770,7 +879,9 @@ get_dashboard_data() {
|
||||
json_add_string "icon" "$icon"
|
||||
json_add_string "color" "$color"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
json_add_boolean "enabled" "$is_enabled"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_add_string "status" "$status"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
@ -844,6 +955,34 @@ clear_alerts() {
|
||||
json_dump
|
||||
}
|
||||
|
||||
# Fix permissions (v0.3.1)
|
||||
fix_permissions() {
|
||||
local fix_script="/usr/libexec/secubox/fix-permissions.sh"
|
||||
|
||||
if [ ! -x "$fix_script" ]; then
|
||||
json_init
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "message" "Fix script not found or not executable"
|
||||
json_dump
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Run the fix script and capture output
|
||||
local output=$($fix_script 2>&1)
|
||||
local exit_code=$?
|
||||
|
||||
json_init
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Permissions fixed successfully"
|
||||
else
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "message" "Failed to fix permissions"
|
||||
fi
|
||||
json_add_string "output" "$output"
|
||||
json_dump
|
||||
}
|
||||
|
||||
# Main dispatcher
|
||||
case "$1" in
|
||||
list)
|
||||
@ -867,6 +1006,15 @@ case "$1" in
|
||||
json_add_object "restart_module"
|
||||
json_add_string "module" "string"
|
||||
json_close_object
|
||||
json_add_object "enable_module"
|
||||
json_add_string "module" "string"
|
||||
json_close_object
|
||||
json_add_object "disable_module"
|
||||
json_add_string "module" "string"
|
||||
json_close_object
|
||||
json_add_object "check_module_enabled"
|
||||
json_add_string "module" "string"
|
||||
json_close_object
|
||||
json_add_object "health"
|
||||
json_close_object
|
||||
json_add_object "diagnostics"
|
||||
@ -887,6 +1035,8 @@ case "$1" in
|
||||
json_close_object
|
||||
json_add_object "clear_alerts"
|
||||
json_close_object
|
||||
json_add_object "fix_permissions"
|
||||
json_close_object
|
||||
json_dump
|
||||
;;
|
||||
call)
|
||||
@ -927,6 +1077,27 @@ case "$1" in
|
||||
json_get_var module module ""
|
||||
restart_module "$module"
|
||||
;;
|
||||
enable_module)
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var module module ""
|
||||
enable_module "$module"
|
||||
;;
|
||||
disable_module)
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var module module ""
|
||||
disable_module "$module"
|
||||
;;
|
||||
check_module_enabled)
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var module module ""
|
||||
local enabled=$(check_module_enabled "$module")
|
||||
json_init
|
||||
json_add_boolean "enabled" "$enabled"
|
||||
json_dump
|
||||
;;
|
||||
health)
|
||||
get_health
|
||||
;;
|
||||
@ -960,6 +1131,9 @@ case "$1" in
|
||||
clear_alerts)
|
||||
clear_alerts
|
||||
;;
|
||||
fix_permissions)
|
||||
fix_permissions
|
||||
;;
|
||||
*)
|
||||
echo '{"error":"Unknown method"}'
|
||||
;;
|
||||
|
||||
169
luci-app-secubox/root/usr/libexec/secubox/fix-permissions.sh
Normal file
169
luci-app-secubox/root/usr/libexec/secubox/fix-permissions.sh
Normal file
@ -0,0 +1,169 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SecuBox Permissions Fix Script
|
||||
# Automatically fixes file permissions for SecuBox modules
|
||||
# Copyright (C) 2025 CyberMind.fr
|
||||
|
||||
set -e
|
||||
|
||||
LOG_TAG="secubox-fix-perms"
|
||||
|
||||
log_info() {
|
||||
logger -t "$LOG_TAG" -p info "$1"
|
||||
echo "[INFO] $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
logger -t "$LOG_TAG" -p err "$1"
|
||||
echo "[ERROR] $1" >&2
|
||||
}
|
||||
|
||||
fix_rpcd_permissions() {
|
||||
log_info "Fixing RPCD script permissions..."
|
||||
|
||||
local rpcd_scripts="
|
||||
/usr/libexec/rpcd/luci.secubox
|
||||
/usr/libexec/rpcd/luci.system-hub
|
||||
/usr/libexec/rpcd/luci.network-modes
|
||||
/usr/libexec/rpcd/luci.crowdsec-dashboard
|
||||
/usr/libexec/rpcd/luci.netdata-dashboard
|
||||
/usr/libexec/rpcd/luci.netifyd-dashboard
|
||||
/usr/libexec/rpcd/luci.wireguard-dashboard
|
||||
/usr/libexec/rpcd/luci.client-guardian
|
||||
/usr/libexec/rpcd/luci.bandwidth-manager
|
||||
/usr/libexec/rpcd/luci.auth-guardian
|
||||
/usr/libexec/rpcd/luci.media-flow
|
||||
/usr/libexec/rpcd/luci.vhost-manager
|
||||
/usr/libexec/rpcd/luci.traffic-shaper
|
||||
/usr/libexec/rpcd/luci.cdn-cache
|
||||
/usr/libexec/rpcd/luci.ksm-manager
|
||||
"
|
||||
|
||||
local count=0
|
||||
for script in $rpcd_scripts; do
|
||||
if [ -f "$script" ]; then
|
||||
chmod 755 "$script" 2>/dev/null && count=$((count + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
log_info "Fixed $count RPCD scripts (755)"
|
||||
}
|
||||
|
||||
fix_web_permissions() {
|
||||
log_info "Fixing web resources permissions..."
|
||||
|
||||
# Fix CSS files
|
||||
local css_count=0
|
||||
if [ -d "/www/luci-static/resources" ]; then
|
||||
css_count=$(find /www/luci-static/resources -type f -name "*.css" -exec chmod 644 {} \; -print 2>/dev/null | wc -l)
|
||||
fi
|
||||
log_info "Fixed $css_count CSS files (644)"
|
||||
|
||||
# Fix JS files
|
||||
local js_count=0
|
||||
if [ -d "/www/luci-static/resources" ]; then
|
||||
js_count=$(find /www/luci-static/resources -type f -name "*.js" -exec chmod 644 {} \; -print 2>/dev/null | wc -l)
|
||||
fi
|
||||
log_info "Fixed $js_count JS files (644)"
|
||||
}
|
||||
|
||||
fix_config_permissions() {
|
||||
log_info "Fixing configuration file permissions..."
|
||||
|
||||
local count=0
|
||||
|
||||
# Fix ACL files
|
||||
for acl in /usr/share/rpcd/acl.d/luci-app-*.json; do
|
||||
if [ -f "$acl" ]; then
|
||||
chmod 644 "$acl" 2>/dev/null && count=$((count + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
# Fix menu files
|
||||
for menu in /usr/share/luci/menu.d/luci-app-*.json; do
|
||||
if [ -f "$menu" ]; then
|
||||
chmod 644 "$menu" 2>/dev/null && count=$((count + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
log_info "Fixed $count config files (644)"
|
||||
}
|
||||
|
||||
restart_services() {
|
||||
log_info "Restarting services..."
|
||||
|
||||
if /etc/init.d/rpcd restart >/dev/null 2>&1; then
|
||||
log_info "RPCD restarted successfully"
|
||||
else
|
||||
log_error "Failed to restart RPCD"
|
||||
fi
|
||||
|
||||
if /etc/init.d/uhttpd restart >/dev/null 2>&1; then
|
||||
log_info "uHTTPd restarted successfully"
|
||||
else
|
||||
log_error "Failed to restart uHTTPd"
|
||||
fi
|
||||
}
|
||||
|
||||
verify_permissions() {
|
||||
log_info "Verifying permissions..."
|
||||
|
||||
local errors=0
|
||||
|
||||
# Check RPCD scripts
|
||||
for script in /usr/libexec/rpcd/luci.*; do
|
||||
if [ -f "$script" ]; then
|
||||
local perms=$(ls -l "$script" 2>/dev/null | cut -c1-10)
|
||||
if [ "$perms" != "-rwxr-xr-x" ]; then
|
||||
log_error "Invalid permissions on $script: $perms (expected -rwxr-xr-x)"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Check critical files
|
||||
for file in /www/luci-static/resources/secubox/api.js /www/luci-static/resources/secubox/dashboard.css; do
|
||||
if [ -f "$file" ]; then
|
||||
local perms=$(ls -l "$file" 2>/dev/null | cut -c1-10)
|
||||
if [ "$perms" != "-rw-r--r--" ]; then
|
||||
log_error "Invalid permissions on $file: $perms (expected -rw-r--r--)"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $errors -eq 0 ]; then
|
||||
log_info "All permissions verified successfully"
|
||||
return 0
|
||||
else
|
||||
log_error "Found $errors permission errors"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
echo "================================================"
|
||||
echo " SecuBox Permissions Fix Script v0.3.1"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
fix_rpcd_permissions
|
||||
fix_web_permissions
|
||||
fix_config_permissions
|
||||
|
||||
echo ""
|
||||
restart_services
|
||||
|
||||
echo ""
|
||||
verify_permissions
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo " Permissions fix completed!"
|
||||
echo "================================================"
|
||||
}
|
||||
|
||||
# Run if executed directly
|
||||
if [ "${0##*/}" = "fix-permissions.sh" ]; then
|
||||
main "$@"
|
||||
fi
|
||||
@ -8,6 +8,7 @@
|
||||
"modules",
|
||||
"modules_by_category",
|
||||
"module_info",
|
||||
"check_module_enabled",
|
||||
"health",
|
||||
"diagnostics",
|
||||
"get_system_health",
|
||||
@ -30,9 +31,12 @@
|
||||
"start_module",
|
||||
"stop_module",
|
||||
"restart_module",
|
||||
"enable_module",
|
||||
"disable_module",
|
||||
"quick_action",
|
||||
"dismiss_alert",
|
||||
"clear_alerts"
|
||||
"clear_alerts",
|
||||
"fix_permissions"
|
||||
],
|
||||
"uci": [
|
||||
"set",
|
||||
|
||||
@ -11,6 +11,9 @@ LUCI_DESCRIPTION:=Central system control with monitoring, services, logs, and ba
|
||||
LUCI_DEPENDS:=+luci-base +rpcd +coreutils +coreutils-base64
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.system-hub:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@ -10,6 +10,10 @@ LUCI_TITLE:=Traffic Shaper - Advanced QoS Control
|
||||
LUCI_DESCRIPTION:=Advanced traffic shaping with TC/CAKE for precise bandwidth control
|
||||
LUCI_DEPENDS:=+luci-base +rpcd +tc +kmod-sched-core +kmod-sched-cake
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.traffic-shaper:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@ -14,6 +14,10 @@ LUCI_DESCRIPTION:=Nginx reverse proxy manager with Let's Encrypt SSL certificate
|
||||
LUCI_DEPENDS:=+luci-base +rpcd +nginx-ssl +acme +curl
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.vhost-manager:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
@ -20,6 +20,10 @@ LUCI_DEPENDS:=+luci-base +luci-app-secubox +luci-lib-jsonc +rpcd +rpcd-mod-luci
|
||||
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
|
||||
# File permissions (RPCD scripts must be executable)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.wireguard-dashboard:755
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
|
||||
209
secubox-tools/add-pkg-file-modes.sh
Executable file
209
secubox-tools/add-pkg-file-modes.sh
Executable file
@ -0,0 +1,209 @@
|
||||
#!/bin/bash
|
||||
# Add PKG_FILE_MODES to OpenWrt Makefiles
|
||||
# Automatically detects RPCD scripts and adds correct permissions
|
||||
#
|
||||
# Usage: ./add-pkg-file-modes.sh [module-path]
|
||||
# ./add-pkg-file-modes.sh --all (process all luci-app-* modules)
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[OK]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Detect RPCD scripts in a module
|
||||
detect_rpcd_scripts() {
|
||||
local module_path="$1"
|
||||
local rpcd_dir="$module_path/root/usr/libexec/rpcd"
|
||||
|
||||
if [ ! -d "$rpcd_dir" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
find "$rpcd_dir" -type f -name "luci.*" 2>/dev/null | while read script; do
|
||||
basename "$script"
|
||||
done
|
||||
}
|
||||
|
||||
# Detect helper scripts in a module
|
||||
detect_helper_scripts() {
|
||||
local module_path="$1"
|
||||
local helper_dir="$module_path/root/usr/libexec"
|
||||
|
||||
if [ ! -d "$helper_dir" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Find .sh files in subdirectories (not in rpcd/)
|
||||
find "$helper_dir" -type f -name "*.sh" ! -path "*/rpcd/*" 2>/dev/null | while read script; do
|
||||
echo "$script" | sed "s|^$module_path/root||"
|
||||
done
|
||||
}
|
||||
|
||||
# Generate PKG_FILE_MODES line
|
||||
generate_pkg_file_modes() {
|
||||
local module_name="$1"
|
||||
local rpcd_scripts="$2"
|
||||
local helper_scripts="$3"
|
||||
|
||||
local modes=""
|
||||
|
||||
# Add RPCD scripts
|
||||
for script in $rpcd_scripts; do
|
||||
if [ -z "$modes" ]; then
|
||||
modes="/usr/libexec/rpcd/$script:755"
|
||||
else
|
||||
modes="$modes \\\\\n\\t/usr/libexec/rpcd/$script:755"
|
||||
fi
|
||||
done
|
||||
|
||||
# Add helper scripts
|
||||
for script in $helper_scripts; do
|
||||
if [ -z "$modes" ]; then
|
||||
modes="$script:755"
|
||||
else
|
||||
modes="$modes \\\\\n\\t$script:755"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$modes" ]; then
|
||||
echo -e "# File permissions (RPCD scripts must be executable)\nPKG_FILE_MODES:=$modes"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if Makefile already has PKG_FILE_MODES
|
||||
has_pkg_file_modes() {
|
||||
local makefile="$1"
|
||||
grep -q "^PKG_FILE_MODES:=" "$makefile" 2>/dev/null
|
||||
}
|
||||
|
||||
# Add PKG_FILE_MODES to Makefile
|
||||
add_to_makefile() {
|
||||
local makefile="$1"
|
||||
local pkg_file_modes="$2"
|
||||
|
||||
if [ ! -f "$makefile" ]; then
|
||||
log_error "Makefile not found: $makefile"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if already exists
|
||||
if has_pkg_file_modes "$makefile"; then
|
||||
log_warning "PKG_FILE_MODES already exists in $makefile"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Find the line with 'include $(TOPDIR)/feeds/luci/luci.mk'
|
||||
if ! grep -q "include.*luci.mk" "$makefile"; then
|
||||
log_error "Cannot find luci.mk include in $makefile"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Create backup
|
||||
cp "$makefile" "$makefile.bak"
|
||||
|
||||
# Insert PKG_FILE_MODES before the include line
|
||||
awk -v modes="$pkg_file_modes" '
|
||||
/^include.*luci\.mk/ {
|
||||
print ""
|
||||
print modes
|
||||
print ""
|
||||
}
|
||||
{ print }
|
||||
' "$makefile.bak" > "$makefile"
|
||||
|
||||
log_success "Added PKG_FILE_MODES to $makefile"
|
||||
rm -f "$makefile.bak"
|
||||
}
|
||||
|
||||
# Process a single module
|
||||
process_module() {
|
||||
local module_path="$1"
|
||||
local module_name=$(basename "$module_path")
|
||||
|
||||
log_info "Processing $module_name..."
|
||||
|
||||
# Detect scripts
|
||||
local rpcd_scripts=$(detect_rpcd_scripts "$module_path")
|
||||
local helper_scripts=$(detect_helper_scripts "$module_path")
|
||||
|
||||
if [ -z "$rpcd_scripts" ] && [ -z "$helper_scripts" ]; then
|
||||
log_warning "No executable scripts found in $module_name"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Generate PKG_FILE_MODES
|
||||
local pkg_file_modes=$(generate_pkg_file_modes "$module_name" "$rpcd_scripts" "$helper_scripts")
|
||||
|
||||
if [ -z "$pkg_file_modes" ]; then
|
||||
log_warning "Could not generate PKG_FILE_MODES for $module_name"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Add to Makefile
|
||||
local makefile="$module_path/Makefile"
|
||||
add_to_makefile "$makefile" "$pkg_file_modes"
|
||||
|
||||
# Show what was added
|
||||
echo ""
|
||||
echo " Scripts found:"
|
||||
[ -n "$rpcd_scripts" ] && echo " RPCD: $(echo $rpcd_scripts | tr '\n' ' ')"
|
||||
[ -n "$helper_scripts" ] && echo " Helper: $(echo $helper_scripts | tr '\n' ' ')"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main
|
||||
main() {
|
||||
echo "================================================"
|
||||
echo " PKG_FILE_MODES Auto-Configurator v0.3.1"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
if [ "$1" = "--all" ]; then
|
||||
log_info "Processing all luci-app-* modules..."
|
||||
echo ""
|
||||
|
||||
find "$PROJECT_ROOT" -maxdepth 1 -type d -name "luci-app-*" | sort | while read module_path; do
|
||||
process_module "$module_path"
|
||||
done
|
||||
|
||||
elif [ -n "$1" ] && [ -d "$1" ]; then
|
||||
process_module "$1"
|
||||
|
||||
else
|
||||
log_error "Usage: $0 [module-path] | --all"
|
||||
log_info "Examples:"
|
||||
log_info " $0 ../luci-app-secubox"
|
||||
log_info " $0 --all"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo " Processing complete!"
|
||||
echo "================================================"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@ -14,9 +14,14 @@ PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
||||
# LuCI specific
|
||||
LUCI_TITLE:=LuCI - Package Description
|
||||
LUCI_DESCRIPTION:=Detailed description of what this package does
|
||||
LUCI_DEPENDS:=+luci-base
|
||||
LUCI_DEPENDS:=+luci-base +rpcd
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
# File permissions (CRITICAL: RPCD scripts MUST be executable)
|
||||
# CSS/JS files are 644 by default (correct)
|
||||
# Only specify files that need non-default permissions (755 for executables)
|
||||
PKG_FILE_MODES:=/usr/libexec/rpcd/luci.PACKAGE_NAME:755
|
||||
|
||||
# Include LuCI build system
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user