diff --git a/app/controllers/api/v1/sites_controller.rb b/app/controllers/api/v1/sites_controller.rb index 1a79cc2c..6abff704 100644 --- a/app/controllers/api/v1/sites_controller.rb +++ b/app/controllers/api/v1/sites_controller.rb @@ -12,6 +12,31 @@ module Api render json: sites_names + alternative_names + api_names end + # Sitios con hidden service de Tor + # + # @return [Array] lista de nombres de sitios sin onion aun + def hidden_services + render json: DeployHiddenService.where(values: nil).includes(:site).pluck(:name) + end + + # Tor va a enviar el onion junto con el nombre del sitio y tenemos + # que guardarlo en su deploy_hidden_service. + # + # @params [String] name + # @params [String] onion + def add_onion + site = Site.find_by(name: params[:name]) + + if site + usuarie = GitAuthor.new email: 'tor@' + Site.domain, name: 'Tor' + service = SiteService.new site: site, usuarie: usuarie, + params: params + service.add_onion + end + + head :ok + end + private # Nombres de los sitios diff --git a/app/models/deploy_hidden_service.rb b/app/models/deploy_hidden_service.rb new file mode 100644 index 00000000..d4d2b822 --- /dev/null +++ b/app/models/deploy_hidden_service.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Genera una versión onion +class DeployHiddenService < DeployWww + def deploy + return true if fqdn.blank? + + super + end + + def fqdn + values[:onion] + end + + def url + 'http://' + fqdn + end +end diff --git a/app/models/site.rb b/app/models/site.rb index ceeea4f3..771dceb6 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -9,7 +9,7 @@ class Site < ApplicationRecord # TODO: Hacer que los diferentes tipos de deploy se auto registren # @see app/services/site_service.rb - DEPLOYS = %i[local www zip].freeze + DEPLOYS = %i[local www zip hidden_service].freeze validates :name, uniqueness: true, hostname: { allow_root_label: true diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 7d647228..54ac113a 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -36,7 +36,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do end def build_deploys - Site::DEPLOYS.map { |deploy| "Deploy#{deploy.capitalize}" } + Site::DEPLOYS.map { |deploy| "Deploy#{deploy.to_s.camelcase}" } .each do |deploy| next if site.deploys.find_by type: deploy @@ -44,6 +44,23 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do end end + # Agregar una dirección oculta de Tor al DeployHiddenService y a la + # configuración del Site. + def add_onion + onion = params[:onion].strip + deploy = DeployHiddenService.find_by(site: site) + + return false unless !onion.blank? && deploy + + deploy.values[:onion] = onion + deploy.save + + site.config['onion-location'] = onion + site.config.write + + commit_config(action: :tor) + end + private # Guarda los cambios de la configuración en el repositorio git diff --git a/app/views/deploy_mailer/deployed.text.haml b/app/views/deploy_mailer/deployed.text.haml index af39ebe0..53a9b008 100644 --- a/app/views/deploy_mailer/deployed.text.haml +++ b/app/views/deploy_mailer/deployed.text.haml @@ -1,4 +1,4 @@ -= "# #{t('.hi')}" += '# ' + t('.hi') \ = t('.explanation', fqdn: @deploy_local.site.hostname) \ diff --git a/app/views/deploys/_deploy_hidden_service.haml b/app/views/deploys/_deploy_hidden_service.haml new file mode 100644 index 00000000..d6388123 --- /dev/null +++ b/app/views/deploys/_deploy_hidden_service.haml @@ -0,0 +1,23 @@ +-# Generar un hidden service + +.row + .col + = deploy.hidden_field :id + = deploy.hidden_field :type + .custom-control.custom-switch + -# + El checkbox invierte la lógica de destrucción porque queremos + crear el deploy si está activado y destruirlo si está + desactivado. + = deploy.check_box :_destroy, + { checked: deploy.object.persisted?, class: 'custom-control-input' }, + '0', '1' + = deploy.label :_destroy, class: 'custom-control-label' do + %h3= t('.title') + = sanitize_markdown t('.help', public_url: deploy.object.site.url), + tags: %w[p strong em a] + + - if deploy.object.fqdn + = sanitize_markdown t('.help_2', url: deploy.object.url), + tags: %w[p strong em a] +%hr/ diff --git a/app/views/deploys/_deploy_www.haml b/app/views/deploys/_deploy_www.haml index bbeebf91..9cf186a6 100644 --- a/app/views/deploys/_deploy_www.haml +++ b/app/views/deploys/_deploy_www.haml @@ -4,15 +4,17 @@ .col = deploy.hidden_field :id = deploy.hidden_field :type - %h3 + + .custom-control.custom-switch -# El checkbox invierte la lógica de destrucción porque queremos crear el deploy si está activado y destruirlo si está desactivado. = deploy.check_box :_destroy, - { checked: deploy.object.persisted? }, + { checked: deploy.object.persisted?, class: 'custom-control-input' }, '0', '1' - = deploy.label :_destroy, t('.title') + = deploy.label :_destroy, class: 'custom-control-label' do + %h3= t('.title') = sanitize_markdown t('.help', fqdn: deploy.object.fqdn), tags: %w[p strong em a] %hr/ diff --git a/app/views/deploys/_deploy_zip.haml b/app/views/deploys/_deploy_zip.haml index 16215d5d..c1588929 100644 --- a/app/views/deploys/_deploy_zip.haml +++ b/app/views/deploys/_deploy_zip.haml @@ -4,15 +4,17 @@ .col = deploy.hidden_field :id = deploy.hidden_field :type - %h3 + + .custom-control.custom-switch -# El checkbox invierte la lógica de destrucción porque queremos crear el deploy si está activado y destruirlo si está desactivado. = deploy.check_box :_destroy, - { checked: deploy.object.persisted? }, + { checked: deploy.object.persisted?, class: 'custom-control-input' }, '0', '1' - = deploy.label :_destroy, t('.title') + = deploy.label :_destroy, class: 'custom-control-label' do + %h3= t('.title') -# TODO: secar la generación de URLs - name = site.name || t('.ejemplo') = sanitize_markdown t('.help', diff --git a/config/locales/en.yml b/config/locales/en.yml index 48b7465c..ea4b5c10 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -25,6 +25,7 @@ en: site_service: create: 'Created %{name}' update: 'Updated %{name}' + tor: 'Added hidden service location' post_service: created: 'Created "%{title}"' updated: 'Updated "%{title}"' @@ -74,6 +75,10 @@ en: title: Build ZIP file success: Available for download error: Error + deploy_hidden_service: + title: Host as Tor Hidden Service + success: Success! + error: Error help: You can contact us by replying this e-mail maintenance_mailer: notice: @@ -265,8 +270,25 @@ en: shares a copy of your site. It also helps with site archival for historical purposes :) - ejemplo: 'example' + deploy_hidden_service: + title: 'Host as Tor Hidden Service' + help: | + A Hidden Service makes your site available anonymously on the + Tor network. + + **Important:** This doesn't mean your site is **entirely + anonymous**. Visitors can still access your site publicly at + <%{public_url}>. + + [Know more](https://sutty.nl/en/hidden-sites-with-tor/) + help_2: | + The hidden address for your site is: + + <%{url}> + + Only accessible through [Tor + Browser](https://www.torproject.org/download/) stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index 58fb3fa8..4e910f4a 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -25,6 +25,7 @@ es: site_service: create: 'Creado %{name}' update: 'Actualizado %{name}' + tor: 'Agregada ubicación del servicio oculto' post_service: created: 'Creado "%{title}"' updated: 'Modificado "%{title}"' @@ -74,6 +75,10 @@ es: title: Generar archivo ZIP success: Disponible para descargar error: Hubo un error + deploy_hidden_service: + title: Alojar como servicio oculto de Tor + success: ¡Éxito! + error: Hubo un error help: Por cualquier duda, responde este correo para contactarte con nosotres. maintenance_mailer: notice: @@ -270,6 +275,24 @@ es: También sirve para archivo histórico :) ejemplo: 'ejemplo' + deploy_hidden_service: + title: 'Alojar como servicio oculto en Tor' + help: | + Un servicio oculto (_hidden service_) aloja una copia anónima de + tu sitio dentro de la red Tor. + + **Atención:** Esto no hace a tu sitio **totalmente anónimo**. + Les visitantes todavía podrán acceder a la versión pública de tu + sitio a través de <%{public_url}>. + + [Saber más](https://sutty.nl/sitios-ocultos-con-tor/) + help_2: | + La dirección de tu sitio es esta: + + <%{url}> + + Sólo será accesible a través del [Navegador + Tor](https://www.torproject.org/es/download/). stats: index: title: Estadísticas diff --git a/config/routes.rb b/config/routes.rb index 4bea1498..0d7e0005 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,6 +16,9 @@ Rails.application.routes.draw do scope module: 'api' do namespace :v1 do resources :csp_reports, only: %i[create] + + get :'sites/hidden_services', to: 'sites#hidden_services' + post :'sites/add_onion', to: 'sites#add_onion' resources :sites, only: %i[index], constraints: { site_id: /[a-z0-9\-\.]+/, id: /[a-z0-9\-\.]+/ } do get :'invitades/cookie', to: 'invitades#cookie' post :'posts/:layout', to: 'posts#create'