lumo:creation_complete_du_plugin_dokuwiki:accueil
Ceci est une ancienne révision du document !
Création complète du plugin DokuWiki
Structure du Plugin
/lib/plugins/bashexec/ ├── action.php # Gestion des actions et appels ├── syntax.php # Syntaxe pour l'insertion dans les pages ├── helper.php # Fonctions utilitaires ├── script.sh # Votre script bash (optionnel) └── manifest.ini # Métadonnées du plugin
1. manifest.ini
[plugin] name=Bash Exec Plugin desc=Exécute des scripts bash avec validation sécurisée author=Votre Nom email=votre@email.com url=https://votre-site.com date=2026-03-12 version=1.0.0
2. helper.php (Fonctions utilitaires)
<?php /** * Helper class for Bash Exec Plugin */ class helper_plugin_bashexec extends DokuWiki_Plugin { /** * Validation stricte des arguments */ public function validateArgument($arg) { // Autorise uniquement alphanumérique, tirets et underscores if (!preg_match('/^[a-zA-Z0-9_-]{1,50}$/', $arg)) { return false; } return true; } /** * Validation du chemin du script */ public function validateScriptPath($path) { $allowedPaths = array( DOKU_PLUGIN . 'bashexec/scripts/', '/usr/local/bin/' ); foreach ($allowedPaths as $allowed) { if (strpos($path, $allowed) === 0) { return true; } } return false; } /** * Journalisation des exécutions */ public function logExecution($script, $args, $returnCode, $user) { $logFile = DOKU_LOG . '/bashexec.log'; $timestamp = date('Y-m-d H:i:s'); $entry = sprintf( "[%s] User: %s | Script: %s | Args: %s | Return: %d\n", $timestamp, $user, basename($script), implode(' ', $args), $returnCode ); file_put_contents($logFile, $entry, FILE_APPEND); } /** * Vérification des permissions */ public function checkPermissions() { global $USERINFO; // Vérifie si l'utilisateur est connecté if (!isset($USERINFO['name'])) { return false; } // Optionnel : Restreindre à certains groupes $allowedGroups = $this->getConf('allowed_groups'); if ($allowedGroups) { $userGroups = explode(',', $allowedGroups); foreach ($userGroups as $group) { if (in_array(trim($group), $USERINFO['groups'])) { return true; } } return false; } return true; } }
3. syntax.php (Syntaxe dans les pages wiki)
<?php /** * Syntax Plugin for Bash Exec */ class syntax_plugin_bashexec extends DokuWiki_Plugin_Syntax { public function getType() { return 'substition'; } public function getPType() { return 'normal'; } public function getSort() { return 150; } public function connectTo($mode) { $this->Lexer->addSpecialPattern('%%bashexec\{[^}]+\}%%', $mode, 'plugin_bashexec'); } public function handle($match, $state, $pos, Doku_Handler $handler) { preg_match('/%%bashexec\{([^}]+)\}%%/', $match, $matches); $params = trim($matches[1]); // Parse: script.sh arg1 arg2 $parts = preg_split('/\s+/', $params); $script = array_shift($parts); $args = $parts; return array($script, $args); } public function render($format, Doku_Renderer $renderer, $data) { if ($format != 'xhtml') { return false; } list($script, $args) = $data; $helper = plugin_load('helper', 'bashexec'); // Vérifier les permissions if (!$helper->checkPermissions()) { $renderer->cdata('Accès refusé'); return true; } // Valider le script if (!$helper->validateScriptPath(DOKU_PLUGIN . 'bashexec/scripts/' . $script)) { $renderer->cdata('Script non autorisé'); return true; } // Valider tous les arguments foreach ($args as $arg) { if (!$helper->validateArgument($arg)) { $renderer->cdata('Argument invalide'); return true; } } // Exécuter le script $fullScript = DOKU_PLUGIN . 'bashexec/scripts/' . $script; $cmd = escapeshellcmd($fullScript); $escapedArgs = array_map('escapeshellarg', $args); $command = $cmd . ' ' . implode(' ', $escapedArgs); exec($command, $output, $returnCode); // Journaliser global $INPUT; $helper->logExecution($script, $args, $returnCode, $INPUT->server->str('REMOTE_USER')); // Afficher le résultat if ($returnCode === 0) { $renderer->cdata(implode("\n", $output)); } else { $renderer->cdata('Erreur d\'exécution (code: ' . $returnCode . ')'); } return true; } }
4. action.php (Actions via URL)
<?php /** * Action Plugin for Bash Exec */ class action_plugin_bashexec extends DokuWiki_Action_Plugin { public function register(Doku_Event_Handler $controller) { $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleScriptRequest'); $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'renderOutput'); } public function handleScriptRequest(Doku_Event $event, $param) { if ($event->data !== 'script') { return; } $helper = plugin_load('helper', 'bashexec'); // Vérifier les permissions if (!$helper->checkPermissions()) { http_response_code(403); print json_encode(['error' => 'Accès refusé']); exit; } // Récupérer les paramètres $script = $this->getInput('script'); $arg1 = $this->getInput('arg1'); $arg2 = $this->getInput('arg2'); // Valider le script if (!$helper->validateScriptPath(DOKU_PLUGIN . 'bashexec/scripts/' . $script)) { http_response_code(400); print json_encode(['error' => 'Script non autorisé']); exit; } // Valider les arguments $args = array_filter([$arg1, $arg2]); foreach ($args as $arg) { if (!$helper->validateArgument($arg)) { http_response_code(400); print json_encode(['error' => 'Argument invalide']); exit; } } // Exécuter $fullScript = DOKU_PLUGIN . 'bashexec/scripts/' . $script; $escapedArgs = array_map('escapeshellarg', $args); $command = escapeshellcmd($fullScript) . ' ' . implode(' ', $escapedArgs); exec($command, $output, $returnCode); // Journaliser global $INPUT; $helper->logExecution($script, $args, $returnCode, $INPUT->server->str('REMOTE_USER')); // Répondre header('Content-Type: application/json'); print json_encode([ 'success' => $returnCode === 0, 'output' => $output, 'return_code' => $returnCode ]); exit; } private function getInput($key) { return isset($_GET[$key]) ? $_GET[$key] : (isset($_POST[$key]) ? $_POST[$key] : ''); } public function renderOutput(Doku_Event $event, $param) { // Peut être utilisé pour afficher des résultats après exécution } }
5. Exemple de Script Bash Sécurisé
#!/bin/bash # /lib/plugins/bashexec/scripts/status.sh # Vérifier les permissions du script if [ "$(id -u)" -eq 0 ]; then echo "Erreur: Le script ne doit pas être exécuté en root" >&2 exit 1 fi # Arguments attendus ARG1="${1:-}" ARG2="${2:-}" # Validation côté script (défense en profondeur) if [[ ! "$ARG1" =~ ^[a-zA-Z0-9_-]{1,50}$ ]]; then echo "Erreur: Argument 1 invalide" >&2 exit 1 fi # Exemple d'exécution case "$ARG1" in "status") echo "Statut: OK" echo "Paramètre: $ARG2" ;; "info") echo "Informations système" uname -a ;; *) echo "Commande inconnue: $ARG1" >&2 exit 1 ;; esac exit 0
6. Configuration Nginx Complète
server { listen 80; server_name wiki.votre-domaine.com; root /var/www/dokuwiki; index index.php; # Sécurité générale add_header X-Content-Type-Options nosniff; add_header X-Frame-Options SAMEORIGIN; add_header X-XSS-Protection "1; mode=block"; # DokuWiki principal location / { try_files $uri $uri/ @dokuwiki; } location @dokuwiki { fastcgi_pass unix:/var/run/php/php-fpm.sock; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/index.php; fastcgi_param HTTPS off; } # Protection des fichiers sensibles location ~* ^/(conf|inc|lib|data)/.*$ { deny all; return 403; } # Protection des scripts bash location ~* \.sh$ { deny all; return 403; } # Rate limiting pour l'exécution de scripts limit_req_zone $binary_remote_addr zone=bashexec:10m rate=5r/m; location /lib/plugins/bashexec/ { limit_req zone=bashexec burst=2 nodelay; fastcgi_pass unix:/var/run/php/php-fpm.sock; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/index.php; } # Logs spécifiques access_log /var/log/nginx/dokuwiki-bashexec.log; }
lumo/creation_complete_du_plugin_dokuwiki/accueil.1773312694.txt.gz · Dernière modification : de estro
