require"set"require"yaml"# This needs to be defined up front in case any internal classes need to base# their behavior off of this.moduleSafeYAMLYAML_ENGINE=defined?(YAML::ENGINE)?YAML::ENGINE.yamler:(defined?(Psych)&&YAML==Psych?"psych":"syck")endrequire"safe_yaml/libyaml_checker"require"safe_yaml/deep"require"safe_yaml/parse/hexadecimal"require"safe_yaml/parse/sexagesimal"require"safe_yaml/parse/date"require"safe_yaml/transform/transformation_map"require"safe_yaml/transform/to_boolean"require"safe_yaml/transform/to_date"require"safe_yaml/transform/to_float"require"safe_yaml/transform/to_integer"require"safe_yaml/transform/to_nil"require"safe_yaml/transform/to_symbol"require"safe_yaml/transform"require"safe_yaml/resolver"require"safe_yaml/syck_hack"ifSafeYAML::YAML_ENGINE=="syck"&&defined?(JRUBY_VERSION)moduleSafeYAMLMULTI_ARGUMENT_YAML_LOAD=YAML.method(:load).arity!=1DEFAULT_OPTIONS=Deep.freeze({:default_mode=>nil,:suppress_warnings=>false,:deserialize_symbols=>false,:whitelisted_tags=>[],:custom_initializers=>{},:raise_on_unknown_tag=>false})OPTIONS=Deep.copy(DEFAULT_OPTIONS)PREDEFINED_TAGS={}ifYAML_ENGINE=="syck"YAML.tagged_classes.eachdo|tag,klass|PREDEFINED_TAGS[klass]=tagendelse# Special tags appear to be hard-coded in Psych:# https://github.com/tenderlove/psych/blob/v1.3.4/lib/psych/visitors/to_ruby.rb# Fortunately, there aren't many that SafeYAML doesn't already support.PREDEFINED_TAGS.merge!({Exception=>"!ruby/exception",Range=>"!ruby/range",Regexp=>"!ruby/regexp",})endDeep.freeze(PREDEFINED_TAGS)module_functiondefrestore_defaults!OPTIONS.clear.merge!(Deep.copy(DEFAULT_OPTIONS))enddeftag_safety_check!(tag,options)returniftag.nil?||tag=="!"ifoptions[:raise_on_unknown_tag]&&!options[:whitelisted_tags].include?(tag)&&!tag_is_explicitly_trusted?(tag)raise"Unknown YAML tag '#{tag}'"endenddefwhitelist!(*classes)classes.eachdo|klass|whitelist_class!(klass)endenddefwhitelist_class!(klass)raise"#{klass} not a Class"unlessklass.is_a?(::Class)klass_name=klass.nameraise"#{klass} cannot be anonymous"ifklass_name.nil?||klass_name.empty?# Whitelist any built-in YAML tags supplied by Syck or Psych.predefined_tag=PREDEFINED_TAGS[klass]ifpredefined_tagOPTIONS[:whitelisted_tags]<<predefined_tagreturnend# Exception is exceptional (har har).tag_class=klass<Exception?"exception":"object"tag_prefix=caseYAML_ENGINEwhen"psych"then"!ruby/#{tag_class}"when"syck"then"tag:ruby.yaml.org,2002:#{tag_class}"elseraise"unknown YAML_ENGINE #{YAML_ENGINE}"endOPTIONS[:whitelisted_tags]<<"#{tag_prefix}:#{klass_name}"endifYAML_ENGINE=="psych"deftag_is_explicitly_trusted?(tag)falseendelseTRUSTED_TAGS=Set.new(["tag:yaml.org,2002:binary","tag:yaml.org,2002:bool#no","tag:yaml.org,2002:bool#yes","tag:yaml.org,2002:float","tag:yaml.org,2002:float#fix","tag:yaml.org,2002:int","tag:yaml.org,2002:map","tag:yaml.org,2002:null","tag:yaml.org,2002:seq","tag:yaml.org,2002:str","tag:yaml.org,2002:timestamp","tag:yaml.org,2002:timestamp#ymd"]).freezedeftag_is_explicitly_trusted?(tag)TRUSTED_TAGS.include?(tag)endendifSafeYAML::YAML_ENGINE=="psych"require"safe_yaml/psych_handler"require"safe_yaml/psych_resolver"require"safe_yaml/safe_to_ruby_visitor"defself.load(yaml,filename=nil,options={})# If the user hasn't whitelisted any tags, we can go with this implementation which is# significantly faster.if(options&&options[:whitelisted_tags]||SafeYAML::OPTIONS[:whitelisted_tags]).empty?safe_handler=SafeYAML::PsychHandler.new(options)do|result|returnresultendarguments_for_parse=[yaml]arguments_for_parse<<filenameifSafeYAML::MULTI_ARGUMENT_YAML_LOADPsych::Parser.new(safe_handler).parse(*arguments_for_parse)returnsafe_handler.resultelsesafe_resolver=SafeYAML::PsychResolver.new(options)tree=SafeYAML::MULTI_ARGUMENT_YAML_LOAD?Psych.parse(yaml,filename):Psych.parse(yaml)returnsafe_resolver.resolve_node(tree)endenddefself.load_file(filename,options={})ifSafeYAML::MULTI_ARGUMENT_YAML_LOADFile.open(filename,'r:bom|utf-8'){|f|self.load(f,filename,options)}else# Ruby pukes on 1.9.2 if we try to open an empty file w/ 'r:bom|utf-8';# so we'll not specify those flags here. This mirrors the behavior for# unsafe_load_file so it's probably preferable anyway.self.loadFile.open(filename),nil,optionsendendelserequire"safe_yaml/syck_resolver"require"safe_yaml/syck_node_monkeypatch"defself.load(yaml,options={})resolver=SafeYAML::SyckResolver.new(SafeYAML::OPTIONS.merge(options||{}))tree=YAML.parse(yaml)returnresolver.resolve_node(tree)enddefself.load_file(filename,options={})File.open(filename){|f|self.load(f,options)}endendend