5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-22 16:06:23 +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
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")
rescue Exception => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h })
message =
if activity_pub.public_send(:"may_#{event}?") && activity_pub.public_send(:"#{event}!")
: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!
end
end

View file

@ -17,14 +17,15 @@ class ActorModerationsController < ApplicationController
# 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.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")
rescue Exception => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h })
flash[message] = I18n.t("actor_moderations.#{actor_event}.#{message}")
flash[:error] = I18n.t("actor_moderations.#{actor_event}.error")
ensure
redirect_to_moderation_queue!
end
end

View file

@ -8,14 +8,15 @@ class InstanceModerationsController < ApplicationController
define_method(event) do
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")
rescue Exception => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h })
flash[message] = I18n.t("instance_moderations.#{event}.#{message}")
flash[:error] = I18n.t("instance_moderations.#{event}.error")
ensure
redirect_to_moderation_queue!
end
end

View file

@ -47,14 +47,19 @@ class ActivityPub < ApplicationRecord
# Todavía no hay una decisión sobre el objeto
state :paused, initial: true
# Le usuarie aprobó el objeto
state :approved
state :approved, before_enter: :allow_remotely!
# Le usuarie rechazó el objeto
state :rejected
state :rejected, before_enter: :reject_remotely!
# Le usuarie reportó el objeto
state :reported
# Le actore eliminó el objeto
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
# revisar los cambios.
event :pause do
@ -67,7 +72,7 @@ class ActivityPub < ApplicationRecord
event :remove do
transitions to: :removed
before do
after do
next if object.blank?
object.update(content: {}) unless object.content.empty?
@ -79,26 +84,18 @@ class ActivityPub < ApplicationRecord
# webhook a modo de confirmación.
event :approve do
transitions from: %i[paused], to: :approved
before do
allow_remotely!
end
end
# La actividad fue rechazada
event :reject do
transitions from: %i[paused], to: :rejected
before do
reject_remotely!
end
end
# Solo podemos reportarla luego de rechazarla
event :report do
transitions from: :rejected, to: :reported
before do
after do
ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting?
end
end

View file

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

View file

@ -16,7 +16,7 @@ module AasmEventsConcern
#
# @return [Array<Symbol>]
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
end
end
@ -32,19 +32,15 @@ module AasmEventsConcern
# scope actual.
#
# @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
success = true
successes = []
self.find_each do |object|
object.public_send(:"#{event}!") if object.public_send(:"may_#{event}?")
rescue Exception => e
success = false
notify_exception! e, object
find_each do |object|
successes << (object.public_send(:"may_#{event}?") && object.public_send(:"#{event}!"))
end
success
successes.all?
end
# Ejecuta la transición del evento en la base de datos sin
@ -53,20 +49,13 @@ module AasmEventsConcern
#
# @return [Integer] Registros modificados
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
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
# 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

View file

@ -20,20 +20,15 @@ class FediblockState < ApplicationRecord
# Aunque queramos las listas habilitadas por defecto, tenemos que
# habilitarlas luego de crearlas para poder generar la lista de
# bloqueo en la Social Inbox.
state :disabled, initial: true
state :enabled
state :disabled, initial: true, before_enter: :disable_remotely_and_pause_instances!
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
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
# Al deshabilitar, las listas pasan a modo pausa, a menos que estén
@ -44,22 +39,31 @@ class FediblockState < ApplicationRecord
# de list_names
event :disable do
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
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.
#
# @return [Array<String>]

View file

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