summaryrefslogtreecommitdiff
path: root/lib/psych/visitors/yaml_tree.rb
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2021-05-19 16:07:24 +0200
committerJean Boussier <jean.boussier@gmail.com>2021-05-19 16:24:18 +0200
commit441958396f40d526a62e564761d2bad534465a5b (patch)
treed8fe066d81bafe293c34d600e9fe58a130505cae /lib/psych/visitors/yaml_tree.rb
parent3fabcb953f04b4c4927b419d6d91026f65e984af (diff)
downloadpsych-441958396f40d526a62e564761d2bad534465a5b.zip
Implement YAML.safe_dump to make safe_load more usable.
In case where Psych is used as a two way serializers, e.g. to serialize some cache or config, it is preferable to have the same restrictions on both load and dump. Otherwise you might dump and persist some objects payloads that you later won't be able to read.
Diffstat (limited to 'lib/psych/visitors/yaml_tree.rb')
-rw-r--r--lib/psych/visitors/yaml_tree.rb46
1 files changed, 46 insertions, 0 deletions
diff --git a/lib/psych/visitors/yaml_tree.rb b/lib/psych/visitors/yaml_tree.rb
index bf7c0bb..05748dd 100644
--- a/lib/psych/visitors/yaml_tree.rb
+++ b/lib/psych/visitors/yaml_tree.rb
@@ -535,5 +535,51 @@ module Psych
end
end
end
+
+ class RestrictedYAMLTree < YAMLTree
+ DEFAULT_PERMITTED_CLASSES = {
+ TrueClass => true,
+ FalseClass => true,
+ NilClass => true,
+ Integer => true,
+ Float => true,
+ String => true,
+ Array => true,
+ Hash => true,
+ }.compare_by_identity.freeze
+
+ def initialize emitter, ss, options
+ super
+ @permitted_classes = DEFAULT_PERMITTED_CLASSES.dup
+ Array(options[:permitted_classes]).each do |klass|
+ @permitted_classes[klass] = true
+ end
+ @permitted_symbols = {}.compare_by_identity
+ Array(options[:permitted_symbols]).each do |symbol|
+ @permitted_symbols[symbol] = true
+ end
+ @aliases = options.fetch(:aliases, false)
+ end
+
+ def accept target
+ if !@aliases && @st.key?(target)
+ raise BadAlias, "Tried to dump an aliased object"
+ end
+
+ unless @permitted_classes[target.class]
+ raise DisallowedClass.new('dump', target.class.name || target.class.inspect)
+ end
+
+ super
+ end
+
+ def visit_Symbol sym
+ unless @permitted_symbols[sym]
+ raise DisallowedClass.new('dump', "Symbol(#{sym.inspect})")
+ end
+
+ super
+ end
+ end
end
end