5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-22 22:46:22 +00:00
panel/app/controllers/api/v1/posts_controller.rb
2020-02-18 13:45:08 -03:00

108 lines
3.5 KiB
Ruby

# frozen_string_literal: true
module Api
module V1
class PostsController < BaseController
# Ver doc/anonymous.md
skip_forgery_protection
# Protecciones antes de procesar los datos
before_action :cookie_is_valid?, unless: :performed?
before_action :valid_authenticity_token_in_cookie?, unless: :performed?
before_action :site_exists_and_is_anonymous?, unless: :performed?
before_action :site_is_origin?, unless: :performed?
# Crea un artículo solo si el sitio es invitado, pero antes
# tenemos que averiguar varias cosas:
#
# * la cookie sea válida
# * el token anti CSRF es válido
# * el sitio existe
# * el sitio admite invitades
# * el origen de la petición no es el sitio
#
# TODO: Definir cuáles van a ser las respuestas para cada error
# o si simplemente vamos a aceptarlas sin dar feedback.
def create
# No procesar nada más si ya se aplicaron todos los filtros
return if performed?
usuarie = Site::Author.new name: 'Anon', email: "anon@#{site.hostname}"
service = PostService.new(params: params,
site: site,
usuarie: usuarie)
service.create_anonymous
# Redirigir a la URL de agradecimiento
redirect_to params[:redirect_to] || site.url
end
private
# Comprueba que no se haya reutilizado una cookie vencida
#
# XXX: Si el navegador envió una cookie vencida es porque la está
# reutilizando, probablemente de forma maliciosa?
def cookie_is_valid?
unless cookies.encrypted[site_id] &&
cookies.encrypted[site_id]['expires'] > Time.now.to_i
render html: 'cookie_invalid', status: :no_content
end
end
# Queremos comprobar que la cookie corresponda con la sesión. La
# cookie puede haber vencido, así que es uno de los chequeos más
# simples que hacemos.
#
# TODO: Pensar una forma de redirigir al origen sin vaciar el
# formulario para que le usuarie recargue la cookie.
def valid_authenticity_token_in_cookie?
if valid_authenticity_token? session, cookies.encrypted[site_id]['csrf']
return
end
render html: 'token_invalid', status: :no_content
end
# El sitio existe y soporta colaboracion anónima
#
# Pedimos el sitio aunque no lo necesitemos para que la consulta
# entre en la caché
def site_exists_and_is_anonymous?
_, anon = site_anon_pair
render html: 'site_not_anon', status: :no_content unless anon
end
# El navegador envía la URL del sitio en el encabezado Origin,
# queremos comprobar que los datos son enviados desde ahí.
def site_is_origin?
site, = site_anon_pair
return if request.headers['Origin'] == "https://#{site}"
render html: 'site_not_origin', status: :no_content
end
# Solo soy un atajo
def site_id
@site_id ||= params[:site_id]
end
# La consulta más barata que podemos hacer y la reutilizamos para
# que esté en la caché
def site_anon_pair
Site.where(name: site_id, colaboracion_anonima: true)
.pluck(:name, :colaboracion_anonima)
.first
end
# Instancia el sitio completo
#
# XXX: Solo usar después de comprobar que el sitio existe!
def site
@site ||= Site.find_by(name: site_id)
end
end
end
end