Linux : ajouter un client sftp et le chrooter

UPDATE : voici le lien (merci Hervé !) que j’aurais dû lire avant de faire tout cela…
A vous de lire mon blog + celui qui suit et de prendre le meilleur de chacun pour aller au plus vite !

Restrict SSH User Access to Certain Directory Using Chrooted Jail


Voici ce qu’il faut savoir (et qui m’a pris le plus de temps) : pour chrooter vraiment un utilisateur, il faut lui mettre les ordres de commande minimales requises dans un dossier bin et l’autre dossier qui gère les entrées-sorties dev. Et puis ajouter configurer le serveur ssh pour préciser « que du sftp, pas de ssh ». Ce n’est presque jamais documenté dans les sites d’exemples que vous trouverez sur le Web, merci unix.stackexchange !

Dans mon cas, voici tous les ordres que j’ai faits, et qui font qu’au final tout a fonctionné. Si ça se trouve il y en a un ou deux qui sont inutiles… mais je n’ai pas le temps de tout parfaitement nettoyer, je vous dis ce que j’ai compris des ordres, à ma manière :

  • Installer une ligne de commande shell qui peut fonctionner sans aucune dépendance :
    apt-get install bash-static
  • Ajouter l’utilisateur thomas en précisant le nom du shell à lancer :
    useradd -m -c /home/thomas -s /home/thomas/bin/sh thomas
  • Changer son mot de passe :
    passwd thomas
  • S’assurer que le home de Thomas appartient bien à root et est en 755 (sinon ssh refuse la connexion) :
    chmod 755 /home/thomas ; chown root: /home/thomas
  • Créer les dossiers bin et dev :
    mkdir /home/thomas/bin
    mkdir /home/thomas/dev
    cp /bin/bash-static /home/thomas/bin/sh
  • Ensuite il faut copier puis exécuter ce code, mais je ne sais pas trop à quoi ça sert :
    cp /dev/MAKEDEV /home/thomas/dev/
    cd /home/thomas/dev/ && ./MAKEDEV
  • Enfin le plus important : configurer le serveur sshd
    vim /etc/ssh/sshd_config

    Et y ajouter ces lignes, qui précisent où chrooter et (surtout) qu’on n’autorise que le sftp :

    Match user thomas
        ChrootDirectory /home/%u
        AllowTCPForwarding no
        X11Forwarding no
        ForceCommand internal-sftp

C’est le tout dernier ordre, toute dernière ligne qui m’a fait perdre énormément de temps !

Linux : compilation de Python en local

A l’IUT d’Aix en Provence, tous les ordinateurs sont gérés à distance, et sous Linux, aucune possibilité d’installer un logiciel.
Par contre, il est possible de compiler en local !

Compilation Python

Récupérez les dernières sources sur le site officiel.
Puis allez dans le dossier source et tapez :

./configure --prefix=$HOME/python

Puis, si tout s’est bien passé = pas de message d’erreur :

make && make install

A partir de là, sous PyCharm, précisez le chemin Python qui correspondra à votre $HOME/python et précisez que vous voulez installer les packages dans le répertoire de l’utilisateur courant (une case à cocher).

Et voilà : vous aurez un serveur Web Python et pourrez développer et installer tous les packages et librairies que vous voulez !

LibreOffice Impress : comment faire une macro

Comme ils l’expliquent officiellement ici, tout est en constante évolution, la documentation est pas forcément à jour etc, donc il vaut mieux aller jeter un coup d’oeil directement dans les rouages pour être sûr du fonctionnement de certains objets de LibreOffice. Ajoutez tout d’abord l’inspecteur d’objet. Il faut aller dans les Macros » Gestion des extensions, et ajouter en une extention en copiant/collant l’URL ici.

Tout d’abord le lieu de référence, celui que tout développeur cherche toujours : celui qui affiche tous les élements accessibles et ce qu’on peut faire avec : les namespaces !

List of all namespaces with brief descriptions

Je vous résume mon problème : la nouvelle mise à jour de LibreOffice change le comportement des animations et il n’est plus possible d’appliquer la même animation à un groupe. Il faut applique l’animation à la main, élément par élément ! Sur un slide de 40 pages j’ai déjà 40 fois à appliquer la même animation (ouverture en fondu), mais si je dois le faire pour 40 x 10 animations = 400 fois c’est du n’importe quoi.

Vous avez tout d’abord une liste d’exemples très intéressants ici. Mais le seul problème c’est qu’il y a très peu de choses concernant Impress. Il y a une super documentation ici, mais c’est sur des macros Python, et Python en macros, n’est utilisable que sur Write, pas sur Impress…

Voici un exemple très poussé et dont plein de choses fonctionnent à merveilles, mais certains appels ne fonctionnent pas.

C’est à partir de là que je me suis débrouillé pour écrire ma macro qui sélectionne toutes les animations du slide en cours, et les change au format « Ouverture en fondu -> Durée : 1.0s ».

Windows : astuce pour gagner du temps

  1. Placez un raccourci sont placés dans le répertoire C:\WINDOWS\system32\lnk.
  2. Ajoutez ce répertoire au PATH de Windows donc tous les raccourcis et autres programmes placés dans ce répertoire pourront être exécutés via DOS ou la commande Exécuter de Windows [WIN+R].
  3. Créez un fichier bat très court, moi j’ai, par exemple « h.bat »
  4. Dans ce fichier, si vous voulez ouvrir l’explorateur à un endroit spécifique, tapez « %SystemRoot%\explorer.exe "C:\BLABLA" » avec BLABLA étant le nom du dossier que vous voulez ouvrir

Note : si vous voulez que vos fenêtres s’ouvrent en mode « maximisé » (qui est différent de plein écran), ajoutez au début start /MAX. Exemple :
start /MAX %SystemRoot%\explorer.exe "C:\BLABLA"

Raccourci de liens

Depuis plus de 15 ans j’utilise cette astuce que peu de gens connaissent : cherchez à gagner du temps, vous verrez cela vous servira tôt ou tard !

Php Json Header

Entêtes

Toujours mettre ces en-têtes pour renvoyer du Php au format JSON + s’assurer qu’il n’y aura pas de problème de cache

header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Content-type: application/json');

Exemple complet fonctionnel

<?php
$phrase1=new stdClass();
$phrase1->composition=array('Nom commun', 'Aux + Verbe 3èmePS', 'CC Lieu');
$phrase1->id=12;
$phrase2=new stdClass();
$phrase2->composition=array('Nom commun', 'CC Temps', 'CC Lieu', 'Aux + Verbe 3èmePS');
$phrase2->id=18;
$retour=new stdClass();
$retour->phrases=array($phrase1, $phrase2);
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Content-type: application/json');
echo json_encode($retour);

Steam : comment créer un serveur de cache local

Toute l’explication est ici, simple et claire, en anglais.

Mais je vais résumer l’idée au cas où vous ne seriez pas forcément tenté de tout lire : lorsque vous installez un jeu, le programme Steam (que j’appellerai dorénavant simplement « Steam » parce que je suis fainéant) va demander au serveur Steam de distribution de contenu le plus proche. Et ça n’est pas forcément toujours le plus proche, ce qui fait que cela risque d’être long, mais surtout, vous serez toujours limité à la vitesse de votre connexion Internet. Ici, l’article explique comment faire la demande de votre Steam en priorité à un serveur Nginx local qui servira de cache : si ce dernier n’a pas le jeu en cache, il va aller faire suivre la demande de manière classique. Bien évidemment, si vous êtes comme moi et que vous possédez plus de 500 jeux sur Steam – oui, 500, certaines personnes croient que je mens… – il vous faudra un disque de plus de un terra pour qu’il garde la plupart des jeux en cache (oui oui, vous voulez quelques exemples de jeux lourds ? Je vous en donne après), mais cela dit à chaque fois que vous voudrez réinstaller un jeu, ou si vous achetez un nouvel ordinateur portable, ou vos amis arrivent avec leur portable chez vous et vous voulez leur faire installer, tester ou éventuellement acheter un jeu sur steam dans tous les cas c’est génial. Lisez l’article ici :

how-to-build-a-local-steam-cache-server

Quelques jeux qu’il est très bon d’avoir en cache :

  1. Viking: battle for Asgard: 5Go
  2. Ys VI: The Ark of Napishtim: 3Go
  3. Styx: Master of Shadows: 7Go
  4. Stronghold Crusader 2: 3Go
  5. Risen 2 – Dark Waters: 8Go
  6. Resident Evil 4 / Biohazard 4: 12Go
  7. Rayman Origins: 2Go
  8. Project Cars: 22Go
  9. Pap & Yo: 2Go
  10. Outlast: 4Go
  11. Ori and the Blind Forest: Definitive Edition: 11Go
  12. Operation Flashpoint: Dragon Rising: 5Go
  13. Operation Flashpoint: Red River: 5Go
  14. Oddworld: new ‘n’ tasty: 8Go

J’arrête là, on en est déjà à plus de 100Go pour 13 jeux, imaginez pour plus de 500 jeux… ils ne font pas tous plus de 2Go, heureusement !

Ergofip : il est sur le point de sortir !

Ergofip - international  ergonomic mechanical hightech customizable keyboard
Ergofip – international ergonomic mechanical hightech customizable keyboard

Après avoir…
– passé le site en https, https://www.ergofip.com,
– travaillé jour et nuit sur les photos
– travaillé plusieurs week ends sur le tournage

il est sur le point de sortir !

Ergofip - international  ergonomic mechanical hightech customizable keyboard
Ergofip – international ergonomic mechanical hightech customizable keyboard

Clavier mécanique, entièrement configurable, international et LEDs RGBs.

Merci à mes étudiants qui ont accepté ces photos :

Licence Pro / IUT Aix en Provence :

Ergofip - etudiants LP/IUT 2016-2017
Ergofip – etudiants LP/IUT 2016-2017

Et Ecole d’ingénieur ISEN Toulon :

Ergofip - etudiants ISEN 2016-2017
Ergofip – etudiants ISEN 2016-2017

Django annotate : à quoi ça sert ?

Je n’avais pas bien compris l’utilité de « annotate » dans les queries Django jusqu’à maintenant…

Voici quel était mon problème :

J’avais un modèle de base, Activite. Une activité contenait des choses concernant… une activité. Si si je vous jure !

Par exemple, une activité consistait à ajouter un voyage. Ou avoir une nouvelle relation. Ou faire un témoignage comme quoi on aimait bien le site. Etc.
Je voulais que ces activités soient « partageables » entre les amis.
J’ai crée un modèles ActiviteShare. Facile jusque là.

Mais lorsque je demandais à récupérer toutes les activités, il fallait que je les trie en me basant sur le fait de savoir si elles étaient partagées. Pour exagérer, imaginons une activité qui était faite en 2010. Vous étiez parti à Malibu. Génial ! Et maintenant, en 2016, un ami s’inscrit, devient votre ami, et vous voulez partager cette activité avec lui. Il faut qu’elle s’affiche dans votre mur, comme activité « partagée récemment », mais qu’elle garde sa date de 2010, ok ?

Donc je devais trier d’abord en fonction de la date de ActiviteShare puis seulement après par la date de création de l’Activite.

Seul hic : si vous aviez partagé cette activité avec 10 contacts, au moment du tri, Django renvoyait dix fois le même enregistrement.

Mon tri était super basique, du genre :

Activite.objects.filter(
    # blabla
).order_by(
    '-activiteshared__date_last_modif',
    '-date_last_modif',
    '-date_publication',)

Mais ça ne marchait pas. 🙁

La solution ? Annotate.

Pour vous expliquer avant de mettre le code : je lui demande, lors de la requête, de garder la date maximale parmi toutes les dates partagées, et de l’appeler « mx ». Ensuite, je demande de trier simplement d’abord par « mx », puis par la date de dernière modification de l’activité.

Activite.objects.filter(
    # blabla
).annotate(mx=Max('activiteshared__date_last_modif')).order_by(
    '-mx',
    '-date_last_modif',
    '-date_publication',)

Merci à ce lien qui m’a bien aidé.

Django : internationalisation des fichiers javascript : tutoriel complet

Django vient tout faire pour l’internationalisation de pages HTML, mais saviez-vous qu’il est aussi possible et de manière très simple d’internationaliser vos échanges AJAX ?

Vous avez un tutoriel ici.

Seul point noir : ils ont oublié deux éléments essentiels, je vais donc faire une explication courte ici, puis ajouter un résumé dans ma cheatsheet Django.

Dans l’ordre :

  • Configuration de urls.py :
    Ajouter le dictionnaire dans lequel vous précisez vos « packages ». Vos « packages », ce sont simplement les dossiers qui correspondent à l’application que vous voulez afficher. Normalement c’est un dossier racine de votre projet, moi je l’appelle très souvent « app » pour qu’il soit tout en haut des dossiers racine. Donc ici :

    js_info_dict = {
        'packages': ('app',)
    }
  • Configuration de urls.py :
    Ajouter l’URL jsi18n. Attention ! L’aide ne précise pas du tout où la mettre et c’est là où j’ai perdu énormément de temps, faites attention : il faut le mettre dans les patterns traduits, soit ici :

    urlpatterns += i18n_patterns(
        url(r'^jsi18n/$', javascript_catalog, js_info_dict,
            name='javascript_catalog'),
            # blabla...
    }
  • Includes des fichiers js dans les pages :
    <script src="{% url 'javascript_catalog' %}"></script>
  • Includes des fichiers js dans les pages :
    <script src="{% static 'js/globals.js' %}"></script>
  • Dans le fichier précédent, j’ai le code suggéré dans la documentation :
    function _(a) {
         return gettext(a);
    }
  • Générer les chaînes à traduire. Là aussi dans la documentation ils en parlent mais très mal. Pour résumer, il faut préciser le domaine djangojs :
    Exemple d’ordre qui lance la recherche de toutes les chaînes à traduire, en ignorant le dossier third_party (où je mets les outils externes que je ne veux pas toucher) :

    makemessages -d djangojs -i third_party --locale fr --locale en
  • Traduire. Ce sont les fichiers djangojs.domaine djangojs.po qu’il faut modifier, pas le classique django.po (sans strong>js).

Et à partir de là, tout fonctionne : dans tous les fichiers JavaScript qui suivent, je peux traduire à la fois ce qui arrive en AJAX, ou bien tout simplement afficher un message via _(). Exemple :

$('#menu').empty().append(
    $('<h5 />').html(_('Waiting...'))
);