From 5da4c796e0e9fc3afe0767822e4ed6b78d5feb7c Mon Sep 17 00:00:00 2001 From: Maki Date: Tue, 17 Jan 2023 18:31:54 -0300 Subject: [PATCH 1/3] agrego toggler para distributed press --- app/models/site.rb | 2 +- .../deploys/_deploy_distributed_press.haml | 21 +++++++++++++++++++ config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 app/views/deploys/_deploy_distributed_press.haml diff --git a/app/models/site.rb b/app/models/site.rb index 638b3f47..fc012d7d 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -17,7 +17,7 @@ class Site < ApplicationRecord # TODO: Hacer que los diferentes tipos de deploy se auto registren # @see app/services/site_service.rb - DEPLOYS = %i[local private www zip hidden_service].freeze + DEPLOYS = %i[local private www zip hidden_service distributed_press].freeze validates :name, uniqueness: true, hostname: { allow_root_label: true diff --git a/app/views/deploys/_deploy_distributed_press.haml b/app/views/deploys/_deploy_distributed_press.haml new file mode 100644 index 00000000..d7d54db0 --- /dev/null +++ b/app/views/deploys/_deploy_distributed_press.haml @@ -0,0 +1,21 @@ +-# Publicar a la web distribuida + +.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] + + +%hr/ diff --git a/config/locales/en.yml b/config/locales/en.yml index 530a9381..e7fb4f76 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -248,6 +248,10 @@ en: Only accessible through [Tor Browser](https://www.torproject.org/download/) + deploy_distributed_press: + title: 'Publish on Distributed Press' + help: | + ipfs stats: index: title: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index eaa23137..18cf5326 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -253,6 +253,10 @@ es: Sólo será accesible a través del [Navegador Tor](https://www.torproject.org/es/download/). + deploy_distributed_press: + title: 'Alojar en la web distribuida' + help: | + Es para que esté en la web distribuida stats: index: title: Estadísticas From 67c0b29029d5f8731f0eb82c6b2c8c7d02e333e7 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 20 Jan 2023 18:22:08 -0300 Subject: [PATCH 2/3] feat: almacenar y renovar tokens de distributed press --- Gemfile | 1 + Gemfile.lock | 40 ++++++++++- Procfile | 1 + .../renew_distributed_press_tokens_job.rb | 17 +++++ app/models/distributed_press_publisher.rb | 68 +++++++++++++++++++ ...5420_create_distributed_press_publisher.rb | 14 ++++ lib/tasks/distributed_press.rake | 10 +++ monit.conf | 5 ++ 8 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 app/jobs/renew_distributed_press_tokens_job.rb create mode 100644 app/models/distributed_press_publisher.rb create mode 100644 db/migrate/20230119165420_create_distributed_press_publisher.rb create mode 100644 lib/tasks/distributed_press.rake diff --git a/Gemfile b/Gemfile index 2b304ee0..f317487b 100644 --- a/Gemfile +++ b/Gemfile @@ -38,6 +38,7 @@ gem 'commonmarker' gem 'devise' gem 'devise-i18n' gem 'devise_invitable' +gem 'distributed-press-api-client', '~> 0.2.0' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 8df2d77e..cdfe7183 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -124,6 +124,7 @@ GEM xpath (>= 2.0, < 4.0) chartkick (4.1.2) childprocess (4.1.0) + climate_control (1.2.0) coderay (1.1.3) colorator (1.1.0) commonmarker (0.21.2-x86_64-linux-musl) @@ -162,12 +163,45 @@ GEM devise_invitable (2.0.5) actionmailer (>= 5.0) devise (>= 4.6) + distributed-press-api-client (0.2.0) + addressable (~> 2.3, >= 2.3.0) + climate_control + dry-schema + httparty (~> 0.18) + json (~> 2.1, >= 2.1.0) + jwt (~> 2.6.0) dotenv (2.7.6) dotenv-rails (2.7.6) dotenv (= 2.7.6) railties (>= 3.2) down (5.2.4) addressable (~> 2.8) + dry-configurable (1.0.1) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-core (1.0.0) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-inflector (1.0.0) + dry-initializer (3.1.1) + dry-logic (1.5.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-schema (1.13.0) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.0, < 2) + dry-initializer (~> 3.0) + dry-logic (>= 1.5, < 2) + dry-types (>= 1.7, < 2) + zeitwerk (~> 2.6) + dry-types (1.7.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + dry-inflector (~> 1.0, < 2) + dry-logic (>= 1.4, < 2) + zeitwerk (~> 2.6) ed25519 (1.2.4-x86_64-linux-musl) editorial-autogestiva-jekyll-theme (0.3.4) jekyll (~> 4) @@ -244,8 +278,8 @@ GEM thor hiredis (0.6.3-x86_64-linux-musl) http_parser.rb (0.8.0-x86_64-linux-musl) - httparty (0.18.1) - mime-types (~> 3.0) + httparty (0.21.0) + mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) i18n (1.8.11) concurrent-ruby (~> 1.0) @@ -320,6 +354,7 @@ GEM jekyll-write-and-commit-changes (0.2.1) jekyll (~> 4) rugged (~> 1) + jwt (2.6.0) kaminari (1.2.1) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.1) @@ -669,6 +704,7 @@ DEPENDENCIES devise devise-i18n devise_invitable + distributed-press-api-client (~> 0.2.0) dotenv-rails down ed25519 diff --git a/Procfile b/Procfile index b308ffd5..1a4580d3 100644 --- a/Procfile +++ b/Procfile @@ -5,3 +5,4 @@ blazer_1h: bundle exec rake blazer:run_checks SCHEDULE="1 hour" blazer_1d: bundle exec rake blazer:run_checks SCHEDULE="1 day" blazer: bundle exec rake blazer:send_failing_checks prometheus: bundle exec prometheus_exporter -b 0.0.0.0 --prefix "sutty_" +distributed_press_renew_tokens: bundle exec rake distributed_press:tokens:renew diff --git a/app/jobs/renew_distributed_press_tokens_job.rb b/app/jobs/renew_distributed_press_tokens_job.rb new file mode 100644 index 00000000..5664d9fa --- /dev/null +++ b/app/jobs/renew_distributed_press_tokens_job.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Renueva los tokens de Distributed Press antes que se venzan, +# activando los callbacks que hacen que se refresque el token. +class RenewDistributedPressTokensJob < ApplicationJob + # Renueva todos los tokens a punto de vencer o informa el error sin + # detener la tarea si algo pasa. + def perform + DistributedPressPublisher.with_about_to_expire_tokens.find_each do |publisher| + publisher.touch + rescue DistributedPress::V1::Error => e + data = { instance: publisher.instance, expires_at: publisher.client.token.expires_at } + + ExceptionNotifier.notify_exception(e, data: data) + end + end +end diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb new file mode 100644 index 00000000..c120811e --- /dev/null +++ b/app/models/distributed_press_publisher.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'distributed_press/v1' + +# Almacena el token de autenticación y la URL, por ahora solo vamos +# a tener uno, pero queda abierta la posibilidad de agregar más. +class DistributedPressPublisher < ApplicationRecord + # Cifrar la información del token en la base de datos + has_encrypted :token + + # La instancia es única + validates_uniqueness_of :instance + + # El token es necesario + validates_presence_of :token + + # Mantener la fecha de vencimiento actualizada + before_save :update_expires_at_from_token!, :update_token_from_client! + + # Devuelve todos los tokens que vencen en una hora + scope :with_about_to_expire_tokens, -> do + where('expires_at > ? and expires_at < ?', Time.now, Time.now + 1.hour) + end + + # Al cambiar el token genera un cliente nuevo + # + # @return [String] + def token=(new_token) + @client = nil + super + end + + # Al cambiar la instancia genera un cliente nuevo + # + # @return [String] + def instance=(new_instance) + @client = nil + super + end + + # Instancia un cliente de Distributed Press a partir del token. Al + # cargar un token a punto de vencer se renueva automáticamente. + # + # @return [DistributedPress::V1::Client] + def client + @client ||= DistributedPress::V1::Client.new(url: instance, token: token) + end + + private + + # Actualiza o desactiva la fecha de vencimiento a partir de la + # información del token. + # + # @return [nil] + def update_expires_at_from_token! + self.expires_at = client.token.forever? ? nil : client.token.expires_at + nil + end + + # Actualiza el token a partir del cliente, que ya actualiza el token + # automáticamente. + # + # @return [nil] + def update_token_from_client! + self.token = client.token.to_s + nil + end +end diff --git a/db/migrate/20230119165420_create_distributed_press_publisher.rb b/db/migrate/20230119165420_create_distributed_press_publisher.rb new file mode 100644 index 00000000..8d8de37a --- /dev/null +++ b/db/migrate/20230119165420_create_distributed_press_publisher.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Crea la tabla de publishers de Distributed Press que contiene las +# instancias y tokens +class CreateDistributedPressPublisher < ActiveRecord::Migration[6.1] + def change + create_table :distributed_press_publishers do |t| + t.timestamps + t.string :instance, unique: true + t.text :token_ciphertext, null: false + t.datetime :expires_at, null: true + end + end +end diff --git a/lib/tasks/distributed_press.rake b/lib/tasks/distributed_press.rake new file mode 100644 index 00000000..8ba270ec --- /dev/null +++ b/lib/tasks/distributed_press.rake @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +namespace :distributed_press do + namespace :tokens do + desc 'Renew tokens' + task renew: :environment do + RenewDistributedPressTokensJob.perform_now + end + end +end diff --git a/monit.conf b/monit.conf index 96c08d8a..b785964d 100644 --- a/monit.conf +++ b/monit.conf @@ -25,3 +25,8 @@ check program blazer with path "/usr/local/bin/sutty blazer" every 61 cycles if status != 0 then alert + +check program distributed_press_tokens_renew + with path "/usr/bin/foreman run -f /srv/Procfile -d /srv distributed_press_tokens_renew" as uid "rails" gid "www-data" + every "0 3 * * *" + if status != 0 then alert From cbf7b5892746b544668c6043915da783a13b00d0 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 20 Jan 2023 18:28:29 -0300 Subject: [PATCH 3/3] fixup! feat: almacenar y renovar tokens de distributed press --- app/models/distributed_press_publisher.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index c120811e..610d698d 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -18,9 +18,9 @@ class DistributedPressPublisher < ApplicationRecord before_save :update_expires_at_from_token!, :update_token_from_client! # Devuelve todos los tokens que vencen en una hora - scope :with_about_to_expire_tokens, -> do + scope :with_about_to_expire_tokens, lambda { where('expires_at > ? and expires_at < ?', Time.now, Time.now + 1.hour) - end + } # Al cambiar el token genera un cliente nuevo #