Complemento ActivityPub

@hellekin Gracias por el informe. Siempre ocurrirá una cierta cantidad de solicitudes fallidas en un servicio ActivityPub, ya que los actores en el fediverso van y vienen. Por ejemplo, parece que:

  • La URL https://activitypub.example del primer registro no es una URL real (¿la cambiaste?)
  • El usuario https://mas.to/users/rikvipcode del segundo registro ya no existe
  • El usuario https://mastodon.social/users/ejovoni46709 del tercer registro ya no existe

La verbosidad de los registros está ahí para ayudar a depurar, sin embargo, si están saturando tus registros, puedes activarlos o desactivarlos usando la configuración del sitio activity pub verbose logging. El valor predeterminado es desactivado.

Estaremos buscando mejorar el manejo de errores en la fase dos si es necesario, pero hasta ahora parece que los fragmentos que publicaste son esperados, es decir, los Actores ya no están en el fediverso.

Actualmente, la forma en que el plugin maneja los fallos de entrega es rastrearlos de la misma manera que lo hace Mastodon, es decir, si hay 7 días de fallo a un punto final, se marcará como “no disponible” y ya no se intentarán las solicitudes.

3 Me gusta

Sí, como se indica en la línea anterior.

De hecho, pero el código de estado es 410, lo que significa que la cuenta puede haberse movido (si hay una “Tombstone” — ¿se comprueba esta condición?)

1 me gusta

No. Es el error 410 Gone y significa que el recurso ha sido eliminado. ¿Qué me estoy perdiendo ahora?

1 me gusta

Te perdiste esto:

Hola @angus,

Acabo de configurar un Discourse autoalojado completamente nuevo con tu plugin AP en https://federation.cafe, y estoy viendo algunos errores 403 en los Registros de Errores de Discourse (y las publicaciones no se están compartiendo).

Me pregunto si podría ser porque hay guiones, ¿tal vez?

[Discourse Activity Pub] GET request to https://bofh.social/internal/fetch failed: Expected([200, 201, 202, 301, 302, 307, 308]) <=> Actual(403 Forbidden)

/var/www/discourse/plugins/discourse-activity-pub/lib/discourse_activity_pub/request.rb:66:in `rescue in perform'
/var/www/discourse/plugins/discourse-activity-pub/lib/discourse_activity_pub/request.rb:50:in `perform'
/var/www/discourse/plugins/discourse-activity-pub/lib/discourse_activity_pub/request.rb:34:in `get_json_ld'
/var/www/discourse/plugins/discourse-activity-pub/lib/discourse_activity_pub/request.rb:106:in `get_json_ld'
/var/www/discourse/plugins/discourse-activity-pub/lib/discourse_activity_pub/json_ld.rb:52:in `request_object'
/var/www/discourse/plugins/discourse-activity-pub/lib/discourse_activity_pub/json_ld.rb:48:in `resolve_object'
/var/www/discourse/plugins/discourse-activity-pub/lib/discourse_activity_pub/ap/actor.rb:103:in `resolve_and_store'
/var/www/discourse/plugins/discourse-activity-pub/app/controllers/concerns/discourse_activity_pub/signature_verification.rb:192:in `actor_from_key_id'
/var/www/discourse/plugins/discourse-activity-pub/app/controllers/concerns/discourse_activity_pub/signature_verification.rb:57:in `signed_request_actor'
/var/www/discourse/plugins/discourse-activity-pub/app/controllers/concerns/discourse_activity_pub/signature_verification.rb:27:in `ensure_verified_signature'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:400:in `block in make_lambda'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:180:in `block (2 levels) in halting_and_conditional'
actionpack-7.0.4.3/lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:181:in `block in halting_and_conditional'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:595:in `block in invoke_before'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:595:in `each'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:595:in `invoke_before'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:116:in `block in run_callbacks'
/var/www/discourse/app/controllers/application_controller.rb:418:in `block in with_resolved_locale'
i18n-1.14.1/lib/i18n.rb:322:in `with_locale'
/var/www/discourse/app/controllers/application_controller.rb:418:in `with_resolved_locale'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:127:in `block in run_callbacks'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:138:in `run_callbacks'
actionpack-7.0.4.3/lib/abstract_controller/callbacks.rb:233:in `process_action'
actionpack-7.0.4.3/lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack-7.0.4.3/lib/action_controller/metal/instrumentation.rb:67:in `block in process_action'
activesupport-7.0.4.3/lib/active_support/notifications.rb:206:in `block in instrument'
activesupport-7.0.4.3/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport-7.0.4.3/lib/active_support/notifications.rb:206:in `instrument'
actionpack-7.0.4.3/lib/action_controller/metal/instrumentation.rb:66:in `process_action'
actionpack-7.0.4.3/lib/action_controller/metal/params_wrapper.rb:259:in `process_action'
activerecord-7.0.4.3/lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack-7.0.4.3/lib/abstract_controller/base.rb:151:in `process'
actionview-7.0.4.3/lib/action_view/rendering.rb:39:in `process'
rack-mini-profiler-3.1.0/lib/mini_profiler/profiling_methods.rb:85:in `block in profile_method'
actionpack-7.0.4.3/lib/action_controller/metal.rb:188:in `dispatch'
actionpack-7.0.4.3/lib/action_controller/metal.rb:251:in `dispatch'
actionpack-7.0.4.3/lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack-7.0.4.3/lib/action_dispatch/routing/route_set.rb:32:in `serve'
actionpack-7.0.4.3/lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack-7.0.4.3/lib/action_dispatch/journey/router.rb:32:in `each'
actionpack-7.0.4.3/lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack-7.0.4.3/lib/action_dispatch/routing/route_set.rb:852:in `call'
railties-7.0.4.3/lib/rails/engine.rb:530:in `call'
railties-7.0.4.3/lib/rails/railtie.rb:226:in `public_send'
railties-7.0.4.3/lib/rails/railtie.rb:226:in `method_missing'
actionpack-7.0.4.3/lib/action_dispatch/routing/mapper.rb:19:in `block in <class:Constraints>'
actionpack-7.0.4.3/lib/action_dispatch/routing/mapper.rb:48:in `serve'
actionpack-7.0.4.3/lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack-7.0.4.3/lib/action_dispatch/journey/router.rb:32:in `each'
actionpack-7.0.4.3/lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack-7.0.4.3/lib/action_dispatch/routing/route_set.rb:852:in `call'
/var/www/discourse/lib/middleware/omniauth_bypass_middleware.rb:74:in `call'
rack-2.2.7/lib/rack/tempfile_reaper.rb:15:in `call'
rack-2.2.7/lib/rack/conditional_get.rb:27:in `call'
rack-2.2.7/lib/rack/head.rb:12:in `call'
actionpack-7.0.4.3/lib/action_dispatch/http/permissions_policy.rb:38:in `call'
/var/www/discourse/lib/content_security_policy/middleware.rb:12:in `call'
/var/www/discourse/lib/middleware/anonymous_cache.rb:367:in `call'
rack-2.2.7/lib/rack/session/abstract/id.rb:266:in `context'
rack-2.2.7/lib/rack/session/abstract/id.rb:260:in `call'
actionpack-7.0.4.3/lib/action_dispatch/middleware/cookies.rb:704:in `call'
actionpack-7.0.4.3/lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport-7.0.4.3/lib/active_support/callbacks.rb:99:in `run_callbacks'
actionpack-7.0.4.3/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack-7.0.4.3/lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
actionpack-7.0.4.3/lib/action_dispatch/middleware/show_exceptions.rb:26:in `call'
logster-2.12.2/lib/logster/middleware/reporter.rb:43:in `call'
railties-7.0.4.3/lib/rails/rack/logger.rb:40:in `call_app'
railties-7.0.4.3/lib/rails/rack/logger.rb:27:in `call'
/var/www/discourse/config/initializers/100-quiet_logger.rb:20:in `call'
/var/www/discourse/config/initializers/100-silence_logger.rb:29:in `call'
actionpack-7.0.4.3/lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
actionpack-7.0.4.3/lib/action_dispatch/middleware/request_id.rb:26:in `call'
/var/www/discourse/lib/middleware/enforce_hostname.rb:24:in `call'
rack-2.2.7/lib/rack/method_override.rb:24:in `call'
actionpack-7.0.4.3/lib/action_dispatch/middleware/executor.rb:14:in `call'
rack-2.2.7/lib/rack/sendfile.rb:110:in `call'
actionpack-7.0.4.3/lib/action_dispatch/middleware/host_authorization.rb:131:in `call'
rack-mini-profiler-3.1.0/lib/mini_profiler.rb:260:in `call'
message_bus-4.3.2/lib/message_bus/rack/middleware.rb:60:in `call'
/var/www/discourse/lib/middleware/request_tracker.rb:228:in `call'
railties-7.0.4.3/lib/rails/engine.rb:530:in `call'
railties-7.0.4.3/lib/rails/railtie.rb:226:in `public_send'
railties-7.0.4.3/lib/rails/railtie.rb:226:in `method_missing'
rack-2.2.7/lib/rack/urlmap.rb:74:in `block in call'
rack-2.2.7/lib/rack/urlmap.rb:58:in `each'
rack-2.2.7/lib/rack/urlmap.rb:58:in `call'
unicorn-6.1.0/lib/unicorn/http_server.rb:634:in `process_client'
unicorn-6.1.0/lib/unicorn/http_server.rb:739:in `worker_loop'
unicorn-6.1.0/lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
unicorn-6.1.0/lib/unicorn/http_server.rb:143:in `start'
unicorn-6.1.0/bin/unicorn:128:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/3.2.0/bin/unicorn:25:in `load'
/var/www/discourse/vendor/bundle/ruby/3.2.0/bin/unicorn:25:in `<main>'

hostname	LILEJAP07-app
process_id	658
application_version	1abfe2e61d12b1b559aab0132ec3fb7cc8b87232
HTTP_HOST	federation.cafe
REQUEST_URI	/ap/actor/5ce52c043e670476a1426f9a66472c07
REQUEST_METHOD	GET
HTTP_USER_AGENT	Akkoma 3.8.0-0-gccae7ef; https://bofh.social <admin@bofh.social>
HTTP_ACCEPT	application/activity+json
HTTP_X_FORWARDED_FOR	91.107.215.39, 172.71.250.70
HTTP_X_REAL_IP	172.71.250.70
time	2:16 pm

¿Opiniones?

También estaría interesado en publicaciones completas. En ese caso, se debe usar el tipo “artículo” en lugar de “nota”.

De hecho, los anuncios son mucho menos interesantes para mí que las funciones de foro federado.

¿Hay una hoja de ruta y/o un lugar para enviar donaciones para funciones como esta?

Hola @gme, gracias por probar el plugin

Algunas cosas a tener en cuenta inicialmente aquí

  1. El plugin MVP se prueba contra Mastodon. Veo que estás usando Pleroma allí. Sé que Pleroma cumple con ActivityPub y funciona con Mastodon, sin embargo, aún no hemos analizado de cerca qué ajustes podrían ser necesarios (si los hay) para garantizar la compatibilidad. Pero sigo interesado en ver qué está pasando aquí.

  2. Parece que las solicitudes fallaron debido a un error de autenticación en tu servidor Pleroma (eso es lo que significa un error 403). Como puedo obtener ese endpoint GET usando una solicitud cURL no autenticada, sospecho que podría ser la autenticación HTTP la que está fallando en el extremo de Pleroma.

Para probar lo último (es decir, el punto 2), ¿podrías revisar tus registros de Pleroma (parece que tú también eres el administrador de ese servidor?) si es posible para ver si puedes obtener más detalles al respecto?

Gracias por tus comentarios @bmann. ¿Podrías ampliar el caso de uso que tienes en mente aquí? Con un ejemplo si es posible.

Este tema es el mejor lugar para mantenerse al tanto de los desarrollos. Cuando definamos un plan de fase 2, lo compartiré aquí. Mientras tanto, la mejor manera de ayudar es compartir los casos de uso específicos para los que estás utilizando, o te gustaría utilizar, el plugin.

5 Me gusta

El caso de uso es utilizar Discourse como un nodo AP más completo. Hay muchas maneras más sencillas de publicar contenido en AP (por ejemplo, usar feeds RSS de categorías y Zapier o Buffer), pero desarrollar una capacidad AP más completa solo se puede hacer como un plugin/integración.

Article es el tipo ActivityStream que está destinado a artículos completos. Dependiendo de la interfaz del cliente, mostrará una vista previa y luego un enlace para mostrar el artículo completo en línea (muy parecido a las advertencias de contenido, pero con “leer más”).

Note es el tipo de microblogging.

Al tener publicaciones Article completas, las personas pueden leer / impulsar / responder directamente en sus clientes AP.

Y, por supuesto, sería interesante conocer su hoja de ruta si van a seguir una instancia AP más de microblogging, o ir en una dirección de foro federado como Lemmy o Kbin, especialmente dadas las recientes noticias de Reddit.

1 me gusta

@angus, @pmusaraj ¿han visto la convocatoria de financiación de NGI Sargasso? Es un aviso bastante corto pero podría ser útil para seguir desarrollando este plugin (a menos que ya tengan otros planes).

1 me gusta

Hola a todos, me complace decir que la segunda fase del trabajo en este plugin ha sido aprobada. Esto es en lo que ya hemos comenzado a trabajar, con el objetivo de lanzarlo en aproximadamente 3,5 meses.

Soporte para editar Notas después de su publicación

Soporte para restaurar Notas

Soporte para publicar posts públicamente, así como solo para seguidores

  • Configuración a nivel de categoría
  • Ver más sobre Segmentación de Audiencia y la documentación de Mastodon sobre to/cc
  • Cambiar a posts públicos como predeterminado

Mejorar el análisis del contenido de las Notas

  • Manejar caracteres especiales (quizás usar un analizador diferente). Ver más.

Soporte para usar Artículo en lugar de Nota como Objeto de un post.

  • Configuración a nivel de categoría

Soporte para aceptar Actividades en respuesta a una Nota hecha en remotos y publicar Actividades en respuesta a una Nota hecha en Discourse.

  • Publicar Actividades relativas a respuestas hechas en Discourse
    • Permitir que los usuarios de Discourse sean Actores
    • Crear objetos de Nota para las respuestas de Discourse (posts)
    • Publicar Actividades de Creación/Eliminación/Actualización/Deshacer asociadas para sus acciones equivalentes en Discourse
  • Aceptar Actividades relativas a respuestas hechas en remotos
    • Preparar los Actores de Actividades de servidores remotos como usuarios de Discourse
    • Crear respuestas de Discourse (posts) a partir de objetos de Nota
    • Convertir Actividades de Creación/Eliminación/Actualización/Deshacer asociadas en sus acciones equivalentes en Discourse
  • Añadir una configuración de categoría para alternar entre Solo Primer Post (actual) y “Tema Completo” que soporta Actividades de respuesta.

Soporte para Actividad de Me Gusta

Soporte para que los usuarios de Discourse verifiquen su identidad en Mastodon para que los posts de Discourse creados a partir de sus Toots se asocien con su cuenta de usuario de Discourse.

  • Permitir a un usuario realizar el flujo de Autorización OAuth de Mastodon con el servidor de Mastodon donde está almacenada su cuenta. Esto se inicia desde la configuración de la cuenta del usuario de Discourse.
  • Usando el token de acceso de Mastodon del usuario de Discourse, obtener y almacenar el ID de AP de su cuenta de Mastodon y almacenarlo con su cuenta de Discourse.
  • Asociar todas las actividades de Discourse asociadas con Actividades de AP de un Actor que tenga el ID de AP de un usuario de Discourse con ese usuario de Discourse, ya sea que se hayan realizado antes o después de que el usuario verificara su identidad.
15 Me gusta

Esto es realmente emocionante de ver: un nivel muy alto de federación e interactividad. :tada:

¿Están planeando hacer lanzamientos intermedios o será un gran lanzamiento en ~3.5 meses?

Puede que haya algunas versiones intermedias, pero aún no puedo prometer nada al respecto. Te mantendré informado a medida que avancemos.

2 Me gusta

110% de acuerdo: esto incluye muchos aspectos geniales. :tada:

¿Hay alguna posibilidad de que al menos haya una versión intermedia en este frente?

Para ser honesto, añadir una versión intermedia de “publicaciones públicas como predeterminado” sería bienvenido de inmediato.

2 Me gusta

Tenga en cuenta que la publicación pública dependería de la federación de acciones de edición (la primera viñeta enumerada), creo.

1 me gusta

No puedo hacer promesas en esta etapa, pero es muy probable que haya actualizaciones intermedias tanto para la federación de actualizaciones como para la segmentación de audiencia (publicación pública).

4 Me gusta

:ojos:

1 me gusta

Esa es una limitación conocida. Hasta que se admitan las ediciones federadas, el plugin bloquea las ediciones de contenido federado y no hay ninguna configuración para deshabilitar esto.

2 Me gusta

Para que quede claro, estaba intentando editar una publicación aquí en meta y recibí este error.

3 Me gusta

Oh, lo siento por haber entendido mal. @feature@meta.discourse.org y @announcements@meta.discourse.org al menos se están federando desde aquí, y esta elección es la razón número uno por la que no he habilitado esto para Maker Forums…

2 Me gusta

Sí, este es el primer elemento de la Fase 2 en el que he trabajado. De hecho, ya hay una PR para ello, así que pronto tendrás algo de alivio en ese frente.

2 Me gusta