encontrar la api independientemente del dominio que la aloje

This commit is contained in:
f 2021-04-15 11:34:42 -03:00
parent 73d1a7dcd8
commit 1d6cf11d52
8 changed files with 84 additions and 28 deletions

View file

@ -0,0 +1,24 @@
# frozen_string_literal: true
module Constraints
# Detecta si el dominio comienzo con api. para servir la API.
#
# Hacemos esto porque Rails históricamente tiene un largo fijo de TLD
# y como alojamos dominios que pueden tener distintas terminaciones,
# no siempre detecta el subdominio como corresponde.
#
# Antes de llegar a este punto tenemos que tener un certificado
# correspondiente en el servidor web, que se expide dentro del
# servidor, por lo que sería la primera línea para detener
# api.cualquiercosa.que.no.existe.org si hiciera falta.
class ApiSubdomain
API_SUBDOMAIN = 'api.'
def initialize; end
# Sólo verificamos que el subdominio empiece con api.
def matches?(request)
request.hostname.start_with? API_SUBDOMAIN
end
end
end

View file

@ -10,7 +10,7 @@ Rails.application.routes.draw do
get 'markdown', to: 'application#markdown' get 'markdown', to: 'application#markdown'
constraints subdomain: 'api' do constraints(Constraints::ApiSubdomain.new) do
scope module: 'api' do scope module: 'api' do
namespace :v1 do namespace :v1 do
resources :csp_reports, only: %i[create] resources :csp_reports, only: %i[create]

View file

@ -13,6 +13,7 @@ module Api
@site.update contact: true, design: Design.find_by_gem('editorial-autogestiva-jekyll-theme') @site.update contact: true, design: Design.find_by_gem('editorial-autogestiva-jekyll-theme')
@site.config.write @site.config.write
@site.reload @site.reload
@host = { host: "api.#{Site.domain}" }
end end
teardown do teardown do
@ -22,11 +23,11 @@ module Api
test 'el sitio tiene que existir' do test 'el sitio tiene que existir' do
@site.destroy @site.destroy
get v1_site_contact_cookie_url(@site.hostname) get v1_site_contact_cookie_url(@site.hostname, **@host)
assert_not cookies[@site.name] assert_not cookies[@site.name]
post v1_site_contact_url(site_id: @site.hostname, form: :contacto), post v1_site_contact_url(site_id: @site.hostname, form: :contacto, **@host),
params: { params: {
name: SecureRandom.hex, name: SecureRandom.hex,
pronouns: SecureRandom.hex, pronouns: SecureRandom.hex,
@ -41,8 +42,8 @@ module Api
end end
test 'hay que enviar desde el sitio principal' do test 'hay que enviar desde el sitio principal' do
get v1_site_contact_cookie_url(@site.hostname) get v1_site_contact_cookie_url(@site.hostname, **@host)
post v1_site_contact_url(site_id: @site.hostname, form: :contacto), post v1_site_contact_url(site_id: @site.hostname, form: :contacto, **@host),
params: { params: {
name: SecureRandom.hex, name: SecureRandom.hex,
pronouns: SecureRandom.hex, pronouns: SecureRandom.hex,
@ -57,8 +58,8 @@ module Api
end end
test 'hay que dar consentimiento' do test 'hay que dar consentimiento' do
get v1_site_contact_cookie_url(@site.hostname) get v1_site_contact_cookie_url(@site.hostname, **@host)
post v1_site_contact_url(site_id: @site.hostname, form: :contacto), post v1_site_contact_url(site_id: @site.hostname, form: :contacto, **@host),
headers: { headers: {
origin: @site.url origin: @site.url
}, },
@ -77,14 +78,14 @@ module Api
test 'enviar un mensaje genera correos' do test 'enviar un mensaje genera correos' do
ActionMailer::Base.deliveries.clear ActionMailer::Base.deliveries.clear
redirect = @site.url + '?thanks' redirect = "#{@site.url}?thanks"
10.times do 10.times do
create :rol, site: @site create :rol, site: @site
end end
get v1_site_contact_cookie_url(@site.hostname) get v1_site_contact_cookie_url(@site.hostname, **@host)
post v1_site_contact_url(site_id: @site.hostname, form: :contacto), post v1_site_contact_url(site_id: @site.hostname, form: :contacto, **@host),
headers: { headers: {
Origin: @site.url Origin: @site.url
}, },
@ -107,14 +108,14 @@ module Api
@site.update name: 'example.org.' @site.update name: 'example.org.'
redirect = @site.url + '?thanks' redirect = "#{@site.url}?thanks"
10.times do 10.times do
create :rol, site: @site create :rol, site: @site
end end
get v1_site_contact_cookie_url(@site.hostname) get v1_site_contact_cookie_url(@site.hostname, **@host)
post v1_site_contact_url(site_id: @site.hostname, form: :contacto), 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,

View file

@ -9,10 +9,11 @@ module Api
skip skip
post v1_csp_reports_url, post v1_csp_reports_url,
host: "api.#{Site.domain}",
params: { params: {
'csp-report': { 'csp-report': {
'document-uri': 'http://example.com/signup.html', 'document-uri': 'http://example.com/signup.html',
'referrer': '', referrer: '',
'blocked-uri': 'http://example.com/css/style.css', 'blocked-uri': 'http://example.com/css/style.css',
'violated-directive': 'style-src cdn.example.com', 'violated-directive': 'style-src cdn.example.com',
'original-policy': "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports" 'original-policy': "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports"

View file

@ -11,6 +11,7 @@ module Api
@usuarie = @rol.usuarie @usuarie = @rol.usuarie
@site.update_attribute :colaboracion_anonima, true @site.update_attribute :colaboracion_anonima, true
@host = { host: "api.#{Site.domain}" }
end end
teardown do teardown do
@ -18,7 +19,7 @@ module Api
end end
test 'primero hay que pedir una cookie' do test 'primero hay que pedir una cookie' do
get v1_site_invitades_cookie_url(@site.hostname) get v1_site_invitades_cookie_url(@site.hostname, **@host)
assert cookies[@site.name] assert cookies[@site.name]
assert cookies['_sutty_session'] assert cookies['_sutty_session']
@ -27,7 +28,7 @@ module Api
test 'solo si el sitio existe' do test 'solo si el sitio existe' do
site = SecureRandom.hex site = SecureRandom.hex
get v1_site_invitades_cookie_url(site_id: site) get v1_site_invitades_cookie_url(site_id: site, **@host)
assert_not cookies[site] assert_not cookies[site]
assert_not cookies['_sutty_session'] assert_not cookies['_sutty_session']
@ -36,7 +37,7 @@ module Api
test 'solo si el sitio tiene colaboracion anonima' do test 'solo si el sitio tiene colaboracion anonima' do
@site.update_attribute :colaboracion_anonima, false @site.update_attribute :colaboracion_anonima, false
get v1_site_invitades_cookie_url(@site.hostname) get v1_site_invitades_cookie_url(@site.hostname, **@host)
assert_not cookies[@site.name] assert_not cookies[@site.name]
assert_not cookies['_sutty_session'] assert_not cookies['_sutty_session']

View file

@ -18,7 +18,7 @@ module Api
end end
test 'no se pueden enviar sin cookie' do test 'no se pueden enviar sin cookie' do
post v1_site_posts_url(@site.hostname, layout: :post), params: { post v1_site_posts_url(@site.hostname, layout: :post, **@host), params: {
post: { post: {
title: SecureRandom.hex, title: SecureRandom.hex,
description: SecureRandom.hex description: SecureRandom.hex
@ -36,15 +36,15 @@ module Api
test 'no se pueden enviar a sitios que no existen' do test 'no se pueden enviar a sitios que no existen' do
site = SecureRandom.hex site = SecureRandom.hex
get v1_site_invitades_cookie_url(site_id: site) get v1_site_invitades_cookie_url(site_id: site, **@host)
assert_not cookies[site] assert_not cookies[site]
get v1_site_invitades_cookie_url(@site.hostname) get v1_site_invitades_cookie_url(@site.hostname, **@host)
assert cookies[@site.name] assert cookies[@site.name]
post v1_site_posts_url(site_id: site, layout: :post), post v1_site_posts_url(site_id: site, layout: :post, **@host),
headers: { cookies: cookies }, headers: { cookies: cookies },
params: { params: {
consent: true, consent: true,
@ -61,9 +61,9 @@ module Api
test 'antes hay que pedir una cookie' do test 'antes hay que pedir una cookie' do
assert_equal 2, @site.posts.size assert_equal 2, @site.posts.size
get v1_site_invitades_cookie_url(@site.hostname) get v1_site_invitades_cookie_url(@site.hostname, **@host)
post v1_site_posts_url(@site.hostname, layout: :post), post v1_site_posts_url(@site.hostname, layout: :post, **@host),
headers: { headers: {
cookies: cookies, cookies: cookies,
origin: @site.url origin: @site.url
@ -88,9 +88,9 @@ module Api
title = SecureRandom.hex title = SecureRandom.hex
order = (rand * 100).to_i order = (rand * 100).to_i
get v1_site_invitades_cookie_url(@site.hostname) get v1_site_invitades_cookie_url(@site.hostname, **@host)
post v1_site_posts_url(@site.hostname, layout: :post), post v1_site_posts_url(@site.hostname, layout: :post, **@host),
headers: { headers: {
cookies: cookies, cookies: cookies,
origin: @site.url origin: @site.url
@ -119,12 +119,12 @@ module Api
test 'las cookies tienen un vencimiento interno' do test 'las cookies tienen un vencimiento interno' do
assert_equal 2, @site.posts.size assert_equal 2, @site.posts.size
get v1_site_invitades_cookie_url(@site.hostname) get v1_site_invitades_cookie_url(@site.hostname, **@host)
expired = (ENV.fetch('COOKIE_DURATION', '30').to_i + 1).minutes expired = (ENV.fetch('COOKIE_DURATION', '30').to_i + 1).minutes
Timecop.freeze(Time.now + expired) do Timecop.freeze(Time.now + expired) do
post v1_site_posts_url(@site.hostname, layout: :post), post v1_site_posts_url(@site.hostname, layout: :post, **@host),
headers: { headers: {
cookies: cookies, cookies: cookies,
origin: @site.url origin: @site.url

View file

@ -22,7 +22,7 @@ module Api
end end
test 'se puede obtener un listado de todos' do test 'se puede obtener un listado de todos' do
get v1_sites_url, headers: @authorization, as: :json get v1_sites_url(host: "api.#{Site.domain}"), headers: @authorization, as: :json
assert_equal Site.all.pluck(:name), JSON.parse(response.body) assert_equal Site.all.pluck(:name), JSON.parse(response.body)
end end
end end

View file

@ -0,0 +1,29 @@
# frozen_string_literal: true
class ConstraintsApiSubdomainTest < ActiveSupport::TestCase
setup do
@constraint = Constraints::ApiSubdomain.new
MockRequest = Struct.new(:hostname, keyword_init: true) unless defined? MockRequest
end
test 'cualquier subdominio que empiece con api. matchea' do
request = MockRequest.new hostname: 'api.'
(rand * 10).to_i.times do
request.hostname += "#{SecureRandom.hex}."
assert @constraint.matches?(request)
end
end
test 'cualquier subdominio que no empiece con api. matchea' do
request = MockRequest.new hostname: 'panel.'
(rand * 10).to_i.times do
request.hostname += "#{SecureRandom.hex}."
assert_not @constraint.matches?(request)
end
end
end