# frozen_string_literal: true # Esta clase se encarga de guardan los archivos YAML de idiomas # # TODO se podría convertir en una clase genérica de editor de YAML class JekyllI18n attr_reader :site, :lang, :attributes def initialize(site:, lang:, attributes:) unless site.is_a? Site raise ArgumentError, I18n.t('errors.argument_error', argument: :site, class: Site) end unless I18n.available_locales.include? lang.to_sym raise ArgumentError, I18n.t('errors.unknown_locale', locale: lang) end @site = site @lang = lang.to_sym @attributes = attributes.to_hash # porque enviamos parametros end # Vuelva los datos a YAML y los guarda en el archivo correspondiente # # TODO es necesario evitar que se agreguen llaves nuevas? No veo nada # inseguro... # # https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/ # # Pero parece que ya se resolvió hace rato. En general es mala # práctica aceptar cualquier input de las usuarias, pero en este caso # parece que no nos tenemos que preocupar? # # En cualquier caso habría que hacer un deep_merge, descartando las # llaves que no están en el original y/o en el destino (pero queremos # que el destino se parezca al original) y chequeando que no haya # deserialización de objetos # # Jekyll usa SafeYAML para cargar los datos, con lo que estaríamos # bien en cuanto a inyección de código. def save # Reemplaza los datos en el sitio replace_lang_in_site # Escribe los cambios en disco write end # Obtiene la ruta a partir del sitio y el idioma def path File.join(@site.path, '_data', "#{@lang}.yml") end def exist? File.exist? path end private def replace_lang_in_site @site.data[@lang.to_s] = @attributes end # Escribe los cambios en disco # # TODO unificar con Post.write def write r = File.open(path, File::RDWR | File::CREAT, 0o640) do |f| # Bloquear el archivo para que no sea accedido por otro # proceso u otra editora f.flock(File::LOCK_EX) # Empezar por el principio f.rewind # Escribir f.write(content) # Eliminar el resto f.flush f.truncate(f.pos) end return true if r.zero? false end def content @attributes.to_yaml end end