Journal CWP : une interface web d'impression de fichiers PDF

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
36
26
août
2016

Bonjour à tous,

Note : désolé pour l'autopromotion, mais cette fois-ci je me dis que ça vaut le coup.

Cela vous est peut-être déjà arrivé : vous accueillez des invités dans votre entreprise ou chez vous. Ils ont des documents sur leur ordinateur portable et veulent les imprimer. Occasionnellement on s'en sort, mais à la longue, ça devient vite contraignant :

  • s'ils ont accès au serveur d'impression :
    • il faut leur fournir les instructions pour l'installation des pilotes
    • ils doivent (ou vous devez, en tant que super-admin) les installer, parfois pour imprimer seulement 3 pages
  • s'ils n'ont pas accès au serveur d'impression :
    • vous devez leur fournir un accès à un poste configuré
    • ils doivent transférer leurs documents sur ce poste (clé USB, e-mail…)
    • et il y manque probablement le logiciel permettant de modifier ces documents.

Une solution évidente, ce serait d'imprimer depuis une page web, mais en dehors de rares solutions propriétaires, rien n'existe pour imprimer sur un serveur CUPS.

Même sans être programmeur, je me suis dit que ça ne devait pas être trop compliqué de faire ça en PHP (que je connais un tout petit peu). Ça n'était pas si simple, mais le résultat n'est pas mal (si on exclut le design…) :
CWP example

CWP (pour CUPS Web Printing) génère donc, à partir d'un fichier JSON, une page web permettant l'envoi de fichiers PDF vers un serveur d'impression CUPS. Les fonctionnalités sont assez simples mais couvrent, je l'espère, pas mal de cas de figures :

  • le serveur CUPS peut-être distant
  • n'importe quelle option d'impression peut être permise par l'administrateur et choisie par l'utilisateur
  • une valeur par défaut peut être définie pour chaque option
  • les options peuvent être verrouillées (affichées mais non modifiables)
  • le nom d'utilisateur associé au job d'impression peut être défini par l'admin, ou réutilisé l'identifiant de l'utilisateur si la page est protégée par login / mot de passe
  • l'état de chaque imprimante peut être affiché (avec le nombre de travaux en attente dans la file)
  • il est possible d'interdire l'impression sur les imprimantes « éteintes »
  • il est possible de mettre des limites à la taille des fichiers PDF ainsi qu'au nombre d'exemplaire pour chaque impression
  • entièrement traduisible (anglais et français uniquement pour l'instant)
  • possibilité de l'inclure dans une page de votre site
  • et un mode debug pour comprendre d'éventuels soucis dans la liaison avec le serveur CUPS

Le code est disponible sur Framagit sous licence GPL.

Si vous avez des remarques, n'hésitez pas à m'en faire part.

  • # sécurité

    Posté par  (site web personnel) . Évalué à 10. Dernière modification le 27 août 2016 à 00:39.

    Le projet est intéressant et utile.

    Une remarque cependant. Je suis allé regarder le code. Le PHP est mélangé au HTML généré, et les variables sont insérées par simple concaténation de chaînes de caractères. Sans même parler de faille XSS, cela signifie que si une imprimante ou une option a un nom qui contient le caractère " par exemple, tout l'affichage de la page est cassé. Je vous recommanderais d'utiliser un système de template, qui en plus régler ces problèmes, rendra le code plus lisible.

    De même, le script lance des commandes sur la machine sans vérifier les arguments. Cela signifie que vous laissez n'importe quel invité exécuter n'importe quelle commande sur votre serveur.

    Et le fichier de configuration est dans un langage inventé pour l'occasion, qui ressemble au json, mais n'est pas totalement compatible, à cause du système de commentaires. Je conseillerais l'utilisation d'un langage existant, comme YAML par exemple, qui supporte les commentaires.

    • [^] # Re: sécurité

      Posté par  (site web personnel) . Évalué à 4. Dernière modification le 27 août 2016 à 09:55.

      Comme c'est du code pour un serveur web, il vaut mieux prendre la licence AGPL que juste GPL.

      • [^] # Re: sécurité

        Posté par  (site web personnel) . Évalué à 1.

        Ah oui je suis passé à côté… Si j'arrive à publier une nouvelle version avec les corrections proposées, ce sera sous AGPL.

    • [^] # Re: sécurité

      Posté par  (site web personnel) . Évalué à 5.

      Merci pour l'intérêt ainsi que pour ces remarques très pertinentes.

      Le PHP est mélangé au HTML généré, et les variables sont insérées par simple concaténation de chaînes de caractères. Sans même parler de faille XSS, cela signifie que si une imprimante ou une option a un nom qui contient le caractère " par exemple, tout l'affichage de la page est cassé. Je vous recommanderais d'utiliser un système de template, qui en plus régler ces problèmes, rendra le code plus lisible.

      Je n'avais que vaguement connaissance de ce système de template… Je vais regarder ça comme il faut.

      De même, le script lance des commandes sur la machine sans vérifier les arguments. Cela signifie que vous laissez n'importe quel invité exécuter n'importe quelle commande sur votre serveur.

      Là je comprends moins : la majorité des arguments sont des listes à choix, les choix étant fournis par l'administrateur. Ils y a éventuellement des champs textes, mais les principaux (les seuls jamais utiles ?) sont contrôlés (le nombre de copie doit être un entier non négatif, la liste des pages à imprimer est vérifiée directement par la commande "lp"). Finalement, toutes les commandes lancées sont échappées avec "escapeshellarg()" : là effectivement vous avez raison (je viens de relire le manuel) cette fonction devrait être utilisée sur chaque argument individuellement.

      Et le fichier de configuration est dans un langage inventé pour l'occasion, qui ressemble au json, mais n'est pas totalement compatible, à cause du système de commentaires. Je conseillerais l'utilisation d'un langage existant, comme YAML par exemple, qui supporte les commentaires.

      Je n'ai ajouté le support des commentaires que tout à la fin, ils ne sont à mon avis que très rarement utiles (sauf à avoir 10 imprimantes disponibles). Je vais regarder du côté de YAML : quitte à faire de gros changements dans le code, c'est vrai que ça vaudrait le coup d'utiliser un format standard et peut-être plus évolutif.

      Je vais essayer de trouver le temps de remettre ça au propre en suivant vos conseils. Encore merci d'avoir jeté un coup d'œil au code.

      • [^] # Re: sécurité

        Posté par  (site web personnel) . Évalué à 2.

        Pour info, il y a des paquetages tout fait pour YAML ou JSON pour PHP dans Debian. C'est plus facile que d'aller chercher à droite ou à gauche un machin sous github… et en général, c'est assez stable coté API ;-)

      • [^] # Re: sécurité

        Posté par  . Évalué à 3.

        la majorité des arguments sont des listes à choix, les choix étant fournis par l'administrateur.

        Un formulaire HTML est traduit en requête HTTP POST.
        Un client ne passant pas par un navigateur classique peut très bien forger cette requête et y mettre ce que bon lui semble.

        Regarde le classique Injection SQL, que tu peux aisément transposer à de l'injection shell comme : couleur="bleu$(rm -rf /*)".

        Lorsque tu passera ça à un shell, il va d'abord exécuter rm -rf /* pour construire l'argument de la commande que tu voulais lancer.

        Il y a plus subtil que cette simple volonté de nuire et qui va te sauter aux yeux quand ton serveur vas exploser en vol. Un pirate s'en servira sûrement pour implanter une porte dérobée, un agent rejoignant un botnet ou pour voler des données sensible.

  • # autre solution

    Posté par  (site web personnel) . Évalué à 4.

    Une autre solution est de partager son imprimante depuis l'ordinateur où CUPS est installé. Ça ne nécessite pas d'installer de pilote chez l'invité. Voir https://wiki.archlinux.org/index.php/CUPS/Printer_sharing

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.