mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-15 07:41:41 +00:00
cifrar campos para protegerlos en el repositorio
This commit is contained in:
parent
9a2f242e0d
commit
c0d0e52df5
11 changed files with 92 additions and 3 deletions
1
Gemfile
1
Gemfile
|
@ -56,6 +56,7 @@ gem 'inline_svg'
|
||||||
gem 'jekyll'
|
gem 'jekyll'
|
||||||
gem 'jekyll-data', require: 'jekyll-data',
|
gem 'jekyll-data', require: 'jekyll-data',
|
||||||
git: 'https://0xacab.org/sutty/jekyll/jekyll-data.git'
|
git: 'https://0xacab.org/sutty/jekyll/jekyll-data.git'
|
||||||
|
gem 'lockbox'
|
||||||
gem 'mini_magick'
|
gem 'mini_magick'
|
||||||
gem 'mobility'
|
gem 'mobility'
|
||||||
gem 'pg'
|
gem 'pg'
|
||||||
|
|
|
@ -262,6 +262,7 @@ GEM
|
||||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||||
rb-inotify (~> 0.9, >= 0.9.7)
|
rb-inotify (~> 0.9, >= 0.9.7)
|
||||||
ruby_dep (~> 1.2)
|
ruby_dep (~> 1.2)
|
||||||
|
lockbox (0.4.6)
|
||||||
lograge (0.11.2)
|
lograge (0.11.2)
|
||||||
actionpack (>= 4)
|
actionpack (>= 4)
|
||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
|
@ -540,6 +541,7 @@ DEPENDENCIES
|
||||||
jekyll-data!
|
jekyll-data!
|
||||||
letter_opener
|
letter_opener
|
||||||
listen (>= 3.0.5, < 3.2)
|
listen (>= 3.0.5, < 3.2)
|
||||||
|
lockbox
|
||||||
lograge
|
lograge
|
||||||
memory_profiler
|
memory_profiler
|
||||||
mini_magick
|
mini_magick
|
||||||
|
|
34
app/models/metadata_encrypted_text.rb
Normal file
34
app/models/metadata_encrypted_text.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Íbamos a usar OpenSSL pero esto es más simple de implementar y no
|
||||||
|
# tenemos que usar cifrado compatible con JavaScript.
|
||||||
|
class MetadataEncryptedText < MetadataText
|
||||||
|
# Decifra el valor si está guardado en el sitio
|
||||||
|
def value
|
||||||
|
self[:value] ||= if (v = document.data.dig(name.to_s))
|
||||||
|
box.decrypt_str v
|
||||||
|
else
|
||||||
|
default_value
|
||||||
|
end
|
||||||
|
rescue Lockbox::DecryptionError => e
|
||||||
|
ExceptionNotifier.notify_exception(e)
|
||||||
|
|
||||||
|
self[:value] ||= I18n.t('lockbox.help.decryption_error')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Cifra el valor antes de guardarlo
|
||||||
|
def save
|
||||||
|
self[:value] = box.encrypt sanitize(value)
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Genera una lockbox a partir de la llave privada del sitio
|
||||||
|
#
|
||||||
|
# @return [Lockbox]
|
||||||
|
def box
|
||||||
|
@box ||= Lockbox.new key: site.private_key, padding: true, encode: true
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,6 +7,12 @@ class Site < ApplicationRecord
|
||||||
include Site::Forms
|
include Site::Forms
|
||||||
include Site::FindAndReplace
|
include Site::FindAndReplace
|
||||||
|
|
||||||
|
# Cifrar la llave privada que cifra y decifra campos ocultos. Sutty
|
||||||
|
# tiene acceso pero los datos se guardan cifrados en el sitio. Esto
|
||||||
|
# protege información privada en repositorios públicos, pero no la
|
||||||
|
# protege de acceso al panel de Sutty!
|
||||||
|
encrypts :private_key
|
||||||
|
|
||||||
# TODO: Hacer que los diferentes tipos de deploy se auto registren
|
# TODO: Hacer que los diferentes tipos de deploy se auto registren
|
||||||
# @see app/services/site_service.rb
|
# @see app/services/site_service.rb
|
||||||
DEPLOYS = %i[local www zip hidden_service].freeze
|
DEPLOYS = %i[local www zip hidden_service].freeze
|
||||||
|
|
7
app/views/posts/attribute_ro/_encrypted_text.haml
Normal file
7
app/views/posts/attribute_ro/_encrypted_text.haml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
%tr{ id: attribute }
|
||||||
|
%th
|
||||||
|
%abbr{ title: t('lockbox.help.description') }
|
||||||
|
🔒
|
||||||
|
%span.sr-only= t('lockbox.help.title')
|
||||||
|
= post_label_t(attribute, post: post)
|
||||||
|
%td{ dir: dir, lang: locale }= metadata.value
|
11
app/views/posts/attributes/_encrypted_text.haml
Normal file
11
app/views/posts/attributes/_encrypted_text.haml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
.form-group
|
||||||
|
= label_tag "post_#{attribute}" do
|
||||||
|
%abbr{ title: t('lockbox.help.description') }
|
||||||
|
🔒
|
||||||
|
%span.sr-only= t('lockbox.help.title')
|
||||||
|
= post_label_t(attribute, post: post)
|
||||||
|
= text_area_tag "post[#{attribute}]", metadata.value,
|
||||||
|
dir: dir, lang: locale,
|
||||||
|
**field_options(attribute, metadata)
|
||||||
|
= render 'posts/attribute_feedback',
|
||||||
|
post: post, attribute: attribute, metadata: metadata
|
1
config/initializers/lockbox.rb
Normal file
1
config/initializers/lockbox.rb
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Lockbox.master_key = Rails.application.credentials.lockbox_master_key
|
|
@ -514,3 +514,8 @@ en:
|
||||||
title: '404: Page not found :('
|
title: '404: Page not found :('
|
||||||
description: "You're reading this message because the page you wanted doesn't exist."
|
description: "You're reading this message because the page you wanted doesn't exist."
|
||||||
button: 'Back to panel'
|
button: 'Back to panel'
|
||||||
|
lockbox:
|
||||||
|
help:
|
||||||
|
title: Encrypted content
|
||||||
|
description: The field contents are encrypted before being stored and won't be available on the public website or its source code. You can save private information here and it will only be readable to this site's users through Sutty's panel.
|
||||||
|
decryption_error: There was an error trying to decrypt the content, Sutty's team has been notified!
|
||||||
|
|
|
@ -527,3 +527,8 @@ es:
|
||||||
title: '404: Página no encontrada :('
|
title: '404: Página no encontrada :('
|
||||||
description: 'Estás leyendo este error porque la página que quisiste acceder no existe.'
|
description: 'Estás leyendo este error porque la página que quisiste acceder no existe.'
|
||||||
button: 'Volver al panel'
|
button: 'Volver al panel'
|
||||||
|
lockbox:
|
||||||
|
help:
|
||||||
|
title: Contenido cifrado
|
||||||
|
description: El contenido de este campo se guarda cifrado y no estará disponible en el sitio ni en su código fuente. Puedes guardar información privada aquí y sólo estará disponible para quienes tengan acceso a ese sitio en el panel de Sutty.
|
||||||
|
decryption_error: Hubo un error al decifrar la información, ¡el equipo de Sutty ya fue notificado!
|
||||||
|
|
16
db/migrate/20200810230944_add_priv_key_to_sites.rb
Normal file
16
db/migrate/20200810230944_add_priv_key_to_sites.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Agrega las llaves privadas cifradas a cada sitio
|
||||||
|
class AddPrivKeyToSites < ActiveRecord::Migration[6.0]
|
||||||
|
def up
|
||||||
|
add_column :sites, :private_key_ciphertext, :string
|
||||||
|
|
||||||
|
Site.find_each do |site|
|
||||||
|
site.update_attribute :private_key, Lockbox.generate_key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :sites, :private_key_ciphertext
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,8 +12,8 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20_200_616_133_218) do
|
ActiveRecord::Schema.define(version: 20_200_810_230_944) do
|
||||||
# Could not dump table "access_logs" because of following StandardError
|
# Could not dump table 'access_logs' because of following StandardError
|
||||||
# Unknown type '' for column 'id'
|
# Unknown type '' for column 'id'
|
||||||
|
|
||||||
create_table 'action_text_rich_texts', force: :cascade do |t|
|
create_table 'action_text_rich_texts', force: :cascade do |t|
|
||||||
|
@ -58,7 +58,7 @@ ActiveRecord::Schema.define(version: 20_200_616_133_218) do
|
||||||
t.index ['deploy_id'], name: 'index_build_stats_on_deploy_id'
|
t.index ['deploy_id'], name: 'index_build_stats_on_deploy_id'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Could not dump table "csp_reports" because of following StandardError
|
# Could not dump table 'csp_reports' because of following StandardError
|
||||||
# Unknown type 'uuid' for column 'id'
|
# Unknown type 'uuid' for column 'id'
|
||||||
|
|
||||||
create_table 'deploys', force: :cascade do |t|
|
create_table 'deploys', force: :cascade do |t|
|
||||||
|
@ -157,6 +157,7 @@ ActiveRecord::Schema.define(version: 20_200_616_133_218) do
|
||||||
t.string 'title'
|
t.string 'title'
|
||||||
t.boolean 'colaboracion_anonima', default: false
|
t.boolean 'colaboracion_anonima', default: false
|
||||||
t.boolean 'contact', default: false
|
t.boolean 'contact', default: false
|
||||||
|
t.string 'private_key_ciphertext'
|
||||||
t.index ['design_id'], name: 'index_sites_on_design_id'
|
t.index ['design_id'], name: 'index_sites_on_design_id'
|
||||||
t.index ['licencia_id'], name: 'index_sites_on_licencia_id'
|
t.index ['licencia_id'], name: 'index_sites_on_licencia_id'
|
||||||
t.index ['name'], name: 'index_sites_on_name', unique: true
|
t.index ['name'], name: 'index_sites_on_name', unique: true
|
||||||
|
|
Loading…
Reference in a new issue