From 7ed0276704775922bfa3f3779cbf96db2d76e742 Mon Sep 17 00:00:00 2001 From: hacklab Date: Tue, 29 Sep 2026 10:26:46 +0200 Subject: [PATCH] =?UTF-8?q?README=20corto=20y=20sin=20comentarios=20en=20e?= =?UTF-8?q?l=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 120 ++--------------------- deploy/hub.conf | 3 - deploy/nginx.conf | 6 -- deploy/web26s.service | 2 - site/css/main.css | 3 - tools/__pycache__/genera.cpython-311.pyc | Bin 0 -> 14395 bytes tools/extrae.js | 18 ---- tools/genera.py | 16 --- tools/limpia-img.sh | 4 - 9 files changed, 7 insertions(+), 165 deletions(-) create mode 100644 tools/__pycache__/genera.cpython-311.pyc diff --git a/README.md b/README.md index 7e4df7d..9683d02 100644 --- a/README.md +++ b/README.md @@ -1,117 +1,11 @@ # acampada26s.net -Web de la acampada del 26S en Madrid. Comunicados, directo, cómo organizarse -y dónde están los colectivos. +Web de la acampada del 26S en Madrid. HTML y CSS, sin JavaScript. -HTML y CSS. Sin JavaScript en el navegador, sin cookies, sin analítica y sin -peticiones a terceros. La tipografía va dentro del repo. +1. `site/` va a `/var/www/acampada26s.net`. `deploy/nginx.conf` y `deploy/hub.conf` a nginx. +2. Directo es el HUB del pub OASIS (`/c`), servido en local en `127.0.0.1:3000`. +3. Comunicados, comisiones y debates salen de OASIS con `deploy/web26s.timer`. Rellenar `CUENTA` y `TRIBU` en `deploy/web26s.service`. +4. Publica quien está en la tribu pública de la acampada y lo sigue la cuenta de la acampada. Comunicado: post con `#comunicado26s`, primera línea de título. Comisión: subtribu pública. Debate: foro público. +5. Fotos subidas a mano: `tools/limpia-img.sh` antes, siempre. -La comunicación viva no depende de esta web: va por un pub de -[OASIS](https://code.03c8.net/krakenslab/oasis) (Secure Scuttlebutt). Si la web -cae o la tiran, el pub y lo publicado siguen en la red. - -## Estructura - -``` -site/ lo que se sirve (copiar tal cual a /var/www/acampada26s.net) -deploy/ nginx y timer de systemd -tools/ generador desde OASIS y limpieza de imágenes -``` - -## Qué sale de dónde - -- **Directo**: enlace al HUB del pub (`/c?type=feed`). Lo sube la gente de - comunicación desde OASIS. No pasa por esta web. -- **Comunicados, comisiones y debates**: los genera `tools/` a partir de OASIS - cada dos minutos. Nadie edita HTML a mano. -- **Colectivos**: lista fija en `site/index.html`. Para añadir uno, un `
  • ` - más. Solo webs o cuentas comprobadas. - -## Publicar desde OASIS - -Quien publica en la web: miembros de la tribu pública de la acampada **a los -que la cuenta de la acampada sigue**. Hacen falta las dos cosas. Unirse a una -tribu es un mensaje que cualquiera puede publicar sobre sí mismo (el código de -invitación solo lo comprueba la interfaz), así que la tribu sola no vale como -permiso. El follow lo firma la cuenta de la acampada y no se puede falsificar. - -- Dar permiso: invitar a la tribu y seguir desde la cuenta de la acampada. -- Quitarlo: dejar de seguir. Sus comunicados desaparecen en la siguiente pasada. - -Qué se publica: - -- **Comunicado**: un post con `#comunicado26s`. La primera línea es el título. - Las imágenes adjuntas salen en la página. Si se borra en OASIS, se borra aquí. -- **Comisión**: una subtribu pública de la tribu de la acampada, creada por - alguien con permiso. -- **Debate**: un foro público abierto por alguien con permiso. - -Las tribus privadas y lo que se escribe dentro de las tribus va cifrado; eso -no sale en la web ni debe salir. - -La tribu tiene que ser pública (no anónima) y con invitación estricta, y la -tiene que crear la cuenta de la acampada. - -## Imágenes - -Las de los comunicados las sirve el pub (`/c/blob/...`). Las que se suban a -mano a `site/img/`, siempre limpias antes: - -``` -tools/limpia-img.sh site/img/*.jpg -``` - -El EXIF lleva GPS, modelo de móvil y hora. Caras tapadas salvo permiso expreso. - -## Despliegue - -Requisitos: nginx, certbot, el pub OASIS en la misma máquina, Node 22 y -Python 3.9+. - -``` -rsync -a --exclude comunicados/ site/ /var/www/acampada26s.net/ -cp deploy/nginx.conf /etc/nginx/sites-available/acampada26s.net -cp deploy/hub.conf /etc/nginx/snippets/acampada26s-hub.conf -ln -s ../sites-available/acampada26s.net /etc/nginx/sites-enabled/ -nginx -t && systemctl reload nginx -``` - -Un `rsync` de `index.html` deja los bloques generados vacíos; el timer los -repone en dos minutos. - -### Pub OASIS - -`sh oasis.sh server`. El HUB web escucha en `:3000`; mejor solo en local -(`--host=127.0.0.1`). nginx publica `/c` en solo lectura y sin la IP de quien -visita. - -### Generador - -``` -cp -r . /opt/26s -cp deploy/web26s.service deploy/web26s.timer /etc/systemd/system/ -# rellenar CUENTA, TRIBU, OASIS_DIR y User en web26s.service -systemctl enable --now web26s.timer -``` - -A mano: - -``` -OASIS_DIR=~/oasis CUENTA=@...ed25519 TRIBU=%...sha256 node tools/extrae.js \ - | python3 tools/genera.py site -``` - -`extrae.js` solo lee del sbot por su socket local. `genera.py` escapa todo lo -que viene de SSB, solo deja enlaces `http(s)` y escribe de forma atómica. - -## Comprobaciones antes de subir - -``` -grep -rniE ' HUB clearnet de OASIS (solo lectura) del pub de la acampada. - server_tokens off; -# Logs sin IP completa: se guarda solo la /24. map $remote_addr $ip_anon { ~(?P\d+\.\d+\.\d+)\.\d+ $ip.0; ~(?P[^:]+:[^:]+): $ip::; @@ -48,7 +43,6 @@ server { expires 7d; } - # HUB de OASIS. Trae CSS inline, así que hub.conf redefine las cabeceras sin la CSP. location = /c { include /etc/nginx/snippets/acampada26s-hub.conf; } location ^~ /c/ { include /etc/nginx/snippets/acampada26s-hub.conf; } } diff --git a/deploy/web26s.service b/deploy/web26s.service index 5e0c8a7..80875c7 100644 --- a/deploy/web26s.service +++ b/deploy/web26s.service @@ -6,11 +6,9 @@ After=oasis.service Type=oneshot User=oasis Environment=OASIS_DIR=/home/oasis/oasis -# cuenta de la acampada y clave (%...sha256) de su tribu pública Environment=CUENTA= Environment=TRIBU= Environment=WEB=/var/www/acampada26s.net -# node tiene que estar en el PATH del servicio (o poner la ruta completa) ExecStart=/bin/sh -c 'set -e; node /opt/26s/tools/extrae.js > /tmp/26s.json; python3 /opt/26s/tools/genera.py "$WEB" < /tmp/26s.json' NoNewPrivileges=yes ProtectSystem=strict diff --git a/site/css/main.css b/site/css/main.css index b52a8a2..4fa0fe4 100644 --- a/site/css/main.css +++ b/site/css/main.css @@ -43,7 +43,6 @@ h1 { font-size: clamp(48px, 11vw, 120px); margin: 24px 0 16px; } h2 { font-size: 40px; margin: 48px 0 16px; border-bottom: var(--bd); padding-bottom: 6px; } h3 { font-size: 26px; margin: 0 0 6px; } -/* cuadros y botones */ .cuadros, .botonera { display: grid; gap: var(--gap); padding: 0; margin: 0; list-style: none; } .cuadros { grid-template-columns: repeat(3, 1fr); } .botonera { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); margin-top: var(--gap); } @@ -68,7 +67,6 @@ h3 { font-size: 26px; margin: 0 0 6px; } outline: none; } -/* comunicados */ .lista { list-style: none; margin: 0; padding: 0; } .lista > li { border-bottom: 1px solid var(--fg); padding: 20px 0; } .lista a:hover, .lista a:focus-visible { color: var(--acc); } @@ -97,7 +95,6 @@ footer { margin: 64px 0 24px; border-top: var(--bd); padding-top: 12px; font-siz .bt:hover, .bt:focus-visible { transform: none; } } -/* colectivos */ .colectivos { list-style: none; margin: 0 0 16px; padding: 0; columns: 2 280px; column-gap: 32px; } .colectivos li { break-inside: avoid; padding: 6px 0; border-bottom: 1px solid var(--fg); } .colectivos a { font-family: var(--tit); font-size: 22px; text-transform: uppercase; text-decoration: none; } diff --git a/tools/__pycache__/genera.cpython-311.pyc b/tools/__pycache__/genera.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..935537cc807956aabda1fa70d905f5e9dd318eb8 GIT binary patch literal 14395 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 KZGmE}lKvl3$6(d~ literal 0 HcmV?d00001 diff --git a/tools/extrae.js b/tools/extrae.js index b3f4e0d..4759ff0 100755 --- a/tools/extrae.js +++ b/tools/extrae.js @@ -1,16 +1,4 @@ #!/usr/bin/env node -// Lee del sbot de OASIS lo que va a la web y lo saca en JSON para tools/genera.py. -// -// Quién publica: miembros de la tribu TRIBU a los que CUENTA sigue, más CUENTA. -// La tribu sola no basta: en SSB cualquiera puede publicar que se une a una tribu -// (la invitación solo la comprueba la interfaz de OASIS). El follow de CUENTA sí -// está firmado por CUENTA. -// -// comunicados posts con #comunicado26s de quien publica -// comisiones subtribus públicas de TRIBU creadas por quien publica -// debates foros públicos abiertos por quien publica -// -// Uso: OASIS_DIR=~/oasis CUENTA=@...ed25519 TRIBU=%...sha256 node tools/extrae.js const path = require('path'); const dir = process.env.OASIS_DIR || path.join(process.env.HOME, 'oasis'); @@ -26,7 +14,6 @@ if (!CUENTA || !CUENTA.startsWith('@') || !TRIBU || !TRIBU.startsWith('%')) { const ssbConfig = require(path.join(dir, 'src', 'server', 'ssb_config')); const ssbClient = require(path.join(dir, 'src', 'server', 'node_modules', 'ssb-client')); -// igual que STRUCTURAL_FIELDS en src/models/tribes_model.js const ESTRUCTURA = ['title', 'description', 'image', 'location', 'tags', 'isAnonymous', 'inviteMode', 'status', 'parentTribeId', 'mapUrl']; @@ -44,9 +31,6 @@ const todos = (src) => new Promise((res, rej) => { const lista = (x) => (Array.isArray(x) ? x : []); const igual = (a, b) => JSON.stringify(a ?? null) === JSON.stringify(b ?? null); -// Cadena de una tribu (create + updates por `replaces`) con las mismas reglas que -// buildTribeIndex: el autor raíz cambia lo que quiera; otro miembro solo puede -// entrar o salir él mismo. Devuelve el último estado válido. function puntaTribu(raiz, msgs) { const porPadre = new Map(); for (const m of msgs) { @@ -98,7 +82,6 @@ ssbClient(ssbConfig.keys, { remote, caps: ssbConfig.caps }).then(async (ssb) => const [contactos, tribus, posts, feeds, foros, lapidas] = await Promise.all( ['contact', 'tribe', 'post', 'feed', 'forum', 'tombstone'].map(tipo)); - // a quién sigue CUENTA (el último contact gana) const sigue = new Map(); for (const m of contactos) { const c = m.value.content; @@ -115,7 +98,6 @@ ssbClient(ssbConfig.keys, { remote, caps: ssbConfig.caps }).then(async (ssb) => const miembros = lista(puntaTribu(raiz, deTribu(raiz)).value.content.members); const editores = new Set([CUENTA, ...miembros.filter((id) => sigue.get(id) === true)]); - // borrado: tombstone del propio autor const borrado = new Set(lapidas .filter((m) => typeof m.value.content.target === 'string') .map((m) => `${m.value.author} ${m.value.content.target}`)); diff --git a/tools/genera.py b/tools/genera.py index beb9aee..961b16f 100755 --- a/tools/genera.py +++ b/tools/genera.py @@ -1,17 +1,4 @@ #!/usr/bin/env python3 -"""Escribe en la web lo que sale de tools/extrae.js. - -Lee el JSON por stdin y, dentro de SITE: - - rellena en index.html los bloques entre y - para X = comunicados, comisiones, debates - - crea comunicados/AAAA-MM-DD-xxxxxxxx.html por comunicado y borra los que - ya no están (borrados en OASIS o de alguien que ya no publica) - -Todo el texto que viene de SSB se escapa. Escritura atómica: nginx nunca sirve -un fichero a medias. - - node tools/extrae.js | python3 tools/genera.py /var/www/acampada26s.net -""" import hashlib import html import json @@ -40,7 +27,6 @@ def blob(ref): def plano(texto): - """Texto sin markdown de imágenes/enlaces ni la etiqueta, en una línea.""" texto = IMG.sub("", texto) texto = ENLACE.sub(r"\1", texto) texto = ETIQUETA.sub("", texto) @@ -48,7 +34,6 @@ def plano(texto): def partir(texto): - """Primera línea con contenido = título; el resto = cuerpo.""" lineas = ETIQUETA.sub("", texto).replace("\r", "").split("\n") for i, l in enumerate(lineas): t = plano(l).lstrip("# ").strip() @@ -58,7 +43,6 @@ def partir(texto): def cuerpo(texto): - """Markdown mínimo: párrafos, saltos, imágenes del pub y enlaces http(s).""" out = [] for parrafo in re.split(r"\n\s*\n", texto.replace("\r", "").strip()): if not parrafo.strip(): diff --git a/tools/limpia-img.sh b/tools/limpia-img.sh index ef902dc..e64d9f5 100755 --- a/tools/limpia-img.sh +++ b/tools/limpia-img.sh @@ -1,7 +1,4 @@ #!/bin/sh -# Quita metadatos (EXIF, GPS, modelo de móvil) de las imágenes antes de subirlas. -# Uso: tools/limpia-img.sh foto1.jpg foto2.png ... -# Necesita exiftool (libimage-exiftool-perl) o mat2. set -eu [ $# -gt 0 ] || { echo "uso: $0 imagen..." >&2; exit 1; } @@ -17,7 +14,6 @@ else exit 1 fi -# comprobación: no debe quedar GPS if command -v exiftool >/dev/null 2>&1; then if exiftool -q -q -if '$GPSLatitude' -p '$FileName' -- "$@" 2>/dev/null | grep .; then echo "ojo: quedan coordenadas GPS en las de arriba" >&2