PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

Le don du mois : Python requests 4

mercredi 4 février 2015 à 12:55

Il n’y aucune cohérence dans ma manière de donner. Je le fais au fil de l’eau, anarchiquement. Parfois j’oublie pendant des mois et des mois.

Là, je me baladais sur l’excellente documentation de la non moins excellente lib requests, à la recherche du one-liner qui allait, encore une fois, me faire gagner un bon quart d’heure.

Et j’ai vu un bouton “Buy request pro”.

Curieux. Il y a plus mieux que le meilleur de requests ?

Je clique, et en fait le bouton est juste là pour proposer de supporter requests. On “achète” la lib gratuite :)

Le minimum est $12, ce qui est fort raisonnable considérant que ce petit bout de code m’a sauvé la mise un million de fois :

Bref, 10 euros, c’est le prix de mon amour en février. Je suis un mec facile.

Des pastes mystérieux sur 0bin 13

vendredi 30 janvier 2015 à 12:19

J’ai reçu un email étrange nous signalant des pastes sur 0bin.net comme étant pédophiles et nous demandant de les retirer.

Le contenu en question ressemble à ceci. Vous pouvez cliquer, c’est safe.

Vu les abus de DMCA ces temps-ci, je suis plutôt méfiant sur ce genre d’allégation, et j’ai donc demandé un peu plus de détails. La personne, contrairement à pas mal de mecs de boites avec des avocats, a pris le temps de quelques échanges avec moi et, malgré mon ton clairement sceptique, a fini par m’expliquer le principe.

Certains forums hébergeant des photos sexualisant des mineurs sont accessibles au public. Néanmoins, pour y accéder, il faut obtenir des indices qui changent régulièrement. Ces indices sont postés sur des boards jetables, comme cette page facebook, qui pointe sur des pastebin, dans notre cas 0bin.

Ensuite, il faut aller sur le site connu pour son contenu, ajouter les filtres adblocks, faire quelques manipulations JS (dans l’exemple, un flag localstorage), et l’entrée est possible.

Je vire donc ces pastes quand on me les signale, et je fais circuler l’info, au cas où vous tombiez sur ce genre de trucs, que vous sachiez de quoi il retourne.

0bin n’étant pas modérable (c’est le principe), il est logique que des usages non souhaités en soit fait. J’aimerais donc profiter de cet article pour rappeler que le chiffrement n’est pas que pour les terroristes et les pédophiles. Tout comme les couteaux ne sont pas uniquement pour les serial killers : la plupart des gens découpent des carottes avec.

Il y a, en proportion, peu de pédophiles, et peu de serial killers. Ils existent, il ne faut pas les ignorer. Mais ne paniquons pas à l’idée qu’ils utilisent des outils utiles pour les citoyens lambda également. Nous créons un monde pour ces citoyens, pas pour les autres.

Écouter sur le port 80 sans être root 16

mercredi 28 janvier 2015 à 14:47

Sous beaucoup d’OS, tous les ports d’un nombre inférieur à 1024 ne peuvent pas être utilisés par des processus sans avoir les privilèges administrateurs. Néanmoins, on a pas vraiment envie que son app bricolée un lendemain de cuite soit lancée en root, pour que la moindre faille de sécurité donne l’accès total à son système.

Beaucoup de logiciels se lancent en root, et relâchent leurs privilèges a posteriori. C’est ce que faisait Apache a une époque (peut être le fait-il toujours, j’ai pas cheché). Nginx lui, lance un processus racine en root, et spawn des enfants avec un utilisateur normal.

Mais nous, on a pas la foi de se faire chier à faire ça, donc généralement, on met nginx en front et il gère ça pour nous.

Sauf que, parfois, on a pas envie de mettre 40 couches devant notre app. Par exemple, si on utilise crossbar.io (ouai, j’ai encore réussi à le placer \o/), le logiciel est clairement capable d’être en front tout seul.

Bonne nouvelle, sur les Linux modernes, les exécutables peuvent avoir des permissions avancées, comme “pourvoir changer l’horloge système” ou “empêcher la mise en veille”. Ces permissions sont changeables avec l’outil setcap.

Sous Ubuntu, ça s’installe avec :

sudo apt-get install libcap2-bin

Puis on choisit l’exécutable à qui on veut donner nos nouvelles permissions. Dans mon cas, le Python du virtualenv de mon projet :

$ pew workon super_projet
$ which python
/home/sam/.local/share/virtualenvs/super_projet/bin/python

Je check si il a pas déjà des permissions (normalement non) :

$ sudo getcap `which python`

Nada. Good.

Un petit coup de man setcap nous liste les permissions utilisables, et on peut voire que CAP_NET_BIND_SERVICE est la permission qui permet d’autoriser un exécutable à binder n’importe quel port.

On rajoute les permissions :

sudo setcap cap_net_bind_service=+ep `which python`

On check que les permissions ont bien été ajoutées :

$ sudo getcap `which python`
/home/sam/.local/share/virtualenvs/super_projet/bin/python = cap_net_bind_service+eip

On a rajouté avec le + la permission cap_net_bind_service pour les cas e et p qui correspondent aux premières lettres de ces définitions :

Permitted (formerly known as forced):
    These capabilities are automatically permitted to the thread, regardless of the thread's inheritable capabilities. 

Inheritable (formerly known as allowed):
    This set is ANDed with the thread's inheritable set to determine which inheritable capabilities are enabled in the permitted set of the thread after the execve(2). 

Effective:
    This is not a set, but rather just a single bit. If this bit is set, then during an execve(2) all of the new permitted capabilities for the thread are also raised in the effective set. If this bit is not set, then after an execve(2), none of the new permitted capabilities is in the new effective set.

Et je n’ai absolument rien compris à celles-ci, je sais juste que ça marche.

Voilà, maintenant tout ce que vous lancez avec le Python de ce virtualenv peut se binder au port 80.

Si vous n’aimez pas l’idée de donner cette permission à tout un Python, il existe une alternative : rediriger tout ce qui rentre sur le port 80 vers un autre port.

Pour ça on peut utiliser un autre soft :

sudo apt-get install socat

Par exemple, balancer tout le trafic du port 80 vers le port 8080 :

socat tcp-listen:80,fork,reuseaddr tcp:localhost:8080

Et pouf, votre appli qui écoute sur le port 8080 reçoit le trafic du port 80.

C’est plus simple, mais il faut le faire pour chaque port, et s’assurer que la commande est bien lancée au démarrage du serveur.

Twisted et requests 8

jeudi 22 janvier 2015 à 12:13

Utiliser les outils de Twisted de base pour faire les requêtes est assez chiant, et quand on est habitué à requests, c’est le retour au moyen age.

La lib treq tente de corriger ça mais n’utilise pas l’API de requests et ne propose pas certaine de ses fonctionnalités.

Du coup, après l’article d’hier, j’ai regardé le code source de requests-futures pour voir si je pouvais pas faire la même chose pour Twisted.

Et on peut. J’ai fais un petit (bon, ok minuscule) wrapper qui permet de faire ça :

    from requests_twisted import TwistedRequestsSession
    session = TwistedRequestsSession()
    defer = session.get('http://github.com/sametmax/')
    def print_status(response):
        print(response.url, response.status_code)
    defer.addCallback(print_status)

Ça utilise l’objet Session de requests et donc on peut faire session.get|post|touslestrucsderequests et toute l’API est disponible.

Donc si vous en avez besoin :

pip install requests-twisted

Le truc fait 3 lignes et 2 tests unittaires, en fait c’est juste un deferToThreads derrière. C’est certain que c’est moins performant que l’approche de treq qui utilise directement l’Agent non bloquant de Twisted, mais pour la plupart des cas c’est juste plus pratique, plus familier, et surtout, plus facile à maintenir :)

Utiliser requests de manière non bloquante facilement 6

mercredi 21 janvier 2015 à 08:17

En attendant le dossier sur la programmation non bloquante, voici une petite lib qui résout un cas d’école : faire une requête HTTP sans bloquer avec une jolie API, en pur Python.

Pour ça, on dégaine pip et installe requests-futures, un plugin pour la célèbre lib requests qui fonctionne avec Python 2 et 3 :

pip install requests-futures

requests-futures va créer pour vous une pool de workers (2 par défaut) et quand vous faites une requête, la lib vous retourne un objet future qui vous permet d’attacher un callback.

Fiou, le nombre de liens référant à d’autres articles du blog est en train d’exploser.

Exemple :

import time
from requests_futures.sessions import FuturesSession
 
# Cette session est notre point d'entrée, c'est elle
# qui gère nos workers. Faites help(FuturesSession)
# pour voir ses paramètres.
session = FuturesSession()
 
# Les URLs sur lesquelles on va faire
# nos requêtes
URLs = [
    "http://sametmax.com",
    "http://sebsauvage.net",
    "http://indexerror.net",
    "http://afpy.org",
    "http://0bin.net"
]
 
# Notre callback qui sera appelé quand une 
# des requêtes sera terminée. Il reçoit
# l'objet future pour seul paramètre
def faire_un_truc_avec_le_resultat(future):
    # On est juste intéressé par le résutlat, qui
    # est un objet response typique de la lib
    # request
    response = future.result()
    print(response.url, response.status_code)
 
# On traite chaque URL. Comme on a 2 workers,
# on pourra traiter au mieux 2 URLs en parallèle,
# mais toujours sans bloquer le programme
# principal
for url in URLs:
    # On fait notre requête GET
    future = session.get(url)
    # On rajoute le callback à appeler quand
    # le résultat de la requête arrive.
    # La flemme de faire la gestion des erreurs.
    future.add_done_callback(faire_un_truc_avec_le_resultat)
 
# Juste pour montrer que c'est bien non bloquant
for x in range(10):
    print(x)
    time.sleep(1)

Output :

0
1
(u'http://sebsauvage.net/', 200)
(u'http://sametmax.com/', 200)
2
(u'http://indexerror.net/', 200)
(u'http://0bin.net/', 200)
(u'http://www.afpy.org/', 200)
3
4
5
6
7
8
9

On remerciera turgon37 pour sa question sur IndexError qui m’a amené à écrire cet article.