commit 696ca4412afc8322ea2695207bca0a7025b2577b Author: jimmyGALLAND Date: Sun Apr 26 15:36:25 2026 +0200 first commit diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..104e3dc --- /dev/null +++ b/install.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +set -e + +SRC_DIR="$(cd "$(dirname "$0")" && pwd)" +WEB_DIR="/var/www" +BIN_TARGET="/usr/local/bin/usb-bind-wrapper.sh" +SUDOERS_FILE="/etc/sudoers.d/010_www-data-nopasswd" +HEADER_FILE="/var/www/header.php" + +echo "== Installation du plugin ==" + +cp -r "$SRC_DIR/js" "$WEB_DIR/js" +cp "$SRC_DIR/usb-toogle.php" "$WEB_DIR/" + +# 2. Installer le script dans /usr/local/bin +echo "-- Installation du wrapper USB" +cp "$SRC_DIR/bin/usb-bind-wrapper.sh" "$BIN_TARGET" +chmod +x "$BIN_TARGET" + +# 3. Vérifier sudo +echo "-- Vérification de sudo" +if ! command -v sudo >/dev/null 2>&1; then + echo "Erreur: sudo n'est pas installé" + exit 1 +fi + +# 4. Configurer sudoers +echo "-- Configuration sudoers" +if [ ! -f "$SUDOERS_FILE" ]; then + echo "Création du fichier sudoers" + echo "www-data ALL=(ALL) NOPASSWD: ALL" | sudo tee "$SUDOERS_FILE" > /dev/null + sudo chmod 440 "$SUDOERS_FILE" +else + echo "Le fichier sudoers existe déjà" +fi + +echo "-- Modification de header.php" + +if [ ! -f "$HEADER_FILE" ]; then + echo "Erreur: $HEADER_FILE introuvable" + exit 1 +fi + +if [ ! -f "$ADD_HEADER_FILE" ]; then + echo "Erreur: add-header.php introuvable" + exit 1 +fi +# Vérifier si déjà présent +if grep -q 'usb-toggle.js' "$HEADER_FILE"; then + echo "Script déjà présent, on skip" +else + TMP_FILE=$(mktemp) + + awk -v script="$SCRIPT_TAG" ' + { + # On injecte juste avant + if ($0 ~ /<\/head>/) { + print " " script + } + print + }' "$HEADER_FILE" > "$TMP_FILE" + + sudo mv "$TMP_FILE" "$HEADER_FILE" + echo "Script injecté avec succès" +fi + +echo "== Installation terminée ==" diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..a1813a1 --- /dev/null +++ b/readme.md @@ -0,0 +1,17 @@ +/var/www/usb-toggle.php +/usr/local/bin/usb-bind-wrapper + +dans header + +add-header.php + +Juste avant
  • Bluetooth
  • +----------- +Dans les script + +----------- +js/usb-toogle.js + +cat /etc/sudoers.d/010_www-data-nopasswd +www-data ALL=(ALL) NOPASSWD: ALL + diff --git a/src/bin/usb-bind-wrapper.sh b/src/bin/usb-bind-wrapper.sh new file mode 100644 index 0000000..05ab8ce --- /dev/null +++ b/src/bin/usb-bind-wrapper.sh @@ -0,0 +1,125 @@ +#!/bin/bash +# /usr/local/bin/usb-bind-wrapper +# Usage: usb-bind-wrapper bind +# usb-bind-wrapper unbind +# Example: usb-bind-wrapper unbind 1-1 + +set -euo pipefail + +if [ "$(id -u)" -ne 0 ]; then + echo "Ce script doit être exécuté via sudo (ex: sudo /usr/local/bin/usb-bind-wrapper.sh ...)" + exit 1 +fi + + +if [ $# -ne 2 ]; then + echo "Usage: $0 {bind|unbind|status} " + exit 2 +fi + +if [ "$1" = "status" ]; then + DEV="$2" + if [ -L "/sys/bus/usb/drivers/usb/$DEV" ]; then + echo "bound" + exit 0 + else + echo "unbound" + exit 1 + fi +fi + +ACTION="$1" +DEV="$2" + +# Validation simple du format (ex: 1-1 ou 1-1.2) +if [[ ! "$DEV" =~ ^[0-9]+(-[0-9]+)(\.[0-9]+)?$ ]]; then + echo "Identifiant USB invalide : $DEV" + exit 3 +fi + +case "$ACTION" in + bind) + SYS_PATH="/sys/bus/usb/drivers/usb/bind" + ;; + unbind) + SYS_PATH="/sys/bus/usb/drivers/usb/unbind" + ;; + *) + echo "Action invalide : $ACTION (utiliser bind ou unbind)" + exit 4 + ;; +esac + +if [ ! -w "$SYS_PATH" ]; then + echo "Impossible d'écrire dans $SYS_PATH (vérifie que le chemin existe et les permissions)" + exit 5 +fi + +# Exécute l'écriture (sécurisée) +printf '%s\n' "$DEV" > "$SYS_PATH" + +echo "OK: $ACTION $DEV" +exit 0 +root@chambre:~# cat /usr/local/bin/usb-bind-wrapper +#!/bin/bash +# /usr/local/bin/usb-bind-wrapper +# Usage: usb-bind-wrapper bind +# usb-bind-wrapper unbind +# Example: usb-bind-wrapper unbind 1-1 + +set -euo pipefail + +if [ "$(id -u)" -ne 0 ]; then + echo "Ce script doit être exécuté via sudo (ex: sudo /usr/local/bin/usb-bind-wrapper ...)" + exit 1 +fi + + +if [ $# -ne 2 ]; then + echo "Usage: $0 {bind|unbind|status} " + exit 2 +fi + +if [ "$1" = "status" ]; then + DEV="$2" + if [ -L "/sys/bus/usb/drivers/usb/$DEV" ]; then + echo "bound" + exit 0 + else + echo "unbound" + exit 1 + fi +fi + +ACTION="$1" +DEV="$2" + +# Validation simple du format (ex: 1-1 ou 1-1.2) +if [[ ! "$DEV" =~ ^[0-9]+(-[0-9]+)(\.[0-9]+)?$ ]]; then + echo "Identifiant USB invalide : $DEV" + exit 3 +fi + +case "$ACTION" in + bind) + SYS_PATH="/sys/bus/usb/drivers/usb/bind" + ;; + unbind) + SYS_PATH="/sys/bus/usb/drivers/usb/unbind" + ;; + *) + echo "Action invalide : $ACTION (utiliser bind ou unbind)" + exit 4 + ;; +esac + +if [ ! -w "$SYS_PATH" ]; then + echo "Impossible d'écrire dans $SYS_PATH (vérifie que le chemin existe et les permissions)" + exit 5 +fi + +# Exécute l'écriture (sécurisée) +printf '%s\n' "$DEV" > "$SYS_PATH" + +echo "OK: $ACTION $DEV" +exit 0 diff --git a/src/js/usb-toogle.js b/src/js/usb-toogle.js new file mode 100644 index 0000000..87dfca7 --- /dev/null +++ b/src/js/usb-toogle.js @@ -0,0 +1,95 @@ +function injectUsbMenu() { + if (document.getElementById("usbControlItem")) return; + + const menu = document.querySelector('.dropdown-menu'); + if (!menu) return; + + const anchor = document.querySelector('#dashboard-menu-item'); + + const li = document.createElement("li"); + li.id = "usbControlItem"; + li.className = "context-menu"; + + li.innerHTML = ` + + + USB Control + + + ... + + `; + + if (anchor && anchor.parentNode) { + anchor.parentNode.insertBefore(li, anchor.nextSibling); + } else { + menu.appendChild(li); + } +} + +document.addEventListener("DOMContentLoaded", injectUsbMenu); +setTimeout(injectUsbMenu, 1000); + + +document.addEventListener('DOMContentLoaded', function() { + const item = document.getElementById('usbControlItem'); + const dot = document.getElementById('usbControlDot'); + const label = document.getElementById('usbControlLabel'); + const link = document.getElementById('usbControlLink'); + + if (!item || !dot || !label || !link) return; + + let isOn = false; + let locked = false; + + // --- Fonction utilitaire : met à jour la pastille + function updateUI() { + dot.style.background = isOn ? '#2b2' : '#b22'; + label.textContent = isOn ? 'ON' : 'OFF'; + } + + // --- Fonction pour changer l’état + function toggleUSB() { + event.stopPropagation(); + if (locked) return; + locked = true; + + label.textContent = '...'; + fetch(`/usb-toggle.php?action=${isOn ? 'unbind' : 'bind'}`) + .then(res => res.json()) + .then(data => { + if (data.status === 'ok') { + isOn = !isOn; + updateUI(); + } else { + alert('Erreur: ' + data.msg); + } + }) + .catch(err => alert('Erreur réseau: ' + err)) + .finally(() => { + locked = false; + }); + } + + // --- Lecture de l’état au démarrage + fetch('/usb-toggle.php?action=status') + .then(res => res.json()) + .then(data => { + if (data.status === 'ok') { + isOn = (data.state === 'bound'); + updateUI(); + } + }) + .catch(() => { + label.textContent = '?'; + }); + + function mouseLeave() { + link.blur(); + + } + + item.addEventListener('click', toggleUSB); + link.addEventListener('mouseleave', mouseLeave); +}); diff --git a/src/usb-toogle.php b/src/usb-toogle.php new file mode 100644 index 0000000..348cba1 --- /dev/null +++ b/src/usb-toogle.php @@ -0,0 +1,27 @@ + 'error', 'msg' => 'Action invalide']); + exit; +} + +if ($action === 'status') { + exec("sudo /usr/local/bin/usb-bind-wrapper.sh status $dev 2>&1", $out, $rc); + $state = trim($out[0] ?? ''); + echo json_encode(['status' => 'ok', 'state' => $state]); + exit; +} + +$cmd = escapeshellcmd("sudo /usr/local/bin/usb-bind-wrapper.sh $action $dev"); +exec($cmd . " 2>&1", $out, $rc); + +if ($rc === 0) { + echo json_encode(['status' => 'ok', 'msg' => ucfirst($action) . " $dev réussi"]); +} else { + echo json_encode(['status' => 'error', 'msg' => implode("\n", $out)]); +} +?> +