los datos privados se cifran!

This commit is contained in:
f 2020-08-20 20:38:31 -03:00
parent b16250059a
commit 21dd44351f
8 changed files with 88 additions and 30 deletions

View file

@ -1,34 +1,11 @@
# 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.
# Como todos los campos pueden ser cifrados, forzamos el cifrado
# configurando este texto como privado.
#
# TODO: Deprecar
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)
def private?
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

View file

@ -14,7 +14,22 @@ class MetadataGeo < MetadataTemplate
return true if empty?
self[:value] = value.transform_values(&:to_f)
self[:value] = encrypt(value) if private?
true
end
private
def encrypt(value)
value.transform_values do |v|
super v
end
end
def decrypt(value)
value.transform_values do |v|
super v
end
end
end

View file

@ -9,7 +9,14 @@ class MetadataNumber < MetadataTemplate
def save
self[:value] = value.to_i
self[:value] = encrypt(value) if private?
true
end
private
def decrypt(value)
super(value).to_i
end
end

View file

@ -13,4 +13,9 @@ class MetadataOrder < MetadataTemplate
true
end
# El orden nunca puede ser privado
def private?
false
end
end

View file

@ -10,6 +10,11 @@ class MetadataRelatedPosts < MetadataArray
end.inject(:merge)
end
# Las relaciones nunca son privadas
def private?
false
end
private
# Obtiene todos los posts y opcionalmente los filtra

View file

@ -38,7 +38,10 @@ class MetadataSlug < MetadataTemplate
private
# Devuelve el título a menos que sea privado y no esté vacío
def title
post.title.try(:value) unless post.title.try(:value).blank?
unless post.title.private? && !post.title.try(:value).try(:blank?)
post.title.try(:value).try(:to_s)
end
end
end

View file

@ -24,7 +24,11 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
# Valor actual o por defecto. Al memoizarlo podemos modificarlo
# usando otros métodos que el de asignación.
def value
self[:value] ||= document.data.fetch(name.to_s, default_value)
self[:value] ||= if private?
decrypt document.data.fetch(name.to_s, default_value)
else
document.data.fetch(name.to_s, default_value)
end
end
# Detecta si el valor está vacío
@ -74,6 +78,8 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
# guardado
def save
self[:value] = sanitize value
self[:value] = encrypt(value) if private?
true
end
@ -85,6 +91,11 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
raise NotImplementedError
end
# Determina si el campo es privado y debería ser cifrado
def private?
!!layout.metadata.dig(name, 'private')
end
private
# Si es obligatorio no puede estar vacío
@ -104,5 +115,34 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
attributes: allowed_attributes + %w[data-trix-attachment],
scrubber: scrubber).strip.html_safe
end
# Decifra el valor
#
# XXX: Otros tipos de valores necesitan implementar su propio método
# de decifrado (Array).
def decrypt(value)
return value if value.blank?
box.decrypt_str value.to_s
rescue Lockbox::DecryptionError => e
ExceptionNotifier.notify_exception(e)
I18n.t('lockbox.help.decryption_error')
end
# Cifra el valor.
#
# XXX: Otros tipos de valores necesitan implementar su propio método
# de cifrado (Array).
def encrypt(value)
box.encrypt value.to_s
end
# 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
# rubocop:enable Metrics/BlockLength

View file

@ -57,6 +57,7 @@ class Site < ApplicationRecord
after_create :load_jekyll, :static_file_migration!
# Cambiar el nombre del directorio
before_update :update_name!
before_save :add_private_key_if_missing!
# Guardar la configuración si hubo cambios
after_save :sync_attributes_with_config!
@ -391,6 +392,11 @@ class Site < ApplicationRecord
private
# Asegurarse que el sitio tenga una llave privada
def add_private_key_if_missing!
self.private_key ||= Lockbox.generate_key
end
# Clona el esqueleto de Sutty para crear el sitio nuevo, no pasa nada
# si el sitio ya existe
def clone_skel!