Billets FR - CyberMind-FR/secubox-deb GitHub Wiki
EN | FR | 🟣 MIND | 🔐 auto-hébergé
Publie court, embarque, republie — un micro-blog passerelle inter-médias, hébergé chez toi.
Billets est une passerelle de micro-blog auto-hébergée : billets courts en Markdown restreint, galeries média zoomables, intégrations (oEmbed), réactions emoji, commentaires et flux Atom/JSON. FastAPI + aiosqlite (WAL) + Jinja2 sur son propre vhost (billets.<box>.secubox.in), derrière nginx → sbxwaf → HAProxy. Chaque billet est versionné dans Gitea ; chaque décision de sécurité va dans un journal chaîné BLAKE2b en ajout seul.
- Fil public :
https://billets.<box>.secubox.in/ - Administration auteur :
…/admin· Panneau opérateur :admin.<box>.secubox.in/billets/
| Cas | Ce que ça fait |
|---|---|
| Micro-blog souverain | notes courtes en Markdown restreint (pas de HTML brut), permalien stable, flux Atom/JSON, brouillon → publication → archivage, révisions dans Gitea |
| Galerie d'images | plusieurs images par billet (png, jpeg, webp, gif, 5 Mo max), ré-encodées (EXIF/GPS supprimés, SVG refusé), vignettes et lightbox au clavier ; la première image alimente og:image
|
| Passerelle inter-médias | collez une URL YouTube, Vimeo, Mastodon, PeerTube, Bluesky… ; sortie oEmbed et partage vers Mastodon |
| Commentaires et réactions | réactions 👍 ❤️ 😂 😮 😢 🔥 ; commentaires gardés par CSRF, pot de miel, jeton de formulaire et cadence ; IP jamais stockée en clair |
Sauvegarde .sbxsite
|
/admin/export.sbxsite : un fichier avec tous les billets et leurs médias, réimportable |
| Console opérateur | panneau d'administration de la box et réinitialisation du mot de passe de l'auteur, gardée par un secret root, mot de passe affiché une seule fois |
Le fil public est un flux vivant : chaque billet est une carte, et une carte avec média s'ouvre en « scène » (théâtre) avec les commentaires en incrustation.
| Comportement | Détail |
|---|---|
| Tri par activité | un billet publié ou commenté remonte en tête (bumped_at : publication ou dernier commentaire approuvé, jamais de recul). Les flux RSS/JSON gardent l'ordre de publication |
| Rafraîchissement automatique |
GET /feed/maj?depuis=<repère> rend les cartes qui ont bougé ; la page l'interroge toutes les 15 s et au retour sur l'onglet, pose les nouveautés en tête sans recharger, garde la position de défilement, ne retire jamais un billet en cours de lecture |
| Animations | un billet neuf tombe avec un halo et une pastille « nouveau », un billet remonté glisse depuis sa place avec « commenté » ; prefers-reduced-motion respecté |
| Reprise | un permalien rouvre exactement où l'on en était (position retenue à la sortie, onglet masqué, toutes les 4 s en lecture) |
| Réglages retenus | les bascules « sous-titres » et « CRT » sont mémorisées |
| Commentaires | publiés dès l'envoi (CSRF, pot de miel, jeton signé, cadence restent) ; un visiteur avec session SecuBox voit son nom de session remplacer ce qu'il a tapé ; 8 000 signes au plus |
| Source | Comportement |
|---|---|
| PeerTube (instance de la box) | se charge tout de suite, rien ne sort de la box |
| YouTube | mode souverain : l'iframe est armée mais non chargée, le clic vaut consentement ; avant, le lecteur voit un instantané local. URL réécrites en youtube-nocookie.com, bandeau « YouTube · clic pour charger ». Vignettes relayées par la box (/yt-vignette?v=<id>), seulement pour une vidéo qu'un billet référence |
| oEmbed (Vimeo, Mastodon, Bluesky…) | résolu sous garde SSRF, HTML assaini, frame-src en liste blanche |
| Carte de lien | pour une URL sans oEmbed utilisable : une carte HTML locale bâtie sur OpenGraph (titre, description, image https), jamais d'iframe ni de HTML distant |
| Images | ré-encodées, vignette de 480 px, agrandissables dans la vue billet et dans le texte (un seul agrandisseur, Échap et flèches) |
| Vidéos hébergées (mp4, webm) | une image extraite par ffmpeg à 1 s (repli : première image) devient la vignette <id>_t.jpg ; le fil et la carte du Hall montrent un aperçu au lieu d'un espace réservé. Sans ffmpeg ou en cas d'échec : pas de vignette, jamais d'erreur. Rattrapage : python -m api.manage backfill-posters
|
Un billet dont la pièce jointe est une vidéo montre sa vignette avec ▶ ; au clic, la vidéo se joue plein cadre, fond noir dans la scène. Sa position est le vrai currentTime et suit lecture et pause.
Un commentaire peut être attaché à un instant du média :
- vidéo hébergée : la position réelle de lecture ;
-
YouTube : la position réelle, lue par l'API
postMessagedu lecteur (temps courant, lecture/pause), dans la page du billet comme dans le théâtre du fil ; - sinon : une estimation (« base + temps écoulé »), bornée à 3 heures, puis « inconnue » : la ligne part sans instant plutôt qu'avec un faux, et rien n'est gardé en local quand l'instant est inconnu.
MetaNews transforme les sujets qui se forment en billets à durée de vie limitée.
-
La porte :
POST /service/ephemere, sur la socket Unix du module seulement. L'appelant présente un jeton de service (HS256) dont lesubestmetanews; une requête portantX-Real-IPouX-Forwarded-Forest passée par nginx et refusée en 403. Jeton absent ou invalide : 401 sans détail. -
Limites :
ttl_sobligatoire de 30 s à 1 h (jamais de billet durable) ; création seulement, ni modification ni suppression ; plafond de 60 par heure côté billets, quelle que soit la conduite de l'appelant. - Côté MetaNews : un sujet couvert par au moins 2 sources et récemment mis à jour entre dans le fil pour 5 minutes par défaut, puis s'efface. Au plus 6 sujets par heure glissante, un délai de grâce d'une heure par sujet, les plus importants d'abord, l'actualité ancienne jamais rejouée. Une panne de billets arrête le tour sans marquer le sujet et n'arrête jamais le sondage.
-
Contenu : le corps liste jusqu'à 5 sources en liens (https seulement, sans doublon) ; l'article principal le plus récent part en
embed_urlpour que billets bâtisse l'aperçu, et l'image du sujet (vignette_urlen https) est rapatriée en local comme vignette, car les sites d'actualité refusent les robots de capture de page. -
Cycle de vie : un billet échu quitte le fil,
/feed/suite,/feed/majet les flux RSS/JSON dès l'échéance ; son permalien répond410 Gone(« Ce billet éphémère a expiré ») ; un balayage l'archive (24 h pour l'audit) puis le supprime. Chaque carte éphémère porte un compte à rebours (⏳ m:ss, rouge et clignotant la dernière minute) calculé depuis les secondes restantes au rendu : l'horloge de l'appareil est indifférente.
Le BBS peut publier un fil en billet. Billets ignore que le BBS existe (le BBS appelle billets, jamais l'inverse), et :
- un fil local est refusé : rendez-le public explicitement d'abord, car publier, c'est mettre sur internet ;
- la publication se fait sous la session SecuBox de l'opérateur, pas sous une identité propre au BBS ;
- les messages locaux d'un fil public ne sont pas transmis ; les images sont ré-encodées (EXIF retiré) ;
- republier met à jour le billet existant au lieu d'en créer un autre ; dépublier le retire.
-
Portail opérateur
/billets/: refait au profil Aurora, en français, sur les statistiques réelles du blog de la box (stats.json) : tuiles, derniers billets, réactions et liens d'administration. Blog injoignable : la page affiche « — » et le dit. Les liens ne sont posés qu'enhttp(s)(jamaisjavascript:).?demo=1et?embed=1sont disponibles. -
Administration du blog habillée en Aurora : tableau de bord, modération, édition, connexion et réinitialisation du mot de passe partagent une feuille de style (
billets-admin.css), avec les mêmes classes, gabarits et routes qu'avant ; une pile de polices système remplace la police distante. Le fil public garde sa propre identité.
apt install secubox-billets
cd /usr/lib/secubox/billets
sudo -u secubox venv/bin/python -m api.manage create-author admin
haproxyctl vhost add billets.<box>.secubox.in # la route sbxwaf est déclarée par le paquet
systemctl restart secubox-billetsÉcrire un billet : …/admin/billets/new, texte Markdown, URL éventuelle (référence ou intégration), images, puis publier.
| Contrôle | Mise en œuvre |
|---|---|
| Envoi de fichiers | ré-encodage depuis les pixels, SVG refusé, 5 Mo avant traitement |
| Média servi |
/media/ statique, img-src 'self', aucun tiers |
| Authentification | argon2id, session signée, TOTP optionnel, CSRF, cadence par client réel |
| Boucle partagée | tout le calcul lourd (Pillow, base64, export) hors boucle d'événements |
| Journal | ajout seul chaîné BLAKE2b ; révisions Gitea par billet |
MODULES-FR · Architecture · API-Reference-FR · ToolBox · SBX-OS-FR · Cartes-du-Hall · Messagerie · Admin-Panels-Gallery-FR