los datos privados se cifran!
This commit is contained in:
parent
b16250059a
commit
21dd44351f
8 changed files with 88 additions and 30 deletions
|
@ -1,34 +1,11 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Íbamos a usar OpenSSL pero esto es más simple de implementar y no
|
# Como todos los campos pueden ser cifrados, forzamos el cifrado
|
||||||
# tenemos que usar cifrado compatible con JavaScript.
|
# configurando este texto como privado.
|
||||||
|
#
|
||||||
|
# TODO: Deprecar
|
||||||
class MetadataEncryptedText < MetadataText
|
class MetadataEncryptedText < MetadataText
|
||||||
# Decifra el valor si está guardado en el sitio
|
def private?
|
||||||
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
|
true
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -14,7 +14,22 @@ class MetadataGeo < MetadataTemplate
|
||||||
return true if empty?
|
return true if empty?
|
||||||
|
|
||||||
self[:value] = value.transform_values(&:to_f)
|
self[:value] = value.transform_values(&:to_f)
|
||||||
|
self[:value] = encrypt(value) if private?
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -9,7 +9,14 @@ class MetadataNumber < MetadataTemplate
|
||||||
|
|
||||||
def save
|
def save
|
||||||
self[:value] = value.to_i
|
self[:value] = value.to_i
|
||||||
|
self[:value] = encrypt(value) if private?
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def decrypt(value)
|
||||||
|
super(value).to_i
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,4 +13,9 @@ class MetadataOrder < MetadataTemplate
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# El orden nunca puede ser privado
|
||||||
|
def private?
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,11 @@ class MetadataRelatedPosts < MetadataArray
|
||||||
end.inject(:merge)
|
end.inject(:merge)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Las relaciones nunca son privadas
|
||||||
|
def private?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Obtiene todos los posts y opcionalmente los filtra
|
# Obtiene todos los posts y opcionalmente los filtra
|
||||||
|
|
|
@ -38,7 +38,10 @@ class MetadataSlug < MetadataTemplate
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
# Devuelve el título a menos que sea privado y no esté vacío
|
||||||
def title
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,7 +24,11 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
|
||||||
# Valor actual o por defecto. Al memoizarlo podemos modificarlo
|
# Valor actual o por defecto. Al memoizarlo podemos modificarlo
|
||||||
# usando otros métodos que el de asignación.
|
# usando otros métodos que el de asignación.
|
||||||
def value
|
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
|
end
|
||||||
|
|
||||||
# Detecta si el valor está vacío
|
# Detecta si el valor está vacío
|
||||||
|
@ -74,6 +78,8 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
|
||||||
# guardado
|
# guardado
|
||||||
def save
|
def save
|
||||||
self[:value] = sanitize value
|
self[:value] = sanitize value
|
||||||
|
self[:value] = encrypt(value) if private?
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -85,6 +91,11 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type,
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Determina si el campo es privado y debería ser cifrado
|
||||||
|
def private?
|
||||||
|
!!layout.metadata.dig(name, 'private')
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Si es obligatorio no puede estar vacío
|
# 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],
|
attributes: allowed_attributes + %w[data-trix-attachment],
|
||||||
scrubber: scrubber).strip.html_safe
|
scrubber: scrubber).strip.html_safe
|
||||||
end
|
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
|
end
|
||||||
# rubocop:enable Metrics/BlockLength
|
# rubocop:enable Metrics/BlockLength
|
||||||
|
|
|
@ -57,6 +57,7 @@ class Site < ApplicationRecord
|
||||||
after_create :load_jekyll, :static_file_migration!
|
after_create :load_jekyll, :static_file_migration!
|
||||||
# Cambiar el nombre del directorio
|
# Cambiar el nombre del directorio
|
||||||
before_update :update_name!
|
before_update :update_name!
|
||||||
|
before_save :add_private_key_if_missing!
|
||||||
# Guardar la configuración si hubo cambios
|
# Guardar la configuración si hubo cambios
|
||||||
after_save :sync_attributes_with_config!
|
after_save :sync_attributes_with_config!
|
||||||
|
|
||||||
|
@ -391,6 +392,11 @@ class Site < ApplicationRecord
|
||||||
|
|
||||||
private
|
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
|
# Clona el esqueleto de Sutty para crear el sitio nuevo, no pasa nada
|
||||||
# si el sitio ya existe
|
# si el sitio ya existe
|
||||||
def clone_skel!
|
def clone_skel!
|
||||||
|
|
Loading…
Reference in a new issue