5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-07-04 00:35:46 +00:00
panel/app/controllers/api/v1/posts_controller.rb

109 lines
3.5 KiB
Ruby
Raw Normal View History

2020-02-11 15:06:36 +00:00
# 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?
2020-02-18 16:45:08 +00:00
usuarie = Site::Author.new name: 'Anon', email: "anon@#{site.hostname}"
service = PostService.new(params: params,
site: site,
usuarie: usuarie)
service.create_anonymous
2020-02-11 15:06:36 +00:00
# Redirigir a la URL de agradecimiento
2020-02-18 16:45:08 +00:00
redirect_to params[:redirect_to] || site.url
2020-02-11 15:06:36 +00:00
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
2020-02-18 16:45:08 +00:00
render html: 'cookie_invalid', status: :no_content
2020-02-11 15:06:36 +00:00
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?
2020-02-18 16:45:08 +00:00
if valid_authenticity_token? session, cookies.encrypted[site_id]['csrf']
return
2020-02-11 15:06:36 +00:00
end
2020-02-18 16:45:08 +00:00
render html: 'token_invalid', status: :no_content
2020-02-11 15:06:36 +00:00
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
2020-02-18 16:45:08 +00:00
render html: 'site_not_anon', status: :no_content unless anon
2020-02-11 15:06:36 +00:00
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
2020-02-18 16:45:08 +00:00
return if request.headers['Origin'] == "https://#{site}"
render html: 'site_not_origin', status: :no_content
2020-02-11 15:06:36 +00:00
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