diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..8c5b7b6 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "oki-preview", + "runtimeExecutable": "pnpm", + "runtimeArgs": ["--dir", "frontend", "preview", "--port", "4173"], + "port": 4173 + } + ] +} diff --git a/.gitignore b/.gitignore index e879e9f..a752cad 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ playwright-report/ test-results/ *.local .DS_Store + +# SvelteKit (frontend/) +.svelte-kit/ +frontend/build/ diff --git a/ADR.md b/ADR.md new file mode 100644 index 0000000..20abad0 --- /dev/null +++ b/ADR.md @@ -0,0 +1,83 @@ +# ADR-001 — Backend : SvelteKit natif (fichiers plats), pas de Strapi + +**Statut** : accepté · **Date** : 2026-07-10 · **Décideur** : migration OKI d'exitchatcontrol.org +**Doctrine de référence** : `ui-ux-souveraine-oki.md` (citée « doctrine §x.y » ci-dessous) + +## Contexte + +exitchatcontrol.org est un annuaire de ~55 outils libres répartis en 23 sections +thématiques, actuellement généré statiquement par Astro à partir de fichiers +versionnés (`src/data/*.json`, `src/content/sections/*/*.mdx`). Le déploiement +cible est un conteneur nginx auto-hébergé (YunoHost/Docker), sans backend. + +Deux options étaient sur la table (mission §2.1) : + +- **Option A** : Strapi v5 headless, base relationnelle, admin web, API, i18n plugin. +- **Option B** : SvelteKit full-stack, contenu en fichiers Markdown/JSON versionnés, + parsés au build, site prérendu. + +## Décision + +**Option B — SvelteKit 2 + Svelte 5, contenu en fichiers plats prérendus.** + +## Justification par la règle de décision + +La règle imposée : minimiser la charge cognitive **extrinsèque** (doctrine §1.2, +Sweller) pour l'utilisateur final ET l'administrateur, dans le budget performance +(doctrine §4.4). + +1. **Les données sont déjà statiques et versionnées.** 55 outils, mises à jour + par pull request espacées de plusieurs jours/semaines (historique git). Le seuil + « le volume de données justifie une base relationnelle » posé comme condition + de l'option A n'est pas atteint — 55 fiches tiennent dans un dossier de + fichiers Markdown lisibles à l'œil nu. +2. **Charge d'administration.** Strapi = un service Node persistant + une base + + des migrations de schéma + des mises à jour de sécurité + des sauvegardes. + Pour l'admin OKI, c'est de la charge extrinsèque pure : la tâche réelle + (« corriger une fiche ») devient « se connecter à un admin, naviguer un CMS, + publier, invalider un cache ». En fichiers plats : éditer un fichier, commit. + Le git devient l'historique éditorial, la revue par PR devient la modération. +3. **Budget performance (doctrine §4.4).** Site 100 % prérendu : premier rendu + = HTML servi par nginx, zéro requête API, JS initial minimal (hydratation + sélective). Strapi n'aiderait pas mais ajouterait un point de latence et de + panne si l'on cédait à la tentation du rendu à la demande. +4. **Souveraineté et surface d'attaque.** Un site statique n'a pas de CVE de CMS, + pas de compte admin à voler, pas de base à exfiltrer. C'est la posture + cohérente avec le sujet même du site (OPSEC, résistance à la censure) : + le site doit être **mirrorable** (un tarball du build suffit), ce qu'un + Strapi rend impossible. +5. **Loi de Tesler (doctrine §1.3)** : la complexité éditoriale n'est pas + supprimée, elle est déplacée vers le format de fichier. On l'absorbe par un + frontmatter strict + validation au build (le build échoue si une fiche est + invalide — équivalent des types du CMS, sans le CMS). + +### Ce qui ferait rebasculer vers Strapi (critères de réversibilité) + +- Une équipe éditoriale non-technique de plusieurs personnes publiant chaque semaine ; +- Des soumissions communautaires en volume nécessitant un workflow draft/publish ; +- Plus de ~500 fiches ou des relations réellement complexes. + +Dans ce cas, le modèle de données de la mission §3 s'applique tel quel ; le +frontend SvelteKit resterait inchangé (il consommerait l'API au build). +Étape intermédiaire possible sans backend : Decap CMS (git-based) sur le dossier +`content/` — écarté pour l'instant, « préférer la solution la plus simple ». + +## Décisions techniques associées + +- **adapter-static + prerender total** : parité avec le déploiement nginx actuel + (Dockerfile conservé dans l'esprit). Un lien fonctionne sans JS (doctrine §4.4). +- **Markdown + frontmatter maison** : parseur frontmatter minimal (~40 lignes, + zéro dépendance) + `marked` (MIT) pour le corps, exécuté **au build uniquement** + — rien de tout cela n'est expédié au client. +- **i18n maison typé** (pattern repris du projet source) plutôt que + Paraglide/inlang : ~40 lignes, dictionnaires JSON `fr`/`gcf` vérifiés par le + compilateur TypeScript (une clé manquante = erreur de build). Paraglide reste + la piste si le nombre de locales croît. +- **Langues** : `fr` (défaut) + `gcf` (créole guadeloupéen, code ISO 639-3 + enregistré BCP 47 valide). Micro-textes créoles d'abord (doctrine §4.2 : + impact affectif disproportionné pour un coût faible) ; traduction intégrale + des fiches = chantier éditorial séparé (voir `docs/CONTENT_GUIDE.md`). +- **CSS natif en `@layer`** : `reset → tokens → base → layouts → components → + utilities` (doctrine §5.2), tokens `oklch()`, container queries, `clamp()`. + Pas de Tailwind (doctrine §5.2 option 4 : écarté en connaissance de cause). +- **Licence du code** : MIT, comme le projet source (continuité). diff --git a/content/categories.json b/content/categories.json new file mode 100644 index 0000000..90039da --- /dev/null +++ b/content/categories.json @@ -0,0 +1,92 @@ +[ + { + "slug": "messagerie", + "title": "Messagerie chiffrée", + "order": 3, + "part": 1 + }, + { + "slug": "email", + "title": "E-mail chiffré & PGP", + "order": 4, + "part": 2 + }, + { + "slug": "navigateur", + "title": "Navigateur & recherche", + "order": 5, + "part": 3 + }, + { + "slug": "dns", + "title": "DNS chiffré & Cloudflare", + "order": 6, + "part": 3 + }, + { + "slug": "vpn", + "title": "VPN : la vérité", + "order": 7, + "part": 4 + }, + { + "slug": "stockage", + "title": "Stockage chiffré", + "order": 10, + "part": 6 + }, + { + "slug": "motsdepasse", + "title": "Gestionnaire de mots de passe", + "order": 11, + "part": 7 + }, + { + "slug": "deuxfa", + "title": "Double authentification & clés matérielles", + "order": 12, + "part": 7 + }, + { + "slug": "social", + "title": "Réseaux sociaux décentralisés", + "order": 13, + "part": 8 + }, + { + "slug": "argent", + "title": "Souveraineté financière", + "order": 14, + "part": 9 + }, + { + "slug": "ia", + "title": "\"L'IA conversationnelle\"", + "order": 15, + "part": 9 + }, + { + "slug": "boiteaoutils", + "title": "La boîte à outils du quotidien", + "order": 16, + "part": 9 + }, + { + "slug": "selfhost", + "title": "Auto-hébergement", + "order": 17, + "part": 10 + }, + { + "slug": "tor", + "title": "Tor", + "order": 18, + "part": 11 + }, + { + "slug": "os", + "title": "\"Systèmes d'exploitation libres\"", + "order": 19, + "part": 12 + } +] diff --git a/content/outils/aegis.md b/content/outils/aegis.md new file mode 100644 index 0000000..7460197 --- /dev/null +++ b/content/outils/aegis.md @@ -0,0 +1,42 @@ +--- +name: "Aegis · Ente Auth" +slug: "aegis" +category: "deuxfa" +difficulty: "beginner" +license: "GPL-3.0" +url: "https://getaegis.app" +color: "#2c5c9c" +monogram: "Ae" +iconSlug: "aegisauthenticator" +tags: ["Codes TOTP","🌍 · open-source"] +lang: "fr" +--- + +## what + +Des applications qui génèrent les codes à six chiffres qui changent toutes les 30 secondes, en + remplacement de Google Authenticator. + +## why + +Aegis (Android) garde vos codes dans un coffre chiffré local, sans cloud.{' '} + Ente Auth ajoute une synchronisation chiffrée de bout en bout entre appareils, et a été + audité. Bien plus sûrs que le SMS, et gratuits. + +## who + +Tout le monde : c'est le niveau de 2FA à adopter par défaut, avant les clés matérielles. + +## install + +
    +
  1. Installez Aegis (F-Droid) ou Ente Auth (toutes plateformes).
  2. +
  3. + Sur chaque compte, activez la 2FA « application d'authentification » et scannez le QR code + affiché. +
  4. +
  5. + Notez les codes de secours sur papier et faites une sauvegarde chiffrée de votre + coffre. +
  6. +
diff --git a/content/outils/alias.md b/content/outils/alias.md new file mode 100644 index 0000000..fdf8b21 --- /dev/null +++ b/content/outils/alias.md @@ -0,0 +1,36 @@ +--- +name: "SimpleLogin · addy.io" +slug: "alias" +category: "boiteaoutils" +difficulty: "beginner" +url: "https://simplelogin.io" +color: "#c0392b" +monogram: "@" +iconSlug: "simplelogin" +tags: ["Alias e-mail","🌍 · open-source"] +lang: "fr" +--- + +## what + +Des alias e-mail jetables : une adresse unique par site, qui redirige vers votre vraie boîte + sans jamais la révéler. + +## why + +Vous ne donnez plus votre vraie adresse partout. Si un site est piraté ou vous spamme, vous + coupez l'alias correspondant, et vous savez immédiatement qui a fait fuiter vos données.{' '} + SimpleLogin est intégré à Proton ; addy.io propose des alias illimités dès l'offre + gratuite. + +## who + +Tout le monde, et particulièrement les comptes pseudonymes qui veulent cloisonner leurs + inscriptions. + +## install + +
    +
  1. Créez un compte, installez l'extension de navigateur.
  2. +
  3. À chaque inscription, générez un nouvel alias au lieu de saisir votre vraie adresse.
  4. +
diff --git a/content/outils/backups.md b/content/outils/backups.md new file mode 100644 index 0000000..ac5a351 --- /dev/null +++ b/content/outils/backups.md @@ -0,0 +1,42 @@ +--- +name: "Sauvegardes chiffrées" +slug: "backups" +category: "boiteaoutils" +difficulty: "intermediate" +url: "https://cryptomator.org" +color: "#5a6570" +monogram: "Bk" +iconSlug: "cryptomator" +tags: ["Cryptomator · restic","🌍 · open-source"] +lang: "fr" +--- + +## what + +De quoi sauvegarder votre téléphone et votre ordinateur en chiffrant les données avant{' '} + qu'elles ne partent dans un cloud. + +## why + +Les sauvegardes iCloud/Google sont souvent accessibles au fournisseur, donc à la justice.{' '} + Cryptomator chiffre vos fichiers avant de les envoyer sur n'importe quel cloud ;{' '} + restic fait des sauvegardes chiffrées automatiques ; Proton Drive est chiffré de + bout en bout. Sur iPhone, activez la « Protection avancée des données » pour chiffrer vos + sauvegardes iCloud. + +## who + +Tout le monde devrait chiffrer ses sauvegardes. Règle d'or : deux copies chiffrées, sur deux + supports, en deux lieux. + +## install + +
    +
  1. + iPhone : Réglages > votre nom > iCloud > Protection avancée des données : activez-la. +
  2. +
  3. + PC : installez Cryptomator, créez un coffre, placez-y vos fichiers avant de synchroniser vers + le cloud. +
  4. +
diff --git a/content/outils/bitchat.md b/content/outils/bitchat.md new file mode 100644 index 0000000..3e288a7 --- /dev/null +++ b/content/outils/bitchat.md @@ -0,0 +1,34 @@ +--- +name: "Bitchat" +slug: "bitchat" +category: "messagerie" +difficulty: "advanced" +url: "https://bitchat.free" +color: "#e8871e" +monogram: "bit" +tags: ["Mesh Bluetooth","🌍 · open-source"] +lang: "fr" +--- + +## what + +La messagerie mesh de Jack Dorsey : les téléphones proches se relaient les messages de proche en + proche, sans internet ni serveur ni compte. + +## why + +Chiffrement de bout en bout (AES-256-GCM) et un « mode panique » qui efface tout en trois + tapotements sur le logo. + +## who + +Manifestations et blackout, en complément de Briar. À utiliser avec prudence. + +## install + +
    +
  1. Installez depuis l'App Store (iOS) ou l'APK/GitHub (Android).
  2. +
  3. Ouvrez l'application et choisissez un pseudo. Aucun compte à créer.
  4. +
  5. Les appareils proches se découvrent automatiquement en Bluetooth.
  6. +
  7. En cas de danger, triple-tapez le logo pour tout effacer (mode panique).
  8. +
diff --git a/content/outils/bitcoin.md b/content/outils/bitcoin.md new file mode 100644 index 0000000..e99aa2c --- /dev/null +++ b/content/outils/bitcoin.md @@ -0,0 +1,38 @@ +--- +name: "Bitcoin (auto-conservation)" +slug: "bitcoin" +category: "argent" +difficulty: "intermediate" +url: "https://bitcoin.org" +color: "#f7931a" +monogram: "₿" +iconSlug: "bitcoin" +tags: ["Résistant à la censure"] +lang: "fr" +--- + +## what + +Une monnaie numérique que vous détenez vous-même, sans passer par une banque. + +## why + +En auto-conservation (vos clés dans un portefeuille que vous seul contrôlez), personne ne + peut geler ni bloquer vos fonds. Sa confidentialité n'est pas parfaite (le registre est public), + mais il échappe à la censure bancaire, utile le jour où un paiement est refusé. + +## who + +Se prémunir contre le gel de compte ou la dé-bancarisation, et payer anonymement un service + comme un VPN. + +## install + +
    +
  1. Procurez-vous des bitcoins (plateforme d'échange, ou entre particuliers).
  2. +
  3. + Transférez-les aussitôt vers un portefeuille que vous contrôlez : un portefeuille + matériel (Trezor, ColdCard) ou une application libre. Ne les laissez pas sur la plateforme. +
  4. +
  5. Sauvegardez votre phrase de récupération sur papier, jamais en photo ni en ligne.
  6. +
diff --git a/content/outils/bitwarden.md b/content/outils/bitwarden.md new file mode 100644 index 0000000..f2fab57 --- /dev/null +++ b/content/outils/bitwarden.md @@ -0,0 +1,43 @@ +--- +name: "Bitwarden" +slug: "bitwarden" +category: "motsdepasse" +difficulty: "beginner" +license: "GPL-3.0" +url: "https://bitwarden.com" +color: "#175ddc" +monogram: "Bw" +iconSlug: "bitwarden" +tags: ["Le meilleur pour débuter","🌍 · open-source"] +lang: "fr" +--- + +## what + +Un coffre-fort à mots de passe qui les mémorise, les génère et les remplit pour vous, sur tous + vos appareils. + +## why + +Gratuit, audité, multiplateforme, et chiffré de bout en bout. Vous n'avez plus qu'un seul mot de + passe fort à retenir. Il est même auto-hébergeable (via Vaultwarden) pour ne dépendre de + personne. + +## who + +Tout le monde. C'est le point de départ de toute la sécurité : un mot de passe unique et fort + par service. + +## install + +
    +
  1. + Créez un compte sur bitwarden.com et choisissez un mot de passe maître long (une + phrase). Ne l'oubliez jamais : il n'est pas récupérable. +
  2. +
  3. Installez l'extension de navigateur et l'application mobile.
  4. +
  5. + Au fil de vos connexions, laissez Bitwarden enregistrer puis remplacer vos anciens mots de + passe par des mots de passe générés. +
  6. +
diff --git a/content/outils/brave.md b/content/outils/brave.md new file mode 100644 index 0000000..9cce23d --- /dev/null +++ b/content/outils/brave.md @@ -0,0 +1,44 @@ +--- +name: "Brave" +slug: "brave" +category: "navigateur" +difficulty: "beginner" +license: "MPL-2.0" +url: "https://brave.com" +color: "#fb542b" +monogram: "Bv" +iconSlug: "brave" +tags: ["Bloque tout par défaut","🌍 · open-source"] +lang: "fr" +--- + +## what + +Un navigateur basé sur Chromium qui bloque publicités et traqueurs par défaut, avec en prime une + fenêtre privée connectée à Tor. + +## why + +C'est l'option la plus simple pour quelqu'un qui vient de Chrome : même ergonomie, mais sans le + pistage. Il bloque les pubs YouTube nativement, propose une visio chiffrée (Brave Talk, basée + sur Jitsi) et un accès Tor en un clic, pratique pour récupérer un site bloqué. + +## who + +Les débutants qui veulent un changement indolore depuis Chrome. (Ignorez les fonctions + crypto/pubs récompensées si elles ne vous intéressent pas.) + +## install + +
    +
  1. + Installez Brave depuis brave.com. +
  2. +
  3. + Réglez les « Boucliers » (Shields) sur « agressif », et désactivez Brave Rewards si vous ne + voulez pas de pubs. +
  4. +
  5. + Pour Tor : menu > « Nouvelle fenêtre privée avec Tor », puis attendez « Tor connecté ». +
  6. +
diff --git a/content/outils/briar.md b/content/outils/briar.md new file mode 100644 index 0000000..cd93e98 --- /dev/null +++ b/content/outils/briar.md @@ -0,0 +1,42 @@ +--- +name: "Briar" +slug: "briar" +category: "messagerie" +difficulty: "advanced" +license: "GPL-3.0" +url: "https://briarproject.org" +color: "#c1272d" +monogram: "Br" +tags: ["Hors-ligne / P2P","Android · open-source"] +lang: "fr" +--- + +## what + +Une messagerie pair-à-pair qui fonctionne sans internet : par Bluetooth, Wi-Fi Direct ou + Tor. + +## why + +Aucun serveur, donc rien à couper ni à saisir. Résiste aux coupures d'internet et à la censure + réseau. + +## who + +Manifestations, catastrophes, zones isolées, blackout. Android uniquement, et les deux personnes + doivent avoir l'application. + +## install + +
    +
  1. + Installez depuis briarproject.org ou F-Droid (pas d'iOS). +
  2. +
  3. + Créez un compte local (pseudo + mot de passe), stocké seulement sur le téléphone. +
  4. +
  5. Ajoutez un contact proche en scannant son QR code, ou à distance via un lien.
  6. +
  7. + Quand le réseau est coupé, activez le Bluetooth : les messages passent d'appareil à appareil. +
  8. +
diff --git a/content/outils/cloudai.md b/content/outils/cloudai.md new file mode 100644 index 0000000..4ce7473 --- /dev/null +++ b/content/outils/cloudai.md @@ -0,0 +1,28 @@ +--- +name: "Duck.ai · Lumo (Proton)" +slug: "cloudai" +category: "ia" +difficulty: "beginner" +url: "https://duck.ai" +color: "#de5833" +monogram: "☁" +iconSlug: "duckduckgo" +tags: ["Cloud orienté vie privée"] +lang: "fr" +--- + +## what + +Des accès à l'IA dans le cloud, mais conçus pour la vie privée, quand une IA locale n'est pas + possible. + +## why + +Duck.ai (DuckDuckGo) donne un accès anonymisé à plusieurs modèles. Lumo (Proton) + chiffre les échanges et ne s'en sert pas pour entraîner. Bien mieux que ChatGPT grand public, + mais cela reste un serveur distant. + +## who + +Ceux qui veulent la commodité du cloud sans nourrir les géants. Gardez-y les sujets non + sensibles. diff --git a/content/outils/cloudflare.md b/content/outils/cloudflare.md new file mode 100644 index 0000000..bd9a1ea --- /dev/null +++ b/content/outils/cloudflare.md @@ -0,0 +1,30 @@ +--- +name: "Cloudflare 1.1.1.1 (à nuancer)" +slug: "cloudflare" +category: "dns" +difficulty: "beginner" +url: "https://one.one.one.one" +color: "#f38020" +monogram: "CF" +iconSlug: "cloudflare" +tags: ["Rapide mais centralisé","🇺🇸"] +lang: "fr" +--- + +## what + +Le DNS chiffré 1.1.1.1 et l'application WARP de Cloudflare : rapides, gratuits, et un vrai + progrès face au résolveur de votre FAI. + +## why + +C'est utile, avec un engagement de non-journalisation audité. Mais soyez lucide : Cloudflare se + trouve déjà devant une immense partie du web (comme intermédiaire technique, il peut voir le + trafic en clair vers ces sites). Y router aussi votre DNS revient à{' '} + concentrer encore plus de vos traces chez une seule entreprise américaine soumise au + droit américain. + +## who + +Bon pour un usage courant et le blocage des maliciels (1.1.1.1 for Families). À éviter ou à + diversifier pour un usage sensible : préférez alors Quad9 ou Mullvad DNS. diff --git a/content/outils/cryptomator.md b/content/outils/cryptomator.md new file mode 100644 index 0000000..5d71a80 --- /dev/null +++ b/content/outils/cryptomator.md @@ -0,0 +1,41 @@ +--- +name: "Cryptomator" +slug: "cryptomator" +category: "stockage" +difficulty: "intermediate" +license: "GPL-3.0" +url: "https://cryptomator.org" +color: "#26a69a" +monogram: "Cy" +iconSlug: "cryptomator" +tags: ["Chiffre avant l'envoi","🇩🇪 · open-source"] +lang: "fr" +--- + +## what + +Un coffre qui chiffre vos fichiers avant de les envoyer sur n'importe quel cloud, même + Google Drive ou Dropbox. + +## why + +L'astuce parfaite si vous devez garder un cloud existant : vous conservez le service pratique, + mais le fournisseur ne voit plus que du charabia chiffré. Vous gardez seul la clé. + +## who + +Ceux qui ne peuvent pas quitter un cloud grand public tout de suite, mais veulent protéger leurs + fichiers dès maintenant. + +## install + +
    +
  1. Installez Cryptomator (PC et mobile) depuis cryptomator.org.
  2. +
  3. + Créez un « coffre » dans le dossier synchronisé de votre cloud, choisissez un mot de passe + fort. +
  4. +
  5. + Placez vos fichiers dans le coffre : ils sont chiffrés puis synchronisés automatiquement. +
  6. +
diff --git a/content/outils/databrokers.md b/content/outils/databrokers.md new file mode 100644 index 0000000..fa8e67c --- /dev/null +++ b/content/outils/databrokers.md @@ -0,0 +1,41 @@ +--- +name: "Effacer ses données (RGPD)" +slug: "databrokers" +category: "boiteaoutils" +difficulty: "intermediate" +url: "https://www.cnil.fr" +color: "#b8860b" +monogram: "RG" +tags: ["Courtiers en données"] +lang: "fr" +--- + +## what + +Faire retirer vos informations personnelles des « courtiers en données » qui les collectent et + les revendent. + +## why + +En Europe, le RGPD (article 17) vous donne un droit à l'effacement : vous pouvez exiger, + gratuitement, qu'une entreprise supprime vos données, en principe sous un mois. Des services + comme Incogni automatisent ces demandes en masse, moyennant paiement. + +## who + +Ceux qui veulent réduire leur exposition. Attention : les données réapparaissent avec le temps, + et cela ne touche ni les registres publics ni les réseaux sociaux. Le faire soi-même est gratuit + mais fastidieux. + +## install + +
    +
  1. + Pour une demande manuelle : écrivez au courtier en invoquant l'article 17 du RGPD et demandez + la suppression. +
  2. +
  3. + Pour automatiser : souscrivez à un service de retrait et laissez-le envoyer les demandes en + votre nom. +
  4. +
diff --git a/content/outils/element.md b/content/outils/element.md new file mode 100644 index 0000000..5fe8185 --- /dev/null +++ b/content/outils/element.md @@ -0,0 +1,39 @@ +--- +name: "Matrix / Element" +slug: "element" +category: "social" +difficulty: "intermediate" +url: "https://element.io" +color: "#0dbd8b" +monogram: "El" +iconSlug: "element" +tags: ["Remplace Discord / Slack","🌍 · fédéré · E2EE"] +lang: "fr" +--- + +## what + +Une messagerie de communautés, dans l'esprit de Discord ou Slack, mais fédérée et chiffrable de + bout en bout. Element est l'application, Matrix le réseau. + +## why + +Vous pouvez héberger votre propre serveur (Synapse) et contrôler vos données. Parfait pour un + collectif, une rédaction, une association qui veut son espace indépendant. + +## who + +Communautés et groupes. Voir la nuance sur les métadonnées ci-dessous. + +## install + +
    +
  1. + Installez Element (element.io) et créez un compte sur un serveur public, ou sur le vôtre + (section 10). +
  2. +
  3. + Rejoignez ou créez des salons, et activez le chiffrement de bout en bout pour les + conversations privées. +
  4. +
diff --git a/content/outils/fediverse.md b/content/outils/fediverse.md new file mode 100644 index 0000000..e44ebb5 --- /dev/null +++ b/content/outils/fediverse.md @@ -0,0 +1,25 @@ +--- +name: "Pixelfed · PeerTube · Lemmy" +slug: "fediverse" +category: "social" +difficulty: "intermediate" +url: "https://pixelfed.org" +color: "#ea580c" +monogram: "Pi" +iconSlug: "pixelfed" +tags: ["Insta · YouTube · Reddit","🌍 · open-source"] +lang: "fr" +--- + +## what + +Les cousins fédérés d'Instagram (Pixelfed), de YouTube (PeerTube) et de Reddit (Lemmy). + +## why + +Même logique que Mastodon : pas de propriétaire unique, pas d'algorithme publicitaire, pas de + traçage. Vous publiez photos, vidéos ou discussions sans nourrir une machine à profiler. + +## who + +Ceux qui veulent quitter Instagram, YouTube ou Reddit sans renoncer au format. diff --git a/content/outils/firefox.md b/content/outils/firefox.md new file mode 100644 index 0000000..6f85150 --- /dev/null +++ b/content/outils/firefox.md @@ -0,0 +1,42 @@ +--- +name: "Firefox (durci)" +slug: "firefox" +category: "navigateur" +difficulty: "beginner" +license: "MPL-2.0" +url: "https://www.mozilla.org/firefox" +color: "#e66000" +monogram: "Fx" +iconSlug: "firefoxbrowser" +tags: ["Remplace Chrome","🌍 · open-source"] +lang: "fr" +--- + +## what + +Le navigateur libre de référence pour un usage quotidien respectueux de la vie privée. + +## why + +Contrairement à Chrome (un mouchard publicitaire de Google), Firefox est développé par une + fondation et n'a pas d'intérêt à vous profiler. Avec quelques réglages (le guide{' '} + arkenfox) et l'extension uBlock Origin, il devient très solide. + +## who + +Tout le monde, comme navigateur principal au quotidien. + +## install + +
    +
  1. + Installez Firefox depuis mozilla.org/firefox. +
  2. +
  3. + Ajoutez l'extension uBlock Origin (blocage des pubs et traqueurs). +
  4. +
  5. + Dans les réglages de vie privée, choisissez « Stricte », désactivez la télémétrie, et videz + les cookies à la fermeture. Pour aller plus loin, appliquez le guide arkenfox. +
  6. +
diff --git a/content/outils/grapheneos.md b/content/outils/grapheneos.md new file mode 100644 index 0000000..4dba926 --- /dev/null +++ b/content/outils/grapheneos.md @@ -0,0 +1,50 @@ +--- +name: "GrapheneOS" +slug: "grapheneos" +category: "os" +difficulty: "advanced" +license: "MIT" +url: "https://grapheneos.org" +color: "#1f8a70" +monogram: "Gr" +iconSlug: "grapheneos" +tags: ["Mobile dégooglisé","Android · Pixel · open-source"] +lang: "fr" +--- + +## what + +Un Android entièrement dégooglisé, installé sur un téléphone Pixel : la souveraineté sur mobile. + +## why + +C'est la défense structurelle par excellence contre un OS ou un magasin d'applications qui + voudrait vous scanner. Services Google en bac à sable optionnel,{' '} + permissions réseau par application, profils cloisonnés, redémarrage automatique qui purge + les clés de la mémoire, code PIN de contrainte qui efface le téléphone. Réputé pour sa sécurité + au point d'être utilisé par des cibles de logiciels espions. + +## who + +Profils exposés, mais aussi tout citoyen prêt à acheter un Pixel pour reprendre le contrôle de + son téléphone. + +## install + +
    +
  1. + Procurez-vous un téléphone Google Pixel compatible (c'est le seul matériel supporté, + pour des raisons de sécurité). +
  2. +
  3. + Sur un ordinateur, allez sur grapheneos.org/install et suivez l'installeur web + (quelques clics, aucun terminal requis). +
  4. +
  5. + Pour vos applications, installez le magasin libre F-Droid ; ajoutez Google Play en bac à sable + seulement si nécessaire. +
  6. +
  7. + Réglez un long mot de passe (pas un code à 4 chiffres) et découvrez le mode « Lockdown ». +
  8. +
diff --git a/content/outils/ivpn.md b/content/outils/ivpn.md new file mode 100644 index 0000000..d412dab --- /dev/null +++ b/content/outils/ivpn.md @@ -0,0 +1,40 @@ +--- +name: "IVPN" +slug: "ivpn" +category: "vpn" +difficulty: "intermediate" +url: "https://www.ivpn.net" +color: "#3b5bdb" +monogram: "iv" +tags: ["Sans e-mail · no-log","🇬🇮 · open-source"] +lang: "fr" +--- + +## what + +Un petit fournisseur de VPN particulièrement rigoureux et transparent, sur le même modèle que + Mullvad. + +## why + +Politique no-log auditée, pas d'e-mail obligatoire, paiement en crypto ou en espèces. Il propose + même des options anti-traçage (blocage des trackers au niveau réseau) et une inscription sans + aucun identifiant. + +## who + +Une alternative solide à Mullvad, pour les profils pseudonymes et à haut risque qui veulent + diversifier. + +## install + +
    +
  1. + Sur ivpn.net, générez un compte (un identifiant est créé pour vous, sans e-mail). +
  2. +
  3. Payez en cryptomonnaie ou en espèces, comme pour Mullvad.
  4. +
  5. + Installez l'application, connectez-vous hors UE, activez le kill switch et le protocole + WireGuard. +
  6. +
diff --git a/content/outils/keepassxc.md b/content/outils/keepassxc.md new file mode 100644 index 0000000..552185e --- /dev/null +++ b/content/outils/keepassxc.md @@ -0,0 +1,38 @@ +--- +name: "KeePassXC" +slug: "keepassxc" +category: "motsdepasse" +difficulty: "advanced" +license: "GPL-2.0/3.0" +url: "https://keepassxc.org" +color: "#2c6b9e" +monogram: "Kp" +iconSlug: "keepassxc" +tags: ["100% local","🌍 · open-source"] +lang: "fr" +--- + +## what + +Un coffre-fort local : un fichier chiffré que vous seul détenez, sans aucun cloud ni + compte. + +## why + +Rien ne quitte votre appareil, sauf si vous décidez de synchroniser le fichier vous-même (par + exemple via Cryptomator). C'est le choix des puristes qui ne veulent aucun intermédiaire. + +## who + +Les profils avancés qui veulent le contrôle total et zéro dépendance en ligne. + +## install + +
    +
  1. + Installez KeePassXC (PC) et une application compatible sur mobile (KeePassDX sur Android, + Strongbox sur iOS). +
  2. +
  3. Créez un fichier de base de données protégé par un mot de passe maître.
  4. +
  5. Pour l'avoir sur tous vos appareils, synchronisez ce fichier via un cloud chiffré.
  6. +
diff --git a/content/outils/linux.md b/content/outils/linux.md new file mode 100644 index 0000000..4e04d14 --- /dev/null +++ b/content/outils/linux.md @@ -0,0 +1,53 @@ +--- +name: "Linux (sur ordinateur)" +slug: "linux" +category: "os" +difficulty: "intermediate" +url: "https://distrochooser.de/fr" +color: "#2b2b2b" +monogram: "🐧" +iconSlug: "linux" +tags: ["Remplace Windows / macOS","🌍 · libre & gratuit"] +lang: "fr" +--- + +## what + +Un système d'exploitation libre et gratuit pour votre ordinateur, en remplacement de Windows ou + de macOS. Il en existe de nombreuses variantes, appelées « distributions ». + +## why + +C'est le point aveugle de beaucoup de gens : ils chiffrent leurs messages mais gardent un + Windows qui transmet en continu de la télémétrie à Microsoft (et dont la fonction « Recall » a + voulu photographier l'écran en permanence), ou un macOS qui signale les applications que vous + lancez. Linux, lui, ne vous espionne pas, il est gratuit, il ressuscite les vieux ordinateurs et + il vous rend enfin maître de votre machine. C'est plus facile que sa réputation : les + distributions modernes ressemblent à Windows ou macOS. + +## who + +Tout le monde peut franchir le pas. Pour débuter, Linux Mint (le plus proche de Windows) + ou Fedora ; Debian pour la stabilité. Pas besoin de tout casser : on peut d'abord + tester, puis installer à côté de son système actuel. + +## install + +
    +
  1. + Pas sûr de la distribution ? Répondez au questionnaire distrochooser.de/fr, qui vous + oriente selon vos besoins. +
  2. +
  3. + Testez-la sans rien installer directement dans votre navigateur sur{' '} + distrosea.com. +
  4. +
  5. + Une fois convaincu, téléchargez l'image de la distribution et créez une clé USB de démarrage + (avec Ventoy ou Balena Etcher). +
  6. +
  7. + Démarrez sur la clé pour essayer le système « en live », puis lancez l'installation. Activez + le chiffrement du disque proposé. +
  8. +
diff --git a/content/outils/localai.md b/content/outils/localai.md new file mode 100644 index 0000000..926d803 --- /dev/null +++ b/content/outils/localai.md @@ -0,0 +1,46 @@ +--- +name: "Ollama · LM Studio · Jan · GPT4All" +slug: "localai" +category: "ia" +difficulty: "intermediate" +url: "https://lmstudio.ai" +color: "#111111" +monogram: "Ai" +iconSlug: "ollama" +tags: ["Remplace ChatGPT","🌍 · 100% local"] +lang: "fr" +--- + +## what + +Des logiciels pour faire tourner un modèle d'intelligence artificielle directement sur votre + ordinateur. + +## why + +Vos questions ne quittent jamais l'appareil : aucun serveur, aucun compte, aucune télémétrie, et + ça marche hors ligne. La qualité dépend de votre matériel, mais rien ne fuit. Ollama et{' '} + LM Studio sont les plus simples ; Jan et GPT4All visent la vie privée + maximale. + +## who + +Tous ceux qui utilisent l'IA pour des sujets un tant soit peu personnels et ne veulent pas les + confier à un serveur américain. + +## install + +
    +
  1. + Pour débuter en douceur, installez LM Studio ou Jan (interface graphique, comme + une application classique). +
  2. +
  3. + Téléchargez un modèle proposé dans l'application (par exemple Llama ou Mistral), adapté à la + puissance de votre machine. +
  4. +
  5. + Discutez : tout se passe en local. Ollama est la version en ligne de commande pour les plus + techniques. +
  6. +
diff --git a/content/outils/mailbox.md b/content/outils/mailbox.md new file mode 100644 index 0000000..dd05b0f --- /dev/null +++ b/content/outils/mailbox.md @@ -0,0 +1,33 @@ +--- +name: "mailbox.org · Posteo" +slug: "mailbox" +category: "email" +difficulty: "beginner" +url: "https://mailbox.org" +color: "#2470d4" +monogram: "mx" +tags: ["Mail classique éthique","🇩🇪 · UE · PGP"] +lang: "fr" +--- + +## what + +Deux fournisseurs de mail européens, éthiques et peu coûteux, avec support PGP côté serveur. + +## why + +Respectueux de la vie privée et de l'écologie, sur des standards ouverts (IMAP, PGP). Ils + fonctionnent avec n'importe quel logiciel de messagerie. + +## who + +Ceux qui veulent un mail « classique » (relevé dans Thunderbird) mais éthique, plutôt qu'une + messagerie chiffrée fermée. + +## install + +
    +
  1. Créez un compte (payant, de l'ordre de 1 à 3 € par mois).
  2. +
  3. Activez le chiffrement PGP côté serveur (fonction « Guard » chez mailbox.org).
  4. +
  5. Configurez le compte dans Thunderbird ou l'application mobile de votre choix.
  6. +
diff --git a/content/outils/maps.md b/content/outils/maps.md new file mode 100644 index 0000000..d60bab9 --- /dev/null +++ b/content/outils/maps.md @@ -0,0 +1,37 @@ +--- +name: "Organic Maps · OsmAnd" +slug: "maps" +category: "boiteaoutils" +difficulty: "beginner" +url: "https://organicmaps.app" +color: "#0a7d33" +monogram: "Om" +iconSlug: "openstreetmap" +tags: ["Remplace Google Maps","🌍 · open-source"] +lang: "fr" +--- + +## what + +Des applications de cartes et de navigation, fondées sur OpenStreetMap, qui fonctionnent hors + ligne. + +## why + +Google Maps enregistre chacun de vos trajets et bâtit un historique de lieux d'une précision + redoutable. Organic Maps ne trace rien et n'affiche aucune publicité ; OsmAnd vise + les utilisateurs avancés (randonnée, courbes de niveau, navigation détaillée). + +## who + +Tout le monde. Le trafic en temps réel et les transports sont moins complets que chez Google, + mais la navigation quotidienne est excellente. + +## install + +
    +
  1. Installez depuis F-Droid, l'App Store ou Google Play.
  2. +
  3. + Téléchargez à l'avance les cartes des régions qui vous intéressent pour l'usage hors ligne. +
  4. +
diff --git a/content/outils/mastodon.md b/content/outils/mastodon.md new file mode 100644 index 0000000..0373690 --- /dev/null +++ b/content/outils/mastodon.md @@ -0,0 +1,41 @@ +--- +name: "Mastodon" +slug: "mastodon" +category: "social" +difficulty: "beginner" +license: "AGPL-3.0" +url: "https://joinmastodon.org" +color: "#6364ff" +monogram: "Ma" +iconSlug: "mastodon" +tags: ["Remplace X / Twitter","🌍 · open-source"] +lang: "fr" +--- + +## what + +L'alternative à X/Twitter : un réseau social fait de milliers de serveurs indépendants qui + communiquent entre eux (le « fédiverse »). + +## why + +Pas de patron unique, pas d'algorithme qui décide à votre place, pas de bannissement arbitraire + par une seule entreprise. Le fil est chronologique, sans publicité ni manipulation. + +## who + +Tout le monde. Idéal pour les comptes d'information qui veulent une présence qu'aucune + entreprise ne peut couper. + +## install + +
    +
  1. + Sur joinmastodon.org, choisissez un serveur (ou « instance ») qui vous correspond, puis créez + un compte. +
  2. +
  3. + Installez une application (l'officielle, ou Ivory, Tusky…) et suivez des comptes : vous voyez + tout le fédiverse, quel que soit leur serveur. +
  4. +
diff --git a/content/outils/molly.md b/content/outils/molly.md new file mode 100644 index 0000000..1445f7d --- /dev/null +++ b/content/outils/molly.md @@ -0,0 +1,39 @@ +--- +name: "Molly" +slug: "molly" +category: "messagerie" +difficulty: "advanced" +license: "GPL-3.0" +url: "https://molly.im" +color: "#6d4bb3" +monogram: "M" +tags: ["Signal durci","Android · open-source"] +lang: "fr" +--- + +## what + +Une version durcie de Signal pour Android, compatible avec le même réseau. + +## why + +Base de données chiffrée au repos, verrouillage automatique, et une variante « FOSS » + entièrement sans services Google. + +## who + +Utilisateurs avancés, notamment sur GrapheneOS, avec un modèle de menace élevé. Android + uniquement. + +## install + +
    +
  1. + Ajoutez le dépôt Molly dans F-Droid, ou récupérez l'APK sur molly.im. +
  2. +
  3. + Choisissez Molly-FOSS si vous voulez zéro dépendance Google. +
  4. +
  5. Enregistrez-vous avec votre numéro (même réseau que Signal).
  6. +
  7. Définissez un mot de passe de base de données et le verrouillage automatique.
  8. +
diff --git a/content/outils/monero.md b/content/outils/monero.md new file mode 100644 index 0000000..39a41e6 --- /dev/null +++ b/content/outils/monero.md @@ -0,0 +1,39 @@ +--- +name: "Monero (XMR)" +slug: "monero" +category: "argent" +difficulty: "advanced" +license: "BSD-3-Clause" +url: "https://www.getmonero.org" +color: "#ff6600" +monogram: "ɱ" +iconSlug: "monero" +tags: ["Confidentiel par défaut"] +lang: "fr" +--- + +## what + +La cryptomonnaie de la vie privée : montants, expéditeur et destinataire sont masqués par + défaut. + +## why + +C'est l'exact opposé de Bitcoin sur ce point : les transactions sont confidentielles par + conception. C'est le meilleur moyen de payer un service sans laisser de trace reliable à vous. + +## who + +Ceux qui veulent le maximum de confidentialité financière. Note : Monero est déjà retiré de + plusieurs plateformes en Europe, il faut souvent passer par un échange décentralisé. + +## install + +
    +
  1. Installez un portefeuille (l'officiel sur getmonero.org, ou Cake Wallet sur mobile).
  2. +
  3. + Obtenez des XMR via un service d'échange décentralisé (par exemple un « swap » depuis une + autre crypto). +
  4. +
  5. Sauvegardez votre phrase de récupération sur papier.
  6. +
diff --git a/content/outils/mullvad.md b/content/outils/mullvad.md new file mode 100644 index 0000000..71d2ca0 --- /dev/null +++ b/content/outils/mullvad.md @@ -0,0 +1,62 @@ +--- +name: "Mullvad VPN" +slug: "mullvad" +category: "vpn" +difficulty: "beginner" +url: "https://mullvad.net" +color: "#2b4b8f" +monogram: "Mv" +iconSlug: "mullvad" +tags: ["Sans compte · cash/Monero","🇸🇪 · open-source"] +lang: "fr" +--- + +## what + +Un VPN qui masque votre adresse IP et chiffre votre trafic jusqu'à ses serveurs, sans jamais + vous demander la moindre information personnelle. + +## why + +C'est l'étalon-or de la vie privée. Pas d'e-mail, pas de nom : à l'inscription, on vous attribue + un simple numéro de compte. Politique « no-log » auditée, prix unique et honnête (5 € par mois, + sans palier ni fausse promesse), et paiement possible en espèces ou en Monero. C'est précisément + ce qui compte le jour où un État tente de couper l'accès aux VPN : un compte impossible à relier + à votre identité, et un paiement que les banques ne peuvent pas bloquer. + +## who + +Tout le monde, du citoyen qui veut contourner une vérification d'identité au profil à haut + risque. C'est le VPN à recommander en priorité. + +## install + +
    +
  1. + Allez sur mullvad.net. Si le site est bloqué dans votre pays, ouvrez-le via le + navigateur Tor ou son adresse .onion. Cliquez sur « Générer un numéro de compte » : + aucun e-mail ni nom n'est demandé. Notez ce numéro dans votre gestionnaire de mots de passe et + ne le partagez jamais, c'est votre unique clé d'accès. +
  2. +
  3. + Choisissez la durée et le mode de paiement. Le prix est fixe. Trois voies : carte bancaire (le + plus simple si elle n'est pas bloquée), espèces envoyées par courrier, ou cryptomonnaie. +
  4. +
  5. + Paiement anonyme en crypto : cliquez sur « Créer une adresse de paiement à usage unique + ». Mullvad affiche une adresse (Bitcoin ou Monero) et un montant exact. Envoyez ce montant + depuis votre portefeuille. Pour l'anonymat maximal, préférez Monero (confidentiel par + défaut) ; Bitcoin est plus simple mais traçable. Voir la section 09 pour acheter de la crypto. + Comptez environ 30 minutes de confirmation. +
  6. +
  7. + Téléchargez l'application sur mullvad.net/download (via Tor si le site est filtré) et + installez-la. Sur mobile, passez par l'App Store, Google Play, ou l'APK officiel si + l'application a été retirée de votre magasin. +
  8. +
  9. + Lancez l'application, entrez votre numéro de compte, puis connectez-vous à un serveur situé{' '} + hors de votre pays, idéalement hors Union européenne (Suisse, États-Unis…). Activez le + « kill switch » (qui coupe Internet si le VPN tombe) et le DNS de Mullvad. +
  10. +
diff --git a/content/outils/mullvadbrowser.md b/content/outils/mullvadbrowser.md new file mode 100644 index 0000000..461fa75 --- /dev/null +++ b/content/outils/mullvadbrowser.md @@ -0,0 +1,41 @@ +--- +name: "Mullvad Browser" +slug: "mullvadbrowser" +category: "navigateur" +difficulty: "intermediate" +url: "https://mullvad.net/browser" +color: "#2b4b8f" +monogram: "Mb" +iconSlug: "mullvad" +tags: ["Anti-empreinte","🇸🇪 · open-source"] +lang: "fr" +--- + +## what + +Le navigateur du Tor Browser, mais sans le réseau Tor : à utiliser avec votre VPN pour un + ordinateur difficile à pister. + +## why + +Développé avec le Tor Project, il est conçu pour que tous ses utilisateurs présentent la{' '} + même empreinte numérique. Résultat : au lieu d'être unique et donc traçable, vous vous + fondez dans la masse. C'est le meilleur choix de vie privée sur ordinateur. + +## who + +Ceux qui veulent aller au-delà du simple blocage de pub, notamment les comptes pseudonymes et + les profils exposés. + +## install + +
    +
  1. + Téléchargez-le sur mullvad.net/browser (Windows, macOS, Linux). +
  2. +
  3. + Utilisez-le tel quel, sans le personnaliser : chaque extension ou réglage ajouté vous rend à + nouveau identifiable. +
  4. +
  5. Associez-le à votre VPN pour masquer aussi votre adresse IP.
  6. +
diff --git a/content/outils/mullvaddns.md b/content/outils/mullvaddns.md new file mode 100644 index 0000000..d055539 --- /dev/null +++ b/content/outils/mullvaddns.md @@ -0,0 +1,40 @@ +--- +name: "Mullvad DNS · NextDNS" +slug: "mullvaddns" +category: "dns" +difficulty: "intermediate" +url: "https://mullvad.net/help/dns-over-https-and-dns-over-tls" +color: "#2b4b8f" +monogram: "DNS" +iconSlug: "mullvad" +tags: ["Filtrage réseau"] +lang: "fr" +--- + +## what + +Deux résolveurs chiffrés qui bloquent en plus pubs et traqueurs pour tout l'appareil. + +## why + +Mullvad DNS (Suède, no-log) est gratuit et propose des listes de blocage. NextDNS{' '} + est très personnalisable, avec un tableau de bord et des profils par appareil, mais il est basé + aux États-Unis et journalise par défaut (à désactiver dans les réglages). + +## who + +Ceux qui veulent un blocage des pubs à l'échelle du système, sans installer d'application par + navigateur. + +## install + +
    +
  1. + Mullvad DNS : utilisez l'adresse indiquée sur mullvad.net/help/dns comme DNS privé (même + méthode que Quad9). +
  2. +
  3. + NextDNS : créez un profil sur nextdns.io, désactivez la journalisation, puis appliquez + la configuration à vos appareils. +
  4. +
diff --git a/content/outils/nc-storage.md b/content/outils/nc-storage.md new file mode 100644 index 0000000..31b50ca --- /dev/null +++ b/content/outils/nc-storage.md @@ -0,0 +1,25 @@ +--- +name: "Nextcloud" +slug: "nc-storage" +category: "stockage" +difficulty: "advanced" +url: "https://nextcloud.com" +color: "#0082c9" +monogram: "Nc" +iconSlug: "nextcloud" +tags: ["Votre propre cloud","🌍 · open-source"] +lang: "fr" +--- + +## what + +Votre propre nuage (fichiers, agenda, contacts, notes) hébergé sur votre serveur. + +## why + +Le degré ultime de contrôle : vos données ne quittent jamais votre matériel. Détaillé dans la + section 10 (Auto-hébergement). + +## who + +Les auto-hébergeurs. Voir la fiche complète en section 10. diff --git a/content/outils/nextcloud.md b/content/outils/nextcloud.md new file mode 100644 index 0000000..10bacf3 --- /dev/null +++ b/content/outils/nextcloud.md @@ -0,0 +1,29 @@ +--- +name: "Nextcloud" +slug: "nextcloud" +category: "selfhost" +difficulty: "advanced" +license: "AGPL-3.0" +url: "https://nextcloud.com" +color: "#0082c9" +monogram: "Nc" +iconSlug: "nextcloud" +tags: ["Remplace toute la suite Google","🇩🇪 · open-source"] +lang: "fr" +--- + +## what + +Votre propre nuage : fichiers, agenda, contacts, photos, notes et documents collaboratifs, sur + votre serveur. + +## why + +C'est le remplacement complet de Google Drive, Agenda et Contacts, mais chez vous. Vous décidez + de la juridiction et personne d'autre n'a la main sur vos fichiers. À savoir : c'est la + confidentialité « votre serveur », pas un chiffrement de bout en bout par défaut ; vous devez le + maintenir à jour. + +## who + +Les auto-hébergeurs. Le plus simple est de l'installer via YunoHost ou Umbrel. diff --git a/content/outils/nostr.md b/content/outils/nostr.md new file mode 100644 index 0000000..a507730 --- /dev/null +++ b/content/outils/nostr.md @@ -0,0 +1,39 @@ +--- +name: "Nostr" +slug: "nostr" +category: "social" +difficulty: "intermediate" +url: "https://nostr.com" +color: "#8e30eb" +monogram: "No" +tags: ["Incensurable","🌍 · protocole ouvert"] +lang: "fr" +--- + +## what + +Pas une application mais un protocole : un réseau social où votre identité est une simple paire + de clés, comme pour Bitcoin. + +## why + +Zéro e-mail, zéro mot de passe, aucun compte qu'on puisse supprimer. Vos messages voyagent sur + des relais décentralisés et vous possédez vraiment votre audience : personne ne peut vous bannir + durablement. Vous pouvez même recevoir des pourboires en Bitcoin (les « zaps ») et changer + d'application quand vous voulez sans perdre vos abonnés. + +## who + +Comptes d'information et créateurs qui craignent la censure de plateforme et veulent une + présence vraiment à eux. + +## install + +
    +
  1. Installez un client : Damus (iPhone), Amethyst ou Primal (Android), ou une version web.
  2. +
  3. + L'application génère votre paire de clés. Sauvegardez votre clé privée (nsec) comme une + phrase de récupération Bitcoin : sur papier, jamais partagée. +
  4. +
  5. Créez votre profil, suivez des gens, activez les zaps pour recevoir des sats.
  6. +
diff --git a/content/outils/notes.md b/content/outils/notes.md new file mode 100644 index 0000000..5968a82 --- /dev/null +++ b/content/outils/notes.md @@ -0,0 +1,37 @@ +--- +name: "Standard Notes · Joplin · CryptPad" +slug: "notes" +category: "boiteaoutils" +difficulty: "beginner" +url: "https://standardnotes.com" +color: "#2e7d6b" +monogram: "No" +tags: ["Remplace Docs / Notion","🌍 · open-source"] +lang: "fr" +--- + +## what + +Des notes et documents chiffrés de bout en bout, pour remplacer Google Docs, Notion ou Evernote. + +## why + +Standard Notes (par Proton) chiffre vos notes par défaut. Joplin gère des carnets + en Markdown avec chiffrement optionnel et la synchronisation de votre choix. CryptPad{' '} + (français) offre l'équivalent de Google Docs en temps réel, entièrement chiffré. + +## who + +Tout le monde pour les notes ; CryptPad pour la collaboration à plusieurs. + +## install + +
    +
  1. + Standard Notes / Joplin : créez un compte, installez l'application, et activez le chiffrement + (par défaut sur Standard Notes, à activer dans Joplin). +
  2. +
  3. + CryptPad : utilisez cryptpad.fr ou une autre instance, aucun compte requis pour commencer. +
  4. +
diff --git a/content/outils/photos.md b/content/outils/photos.md new file mode 100644 index 0000000..6f59248 --- /dev/null +++ b/content/outils/photos.md @@ -0,0 +1,41 @@ +--- +name: "Ente · Immich" +slug: "photos" +category: "boiteaoutils" +difficulty: "intermediate" +url: "https://ente.io" +color: "#7b3fbf" +monogram: "Ph" +iconSlug: "immich" +tags: ["Remplace Google Photos","🌍 · open-source"] +lang: "fr" +--- + +## what + +Deux façons de garder vos photos sans les confier à Google ou Apple. + +## why + +Ente est un service géré, chiffré de bout en bout, avec reconnaissance et recherche + faites sur l'appareil : simple et sûr. Immich est un clone de Google Photos que vous{' '} + hébergez vous-même (recherche par visages et objets incluse), à réserver à ceux qui + savent gérer un serveur. + +## who + +Ente pour tous ; Immich pour les auto-hébergeurs. Attention : Immich n'est pas chiffré de bout + en bout, sa sécurité dépend de votre serveur. + +## install + +
    +
  1. + Ente : installez l'application, créez un compte, activez la sauvegarde automatique de votre + pellicule. +
  2. +
  3. + Immich : déployez-le sur votre serveur (voir section 10) via Docker, puis connectez + l'application mobile. +
  4. +
diff --git a/content/outils/pihole.md b/content/outils/pihole.md new file mode 100644 index 0000000..73aedba --- /dev/null +++ b/content/outils/pihole.md @@ -0,0 +1,39 @@ +--- +name: "Pi-hole · AdGuard Home" +slug: "pihole" +category: "dns" +difficulty: "advanced" +url: "https://pi-hole.net" +color: "#96060c" +monogram: "π" +iconSlug: "pihole" +tags: ["Blocage tout le réseau","🌍 · open-source"] +lang: "fr" +--- + +## what + +Un bloqueur de publicités et de traqueurs qui protège tout votre réseau à la fois, + installé sur un petit ordinateur comme un Raspberry Pi. + +## why + +Là où uBlock Origin protège un navigateur, Pi-hole filtre chaque appareil de la maison, y + compris ceux où l'on ne peut pas installer d'extension : téléphones, téléviseurs connectés, + objets connectés. Les pubs et traqueurs sont bloqués au niveau du DNS, avant même de se charger.{' '} + AdGuard Home est une alternative à l'interface plus moderne. + +## who + +Les foyers qui veulent nettoyer tous leurs appareils d'un coup, et qui ont (ou veulent) un + Raspberry Pi ou un petit serveur. + +## install + +
    +
  1. Sur un Raspberry Pi (ou un conteneur), lancez l'installeur officiel de Pi-hole.
  2. +
  3. + Dans les réglages de votre box/routeur, indiquez l'adresse du Pi-hole comme serveur DNS. +
  4. +
  5. Désormais, tous les appareils connectés à votre réseau sont filtrés automatiquement.
  6. +
diff --git a/content/outils/pocketpal.md b/content/outils/pocketpal.md new file mode 100644 index 0000000..1295076 --- /dev/null +++ b/content/outils/pocketpal.md @@ -0,0 +1,41 @@ +--- +name: "PocketPal AI" +slug: "pocketpal" +category: "ia" +difficulty: "intermediate" +license: "MIT" +url: "https://pocketpal.dev" +color: "#6b4eff" +monogram: "Pp" +tags: ["Remplace ChatGPT sur mobile","📱 · 100% local"] +lang: "fr" +--- + +## what + +Une application pour faire tourner des modèles d'IA directement sur votre téléphone, entièrement + hors ligne. + +## why + +Vos requêtes ne quittent jamais le téléphone : aucun compte, aucun cloud, aucune télémétrie, et + ça marche en mode avion. Open source (MIT), l'appli télécharge des modèles GGUF (Gemma, + Qwen, Phi, Llama) depuis Hugging Face et les exécute sur le CPU, le GPU ou le NPU de l'appareil. + Le pendant mobile d'Ollama et LM Studio. + +## who + +Tous ceux qui dégainent ChatGPT sur leur téléphone pour des questions personnelles et ne veulent + pas les confier à un serveur américain. + +## install + +
    +
  1. + Installez PocketPal depuis l'App Store ou Google Play (ou compilez les sources). +
  2. +
  3. + Ouvrez Models, choisissez un modèle adapté à votre téléphone et téléchargez-le. +
  4. +
  5. Chargez-le et discutez : tout tourne hors ligne, sur l'appareil.
  6. +
diff --git a/content/outils/protondrive.md b/content/outils/protondrive.md new file mode 100644 index 0000000..4439e8d --- /dev/null +++ b/content/outils/protondrive.md @@ -0,0 +1,32 @@ +--- +name: "Proton Drive" +slug: "protondrive" +category: "stockage" +difficulty: "beginner" +url: "https://proton.me/drive" +color: "#6d4aff" +monogram: "Pd" +iconSlug: "protondrive" +tags: ["Remplace Google Drive / iCloud","🇨🇭 · E2EE"] +lang: "fr" +--- + +## what + +Un cloud chiffré de bout en bout pour vos fichiers et vos photos, intégré à Proton. + +## why + +Contrairement à Google Drive ou iCloud, Proton ne peut pas lire vos fichiers : ils sont chiffrés + avant de quitter votre appareil. Juridiction suisse, même compte que Proton Mail. + +## who + +Tout le monde, comme remplacement direct et simple du cloud de Google ou d'Apple. + +## install + +
    +
  1. Activez Proton Drive dans votre compte Proton et installez l'application.
  2. +
  3. Activez la sauvegarde automatique de vos photos, puis désactivez celle de Google/Apple.
  4. +
diff --git a/content/outils/protonmail.md b/content/outils/protonmail.md new file mode 100644 index 0000000..7f163ed --- /dev/null +++ b/content/outils/protonmail.md @@ -0,0 +1,43 @@ +--- +name: "Proton Mail" +slug: "protonmail" +category: "email" +difficulty: "beginner" +url: "https://proton.me/mail" +color: "#6d4aff" +monogram: "Pm" +iconSlug: "protonmail" +tags: ["Remplace Gmail","🇨🇭 · open-source · OpenPGP"] +lang: "fr" +--- + +## what + +Une boîte mail chiffrée qui remplace Gmail ou Outlook, et le compte pivot de tout l'écosystème + Proton. + +## why + +Basé en Suisse, hors juridiction des « Five Eyes ». Compatible OpenPGP : chiffrement automatique + entre comptes Proton et vers les autres services PGP. + +## who + +Tout le monde. C'est le meilleur point de départ pour quitter Google (voir section 05 pour le + reste de la suite). + +## install + +
    +
  1. + Créez un compte sur proton.me (offre gratuite suffisante pour commencer). +
  2. +
  3. + Importez vos anciens messages et contacts avec Easy Switch (intégré). +
  4. +
  5. Mettez une redirection depuis Gmail et prévenez vos contacts de votre nouvelle adresse.
  6. +
  7. + Installez l'application mobile, activez la double authentification, et utilisez Proton + Bridge si vous tenez à Thunderbird. +
  8. +
diff --git a/content/outils/protonpass.md b/content/outils/protonpass.md new file mode 100644 index 0000000..dd10cb2 --- /dev/null +++ b/content/outils/protonpass.md @@ -0,0 +1,25 @@ +--- +name: "Proton Pass" +slug: "protonpass" +category: "motsdepasse" +difficulty: "beginner" +url: "https://proton.me/pass" +color: "#6d4aff" +monogram: "Pp" +tags: ["Avec alias e-mail","🇨🇭 · open-source"] +lang: "fr" +--- + +## what + +Le gestionnaire de mots de passe de l'écosystème Proton, avec des alias e-mail jetables + intégrés. + +## why + +Idéal si vous êtes déjà chez Proton : un seul compte pour le mail, le cloud et les mots de + passe. Ses alias e-mail vous évitent de donner votre vraie adresse partout. + +## who + +Ceux qui veulent tout regrouper chez Proton. diff --git a/content/outils/protonvpn.md b/content/outils/protonvpn.md new file mode 100644 index 0000000..bdf2c65 --- /dev/null +++ b/content/outils/protonvpn.md @@ -0,0 +1,40 @@ +--- +name: "Proton VPN" +slug: "protonvpn" +category: "vpn" +difficulty: "beginner" +url: "https://protonvpn.com" +color: "#6d4aff" +monogram: "Pv" +iconSlug: "protonvpn" +tags: ["Offre gratuite honnête","🇨🇭 · open-source"] +lang: "fr" +--- + +## what + +Le VPN de l'écosystème Proton, avec une véritable offre gratuite (rare et honnête). + +## why + +Basé en Suisse, audité, open-source. Son offre gratuite est sans publicité, sans revente de + données et sans limite de volume (le nombre de pays est simplement réduit). C'est la porte + d'entrée idéale pour un débutant, surtout si vous utilisez déjà Proton Mail. + +## who + +Débutants, et toute personne déjà dans l'écosystème Proton qui veut un seul compte pour tout. + +## install + +
    +
  1. + Rendez-vous sur protonvpn.com et connectez-vous avec votre compte Proton (ou créez-en + un). +
  2. +
  3. Installez l'application (Windows, macOS, Linux, Android, iOS).
  4. +
  5. + Utilisez « Quick Connect » ou choisissez un pays, puis activez le kill switch et NetShield + (blocage des pubs et traqueurs). +
  6. +
diff --git a/content/outils/quad9.md b/content/outils/quad9.md new file mode 100644 index 0000000..512e6d0 --- /dev/null +++ b/content/outils/quad9.md @@ -0,0 +1,38 @@ +--- +name: "Quad9" +slug: "quad9" +category: "dns" +difficulty: "beginner" +url: "https://quad9.net" +color: "#1a5fb4" +monogram: "9" +iconSlug: "quad9" +tags: ["Anti-maliciel","🇨🇭 à but non lucratif"] +lang: "fr" +--- + +## what + +Un résolveur DNS chiffré, suisse et à but non lucratif, qui bloque en plus les domaines + malveillants connus. + +## why + +Juridiction suisse, pas de conservation de votre adresse IP, protection contre l'hameçonnage et + les logiciels malveillants. Un excellent réglage « installer et oublier ». + +## who + +Tout le monde, en particulier ceux qui veulent la simplicité et une bonne juridiction. + +## install + +
    +
  1. + Sur Android : Réglages > Réseau > DNS privé > saisissez dns.quad9.net. +
  2. +
  3. + Sur iPhone/Mac : installez le profil DoH depuis quad9.net. Sur PC : configurez le + DNS-over-HTTPS dans le navigateur ou le système. +
  4. +
diff --git a/content/outils/qubes.md b/content/outils/qubes.md new file mode 100644 index 0000000..1c608c1 --- /dev/null +++ b/content/outils/qubes.md @@ -0,0 +1,27 @@ +--- +name: "Qubes OS · postmarketOS" +slug: "qubes" +category: "os" +difficulty: "advanced" +url: "https://www.qubes-os.org" +color: "#3874d8" +monogram: "Qb" +iconSlug: "qubesos" +tags: ["Cloisonnement","🌍 · open-source"] +lang: "fr" +--- + +## what + +Deux systèmes de niche : Qubes cloisonne votre PC en machines virtuelles étanches ; postmarketOS + fait tourner du Linux sur d'anciens téléphones. + +## why + +Qubes isole chaque activité (travail, banque, navigation risquée) dans son propre compartiment : + une compromission n'atteint pas le reste. postmarketOS prolonge la vie de téléphones abandonnés + par leur constructeur. + +## who + +Utilisateurs experts avec un modèle de menace très élevé. diff --git a/content/outils/search.md b/content/outils/search.md new file mode 100644 index 0000000..8b4e9d3 --- /dev/null +++ b/content/outils/search.md @@ -0,0 +1,39 @@ +--- +name: "DuckDuckGo · Brave Search · SearXNG" +slug: "search" +category: "navigateur" +difficulty: "beginner" +url: "https://duckduckgo.com" +color: "#de5833" +monogram: "🔎" +iconSlug: "duckduckgo" +tags: ["Remplace Google Search"] +lang: "fr" +--- + +## what + +Des moteurs de recherche qui ne profilent pas chaque requête, contrairement à Google. + +## why + +DuckDuckGo et Brave Search ne conservent pas d'historique lié à votre identité. Startpage vous + sert des résultats Google sans le pistage. SearXNG va plus loin : c'est un métamoteur{' '} + auto-hébergeable, la souveraineté jusque dans la barre de recherche. + +## who + +Tout le monde. SearXNG vise ceux qui veulent héberger leur propre moteur. + +## install + +
    +
  1. + Dans les réglages de votre navigateur, changez le moteur par défaut pour DuckDuckGo, Brave + Search ou Startpage. +
  2. +
  3. + Pour SearXNG : utilisez une instance publique (annuaire sur searx.space) ou hébergez la vôtre + (voir section 10). +
  4. +
diff --git a/content/outils/session.md b/content/outils/session.md new file mode 100644 index 0000000..9323f4e --- /dev/null +++ b/content/outils/session.md @@ -0,0 +1,40 @@ +--- +name: "Session" +slug: "session" +category: "messagerie" +difficulty: "intermediate" +license: "GPL-3.0" +url: "https://getsession.org" +color: "#178a5a" +monogram: "Se" +iconSlug: "session" +tags: ["Sans numéro","🌍 · open-source"] +lang: "fr" +--- + +## what + +Un chiffrement à la Signal, mais sans numéro de téléphone et avec un routage en oignon. + +## why + +Votre identité est un « Session ID » aléatoire. Le trafic passe par un réseau décentralisé + (Lokinet) qui réduit fortement les métadonnées. + +## who + +Quand un numéro de téléphone est un risque. Écosystème plus petit, à réserver aux échanges qui + comptent. + +## install + +
    +
  1. + Installez depuis getsession.org (toutes plateformes). +
  2. +
  3. + « Create account » génère votre Session ID et une phrase de récupération. +
  4. +
  5. Notez la phrase de récupération sur papier : c'est la seule clé de votre compte.
  6. +
  7. Partagez votre Session ID (ou QR) à vos contacts.
  8. +
diff --git a/content/outils/signal.md b/content/outils/signal.md new file mode 100644 index 0000000..2ddcd48 --- /dev/null +++ b/content/outils/signal.md @@ -0,0 +1,43 @@ +--- +name: "Signal" +slug: "signal" +category: "messagerie" +difficulty: "beginner" +license: "AGPL-3.0" +url: "https://signal.org" +color: "#3a76f0" +monogram: "S" +iconSlug: "signal" +tags: ["Remplace WhatsApp","🇺🇸 · open-source"] +lang: "fr" +--- + +## what + +Une messagerie chiffrée pour vos textos, appels, visios et groupes. C'est le remplaçant direct + de WhatsApp, en aussi simple. + +## why + +Chiffrement de bout en bout par défaut, à but non lucratif, protocole audité qui sert de + référence mondiale. Presque aucune métadonnée conservée, et l'équipe a promis de quitter l'UE + plutôt que d'installer un scan. + +## who + +Tout le monde, dès aujourd'hui. C'est le premier geste et le plus utile. Seule contrainte : un + numéro de téléphone, que l'on peut masquer derrière un nom d'utilisateur. + +## install + +
    +
  1. + Installez depuis signal.org (App Store, Google Play, ou l'APK direct sur Android). +
  2. +
  3. Confirmez votre numéro par SMS, puis choisissez un code PIN.
  4. +
  5. + Réglages > Confidentialité : créez un nom d'utilisateur pour cacher votre numéro, et + activez le verrou d'inscription. +
  6. +
  7. Invitez vos proches. Sur ordinateur, liez l'application de bureau à votre téléphone.
  8. +
diff --git a/content/outils/simplex.md b/content/outils/simplex.md new file mode 100644 index 0000000..9bd530c --- /dev/null +++ b/content/outils/simplex.md @@ -0,0 +1,43 @@ +--- +name: "SimpleX Chat" +slug: "simplex" +category: "messagerie" +difficulty: "intermediate" +url: "https://simplex.chat" +color: "#1e63d0" +monogram: "SX" +iconSlug: "simplex" +tags: ["Sans identifiant","🌍 · open-source"] +lang: "fr" +--- + +## what + +Une messagerie chiffrée sans aucun compte, sans numéro et sans identifiant. On se connecte en + partageant un lien ou un QR code. + +## why + +Par conception, même les serveurs ignorent qui parle à qui. C'est aujourd'hui l'option la plus + protectrice contre la corrélation des métadonnées. + +## who + +Comptes pseudonymes, contacts sensibles, haut risque. Un peu plus jeune que Signal, avec + quelques aspérités. + +## install + +
    +
  1. + Installez depuis simplex.chat (F-Droid, Google Play, App Store ou APK). +
  2. +
  3. + Choisissez un nom d'affichage local (jamais votre vrai nom : il ne quitte pas votre + appareil). +
  4. +
  5. + Pour ajouter un contact, partagez un lien d'invitation à usage unique ou un QR code. +
  6. +
  7. Activez le verrou par code, et (avancé) configurez vos propres serveurs SMP.
  8. +
diff --git a/content/outils/synapse.md b/content/outils/synapse.md new file mode 100644 index 0000000..d5ae6ea --- /dev/null +++ b/content/outils/synapse.md @@ -0,0 +1,27 @@ +--- +name: "Matrix Synapse" +slug: "synapse" +category: "selfhost" +difficulty: "advanced" +license: "AGPL-3.0" +url: "https://element.io/server" +color: "#0dbd8b" +monogram: "Mx" +iconSlug: "matrix" +tags: ["Votre serveur de chat","🌍 · open-source"] +lang: "fr" +--- + +## what + +Votre propre serveur de messagerie Matrix, sur lequel tournent Element et les appels chiffrés. + +## why + +En hébergeant le serveur, vous contrôlez aussi les métadonnées (qui parle à qui, quand), + le point faible de Matrix en fédération. C'est la messagerie communautaire dont vous êtes le + seul maître. + +## who + +Communautés, collectifs, rédactions qui veulent leur espace fédéré indépendant. diff --git a/content/outils/tails.md b/content/outils/tails.md new file mode 100644 index 0000000..fea4f14 --- /dev/null +++ b/content/outils/tails.md @@ -0,0 +1,36 @@ +--- +name: "Tails" +slug: "tails" +category: "os" +difficulty: "advanced" +license: "GPL-3.0" +url: "https://tails.net" +color: "#56347c" +monogram: "Ta" +iconSlug: "tails" +tags: ["Clé USB amnésique","🌍 · tout via Tor"] +lang: "fr" +--- + +## what + +Un système qui démarre depuis une clé USB, fait passer tout le trafic par Tor et ne laisse{' '} + aucune trace à l'extinction. + +## why + +À l'arrêt, tout est oublié : c'est « amnésique ». Idéal pour un travail sensible et ponctuel sur + un ordinateur qui n'est pas le vôtre, sans rien y laisser. + +## who + +Lanceurs d'alerte, journalistes, sources. L'outil de référence pour les missions à haut risque. + +## install + +
    +
  1. + Téléchargez Tails sur tails.net et suivez l'assistant pour créer la clé USB. +
  2. +
  3. Redémarrez l'ordinateur sur cette clé. Utilisez-le, puis éteignez : tout disparaît.
  4. +
diff --git a/content/outils/tailscale.md b/content/outils/tailscale.md new file mode 100644 index 0000000..c591bd1 --- /dev/null +++ b/content/outils/tailscale.md @@ -0,0 +1,43 @@ +--- +name: "Tailscale · Headscale · WireGuard" +slug: "tailscale" +category: "vpn" +difficulty: "advanced" +license: "BSD-3-Clause" +url: "https://tailscale.com" +color: "#242424" +monogram: "Ts" +iconSlug: "tailscale" +tags: ["Accès privé à son serveur","🌍 · open-source"] +lang: "fr" +--- + +## what + +Un réseau privé chiffré qui relie vos appareils à votre serveur, sans jamais l'exposer sur + l'Internet public. + +## why + +Au lieu d'ouvrir des ports (et de vous faire attaquer), Tailscale crée un tunnel + WireGuard entre vos seuls appareils autorisés : votre serveur n'a aucune surface d'attaque + publique. Headscale est la version que vous hébergez vous-même, pour ne dépendre d'aucun + tiers. WireGuard seul offre le contrôle total, au prix d'une configuration manuelle. + +## who + +Tout auto-hébergeur. C'est la façon sûre d'atteindre son Nextcloud ou ses photos depuis + l'extérieur. + +## install + +
    +
  1. + Installez Tailscale sur votre serveur et sur votre téléphone/PC, connectez-les au même compte. +
  2. +
  3. + Vos appareils se voient aussitôt sur un réseau privé ; accédez à votre serveur par son adresse + Tailscale. +
  4. +
  5. Pour zéro dépendance, remplacez le serveur de coordination par Headscale, auto-hébergé.
  6. +
diff --git a/content/outils/tor.md b/content/outils/tor.md new file mode 100644 index 0000000..d481d25 --- /dev/null +++ b/content/outils/tor.md @@ -0,0 +1,45 @@ +--- +name: "Tor Browser" +slug: "tor" +category: "tor" +difficulty: "advanced" +license: "BSD-3-Clause" +url: "https://www.torproject.org" +color: "#7d4698" +monogram: "Tor" +iconSlug: "torbrowser" +tags: ["Anonymat réseau","🌍 · open-source"] +lang: "fr" +--- + +## what + +Un réseau qui sépare qui vous êtes de ce que vous faites en ligne, accessible via le Tor + Browser. + +## why + +Votre trafic rebondit à travers plusieurs relais chiffrés dans le monde : aucun ne connaît à la + fois votre identité et votre destination. C'est l'outil des journalistes et des sources, et le + moyen d'atteindre un site bloqué (par exemple pour télécharger un VPN censuré). + +## who + +Profils à haut risque, et quiconque doit dissocier son activité de son adresse IP réelle. À + utiliser ponctuellement, pas comme navigateur de tous les jours. + +## install + +
    +
  1. + Téléchargez le Tor Browser sur torproject.org (Windows, macOS, Linux, Android). +
  2. +
  3. + Lancez-le et cliquez « Se connecter ». Si Tor est bloqué dans votre pays, activez un « pont » + (bridge). +
  4. +
  5. + Naviguez sans maximiser la fenêtre, sans installer d'extension, et{' '} + sans vous connecter à vos vrais comptes. +
  6. +
diff --git a/content/outils/tuta.md b/content/outils/tuta.md new file mode 100644 index 0000000..cf20dec --- /dev/null +++ b/content/outils/tuta.md @@ -0,0 +1,40 @@ +--- +name: "Tuta" +slug: "tuta" +category: "email" +difficulty: "beginner" +license: "GPL-3.0" +url: "https://tuta.com" +color: "#b01e2e" +monogram: "Tu" +iconSlug: "tuta" +tags: ["Remplace Gmail","🇩🇪 · open-source · post-quantique"] +lang: "fr" +--- + +## what + +Une messagerie e-mail allemande, entièrement open-source et sans aucun service Google. + +## why + +Elle chiffre aussi l'objet et une partie des métadonnées, avec un chiffrement résistant à + l'informatique quantique. Juridiction UE. + +## who + +Ceux qui veulent le maximum de métadonnées chiffrées et du 100 % libre. Elle n'utilise pas PGP : + pour écrire chiffré à l'extérieur, on protège le message par mot de passe. + +## install + +
    +
  1. + Créez un compte sur tuta.com et installez l'application (disponible sur F-Droid). +
  2. +
  3. + Pour écrire à un non-utilisateur de façon chiffrée : cliquez sur le cadenas et définissez un + mot de passe, transmis à votre correspondant par un autre canal. +
  4. +
  5. Activez la double authentification.
  6. +
diff --git a/content/outils/ublock.md b/content/outils/ublock.md new file mode 100644 index 0000000..253a181 --- /dev/null +++ b/content/outils/ublock.md @@ -0,0 +1,36 @@ +--- +name: "uBlock Origin" +slug: "ublock" +category: "navigateur" +difficulty: "beginner" +url: "https://ublockorigin.com" +color: "#7a0d0d" +monogram: "uB" +iconSlug: "ublockorigin" +tags: ["Extension","🌍 · open-source"] +lang: "fr" +--- + +## what + +L'extension de navigateur qui bloque publicités, traqueurs et scripts espions. Le geste le plus + rentable, en dix secondes. + +## why + +La publicité en ligne est le principal vecteur de surveillance et de profilage. La bloquer coupe + l'essentiel du pistage, accélère les pages et réduit les risques de logiciels malveillants. + +## who + +Tout le monde, sur Firefox comme sur les navigateurs Chromium. + +## install + +
    +
  1. + Ouvrez le magasin d'extensions de votre navigateur et cherchez « uBlock Origin » (l'original, + par Raymond Hill). +
  2. +
  3. Installez-le. Il fonctionne aussitôt, sans réglage nécessaire.
  4. +
diff --git a/content/outils/visio.md b/content/outils/visio.md new file mode 100644 index 0000000..722767d --- /dev/null +++ b/content/outils/visio.md @@ -0,0 +1,38 @@ +--- +name: "Jitsi Meet · Element Call" +slug: "visio" +category: "boiteaoutils" +difficulty: "beginner" +url: "https://jitsi.org" +color: "#1d6fb8" +monogram: "Vi" +iconSlug: "jitsi" +tags: ["Remplace Zoom / Meet","🌍 · open-source"] +lang: "fr" +--- + +## what + +Des outils de visioconférence sans compte ni installation lourde, pour remplacer Zoom, Google + Meet ou Teams. + +## why + +Jitsi Meet se lance dans le navigateur, sans compte, et peut être auto-hébergé (c'est + aussi la base de Brave Talk). Element Call est chiffré de bout en bout et fédéré via + Matrix. Pour un appel simple et totalement chiffré, les appels Signal font aussi le + travail. + +## who + +Tout le monde. Sur un serveur Jitsi public, les appels à plusieurs sont chiffrés en transport ; + le chiffrement de bout en bout est en option. + +## install + +
    +
  1. + Jitsi : allez sur meet.jit.si, créez un nom de salon, partagez le lien. Rien à installer. +
  2. +
  3. Element Call : depuis l'application Element (Matrix), lancez un appel dans un salon.
  4. +
diff --git a/content/outils/website.md b/content/outils/website.md new file mode 100644 index 0000000..442de4d --- /dev/null +++ b/content/outils/website.md @@ -0,0 +1,44 @@ +--- +name: "Votre propre site web" +slug: "website" +category: "selfhost" +difficulty: "intermediate" +url: "https://astro.build" +color: "#7a4ddb" +monogram: "www" +tags: ["Résister au bannissement"] +lang: "fr" +--- + +## what + +Un site à vous, sur votre nom de domaine, où votre contenu ne dépend d'aucune plateforme. + +## why + +Le jour où un réseau supprime ou suspend votre compte, tout votre travail disparaît. Un site + personnel est votre point d'ancrage : vos articles y restent, archivés et à jour, quoi qu'il + arrive. C'est exactement ce que font les comptes d'information prudents. Un site statique + (généré par Hugo, Astro ou Jekyll) suffit et se publie presque gratuitement ; pour un blog + dynamique, un WordPress ou un Ghost auto-hébergé fait l'affaire. + +## who + +Comptes d'information, créateurs, militants, quiconque publie et craint la censure de + plateforme. + +## install + +
    +
  1. + Achetez un nom de domaine (idéalement chez un registraire respectueux de la vie privée). +
  2. +
  3. + Choisissez un générateur de site statique (Astro, Hugo) et hébergez le résultat, ou installez + WordPress/Ghost sur votre serveur. +
  4. +
  5. + Renvoyez-y systématiquement depuis vos réseaux : votre audience vous retrouve même si un + compte tombe. +
  6. +
diff --git a/content/outils/yubikey.md b/content/outils/yubikey.md new file mode 100644 index 0000000..6485075 --- /dev/null +++ b/content/outils/yubikey.md @@ -0,0 +1,39 @@ +--- +name: "YubiKey · Nitrokey" +slug: "yubikey" +category: "deuxfa" +difficulty: "intermediate" +url: "https://www.yubico.com" +color: "#84bd00" +monogram: "Yk" +iconSlug: "yubico" +tags: ["Clé matérielle FIDO2"] +lang: "fr" +--- + +## what + +Une petite clé physique (format USB, souvent avec NFC) qui prouve votre identité d'un simple + contact du doigt. + +## why + +C'est la 2FA la plus solide : elle résiste à l'hameçonnage, car la clé vérifie l'adresse réelle + du site avant de répondre. Nitrokey est l'alternative à matériel et micrologiciel + entièrement ouverts. Un faux site ne peut pas vous piéger. + +## who + +Ceux qui veulent le maximum de sécurité sur leurs comptes clés. Achetez-en deux (une + principale, une de secours). + +## install + +
    +
  1. Procurez-vous deux clés sur yubico.com ou nitrokey.com.
  2. +
  3. + Dans les réglages de sécurité de chaque compte (e-mail, gestionnaire de mots de passe…), + ajoutez une « clé de sécurité » ou « passkey ». Enregistrez vos deux clés. +
  4. +
  5. Gardez la clé de secours dans un lieu sûr, séparé.
  6. +
diff --git a/content/outils/yunohost.md b/content/outils/yunohost.md new file mode 100644 index 0000000..be31a40 --- /dev/null +++ b/content/outils/yunohost.md @@ -0,0 +1,43 @@ +--- +name: "YunoHost · Umbrel · Start9" +slug: "yunohost" +category: "selfhost" +difficulty: "advanced" +license: "AGPL-3.0" +url: "https://yunohost.org" +color: "#e29100" +monogram: "Yh" +tags: ["Serveur clé en main","🌍 · open-source"] +lang: "fr" +--- + +## what + +Des systèmes qui transforment un vieux PC ou un Raspberry Pi en serveur personnel, avec un + catalogue d'applications à installer en quelques clics. + +## why + +L'auto-hébergement fait peur, mais ces outils font le gros du travail. YunoHost gère même + votre propre e-mail et une authentification unique. Umbrel offre un magasin de plus de + 300 applications, très prisé des amateurs de vie privée et de Bitcoin. Start9 chiffre les + sauvegardes et donne une adresse Tor à chaque service par défaut. + +## who + +Les profils avancés prêts à consacrer un après-midi à monter leur propre cloud. C'est la parade + structurelle la plus radicale à Chat Control. + +## install + +
    +
  1. + Récupérez un vieil ordinateur, un Raspberry Pi, ou louez un petit serveur (VPS) dans un pays + protecteur. +
  2. +
  3. Installez YunoHost, Umbrel ou Start9 en suivant leur guide officiel.
  4. +
  5. Depuis le catalogue, installez Nextcloud, un serveur Matrix, une galerie photo, etc.
  6. +
  7. + Accédez-y en privé avec Tailscale (section VPN) plutôt que d'exposer le serveur au public. +
  8. +
diff --git a/docs/CONTENT_GUIDE.md b/docs/CONTENT_GUIDE.md new file mode 100644 index 0000000..3296150 --- /dev/null +++ b/docs/CONTENT_GUIDE.md @@ -0,0 +1,76 @@ +# Guide de rédaction — fiches d'outils FR/créole + +## Format d'une fiche (`content/outils/.md`) + +```markdown +--- +name: "Signal" +slug: "signal" +category: "messagerie" # slug d'une catégorie de content/categories.json +difficulty: "beginner" # beginner | intermediate | advanced +license: "AGPL-3.0" # identifiant SPDX exact (spdx.org/licenses) +url: "https://signal.org" +color: "#3a76f0" # couleur du monogramme (décorative) +monogram: "S" +tags: ["Remplace WhatsApp","🇺🇸 · open-source"] +lang: "fr" +--- + +## what +À quoi sert l'outil, en deux phrases maximum. + +## why +Pourquoi il compte pour la souveraineté numérique. + +## who +Pour qui, et à quel moment du parcours. + +## install +
  1. Étapes concrètes, numérotées.
+``` + +Les valeurs du frontmatter sont encodées en JSON (guillemets doubles). +Le corps accepte Markdown et HTML simple ; il est rendu au build, rien n'est +interprété côté client. **Le build échoue si une fiche est invalide** — c'est +le contrat de validation (ADR-001). + +## Ton éditorial + +- **Militant mais chaleureux, ancré Caraïbe.** Pas de langage corporate, pas + de peur gratuite : on explique le geste, on donne le pouvoir d'agir. +- Tutoiement. Phrases courtes. Le premier mot de chaque section porte le sens + (motif en F, doctrine §1.1). +- `what` dit le service rendu, `why` dit l'enjeu politique/technique, `who` + donne la porte d'entrée (« commence ici si… »), `install` est actionnable + sans autre lecture. +- Exemples et localisation ancrés territoire — jamais de Lorem ipsum + hexagonal (doctrine §4.2). + +## Créole guadeloupéen (gcf) + +- Les **micro-textes de l'interface** (boutons, filtres, états vides, marqueur + de fin) vivent dans `frontend/src/lib/i18n/gcf.json`. C'est la couche à + plus fort impact affectif pour le plus faible coût (doctrine §4.2) — elle + est traduite en premier. +- ⚠️ **Relecture par un locuteur natif requise** : les chaînes gcf actuelles + sont un premier jet à valider avant mise en production. La graphie de + référence à trancher (GEREC-F ou autre) doit être notée ici une fois choisie. +- La traduction intégrale des fiches est un chantier éditorial séparé : + le format prévu est un fichier jumeau `content/outils/gcf/.md` avec + `lang: "gcf"` (le chargeur l'ignorera tant que la locale de contenu n'est + pas activée). +- Termes fixés : « zouti » (outil), « Ou pa manké ayen » (fin de liste), + « Chwazi zouti ou » (héros), niveaux « Débitan / Entèmédia / Avansé ». + +## Ajouter une catégorie + +Ajouter une entrée à `content/categories.json` (`slug`, `title`, `order`, +`part`). La navigation n'affiche que 4 catégories avant la divulgation +progressive (Hick-Hyman, doctrine §1.3) : l'ordre `order` décide lesquelles. + +## Vérifications avant merge + +- [ ] `license` est un identifiant SPDX valide +- [ ] `difficulty` reflète l'expérience réelle d'installation (pas le prestige) +- [ ] Chaque section respecte sa question (what/why/who/install) +- [ ] `pnpm build` passe (validation du frontmatter incluse) diff --git a/docs/DESIGN_SYSTEM.md b/docs/DESIGN_SYSTEM.md new file mode 100644 index 0000000..eaa3b43 --- /dev/null +++ b/docs/DESIGN_SYSTEM.md @@ -0,0 +1,72 @@ +# Design system OKI — exitchatcontrol.org + +Toutes les valeurs visuelles vivent dans +[`frontend/src/styles/tokens.css`](../frontend/src/styles/tokens.css). +Les composants Svelte consomment les tokens ; **jamais de valeur brute** +(couleur, taille) dans un composant (doctrine §5.2). + +## Architecture CSS + +Cascade explicite par `@layer` ([app.css](../frontend/src/app.css)) : + +``` +reset → tokens → base → layouts → components → utilities +``` + +- `reset.css` — reset moderne minimal (~40 lignes), inclut `prefers-reduced-motion`. +- `tokens.css` — custom properties : couleurs `oklch()`, typo fluide `clamp()`, espacements, interaction. +- `base.css` — HTML sémantique nu : typo, liens, focus visible, boutons. +- `layouts.css` — primitives Every Layout : `.stack`, `.cluster`, `.center`, `.card-grid` (container queries, pas de media queries de largeur d'écran). +- Le style propre à chaque composant vit dans son ` diff --git a/frontend/src/lib/components/DifficultyBadge.svelte b/frontend/src/lib/components/DifficultyBadge.svelte new file mode 100644 index 0000000..8144eec --- /dev/null +++ b/frontend/src/lib/components/DifficultyBadge.svelte @@ -0,0 +1,36 @@ + + + + + {t(`difficulty.${difficulty}`)} + + + diff --git a/frontend/src/lib/components/EndMarker.svelte b/frontend/src/lib/components/EndMarker.svelte new file mode 100644 index 0000000..1dfa07f --- /dev/null +++ b/frontend/src/lib/components/EndMarker.svelte @@ -0,0 +1,34 @@ + + + +

+ {t('directory.endOfList')} + {t('directory.endOfListSub')} +

+ + diff --git a/frontend/src/lib/components/LanguageSwitcher.svelte b/frontend/src/lib/components/LanguageSwitcher.svelte new file mode 100644 index 0000000..f1d5204 --- /dev/null +++ b/frontend/src/lib/components/LanguageSwitcher.svelte @@ -0,0 +1,40 @@ + + + +
+ {#each locales as locale (locale)} + + {/each} +
+ + diff --git a/frontend/src/lib/components/SearchBar.svelte b/frontend/src/lib/components/SearchBar.svelte new file mode 100644 index 0000000..187abb0 --- /dev/null +++ b/frontend/src/lib/components/SearchBar.svelte @@ -0,0 +1,43 @@ + + + + + + + diff --git a/frontend/src/lib/components/ToolCard.svelte b/frontend/src/lib/components/ToolCard.svelte new file mode 100644 index 0000000..3664778 --- /dev/null +++ b/frontend/src/lib/components/ToolCard.svelte @@ -0,0 +1,99 @@ + + +
+
+ +

{tool.name}

+
+ +

{t('tool.why')} : {tool.excerpt}

+ +
+ + {#if tool.license} + {tool.license} + {/if} + {#each tool.tags as tag (tag)} + {tag} + {/each} +
+
+ + diff --git a/frontend/src/lib/content/tools.server.ts b/frontend/src/lib/content/tools.server.ts new file mode 100644 index 0000000..a5b12a2 --- /dev/null +++ b/frontend/src/lib/content/tools.server.ts @@ -0,0 +1,117 @@ +/** + * Chargeur de contenu — s'exécute uniquement au build (site prérendu, + * ADR-001) : ni fs ni marked ne sont expédiés au client. + */ +import { readFileSync, readdirSync } from 'node:fs' +import path from 'node:path' +import { marked } from 'marked' + +export type Difficulty = 'beginner' | 'intermediate' | 'advanced' + +export interface ToolSections { + what?: string + why?: string + who?: string + install?: string + extra?: string +} + +export interface Tool { + name: string + slug: string + category: string + difficulty: Difficulty + license?: string + url: string + color?: string + monogram?: string + iconSlug?: string + tags: string[] + /** extrait texte brut de « why », pour les cartes */ + excerpt: string + sections: ToolSections +} + +export interface Category { + slug: string + title: string + order: number + part: number +} + +const CONTENT = path.resolve(process.cwd(), '..', 'content') +const SECTION_KEYS = ['what', 'why', 'who', 'install', 'extra'] as const + +function parseFrontmatter(raw: string): [Record, string] { + const m = raw.match(/^---\n([\s\S]*?)\n---\n?/) + if (!m) throw new Error('frontmatter manquant') + const meta: Record = {} + for (const line of m[1].split('\n')) { + const i = line.indexOf(':') + if (i === -1) continue + // les valeurs sont encodées en JSON par le script de migration + meta[line.slice(0, i).trim()] = JSON.parse(line.slice(i + 1).trim()) + } + return [meta, raw.slice(m[0].length)] +} + +function parseSections(body: string): ToolSections { + const sections: ToolSections = {} + const parts = body.split(/^## (\w+)\s*$/m) + for (let i = 1; i < parts.length; i += 2) { + const key = parts[i] as (typeof SECTION_KEYS)[number] + if (SECTION_KEYS.includes(key)) { + sections[key] = marked.parse(parts[i + 1].trim(), { async: false }) + } + } + return sections +} + +const ENTITIES: Record = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'", + ' ': ' ' +} + +function stripHtml(html: string): string { + return html + .replace(/<[^>]+>/g, ' ') + .replace(/&(?:amp|lt|gt|quot|#39|nbsp);/g, (e) => ENTITIES[e]) + .replace(/[ \t\r\n]+/g, ' ') + .trim() +} + +function loadTool(file: string): Tool { + const raw = readFileSync(path.join(CONTENT, 'outils', file), 'utf8') + const [meta, body] = parseFrontmatter(raw) + const sections = parseSections(body) + const why = stripHtml(sections.why ?? sections.what ?? '') + return { + ...(meta as unknown as Omit), + excerpt: why.length > 160 ? `${why.slice(0, 157).trimEnd()}…` : why, + sections + } +} + +let cache: { tools: Tool[]; categories: Category[] } | null = null + +export function loadContent() { + if (cache) return cache + const categories = ( + JSON.parse(readFileSync(path.join(CONTENT, 'categories.json'), 'utf8')) as Category[] + ).sort((a, b) => a.order - b.order) + const order = new Map(categories.map((c, i) => [c.slug, i])) + const tools = readdirSync(path.join(CONTENT, 'outils')) + .filter((f) => f.endsWith('.md')) + .map(loadTool) + .sort( + (a, b) => + (order.get(a.category) ?? 99) - (order.get(b.category) ?? 99) || + a.name.localeCompare(b.name, 'fr') + ) + cache = { tools, categories } + return cache +} diff --git a/frontend/src/lib/i18n/fr.json b/frontend/src/lib/i18n/fr.json new file mode 100644 index 0000000..29f9e44 --- /dev/null +++ b/frontend/src/lib/i18n/fr.json @@ -0,0 +1,63 @@ +{ + "site": { + "name": "Exit Chat Control", + "tagline": "Reprends le contrôle de ton internet", + "description": "Annuaire d'outils libres pour la souveraineté numérique — messagerie chiffrée, VPN, auto-hébergement, OS libres." + }, + "nav": { + "home": "Accueil", + "directory": "Annuaire", + "contribute": "Contribuer", + "skipToContent": "Aller au contenu" + }, + "hero": { + "title": "Chwazi zouti ou", + "subtitle": "Reprends le contrôle de ton internet : des outils libres, expliqués simplement, du premier geste au serveur auto-hébergé.", + "cta": "Voir l'annuaire" + }, + "directory": { + "title": "Annuaire des outils", + "intro": "Chaque outil est libre, vérifié, et classé par difficulté. Commence par le vert.", + "filterCategory": "Catégorie", + "filterDifficulty": "Difficulté", + "allCategories": "Toutes les catégories", + "allDifficulties": "Toutes", + "results": "outils", + "resultOne": "outil", + "empty": "Ayen pa maché èvè filtè-lasa — essaie d'élargir les filtres.", + "endOfList": "Ou pa manké ayen", + "endOfListSub": "Tu es au bout de la liste — rien ne se recharge dans ton dos.", + "prevPage": "Page précédente", + "nextPage": "Page suivante", + "page": "Page" + }, + "tool": { + "what": "À quoi ça sert", + "why": "Pourquoi c'est important", + "who": "Pour qui, quand", + "install": "Installer et utiliser", + "officialSite": "Site officiel", + "sourceCode": "Code source", + "license": "Licence", + "category": "Catégorie", + "backToDirectory": "Retour à l'annuaire" + }, + "difficulty": { + "beginner": "Débutant", + "intermediate": "Intermédiaire", + "advanced": "Avancé" + }, + "search": { + "label": "Rechercher un outil", + "placeholder": "Rechercher… (touche /)", + "noResults": "Aucun outil trouvé" + }, + "lang": { + "switchLabel": "Langue", + "switchTo": "Passer en" + }, + "footer": { + "license": "Contenu et code libres (MIT). Zéro tracker, zéro CDN, zéro cookie.", + "contribute": "Proposer un outil ou une correction" + } +} diff --git a/frontend/src/lib/i18n/gcf.json b/frontend/src/lib/i18n/gcf.json new file mode 100644 index 0000000..81f3aef --- /dev/null +++ b/frontend/src/lib/i18n/gcf.json @@ -0,0 +1,63 @@ +{ + "site": { + "name": "Exit Chat Control", + "tagline": "Pran kontwòl entènèt a-w", + "description": "Lis a zouti lib pou libèté niméwik — mésajri chifré, VPN, oto-ébèjman, sistèm lib." + }, + "nav": { + "home": "Lakou", + "directory": "Lis a zouti", + "contribute": "Pòté mannèv", + "skipToContent": "Alé dirèk asi kontni-la" + }, + "hero": { + "title": "Chwazi zouti ou", + "subtitle": "Pran kontwòl entènèt a-w : zouti lib, èspliké senp, dépi prèmyé jès jis sèwvè a-w.", + "cta": "Gadé lis-la" + }, + "directory": { + "title": "Lis a zouti", + "intro": "Chak zouti lib, vérifyé, é rangé pa difikilté. Koumansé èvè vèw-la.", + "filterCategory": "Katégori", + "filterDifficulty": "Difikilté", + "allCategories": "Tout katégori", + "allDifficulties": "Tout", + "results": "zouti", + "resultOne": "zouti", + "empty": "Ayen pa maché èvè filtè-lasa — èséyé louvri filtè a-w.", + "endOfList": "Ou pa manké ayen", + "endOfListSub": "Ou rivé an bout a lis-la — ayen pa ka richajé dèyè do a-w.", + "prevPage": "Paj avan", + "nextPage": "Paj apré", + "page": "Paj" + }, + "tool": { + "what": "Pou ki sa i sèwvi", + "why": "Poukisa sa enpòwtan", + "who": "Pou kimoun, kitan", + "install": "Enstalé é sèwvi", + "officialSite": "Sit ofisyèl", + "sourceCode": "Kòd sous", + "license": "Lisans", + "category": "Katégori", + "backToDirectory": "Viré an lis-la" + }, + "difficulty": { + "beginner": "Débitan", + "intermediate": "Entèmédia", + "advanced": "Avansé" + }, + "search": { + "label": "Chèché on zouti", + "placeholder": "Chèché… (touch /)", + "noResults": "Pon zouti pa touvé" + }, + "lang": { + "switchLabel": "Lang", + "switchTo": "Pasé an" + }, + "footer": { + "license": "Kontni é kòd lib (MIT). Pon trakè, pon CDN, pon cookie.", + "contribute": "Pwopozé on zouti oben on koreksyon" + } +} diff --git a/frontend/src/lib/i18n/index.svelte.ts b/frontend/src/lib/i18n/index.svelte.ts new file mode 100644 index 0000000..7d10574 --- /dev/null +++ b/frontend/src/lib/i18n/index.svelte.ts @@ -0,0 +1,54 @@ +import fr from './fr.json' +import gcf from './gcf.json' +import { browser } from '$app/environment' +import { defaultLocale, type Locale } from './locales' + +export { locales, localeNames, defaultLocale, type Locale } from './locales' + +type Dict = typeof fr +// gcf est vérifié par TypeScript contre la forme du français : une clé +// manquante est une erreur de build, pas un fallback silencieux (ADR-001). +const dicts: Record = { fr, gcf } + +const STORAGE_KEY = 'oki-lang' + +function initialLocale(): Locale { + if (!browser) return defaultLocale + const saved = localStorage.getItem(STORAGE_KEY) + return saved === 'gcf' || saved === 'fr' ? saved : defaultLocale +} + +// Rune d'état partagée (Svelte 5) : la langue de l'interface. +// Le HTML prérendu est en fr ; le créole est une amélioration progressive +// (persistance localStorage — mission §4.3, doctrine §4.2). +const state = $state({ locale: initialLocale() }) + +export function getLocale(): Locale { + return state.locale +} + +export function setLocale(locale: Locale) { + state.locale = locale + if (browser) { + localStorage.setItem(STORAGE_KEY, locale) + document.documentElement.lang = locale + } +} + +function lookup(dict: Dict, path: string): unknown { + return path.split('.').reduce((node, key) => { + if (node && typeof node === 'object' && key in node) { + return (node as Record)[key] + } + return undefined + }, dict) +} + +/** Chaîne d'interface pour `path` dans la langue courante (réactif). */ +export function t(path: string): string { + const hit = lookup(dicts[state.locale], path) ?? lookup(dicts[defaultLocale], path) + if (typeof hit !== 'string') { + throw new Error(`Clé i18n manquante « ${path} » (locale : ${state.locale})`) + } + return hit +} diff --git a/frontend/src/lib/i18n/locales.ts b/frontend/src/lib/i18n/locales.ts new file mode 100644 index 0000000..759991c --- /dev/null +++ b/frontend/src/lib/i18n/locales.ts @@ -0,0 +1,11 @@ +// gcf = créole guadeloupéen (ISO 639-3, valide BCP 47). +// La langue du cœur d'OKI : les micro-textes créoles activent les circuits +// de confiance avant toute lecture consciente (doctrine §4.2). +export const locales = ['fr', 'gcf'] as const +export type Locale = (typeof locales)[number] +export const defaultLocale: Locale = 'fr' + +export const localeNames: Record = { + fr: 'Français', + gcf: 'Kréyòl' +} diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte new file mode 100644 index 0000000..d4f622c --- /dev/null +++ b/frontend/src/routes/+layout.svelte @@ -0,0 +1,108 @@ + + + + +
+ +
+ +
+ {@render children()} +
+ + + + diff --git a/frontend/src/routes/+layout.ts b/frontend/src/routes/+layout.ts new file mode 100644 index 0000000..f962865 --- /dev/null +++ b/frontend/src/routes/+layout.ts @@ -0,0 +1,3 @@ +// Tout le site est prérendu (ADR-001) : HTML statique servi par nginx, +// un lien fonctionne sans JS (doctrine §4.4). +export const prerender = true diff --git a/frontend/src/routes/+page.server.ts b/frontend/src/routes/+page.server.ts new file mode 100644 index 0000000..aee7f1d --- /dev/null +++ b/frontend/src/routes/+page.server.ts @@ -0,0 +1,11 @@ +import { loadContent } from '$lib/content/tools.server' + +export function load() { + const { tools, categories } = loadContent() + return { + categories, + toolCount: tools.length, + // les premiers gestes : outils débutant, un par catégorie + starters: tools.filter((t) => t.difficulty === 'beginner').slice(0, 3) + } +} diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte new file mode 100644 index 0000000..69806be --- /dev/null +++ b/frontend/src/routes/+page.svelte @@ -0,0 +1,92 @@ + + + + {t('site.name')} — {t('site.tagline')} + + + + +
+

{t('hero.title')}

+

{t('hero.subtitle')}

+

{t('hero.cta')} · {data.toolCount} {t('directory.results')}

+
+ +
+

{t('directory.intro')}

+
+
    + {#each data.starters as tool (tool.slug)} +
  • + {/each} +
+
+
+ +
+

{t('directory.filterCategory')}

+
    + {#each data.categories as cat (cat.slug)} +
  • {cat.title}
  • + {/each} +
+
+ + diff --git a/frontend/src/routes/outils/+page.server.ts b/frontend/src/routes/outils/+page.server.ts new file mode 100644 index 0000000..bbea4ba --- /dev/null +++ b/frontend/src/routes/outils/+page.server.ts @@ -0,0 +1,10 @@ +import { loadContent } from '$lib/content/tools.server' + +export function load() { + const { tools, categories } = loadContent() + return { + categories, + // seules les données de carte partent au client (budget JS, doctrine §4.4) + tools: tools.map(({ sections: _sections, ...card }) => card) + } +} diff --git a/frontend/src/routes/outils/+page.svelte b/frontend/src/routes/outils/+page.svelte new file mode 100644 index 0000000..b7740b7 --- /dev/null +++ b/frontend/src/routes/outils/+page.svelte @@ -0,0 +1,136 @@ + + + + {t('directory.title')} — {t('site.name')} + + + +
+

{t('directory.title')}

+

{t('directory.intro')}

+
+ +
+ + + +
+ +
+

+ {filtered.length} + {filtered.length === 1 ? t('directory.resultOne') : t('directory.results')} +

+ + {#if filtered.length === 0} +

{t('directory.empty')}

+ {:else} +
+
    + {#each filtered as tool (tool.slug)} +
  • + {/each} +
+
+ {/if} + + +
+ + diff --git a/frontend/src/routes/outils/[slug]/+page.server.ts b/frontend/src/routes/outils/[slug]/+page.server.ts new file mode 100644 index 0000000..0eec6df --- /dev/null +++ b/frontend/src/routes/outils/[slug]/+page.server.ts @@ -0,0 +1,14 @@ +import { error } from '@sveltejs/kit' +import { loadContent } from '$lib/content/tools.server' + +export function entries() { + return loadContent().tools.map(({ slug }) => ({ slug })) +} + +export function load({ params }: { params: { slug: string } }) { + const { tools, categories } = loadContent() + const tool = tools.find((t) => t.slug === params.slug) + if (!tool) error(404) + const category = categories.find((c) => c.slug === tool.category) + return { tool, category } +} diff --git a/frontend/src/routes/outils/[slug]/+page.svelte b/frontend/src/routes/outils/[slug]/+page.svelte new file mode 100644 index 0000000..aefaa30 --- /dev/null +++ b/frontend/src/routes/outils/[slug]/+page.svelte @@ -0,0 +1,132 @@ + + + + {tool.name} — {t('site.name')} + + + + + + {@html jsonLd} + + + + +
+
+
+ +

{tool.name}

+
+
+ + {#if data.category} + {data.category.title} + {/if} + {#if tool.license} + {t('tool.license')} : {tool.license} + {/if} + {#each tool.tags as tag (tag)} + {tag} + {/each} +
+

+ {t('tool.officialSite')} ↗ +

+
+ + {#each SECTION_ORDER as key (key)} + {#if tool.sections[key]} +
+

{t(HEADINGS[key])}

+ + +
{@html tool.sections[key]}
+
+ {/if} + {/each} +
+ + diff --git a/frontend/src/styles/base.css b/frontend/src/styles/base.css new file mode 100644 index 0000000..41edc52 --- /dev/null +++ b/frontend/src/styles/base.css @@ -0,0 +1,99 @@ +/* + * base.css — HTML sémantique nu (doctrine §4.3 : l'accessibilité est + * d'abord un problème de HTML correct). + */ +body { + font-family: var(--font-text); + font-size: var(--text-1); + line-height: var(--leading); + color: var(--oki-ink); + background: var(--oki-surface); +} + +h1, +h2, +h3 { + font-family: var(--font-display); + line-height: 1.15; + text-wrap: balance; +} + +h1 { + font-size: var(--text-5); +} +h2 { + font-size: var(--text-4); +} +h3 { + font-size: var(--text-2); +} + +p, +li { + max-width: var(--measure); +} + +a { + color: var(--accent-ink); + text-decoration-thickness: 1px; + text-underline-offset: 0.2em; +} + +a:hover { + text-decoration-thickness: 2px; +} + +/* focus visible sur TOUT élément interactif (doctrine §4.3) */ +:focus-visible { + outline: var(--focus-ring); + outline-offset: 2px; + border-radius: var(--radius-1); +} + +button { + min-height: var(--tap-target); /* Fitts, doctrine §1.3 */ + padding-inline: var(--space-3); + border: 1px solid var(--oki-line); + border-radius: var(--radius-2); + background: var(--oki-surface-2); + cursor: pointer; +} + +code { + font-size: 0.9em; + background: var(--oki-surface-2); + padding: 0.1em 0.35em; + border-radius: var(--radius-1); +} + +pre { + overflow-x: auto; + padding: var(--space-3); + background: var(--oki-surface-2); + border-radius: var(--radius-2); +} + +pre code { + background: none; + padding: 0; +} + +::selection { + background: var(--oki-jaune); + color: var(--oki-noir); +} + +/* lien d'évitement clavier */ +.skip-link { + position: absolute; + inset-inline-start: var(--space-3); + inset-block-start: var(--space-3); + translate: 0 -300%; + background: var(--oki-surface); + padding: var(--space-2) var(--space-3); + z-index: 10; +} + +.skip-link:focus { + translate: 0 0; +} diff --git a/frontend/src/styles/fonts.css b/frontend/src/styles/fonts.css new file mode 100644 index 0000000..e30b6f0 --- /dev/null +++ b/frontend/src/styles/fonts.css @@ -0,0 +1,20 @@ +/* + * Polices auto-hébergées, servies depuis notre domaine — jamais de Google + * Fonts (doctrine §5.3 : performance, RGPD, souveraineté). + * Budget : 2 fichiers WOFF2 maximum. Le gras du corps est synthétisé. + */ +@font-face { + font-family: 'Atkinson Hyperlegible'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/atkinson-hyperlegible-latin-400-normal.woff2') format('woff2'); +} + +@font-face { + font-family: 'Fraunces'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/fraunces-latin-700-normal.woff2') format('woff2'); +} diff --git a/frontend/src/styles/layouts.css b/frontend/src/styles/layouts.css new file mode 100644 index 0000000..ef07f8c --- /dev/null +++ b/frontend/src/styles/layouts.css @@ -0,0 +1,63 @@ +/* + * layouts.css — primitives de composition (approche « Every Layout » : + * des compositions, pas des pages — doctrine §5.2). + * Le responsive passe par container queries, jamais par media queries + * de largeur d'écran (doctrine §2.2 point 6). + */ +.stack { + display: flex; + flex-direction: column; + gap: var(--gap, var(--space-3)); +} + +.cluster { + display: flex; + flex-wrap: wrap; + gap: var(--gap, var(--space-2)); + align-items: var(--align, center); +} + +.center { + box-sizing: content-box; + max-inline-size: var(--max, 70rem); + margin-inline: auto; + padding-inline: var(--space-3); +} + +.prose { + max-inline-size: var(--measure); +} + +/* grille de cartes : pilotée par le conteneur, pas par l'écran */ +.card-grid { + container-type: inline-size; +} + +.card-grid > ul { + list-style: none; + padding: 0; + display: grid; + gap: var(--space-3); + grid-template-columns: 1fr; +} + +@container (min-width: 44rem) { + .card-grid > ul { + grid-template-columns: repeat(2, 1fr); + } +} + +@container (min-width: 68rem) { + .card-grid > ul { + grid-template-columns: repeat(3, 1fr); + } +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; +} diff --git a/frontend/src/styles/reset.css b/frontend/src/styles/reset.css new file mode 100644 index 0000000..1eff647 --- /dev/null +++ b/frontend/src/styles/reset.css @@ -0,0 +1,54 @@ +/* Reset moderne minimal (doctrine §5.2 — ~30 lignes, rien de plus). */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; +} + +html { + /* jamais de font-size en px sur html : respect de la taille utilisateur (doctrine §4.3) */ + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; +} + +body { + min-height: 100dvh; + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +img, +picture, +svg, +video { + display: block; + max-width: 100%; +} + +input, +button, +textarea, +select { + font: inherit; + color: inherit; +} + +p, +h1, +h2, +h3, +h4 { + overflow-wrap: break-word; +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} diff --git a/frontend/src/styles/tokens.css b/frontend/src/styles/tokens.css new file mode 100644 index 0000000..81b45ae --- /dev/null +++ b/frontend/src/styles/tokens.css @@ -0,0 +1,77 @@ +/* + * tokens.css — design tokens OKI (doctrine §5.2). + * Toute valeur visuelle du site vit ici ; les composants Svelte consomment + * les tokens, jamais de valeur brute (couleur, taille) dans un composant. + * Couleurs en oklch() : luminance perceptuelle maîtrisée => contraste WCAG + * calculable (méthode modus-vivendi, doctrine §4.3). + */ +:root { + color-scheme: light dark; + + /* ── Identité panafricaine OKI ─────────────────────────────────────── */ + --oki-ink: light-dark(oklch(18% 0.02 260), oklch(94% 0.01 260)); + --oki-surface: light-dark(oklch(97% 0.005 90), oklch(14% 0.02 260)); + --oki-surface-2: light-dark(oklch(93% 0.008 90), oklch(20% 0.02 260)); + --oki-line: light-dark(oklch(85% 0.01 90), oklch(32% 0.02 260)); + --oki-ink-2: light-dark(oklch(38% 0.02 260), oklch(75% 0.01 260)); + + /* Couleurs identitaires (drapeau panafricain — jaune/vert/rouge/noir) */ + --oki-jaune: oklch(75% 0.18 85); + --oki-vert: oklch(55% 0.18 145); + --oki-rouge: oklch(55% 0.22 25); + --oki-noir: oklch(15% 0.01 260); + + /* Accent principal : le jaune OKI, décliné pour rester AA sur chaque fond */ + --accent: light-dark(oklch(52% 0.14 85), var(--oki-jaune)); + --accent-ink: light-dark(oklch(35% 0.1 85), oklch(85% 0.16 85)); + + /* ── Difficulté — jamais portée par la couleur seule (doctrine §1.1) ── + Chaque niveau = couleur + texte + icône dans DifficultyBadge. */ + --diff-beginner: oklch(65% 0.15 145); + --diff-intermediate: oklch(75% 0.16 85); + --diff-advanced: oklch(55% 0.18 25); + /* variantes texte, contrastées AA sur --oki-surface */ + --diff-beginner-ink: light-dark(oklch(42% 0.14 145), oklch(78% 0.15 145)); + --diff-intermediate-ink: light-dark(oklch(48% 0.13 85), oklch(80% 0.15 85)); + --diff-advanced-ink: light-dark(oklch(46% 0.18 25), oklch(72% 0.16 25)); + + /* ── Typographie fluide (clamp, zéro media query — doctrine §5.2) ──── + Échelle modulaire ratio 1.25, corps 16px mobile → 18px desktop. */ + --text-0: clamp(0.875rem, 0.85rem + 0.15vw, 0.9375rem); + --text-1: clamp(1rem, 0.95rem + 0.4vw, 1.125rem); + --text-2: clamp(1.25rem, 1.17rem + 0.5vw, 1.4rem); + --text-3: clamp(1.56rem, 1.42rem + 0.8vw, 1.75rem); + --text-4: clamp(1.95rem, 1.7rem + 1.4vw, 2.44rem); + --text-5: clamp(2.44rem, 2rem + 2.4vw, 3.4rem); + + --font-text: 'Atkinson Hyperlegible', system-ui, sans-serif; + --font-display: 'Fraunces', var(--font-text); + + --measure: 65ch; /* largeur de lecture 45-75ch (doctrine §2.2) */ + --leading: 1.6; + + /* ── Espacement modulaire ────────────────────────────────────────── */ + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 1rem; + --space-4: 1.5rem; + --space-5: 2.5rem; + --space-6: 4rem; + + /* ── Interaction ─────────────────────────────────────────────────── */ + --tap-target: 48px; /* Fitts (doctrine §1.3) */ + --radius-1: 4px; + --radius-2: 10px; + --duration-1: 120ms; + --duration-2: 240ms; + --ease-out: cubic-bezier(0.2, 0, 0, 1); + + --focus-ring: 3px solid var(--accent); +} + +@media (prefers-contrast: more) { + :root { + --oki-ink: light-dark(oklch(5% 0.01 260), oklch(99% 0 0)); + --oki-line: light-dark(oklch(40% 0.01 260), oklch(70% 0.01 260)); + } +} diff --git a/frontend/static/favicon.png b/frontend/static/favicon.png new file mode 100644 index 0000000..0793b0a Binary files /dev/null and b/frontend/static/favicon.png differ diff --git a/frontend/static/fonts/atkinson-hyperlegible-latin-400-normal.woff2 b/frontend/static/fonts/atkinson-hyperlegible-latin-400-normal.woff2 new file mode 100644 index 0000000..2e43c90 Binary files /dev/null and b/frontend/static/fonts/atkinson-hyperlegible-latin-400-normal.woff2 differ diff --git a/frontend/static/fonts/fraunces-latin-700-normal.woff2 b/frontend/static/fonts/fraunces-latin-700-normal.woff2 new file mode 100644 index 0000000..71bbace Binary files /dev/null and b/frontend/static/fonts/fraunces-latin-700-normal.woff2 differ diff --git a/frontend/static/site.webmanifest b/frontend/static/site.webmanifest new file mode 100644 index 0000000..3bf4fdd --- /dev/null +++ b/frontend/static/site.webmanifest @@ -0,0 +1,18 @@ +{ + "name": "Exit Chat Control", + "short_name": "ExitCC", + "description": "Annuaire d'outils libres pour la souveraineté numérique", + "lang": "fr", + "start_url": "/", + "display": "standalone", + "background_color": "#17181f", + "theme_color": "#17181f", + "icons": [ + { + "src": "/favicon.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + } + ] +} diff --git a/frontend/svelte.config.js b/frontend/svelte.config.js new file mode 100644 index 0000000..c4e11fa --- /dev/null +++ b/frontend/svelte.config.js @@ -0,0 +1,19 @@ +import adapter from '@sveltejs/adapter-static' +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + preprocess: vitePreprocess(), + kit: { + // Site 100 % prérendu : servi par nginx sur l'infra OKI, mirrorable + // (ADR-001 ; doctrine §4.4 — HTML rendu serveur, un lien marche sans JS). + adapter: adapter({ + fallback: '404.html' + }), + prerender: { + handleHttpError: 'fail' + } + } +} + +export default config diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..4344710 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..78873e7 --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,12 @@ +import { sveltekit } from '@sveltejs/kit/vite' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [sveltekit()], + server: { + fs: { + // le contenu éditorial vit à la racine du repo, hors de frontend/ + allow: ['..'] + } + } +})