From 1f7eed1a9ab01b1d87495b73f912cf7a912264de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20Bo=CC=88ning?= Date: Sat, 2 Dec 2017 23:30:43 +0100 Subject: [PATCH 1/4] Allow Date, Regexp and Symbol in YAML.safe_load in generators Date and Symbol values are quite common as default values for contents in the element definitions, so these types need to be allowed when the element generator parses them. --- lib/rails/generators/alchemy/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rails/generators/alchemy/base.rb b/lib/rails/generators/alchemy/base.rb index e2d4b7ef9e..11b0a9319c 100644 --- a/lib/rails/generators/alchemy/base.rb +++ b/lib/rails/generators/alchemy/base.rb @@ -32,7 +32,7 @@ def template_engine end def load_alchemy_yaml(name) - YAML.safe_load(ERB.new(File.read("#{Rails.root}/config/alchemy/#{name}")).result, [Regexp], [], true) + YAML.safe_load(ERB.new(File.read("#{Rails.root}/config/alchemy/#{name}")).result, [Date, Regexp, Symbol], [], true) rescue Errno::ENOENT puts "\nERROR: Could not read config/alchemy/#{name} file. Please run: rails generate alchemy:scaffold" end From 3a8aad336167c630c394ac3c5ba20a3857253a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20Bo=CC=88ning?= Date: Sun, 10 Dec 2017 22:42:41 +0100 Subject: [PATCH 2/4] Whitelist classes for YAML.safe_load using a constant --- app/models/alchemy/cell.rb | 2 +- app/models/alchemy/element/definitions.rb | 2 +- lib/alchemy/page_layout.rb | 2 +- lib/alchemy_cms.rb | 1 + lib/rails/generators/alchemy/base.rb | 2 +- spec/models/alchemy/element_spec.rb | 27 +++++++++++++++++++++++ 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/app/models/alchemy/cell.rb b/app/models/alchemy/cell.rb index dd301de215..30f1401655 100644 --- a/app/models/alchemy/cell.rb +++ b/app/models/alchemy/cell.rb @@ -58,7 +58,7 @@ def translated_label_for(cell_name) private def read_yml_file - ::YAML.safe_load(ERB.new(File.read(yml_file_path)).result, [], [], true) || [] + ::YAML.safe_load(ERB.new(File.read(yml_file_path)).result, YAML_WHITELIST_CLASSES, [], true) || [] end def yml_file_path diff --git a/app/models/alchemy/element/definitions.rb b/app/models/alchemy/element/definitions.rb index b5a47d1584..47a9bc1b4c 100644 --- a/app/models/alchemy/element/definitions.rb +++ b/app/models/alchemy/element/definitions.rb @@ -28,7 +28,7 @@ def definition_by_name(name) # def read_definitions_file if ::File.exist?(definitions_file_path) - ::YAML.safe_load(ERB.new(File.read(definitions_file_path)).result, [Date, Regexp, Symbol], [], true) || [] + ::YAML.safe_load(ERB.new(File.read(definitions_file_path)).result, YAML_WHITELIST_CLASSES, [], true) || [] else raise LoadError, "Could not find elements.yml file! Please run `rails generate alchemy:scaffold`" end diff --git a/lib/alchemy/page_layout.rb b/lib/alchemy/page_layout.rb index 4beeaf2432..7a8db34a27 100644 --- a/lib/alchemy/page_layout.rb +++ b/lib/alchemy/page_layout.rb @@ -159,7 +159,7 @@ def available_on_site?(layout) # def read_definitions_file if File.exist?(layouts_file_path) - YAML.safe_load(ERB.new(File.read(layouts_file_path)).result, [Date, Symbol], [], true) || [] + YAML.safe_load(ERB.new(File.read(layouts_file_path)).result, YAML_WHITELIST_CLASSES, [], true) || [] else raise LoadError, "Could not find page_layouts.yml file! Please run `rails generate alchemy:scaffold`" end diff --git a/lib/alchemy_cms.rb b/lib/alchemy_cms.rb index 4edd894258..4dba0e262b 100644 --- a/lib/alchemy_cms.rb +++ b/lib/alchemy_cms.rb @@ -1,5 +1,6 @@ # Instantiate the global Alchemy namespace module Alchemy + Alchemy::YAML_WHITELIST_CLASSES = %w(Symbol Date Regexp) end # Require globally used external libraries diff --git a/lib/rails/generators/alchemy/base.rb b/lib/rails/generators/alchemy/base.rb index 11b0a9319c..38b2a5659e 100644 --- a/lib/rails/generators/alchemy/base.rb +++ b/lib/rails/generators/alchemy/base.rb @@ -32,7 +32,7 @@ def template_engine end def load_alchemy_yaml(name) - YAML.safe_load(ERB.new(File.read("#{Rails.root}/config/alchemy/#{name}")).result, [Date, Regexp, Symbol], [], true) + YAML.safe_load(ERB.new(File.read("#{Rails.root}/config/alchemy/#{name}")).result, YAML_WHITELIST_CLASSES, [], true) rescue Errno::ENOENT puts "\nERROR: Could not read config/alchemy/#{name} file. Please run: rails generate alchemy:scaffold" end diff --git a/spec/models/alchemy/element_spec.rb b/spec/models/alchemy/element_spec.rb index fdc5ebb556..843e0761c4 100644 --- a/spec/models/alchemy/element_spec.rb +++ b/spec/models/alchemy/element_spec.rb @@ -119,6 +119,33 @@ module Alchemy context "with a YAML file including a symbol" do let(:yaml) { '- name: :symbol' } + + before do + expect(File).to receive(:exist?).and_return(true) + expect(File).to receive(:read).and_return(yaml) + end + + it "returns the definition without error" do + expect { Element.definitions }.to_not raise_error + end + end + + context "with a YAML file including a Date" do + let(:yaml) { '- default: 2017-12-24' } + + before do + expect(File).to receive(:exist?).and_return(true) + expect(File).to receive(:read).and_return(yaml) + end + + it "returns the definition without error" do + expect { Element.definitions }.to_not raise_error + end + end + + context "with a YAML file including a Regex" do + let(:yaml) { "- format: !ruby/regexp '/\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/'" } + before do expect(File).to receive(:exist?).and_return(true) expect(File).to receive(:read).and_return(yaml) From efa3f3b681dd7cdd7d65a8cff9ee2c79fa4d8d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20Bo=CC=88ning?= Date: Mon, 11 Dec 2017 03:07:45 +0100 Subject: [PATCH 3/4] Use YAML.safe_load in Alchemy::Config --- lib/alchemy/config.rb | 3 ++- spec/libraries/config_spec.rb | 13 +++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/alchemy/config.rb b/lib/alchemy/config.rb index a101cd3822..7eda5cec9f 100644 --- a/lib/alchemy/config.rb +++ b/lib/alchemy/config.rb @@ -48,7 +48,8 @@ def env_specific_config # If it does not exist, or its empty, it returns an empty Hash. # def read_file(file) - return YAML.load_file(file) || {} if File.exist?(file) # YAML.load_file returns false if file is empty. + YAML.safe_load(ERB.new(File.read(file)).result, YAML_WHITELIST_CLASSES, [], true) || {} + rescue Errno::ENOENT {} end diff --git a/spec/libraries/config_spec.rb b/spec/libraries/config_spec.rb index 34eb824a32..970bafd0e9 100644 --- a/spec/libraries/config_spec.rb +++ b/spec/libraries/config_spec.rb @@ -54,17 +54,10 @@ module Alchemy describe '.read_file' do context 'when given path to yml file exists' do - before { allow(File).to receive(:exist?).and_return(true) } - - it 'should call YAML.load_file with the given config path' do - expect(YAML).to receive(:load_file).once.with('path/to/config.yml').and_return({}) - Config.send(:read_file, 'path/to/config.yml') - end - - context 'but its empty' do + context 'and file is empty' do before do - allow(File).to receive(:exist?).with('empty_file.yml').and_return(true) - allow(YAML).to receive(:load_file).and_return(false) # YAML.load_file returns false if file is empty. + # YAML.safe_load returns nil if file is empty. + allow(YAML).to receive(:safe_load) { nil } end it "should return an empty Hash" do From 55b6b6016083d7aacff616e4cf9c7b5c89c6fc30 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Mon, 19 Mar 2018 09:13:40 +0100 Subject: [PATCH 4/4] Fix the error message for missing yml file. --- lib/rails/generators/alchemy/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rails/generators/alchemy/base.rb b/lib/rails/generators/alchemy/base.rb index 38b2a5659e..2e1de6f856 100644 --- a/lib/rails/generators/alchemy/base.rb +++ b/lib/rails/generators/alchemy/base.rb @@ -34,7 +34,7 @@ def template_engine def load_alchemy_yaml(name) YAML.safe_load(ERB.new(File.read("#{Rails.root}/config/alchemy/#{name}")).result, YAML_WHITELIST_CLASSES, [], true) rescue Errno::ENOENT - puts "\nERROR: Could not read config/alchemy/#{name} file. Please run: rails generate alchemy:scaffold" + puts "\nERROR: Could not read config/alchemy/#{name} file. Please run: `rails generate alchemy:install`" end end end