Ruby - parsing a hash string using YAML - error if the hash is injected and coerced into a string rather than typed as a string

I have a gem that I created that wraps Git as a keystore: value (dictionary / hash). Source here .

The way it works in said process is as follows:

  • run a function set

    containing a key and a value argument
  • hash these with git, have a cue point in the hash
  • return the key if this operation is successful and added to the globals and dictionary hashes

Now if I call something like

db.set('key', {some: 'value'})
# => 'key'

      

and then try to find it,

db.get('key')
Psych::SyntaxError: (<unknown>): did not find expected node content while parsing a flow node at line 1 column 2
from /home/bobby/.rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/psych.rb:370:in `parse'
from /home/bobby/.rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/psych.rb:370:in `parse_stream'
from /home/bobby/.rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/psych.rb:318:in `parse'
from /home/bobby/.rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/psych.rb:245:in `load'
from /home/bobby/.rvm/gems/ruby-2.2.1/gems/gkv-0.2.1/lib/gkv/database.rb:21:in `get'
from (irb):6
from /home/bobby/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>'

      

Now if I set the key as the same dictionary but as a string:

db.set('key', "{some: 'value'}")
# => 'key'
db.get('key')
# => {"key"=>"value"} 
db.get('key').class
=> Hash

      

An operation doing Git operations and pushing them into the kv repository source:

...
    def get(key)
      if $ITEMS.keys.include? key
        YAML.load(Gkv::GitFunctions.cat_file($ITEMS[key].last))
      else
        raise KeyError
      end
    end

    def set(key, value)
      update_items(key, value.to_s)
      key
    end
...

      

And here's the function get_items

that the source refers to:

...    
  def update_items(key, value)
      if $ITEMS.keys.include? key
        history = $ITEMS[key]
        history << Gkv::GitFunctions.hash_object(value.to_s)
        $ITEMS[key] = history
      else
        $ITEMS[key] = [Gkv::GitFunctions.hash_object(value.to_s)]
      end
    end
  end
...

      

hash_object

and cat_object

simple wrapping git hash-object

and git cat-file

in the method writing the input to the tmp file, git add

ing and then erasing the temp file.

I really don't understand why this works with strings, but not true dictionaries. This results in the same error if you use the old hash hash syntax:

db.set('a', {:key => 'value'})
=> "a" 
db.get('a')
# => Psych::SyntaxError: (<unknown>): did not find expected node content while parsing a flow node at line 1 column 2
from /home/bobby/.rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/psych.rb:370:in `parse'
from /home/bobby/.rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/psych.rb:370:in `parse_stream'
from /home/bobby/.rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/psych.rb:318:in `parse'
from /home/bobby/.rvm/rubies/ruby-2.2.1/lib/ruby/2.2.0/psych.rb:245:in `load'
from /home/bobby/.rvm/gems/ruby-2.2.1/gems/gkv-0.2.1/lib/gkv/database.rb:21:in `get'
from (irb):6
from /home/bobby/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>'

      

Any ideas?

+3


source to share


1 answer


In your method get

you are calling YAML.load

, but in your set method you are using .to_s

. This means that the YAML parser tries to read an arbitrary string as if it were YAML. For symmetry YAML.dump

, use the method instead set

.



I created a pull request with changes.

+2


source







All Articles