counted

Vérifier Counted

Le chiffrement de bout en bout n'a de valeur que si le code qui tourne dans votre navigateur est bien celui que nous disons servir. Cette page est là pour que vous n'ayez pas à nous croire sur parole.

Ce qui est publié

Chaque version de Counted est construite une seule fois, dans un environnement figé, et le résultat est empreint : le serveur, le module WebAssembly, son code JavaScript et chaque fichier de l'application, en SHA-256. La liste est servie par la version qui tourne :

https://counted.fr/SHA256SUMS.txt

Chaque ligne donne l'empreinte d'un fichier et son chemin sur counted.fr : assets/web_bg-….wasm, assets/web-….js, les polices et les feuilles de style. La même liste figure dans les notes de chaque version, hors du serveur qui la sert.

Vérifier ce que vous recevez

Depuis un terminal, téléchargez la liste et chaque fichier qu'elle nomme, puis comparez :

curl -sO https://counted.fr/SHA256SUMS.txt
for f in $(awk '$2 != "server" {print $2}' SHA256SUMS.txt); do
  curl -s --create-dirs -o "$f" "https://counted.fr/$f"
done
sha256sum -c --ignore-missing SHA256SUMS.txt

Chaque ligne doit se terminer par OK. Le fichier server est l'exécutable du serveur ; il n'est pas servi, son empreinte est là pour la comparaison avec une compilation.

Le reconstruire vous-même

La construction est reproductible : images de base et compilateur figés par empreinte, mêmes chemins, mêmes options. Le code source du client est public sur github.com/counted-labs/counted, un tag par version, sous licence AGPL-3.0. Trois commandes suffisent pour reconstruire ce que ce site sert et comparer :

git clone --branch vX.Y.Z https://github.com/counted-labs/counted.git && cd counted
docker buildx build --platform linux/amd64 -f Dockerfile.client --target sums --output type=local,dest=out .
curl -s https://counted.fr/SHA256SUMS.txt | grep -v '  server$' | diff - out/SHA256SUMS.txt

Un diff vide signifie que chaque fichier reçu par votre navigateur est, octet pour octet, ce que ces sources produisent. La ligne server est le binaire natif : son code n'est pas publié, elle est exclue de la comparaison, et il ne voit jamais vos données en clair - tout est chiffré sur votre appareil avant l'envoi. Chaque version sur GitHub porte aussi son SHA256SUMS.txt, une copie indépendante de ce serveur. Nous refaisons la même reconstruction nous-mêmes, sans cache, à chaque version.

Vérifier la signature

Chaque SHA256SUMS.txt est signé par notre chaîne de compilation avec Sigstore, et la signature est inscrite dans un registre public en ajout seul : la liste d'une version ne peut pas être remplacée après coup sans que cela se voie. Avec cosign :

base=https://github.com/counted-labs/counted/releases/download/vX.Y.Z
curl -sLO $base/SHA256SUMS.txt -sLO $base/SHA256SUMS.txt.sigstore.json
cosign verify-blob --bundle SHA256SUMS.txt.sigstore.json \
  --certificate-identity "https://gitlab.com/jbosi/counted//.gitlab-ci.yml@refs/heads/main" \
  --certificate-oidc-issuer https://gitlab.com SHA256SUMS.txt
curl -s https://counted.fr/SHA256SUMS.txt | cmp - SHA256SUMS.txt

Verified OK puis aucune sortie de cmp : la liste servie par ce site est exactement celle que la compilation de cette version a signée. La signature atteste d'où vient la liste, pas que le code est sûr - c'est le rôle des deux vérifications ci-dessus.

Contrôlé sans nous

Deux contrôles tournent sur les machines de GitHub, qui ne partagent rien avec les nôtres, et leurs résultats sont publics :

  • À chaque version, le client est reconstruit depuis son tag et comparé au SHA256SUMS.txt signé de cette version.
  • Toutes les 6 heures, la liste servie par counted.fr est comparée à celle, signée, d'une version publiée ; chaque fichier listé doit être servi à l'identique, et les pages de l'application ne doivent charger que des fichiers de la liste.

Les applications mobiles

Les applications Android et iOS sont construites depuis les mêmes sources. Ce qui se vérifie dépend du magasin :

  • F-Droid reconstruit chaque version depuis le dépôt public et ne distribue notre APK que si sa propre compilation donne les mêmes octets, signature mise à part.
  • Google Play signe l'application avec sa propre clé, dont le certificat est ci-dessous : il prouve qu'une copie vient de Play, mais elle ne se compare pas encore à une compilation.
  • L'App Store chiffre chaque copie pour l'appareil qui l'installe : personne ne peut la comparer à une compilation, nous compris. Identifiants : équipe UK936HFQ24, application fr.counted.app.

Certificat de signature de l'APK F-Droid et de celui joint aux versions GitHub, en SHA-256 :

D8:D4:02:6F:49:6F:3C:21:54:F1:38:E8:17:10:33:2E:A5:28:8A:AA:B8:56:7A:2F:8D:0E:71:3D:E1:D5:93:E8

Pour vérifier l'application installée sur votre téléphone, l'application AppVerifier compare son certificat à celui-ci. Depuis un ordinateur :

adb pull "$(adb shell pm path fr.counted.app | head -1 | cut -d: -f2)" counted.apk
apksigner verify --print-certs counted.apk | grep SHA-256

Certificat de signature de Google Play, en SHA-256 :

4C:1E:7D:F5:2C:FB:D6:03:14:C2:0B:E4:AA:7E:9E:7D:30:19:1C:50:24:3B:F5:09:1A:21:F4:B1:30:98:A6:DC

Ce que cela prouve

  • Le code que votre navigateur exécute est celui dont l'empreinte est publiée.
  • Deux personnes qui vérifient au même moment reçoivent le même code.
  • Une version reconstruite depuis ses sources donne les mêmes fichiers - et donc que rien n'a été ajouté entre le code et ce qui est servi.

Ce que cela ne prouve pas

  • Que le code est correct : une empreinte atteste l'identité d'un fichier, pas sa qualité.
  • Qu'un fichier différent servi à une seule personne serait repéré : les contrôles automatiques voient ce que tout le monde reçoit, et votre navigateur ne vérifie rien de lui-même. Si cela vous inquiète, utilisez l'application mobile, dont le code est fixé à l'installation.
  • Ce que fait le serveur : son code n'est pas public. Il ne reçoit que des données chiffrées, mais son traitement des métadonnées ne se vérifie pas de l'extérieur. Notre politique de sécurité dit, pour chaque affirmation, ce qui la prouve.

Une empreinte qui ne correspond pas ? Écrivez-nous avec la ligne concernée et la date.