5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2025-03-14 20:08:19 +00:00

Merge branch 'issue-17722' into 'rails'

Draft: feat: prueba de antispam

See merge request sutty/sutty!286
This commit is contained in:
fauno 2025-01-24 23:36:23 +00:00
commit 686c6d6b9b
4 changed files with 100 additions and 1 deletions

View file

@ -0,0 +1,77 @@
# frozen_string_literal: true
# Modificaciones locales al registro de usuaries
#
# @see {https://github.com/heartcombo/devise/wiki/How-To:-Use-Recaptcha-with-Devise}
class RegistrationsController < Devise::RegistrationsController
class SpambotError < StandardError; end
PRIVATE_HEADERS = /(cookie|secret|token)/i
prepend_before_action :anti_spambot_traps, only: %i[create]
prepend_after_action :lock_spambots, only: %i[create]
private
# Condiciones bajo las que consideramos que un registro viene de unx
# spambot
#
# @return [Bool]
def spambot?
@spambot ||= params.dig(:usuarie, :name).present?
end
# Bloquea las cuentas de spam dentro de un minuto, para hacerles creer
# que la cuenta se creó correctamente.
def lock_spambots
return unless spambot?
return unless current_usuarie
LockUsuarieJob.set(wait: 1.minute).perform_later(usuarie: current_usuarie)
end
# Detecta e informa spambots muy simples
#
# @return [nil]
def anti_spambot_traps
raise SpambotError if spambot?
rescue SpambotError => e
ExceptionNotifier.notify_exception(e, data: { params: anonymized_params, headers: anonymized_headers })
nil
end
# Devuelve parámetros anonimizados para prevenir filtrar la contraseña
# de falsos positivos.
#
# @return [Hash]
def anonymized_params
params.except(:authenticity_token).permit!.to_h.tap do |p|
p['usuarie'].delete 'password'
p['usuarie'].delete 'password_confirmation'
end
end
# Devuelve los encabezados de la petición sin información sensible de
# Rails
#
# @return [Hash]
def anonymized_headers
request.headers.to_h.select do |_, v|
v.is_a? String
end.reject do |k, _|
k =~ PRIVATE_HEADERS
end
end
# Si le usuarie es considerade spambot, no enviamos el correo de
# confirmación al crear la cuenta.
def sign_up_params
if spambot?
params[:usuarie][:confirmed_at] = Time.now.utc
devise_parameter_sanitizer.permit(:sign_up, keys: %i[confirmed_at])
end
super
end
end

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
# Bloquea el acceso a une usuarie
class LockUsuarieJob < ApplicationJob
# Cambiamos la contraseña, aplicamos un bloqueo y cerramos la sesión
# para que no pueda volver a entrar hasta que siga las instrucciones
# de desbloqueo.
#
# @param :usuarie [Usuarie]
# @return [nil]
def perform(usuarie:)
password = SecureRandom.base36
usuarie.skip_password_change_notification!
usuarie.update(password: password, password_confirmation: password, remember_created_at: nil, locked_at: Time.now.utc)
nil
end
end

View file

@ -12,6 +12,9 @@
as: resource_name, as: resource_name,
url: registration_path(resource_name, params: { locale: params[:locale] })) do |f| url: registration_path(resource_name, params: { locale: params[:locale] })) do |f|
.d-none
= f.text_field :name, autocomplete: 'off'
.form-group .form-group
= f.label :email, class: 'sr-only' = f.label :email, class: 'sr-only'
= f.email_field :email, autofocus: true, autocomplete: 'email', = f.email_field :email, autofocus: true, autocomplete: 'email',

View file

@ -6,7 +6,7 @@
SITE_ID_RE = %r{[^/]+}.freeze SITE_ID_RE = %r{[^/]+}.freeze
Rails.application.routes.draw do Rails.application.routes.draw do
devise_for :usuaries devise_for :usuaries, controllers: { registrations: 'registrations' }
get '/.well-known/change-password', to: redirect('/usuaries/edit') get '/.well-known/change-password', to: redirect('/usuaries/edit')
require 'que/web' require 'que/web'