5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-26 07:06:22 +00:00

feat: no permitir entrar al evento si falla la request

This commit is contained in:
f 2024-03-16 15:12:55 -03:00
parent 8f91b748ff
commit 8ff5626e99
No known key found for this signature in database
8 changed files with 88 additions and 110 deletions

View file

@ -9,14 +9,16 @@ class ActivityPubsController < ApplicationController
authorize activity_pub authorize activity_pub
activity_pub.update(remote_flag_params(activity_pub)) if event == :report activity_pub.update(remote_flag_params(activity_pub)) if event == :report
activity_pub.public_send(:"#{event}!") if activity_pub.public_send(:"may_#{event}?")
flash[:success] = I18n.t("activity_pubs.#{event}.success") message =
rescue Exception => e if activity_pub.public_send(:"may_#{event}?") && activity_pub.public_send(:"#{event}!")
ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h }) :success
else
:error
end
flash[message] = I18n.t("activity_pubs.#{event}.#{message}")
flash[:error] = I18n.t("activity_pubs.#{event}.error")
ensure
redirect_to_moderation_queue! redirect_to_moderation_queue!
end end
end end

View file

@ -17,14 +17,15 @@ class ActorModerationsController < ApplicationController
# Crea una RemoteFlag si se envían los parámetros adecuados # Crea una RemoteFlag si se envían los parámetros adecuados
actor_moderation.update(remote_flag_params(actor_moderation)) if actor_event == :report actor_moderation.update(remote_flag_params(actor_moderation)) if actor_event == :report
actor_moderation.public_send(:"#{actor_event}!") if actor_moderation.public_send(:"may_#{actor_event}?") message =
if actor_moderation.public_send(:"may_#{actor_event}?") && actor_moderation.public_send(:"#{actor_event}!")
:success
else
:error
end
flash[:success] = I18n.t("actor_moderations.#{actor_event}.success") flash[message] = I18n.t("actor_moderations.#{actor_event}.#{message}")
rescue Exception => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h })
flash[:error] = I18n.t("actor_moderations.#{actor_event}.error")
ensure
redirect_to_moderation_queue! redirect_to_moderation_queue!
end end
end end

View file

@ -8,14 +8,15 @@ class InstanceModerationsController < ApplicationController
define_method(event) do define_method(event) do
authorize instance_moderation authorize instance_moderation
instance_moderation.public_send(:"#{event}!") if instance_moderation.public_send(:"may_#{event}?") message =
if instance_moderation.public_send(:"may_#{event}?") && instance_moderation.public_send(:"#{event}!")
:success
else
:error
end
flash[:success] = I18n.t("instance_moderations.#{event}.success") flash[message] = I18n.t("instance_moderations.#{event}.#{message}")
rescue Exception => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h })
flash[:error] = I18n.t("instance_moderations.#{event}.error")
ensure
redirect_to_moderation_queue! redirect_to_moderation_queue!
end end
end end

View file

@ -47,14 +47,19 @@ class ActivityPub < ApplicationRecord
# Todavía no hay una decisión sobre el objeto # Todavía no hay una decisión sobre el objeto
state :paused, initial: true state :paused, initial: true
# Le usuarie aprobó el objeto # Le usuarie aprobó el objeto
state :approved state :approved, before_enter: :allow_remotely!
# Le usuarie rechazó el objeto # Le usuarie rechazó el objeto
state :rejected state :rejected, before_enter: :reject_remotely!
# Le usuarie reportó el objeto # Le usuarie reportó el objeto
state :reported state :reported
# Le actore eliminó el objeto # Le actore eliminó el objeto
state :removed state :removed
# Gestionar todos los errores
error_on_all_events do |e|
ExceptionNotifier.notify_exception(e, data: { site: site.name, activity_pub: self.id, activity: activities.first.uri })
end
# Se puede volver a pausa en caso de actualización remota, para # Se puede volver a pausa en caso de actualización remota, para
# revisar los cambios. # revisar los cambios.
event :pause do event :pause do
@ -67,7 +72,7 @@ class ActivityPub < ApplicationRecord
event :remove do event :remove do
transitions to: :removed transitions to: :removed
before do after do
next if object.blank? next if object.blank?
object.update(content: {}) unless object.content.empty? object.update(content: {}) unless object.content.empty?
@ -79,26 +84,18 @@ class ActivityPub < ApplicationRecord
# webhook a modo de confirmación. # webhook a modo de confirmación.
event :approve do event :approve do
transitions from: %i[paused], to: :approved transitions from: %i[paused], to: :approved
before do
allow_remotely!
end
end end
# La actividad fue rechazada # La actividad fue rechazada
event :reject do event :reject do
transitions from: %i[paused], to: :rejected transitions from: %i[paused], to: :rejected
before do
reject_remotely!
end
end end
# Solo podemos reportarla luego de rechazarla # Solo podemos reportarla luego de rechazarla
event :report do event :report do
transitions from: :rejected, to: :reported transitions from: :rejected, to: :reported
before do after do
ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting?
end end
end end

View file

@ -2,8 +2,8 @@
# Mantiene la relación entre Site y Actor # Mantiene la relación entre Site y Actor
class ActorModeration < ApplicationRecord class ActorModeration < ApplicationRecord
IGNORED_EVENTS = %i[remove] IGNORED_EVENTS = %i[remove].freeze
IGNORED_STATES = %i[removed] IGNORED_STATES = %i[removed].freeze
include AASM include AASM
@ -14,38 +14,30 @@ class ActorModeration < ApplicationRecord
accepts_nested_attributes_for :remote_flag accepts_nested_attributes_for :remote_flag
aasm do aasm do
state :paused, initial: true state :paused, initial: true, before_enter: :pause_remotely!
state :allowed state :allowed, before_enter: :allow_remotely!
state :blocked state :blocked, before_enter: :block_remotely!
state :reported state :reported
state :removed state :removed
error_on_all_events do |e|
ExceptionNotifier.notify_exception(e, data: { site: site.name, actor: actor.uri, actor_moderation: id })
end
event :pause do event :pause do
transitions from: %i[allowed blocked reported], to: :paused transitions from: %i[allowed blocked reported], to: :paused
before do
pause_remotely!
end
end end
# Al permitir una cuenta no se permiten todos los comentarios # Al permitir una cuenta no se permiten todos los comentarios
# pendientes de moderación que ya hizo. # pendientes de moderación que ya hizo.
event :allow do event :allow do
transitions from: %i[paused blocked reported], to: :allowed transitions from: %i[paused blocked reported], to: :allowed
before do
allow_remotely!
end
end end
# Al bloquear una cuenta no se bloquean todos los comentarios # Al bloquear una cuenta no se bloquean todos los comentarios
# pendientes de moderación que hizo. # pendientes de moderación que hizo.
event :block do event :block do
transitions from: %i[paused allowed], to: :blocked transitions from: %i[paused allowed], to: :blocked
before do
block_remotely!
end
end end
# Al reportar, necesitamos asociar una RemoteFlag para poder # Al reportar, necesitamos asociar una RemoteFlag para poder
@ -53,7 +45,7 @@ class ActorModeration < ApplicationRecord
event :report do event :report do
transitions from: %i[blocked], to: :reported transitions from: %i[blocked], to: :reported
before do after do
ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting?
end end
end end
@ -63,8 +55,8 @@ class ActorModeration < ApplicationRecord
event :remove do event :remove do
transitions to: :removed transitions to: :removed
before do after do
site.activity_pubs.where(actor_id: self.actor_id).remove_all! site.activity_pubs.where(actor_id: actor_id).remove_all!
end end
end end
end end

View file

@ -16,7 +16,7 @@ module AasmEventsConcern
# #
# @return [Array<Symbol>] # @return [Array<Symbol>]
def self.transitionable_events(current_state) def self.transitionable_events(current_state)
self.events.select do |event| events.select do |event|
aasm.events.find { |x| x.name == event }.transitions_from_state? current_state aasm.events.find { |x| x.name == event }.transitions_from_state? current_state
end end
end end
@ -32,19 +32,15 @@ module AasmEventsConcern
# scope actual. # scope actual.
# #
# @return [Bool] Si hubo al menos un error, devuelve false. # @return [Bool] Si hubo al menos un error, devuelve false.
self.aasm.events.map(&:name).each do |event| aasm.events.map(&:name).each do |event|
define_singleton_method(:"#{event}_all!") do define_singleton_method(:"#{event}_all!") do
success = true successes = []
self.find_each do |object| find_each do |object|
object.public_send(:"#{event}!") if object.public_send(:"may_#{event}?") successes << (object.public_send(:"may_#{event}?") && object.public_send(:"#{event}!"))
rescue Exception => e
success = false
notify_exception! e, object
end end
success successes.all?
end end
# Ejecuta la transición del evento en la base de datos sin # Ejecuta la transición del evento en la base de datos sin
@ -53,20 +49,13 @@ module AasmEventsConcern
# #
# @return [Integer] Registros modificados # @return [Integer] Registros modificados
define_singleton_method(:"#{event}_all_without_callbacks!") do define_singleton_method(:"#{event}_all_without_callbacks!") do
aasm_event = self.aasm.events.find { |e| e.name == event } aasm_event = aasm.events.find { |e| e.name == event }
to_state = aasm_event.transitions.map(&:to).first to_state = aasm_event.transitions.map(&:to).first
from_states = aasm_event.transitions.map(&:from) from_states = aasm_event.transitions.map(&:from)
self.unscope(where: :aasm_state).where(aasm_state: from_states).update_all(aasm_state: to_state, updated_at: Time.now) unscope(where: :aasm_state).where(aasm_state: from_states).update_all(aasm_state: to_state,
updated_at: Time.now)
end end
end end
# Envía notificación de errores
#
# @param exception [Exception]
# @param record [ApplicationRecord]
def self.notify_exception!(exception, record)
ExceptionNotifier.notify_exception(exception, data: { record_type: record.class.name, record_id: record.id })
end
end end
end end

View file

@ -20,20 +20,15 @@ class FediblockState < ApplicationRecord
# Aunque queramos las listas habilitadas por defecto, tenemos que # Aunque queramos las listas habilitadas por defecto, tenemos que
# habilitarlas luego de crearlas para poder generar la lista de # habilitarlas luego de crearlas para poder generar la lista de
# bloqueo en la Social Inbox. # bloqueo en la Social Inbox.
state :disabled, initial: true state :disabled, initial: true, before_enter: :disable_remotely_and_pause_instances!
state :enabled state :enabled, before_enter: :enable_remotely_and_block_instances!
error_on_all_events do |e|
ExceptionNotifier.notify_exception(e, data: { site: site.name, fediblock: id })
end
event :enable do event :enable do
transitions from: :disabled, to: :enabled transitions from: :disabled, to: :enabled
before do
# Bloquear todos las instancias de este Fediblock
enable_remotely! list_names(fediblock.hostnames)
# Luego esta tarea crea las que falten e ignora las que ya se
# bloquearon.
ActivityPub::InstanceModerationJob.perform_now(site: site, hostnames: fediblock.hostnames, perform_remotely: false)
end
end end
# Al deshabilitar, las listas pasan a modo pausa, a menos que estén # Al deshabilitar, las listas pasan a modo pausa, a menos que estén
@ -44,22 +39,31 @@ class FediblockState < ApplicationRecord
# de list_names # de list_names
event :disable do event :disable do
transitions from: :enabled, to: :disabled transitions from: :enabled, to: :disabled
before do
# Deshabilitar todas las instancias que no estén habilitadas por
# otros fediblocks
disable_remotely! list_names(unique_hostnames)
# Pausar todas las moderaciones de las instancias que no estén
# bloqueadas por otros fediblocks.
instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids
site.instance_moderations.where(instance_id: instance_ids).pause_all_without_callbacks!
end
end end
end end
private private
def enable_remotely_and_block_instances!
# Bloquear todos las instancias de este Fediblock
enable_remotely! list_names(fediblock.hostnames)
# Luego esta tarea crea las que falten e ignora las que ya se
# bloquearon.
ActivityPub::InstanceModerationJob.perform_now(site: site, hostnames: fediblock.hostnames, perform_remotely: false)
end
def disable_remotely_and_pause_instances!
# Deshabilitar todas las instancias que no estén habilitadas por
# otros fediblocks
disable_remotely! list_names(unique_hostnames)
# Pausar todas las moderaciones de las instancias que no estén
# bloqueadas por otros fediblocks.
instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids
site.instance_moderations.where(instance_id: instance_ids).pause_all_without_callbacks!
end
# Devuelve los hostnames únicos a esta instancia. # Devuelve los hostnames únicos a esta instancia.
# #
# @return [Array<String>] # @return [Array<String>]

View file

@ -2,8 +2,8 @@
# Mantiene el registro de relaciones entre sitios e instancias # Mantiene el registro de relaciones entre sitios e instancias
class InstanceModeration < ApplicationRecord class InstanceModeration < ApplicationRecord
IGNORED_EVENTS = [] IGNORED_EVENTS = [].freeze
IGNORED_STATES = [] IGNORED_STATES = [].freeze
include AASM include AASM
@ -11,38 +11,30 @@ class InstanceModeration < ApplicationRecord
belongs_to :instance, class_name: 'ActivityPub::Instance' belongs_to :instance, class_name: 'ActivityPub::Instance'
aasm do aasm do
state :paused, initial: true state :paused, initial: true, before_enter: :pause_remotely!
state :allowed state :allowed, before_enter: :allow_remotely!
state :blocked state :blocked, before_enter: :block_remotely!
error_on_all_events do |e|
ExceptionNotifier.notify_exception(e, data: { site: site.name, instance: instance.hostname, instance_moderation: id })
end
# Al volver la instancia a pausa no cambiamos el estado de # Al volver la instancia a pausa no cambiamos el estado de
# moderación de actores pre-existente. # moderación de actores pre-existente.
event :pause do event :pause do
transitions from: %i[allowed blocked], to: :paused transitions from: %i[allowed blocked], to: :paused
before do
pause_remotely!
end
end end
# Al permitir, solo bloqueamos la instancia, sin modificar el estado # Al permitir, solo bloqueamos la instancia, sin modificar el estado
# de les actores y comentarios retroactivamente. # de les actores y comentarios retroactivamente.
event :allow do event :allow do
transitions from: %i[paused blocked], to: :allowed transitions from: %i[paused blocked], to: :allowed
before do
allow_remotely!
end
end end
# Al bloquear, solo bloqueamos la instancia, sin modificar el estado # Al bloquear, solo bloqueamos la instancia, sin modificar el estado
# de les actores y comentarios retroactivamente. # de les actores y comentarios retroactivamente.
event :block do event :block do
transitions from: %i[paused allowed], to: :blocked transitions from: %i[paused allowed], to: :blocked
before do
block_remotely!
end
end end
end end
@ -51,7 +43,7 @@ class InstanceModeration < ApplicationRecord
# @return [Array<String>] # @return [Array<String>]
def actor_ids def actor_ids
ActivityPub::Actor.where(instance_id: self.instance_id).ids ActivityPub::Actor.where(instance_id: instance_id).ids
end end
# Elimina la instancia de todas las listas # Elimina la instancia de todas las listas