https://si3t.ch/log/journal de prxprxprx@si3t.ch2024-03-26T14:07:09ZMon fils m'a envoyé un courrierhttps://si3t.ch/log/2024-03-24-mon-fils-m-a-envoye-un-courrier.txt2024-03-24T15:11:31Z mailto:bla@bla.si3t.ch?subject=mon-fils-m-a-envoye-un-courrier
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> /log/_commentaires_.txt
]]>
sloweb partie 3 : lecturehttps://si3t.ch/log/2024-03-21-sloweb-part-3-whatsinthebox.txt2024-03-21T12:32:06Z "
read ans
case "${ans}" in
k|K)
printf "Keep ${f}\n"
;;
e|E)
exit
;;
*)
#d|D|n|N)
printf "Delete ${f}, next!\n"
rm -f "${f}"
rm -rf "${f}-data"
;;
esac
done
IFS=$OLDIFS
```
On voit qu'il appelle "SLOWEB_OPENER" pour ouvrir un fichier.
Par défaut, il s'agit d'olab, un autre script à modifier qui effectue une action selon l'extension du fichier. Par défaut, il appelle xdg-open:
```
#!/bin/sh
# olab : open like a boss
# Usage:
# ./olab.sh /path/to/file
# get extension + lower extension
ext="$(echo .${1#*.} | tr '[:upper:]' '[:lower:]')"
case "${ext}" in
*.htm|*.html|*.xhtml)
#fmt="w3m %s"
fmt="surf %s"
;;
*.pdf|*.xps|*.cbz|*.epub)
fmt="mupdf %s" ;;
*.jpg|*.jpeg|*.png|*.gif|*.tiff|*.svg)
fmt="nsxiv %s" ;;
*.odt|*.odt|*.ods|*.od*|*.docx|*.doc|*.xls|*.xlsx|*.ppt*)
fmt="libreoffice %s" ;;
*.mp4|*.avi|*.mpg|*.ogv|*.webm|*.mkv)
fmt="mpv %s" ;;
*.ogg|*.flac|*.wav|*.mp3|*.opus)
fmt="mpv %s" ;;
*.[1-9])
fmt="man -l %s" ;;
*.c|*.h|*.sh|*.lua|*.py|*.ml|*[Mm]akefile|*.md|*.tex)
fmt="st -e $EDITOR %s" ;;
*.txt|*.gmi|*.gemtext)
which bat && fmt="bat %s" || fmt="less %s" ;;
*)
fmt="xdg-open %s" ;;
esac
printf "$fmt" "\"$1\"" | ${SHELL:-"/bin/sh"}
exit
```
En passant, on remarquera que pour les fichiers gmi, la coloration est obtenue avec "bat" s'il est présent.
À l'usage, je me dis qu'utiliser un navigateur de fichier comme noice serait tout aussi pratique, mais retire la possibilité de supprimer par défaut.
=> https://git.2f30.org/noice/log.html
---
Une réaction?
Envoyez votre commentaire par mail (votre adresse mail sera retirée des entêtes cachée):
=> mailto:bla@bla.si3t.ch?subject=sloweb-part-3-whatsinthebox
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> /log/_commentaires_.txt
]]>
sloweb partie 2 : les fluxhttps://si3t.ch/log/2024-03-14-sloweb-part-2-feeds.txt2024-03-14T12:29:58Z https://github.com/rss2email/rss2email
Cependant, je lui ai trouvé 2 défauts:
* La gestion des abonnements est un peu pénible, surtout si je charge mon serveur de faire tourner rss2email.
* Les articles étant des mails, je suis trop tenté d'ouvrir mon application de messagerie pour vérifier s'il y a de nouveaux articles. C'est de ma faute, mais je retombe dans les travers du "plus, encore, maintenant!".
À la place, je lui préfère sfeed et son interface éventuelle qui rappelle newsboat:
=> https://codemadness.org/sfeed.html
=> https://codemadness.org/sfeed_curses-ui.html
sfeed est justement très modulaire, et s'entoure de plusieurs petits outils faciles à articuler entre eux. On peut d'ailleurs très bien faire de sfeed un équivalent de rss2email si on le souhaite, tout est expliqué dans le readme.
Sur mon ordinateur, sfeed m'apporte les avantages suivants :
* Récupération des flux avec curl, ou une autre commande. Ça supporte ainsi aussi le protocole gopher, donc les phlogs. Il ne devrait pas être trop difficile d'y ajouter les gemlogs, mais j'ai écrit un script dédié pour ça.
* Il garde en mémoire les articles déjà lus dans sfeed-curses. On peu les lire ou ouvrir dans le navigateur. Le lien de l'article est affiché, je peux l'utiliser pour l'envoyer à d'autres outils (voir Exemple).
* Il permet de filtrer les flux et d'effectuer des remplacements du type youtube > invidious, ou encore retirer des liens publicitaires... On peut même choisir de télécharger les vidéos des abonnements youtubes avec yt-dlp.
* La mutliplicité des outils pour lire me plaît : dmenu, mail, texte, ...
Il reste limité à un affichage en mode texte, parfois gênant pour des articles contenant des images (xkcd, APOD) que j'aimerais pouvoir voir même hors-ligne.
Pour cela, le script sloweb_forlater est là.
## Un exemple avec APOD
Si vous ne connaissez pas, sachez que la NASA publie chaque jour une photo d'astronomie avec des commentaires d'astronomes profesionnels.
=> https://apod.nasa.gov/apod/
Ça n'a d'intérêt que si on a l'image sous la main.
Lorsqu'une nouvelle entrée apparaît dans le flux, je passe l'URL à forlater:
```
forlater https://apod.nasa.gov/apod/ap240314.html
```
Ce script est très court.
Il va faire en sorte que la commande sloweb_forlater soit exécutée la prochaine fois que sloweb tourne, avec l'aide de sloweb_cmd déjà présenté dans l'article précédent.
```
sloweb_cmd "cd \"${SLOWEB_BOX}\"; sloweb_forlater \"$1\""
```
La commande sloweb_forlater sera alors exécutée dans le dossier ~/sloweb/box pour enregistrer la page apod ainsi que l'image.
## sloweb_forlater
sloweb_forlater est un des outils dont je suis le plus content car il permet d'avoir une version locale d'une page web/gemini/gopher.
Dans le cas d'une page web, je sais que wget sait déjà aspirer un site. Cependant, les liens vers le ressources ne sont pas réécris.
Autement dit, si la page appelle un script vers googleapis, ou encore si elle demande le chargement d'une image avec un lien du type "https://bla/blop/blup.jpg", alors impossible de charger l'image si on est hors-ligne.
sloweb_forlater se charge donc de réécrire les liens vers les images. Ces liens sont des liens locaux du type "./chemin_vers_limage.jpg".
Pour télécharger les ressources, je vais appel à "sloweb_anyget", qui n'est qu'un "wrapper" afin d'appeler la bonne commande de téléchargement selon si le protocole esthttp, gopher ou gemini. À la même occasion, si le lien est une vidéo youtube, alors yt-dlp va la télécharger.
Ainsi, je peux lire les pages et médias gardés dans la "box" sans avoir besoin d'un accès à internet. Cela fera appel au script sloweb_whatsinthebox, mais c'est pour un futur article ;)
---
Une réaction?
Envoyez votre commentaire par mail (votre adresse mail sera retirée des entêtes cachée):
=> mailto:bla@bla.si3t.ch?subject=sloweb-part-2-feeds
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> /log/_commentaires_.txt
]]>
sloweb partie 1 : run_cmdshttps://si3t.ch/log/2024-03-13-sloweb-part-1-run-cmds.txt2024-03-13T13:42:23Z https://git.sr.ht/~prx/sloweb
## sloweb_online
Tout d'abord, sloweb vérifie que l'on a bien un accès en ligne, et appelle pour cela le script sloweb_online. Si tout va bien, ce dernier retourne 0, sinon il retourne une erreur.
On peut lire au tout début de ce script quelques lignes communes à tous les scripts sloweb_*. Cela concerne la configuration :
```
# configuration
# if SLOWEB_DIR not set as ENV VARS, set default
test -z "${SLOWEB_DIR}" && SLOWEB_DIR=~/sloweb
config="${SLOWEB_DIR}/slowebrc"
if [ ! -f "${config}" ]; then
printf "%s" "Configuration not found, copy slowebrc.example to ${config}"
exit 1
fi
# import config
. "${config}"
```
On peut voir qu'à moins qu'une variable d'environnement soit déjà définie, on va aller chercher le fichier ~/sloweb/slowebrc comme configuration.
Utiliser une variable d'environnement facilite la possibilité de changer la structure des répertoires utilisés par sloweb sans se prendre la tête. Dans le fichier ~/.profile, on pourra écrire:
```
export SLOWEB_DIR=/var/sloweb/or/else
```
On retiendra donc que par défaut, la configuration de sloweb a lieu dans ~/sloweb/slowebrc. Un exemple est fourni, il est commenté pour expliquer à quoi servent chaque partie.
On trouve notamment dans ce fichier la partie relative à sloweb_online:
```
# sloweb_online
# connectivity check, multiple domains in case one of them is down
SLOWEB_ONLINE_DOMAINS="openbsd.org wikipedia.org www.nasa.gov"
SLOWEB_ONLINE_PORT=443
```
Voici une liste de domaines qu'on va chercher à atteindre via le port 443.
Si le premier échoue, alors on essaie le suivant : après tout, un site peut bien être en panne alors que vous êtes pourtant connecté.
Dès qu'un accès a réussi, alors sloweb_s'arrête et retourne 0.
Ça tient finalement en quelques lignes:
```
# check if currently connected
connected=0
for d in ${SLOWEB_ONLINE_DOMAINS}; do
# uncomment to use ping instead of netcat
# ping -c1 -w2 "$d" >/dev/null 2>&1
nc -zw1 "${d}" $SLOWEB_ONLINE_PORT >/dev/null 2>&1
if [ $? -eq 0 ]; then
connected=1
break
fi
done
if [ $connected -eq 0 ]; then
_err "It seems you cannot reach the Internet"
exit 1
fi
exit 0
```
Vous aurez noté l'utilisation de netcat. Il est présent par défaut sous OpenBSD.
Certains préféreront décommenter l'appel à "ping" à la place. J'ai cependant lu à ce propos que certains fournisseurs bloquent le ping, pas tant le serveur que le point d'accès : pensez WiFi public, ce qui donnerait l'impression d'être hors ligne, alors que le port 443 protocole TCP utilisé pour les "accès https" est bien ouvert. J'avoue, je n'ai pas trop d'avis là-dessus, je n'ai jamais été confronté à ça.
Pour finir, vous aurez remarqué la fonction "_err", qu'on retrouvera dans d'autres scripts.
J'aurais pu l'écrire dans le fichier de configuration, mais je craignais de rentre les choses trop confuses en mélangeant fonctions et configuration.
## sloweb_run_cmds
le script sloweb_run_cmds va exécuter toutes les commandes présentes dans des fichiers, eux-même stockés dans le dossier SLOWEB_CMDS (~/sloweb/cmds par défaut).
```
find "${SLOWEB_CMDS}" -type f | while read -r cmd; do
${SHELL:-"/bin/sh"} -e "${cmd}"
if [ $? -ne 0 ]; then
_err "'$(cat ${cmd})' in ${cmd} failed"
else
_log "'$(cat ${cmd})' successfully executed"
rm -f "${cmd}"
fi
done
```
"find" permet de lister tous les fichiers du dossier cité ci-dessus puis d'en exécuter le contenu comme un script. On passe ce fichier au shell par défaut et on informe l'utilisateur si tout s'est bien déroulé. Dans ce cas, on supprime le fichier.
On laisse le fichier présent pour que l'utilisateur puisse éventuellement corriger la commande.
On pourrait laisser l'utilisateur créer des fichiers dans ce dossier, mais autant l'aider avec un script qui va créer des fichiers uniques pour les commandes qu'il voudra exécuter lors de son retour en ligne. C'est ce que fait sloweb_cmd.
## sloweb_cmd
Ce script se charge de créer un fichier dont le nom est unique pour ne pas écraser un éventuel fichie déjà existant. Pour cela, la commande "mktemp" est parfaite.
```
# use mktemp for unique file, and a timestamp to keep order
cmd_file=$(mktemp "${SLOWEB_DIR}/cmds/$(date +%s).XXXXXXXX")
printf "%s\n" "$*" >> "${cmd_file}"
```
Le "printf" permet de conserver tous les caractères qui seraient sinon interprétés.
## Le mot de la fin
J'ai commencé par une partie un peu technique de sloweb.
Le prochain coup, je présenterai la partie sur les abonnements aux flux RSS/ATOM, qui utilise des outils déjà existants.
---
Une réaction?
Envoyez votre commentaire par mail (votre adresse mail sera retirée des entêtes cachée):
=> mailto:bla@bla.si3t.ch?subject=sloweb-part-1-run-cmds
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> /log/_commentaires_.txt
]]>
sloweb -- Le web sans s'essoufflerhttps://si3t.ch/log/2024-03-12-sloweb-le-web-sans-s-essoufler.txt2024-03-12T20:47:27Z gemini://ploum.net/3-janvier-2022-quest-ce-quune-deconnexion/
=> https://ploum.net/3-janvier-2022-quest-ce-quune-deconnexion/index.html
J'ai suivi son exemple et écrit un "do-the-internet.sh" à ma sauce.
Le résultat, c'est "sloweb" : on prend le temps de respirer, on y va doucement.
Avant qu'il ne m'écrive agacé par mes divagations, notez que la plupart des choses que fait sloweb se retrouvent aussi dans offpunk de ploum:
=> https://sr.ht/~lioploum/offpunk/
Cependant, j'avais besoin de m'approprier la démarche, de me faire mon petit outil afin de bien cerner mes besoins, mais aussi mes défauts dans mon utilisation d'internet.
Voilà quelques semaines que je l'utilise, je peux désormais détailler ses différents aspects dans une série de petits articles. En effet, sloweb ne se limite pas à la navigation, mais va intervenir dans de nombreux aspects de mes accès en ligne.
Pour les plus pressés et plus curieux, voici le code source :
sloweb: tools to stay offline/offtime
=> https://sr.ht/~prx/sloweb/
## À l'allumage de mon ordinateur
Lorsque ma session s'ouvre, sloweb se charge de :
* Récupérer les nouveaux articles des flux RSS/ATOM auxquels je suis abonnés.
* Télécharger les nouveaux articles des capsules gemini (gemlogs) suivis.
* Télécharger mes mails
* Vérifier et récupérer les changements éventuels de sites qui n'auraient pas de flux.
* Enregistrer dans un fichier ma timeline mastodon.
* Afficher le nombre de nouveaux mails et la météo à venir.
## Lorsque je ferme ma session/éteins mon ordinateur
Dans ce cas, sloweb se charge "d'envoyer" mon activité en ligne, c'est à dire:
* Envoyer les mails rédigés, en attente
* Exécuter une liste de commandes. Ces derniers peuvent être l'envoi de status mastodon, des réponses à des posts, booster un message, télécharger une page web et les médias associés pour lecture ultérieure, ...
* Sauvegarder mes documents
* Uploader mon site web/capsule/gopherhole
## Entre les deux
sloweb me permet de garder en stock les commandes qui seraient à exécuter lors de mon retour en ligne.
Quelques scripts sont alors utile pour prévoir le téléchargement d'une vidéo youtube ou bien une page web avec ses images.
D'autres se chargent de garder les toots/twtxt à envoyer.
Enfin, un autre script me permet de lire les documents gardés dans la bibliothèque. Tous les trucs "à lire + tard" : flux rss, vidéos récupérés, ...
## Pour finir
J'ai pour l'instant l'impression que ça fonctionne.
Je prends plus le temps de lire, je découvre de nouvelles choses.
Je redécouvre aussi les petits bonheurs simples : discuter avec mon entourage, profiter du spectacle à ma fenêtre, ou simplement m'asseoir et profiter du temps qui coule.
---
Une réaction?
Envoyez votre commentaire par mail (votre adresse mail sera retirée des entêtes cachée):
=> mailto:bla@bla.si3t.ch?subject=sloweb-le-web-sans-s-essoufler
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> /log/_commentaires_.txt
]]>
Moi, je pollue. Et toi? Autocollants...https://si3t.ch/log/2024-03-06-moi-je-pollue.txt2024-03-06T15:53:58Z https://si3t.ch/pub/img/ecolo/suv.svg
=> http://si3t.ch/pub/img/ecolo/suv.svg
=> gemini://si3t.ch/pub/img/ecolo/suv.svg
=> gopher://si3t.ch/9/pub/img/ecolo/suv.svg
Et juste comme ça, je me demandais, de façon tout à fait hypothétique, où faire imprimer des stickers en grande quantité?
Si vous avez envie de jouer vous aussi avec inkscape, ou des réponses à ces interrogations conditionnelles, vous savez où me trouver ;)
---
Une réaction?
Envoyez votre commentaire par mail (votre adresse mail sera retirée des entêtes cachée):
=> mailto:bla@bla.si3t.ch?subject=moi-je-pollue
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> /log/_commentaires_.txt
]]>
Comment j'ai perdu un amihttps://si3t.ch/log/2024-03-06-comment-j-ai-perdu-un-ami.txt2024-03-06T09:43:22Z book-folded.txt
```
J'envoie maintenant les lignes une à unes:
```
#!/bin/sh -e
book=~/book/book-folded.txt
tel="+33xxxxxxxxx"
# warning : lines must be 70 char max long
while [ $(awk 'END {print NR}' $book) -ne 0 ]; do
# get the line and replace quotes with apostrophes
l="$(sed -n '1p' $book | sed -e 's/\x27/’/g')"
# wait as many seconds as there are chars / 4
n=$(($(printf "%s" "${l}" | awk '{print length($0)}') / 4))
# send sms
printf "%s [%s]\n" "$l" "$n"
adb shell service call isms 5 i32 1 s16 "com.android.mms.service" s16 "null" s16 "$tel" s16 "null" s16 "'${l}'" s16 "null" s16 "null" i32 1 i32 0
# delete line
sed -i '1d' $book
sleep $n
done
```
En supprimant les lignes au fur et à mesure, on peut arrêter et reprendre quand on veut.
Il y a des limites contre les spams, et c'est très bien comme ça. Il vaut donc mieux garder le délai entre chaque message. J'ai dans le script considéré qu'il faut 0.25s pour écrire un caractère.
Ne faîtes pas ça chez vous :)
---
Une réaction?
Envoyez votre commentaire par mail (votre adresse mail sera retirée des entêtes cachée):
=> mailto:bla@bla.si3t.ch?subject=comment-j-ai-perdu-un-ami
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> /log/_commentaires_.txt
]]>
Dune partie 2, le garçon pas content qui voulait se vengerhttps://si3t.ch/log/2024-03-01-dune-partie-2.txt2024-03-01T09:06:46Z Aucun titre pour moi, dit Chani. Rien. Je vous en supplie.
Paul rencontra son regard et il la revit soudain avec le petit Leto dans ses bras, leur fils qui avait trouvé la mort dans toute cette violence.
> Je te jure, dit-il, que tu n'as besoin d'aucun titre. Cette femme, là-bas, sera mon épouse et tu ne seras qu'une concubine parce que ceci est une affaire politique et que nous devons conclure la paix et rallier les Grandes Maisons du Landsraad. Il faut obéir aux usages. Mais cette princesse n'aura de moi que mon nom. Elle n'aura nul enfant, nul geste, nul regard, nul instant de désir.
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=dune-partie-2
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> /log/_commentaires_.txt
]]>
Gemfeeds downloaderhttps://si3t.ch/log/2024-02-28-gemfeeds-downloader.txt2024-02-28T14:15:32Z https://github.com/rss2email/rss2email
=> https://codemadness.org/sfeed.html
However, it doesn't support gemfeeds.
I wasn't happy to open a gemini client to check for new entries.
It felt not natural to me, and even if lagrange or amfora are great to these tasks, I finally never opened them.
But it was disappointing, there are capsules I miss reading.
So, here I am with this piece of awk: gemfeeds.
awk is great to parse text, and gemtext is line-oriented so it's perfect.
There is one part I don't really like: to download over gemini protocol, I use openssl. I miss gemini support in curl, and feel lazy to install one. I should install "gg":
=> https://gmid.omarpolo.com/
For now, I use gemfeeds this way:
```
gemfeeds file-with-list-of-gemfeeds.txt
```
in file-with-list-of-gemfeeds.txt, there is :
```
gemini://ploum.net/
gemini://adele.pollux.casa/gemlog/
...
```
When a new entry is found, it is downloaded in the current directory, and the item url is recorded in "~/.gemfeeds-items.urls".
Feel free to check the code below and suggest improvements ;)
```gemfeeds.awk
#!/usr/bin/awk -f
# gemfeeds : download new items from gemfeeds
#
# 1. read a gemfeed url as input
# 2. download new items
# 3. keep track of old items in ~/.gemfeeds-items.urls
#
# ex: gemfeed list-of-gemfeeds-urls.txt
# require: openssl
BEGIN {
# set defaults
if ( oldurls == "" ) {
oldurls = ENVIRON["HOME"] "/.gemfeeds-items.urls"
}
}
function fetch_gemini_cmd(url) {
# return command to get gemini content
host = ""
split(url, a, "/")
if (a[3] !~ /:[[:digit:]]+/) {
a[3] = sprintf("%s:1965", a[3])
}
host = a[3]
# FIXME : check response code
cmd = sprintf("printf \"%s\\n\" |\
openssl s_client -crlf -quiet -connect \"%s\" 2> /dev/null |\
sed '1d'", url, host)
return cmd
}
function isnew(url) {
# quite slow...
ret = 1
while ((getline o < oldurls) == 1 ) {
if ( o == url ) {
ret = 0
break
}
}
close oldurls
return ret
}
function download_item(url) {
if (isnew(url) == 1) {
printf "new item: %s\n", url
print url >> oldurls
# get filename
n = split(url, a, "/")
filename = sprintf("%s-%s", a[3], a[n])
fetch_cmd = fetch_gemini_cmd(url)
getitem_cmd = sprintf("%s > %s", fetch_cmd, filename)
system(getitem_cmd)
}
}
function gemfeed(url) {
fetch_cmd = fetch_gemini_cmd(url)
while ((fetch_cmd | getline) == 1) {
link = ""
# skip non-links
if ( $1 != "=>" ) { continue }
# skip if date not YYYY-mm-dd,
# gemini://geminiprotocol.net/docs/companion/subscription.gmi
if ( $3 !~ /[0-9]{4}-[0-9]{2}-[0-9]{2}/ ) {
continue
}
# now build an appropriate link
if ( $2 ~ /^gemini:\/\// ) {
link = $2
} else if ( $2 ~ /^\// ) {
# start with /, add domain in link
split(url, a, "/")
link = sprintf("%s//%s%s", a[1], a[3], $2)
} else {
# link relative to current url
# remove page name if any
if ( $2 ~ /\.gmi$/ ) {
sub(/\/[^/]*\.gmi$/, "/", $2)
}
link = sprintf("%s%s", url, $2)
}
download_item(link)
}
close(cmd)
}
/gemini:\/\// {
gemfeed($0)
next
}
{
printf "unhandled protocol, sorry\n"
}
```
(I also added a phlog parser somewhere else, but curl support gopher protocol, and sfeed can parse atom feeds over gopher :))
---
Comments?
Using email (anonymous)
=> mailto:bla@bla.si3t.ch?subject=gemfeeds-downloader
Instructions
=> https://si3t.ch/log/_commentaires_.txt
]]>
J'aimerais plus ou moins que tu ailles te faire cuire le culhttps://si3t.ch/log/2024-02-23-j-aimerais-que-tu-ailles-te-faire-cuire-le-cul.txt2024-02-23T11:07:35Z "Il y a deux mois, jour pour jour, Gabriel Attal, ministre de l’Education nationale annonçait la création de 2137 postes d’enseignants par rapport au budget 2024 prévu pour permettre l’application de ses réformes. Deux mois plus tard il en supprime plus du double."
=> https://www.cafepedagogique.net/2024/02/22/pres-de-11-000-emplois-supprimes-a-leducation-nationale/
Gabriel,
=> /log/img/cuire-le-cul.png J'aimerais plus ou moins que tu ailles te faire cuire le cul.
=> /log/img/peter-dans-les-fleurs.png Va péter dans les fleurs.
L'image vient des Cartes de désaveux. J'adore, allez y jeter un oeil, c'est vraiment drôle et grinçant :
=> https://librairie.lapin.org/fr/strip-club/267-les-cartes-de-desavoeux-9782918653943.html
Parce qu'en attendant, j'ai des élèves qui bossent POUR LES AUTRES, et m'envoient des trucs juste pour aider les petits copains. Le prof a rien demandé, et c'est partagé comme ça en toute simplicité. Voilà qui redonne espoir en l'humanité!
=> /educ/3/atome-feuille-de-route/Carte-mentale-atome-Olivia.pdf
Dans un tout autre registre, je me suis déjà servi de btdigg, très pratique et surtout ne nécessitant pas de tracker. Je découvre aujourd'hui bitmagnet, à auto-héberger.
=> https://bitmagnet.io/
Faut que je teste :)
Ah non en fait, c'est docker :/
Arrêtez de faire des trucs compliqués comme ça!
Allez, un peu de Shaka Ponk pour se redonner des forces et finir la journée:
=> https://invidious.fdn.fr/watch?v=Fw0O_0V6538
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=j-aimerais-que-tu-ailles-te-faire-cuire-le-cul
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Prise de note à l'ouverture de l'ordinateurhttps://si3t.ch/log/2024-02-22-prise-de-note-a-l-ouverture.txt2024-02-22T12:22:56Z
NOTESDIR=~/work/notes/notd
dotd="$(date +%Y-%m-%d)"
f="${NOTESDIR}/${dotd}.txt"
test -d ${NOTESDIR} || mkdir -p ${NOTESDIR}
test -f "${f}" || printf "# %s - Notes du jour\n\n" "${dotd}" > "${f}"
${EDITOR} "${f}"
```
Après quelques tests, les dossiers et fichiers inexistants sont éventuellement créés.
J'utilise la variable d'environnement ${EDITOR} pour ouvrir le fichier, mais en réalité, j'ai remplacé cette ligne par la suivants pour automatiquement : placer le curseur à la fin :
```
#${EDITOR} "${f}"
vi + "${f}"
```
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=prise-de-note-a-l-ouverture
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
sfeed show mastodon toot titlehttps://si3t.ch/log/2024-02-20-sfeed-mastodon-title.txt2024-02-20T14:03:20Z https://codemadness.org/sfeed.html
I also prefer to follow people on mastodon with the associated rss feed, I mean https://instance.tld/@username.rss.
However, this rss feed don't have a title, resulting of the publication date displayed in sfeed_curses.
Even if I can read the toot when pressing enter, I'd like to see a preview of the toot.
sfeed is so good that you can write you own filter() function.
So now, in my sfeedrc, I have:
```
filter() {
case "$1" in
masto*:*)
# don't insert date in title, just first line
awk -F '\t' 'BEGIN { OFS = "\t"; }
{
# turn description into title
$2 = gensub("<[^>]+>", " ", "G", $4)
print $0
}
'
;;
```
It isn't perfect, but give a nice preview:
```
2024-02-19 11:12 I forgot about audacity's fork Tenacity it's still alive! https:// codeber…
2024-02-18 17:04 Interesting project, but a bit weird it's a tool to create interactive documents, i…
2024-02-14 16:39 TIL ecryptfs doesn't support very long file names long as in 148 characters "only"
2024-02-12 19:24 As a former ZNC user, is there an advantage at switching to soju? I don't have any ZNC…
2024-02-11 16:48 If you want to experience # Gentoo Linux for the first time, or if you are bored wit…
2024-02-08 23:50 # OpenBSD may introduces Word into the base system https:// marc.info/?l=openbsd…
```
Of course, I have to name mastodon feeds with "masto:otherthing" like this:
```
feed 'masto:drewdevault@fosstodon.org' 'https://fosstodon.org/@drewdevault.rss'
feed 'masto:fredg@pouet.chapril.org' 'https://pouet.chapril.org/@fredg.rss'
feed 'masto:ploum@mamot.fr' 'https://mamot.fr/@ploum.rss'
feed 'masto:noroanka@im-in.space' 'https://im-in.space/@noroanka.rss'
feed 'masto:solene@bsd.network' 'https://bsd.network/@solene.rss' "" "iso-8859-1"
feed 'mastotag:solarpunk' 'https://im-in.space/tags/solarpunk.rss'
feed 'mastotag:openbsd' 'https://im-in.space/tags/openbsd.rss'
```
You you're interesed, here is the full filter() I use now:
```
filter() {
case "$1" in
masto*:*)
# don't insert date in title, just first line
awk -F '\t' 'BEGIN { OFS = "\t"; }
{
# turn description into title
$2 = gensub("<[^>]+>", "", "G", $4)
print $0
}
'
;;
"xkcd.com")
# do not turn html with w3m/lynx -dump to get img url
awk -F '\t' 'BEGIN { OFS = "\t"; }
{
$5 = "plain";
# extract img url
match($4, "src=\"(.+)");
imglink = substr($4, RSTART,RLENGTH);
split(imglink , a, "\"");
imglink = a[2];
# same with alt
match($4, "alt=\"(.+)");
alt = substr($4, RSTART,RLENGTH);
split(alt , a, "\"");
alt = a[2]
# append img link at the end
$4 = sprintf("%s \\n=> %s", alt, imglink);
print $0
# download the img
#cmd = sprintf("cd /home/prx/lessernet/box/; curl -O -s -L -H 'User-Agent:' '%s'", imglink)
#system(cmd)
}
'
;;
*)
cat
;;
esac | \
# replace privacy invasive services with alternatives
# see https://farside.link/
sed 's@www\.youtube\.com/@invidious.fdn.fr/@g' | \
sed 's@youtu\.be/@invidious.fdn.fr/@g' | \
sed 's@.*twitter\.com/@https://nitter.net/@g' | \
sed 's@.*reddit\.com/@https://i.opnxng.com/@g' | \
sed 's@.*medium\.com/@https://scribe.rip/@g' | \
awk -F '\t' 'BEGIN { OFS = "\t"; }
function filterlink(s) {
# protocol must start with http, https or gopher.
if (match(s, /^(http|https|gopher):\/\//) == 0) {
return "";
}
# shorten feedburner links.
if (match(s, /^(http|https):\/\/[^\/]+\/~r\/.*\/~3\/[^\/]+\//)) {
s = substr($3, RSTART, RLENGTH);
}
# strip tracking parameters
# urchin, facebook, piwik, webtrekk and generic.
gsub(/\?(ad|campaign|fbclid|pk|tm|utm|wt)_([^&]+)/, "?", s);
gsub(/&(ad|campaign|fbclid|pk|tm|utm|wt)_([^&]+)/, "", s);
gsub(/\?&/, "?", s);
gsub(/[\?&]+$/, "", s);
return s
}
{
$3 = filterlink($3); # link
$8 = filterlink($8); # enclosure
# try to remove tracking pixels: tags with 1px width or height.
gsub("]*(width|height)[[:space:]]*=[[:space:]]*[\"'"'"' ]?1[\"'"'"' ]?[^0-9>]+[^>]*>", "", $4);
print $0;
}'
}
```
---
Comments?
Send it by mail (anonymous, add a signature if you want):
=> mailto:bla@bla.si3t.ch?subject=sfeed-mastodon-title
Diff list instructions:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Générateur de mot de passehttps://si3t.ch/log/2024-02-14-generateur-mots-de-passes.txt2024-02-14T15:20:31Z /log/2024-02-07-miroirs.txt
et après avoir réservé un domaine de secours (si3tch.eu), je m'attelle à des outils. J'ai du boulot devant moi :
=> https://lehollandaisvolant.net/tout/tools/
Pour l'instant, je proposais un générateur de mot de passe via gemini, un script crée des chaînes aléatoires ainsi qu'une liste de mots issus d'une page man tirée au sort.
=> gemini://si3t.ch/tools/pw/
J'ai écrit un peu de C pour faire la même chose et respecter le chroot strict d'httpd en compilant avec l'option ''-static''.
S'il y a un bout de code intéressant ici, c'est cette portion :
```
#define ASCII_START 33
#define ASCII_END 126
for (int i = 0; i < wordlen; i++) {
printf("%c",
arc4random_uniform(ASCII_END - ASCII_START) + ASCII_START);
}
```
La fonction arc4random_uniform va retourner n'importe quel nombre dont le maximum est donné en argument. Après avoir regardé "man ascii", j'ai décidé que tous les caractères après l'espace (32) pourraient être affichés.
Si vous voulez tester, ça donne ça:
=> https://si3t.ch/tools/rdmpw
"Mes" outils sont par ici:
=> /tools/
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=generateur-mots-de-passes
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
uptm: just show system uptimehttps://si3t.ch/log/2024-02-10-uptm-only-show-system-uptime.txt2024-02-10T14:32:16Z
#include
#define SECSPERHOUR (60 * 60)
#define SECSPERDAY (24 * 60 * 60)
int
main(void)
{
struct timespec boottime;
time_t uptime, now;
int days, hrs, mins;
time(&now);
/*
* Print how long system has been up.
*/
if (clock_gettime(CLOCK_BOOTTIME, &boottime) != -1) {
uptime = boottime.tv_sec;
if (uptime > 59) {
uptime += 30;
days = uptime / SECSPERDAY;
uptime %= SECSPERDAY;
hrs = uptime / SECSPERHOUR;
uptime %= SECSPERHOUR;
mins = uptime / 60;
if (days > 0)
(void)printf("%d day%s", days,
days > 1 ? "s" : "");
if (hrs > 0 && mins > 0)
(void)printf("%2d:%02d", hrs, mins);
else {
if (hrs > 0)
(void)printf("%d hr%s",
hrs, hrs > 1 ? "s" : "");
if (mins > 0 || (days == 0 && hrs == 0))
(void)printf("%d min%s",
mins, mins != 1 ? "s" : "");
}
} else
printf("%d secs", (int)uptime);
}
return 0;
}
```
---
Comments?
=> mailto:bla@bla.si3t.ch?subject=uptm-only-show-system-uptime
Comments intructions
=> https://si3t.ch/log/_commentaires_.txt
]]>
miroirshttps://si3t.ch/log/2024-02-07-miroirs.txt2024-02-07T21:24:39Z https://srht.site/
J'ai ensuite tenté un accès chez sdf.org.
C'est excellent ce truc, mais pas possible d'utiliser rsync avec mon compte.
De plus, il n'est pas possible d'avoir du https.
Ça fonctionne, je le garde sous le coude, puisque je peux toujours mettre à jour à partir du dépôt git.
=> https://sdf.org
Finalement, j'ai configuré un truc un peu plus propre avec ma VM chez openbsd.amsterdam.
=> https://openbsd.amsterdam/
J'ai édité ma zone DNS pour y ajouter un nouveau champ et j'ai configuré acme-client pour activer le https.
J'uploade les changements via rsync, et je me garde une crontab qui met à jour le dépôt git sous le coude si un jour le rsync m'ennuie.
Cette VM me laisse la possibilité d'activer un jour les protocoles gopher/gemini si j'ai envie.
Finalement, voici les miroirs:
=> https://si3t.ch
=> https://mirror.si3t.ch
=> https://git.sr.ht/~prx/si3t.ch
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=miroirs
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Turn following csv mastodon list to rss for sfeedhttps://si3t.ch/log/2024-01-27-turn-mastodon-followed-to-rss-list-for-sfeed.txt2024-01-27T21:25:17Z https://codemadness.org/sfeed.html
Find below an awk file to convert a following_accounts.csv to sfeedrc format.
Now, in ~/.sfeed/sfeedrc, I have:
```
feeds() {
...
...
. ~/.sfeed/mastodon.txt
```
I filled ~/.sfeed/mastodon.txt with:
```
awk -F, -f mastocsv2sfeed.awk following_accounts.csv > ~/.sfeed/mastodon.txt
```
mastocsvfeed.awk is:
```mastocsvfeed.awk
#!/usr/bin/awk -f
{
account = $1
split($1, a, "@")
username = a[1]
domain = a[2]
printf "feed '%s' 'https://%s/@%s.rss'\n", account, domain, username
}
```
To get your following_accounts.csv, go to your profile export panel.
---
Something to say?
Send it by email:
=> mailto:bla@bla.si3t.ch?subject=turn-mastodon-followed-to-rss-list-for-sfeed
See instructions:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Update zim libraryhttps://si3t.ch/log/2024-01-23-update-zim-library.txt2024-01-23T15:15:42Z https://kiwix.org/en/
It uses dumps writen in zim files.
You can find a lot of them here:
=> https://download.kiwix.org/zim
From wikipedia to gutenberg and even french show "C'est pas sorcier" i used to watch when I was a kid.
Most of the times, zim files are big.
To update them one in a while, i wrote a script: zim-update.sh.
It require curl to download zim files, but you can use wget or another tool if you prefer. I strongly suggest to uncomment parts of the script using aria2 to download zim with bittorrent protocol.
In the end, kiwix-manage add new zim to your library, you can read them in a browser thanks to kiwix-serve.
It looks like this:
=> /log/img/kiwix-serve-shot.png
```zim-update.sh
#!/bin/sh
# update zim files
# see https://wiki.kiwix.org/wiki/Content_in_all_languages
# require kiwix-tools and curl
zim_dir=~/docs/zim
zim_library=~/docs/zim/library.xml
zims="wikipedia_fr_all_nopic wiktionary_fr_all_nopic vikidia_fr_all_maxi lesbelleshistoires_fr"
dlurl="https://download.kiwix.org/zim"
cd "${zim_dir}"
for z in ${zims}; do
# please uncomment to use torrent if you can. Install aria2 to do so
#zimurl="${dlurl}/${z}.zim"
#zimtorrent="${zimurl}.torrent"
#aria2c --seed-time=0 "${zimtorrent}" # disable seed
#rm *.torrent
# direct download
curl -L -O -C - "${zimurl}"
done
# add zims to library
for zim in *.zim; do
kiwix-manage "${zim_library}" add "${zim}"
done
cat << EOF
You can now run
kiwix-serve --library ${zim_library} -p 51318
and open a browser at http://127.0.0.1:51318
EOF
```
---
Comment?
Send it to:
=> mailto:bla@bla.si3t.ch?subject=update-zim-library
Find instructions here:
=> https://si3t.ch/log/_commentaires_.txt
]]>
gghget: téléchargement multi-protocole gemini/gopher/http(s)/...https://si3t.ch/log/2024-01-21-gghget-wget-pour-tous-protocoles.txt2024-01-21T15:52:23Z https://everything.curl.dev/protocols/curl
Restait à trouver comment faire pour gemini.
La commande openssl fait le job, il faut juste virer l'entête avec "sed '1d'" et on est bon :)
Au final, ça donne le script suivant qui permet de préciser si on le souhaite le nom du fichier à écrire.
J'aurais bien laissé vers stdout, mais ça met le bazar quand on récupère des binaires ^^.
```
#!/bin/sh
# gghget : download file grom gemini, gopher or http(s)
# require curl and openssl
usage()
{
printf "usage: %s 'protocol://url/something' '[output_file]'\n" "$0"
exit 1
}
# remove ending "/" if any to get the filename
if [ -z "$2" ]; then
name="$(printf "$1" | awk -F/ '{sub("/+$", "", $0); print $NF}')"
else
name="$2"
fi
case "$1" in
-h|--help|help)
usage
;;
gemini://*)
# set default port if not specified next to domain in url
host="$(printf "$1" | awk -F/ '$3 !~ /:[[:digit:]]+/ {$3=$3 ":1965"} END {print $3; exit}')"
# sed will remove response header
printf "$1\r\n" |\
openssl s_client -crlf -quiet -connect "${host}" 2>/dev/null |\
sed '1d' \
> "${name}"
;;
*://*)
curl \
-L \
-f \
-s \
-m 5 \
-H "User-Agent:" \
--compressed \
"$1" \
> "${name}"
;;
*)
printf "The URL must start with protocol://\n"
;;
esac
```
Voir aussi hurl:
=> https://codemadness.org/hurl.html
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=gghget-wget-pour-tous-protocoles
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Répondre à un toot sans ouvrir son navigateurhttps://si3t.ch/log/2024-01-20-repondre-toot-en-cli.txt2024-01-20T14:49:48Z https://ploum.net/2023-11-25-offpunk2.html
Malheureusement, je n'y arrive pas encore.
Mon travail nécessite que j'ouvre un navigateur qui supporte du javascript pour Pronote.
La vie fait qu'il est souvent indispensable de consulter le site de la banque pour faire les comptes.
Il faut déclarer les salaires de la nounou sur Pajemploi.
Je vérifie le trajet pour la prochaine formation sur openstreetmap.
...
Tout ceci, je pourrai le réserver à une session dédiée pour ces tâches après m'être fait un planning, et éviter de me perdre sur internet.
Pour l'instant, je gagne du temps avec les flux RSS/ATOM.
Ils sont récupérés par sfeed (ou rss2email), ça fait une synchronisation des choses à lire. C'était avant envoyé par mail, mais je tente de réserver la lecture sur mon ordinateur plutôt que d'être tenté d'ouvrir un webmail à chaque instant "libre" de la journée dans une quête futile d'optimisation de la moindre seconde.
=> https://github.com/rss2email/rss2email
=> https://codemadness.org/sfeed-simple-feed-parser.html
Reste un problème : les messages sur mastodon.
Je déteste l'interface de Mastodon, c'est un piège, un distracteur, avec notifications et nouveautés régulières.
Alors, je m'abonne au flux RSS des personnes que je veux lire. Il suffit d'ajouter ".rss" à la fin, par exemple :
=> https://mamot.fr/@ploum.rss
Seulement, je perds la possibilité d'interagir et de commenter les posts.
On en arrive enfin au sujet de ce billet : comment répondre à un toot sans ouvrir le navigateur?
Facile, le lecteur de flux RSS indique l'URL des toots.
J'ai écrit un petit script qui prend en argument l'id du toot auquel on veut répondre. Il s'utilise par exemple ainsi :
```
pwet -r https://im-in.space/@prx/111788504349081874 Réponse au toot
```
Voici la tête du script, qui a seulement besoin de "curl":
```
#!/bin/sh
# toot with curl
# create a new application in your mastodon profile to get a token and write it in ~/.config/mastodon.token
instance="im-in.space"
token="$(cat $HOME/.config/mastodon.token)"
url="https://$instance/api/v1/statuses"
help()
{
printf "usage:\n"
printf "\t%s [-r reply_to ] [-h] Your status\n" "$0"
printf "\n"
printf "\t-h Show this help\n"
printf "\t-r reply_to String. ID or url of the status being replied to.\n"
printf "\n"
printf "example:\n"
printf "\t%s -r https://foo.bar/@username/1104349081874 The reply message\n" "$0"
exit 1
}
while getopts 'hr:' c
do
case $c in
h) help ;;
r) reply_to="${OPTARG}" ;;
esac
done
# skip options in argument index so $1 is the status
shift $((OPTIND - 1))
status="\"$*\""
test -z "$status" && help
if [ -n "${reply_to}" ]; then
# get id if url is given
reply_to_id="$(printf "${reply_to}" | awk -F/ '{print $NF}')"
curl -s "${url}" \
-H "Authorization: Bearer $token" \
-F status="${status}" \
-F in_reply_to_id="${reply_to_id}" > /dev/null
else
curl -s "${url}" \
-H "Authorization: Bearer $token" \
-F status="${status}" > /dev/null
fi
```
Toutes ces réponses prennent la forme de commandes, lignes après lignes, dans un fichier qui est éxécuté comme un script lorsque je veux les envoyer (lorsque je passe en mode "en ligne").
En complément, il me reste à créer une file d'attente des mails à envoyer. Ils sont rédigés hors ligne, et j'envoie quand tout est prêt.
=> https://github.com/Stebalien/msmtp-queue
Ces idées de déconnexion a déjà été bien décrit par ploum:
=> https://ploum.net/3-janvier-2022-quest-ce-quune-deconnexion/index.html
Je n'en suis qu'aux début de l'aventure, mais j'en ai besoin.
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=repondre-toot-en-cli
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Afficher les paroles de la chanson jouée par mpdhttps://si3t.ch/log/2024-01-18-afficher-paroles-mpd.txt2024-01-18T13:47:20ZChoisissez l'apparence du site que vous lisezhttps://si3t.ch/log/2024-01-14-choose-webste-appearance.txt2024-01-14T14:55:26Zmediacenter-sync-at-startuphttps://si3t.ch/log/2023-12-12-mediacenter-sync-at-startup.txt2023-12-12T10:44:44Z https://si3t.ch/log/2023-07-30-light-mediacenter-with-alpine.txt
Désormais, quand j'allume mon mediacenter, il récupère les fichiers que j'ai déposé sur mon serveur.
C'est tout simple, j'ai simplement configuré ssh pour une identification par clé:
=> https://si3t.ch/w/doku.php?id=ah:fr:02-admin#connexion_par_cles_sans_mot_de_passe
Puis j'ai installé rsync.
Dans ~/.profile, il y a désormais :
```
/home/watcher/syncvids.sh
ranger ~/videos
```
Le script syncvid récupère les vidéos et supprime les fichiers d'origine après le transfert.
```
#!/bin/sh
rsync \
-zriv \
--progress \
--remove-source-files \
ledzep:/var/users-backups/watcher/videos/ \
/home/watcher/videos/
```
C'est très pratique, je n'ai plus à transférer manuellement les vidéos : je les dépose tranquilou sur mon serveur, je sais qu'elle seront automatiquement récupérées et effacées le moment venu quand je voudrai les regarder.
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=mediacenter-sync-at-startup
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Youtube moins lenthttps://si3t.ch/log/2023-12-09-youtube-moins-lent.txt2023-12-09T20:16:02Z https://lehollandaisvolant.net/?mode=links&id=20231209142314
Youtube est effectivement pénible, surtout lorsque je dois m'en servir en classe : les élèves ont un lien à aller visiter, un petite capsule vidéo de 5 min, une autre forme de travail documentaire...
La lecture est saccadée, alors que les ordinateurs bien que modestes sont neufs.
Et puis je déteste voir des pubs, dont le contenu peut être discutable, diffusées à mon/leur insu. Point de vue éthique, mes cours en pâtissent et je supporte mal.
Contrairement à Timo, j'utilise d'autres solutions pour visionner les vidéos hébergées sur Youtube, si possible des outils libres, j'ai eu de mauvaises surprises avec des sites d'extractions de vidéos par le passé.
## mpv + yt-dlp
Le lecteur de vidéos ''mpv'' permet de visionner directement la vidéo pour peu qu'on lui donne le lien.
Exemple : ''mpv https://www.youtube.com/watch?v=dQw4w9WgXcQ''
=> https://mpv.io/
Ça télécharge la vidéo avec yt-dlp''.
=> https://github.com/yt-dlp/yt-dlp
C'est cool pour moi, mais pas trop en classe.
## digiview
Je décrapifie les vidéos avec l'outil digiview de ladigitale.dev :
=> https://ladigitale.dev/digiview/#/
C'est tout simple à utiliser, c'est ce que je privilégie avec mes élèves :
=> https://ladigitale.dev/digiview/#/v/6574bf745d52f
## idiotbox
Un peu comme digiview, mais cette fois-ci on peut directement faire une recherche sans passer par youtube:
=> https://codemadness.org/idiotbox/
## invidious
Utiliser une instance invidious rend youtube de nouveau agréable.
=> https://yewtu.be/
Mon seul souci, c'est de savoir si une instance sera toujours là dans 5 ans.
En attendant, des addons Firefox permettent de rediriger vers une instance invidious lorsqu'un lien youtube est visité.
## Et dans 10 ans ?
Dans le doute, et comme pour tout sur internet, si une ressource est intéressante, je la télécharge et fait un snapshot sur archive.org.
Car comme tout le reste, un jour, Youtube va disparaître.
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=youtube-moins-lent
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Update lenovo thinkpad bioshttps://si3t.ch/log/2023-12-07-bios-lenovo-update.txt2023-12-07T12:59:05Z dmesg |grep bios.*version
bios0: vendor LENOVO version "N10ET63W (1.42 )" date 07/29/2021
```
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=bios-lenovo-update
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Silurianhttps://si3t.ch/log/2023-11-25-silurian.txt2023-11-25T13:17:13Z mailto:bla@bla.si3t.ch?subject=silurian
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Un peu de dessert en physique chimiehttps://si3t.ch/log/2023-11-15-un-peu-de-dessert-physique-chimie.txt2023-11-15T21:21:37Z https://si3t.ch/w/lib/exe/fetch.php?media=cours:un-peu-de-dessert.pdf
Pendant 30 minutes, ils ont accès à un ordinateur (si possible...) et peuvent prendre des notes sur le sujet choisi.
Il y en a pour tous les goûts, et si possible :
* ludique
* étonnant
* mixte, dans le sens où on rappelle que les femmes comem les hommes ont leur place dans la recherche scientifique.
Ce dernier point fait écho à une table ronde des Utopiales sur le matrimoine scientifique.
En effet, les jeunes filles ont du mal à se projeter chercheuse, ingénieure, physicienne... Et ce n'est pas étonnant, ces métiers évoquent dans l'imaginaire collectif des vieux barbus, pas de jolies filles aux yeux pétillants d'intelligence.
À nous de changer ces à prioris : en présentant des femmes de science (car il y en a un paquet dont on ne parle pas), en faisant un effort de recherche historique pour rétablir la vérité sur la place des femmes, et écrire des récits (films, livres, séries...) avec des héroïnes intelligentes : de VRAIS personnages féminins.
Pour ma part de petit prof, j'essaie de veiller à proposer :
* Des recherches sur des scientifiques de tous sexes;
* Des recherches avec un nom de métier à l'écriture inclusive (NA!)
* Des vulgarisateurices scientifiques.
J'ai eu droit à des productions d'élèves aussi épatantes qu'émouvantes. Bravo!
> Qu’est-ce que cela fait d’épouser un génie ?
> Allez donc demander à mon mari
(Marie Curie, évidemment).
Je suis ouvert à toutes suggestions pour de nouveaux sujets ou commentaires :)
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=un-peu-de-dessert-physique-chimie
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
txtoverssh.chttps://si3t.ch/log/2023-11-13-txtoverssh.c.txt2023-11-13T08:58:20Z gopher://phlog.z3bra.org/0/ssh-as-a-public-service.txt
En effet, ssh pourrait permettre tant de choses!
J'ai eu envie de faire un système de commentaire, une sorte de grand mur sur lequel chacun pourrait écrire.
Il m'est aussi venu à l'idée un système de publication, mais je ne ferai jamais mieux que prose.sh, ou alors il faudrait que j'y consacre un peu de temps
=> https://prose.sh/
(oui, c'est le genre de trucs dans mes projets)
Puis finalement, pour le fun, j'ai décidé de seulement publier mes articles et à l'avenir quelques textes plus personnels que je souhaite garder un peu plus discrets. Déjà, ça sera pas mal.
Je suis donc parti sur :
* Un chroot ssh
* Un utilisateur dédié et l'instruction ForceCommand pour qu'il ne puisse pas faire n'importe quoi
* Du C pour profiter d'unveil et pledge, et surtout parce que avec le shell on n'est jamais totalement sûr de bien tout sécuriser pour s'assurer qu'un utilisateur ne va pas s'échapper.
Au final, l'outil s'appelle txtoverssh.
## Configuration de SSH
On crée une section rien que pour l'utilisateur "lire"
```/etc/ssh/sshd_config
Match User lire
ChrootDirectory /home/lire
Banner /home/lire/banner.txt
DisableForwarding yes
PubkeyAuthentication no
PasswordAuthentication yes
MaxAuthTries 2
MaxSessions 2
ChannelTimeout session:*=15m
UnusedConnectionTimeout 15m
PermitTTY no
ForceCommand bin/txtoverssh /dossier1 /dossier2
```
* ChrootDirectory précise le dossier dans lequel l'utilisateur est enfermé.
* Banner permet d'afficher le contenu d'un fichier avant l'invite pour le mot de passe. Il faut préciser le chemin entier, pas relatif au chroot.
* DisableForwarding pour plus de tranquilité
* PubkeyAuthentication et PasswordAuthentication c'est pourr forcer la demande d'un mot de passe
* MaxAuthTries et MaxSessions c'est pour plus de tranquilité.
* ChannelTimeout et UnusedConnectionTimeout pour fermer une connexion inactive. Ça ne se comporte pas comme je pense, mais ça fait du nettoyage quand même.
* PermitTTT no évite d'avoir à créer des devices avec mknod ou d'avoir des messages d'erreur dans les logs.
* ForceCommand appelle le fichier bin/txtoverssh qu'il faudra mettre dans le chroot. Il ira chercher des fichiers dans les dossiers appelés "dossier1" et "dossier2". Ces dossiers sont en réalité "/home/lire/dossier1" et "/home/lire/dossier2".
Pour préparer le chroot, il faudra au moins un dossier pour les binaires et pour le device tty:
```
chown root:wheel /home/lire
mkdir -p /home/lire/bin
cp /bin/sh /home/lire/bin/
```
Pour savoir si quelqu'un accède au service de lecture, on peut créer un fichier /etc/ssh/sshrc qui enverra un mail à l'admin.
Je ne l'ai pas mis en place puisque de toute façon, txtoverssh logge dans /var/log/daemon ce qui est lu.
```/etc/ssh/sshrc
#!/bin/sh
if [ "$USER" == "lire" ]; then
echo "User $USER just logged in from $SSH_CONNECTION" |\
mail -s "$USER connected" root
fi
```
## Commentaire du code txtoverssh
Comme indiqué plus haut, txtoverssh est écrit en C.
Je le compile avec le flag "-static" puisqu'il est lancé dans un chroot et que ça me prend la tête de copier au bon endroit les bouts de bibliothèque nécessaires.
On va commencer avec les options. Rien de bien farfelu:
```
/* parse options */
while ((opt = getopt(argc, argv, "re:")) != -1) {
switch (opt) {
case 'r':
recursive = 1;
break;
case 'e':
esnprintf(ext, sizeof(ext), "%s", optarg);
break;
default:
usage();
}
}
```
On peut y voir que txtoverssh va accepter les options "-r" pour scanner récursivement, on change la valeur de la variable recursive le cas échéant, et l'option "-e" pour changer l'extension des fichiers qui seront à proposer à la lecture.
À cette occasion, on appelle la fonction esnprintf, une variante de snprintf que je prévère à strlcpy et strlcat car elle permet de faire la même chose que ces 2 fonctions à elle toute seule tout en vérifiant que la chaîne est correctement terminée.
```
/* build string and end it with \0
* usage : esnprintf(str, sizeof(str), "%s ... %s", arg1, arg2);
*/
size_t
esnprintf(char *str, size_t size, const char *format, ...)
{
va_list ap;
size_t ret = 0;
va_start(ap, format);
ret = vsnprintf(str, size, format, ap);
va_end(ap);
if (ret < 0 || ret >= size)
err(EXIT_FAILURE, "vsnprintf: Output trunkated");
return ret;
}
```
Après avoir vérifié les options, on décale argc et argv pour pouvoir lire la liste des dossiers à scanner dans argv.
Si aucun dossier n'est précisé, on affiche l'aide.
```
argc -= optind;
argv += optind;
if (argc == 0)
usage();
```
Au départ, j'avais tout hardcodé dans un config.h, mais les options, c'est quand même nettement plus pratique.
Juste après, on sécurise le bouzin: pour chaque dossier précisé, on n'autorise que la lecture de fichiers et des opérations stdin/stdio avec pledge:
```
#ifdef __OpenBSD__
for (size_t i=0; iid > id)
id = pp->id;
if ((n = scandir(path, &namelist, NULL, alphasort)) < 0) {
err(EXIT_FAILURE, "Can't scan %s", path);
} else {
for (int j = 0; j < n; j++) {
/* skip self and parent */
if ((strcmp(namelist[j]->d_name, ".") == 0) ||
(strcmp(namelist[j]->d_name, "..") == 0)) {
continue;
}
/* create full path */
esnprintf(fullpath, sizeof(fullpath), "%s/%s",
path, namelist[j]->d_name);
if ((recursive) && (namelist[j]->d_type == DT_DIR)) {
/* list sub directory */
list_entries(fullpath, Pagehead);
} else if (endswith(namelist[j]->d_name, ext)) {
/* create new page entry */
if ((new_page = malloc(sizeof(*new_page))) == NULL)
err(EXIT_FAILURE, "malloc");
/* store page data */
id++;
new_page->id = id;
esnprintf(new_page->filename,
sizeof(new_page->filename),
"%s",
namelist[j]->d_name);
esnprintf(new_page->path,
sizeof(new_page->path),
"%s",
fullpath);
get_title(fullpath,
new_page->title,
sizeof(new_page->title));
SIMPLEQ_INSERT_TAIL(Pagehead, new_page, page);
}
free(namelist[j]);
}
free(namelist);
}
}
```
Pas vraiment de choses intéressantes ici, si ce n'est qu'on fait une récursion sur les dossiers si on a activé l'option récursive.
esnprint permet d'enregistrer simplement le chemin complet vers les fichiers.
Ainsi, ensuite, on peut les enregistrer dans notre liste chainée.
On récupère le titre des pages avec la fonction get_title.
Cette dernière considère que la première ligne du fichier, c'est le titre. On la récupère avec fgets() et on enlève le retour à la ligne final (sauf si le titre est trop long, et dans ce cas tronqué).
```
void
get_title(const char *path, char *title, size_t titlesiz)
{
size_t nread = 0;
FILE *fd = NULL;
if ((fd = fopen(path, "r")) == NULL)
err(EXIT_FAILURE, "can't open: %s", path);
if (fgets(title, titlesiz, fd) == NULL)
err(EXIT_FAILURE, "can't read: %s", path);
title[strcspn(title, "\r\n")] = '\0'; /* remove newline */
```
Ensuite, on va virer les "#" et espaces souvent présents au début de mes lignes de titre avec memmove()
```
/* delete leading "#" if any */
/* while ((title[0] == '#') || (title[0] == ' ')) */
while ((strpbrk(title, "# ") == title))
memmove(title, title+1, strlen(title));
```
J'ai indiqué ici 2 façons de faire la même chose : soit on vérifie que le premier caractère de la chaîne est un "#" ou un " ", soit on appelle strpbrk qui retourne la position du premier caractère trouvé dans la chaîne passée en argument, ici "# ".
Le cas échéant, on décale la chaîne d'un cran vers la gauche.
Après avoir récupéré ces informations, on les affiche à l'écran avec show_page_list:
```
void
show_page_list(struct Page_head *Pageh)
{
struct Page *pp = NULL;
/* display available pages */
SIMPLEQ_FOREACH(pp, Pageh, page)
printf("#%d - %s\n", pp->id, pp->title);
}
```
On va afficher cette liste tant qu'une variable selection est égale à 0 :
```
while (selection == 0) {
show_page_list(&Pageh);
```
On va donc demander à l'utilisateur d'entrer son choix. Pour cela, j'ai un peu cherché.
Au départ, je récupérais du texte, ça permettait de faire un strstr() sur chaque page et afficher les résultats correspondants, un peu à la dmenu.
C'était finalement peu pratique si on voulait juste quitter avec "q" : est-ce quitter ou bien chercher tous les fichiers avec un titre contenant la lettre "q"?
Ensuite, j'ai pensé à récupérer juste l'id du fichier, un nombre, avec scanf. Là encore, mauvaise idée, pas moyen de quitter en entrant une lettre comme "q".
Finalement, un fgets est ce qu'il y a de mieux : on peut récupérer n'importe quel texte.
```
if (fgets(buf, sizeof(buf), stdin) != NULL)
buf[strcspn(buf, "\n")] = '\0';
else
err(EXIT_FAILURE, "can't read input");
```
On vérifie si c'est une demande pour quitter, et on arrête tout si oui :
```
if (strcasecmp(buf, "q") == 0) {
selection = -1; /* != 0 to leave loop */
continue;
```
Sinon, on va transformer l'entrée de l'utilisateur en nombre. Pour ça, strtonum est tout indiqué :
```
selection = (int)strtonum(buf, 1, INT_MAX, NULL);
```
Ici, strtonum tranforme buf en long long. Donc on caste le résultat avec (int).
On accepte les valeurs entre 1 et INT_MAX : le maximum possible pour un int, ça devrait être bien suffisant dans mon cas.
Notez qu'il ne peut pas y avoir de "0".
Si au contraire strtonum retourne 0, c'est qu'il y a eu une erreur de saisie : il faut donc recommencer. Voilà pourquoi je ne récupère pas le message d'erreur et passe à la place NULL à strtonum.
Ensuite, on va chercher le fichier correspondant et l'afficher, sans oublier de remettre selection à 0 pour proposer d'afficher une autre page:
```
SIMPLEQ_FOREACH(pp, &Pageh, page)
if (pp->id == selection) {
syslog(LOG_DAEMON,
"Someone read %s", pp->path);
clear();
puts(PRINT_INSTRUCTIONS);
print_txt_file(pp->path);
}
selection = 0; /* start again */
}
```
Reste à voir la fonction print_txt_file.
Cette dernière va lire le fichier ligne par ligne et l'afficher.
Cependant, pour éviter de remplir l'écran d'un coup et obliger à scroller, on va permettre au lecteur de quitter avec "q" ou bien d'afficher la suite avec Entrée :
```
if ((fd = fopen(path, "r")) == NULL)
err(EXIT_FAILURE, "can't open: %s", path);
while ((c = getc(fd)) != EOF) {
if (c == '\n') {
if (getchar() == 'q')
break;
} else {
putchar(c);
}
}
fclose(fd);
if (ferror(fd))
err(EXIT_FAILURE, "error when reading or closing %s", path);
```
Oui, juste "getc()" sufffit.
## Et pourquoi pas curses.h ?
Ça pourrait être bien en effet.
C'est pour si un jour je faire quelque chose de plus complet avec davantage de services que la lecture. En attendant, la plupart des terminaux permettent de scroller, et sinon, il y a tmux 👼.
## Où sont les sources?
Un petit mail, et hop, je vous les envoie en réponse ;)
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=txtoverssh.c
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Lire dans le si3t.ch en sshhttps://si3t.ch/log/2023-11-09-si3tch-ssh-service.txt2023-11-09T12:43:36Z gopher://phlog.z3bra.org/0/ssh-as-a-public-service.txt
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=si3tch-ssh-service
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Comment écrire correctement du texte brut?https://si3t.ch/log/2023-10-24-plaintext.txt2023-10-24T12:21:23Z
int
main(int argc, char *argv[])
{
return 0;
}
```
## Les listes
Une liste, c'est une série de lignes commençant par "*" :
* item 1
* item 2
* item 3
Une liste numérotée, on ne change pas de symbole. Il suffit d'ajouter le numéro :
* 1 : premier item
* 2 : 2 item
* 3 : et un troisième
## Les liens
Un lien doit être simple à copier/coller : il sera seul sur sa ligne.
Un lien doit être facilement identifiable. On peut si on le souhaite le précéder de "=>" comme en gemtext, ou bien d'un alinéa (tabulation). Je préfère cette dernière solution, car c'est parfois pénible de sélectionner le lien avec "=>" devant.
Un lien doit être décrit : la description sera sur la ligne/paragraphe précédent(e).
Voici un exemple de lien:
https://ceciestunexemple.pwet
## Mises en évidence.
Pour mettre des mots ou du texte en évidence, je pense qu'encadrer du texte avec "**" ou "__" voire "//" rend la lecture plus difficile.
À la place, on peut simplement utiliser des MAJUSCULES.
Ça évite le mélange gras/souligné/italique insupportable et fatiguant. Qu'est-ce qui est important entre les 3 ?
Pour distinguer les niveaux d'importance, c'est à l'auteur de mettre son texte en forme, de créer des paragraphes dédiés, de réfléchir.
## Citations
> Pourquoi pas?
Hors contexte, ça na guère de sens. Il faut préciser l'auteurice par exemple.
## Liberté
Chacun est libre de mettre son texte en forme comme il le souhaite.
Ajouter de l'ascii art.
Écrire des paragraphes longs, des lignes courtes...
Marquer de longues pauses:
Certains clients mails mettent en forme les citations, et aussi les séparations:
---
C'est comme chacun le souhaite.
On peut d'autant plus innover avec l'immense grand nombre de caractères utft8.
## Liens
Pour finir, voici 2 textes qui vont encouragent l'utilisation du texte brut avec des exemples :
Un blog tout en txt:
https://www.curiositry.com/blog.txt
WRITING FOR THE INTERNET ACROSS A HUMAN LIFETIME:
https://web.archive.org/web/20211025182333/https://len.falken.ink/misc/writing-for-the-internet-across-a-human-lifetime.txt
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
mailto:bla@bla.si3t.ch?subject=plaintext
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
https://si3t.ch/log/_commentaires_.txt
]]>
onion for allhttps://si3t.ch/log/2023-10-23-onion-all.txt2023-10-23T15:33:03Z https://si3t.ch/w/doku.php?id=ah:fr:09-services#configurer_un_service_cache_tor
Configurer un onion Tor (gopher)
=> /log/2023-10-11-gopher-onion.txt
Ne manquait plus que la version gemini, que j'avais déjà configurée il y a quelques temps déjà avant de délaisser un peu ce protocole.
Bien qu'il ne soit toujours pas officiel, une discussion avec Solène m'a rappelé pourquoi il reste digne d'intérêt : utf-8 par défaut, liens relatifs, et le gemtext c'est vraiment chouette.
Et puisqu'il ne pourra devenir vraiment répandu que si on l'utilise, je l'ai réactivé et par la même occasion souhaite garder ici quelques notes pour la mise en place d'un onion Tor pour gemini.
Tout d'abord, dans /etc/tor/torrc, on ajoute un service caché.
```
HiddenServiceDir /var/tor/hidden-gemini/
HiddenServicePort 1965 localhost:11966
```
Dans /var/tor/hidden-gemini/hostname, j'ai retrouvé le même .onion que la dernière fois \o/
Vous aurez peut-être noté que tor va écouter sur le port gemini par défaut 1965 et va renvoyer en local sur le port 11966. C'est pour le support des certificats TLS.
En effet, bien qu'un service caché onion soit déjà chiffré, gemini ne fonctionne qu'au travers d'une connexion TLS réussie : sinon, le client renvoie une erreur. Le client peut d'ailleurs par ce biais s'identifier avec une empreinte (pas de mots de passe, c'est plus fort).
Par conséquent, j'ai une nouvelle section dans /etc/relayd.conf pour gérer les accès via Tor sur le port 11966:
```/etc/relayd.conf
ext_ip4 = "192.168.1.5"
ext_ip6 = "2a01:e0a:2b8:ca70::1bad"
prefork 10
log connection
log state changes
tcp protocol "gemini" {
tls keypair si3t.ch-self
}
relay "gemini4" {
listen on $ext_ip4 port 1965 tls
protocol "gemini"
forward to localhost port 11965
}
relay "gemini6" {
listen on $ext_ip6 port 1965 tls
protocol "gemini"
forward to localhost port 11965
}
relay "geminitor" {
listen on localhost port 11966 tls
protocol "gemini"
forward to localhost port 11965
}
```
Les deux premiers relays, c'est comme dans la documentation pour vger:
=> https://tildegit.org/solene/vger
J'ai juste fait en sorte de pouvoir gérer l'ipv6 avec "localhost":
=> https://si3t.ch/w/doku.php?id=ah:fr:09-services#gemini_vger
C'est la dernière section "geminitor" qui est importante ici : elle renvoie les accès en localhost sur le port 11966 vers le port 11965 après avoir introduit le certificat si3t.ch-self.
En effet, et c'est important, l'url en ".onion" doit être indiquée dans le certificat.
Pour cela, il faut générer un certificat avec ssl et indiquer un "subject alt name". D'après ssl(8), il faut utiliser l'option -extfile server.ext.
Pour mon cas, j'ai inscrit dans le fichier server.ext:
```
subjectAltName=DNS:si3t.ch,DNS:b2khgkvb2wn4avjshjp63kknsjwikgwff5dwwydldia6qwf4kdnueyad.onion
```
Et généré le certificat pour 100 ans:
```
openssl genrsa -out /etc/ssl/private/server.key 4096
openssl req -new -key /etc/ssl/private/server.key \
-out /etc/ssl/private/server.csr
openssl x509 -sha256 -req -days 36500 \
-in /etc/ssl/private/server.csr \
-signkey /etc/ssl/private/server.key \
-extfile /etc/ssl/server.ext \
-out /etc/ssl/server.crt
```
Et voilà!
Vous trouverez donc à la racine de mon site un fichier "onions.txt" qui recense les différentes urls permettant de joindre mon serveur.
=> http://si3t.ch/onions.txt
=> https://si3t.ch/onions.txt
=> gopher://si3t.ch/0/onions.txt
=> gemini://si3t.ch/onions.txt
=> http://6gvb6fzoxv72mtlpvr2fgj7ytpeggwuerdawspt24njlkwfxir6jncid.onion
=> gopher://of2w2p5f4hsslk63hmo6tid6r7inhlxuxviq4pb5cxg45enswpbrfjad.onion
=> gemini://b2khgkvb2wn4avjshjp63kknsjwikgwff5dwwydldia6qwf4kdnueyad.onion
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=onion-all
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Nethack -- Épisode 16https://si3t.ch/log/2023-10-21-nethack-16.txt2023-10-21T10:27:09Z Hello prx, welcome to NetHack! You are a lawful male human Monk.
Je recommence en tant que moine. NINJA!
Dans mon inventaire, j'ai un parchemin de détection de nourriture... Ça donnera des indices j'imagine.
Oh, et mon livre de sort c'est pour lancer "protection". Cool, ça compensera le manque d'armure.
Cette fois-ci, je suis accompagné d'un chien. Très vite, ce dernier m'abandonne et file buter des monstres loin de moi... Que c'est pénible de ne pas pouvoir appeler son animal de compagnie :/
Je décide de ne plus perdre mon temps à le retrouver et file vers le prochain escalier. J'écrase un triton sur le et trouve un ouvre-boîte en-dessous :). Une fois près de l'escalier, mon chien réapparaît. Je vais lui donner un petit nom tiens :
> What do you want to call the little dog? Gaby
À peine au niveau 2, j'ai déjà trouvé 3 baguettes magiques. C'est la partie des baguettes!
Et un sifflet aussi, peut-être que ça m'aidera à rappeler Gaby!
Au niveau 4, je retrouve une fourmi, je vais prendre ma revanche cette fois! Sans oublier mon armure magique ;)
Un peu plus loin : un commerce! Chouette, il était temps!
J'y trouve un parchemin à pas cher que j'ai déjà dans mon inventaire : j'espère que c'est bien un parchemin d'identification... Hé ben non, c'est un parchemin de téléportation ^^
J'ai une autre paire de parchemins, au moins cette fois c'est la bonne, je peux identifier des chose :) Ça me permet de revendre un scroll of punishment :)
À peine arrivé au niveau 5, mon chien file se défouler et je trouve juste à côté une pièce pleine de monstres.
> You enter an opulent throne room!
Décidément, j'ai de la chance!
Bon, je tente ma chance hein ! Mon chien est de retour, je lance mon sort de protection, et zou!
Résultat :
> Dlvl:5 $:237 HP:50(50) Pw:33(36) AC:2 Xp:6 Hungry
Bon évidemment, je tombe nez à nez avec un leprechaun à la pièce suivante . GRRR
Et mon chien qui a encore disparu...
Je tente de déposer mon or un peu plus loin pour faire face au leprechaun... Celui-ci me contourne, et vole mon or posé un peu plus loin, je suis ruiné! Un autre est dans ma ligne de mire mais s'échappe rapidement. Décidément, c'est compliqué de faire face à ces lutins.
Un peu plus loin, j'en retrouve un : je l'assaille de ma baguette de "strike" et finit par récupérer 300 pièces. Yay!
Je continue ma recherche et retrouve le 2e. Ce dernier recoit un petit boomegang en pleine face, bien visé mon gars! Il s'enfuit et tombe dans un piège : sprotch, écrabouillé par un boulet!
Niveau 6, j'y découvre de nouveaux monstres : un rat-garou, un homonculus. Changement d'ambiance, ce n'est plus les petits tritons.
Au niveau 7, un singe me vole ma robe! Non mais sans dec'! C'est à poil que je l'écrabouille! Na! Dans ce niveau, ça regorge d'orcs! Yaaa!
Un yéti me met la misère. Je bois toutes mes potions de soin pour l'affronter et descent avec plusieurs sorts mon AC à -2. ouf!
En voulant ouvrir un coffre, j'équipe un sabre qui semble maudit, impossible de le retirer. Je n'ai plus qu'à tester tous mes parchemins encore non identifiés... Il y en a trop de toute façon.
Je découvre ainsi les parchemins de lumière, de magic mapping et au 3e essai d'enchant weapon (ou de remove curse). Cool!
Emballé par ces découvertes, j'en tente un autre : mes potions explosent, mes parchemins brûlent, mon livre de sort brûle, ma robe brule et il me reste 3 points de vie... Woah, c'était chaud!
J'essaie de récupérer mais des monstres ne cessent de réapparaître. Galère. J'ai beau me démener, je finis par succomber aux multibles attaques de poneys (oui...) et d'un jaguar.
----------
/ \
/ REST \
/ IN \
/ PEACE \
/ \
| prx |
| 623 Au |
| killed by a |
| jaguar |
| |
| |
| 2023 |
*| * * * | *
_________)/\\_//(\/(/\)/\//\/|_)_______
Goodbye prx the Monk...
You died in The Dungeons of Doom on dungeon level 6 with 5265 points,
and 623 pieces of gold, after 3987 moves.
You were level 7 with a maximum of 55 hit points when you died.
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=nethack-16
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Nethack -- Épisode 15https://si3t.ch/log/2023-10-20-nethack-15.txt2023-10-20T15:03:32Z Hello prx, welcome to NetHack! You are a neutral male human Monk.
> Be careful! New moon tonight.
Ça commence bien...
Cette fois-ci, je jette un oeil à mon inventaire : j'y découvre un "scroll of punishment", le genre de trucs que je vais revendre au plus vite et que je suis bien content d'avoir identifié.
Le gros boulet que je suis ne savais pas que j'avais un livre de soin, ce qui semble assez logiue pourtant pour un moine. Il y a aussi une lampe à huile tiens :)
Bref, allons-y!
Au niveau 2, je dois sonder pour trouver mon chemin. Je gagne un peu d'expérience au combat, et entend tinter au loin des pièces : un commerce doit être proche. Pas moyens de mettre la main dessus cependant!
Au niveau 3, un corps traîne au sol juste à côté de l'escalier. Muhahaha, je ne m'y ferai pas prendre cette fois : je vérifie si un piège est en-dessous.
> You know of no traps there.
\o/ cool, je vais dessus :
> An arrow shoots out at you! You are almost hit by an arrow.
Bon, je m'y prends mal apparemment :/ Il ne faut pas utiliser "#untrap" mais "s".
Au niveau 4, je découvre un marchand de parchemins et de livres. Au milieu des pages, un mimic me grignote les orteils, mais j'en fait de la patée pour chat! Je découvre ici un parchemin pas trop cher en espérant que ce soit un parchemin d'identification et revent pour 150 pièces d'or mon parchemin de punishment. Yay, bingo! Du coup j'achète tous les autres parchemins d'identification dans la foulée, il me reste même 81 pièces \o/
J'en profite pour identifier un max de trucs dans mon inventaire: j'y avais un anneau de téléportation maudit, j'ai bien fait de ne pas l'enfiler! Il y a aussi une potion maudite de lévitation, le genre de trucs dont on se passerait bien... Enfin, j'identifie un parchemin maudit de magic mapping, le truc qui permet de connaître tout un niveau. Mais... maudit??? Ça change quoi ? J'oublie tout un niveau à la place? Je préfère m'abstenir ^^
Un peu plus loin, au milieu d'un couloir, je tombe nez à nez avec un floating eye. Oh non, pas ça!!! Je tente d'utiliser une baguette magique non identifiée : je n'ai pas mieux, ou alors un parchemin de feu, mais invoquer une grosse explosion au milieu d'un minuscule couloir, bof!
> The floating eye turns transparent!
Je ne sais pas si c'est une bonne idée... Parce que du coup, je ne le vois plus, donc je ne suis plus paralysé en théorie. Mais par contre, il peut me taper à sa guise : je fuis!
Après quelques tours, je me rend invisible et retourne tuer l'oeil... Autant vous dire qu'heureusement, mon chat était là, je me suis quand même trouvé paralysé (le boulet).
Un peu plus loin, un leprechaun me vole tout mon or! NOOON ! Impossible à éviter en plus le bougre! Tant pis, il faudra faire sans...
Un peu plus loi je manque de peu de perdre mon chat, celui-là va un peu n'importe où... Du coup je perds un temps fou à aller le chercher... Je n'ai pas trouvé dans l'aide comment l'appeler.
J'ai l'impression de ne pas trop mal me débrouiller pour l'instant:
> Prx the Novice St:18/04 Dx:13 Co:11 In:10 Wi:14 Ch:9 Neut
> Dlvl:6 $:18 HP:34(34) Pw:30(30) AC:2 Xp:5
Au niveau 7, je croise la route d'un golem doré, il tape fort celui-là !
Je prend la fuite avant de décéder.
Un peu plus loin, je tombe sur un véritable zoo! Tout un tas de créatures, qu'on ne peut malheureusement pas adopter, mais qu'il va falloir dégommer pour récupérer les trésors en-dessous. Ça prend du temps, je préfère jeter des flèches plutôt que me retrouver encercler... Et le golem doré rôde toujours. Centaure, nymphe, nain shaman, orc... Il y a même une licorne XD.
Au final, j'ai récupéré un trésor considérable, plus de 1000 pièces d'or!!! Je file donc dépenser tout ça dans un des précédents commerce.
En chemin, je suis coincé dans une embuscade avec des fourmis qui tapent fort! À croire que l'or les attire oO.
Et bien évidemment, idiot que je suis, enthousiasmé par ce bon début de partie et les poches pleines de pièces, j'en oublie de faire appel à Elbereth ou même de lancer un sort de soin...
----------
/ \
/ REST \
/ IN \
/ PEACE \
/ \
| prx |
| 1301 Au |
| killed by a |
| soldier ant |
| |
| |
| 2023 |
*| * * * | *
_________)/\\_//(\/(/\)/\//\/|_)_______
Goodbye prx the Monk...
You died in The Dungeons of Doom on dungeon level 6 with 3949 points,
and 1301 pieces of gold, after 3564 moves.
You were level 6 with a maximum of 36 hit points when you died.
Être riche, ça peut être dangereux? Moins que d'être étourdi.
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=nethack-15
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Nethack -- Épisode 14https://si3t.ch/log/2023-10-19-nethack-14.txt2023-10-19T21:24:29Z Hello prx, welcome to NetHack! You are a chaotic female human Monk.
Un rôle que je ne connaîs pas du tout, ça fait envie. Je me sens déjà être une sorte de ninja en robe hyper fit et intelligente!
Je trouve rapidement une grande boîte, impossible à ouvrir sans outils pour l'instant.
Être moine c'est trop cool, je dégomme tout ce qui passe sans soucis.
Bon par contre, même en étant chaotique, ça ne semble pas bon pour mon karma de manger des cadavres O:)
Je trouve un petit commerce en passant. Beaucoup de choses à manger, je dois m'en rappeler pour plus tard : boîte à ouvrir, commerce à manger :)
D'ailleurs, dès le niveau 3, un hobbit laisse tomber par inadvertance une dague lorsqu'il décède. Hop, direction le niveau 1 pour ouvrir la boîte :)
J'ytrouve 3 parchemins, un livre et une baguette magique. Pour l'instant, leurs effet est inconnu. Je tente de lire le livre pour voir, il se tranforme en poussière et je me sens menacé... Ça ira comme ça hein ;)
Je retourne dans les mines au lieu du niveau 3 classique pour tester ma baguette : ça tue un gnome direct! oO C'est une baguette de "striking".
Par contre mon petit chien se fait écrabouiller par un rocher dans un piège des mines. Snif!
Je gagne vite de l'expérience dans les mines, trouve des chaussures, de quoi un peu progresser en tant que moine.
Les mines me mettent vite en danger à partir du 2e niveau, je choisis de remonter explorer le donjon sans mourir ^^.
Par contre, la nourriture se fait rare... Je vais vite remonter au niveau 2 acheter à manger à ce rythme. Cependant, un boulet me barre la route puisqu'un montre se trouve derrière :s. Heureusement, la "wand of striking" l'éclate vite fait. Niark! Je remontre acheter quelques fruits, je n'ai pas encore assez d'argent pour des rations complètes.
Au niveau 4, je trouve une nouvelle boîte. Après l'avoir crochetée, je me fais engloutir par des flammes en l'ouvrant : c'était un vilain piège!!! Mes gants brûlent :s.
Quelques pièces plus loin, je tombe nez à nez face à un oeil flottant!!!
Impossible de fuir, je suis paralysé.
Et ce con invoque des trucs qui me frappent en tous sens!!!
Aaargh, ça semblait si bien partiiii!!
----------
/ \
/ REST \
/ IN \
/ PEACE \
/ \
| prx |
| 31 Au |
| killed by a |
| manes |
| |
| |
| 2023 |
*| * * * | *
_________)/\\_//(\/(/\)/\//\/|_)_______
Goodbye prx the Monk...
You died in The Dungeons of Doom on dungeon level 4 with 1262 points,
and 31 pieces of gold, after 2006 moves.
You were level 5 with a maximum of 32 hit points when you died.
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=nethack-14
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Nethack -- Épisode 13https://si3t.ch/log/2023-10-18-nethack-13.txt2023-10-18T15:38:53Z Salutations prx, welcome to NetHack! You are a lawful male human Knight.
Tiens, je suis un chevalier. Ça va changer un peu. Pas trop besoin de réfléchir à priori : on fonce et on tape. :)
Bon, je dois juste me souvenir de ne pas tenter de monter sur mon poney, la dernière fois que j'ai tenté un truc du genre en début de partie, je suis mort en tombant de la selle XD.
À la 3e pièce du donjon, je fonce bêtement dans un piège : je devrais vraiment prendre le temps de regarder ce qui est au sol avant d'y aller. Il y avait au sol un elfe mort avec des flèches, les indices étaient là. Heureusement, pas de mal, et j'ai la chance de trouver une serviette, accessoire indispensable pour nfaire de l'auto-stop intergalactique ;).
Dans la pièce suivante, je tombe sur un gobelin imprudent. Hop, couic! Il y a de la viande au menu:
> Blecch! Rotten food! Everything suddenly goes dark.
DONC, manger de la viande fraîchement hachée, qui est apparemment déjà pourrie, me rend AVEUGLE!
Bien joué mon gars!
Tant pis, pas le choix, il faut continuer. Ça passe vite heureusement.
Pour une fois, le niveau semble bien grand, je trouve un passage tout à l'ouest:
```
----------
------------- |<.......|
----- ###-...........| |........| ------
|...| # |...........| |........-#####.....|
|...| # |...........| -------.--# |....|
|...| # ----------.-- ## # --.---
|...-### ## # ## #
|...| # # # ###
--.-- # # # #
# -.----- ### ## ####
# |.....| # # --------|--
# |...:.-##################################..........|
-@- |.....|#####------- ---.-- ##|.........|
|.%.| |......# #...>...######|....| #|.........|
|.... -------## |.....| #|....| #|.........|
|{..| ####-......## #|....| #..........|
----- |.....| ### #|....| |..%......|
------- ###.....| -----------
#------
Prx the Gallant St:15 Dx:9 Co:10 In:9 Wi:15 Ch:17 Lawful
Dlvl:1 $:10 HP:16(16) Pw:5(5) AC:3 Xp:1
```
Ça sent le piège, mais il y a une tasse avec une fontaine à côté. Dois-je boire l'eau?
Allez, j'y vais!
Tout va bien, comme quoi, nethack n'est pas toujours si méchant :)
Ma route continue, le niveau 2 se passe tout seul, mis à part qu'il y a un coffre et une boîte que je ne peux pas encore ouvrir : il me manque des outils de crochetage. Note à moi-même : revenir ici un peu plus tard.
Il y a d'ailleurs 2 escaliers vers le bas, qui ne mènent pas au même niveau.
Dans l'un des niveaux 3, j'ai bien failli y rester face à une chauve-souris géante. Heureusement mon poney mort fort. Tiens, hop, une carrote non-maudite pour toi!
Ça commence à devenir compliqué de tout porter. Et pas un seul parchemin à l'horizon pour identifier mes potions.
J'ai compris ce que c'était l'autre niveau 3 : c'est les mines.
Mon poney fait des ravages, quand soudain:
> Your saddled pony grows up into a horse.
Alleeeeez, si ça continue comme ça il va évoluer en licorne. Ça serait la classe! (le wiki dit que ça deviendra un cheval de guerre).
En descendant au niveau 4 des mines, je me fais attaquer à coup de carreaux, on me jette une carafe à la tronche, et je suis tellement lent que je peine à me défendre. Je remonte bien vite alors qu'il me reste 5HP, mais il vaut mieux fuir!
En passant, je découvre une amulette que j'essaie:
> It constricts your throat!
Génial, je me fais étrangler... C'est mal barré!
> You find it hard to breathe.
> You're gasping for air. You can no longer breathe.
> You're turning blue.
> You suffocate.
4 tours...
Les colliers, c'est pourri!
```
----------
/ \
/ REST \
/ IN \
/ PEACE \
/ \
| prx |
| 41 Au |
| killed by |
| strangulation |
| |
| |
| 2023 |
*| * * * | *
_________)/\\_//(\/(/\)/\//\/|_)_______
Fare thee well prx the Knight...
You died in The Dungeons of Doom on dungeon level 2 with 575 points,
and 41 pieces of gold, after 2218 moves.
You were level 4 with a maximum of 40 hit points when you died.
```
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=nethack-13
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
mission terroriste réussiehttps://si3t.ch/log/2023-10-16-mission-terroriste-reussie.txt2023-10-16T20:36:33Z C'était un professeur [...] qui pensait que savoir était un grand trésor, que tous les "moins que rien", n'avaient pour s'en sortir, que l’école et le droit qu’a chacun de s’instruire. Il y mettait du temps, du talent et du cœur...
Puis la vie continue. Heureusement, les enfants/élèves sont dépassés par tout ça. On enseigne, et c'est ce qui est le plus important. Mais le Soleil est lent dans le ciel, la bouche a un gout amer.
Tout le monde est déjà passé à autre chose. Dommage colatéral. On a fait rentrer les profs dans les rangs et garder les enfants pour que les ouvriers puissent continuer à faire tourner la fraiseuse au lieu de garder leurs enfants si l'école ferme, le PIB passe d'abord. Rien à faire.
Et les collègues qui intellectualisent le truc en salle de pause... Et gnagnagna l'histoire, et blablabla la Palestine et l'Israël, et vas-y que je te lance des trucs en fait racistes, toi, le collègue si humain que j'estime tant.
Bravo. Mission terroriste réussie.
Les religions sont un poison.
Les territoires sont des illusions.
Pendant ce temps, les collègues du primaire recevaient la consigne de Gabriel Attal, Ministre de l'Éducation Nationale, de préparer des choses pour une commémoration, pendant leur PAUSE DÉJ'! Au lieu d'inventer des problèmes d'Abaya, y avait peut-être mieux à faire...
Fatigue... Colère... Fatigue... Tant de fatigue! Désespoir. Futilité. Vanité!
Ça ne profite à personne. Il y a juste des morts et du temps gaspillé.
À quoi bon?
Et le soir... alors que les enfants sont censés être endormis :
> Mais maman, ça aurait pu être toi?!
Bravo. Mission terroriste réussie.
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=mission-terroriste-reussie
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
teach-even-harderhttps://si3t.ch/log/2023-10-14-teach-even-harder.txt2023-10-14T16:11:03Z You know what, I'm gonna start teaching even harder!
https://si3t.ch/log/img/teach-even-harder.jpg
Quelques heures plus tard, Gabriel Attal, Ministre de l'éducation nationale:
> les cours sont annulés pour les élèves jusqu’à 10 heures.
😫
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=teach-even-harder
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
gopher onion - gopher over TORhttps://si3t.ch/log/2023-10-11-gopher-onion.txt2023-10-11T10:53:48Z gopher://bitreich.org/0/con/2022/rec/big-browser.md
Cependant, même si c'est surtout utile pour consulter des documents et peu pour envoyer des données, la question de l'anonymat se pose puisque tout est transmis en clair.
Solène expliquait comment y ajouter une couche de TLS :
=> https://dataswamp.org/~solene/2019-03-07-gopher-server-tls.html
C'est là qu'intervient TOR, un service caché me paraît encore mieux qu'une couche TLS:
=> gopher://bitreich.org/1/onion
Je vais donc reprendre les grandes lignes de ce qui est décrit dans le lien ci-dessus avec quelques détails mineurs pour OpenBSD.
Tout d'abord, on ajoute un service caché dans la configuration de tor:
```/etc/tor/torrc
SocksPort 0
HiddenServiceDir /var/tor/hidden-gopher/
HiddenServicePort 70 localhost:71
```
De cette façon, tor va renvoyer tout ce qui arrive sur le service caché au port 70 vers le serveur gopher local sur le port 71. Ce qui est génial, c'est que c'est toujours le port 70 qui est exposé, c'est beaucoup + pratique:
```
user -----> .onion port 70 <-----> localhost port 71
```
Ici, j'utilise ''localhost'' plutôt que ''127.0.0.1'' car ça permet de proposer l'IPv6 si dans ''/etc/hosts'' vous avez bien précisé:
```/etc/hosts
127.0.0.1 localhost
::1 localhost
```
On peut relancer tor: ''# rcctl restart tor''.
Dans le fichier ''/var/tor/hidden-gopher/hostname'', vous trouvez votre adresse onion. Ce domaine ne changera pas, même si vous changez d'IP ou de machine.
```
# cat /var/tor/hidden-gopher/hostname
of2w2p5f4hsslk63hmo6tid6r7inhlxuxviq4pb5cxg45enswpbrfjad.onion
```
Reste à lancer le serveur gopher en local sur le port 71. Pour cela, geomyidae propose des options très pratiques.
=> gopher://gopher.r-36.net:70/1/scm/geomyidae/
On va créer le fichier ''/etc/rc.d/geomyidae_tor'' pour recopier le fichier rc d'origine et ajouter les options voulues:
```/etc/rc.d/geomyidae_tor
#!/bin/ksh
daemon="/usr/local/bin/geomyidae"
onion="of2w2p5f4hsslk63hmo6tid6r7inhlxuxviq4pb5cxg45enswpbrfjad.onion"
geomyidae_flags="-c -e -h $onion -b /var/gopher/si3t.ch -p 71 -o 70"
daemon_flags="-l /var/log/geomyidae.log -u _geomyidae -g _geomyidae $geomyidae_flags"
. /etc/rc.d/rc.subr
pexp="${daemon}_tor .*"
rc_cmd $1
```
On y retrouve:
* L'adresse en .onion
* les options à passer à geomyidae. Notamment:
* -h $onion permet d'envoyer au client le bon nom de domaine en onion
* -p 71 indique que le port d'acoute est le 71
* -o 70 indique que le port à diffuser en sortie reste le 70
Ces 3 dernières options sont particulièrement pratiques si vous ne voulez pas avoir à changer tous vos gophermaps et y préciser le domaine en onion à la place de votre domaine d'origine. En effet, geomyidae va remplacer "server" et "port" par les valeurs appropriées dans un fichier index.gph. Cela évite qu'un lien ne pointe vers votre nom de domaine et pas vers le service caché. Par exemple :
```
[1|log|/log|server|port]
[1|si3tch|/w|server|port]
[0|twtxt.txt|/twtxt.txt|server|port]
[0|public bookmarks|/pub/public_bookmarks.txt|server|port]
[0|positive space|/positive_space.txt|server|port]
[1|pub|/pub|server|port]
```
On termine par ''# rcctl enable geomyidae_tor && rcctl start geomyidae_tor'', et vous pourrez consulter le gopherhole via tor:
```
torsocks lynx gopher://of2w2p5f4hsslk63hmo6tid6r7inhlxuxviq4pb5cxg45enswpbrfjad.onion
```
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=gopher-onion
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
À lire + tardhttps://si3t.ch/log/2023-10-10-a-lire-+-tard.txt2023-10-10T20:51:11Z https://forlater.email/
D'autres utilisent shaarli et taggent les liens avec "#toread" ou "#souslecoudé" ^^.
En ce qui me concerne, une certaine personne qui se reconnaîtra vite ici m'a envoyé des articles que j'ai vraiment très envie de lire.
VRAIMENT lire, pas regarder à toute vitesse en 2 minutes entre le grand qui hurle parce qu'il n'arrive pas à terminer son bricolage avec un trait qui n'est pas parfaitement droit et sa petite soeur qui lui chipe ses crayons et en profite pour les mettre dans la bouche tout en criant parce que elle veut elle aussi la même feuille pour dessiner tout en ayant peur du chat qui veut juste des caresses...
Juste, pouvoir lire calmement, car ça semble très intéressant, et ça demande + de 2 minutes de lecture, et être sûr de ne pas l'oublier.
En plus, je suis du genre à être anxieux à l'idée que des textes ou ressources peuvent disparaître entre le moment où je note le lien et celui où je vais effectivement le lire et encore le jour où je vais y faire référence pour un ami ou parce que j'en ai besoin. C'est là qu'intervient archive.org et sa machine à remonter le temps.
Voici donc un petit script nommé ''soulcoud'' (ouais...) qui va récupérer une copie d'un lien avec lynx, 100% plaintext, effectuer une copie chez archive.org et envoyer le tout par mail.
C'est tout nouveau, ça va sans doute être modifié un peu à l'avenir, du coup les conseils sont bienvenus.
Vous remarquerez que l'adresse mail à laquelle l'article doit être envoyé est définie dans une variable d'environnement, ça me paraissait + simple pour l'utiliser via dmenu. De plus, les liens gopher sont supportés, ça ne doit pas être trop dur d'ajouter d'autres protocoles.
Ça s'utilise ainsi :
```
soulcoud https://www.filfre.net/2023/07/going-rogue/ recommended by f6k
```
Bref, voici soulcoud:
```
#!/bin/sh
# soulcoud: save an url on archive.org and send a copy by email to read later
# the email address is read from environment SOULCOUD_MAIL
# Author: prx
# licence: MIT
# Require: curl, lynx or reader
# one may replace mail command with msmtp or else
# improve with wkhtml2pdf or other snapshot tool
usage()
{
printf "usage:\n\t"
printf "%s (-h) \n" "$0"
printf "\t-h : print help\n"
printf "\nexample:\n"
printf "\t%s 'http://who-is-clarkkent.net' Superman id?\n" "$0"
printf "\nThe page is sent to the mail address set in environment variable SOULCOUD_MAIL\n"
exit
}
archive_url()
{
# archive the url and output the page link on archive.org
curl -s "https://web.archive.org/$1" |
sed -n 's/.*href="\([^"]*\).*/\1/p'
}
dump_page()
{
# use reader or lynx to echo page content
#reader "$1"
lynx \
-dump \
-underline_links \
-image_links \
-collapse_br_tags \
-list_inline \
"$1"
}
if [ -z "${SOULCOUD_MAIL}" ]; then
printf "You must set the environment variable SOULCOUD_MAIL\n"
printf "Example: in ~/.profile, enter\n"
printf "\texport SOULCOUD_MAIL=bruce.wayne.corp\n"
exit
fi
while getopts 'h' c
do
case $c in
h) usage ;;
esac
done
shift $((OPTIND - 1))
test $# -lt 1 && usage
url="$(printf "$*" | cut -d' ' -f1)"
title="$(printf "$*" | cut -d' ' -f2-)"
test -z "${title}" && title="${url}"
(
# save the page with lynx
dump_page "${url}"
printf "\n---\n"
printf "url: "${url}"
# then save on archive.org
case "${url}" in
http* )
archived="$(archive_url "${url}")"
if [ $? -eq 0 ]; then
printf "Saved on: https://web.archive.org/%s\n" "${archived}"
fi
;;
esac
) | mail -s "${title}" "${SOULCOUD_MAIL}"
```
Pour l'utiliser, vous devrez avoir installé curl, lynx, et un serveur mail en route ou bien remplacer ''mail'' par ''msmtp'' ou équivalent.
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=a-lire-+-tard
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
fin de gmi.si3t.chhttps://si3t.ch/log/2023-10-09-fin-gmi.si3t.ch.txt2023-10-09T16:44:02Z Configurer un chroot sftp:
https://si3t.ch/w/doku.php?id=ah:fr:02-admin#sftp_dans_un_chroot
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
=> mailto:bla@bla.si3t.ch?subject=fin-gmi.si3t.ch
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Nethack -- Épisode 12https://si3t.ch/log/2023-10-05-nethack-12.txt2023-10-05T21:20:27Z Aloha prx, welcome to NetHack! You are a neutral female human Tourist.
Voilà trop longtemps que je n'ai pas pris le temps de jouer. J'espère ne pas avoir oublié trop de choses.
J'indiquerai ici les éléments importants de l'aventure selon ce que je découvre.
C'est reparti!
Déjà, inventaire de fou : 764 pièces d'or, 3è flèches, plein de trucs à manger, et le reste classique chez le touriste : appareil photo et carte de crédit :D.
Le premier niveau se passe bien. J'avais oublié qu'on est vraiment faible au début. Un rat a failli m'avoir, mais mon appareil photo a fait le reste ;)
Au niveau 2, je découvre un coffre, mais impossible de le forcer sans armes. Plus loin, je récupère une massue (dans un piège...), alors je tente d'ouvrir, mais la massue est maudite :s. Du coup je suis lent, j'ai faim, alors j'ouvre une boîte de conserve, et là, j'éclate de rire :
> Eating french fried food made your fingers very slippery.
Ça ne va pas m'aider à ouvrir cette malle !!!
Je finis par y parvenir et découvre une potion effervescente, une baguette magique, 2 gemmes (il faut décidément que je découvre à quoi servent les gemmes!) et un livre de sorts poussiéreux. Bof, rien d'hyper essentiel pour une touriste.
Cependant, un peu plus loin, un marchand!!! J'ai donc des choses à vendre si besoin de sous.
Ah, je suis content, c'est la première fois que je trouve un marchand si tôt dans le jeu en tant que touriste. D'ailleurs, heureusement que je suis riche, mon chat mange les tripes du magasin :s
J'y trouve une hache, une armure simple, et surtout, un parchemin d'identification qui est bien pratique!! En tout cas, je me ruine avant de descendre au niveau 3. Hâte de me débarasser de cette massue maudite!
Au niveau 4, je découvre une cape elfique. Youpi !
Plus loin, un gnome m'attaque. Je le découpe en petites rondelles alors que mon chat lui griffe les fesses. Cela me laisse affamé, je dévore les morceaux restants :
> Ulch - that meat was tainted! You feel deathly sick.
> (It must have died too long ago to be safe to eat.)
> You die from your illness.
oO
Mais POURQUOI n'ai-je pas bu une de mes super potions de soin???
```
----------
/ \
/ REST \
/ IN \
/ PEACE \
/ \
| prx |
| 122 Au |
| poisoned by a |
| rotted gnome |
| corpse |
| |
| 2023 |
*| * * * | *
_________)/\\_//(\/(/\)/\//\/|_)_______
Aloha prx the Tourist...
You were poisoned in The Dungeons of Doom on dungeon level 4 with 250
points,
and 122 pieces of gold, after 2206 moves.
You were level 2 with a maximum of 16 hit points when you were
poisoned.
```
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
mailto:bla@bla.si3t.ch?subject=nethack-12
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
https://si3t.ch/log/_commentaires_.txt
]]>
Host with OpenBSD: english translation donehttps://si3t.ch/log/2023-10-03-ah-en-finally-done.txt2023-10-03T10:35:42ZÀ quoi peut me servir OpenBSD ? (édition serveur)https://si3t.ch/log/2023-10-02-octopenbsd-server.txt2023-10-02T12:56:36ZÀ quoi peut me servir OpenBSD ? https://si3t.ch/log/2023-10-02-octopenbsd-desktop.txt2023-10-02T12:50:38Z ${LOCKFILE}
set_status
DELAY=".5"
# clock
(while true; do sleep 60; set_status; done) &
# mpd changes
(while true; do mpc -q --wait current >/dev/null 2>&1; set_status; done) &
# global loop
while true; do sleep $DELAY; done
```
, j'envoie les fenêtres sur la sortie du vidéo-projecteur avec un petit raccourci. Sur mon écran à moi, j'affiche dans la sortie qui s'affiche dans mon dos avec ffplay :
```
#!/bin/sh
res="800x600"
ffplay -f x11grab -s $res -framerate 25 -i :0.0+1366,0
```
Je peux voir ma classe tout en écrivant ou en bricolant ce qui est affiché, c'est très pratique.
Avec le gestionnaire de fichiers rover dans tmux, j'ouvre mes documents en quelques frappes.
En cas de doute, j'utilise le script "f" pour chercher un fichier dont je ne me souviens plus l'emplacement :
```
#!/bin/sh
# find and open a file
if [ "$#" == "0" ] ; then
file="$(find . -type f | match)"
else
file="$(find . -name "*${*}*" -type f | match)"
fi
test -f "$file" && opener "$file"
```
Autant dire qu'il y a des scripts partout. match appelle dmenu ou pick, opener ouvre les fichiers selon leur extension...
Avec ce dernier, j'écoute de la musique avec mpd. L'espace disque est limité, je branche donc un SSD externe qui contient mes musiques. Un script se charge de le monter et lancer mpd:
```
#!/bin/sh
slice=$(dmesg | awk '/serial.21090715000000123E9A/ {d=$1} END{print d}')
test $? || exit
if [ -n "$slice" ]; then
doas /sbin/mount "/dev/${slice}i" /home/prx/mpd
#doas /sbin/mount /home/prx/mpd
pgrep -q mpd || mpd
mpc play
echo "ok"
fi
```
Quand un élève a des documents à projeter ou à me donner, il vient avec une clé USB que je monte avec "mnt". Ça évite de monter automatiquement des trucs potentiellement dangereux:
```
#!/bin/sh
# detect recently insterted media
# look for slice
# choose the one to mount.
# mount the partition in $mountdir/sdnm
# where "n" is the disk and "m" the slice
# doas.conf :
#permit nopass :wheel cmd /sbin/mount
#permit nopass :wheel cmd /sbin/disklabel
# change "mountdir" according to your needs
mountdir=$HOME/mnt/
sdn="$(dmesg | grep "sd[0-9] "| tail | \
match -p 'disk ?'|\
awk '{print $1}')"
test -z "${sdn}" && exit 1
slice="$(doas /sbin/disklabel ${sdn} |\
awk '/^ / { gsub("[:,c]","",$1); print $1}' |\
match -p 'slice ?')"
test -z "${slice}" && exit 1
partition="${sdn}${slice}"
mntpt="${mountdir}/${partition}"
mkdir -p "${mntpt}"
if [ "$sdn" != "" ]; then
doas /sbin/mount /dev/"${partition}" ${mntpt}
# xfe ${mntpt}
fi
rover "${mntpt}"
exit $?
```
Avec nvi, je code à l'occasion. Il y a tout sous OpenBSD pour compiler.
À la connexion, calendar m'indique si j'ai des trucs à penser (anniversaires, choses à faire...)
Pour ma ToDo list, j'ai un alias qui ouvre un fichier texte qui suit les idées indiquées là : https://codemadness.org/todo-application.html
Un script rsync sauvegarde périodiquement tous mes documents importants sur mon serveur, ainsi que lorsque j'éteins mon ordi:
```
#!/bin/sh
if [ -n "$TERM" ]; then
prxsync push
else
xterm -e "prxsync push"
fi
shutdown -hp now
```
Pour la connectivité, au travail j'utilise le partage 4G de mon téléphone, à la maison y a le wifi, je n'ai rien à faire depuis que c'est configuré:
```
# cat /etc/hostname.iwm0
up
join kamehameha wpakey ********************
join prxAP wpakey *******************************
join WIFI_PUBLIC -wpa
```
Lorsque je branche un cable ethernet, il devient prioritaire:
```
# cat /etc/hostname.trunk0
trunkproto failover trunkport em0 trunkport iwm0
inet6 autoconf
inet autoconf
```
Et puis au besoin, j'ai wireguard prêt si j'ai besoin de changer d'IP: juste à lancer le script qui va bien 👼.
Firefox, gimp, Libreoffice, LaTeX, rien de très original pour un prof.
C'est mutt qui me permet de répondre aux mails. fdm récupère les messages quand je lui demande, ça m'évite les notifications trop distrayantes. Dedans, je lis mes flux RSS puisque mon serveur fait tourner rss2email.
Alors ok, il y a quelques scripts qui facilitent la vie : charger un bookmark avec dmenu, prendre des notes grâce à dmenu, choisir une musique grâce à dmenu, chercher sur le web grâce à dmenu, chercher des fichiers grâce à dmenu... Rien de propre à OpenBSD à vrai dire.
Si ma batterie est trop faible, alors l'ordinateur se met en veille le temps que j'aille trouver un cable d'alimentation:
```
# rc.conf.local
apmd_flags=-A -z 8
```
D'ailleurs, la batterie ne sera pas chargée au delà des 80% pour éviter son vieillissement prématuré:
```
# /etc/sysctl.conf
hw.battery.chargemode=1
hw.battery.chargestart=75
hw.battery.chargestop=80
```
Unwind, le résolveur DNS local se charge de filtrer les pubs et autres domaines malveillants et allège considérablement mon quotidien.
J'ai un script associé à une combinaison de touches qui me permet d'afficher/cacher une session tmux dédiée. Pratique pour écrire en 2 secondes une petite interro ou les devoirs pour la semaine suivante, lancer un compte à rebours...
Oh, et j'allais oublier. Je joue parfois dessus: nethack, moria, wesnoth, xonotic, terraria, rogue ledacy, ...
## moria
Il y a un autre ordinateur à la maison, un pc fixe que je synchronisais avec mon pc portable avant. Avant, quand je pouvais rester dans 1 pièce sans être interrompu pour bosser ni craindre de réveiller les enfants. Pour l'instant il est au repos, il servira peut-être un jour à nouveau.
Cela dit, ça reviendra, et tout est prêt pour avoir un clone de ce qui est déjà présent sur mon ordinateur portable.
La synchronisation se réalisait avec synthing, puis unison, et finalement des scripts rsync qui déposent ou récupèrent sur mon serveur selon si l'ordinateur est en avance ou en retard. Pour le savoir, un fichier témoin contenant un timestamp de la dernière synchronisation est déposé.
J'ai mis ça en place puisque unison, qui est EXCELLENT, nécessite exactement les même version de chaque côté, ce qui n'était pas le cas entre ma -current et mon serveur en -stable.
Le script en question s'appelle "prxsync", il est appelé en début de session, toutes les heures, puis à l'extinction.
```
#!/bin/sh -e
# sync my data between over my server
#
# ~/.lastsync : date of last sync
# ~/.prxsync.lst : list of files to sync, relative to $HOME. Must containt ~/.lastsync
usage() {
echo "$0 push/pull"; exit 1
}
test $# -eq 1 || usage
# check if network access
nc -zw1 "si3t.ch" 22 > /dev/null 2>&1 || exit 1
DISPLAY=:0 xsetroot -name "prxsync running..."
tosync=$HOME/.prxsync.lst # dirs MUST end with /
exclude=$HOME/.prxsync-exclude.lst
lastsync=.lastsync
localdir=$HOME
remote=ledzep:/var/users-backups/prx
locallastsync=$localdir/$lastsync
# get remote lastsync
remotelasttmp=$(mktemp)
scp $remote/$lastsync $remotelasttmp
remotelast=$(cat $remotelasttmp)
rm $remotelasttmp
# compare remote w local lastsync
locallast=$(cat $locallastsync)
case "$1" in
"push")
if [ $remotelast -gt $locallast ]; then
echo "/!\ Remote newer than local, please check manually"
exit 1
fi
SRC=$localdir
DST=$remote
;;
"pull")
if [ $remotelast -eq $locallast ]; then
echo "Already sync, nothing to do"
exit
elif [ $remotelast -lt $locallast ]; then
echo "/!\ Local newer than remote, you may push"
exit 1
fi
SRC=$remote
DST=$localdir
;;
esac
echo ".:!|-- Start prxsync --|!:."
/usr/local/bin/rsync \
--exclude-from=$exclude \
--delete \
--files-from=$tosync \
--progress \
-zrltpuv $SRC $DST
# keep track of last sync date
date +%s > $locallastsync
reload-dwm-status
```
## Liste de liens
https://si3t.ch/w/doku.php?id=notes:uses
^ Ce que j'utilise
https://si3t.ch/w/doku.php?id=notes:openbsd:postinst
^ Ce que je configure après l'installation d'OpenBSD
https://si3t.ch/w/doku.php?id=evils
^ Listes d'IP à blacklister, générées et préparées sur mon serveur
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
mailto:bla@bla.si3t.ch?subject=octopenbsd-desktop
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
https://si3t.ch/log/_commentaires_.txt
]]>
Préserver sa batterie avec OpenBSD : hw.battery.*https://si3t.ch/log/2023-09-14-preserver-batterie-openbsd.txt2023-09-14T12:31:55Z> /etc/sysctl.conf
hw.battery.chargemode=1
hw.battery.chargestop=80
hw.battery.chargestart=75
EOF
```
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
mailto:bla@bla.si3t.ch?subject=preserver-batterie-openbsd
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
https://si3t.ch/log/_commentaires_.txt
]]>
Display div when link anchor is activehttps://si3t.ch/log/2023-09-05-display-div-when-link-anchor-is-active.txt2023-09-05T13:01:26Z and tag.
However, it can be replaced with a link whose href refer to the id of a container. Then, CSS can make the container visible when targeted.
Example :
```
Click me
Something
```
CSS :
```
#to_show_on_click {visibility:hidden}
#to_show_on_click:target {visibility:visible}
```
]]>
onion-location header dans dokuwikihttps://si3t.ch/log/2023-08-31-onion-location-dokuwiki.txt2023-08-31T13:56:08Z" />
```
Et voilà, tor-browser propose le .onion :)
https://0x0.st/HpaA.png
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
mailto:bla@bla.si3t.ch?subject=onion-location-dokuwiki
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
https://si3t.ch/log/_commentaires_.txt
]]>
Et pendant ce temps...https://si3t.ch/log/2023-08-29-abaya.txt2023-08-29T10:02:18Z G. Attal, oui, c'est toi qu'on regarde pendant ce temps.
(pour les nuls comme moi, l'abaya c'est en gros une robe longue).
Ça demande moins d'effort d'annoncer une possible reprise des cours le 20 août pour les élèves en difficulté et d'allonger leurs journées à 18h. C'est plus facile que de réfléchir à leurs difficultés et les résoudre.
--> Manu 1er, c'est toi qui fait du bruit pendant ce temps.
Tout ce temps perdu.
Ce n'est pas nouveau, et cela fait longtemps que c'est su et démontré : on augmente le PIB, on améliore les conditions de vie, on on réduit la criminalité lorsqu'on investit dans l'éducation. (2/3 des arguments sont de droite dis donc) Sans parler de la liberté de s'épanouir... Je la fais courte.
En bref :
* On réduit les vacances d'été. 2 mois sans cours, c'est beaucoup trop.
* On va en cours le matin seulement. Le début d'aprèm, c'est une activité culturelle, artistique ou sportive. Stop à 15h maxi.
* Classes de 15 à 20 élèves maxi : un vrai suivi et une vraie aide peut alors être proposée.
En effet, ça suppose de faire le choix de prendre soins de nos enfants et de mettre les moyens pour les aider plutôt que favoriser le tourisme ou encore l'entrepreneuriat : moins de touristes l'été, des horaires de travail pour les parents adaptées. C'est sûr que si les gamins finissent à 18h, on peut rester + longtemps devant le tapis roulant...
Capitalisme ou intelligence, il faut choisir.
♪ Ceci était le coup de gueule pré-rentrée offert par votre idéaliste du coin ♫
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
mailto:bla@bla.si3t.ch?subject=abaya
Voici quelques instructions pour utiliser la liste de diffusion et recevoir les réponses à vos messages:
https://si3t.ch/log/_commentaires_.txt
]]>
Super Mario War ou Cat Wars sur retroarchhttps://si3t.ch/log/2023-08-16-super-mario-war-retroarch.txt2023-08-16T12:08:25ZUltra light mediacenter with alpinelinux and ranger in ttyhttps://si3t.ch/log/2023-07-30-light-mediacenter-with-alpine.txt2023-07-30T14:52:18Z https://wiki.alpinelinux.org/wiki/ALSA
Configure mpv:
```
mkdir -p ~/.config/mpv
cat << EOF >> ~/.config/mpv/mpv.conf
alang=en,fr
slang=fr,en
save-position-on-quit=yes
fullscreen=yes
EOF
```
Configure ranger:
```
ranger --copy-config all
```
Enable image preview in .config/ranger/rc.conf:
```
set preview_images true
set colorscheme snow
```
Uncomment video preview in .config/ranger/scope.sh:
```
video/*)
# Thumbnail
ffmpegthumbnailer -i "${FILE_PATH}" -o "${IMAGE_CACHE_PATH}"
exit 1;;
```
Open ranger in the video directory when "watcher" user is logged in:
```
echo "ranger ~/videos" > .profile
```
At boot, log watcher user in automatically. Edit /etc/inittab:
```
tty1::respawn:/bin/login -f watcher
```
Reboot.
Enjoy.
Press power button briefly to turn off.
=> https://alpinelinux.org/
=> https://github.com/ranger/ranger
=> https://mpv.io/
UPDATE:
Set a nice font for subtitles
```
mkdir -p ~/.config/mpv
cat << EOF >> ~/.config/mpv/mpv.conf
alang=en,fr
slang=fr,fre,en
save-position-on-quit=yes
fullscreen=yes
sub-font="Roboto"
sub-auto=fuzzy
EOF
```
```
apk add font-roboto font-terminus font-dejavu font-noto font-noto-cjk font-noto-extra terminus-font
```
Increase console font size:
```
vi /etc/conf.d/consolefont
consolefont="ter-132n.psf.gz"
rc-update add consolefont boot
```
UPDATE 2:
mpv needs some xorg files:
```
setup-xorg-base
```
---
Comment to:
=> mailto:bla@bla.si3t.ch?subject=light-mediacenter-with-alpine
Instructions for comments:
=> https://si3t.ch/log/_commentaires_.txt
]]>
Nouveau mot de passe à chaque démarrage ou périodiquehttps://si3t.ch/log/2023-07-08-new-password-at-each-boot.txt2023-07-08T13:18:57Znono : détecter les tentatives d'intrusion et sévirhttps://si3t.ch/log/2023-06-30-nono.txt2023-06-30T13:40:08Z Réécrire vilain en C
Vilain, c'était un outil en python pour analyser les logs et détecter des tentatives d'intrusion pour bannir les IP correspondantes.
https://framagit.org/prx/vilain
Ça a vieilli, ce n'est pas si bien écrit, et ça intègre un démon alors qu'on doit pouvoir faire mieux avec moins.
Alors, quand j'ai vu l'article de Solène qui présentait une solution similaire mais en awk, j'y ai vu un cadeau :
https://dataswamp.org/~solene/2023-06-22-opensmtpd-block-attempts.html
Mais oui! awk est parfait pour ce genre de tâches!
J'ai eu l'idée d'utiliser ''tail -f'' pour monitorer en continu les logs. En cas de rotation, tail sait se débrouiller, ce qui permet d'avoir un démon à moindre cout :)
Solène m'a donné envie de m'y mettre, et en quelques heures, j'avais un nouvel outil qui faisait comme vilain, mais en mieux, car
en awk.
Ça s'appelle nono, et c'est par ici :
https://si3t.ch/w/doku.php?id=code:nono.awk
Je pourrais y ajouter un démon... Pour l'instant, je le laisse dans tmux pour voir ce que ça donne. Et semble-t-il, ça tourne bien :
```
Jun 30 10:26:55 ledzep nono: 65.49.1.48 is naughty and is now banned because: ssh wrong pw or invalid user
Jun 30 12:47:13 ledzep nono: 178.151.169.14 is naughty and is now banned because: ssh wrong pw or invalid user
Jun 30 13:33:45 ledzep nono: 118.185.157.225 is naughty and is now banned because: ssh wrong pw or invalid user
Jun 30 13:33:57 ledzep nono: 122.0.26.154 is naughty and is now banned because: ssh wrong pw or invalid user
```
Le code se présente ainsi.
On commence par vérifier si l'utilisateur a défini les options, sinon on attribue des valeurs par défaut. La fonction ''usage()'' ne fait qu'afficher l'aide.
```
BEGIN {
if ((ARGV[2] == "-h") || (ARGV[2] == "--help")) {
usage()
}
# check for options or set defaults
if ( ! TRIES ) { TRIES = 5 }
if ( ! BANCMD ) { BANCMD = "pfctl -T add -t bot" }
if ( ! KILLSTATE ) { KILLSTATE = "pfctl -k" }
if ( ! IGNORE ) { IGNORE = "/etc/nono.ignore" }
}
```
Ensuite, on a des blocs correspondant aux lignes des logs pouvant indiquer un défaut. Par exemple, pour les tentatives de connexion ssh:
```
/ sshd.* Failed password | sshd.* Invalid user / {
match($0, "from ([0-9\.:abcdef]*)")
```
Dans l'exemple ci-dessus, on recherche une ip/ipv6 dans la ligne détectée.
Si une ip est obtenue, on appelle la fonction 'ban' qui enregistre dans un tableau si l'ip a déjà été vue. Si cela dépasse le nombre maximum de tentatives, elle est bannie :
```
function ban(seen, ip, reason) {
seen[ip]++
if(seen[ip] >= tries) {
if (isignored(ip) == 0) {
system(sprintf("logger -t \"nono\" \"%s is naughty and is now banned because: %s\"", ip, reason))
system(sprintf("%s %s", BANCMD, ip))
system(sprintf("%s %s", KILLSTATE, ip))
}
seen[ip] = 0 # reset
}
}
```
Un tableau était tout à fait adapté pour ça.
Ici, j'utilise la fonction ''system'' pour appeler une commande qui enregistre l'activité de nono et bannit l'ip. Utiliser xargs comme le fait Solène semble tout aussi intéressant, ici je me suis juste restreint à awk.
On voit qu'avant de bannir l'ip, un appel à ''isignored'' est réalisé pour éviter de s'auto-bannir.
Cette fonction va parcourir les lignes d'un fichier à la recherche de l'ip. Merci ''getline'':
```
function isignored(ip) {
ret = 0
while ((getline current_ip < IGNORE) == 1 ) {
if (ip == current_ip ) {
ret = 1
break
}
}
close(IGNORE)
return ret
}
```
Et voilà, c'est à peu près tout :)
Merci Solène !
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
mailto:bla@bla.si3t.ch?subject=nono
Voici quelques instructions pour utiliser la liste de diffusion et
recevoir les réponses à vos messages:
https://si3t.ch/log/_commentaires_.txt
]]>
Générateur de liste de lecture amélioréhttps://si3t.ch/log/2023-06-19-generateur-de-liste-de-lecture-ameliore.txt2023-06-19T20:41:49Z/%3E/g;
s/\#/%23/g;
s/{/%7B/g;
s/}/%7D/g;
s/|/%7C/g;
s/\\/%5C/g;
s/\^/%5E/g;
s/~/%7E/g;
s/\[/%5B/g;
s/\]/%5D/g;
s/`/%60/g;
s/;/%3B/g;
s/?/%3F/g;
s/:/%3A/g;
s/@/%40/g;
s/:/%3D/g;
s/&/%26/g;
s/\$/%24/g;
'
}
usage()
{
printf "usage:\n\t"
printf "%s (-h) (-u )\n" "$0"
printf "\t-h : print help\n"
printf "\t-u : prepend to path for streaming\n"
printf "\t\t i.e. -u "http://example.com/audio/"\n"
exit
}
while getopts 'hu:' c
do
case $c in
h) usage ;;
u) url="${OPTARG}" ;;
esac
done
printf "#EXTM3U\n\n"
find . -type f \
-name '*.flac' -o \
-name '*.FLAC' -o \
-name '*.mp3' -o \
-name '*.MP3' -o \
-name '*.m4a' -o \
-name '*.M4A' -o \
-name '*.ogg' -o \
-name '*.OGG' -o \
-name '*.opus' -o \
-name '*.OPUS' -o \
-name '*.webm' -o \
-name '*.WEBM' | \
sed 's/^\.\///' |\
while read -r line; do
duration="$(ffprobe -v 0 -show_entries stream=duration "${line}" |\
awk -F '=' '/duration=/ {sub("\\..*", "", $2); printf $2; exit}')"
title="$(ffprobe -v 0 -show_entries 'format_tags=title' "${line}" |\
awk -F '=' '/title=/ {print $2}')"
artist="$(ffprobe -v 0 -show_entries 'format_tags=artist' "${line}" |\
awk -F '=' '/artist=/ {print $2}')"
test -z "${title}" && title="$(basename "${line}")"
printf "#EXTINF:${duration}, %s - %s\n" "${artist}" "${title}"
path="$(printf "%s" "${line}" | urlescape)"
printf "${url}%s\n\n" "${path}"
done
```
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
mailto:bla@bla.si3t.ch?subject=generateur-de-liste-de-lecture-ameliore
Voici quelques instructions pour utiliser la liste de diffusion et
recevoir les réponses à vos messages:
https://si3t.ch/log/_commentaires_.txt
]]>
Diffuser de la musique vraiment facilementhttps://si3t.ch/log/2023-06-18-Diffuser-de-la-musique-vraiment-facilement.txt2023-06-18T14:42:39Z > file.m3u\n", $0
exit 1
}
#https://rosettacode.org/wiki/URL_encoding#AWK
urlencode()
{
awk '
BEGIN {
for (i = 0; i <= 255; i++)
ord[sprintf("%c", i)] = i
}
# Encode string with application/x-www-form-urlencoded escapes.
function escape(str, c, len, res) {
len = length(str)
res = ""
for (i = 1; i <= len; i++) {
c = substr(str, i, 1);
if (c ~ /[-._*0-9A-Za-z]/)
res = res c
else if (c == " ")
res = res "+"
else
res = res "%" sprintf("%02X", ord[c])
}
return res
}
# Escape every line of input.
{ print escape($0) }
'
}
test -d "$1" || usage
find "$1" -type f \
-name '*.flac' -o \
-name '*.FLAC' -o \
-name '*.mp3' -o \
-name '*.MP3' -o \
-name '*.m4a' -o \
-name '*.M4A' -o \
-name '*.ogg' -o \
-name '*.OGG' -o \
-name '*.opus' -o \
-name '*.OPUS' -o \
-name '*.webm' -o \
-name '*.WEBM' |\
cut -c 3- |\
urlencode
```
Reste à créer des fichiers m3u pour chaque dossier. Pour l'instant,
je laisse en aléatoire, et ça me va :)
Petit détail, j'ai légèrement modifié ce script pour intégrer
les identifiants puisque je protège l'accès au dossier contenant les
musiques par mot de passe, histoire de ne pas être accusé de
diffuser du contenu illégalement. J'ai donc ajouté à la fin:
```
cut -c 3- |\
urlencode |\
xargs printf "https://user:password@si3t.ch/dossier-inexistant-de-musique/%s\n"
```
---
Une réaction?
Envoyez votre commentaire par mail (anonyme):
mailto:bla@bla.si3t.ch?subject=Diffuser-de-la-musique-vraiment-facilement
Voici quelques instructions pour utiliser la liste de diffusion et
recevoir les réponses à vos messages:
https://si3t.ch/log/_commentaires_.txt
]]>
si3t.ch avec dokuwikihttps://si3t.ch/log/2023-06-10-si3tch-avec-dokuwiki.txt2023-06-10T13:54:17ZTaBr - un Makefile pour tout installer proprementhttps://si3t.ch/log/2023-05-15-TaBr-part5-tabr-Makefile.txt2023-05-15T15:26:55Z /code/TaBr.tgz Si vous souhaitez vous approprier la suite "TaBr" dont je parle depuis plusieurs articles, vous pouvez en consulter les sources ici. (TaBr.tgz)
Vous y trouverez un fichier README.txt qui explique rapidement les différents composants ainsi que les instructions pour créer les utilisateurs et configurer doas pour bien séparer les privilèges.
Pour le reste, je vous ai préparé un Makefile qui simplifie l'installation et ajuste automatiquement les permissions.
Je voudrais ici mettre en avant la commande "install" qui permet de faire ça beaucoup plus proprement qu'une suite de "cp", "mkdir", "chown" et "chmod".
En gros, un simple "make install" et c'est prêt :)
Tout d'abord, on précise quelques variables. Ce n'est sans doute pas parfait, mais c'est un bon début pour rendre la suite portable si un jour quelqu'un en a l'intention:
```
PREFIX ?=/usr/local
BINDIR ?=${PREFIX}/bin
SBINDIR ?=${PREFIX}/sbin
CGIDIR ?=/var/www/cgi-bin
CHPWREQDIR ?=/var/www/tabr_chpw_requests
```
Je précise ensuite les trucs qui devront être compilés:
```
all: src/tabr_chpw_cgi src/hashmatchstr
```
Reste à préciser les dépendances des fichiers à compier, histoire qu'ils soient recompilés en cas de modification de la configuration:
```
src/chpw_cgi/main.c: src/chpw_cgi/config.h
src/tabr_chpw_cgi: src/chpw_cgi/main.c
${CC} -static -o $@ $?
src/hashmatchstr: src/hashmatchstr.c
${CC} -o $@ $?
```
Avant d'aller plus loin, on précise comment nettoyer les fichiers compilés. C'est surtout utile pour les tests
```
clean:
rm src/tabr_chpw_cgi
rm src/hashmatchstr
```
La suite permet d'installer les fichiers en les rendant éxécutables et en les faisant appartenir à root ou _tabr_admin selon les cas :
```
install: src/tabr_chpw_cgi src/hashmatchstr
install -o root -g daemon -m 0755 src/tabr_chpw_cgi ${CGIDIR}/tabr_chpw.cgi
@# IMPORTANT: chmod 730, www can write but can't read
install -o _tabr_admin -g www -m 0730 -d ${CHPWREQDIR}
install -m 0755 -o root -g bin src/hashmatchstr ${BINDIR}/hashmatchstr
install -m 0755 -o root -g bin src/tabr_adduser.sh ${SBINDIR}/tabr_adduser
install -m 0755 -o root -g bin src/tabr_passwd.sh ${SBINDIR}/tabr_passwd
install -m 0755 -o root -g bin src/tabr_deluser.sh ${SBINDIR}/tabr_deluser
install -m 0644 -o root -g wheel src/tabr.conf /etc/
```
Remarquez la ligne avec "-m 0730" qui permet de restreindre l'accès au dossier qui contiendra les requêtes pour changer de mot de passe.
Enfin, parce que ça me manque dans de nombreux Makefile, je prévois de quoi faire le ménage:
```
uninstall:
rm -rf ${CGIDIR}/tabr_chpw.cgi
rm -f ${BINDIR}/hashmatchstr
rm -f ${BINDIR}/tabr_adduser
rm -f ${BINDIR}/tabr_passwd
rm -f ${BINDIR}/tabr_deluser
@printf "You probably should remove %s and %s too\n"\
"${CHPWREQDIR}" "/etc/tabr.conf"
```
Voilà de quoi me simplifier la vie et proposer des services à ma famille.
Ici, je n'ai présenté que le mail et xmpp, mais il y en a en réalité un peu d'autres de prévus : dokuwiki (grâce à son interface de gestion des utilisateurs en CLI) qui offre un espace de publication ET de stockage. Il faut juste bien ajuster les ACL.
=> /contact/ J'y pense, si ça intéresse quelqu'un, je peux vous proposer une adresse en @si3t.ch, il suffit de me faire signe.
## Une réaction?
=> mailto:bla@bla.si3t.ch?subject=TaBr-Makefile-part5 Envoyez votre commentaire par mail (anonyme).
=> /log/commentaires/ Mode d'emploi de la liste de diffusion pour recevoir les réponses.
]]>
TaBr - tabr_chpw_cgi interface web pour réclamer un autre mot de passehttps://si3t.ch/log/2023-05-15-TaBr-part4-tabr_chpw_cgi.txt2023-05-15T14:10:19Z /img/log/tabr-oubli.png Aperçu de l'interface
Oui, c'est il n'y a pas de paillettes, d'animations ou de boutons de partages vers les réseaux sociaux. Mais c'est accessible et ça fonctionne dans n'importe quel navigateur, même lynx. Moi, je trouve ça beau :P
On remarque 4 champs :
* le nom d'utilisateur, normal
* son code de récupération. Merci le html5 pour proposer un placeholder, bien que ça ne soit pas forcément utile (c'est facile de mettre un exemple à côté du label du champ.
* le nouveau mot de passe demandé (normal).
* un captcha aléatoire.
À propos du html5, je m'en sers pour valider au maximum ce que les utilisateurs proposent (longueur du mot de passe, validité du nom d'utilisateur...). Cependant, il vaut mieux revérifier ensuite, je ne vais pas confiance à tous les navigateurs pour supporter ces éléments correctement.
## Le code
Le code est du C. C'est quelque chose que je maîtrise et qui me permet de profiter sans difficultés des générateurs de nombres aléatoires avec arc4random, de unveil, de pledge...
Puisque c'est un peu long (~246 lignes uniques), je vais me concentrer ici seulement sur les parties "intéressantes".
### config.h
On configure directement en C.
On y trouve des variables, et surtout les templates html. Ces derniers ne sont pas très propres car il y a beaucoup de guillemets échappés, mais ce n'est pas quelque chose qu'on édite souvent.
Par exemple, on y définit le dossier (à l'intérieur du chroot) où seront stockées les demandes de changement de mot de passe:
```
static const char *chpw_requests_dir = "/tabr_chpw_requests";
```
On y voit aussi les différents types de captchas possibles avec les consignes associées:
```
/* captcha config */
enum { DIGIT, LOWER, UPPER, PUNCT };
/* instructions displayed for humans, same order as above! */
static const char *instructions[] = {
"Recopiez uniquement les chiffres",
"Recopiez uniquement les lettres minuscules",
"Recopiez uniquement les lettres majuscules",
"Recopiez uniquement les symboles et ponctuation",
};
```
Au niveau des templates html, je veux être sûr que la page ne soit pas mise en cache (avec un succès limité):
```
"\n"
"\n"
"\n"
```
j'attire votre attention sur la validation des champs.
Un "title" permet de préciser ce qui est attendu à chaque fois.
```
"
\n"
"\n"
"\n"
```
Ici, le "pattern" me permet de reproduite une regex trouvée dans le code de "adduser", en la modifiant un peu au passage. Qui voudrait d'un nom d'utilisateur terminant pas "$"???
J'impose aussi 15 caractères pour le nouveau mot de passe:
```
"
\n"
"
\n"
"\n"
```
Pour le captcha, il y a les "%s" qui me permettront d'y mettre ce que je veux le moment voulu, puisque c'est une énigme aléatoire à chaque fois:
```
"
\n"
"
%s
\n"
"
%s
\n"
"\n"
"
\n"
"
\n"
"\n"
"
\n"
```
Pour finir, il y a les messages d'erreur affichés selon les cas:
j
```
/* error messages */
static const char *errcaptcha = "Mauvaise réponse! 😱";
static const char *errusername = "Mauvais format. Le nom d'utilisateur doit avoir une longueur entre 1 et 31 caractères, ne peut pas commencer par un \"-\" et ne peut contenir que les symboles suivants: \"abcdefghijklmnopqrstuvwxyz0123456789-_.\"";
static const char *errshortpw = "Mot de passe trop court : au moins 15 caractères sont attendus. Une phrase peut fonctionner.";
```
### main.c
C'est ici que le vrai code commence. Mais avant d'aller plus loin, je vais me préparer un petit café à partager avec vous.
> ☕ Slurp!
Je vous avais promis du unveil et du pledge. Rien de plus simple, on n'autorise l'accès que au dossier contenant les requêtes pour pouvoir y créer des fichiers avec unveil, et on promet seulement des entrée/sorties et écritures dans des fichiers avec pledge:
```
#ifdef __OpenBSD__
/*
if (unveil(chpw_requests_dir, "rwc") == -1)
err(1, "unveil");
unveil(NULL, NULL);
if (pledge("stdio cpath wpath", NULL) == -1)
err(1, "pledge");
*/
#endif
```
Avant d'aller plus loin, on va faire patienter un peu celui ou celle qui fait la requête avec un appel à "sleep". Le nombre de secondes d'attente sera aléatoire grâce à arc4random_uniform:
```
sleep(arc4random_uniform(MAXWAIT));
```
On regarde maintenant si on doit traiter une demande. Cette dernière est passée en entrée, donc on lit stdin avec fgets:
```
if (fgets(rawpost, sizeof(rawpost), stdin) == NULL)
if (ferror(stdin))
http400("Request too long ?");
```
On note au passage la fonction "http400", qui au même titre que "http500" permet de renvoyer le code d'erreur au navigateur si beosin et d'afficher un petit message en passant.
Dans le cas où il n'y a pas de demande à traiter, on affiche un formulaire vide.
```
if (strlen(rawpost) == 0) {
while (strlen(secret) < 6) {
//secret[0] = '\0';
memset(secret, '\0', sizeof(secret));
rdmstr(question, sizeof(question));
secret_class = strtosecret(question, secret);
}
```
Ici, je cherche à créer une chaîne de caractère aléatoire suffisamment longue, d'où la boucle "while" qui se répète tant que la longueur est inférieure à 6.
À chaque tour, memset() s'assure que le chaîne est bien vide, puis un appel à rdmstr() permet d'obtenir une chaîne aléatoire.
```
size_t
rdmstr(char *s, size_t len)
{
/* fill s with random chars */
size_t l=0;
const char charset[] =
"0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMOPQRSTUVWXYZ"
"-_+~#()%,?;.:/!=";
for (size_t i = 0; i < len; i++) {
s[i] = charset[arc4random_uniform(strlen(charset))];
l++;
}
s[len] = '\0';
return l;
}
```
Cette fonction pioche dans la liste de caractères définie dans "charset" grâce à arc4random_uniform().
Notez que je n'ai choisi que des caractères spéciaux assez faciles d'accès sur un clavier (de smartphone notamment). On pourrait y ajouter des espaces et d'autres symboles plus étranges encore. On peut aussi prciser plusieurs fois un caractère si on veut augmenter sa probabilité d'apparaître. Je n'ai pas mis d'espace, j'ai pensé que ça pourrait prêter à confusion.
S'ensuit la fonction strtosecret qui va choisir une classe de caractères à recopier et qui constituera la réponse au captcha:
```
int
strtosecret(const char *s, char *secret)
{
/* choose a random class of char
* secret is all char of the selected class
* from string s
*/
int char_classes[] = { DIGIT, LOWER, UPPER, PUNCT };
int char_class = char_classes[arc4random_uniform(LEN(char_classes))];
for (size_t i=0; i < strlen(s); i++) {
switch (char_class) {
case DIGIT:
if (isdigit(s[i]))
secret[strlen(secret)] = s[i];
break;
case LOWER:
if (islower(s[i]))
secret[strlen(secret)] = s[i];
break;
case UPPER:
if (isupper(s[i]))
secret[strlen(secret)] = s[i];
break;
case PUNCT:
if (ispunct(s[i]))
secret[strlen(secret)] = s[i];
break;
}
}
return char_class;
}
```
Vous l'aurez compris, cette fonction lit la chaîne caractère par caractère et le recopie s'il correspond à la condition choisie aléatoirement.
La classe de caractère choisie est retournée pour savoir quelle consigne afficher à l'utilisateur.
On transforme la réponse en hash avec crypt_newhash(), pour permettre la vérification du captcha ensuite:
```
if (crypt_newhash(secret, "bcrypt,a", anshash,
sizeof(anshash)) != 0)
```
Reste à afficher le formulaire:
```
http200("text/html; charset=utf-8");
printf(form,
instructions[secret_class],
question,
anshash
);
```
Si au contraire on a reçu des données, il faut traiter la demande.
Pour cela, on va découper le texte d'entrée:
```
get_post_field("user=", rawpost, user);
get_post_field("recovery=", rawpost, recovery);
get_post_field("newpass=", rawpost, newpass);
get_post_field("answer=", rawpost, answer);
get_post_field("anshash=", rawpost, anshash);
```
La fonction get_post_field recherche dans "rawpost" la chaîne passée en premier argument et l'enregistre dans la dernière variable.
Regardons-là de plus près:
```
char *
get_post_field(const char *str, const char *post, char *field)
{
char *pos = NULL;
char buf[BUFSIZ] = {'\0'};
char *r = strdup(post);
char *tofree = r;
char *tok = NULL;
while ((tok = strsep(&r, "&")) != NULL) {
if ((pos = strstr(tok, str)) == NULL) {
continue;
} else {
if (strlcpy(buf, tok + strlen(str),
sizeof(buf)) >= sizeof(buf))
http500("strlcpy");
break;
}
}
if (urldecode(buf, field) < 0)
http400("Bad request");
free(tofree);
return field;
}
```
On remarque qu'elle fait appel à strsep(). Cette fonction modifie la chaîne, c'est pourquoi on a utilisé strdup() au préalable, et enregistré dans tofree la référence au pointeur qu'il faudra libérer avec free() ensuite.
Une fois ces éléments rassemblés, on va vérifier que le nom d'utilisateur correspond à une regex:
```
if (regcomp(®_username, valid_username_regex,
REG_EXTENDED) != 0) {
regfree(®_username);
http500("can't compile regex");
}
if (regexec(®_username, user, 0, NULL, 0) != 0) {
regfree(®_username);
http400(errusername);
}
regfree(®_username);
```
Ici, regex.h n'est pas trop compliqué à utiliser puisqu'il s'agit de seulement vérifier si "ça match".
Plus simple, on vérifie juste si le nouveau mot de passe demandé est assez long:
```
if (strlen(newpass) < 15)
http400(errshortpw);
```
Oui, 15 seulement... On va me détester si j'impose +.
Reste à enregistrer la demande dans un fichier portant le nom d'utilisateur.
La suite est donc un peu barbante, il s'agit juste de créer un chemin puis d'écrire dedans:
```
/* build the path to file with request */
if ((strlcpy(request_file, chpw_requests_dir, sizeof(request_file))
> sizeof(request_file)) ||
(strlcat(request_file, "/", sizeof(request_file))
> sizeof(request_file)) ||
(strlcat(request_file, user, sizeof(request_file))
> sizeof(request_file)))
http500("strlcpy & strlcat");
/* open the file and save data */
f = fopen(request_file, "w");
if (f == NULL)
http500("can't open file to write");
fprintf(f, "%s\n", recovery);
fprintf(f, "%s\n", newpass);
fclose(f);
```
Je termine en faisant un petit chmod afin de limiter qui aura accès à ce fichier.
```
chmod(request_file,
S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH
);
```
C'est le point dont je suis le moins satisfait, mais je n'ai pas trouvé mieux car:
* httpd (slowcgi) doit pouvoir écrire dans les fichiers. Le propriétaire est donc "www".
* _tabr_admin doit pouvoir lire ces fichiers. Cependant, ce dernier n'appartient pas au groupe "www".
Par conséquent, ces fichiers sont lisibles par tous. TOUTEFOIS, le dossier dans lequel ils sont stockés n'est accessible en lecture QUE par _tabr_admin. L'utilisateur www ne peut que écrire dedans, et les autres n'ont aucune permission :
```
drwx-wx--- 2 _tabr_admin www 512 May 13 13:39 tabr_chpw_requests
```
C'est LA partie de l'installation à ne pas rater.
Heureusement, un petit Makefile est prévu pour ça. On en parle dans le prochain article :)
## Une réaction?
=> mailto:bla@bla.si3t.ch?subject=TaBr-tabr_chpw_cgi-part4 Envoyez votre commentaire par mail (anonyme).
=> /log/commentaires/ Mode d'emploi de la liste de diffusion pour recevoir les réponses.
]]>
TaBr - tabr_passwd pour modifier un mot de passehttps://si3t.ch/log/2023-05-15-TaBr-part3-tabr_passwd.txt2023-05-15T13:54:04Z"
exit 1
}
```
Ensuite, voici une fonction qui va se charger de terminer le script en alertant dans tous les cas l'admin. D'ailleurs, on voudra sans doute créer un alias dans "/etc/mail/aliases" pour rediriger le mail
```
end()
{
# $1 : file
# $2 : message
# $3 : exit code
## alert root
cat << EOF | mail -s "$(basename $1) password change request" ${admin}
$1 was created to change password and returned:
$2
EOF
rm -f "$1"
exit $3
}
```
On voit dans cette fonction qu'elle envoie un mail à l'admin définit dans "/etc/tabr.conf" indiquant qu'il y a eu demande de changement de mot de passe. Ensuite, on indique un éventuel message d'erreur.
Dans tous les cas, on supprime le fichier de demande de changement de mot de passe avant de quitter.
On peut passer à la fonction qui va se charger de traiter la demande:
```
handle_request() {
u="$(basename ${1})"
## check if user is indeed registered
[[ -e $data/$u ]] || end "${1}" "No user $u found" 1
```
Cette fonction prend en argument le chemin complet vers le fichier de demande de changement. Ce fichier porte le nom de l'utilisateur, on le met dans une variable "$u" comme à l'accoutumée.
On vérifie avant d'aller plus loin qu'on a bien un fichier de récupération pour l'utilisateur en question.
```
## check if recovery match user hashed recovery
# recovery is on first line
#recovery="$(sed -n '1p' ${1})"
head -n 1 "${1}" | /usr/local/bin/hashmatchstr $(cat ${data}/${u}) \
|| end "${1}" "Wrong recovery code" 1
```
On vérifie ici que le code de récupération précisé par l'utilisateur correspond au hash de ce code enregistré lors de l'inscription. Pour cela, on utilise un bout de C "hashmatchstr".
=> /log/2023-05-04-Check-if-a-string-match-a--bcrypt--hash.xhtml hasmatchstr fait appel à la fonction "crypt_checkpass".
Ensuite, on récupère le mot de passe demandé et on procède aux modification:
```
newpw="$(sed -n '2p' ${1})" # pw on 2nd line
newpwhash="$(print "%s" "${newpw}" | encrypt -b a )"
## change system pw
doas /usr/sbin/usermod -p "${newpwhash}" "${u}"
## xmpp
printf "%s\n%s\n" "${newpw}" "${newpw}" |
doas /usr/local/sbin/prosodyctl passwd "${u}@${domain}"
end ${1} "Everything seems OK" 0
}
```
usermod attend le hash du mot de passe, d'où l'appel à "encrypt".
Vous noterez ici la petite astuce avec "printf" pour prosody qui attend le nouveau mot de passe en entrée.
Enfin, on appelle la fonction ci-dessus par une boucle sur tous les fichiers du dossier passé en argument. On se sert pour cela de "find", c'est plus propre et gère les éventuels noms de fichiers chelous (je ne fais pas confiance à ce qu'un petit malin a pu éventuellement réussir à déposer malgré toutes mes précautions).
```
[[ $# -ne 1 ]] && usage
# loop over file lists
find "$1"/ -type f | while read -r request_file; do
handle_request "${request_file}"
done
```
Ces fichiers contenant les requêtes peuvent être créés via un script, appelé via l'instruction "ForceCommand" lors d'une connexion SSH.
Cependant, ce n'est pas très facile d'accès pour les gens normaux.
Aussi, j'ai prévu un petit code CGI afin de demander le changement de mot de passe en ligne.
Mais ça, c'est pour le prochain article ^^
## Une réaction?
=> mailto:bla@bla.si3t.ch?subject=TaBr-tabr_passwd-part3 Envoyez votre commentaire par mail (anonyme).
=> /log/commentaires/ Mode d'emploi de la liste de diffusion pour recevoir les réponses.
]]>
TaBr - tabr_deluser pour supprimer un utilisateurhttps://si3t.ch/log/2023-05-14-TaBr-part2-tabr_deluser.txt2023-05-14T21:38:21Z\n" $0
exit 1
}
## get arguments into variables
[[ -z "${1}" ]] && usage
```
Vous noterez ici que j'utilise un test "si chaîne nulle" et non "si nombre d'argument est égal à 1". C'est parce que j'ai passé le flag "-e" au shebang, qui provoque l'arrêt du script en cas d'erreur. Or, si un test échoue, c'est considéré comme une erreur.
Pour simplifier la suite, on met le nom d'utilisateur dans une variable:
```
u="${1}"
```
Et c'est tout, on peut supprimer l'utilisateur:
```
## system user
doas /usr/sbin/userdel -r "${u}"
```
Vous noterez l'option "-r" qui permet de supprimer aussi le dossier personnel de l'utilisateur.
```
## xmpp account
doas /usr/local/sbin/prosodyctl deluser "${u}@${domain}"
```
On en fait de même avec prosody.
Si on avait ajouté l'utilisateur à une installation dokuwiki, on pourrait aussi avoir ensuite:
```
php /path/to/dokuwiki/bin/plugin.php usermanager delete hseldon
```
Pour terminer, on supprimer les fichiers qui contenaient le code de récupération et les instructions destinées à l'utilisateur:
```
## recovery file
rm ${data}/${u}
## instructions
rm "${data_instructions}/${u}.txt"
```
Et voilà!
Prochains articles : on décrit le changement de mot de passe, et l'interface CGI qui permettra de faire la demande.
## Une réaction?
=> mailto:bla@bla.si3t.ch?subject=TaBr-tabr_deluser-part2.gmi Envoyez votre commentaire par mail (anonyme).
=> /log/commentaires/ Mode d'emploi de la liste de diffusion pour recevoir les réponses.
]]>
TaBr - tabr_adduser pour ajouter un utilisateur au serveur familialhttps://si3t.ch/log/2023-05-13-TaBr-part1-tabr_adduser.txt2023-05-13T13:22:25Z\n" "$0"
printf "if not specified, a random recovery-passphrase will be generated\n"
exit 1
}
```
Voici une fonction pour générer un mot de passe aléatoire:
```
genpw()
{
#jot -rcs '' $1 33 126
tr -cd '[:alnum:]~#()%@,?;.!*' < /dev/urandom |\
fold -w $1 | head -n 1
}
```
Comme on peut le voir, j'ai commenté une version avec "jot" qui proposait une suite aléatoire de tous les caractères entre le n°33 et le 126 (voir man ascii).
Cependant, j'ai opté pour une solution avec "tr" me laissant le choix des caractères possibles. J'en reste donc aux lettres, chiffres et ponctuation habituelle. Cela évite pour les utilisateurs moins à l'aise de devoir fouiller dans le clavier de leur smartphone.
Ensuite, on génère un code de récupération aléatoire:
```
rdm-recovery-pass()
{
genpw 30 |
sed -E 's/^(.{6})(.{6})(.{6})(.{6})/\1-\2-\3-\4-/'
}
```
L'appel de "sed" permet d'insérer des tirets "-" à intervalles réguliers pour faciliter la saisie ensuite.
On s'assure ensuite qu'on a bien le bon nombre d'arguments pour le bon fonctionnement du script:
```
## get arguments into variables
[[ $# -ge 1 ]] && [[ $# -lt 3 ]] || usage
```
On met le nom d'utilisateur dans une variable plus facile à identifier:
```
u="${1}"
```
S'ensuit un test pour vérifier si une phrase de récupération a été précisée. Je pense notamment à ma famille pour qui il serait facile de proposer des phrases faciles à retenir en référence à un vécu commun. Sinon, un code de récupération est généré.
```
[[ -z "${2}" ]] && recovery="$(rdm-recovery-pass)" || recovery="${2}"
```
On vérifie si un utilisateur au nom de celui demandé existe déjà:
```
## check if user already exist
id -u $u > /dev/null 2>&1 && die "User already exists"
#[[ -e $data/$u ]] && die "User already exists" # commented, previous is safer
```
On génère un mot de passe totalement aléatoire. J'ai choisi une longueur de 16 caractères. On peut bien sûr faire mieux, mais si j'en rajoute, on va m'envoyer des cailloux.
```
## generate random password
pw="$(genpw 16)"
```
On enregistre le code de récupération dans un fichier portant le nom de l'utilisateur (unique), situé dans un dossier qui appartient à _tabr_admin, dont seul _tabr_admin a accès. C'est en réalité dans un dossier de son répertoire personnel, dont j'ai ajusté le spermissions en 0700.
```
## store recovery pass
encrypt -b a ${recovery} > $data/$u
```
On crée l'utilisateur système.
```
## create system user
doas /usr/sbin/useradd -m -g $usergroup -s /sbin/nologin -p "$(encrypt -b a "${pw}")" "$u"
```
Cet utilisateur peut recevoir des mails puisque dovecot et smtpd sont configurés pour utiliser le processus de login de l'OS.
On remarque plusieurs choses dans cette commande:
* On crée un $HOME à l'utilisateur (-m)
* On demande à ce qu'il appartienne au groupe _tabr_users
* On lui attribue le shell /sbin/nologin. Autrement dit, il est désactivé.
* On définit aussitôt son mot de passe en passant le hash de ce dernier avec la commande "encrypt" .
On peut désormais créer le compte xmpp. Ici, il y a une petite bidouille pour passer le mot de passe avec printf:
```
## create xmpp account
printf "%s\n%s\n" "${pw}" "${pw}" | doas /usr/local/sbin/prosodyctl adduser "${u}@${domain}"
```
On termine par générer les instructions à envoyer qui seront stockées dans un fichier puis affichée.
Libre à l'admin d'envoyer/imprimer/...? ce fichier texte.
```
## generate notice with qr code
print_notice "${u}" "${pw}" "${recovery}" > ${data_instructions}/${u}.txt
cat ${data_instructions}/${u}.txt
```
Enfin, on rappelle à l'admin de supprimer le fichier contenant les données du nouvel utilisateur rapidement, une fois qu'elles ont été transmises:
```
print "*** WARNING ***\n%s\n" \
"You probably should delete ${data_instructions}/${u}.txt very soon"
```
## Une réaction?
=> mailto:bla@bla.si3t.ch?subject=TaBr-tabr_adduser-part1 Envoyez votre commentaire par mail (anonyme).
=> /log/commentaires/ Mode d'emploi de la liste de diffusion pour recevoir les réponses.
]]>
TaBr - gestion d'un serveur familial partie 1https://si3t.ch/log/2023-05-12-TaBr-suite-gestion-serveur.txt2023-05-12T13:59:15Z https://si3t.ch/ah/fr/#_89_SFTPdansunchroot Pour la mise en place d'un chroot SFTP, c'est facile.
4 composants sont prévus :
* tabr_adduser : pour ajouter les utilisateurs. Il crée au passage un code de récupération pour changer le mot de passe.
* tabr_deluser : supprime un utilisateur et toute référence à ce derier
* tabr_passwd : traite les demandes de changement de mot de passe. Il sera appelé via une tâche cron.
* tabr_chpw_cgi : une interface web pour demander le changement de mot de passe. Pour un public un peu plus geek, j'utiliserais plutôt une identification par clé ssh et un script appelé à la connexion avec "ForceCommand".
On détaillera chaque composants dans une série d'articles à venir.
Pour finir celui-ci, je vous présente seulement le fichier Makefile qui permet l'installation:
```
# tabr suite
# prx
# Quelques variables...
PREFIX ?=/usr/local
BINDIR ?=${PREFIX}/bin
SBINDIR ?=${PREFIX}/sbin
CGIDIR ?=/var/www/cgi-bin
CHPWREQDIR ?=/var/www/tabr_chpw_requests
# Tout ce qu'il faudra compiler
all: src/tabr_chpw_cgi src/hashmatchstr
# chpw_cgi sera à recompiler si on modifie sa configuration
src/chpw_cgi/main.c: src/chpw_cgi/config.h
# Comment compiler tabr_chpw_cgi.
# On utilise -static car il sera dans un chroot
src/tabr_chpw_cgi: src/chpw_cgi/main.c
${CC} -static -o $@ $?
# Compilation de hashmatchstr, l'outil
# qui permet de comparer les hash et les passwords
src/hashmatchstr: src/hashmatchstr.c
${CC} -o $@ $?
# On prévoit comment remettre à zéro
clean:
rm src/tabr_chpw_cgi
rm src/hashmatchstr
# Installation des fichiers.
# On utilise la commande install pour
# gérer finement les permissions
install: src/tabr_chpw_cgi src/hashmatchstr
install -o root -g daemon -m 0755 src/tabr_chpw_cgi ${CGIDIR}/tabr_chpw.cgi
@# IMPORTANT: chmod 730, www can write but can't read
install -o _tabr_admin -g www -m 0730 -d ${CHPWREQDIR}
install -m 0755 -o root -g bin src/hashmatchstr ${BINDIR}/hashmatchstr
install -m 0755 -o root -g bin src/tabr_adduser.sh ${SBINDIR}/tabr_adduser
install -m 0755 -o root -g bin src/tabr_passwd.sh ${SBINDIR}/tabr_passwd
install -m 0755 -o root -g bin src/tabr_deluser.sh ${SBINDIR}/tabr_deluser
install -m 0644 -o root -g wheel src/tabr.conf /etc/
# On prépare aussi le nettoyage
uninstall:
rm -rf ${CGIDIR}/tabr_chpw.cgi
rm -f ${BINDIR}/hashmatchstr
rm -f ${BINDIR}/tabr_adduser
rm -f ${BINDIR}/tabr_passwd
rm -f ${BINDIR}/tabr_deluser
@printf "You probably should remove %s and %s too\n"\
"${CHPWREQDIR}" "/etc/tabr.conf"
```
## Une réaction?
=> mailto:bla@bla.si3t.ch?subject=TaBr-suite-gestion-serveur Envoyez votre commentaire par mail (anonyme).
=> /log/commentaires/ Mode d'emploi de la liste de diffusion pour recevoir les réponses.
]]>
Check if a string match a (bcrypt) hashhttps://si3t.ch/log/2023-05-04-Check-if-a-string-match-a--bcrypt--hash.txt2023-05-04T16:55:17Z
#include
#include
#include
#include
#include
/* compare password passed on stdin with hash passed as argv[2] */
int
main(int argc, char *argv[])
{
char pw[LINE_MAX] = {'\0'};
if (argc != 2)
errx(1, "usage: printf \"pw\" | %s ", argv[0]);
if (fgets(pw, LINE_MAX, stdin) == NULL)
err(1, "fail to read from stdin");
pw[strcspn(pw, "\n")] = '\0'; /* remove ending \n if any */
if (crypt_checkpass(pw, argv[1]) != 0)
return 1;
printf("match \\o/\n");
return 0;
}
```
]]>
Un serveur pour les communications familialeshttps://si3t.ch/log/2023-05-01-family-server.txt2023-05-01T14:18:46Z Allez, ça serait quand même bien que vous mettiez Whatsapp, comme ça on pourrait créer un groupe. Ça serait vachement sympa pour les photos des enfants. Et puis c'est pas pratique les SMS groupés, on ne sait jamais trop si on répond à tout le monde.
Alors non, Whatsapp, vraiment pas. GAFAM, vie privée, données personnelles, tout ça tout ça.
Mais je sais bien au fond de moi que les photos envoyées par MMS, ce n'est pas tellement privé non plus finalement.
Alors si je refuse, que puis-je proposer à la place?
=> https://delta.chat/fr/ Deltachat est génial en remplacement.
Il suffit d'une adresse mail, que tout le monde a.
Encore faut-il, si je veux pleinement garder le contrôle sur les photos de famille, que tout le monde utiliser un serveur mail adapté -- PAS GMAIL.
J'ai la chance d'avoir un serveur à la maison, je peux donc en théorie créer un compte mail pour chaque personne dans la famille. C'est un peu pénible pour moi, et j'entends déjà les "j'ai oublié mon mot de passe :s". Ceci dit, ça pourrait être un joli cadeau de Noël un jour pour tout le monde : une adresse mail propre gérée à la maison.
Bon, sinon, il y a Signal. Cependant, ça m'ennuie vraiment de devoir m'appuyer sur un système qui n'existera peut-être plus dans 5 ans. C'est aussi le cas pour Deltachat en théorie, même si le mail sur lequel cet outil repose restera toujours fonctionnel.
Un autre défaut à Deltachat qui pourtant semble quasi-parfait avec son système d'invitation une fois l'effort de créer des comptes mails à tout le monde : il n'y a pas de client disponible sous OpenBSD. Je rêve juste d'un petit client en console, même pas besoin du gros machin GUI. Un jour peut-être ^^.
Ceci dit, Deltachat pose le souci de pouvoir lire les messages qui ont été chiffrés avec un client mail aute que celui de DeltaChat. Ça risque d'en perturber quelques uns.
Une autre idée que je souhaite tester, ce serait d'utiliser mon serveur XMPP.
J'ai pensé à utiliser le système d'invitations. Cependant, ce n'est pas si simple pour quelqu'un n'ayant pas trop l'habitude des clients XMPP (mais je conseille vivement mod_invites).
Je me suis demandé aussi si prévoir un répertoire LDAP avec identifiants pour chaque user ne serait pas pratique, mais il faut avouer que l'intégration de LDAP n'est pas très bien documentée. En tout cas, pas assez pour moi.
De plus, ça signifie que chaque service soit capable de parler LDAP, donc chacun de ces services est une nouvelle voie d'accès pour des attaques sur le serveur afin de piquer les identifiants de quelqu'un.
Je préfère les choix par défaut des développeurs, c'est + sûr.
Il faut me rendre à l'évidence : je vais créer des comptes pour chacun. À moi de réfléchir à une façon de leur permettre de changer/récupérer leurs mots de passe. Non seulement cela m'évitera d'intervenir, mais m'évitera d'avoir connaissance de ces identifiants.
Pour l'instant, j'envisage les choses ainsi:
* Création d'un compte avec mot de passe aléatoire ainsi qu'un code de récupération, une sorte de longue phrases. À la création, une fiche imprimable avec un QR code contenant les instructions et codes de récupération sera généré : c'est ce que j'enverrai à mes proches.
* Interface pour changer le mot de passe via un script CGI. Je me rend compte que le faire via gemini serait presque plus sûr puisque ça permettrait d'utiliser les certificats utilisateurs plutôt qu'un mot de passe, mais bon, mes proches n'en sont pas là. Pour l'instant, ça sera derrière une authentification http (htpasswd).
* Pour aller + loin, pour les + geeks, on pourrait envisager plutôt d'utiliser les clés SSH, avec un ForceCommand qui appelerait un script permettant le changement de mot de passe.
* Le changement de mot de passe modifiera pour chacun des services : mail, xmpp, dokuwiki, ... que sais-je?
Tout ceci devrait être scripté pour faciliter l'automatisation.
> Mais tu recrées un CHATONS en fait?
C'est un peu l'idée, alors que dernièrement avec les 3hg on a quitté le collectif CHATONS.
Ce que j'envisage de faire ici sera à une bien plus petite échelle, avec 1 seul domaine.
De plus, je n'ai pas le temps de participer au collectif, alors s'estampiller membre des CHATONS semblait un peu trop hypocrite.
Par ailleurs, ça sera nettement mieux organisé. Je me laisse le temps :)
Quoi qu'il en soit, ce ne sont que des idées pour l'instant : c'est parti pour le code!
## Une réaction?
=> mailto:bla@bla.si3t.ch?subject=family-server Envoyez votre commentaire par mail (anonyme).
=> /log/commentaires/ Mode d'emploi de la liste de diffusion pour recevoir les réponses.
]]>
random passwords from manpageshttps://si3t.ch/log/2023-04-23-random-passwords-from-manpages.txt2023-04-23T13:45:12Z
# usage : rdmempw.sh (default: 6)
# default is 6 words
[[ $1 -gt 0 ]] && w=$1 || w=6
# find a random manpage
manpage="$((apropos -s 1 .; apropos -s 5 .; apropos -s 6 .) |\
sort -R |\
awk '{sub("\\(.*|,", "", $1); print $1; exit}')"
man $manpage |\
tr " " "\n" |\
sort -Ru |\
awk -v w="$w" '
# keep only word at least 4 char long
/^[[:alnum:][:digit:]]{4,}$/ {
pw = pw $0
n++
if (n > w) { exit }
pw = pw "-"
}
END { print pw }
'
```
As you can see, "apropos" gives a list of availables manpages. I only use sections 1, 5 and 6 since the others are quite complex.
I use a lot of "sort -R" to randomize the wordlists.
Then, "awk" print the manpage, removing parentheses.
After, I call "man" and "tr" to replace every spaces with newlines so I can randomize with "sort" the wordlist. "awk" is used again to store words long enough in a string. When anough words are picked, we exit and display the password.
=> gemini://si3t.ch/cgi-bin/pw I've updated my online password generator if you want to try.
I guess it could be faster by using a cache.
## Comments?
=> mailto:bla@bla.si3t.ch?subject=random-passwords-from-manpages Comments by mail
=> /log/commentaires/ Mailing list instructions
]]>