Acomodar la API de formularios de contacto a los deploys nuevos.

La API no cambia por retrocompatibilidad pero ameritaría una v2 sabiendo
más cosas sobre CORS.
This commit is contained in:
f 2021-08-08 21:18:13 -03:00
parent 61b3b97313
commit 22a7a811b4
5 changed files with 56 additions and 14 deletions

View file

@ -21,7 +21,22 @@ module Api
# TODO: Generar API v2 que use solo el hostname y no haya que # TODO: Generar API v2 que use solo el hostname y no haya que
# pasar site_id como parámetro redundante. # pasar site_id como parámetro redundante.
def site_id def site_id
@site_id ||= Deploy.where(hostname: params[:site_id]).pluck(:site_id).first @site_id ||= Deploy.site_name_from_hostname(params[:site_id])
end
# @return [Site]
def site
@site ||= Site.find_by_name(site_id)
end
# Obtiene el hostname desde el Origin, con el hostname local como
# fallback.
#
# @return [String]
def origin_hostname
URI.parse(origin || origin_from_referer).host
rescue StandardError
"#{site_id}.#{Site.domain}"
end end
# Referer # Referer

View file

@ -44,15 +44,10 @@ module Api
# Genera el Origin correcto a partir de la URL del sitio. # Genera el Origin correcto a partir de la URL del sitio.
# #
# En desarrollo devuelve el Origin enviado.
#
# XXX: Si el sitio tiene varias URLs, hay que devolver la más
# similar al Origin o vamos a estar generando errores de CORS.
#
# @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin} # @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin}
# @return [String] # @return [String]
def return_origin def return_origin
Rails.env.production? ? Site.find_by(name: site_id).url : origin site&.deploys&.find_by_hostname(origin_hostname)&.url
end end
# La cookie no es accesible a través de JS y todo su contenido # La cookie no es accesible a través de JS y todo su contenido
@ -63,6 +58,8 @@ module Api
# TODO: Volver configurable por sitio # TODO: Volver configurable por sitio
expires = ENV.fetch('COOKIE_DURATION', '30').to_i.minutes expires = ENV.fetch('COOKIE_DURATION', '30').to_i.minutes
# TODO: ¿Son necesarios estos headers en la descarga de una
# imagen? ¿No será mejor moverlos al envío de datos?
headers['Access-Control-Allow-Origin'] = return_origin headers['Access-Control-Allow-Origin'] = return_origin
headers['Access-Control-Allow-Credentials'] = true headers['Access-Control-Allow-Credentials'] = true
headers['Vary'] = 'Origin' headers['Vary'] = 'Origin'

View file

@ -118,11 +118,6 @@ module Api
raise NotImplementedError raise NotImplementedError
end end
# Encuentra el sitio o devuelve nulo
def site
@site ||= Site.find_by(name: site_id)
end
# Genera un registro con información básica para debug, quizás no # Genera un registro con información básica para debug, quizás no
# quede asociado a ningún sitio. # quede asociado a ningún sitio.
# #

View file

@ -27,6 +27,13 @@ class Deploy < ApplicationRecord
# Cada deploy puede implementar su propia validación # Cada deploy puede implementar su propia validación
validates :hostname, hostname: true, unless: :implements_hostname_validation? validates :hostname, hostname: true, unless: :implements_hostname_validation?
# Retrocompatibilidad: Encuentra el site_name a partir del hostname.
#
# @return [String,Nil]
def self.site_name_from_hostname(hostname)
where(hostname: hostname).includes(:site).pluck(:name).first
end
# Genera el hostname # Genera el hostname
# #
# @return [String] # @return [String]

View file

@ -114,8 +114,8 @@ module Api
create :rol, site: @site create :rol, site: @site
end end
get v1_site_contact_cookie_url(@site.name, **@host) get v1_site_contact_cookie_url(@site.hostname, **@host)
post v1_site_contact_url(site_id: @site.name, form: :contacto, **@host), post v1_site_contact_url(site_id: @site.hostname, form: :contacto, **@host),
headers: { origin: @site.url }, headers: { origin: @site.url },
params: { params: {
name: SecureRandom.hex, name: SecureRandom.hex,
@ -130,6 +130,34 @@ module Api
assert_equal redirect, response.headers['Location'] assert_equal redirect, response.headers['Location']
assert_equal 2, ActionMailer::Base.deliveries.size assert_equal 2, ActionMailer::Base.deliveries.size
end end
test 'algunos navegadores no soportan Origin' do
ActionMailer::Base.deliveries.clear
@site.update name: 'example'
redirect = "#{@site.url}?thanks"
10.times do
create :rol, site: @site
end
get v1_site_contact_cookie_url(@site.hostname, **@host)
post v1_site_contact_url(site_id: @site.hostname, form: :contacto, **@host),
headers: { referer: @site.url },
params: {
name: SecureRandom.hex,
pronouns: SecureRandom.hex,
contact: SecureRandom.hex,
from: "#{SecureRandom.hex}@sutty.nl",
body: SecureRandom.hex,
consent: true,
redirect: redirect
}
assert_equal redirect, response.headers['Location']
assert_equal 2, ActionMailer::Base.deliveries.size
end
end end
end end
end end