macOS 26 · Apple Silicon

Un navigateur qui tient
en une fenêtre.

Écrit en Swift et AppKit, posé sur WebKit. Une colonne d'onglets à gauche, la page à droite, et une palette au centre quand on cherche quelque chose. Pas de barre d'outils qui s'accumule, pas de bouton qui ne fait rien.

Version 0.1.5 · image signée et notarisée par Apple · GPL-3.0

La fenêtre de Wuji sur un article de Wikipédia : la colonne d'onglets à gauche,
                la page à droite, et la barre du haut réduite à l'adresse.
Une colonne, une page. La barre du haut ne porte que l'adresse.
260règles écrites à la main, au format que WebKit compile
0dépendance dans le paquet
0octet de télémétrie
6listes qui se compilent et s'éteignent séparément

Ce que le navigateur sait faire

Chaque fonction est là parce qu'elle rend quelque chose possible, pas parce qu'un navigateur est censé l'avoir.

Espaces et dossiers

Les onglets appartiennent à un espace, pas à l'application. Un espace naît privé ou ne l'est jamais : ⇧⌘N en crée un — magasin de données éphémère, rien sur le disque — et il l'est jusqu'à sa fermeture. Une bascule privé/normal mentirait dans les deux sens.

Un onglet ne se ferme jamais tout seul

Passé un délai réglable — jamais, une minute, jusqu'à une heure — il rend sa mémoire sans quitter la colonne, et le survol le réveille avant même le clic. Un onglet qui joue du son ne s'endort pas, et il porte un haut-parleur à droite de son titre.

Zoom par site

⌘+ et ⌘− règlent le site qu'on regarde, et il s'en souvient : un site qui se lit mal n'impose pas sa correction à tout le web. Seuls les écarts sont conservés, et Réglages › Sites web les liste.

Journal de blocage

Une fenêtre qui montre ce qui est arrêté, ligne par ligne — pas de compteur : un chiffre qui monte ne se vérifie pas. Chaque ligne porte la liste dont une règle vise l'adresse, et la règle exacte au survol. « Aucune règle ne vise cette adresse » est la réponse la plus utile : l'absence ne vient pas de nous.

Certificats qu'aucune autorité n'atteste

L'ordinaire d'un service qu'on héberge soi-même. La page d'erreur montre le certificat — délivré à qui, par qui, jusqu'à quand, et son empreinte SHA-256 — puis propose de continuer. L'exception vaut pour cet hôte et cette session seulement, et n'est jamais écrite sur le disque.

Autorisations par site

Caméra, micro, position. Demandées une fois, retenues, révocables. La position passe par deux portes : le site vous demande, et macOS demande à Wuji — accorder la première sans la seconde donnait un refus que la page vous attribuait.

Scripts utilisateur

Installation depuis une adresse en .user.js, portée affichée avant d'accepter, mise à jour à la demande. Leur icône quitte la barre quand la fonction est éteinte.

Serveurs qui demandent qui vous êtes

Une authentification HTTP ouvre une bulle en bas à droite, au même endroit que les autres questions. Rien n'est retenu : ce qui est tapé part au serveur et disparaît avec la bulle.

Pages internes en wuji://

Favoris, historique, téléchargements, listes de règles, sites exclus, scripts, réglages — avec le même sommaire à gauche partout.

La palette

⌘L ouvre le même champ pour tout : une adresse, une recherche, un onglet déjà ouvert, l'historique, les favoris. Elle ne cherche que chez vous — aucune frappe ne part chez un moteur de recherche.

Téléverser un fichier

Un champ « choisir un fichier » ouvre le panneau du système, en feuille sur la fenêtre. C'est le seul endroit où le panneau de macOS est le bon : c'est son navigateur de fichiers qu'on demande, avec ses favoris et sa recherche.

Mises à jour

Réglages › Fonctions demande à GitHub la dernière version publiée, sans identifiant et sans dire laquelle vous utilisez : la comparaison se fait chez vous. Rien n'est téléchargé ni installé tout seul. La vérification au lancement est éteinte par défaut.

La palette ouverte au-dessus d'une page de résultats : un champ de saisie, puis
                  les onglets ouverts, les pages internes et l'historique, chacun avec son origine.
⌘L — la palette cherche dans ce que vous avez déjà : onglets ouverts, pages internes, historique, favoris. Rien ne part chez un moteur de recherche.

Le blocage

260 règles écrites directement dans le format de WKContentRuleList, celui que WebKit compile : 240 blocages et 20 masquages. Rien n'est téléchargé, rien n'est converti au démarrage — le navigateur lit les fichiers et les donne au moteur. Un convertisseur, si rapide soit-il, refait à chaque lancement un travail dont le résultat ne change pas.

Les six listes de blocage
ListeRèglesCe qu'elle vise
Mouchards72audience, comportement, attribution, courtiers d'identité, empreinte
Publicité84régies, enchères en temps réel, articles sponsorisés
Télémétrie des appareils57ce que les systèmes et les objets renvoient à leur fabricant
Habillage publicitaire20masque les éléments dont la classe annonce une publicité
Réseaux sociaux15boutons et pixels sociaux, hors du site du réseau
Rejeu de session12l'enregistrement de vos mouvements et de vos frappes
La page wuji://ad-block/lists : les six listes, leur nombre de règles, ce qu'elles
                  visent, et un interrupteur pour chacune.
wuji://ad-block/lists — six listes, six interrupteurs. Éteinte, une liste quitte le moteur et le disque.

Six listes, six interrupteurs

Chacune se compile à part et s'éteint dans wuji://ad-block/lists — éteinte, elle quitte le moteur et le disque, elle n'y reste pas neutralisée. Une famille n'existe que si l'on peut vouloir la garder en éteignant les autres : la télémétrie d'un téléviseur qu'on ne possède pas ne bloquera jamais rien.

Comment une règle entre dans la liste

Chacune est adossée à au moins une liste de référence — EasyList, EasyPrivacy, AdGuard, uBlock Origin, Peter Lowe, Turtlecute — et à une règle qui bloque le domaine entier, jamais à une simple mention. Chercher un nom n'importe où ferait bloquer un CDN majeur et la page de connexion Google.

Ce que ces règles ne font pas

  • Les publicités servies depuis le domaine du site lui-même passent — YouTube au premier chef. Les retirer demande d'exécuter du code dans la page et de le corriger chaque semaine. Wuji ne le fait pas et ne prétend pas le faire.
  • Les domaines jetables passent aussi. Les sites les plus agressifs tirent leurs publicités de noms générés au hasard ; une liste tenue à la main ne suit pas ce rythme.
  • Deux familles sont exclues même quand les listes les bloquent : les gestionnaires de consentement et les anti-robots. Absents, ils ne retirent pas la publicité — ils verrouillent la page.

Ce que le projet s'interdit

Les absences sont décidées, et voici pourquoi.

  • Aucun contrôle mort

    Un réglage qui ne pilote rien est pire qu'un réglage absent : il donne l'illusion d'un produit plus avancé qu'il ne l'est.

  • Aucune télémétrie

    Rien ne part de cette machine que vous n'ayez demandé. La seule requête que Wuji émette pour son propre compte est la vérification de version, et elle ne se déclenche que sur un clic.

  • Aucun mot de passe enregistré

    Stocker des identifiants demande de les remplir, et c'est le remplissage qui coûte : au mauvais endroit, il livre un mot de passe à un site qui ne l'a jamais eu. À moitié faite, cette fonction serait la pire chose que Wuji puisse embarquer.

  • Aucune suggestion du moteur de recherche

    Elles supposent d'envoyer chaque frappe à un tiers — « c », « ch », « cha » — y compris pour les recherches qu'on efface avant de les valider. La palette cherche donc chez vous seulement : onglets ouverts, historique, favoris.

  • Une seule fenêtre, parce qu'il y a les espaces

    Ailleurs, on ouvre une seconde fenêtre parce que les onglets n'ont aucun autre moyen d'être groupés — c'est un contournement. Ici les espaces persistent, se nomment et survivent à la fermeture.

  • Les favicons viennent du site

    Jamais d'un service tiers qui apprendrait au passage ce que vous visitez.

  • Aucune règle écrite pour faire passer un test

    Les pages de conformité proposent leurs propres filtres ; les adopter donne un bon score et ne protège personne.

Raccourcis

Tout se fait au clavier, y compris ce qui n'a pas de bouton.

⌘LPalette — adresse, recherche, onglets ouverts
⌘TNouvel onglet
⌘WFermer l'onglet
⇧⌘TRouvrir le dernier fermé
⌘]Onglet suivant
⌘[Onglet précédent
⇧⌘NNouvel espace privé
⌥⌘NNouveau dossier
⌘FRechercher dans la page
⌘RRecharger
⌘+Zoom du site · ⌘0 par défaut
⌘DMettre en favori · ⇧⌘B les ouvrir
⌘YHistorique
⌘JTéléchargements
⌘,Réglages
⌘MMinimiser la fenêtre

Installer

Ou le compiler soi-même

git clone https://github.com/Black0S/Wuji.git
cd Wuji
./run.sh

./run.sh compile en release, installe dans /Applications et lance depuis là — on teste où l'application vivra. Lancée depuis .build, elle n'a ni la place ni l'identité qu'elle aura chez quelqu'un.

./build.sh
assemble le paquet, sans le lancer
./dmg.sh
produit Wuji.dmg, signé ad-hoc — pour soi
./release.sh
le même, signé, notarisé et agrafé — pour les autres
./uninstall.sh
efface l'application et tout ce qu'elle a laissé
swift test
la logique pure : règles, nom d'un site, validité de l'asset

Licence

GPL-3.0. Wuji peut être lu, modifié et redistribué par qui veut — mais pas fermé : qui publie une version modifiée doit en publier le code sous la même licence. Le travail reste ouvert en aval, ce qu'une licence permissive ne garantit pas.

Ce choix ne l'empêche pas d'être vendu ni de recevoir un soutien : « libre » n'a jamais voulu dire gratuit. Il demande en revanche que les droits restent réunis en une seule main — d'où l'accord décrit dans CONTRIBUTING.md, qui laisse le travail des contributeurs sous GPL-3.0 comme le reste.

Aucune dépendance

La liste des suffixes publics vient de swift-psl et vit dans les sources, recopiée avec sa licence MIT.

Ce n'est pas une préférence : SwiftPM range les ressources d'une dépendance à la racine du paquet .app, et macOS refuse de signer une application qui porte quoi que ce soit à cet endroit. Le choix était donc entre la dépendance et la distribution.