How do I get OpenSSL style salted MD5 in Ruby? - ruby

I'm talking about this:
$ openssl passwd -1 -salt thesalt thepassword
$1$thesalt$HAWpBmvUCutuyTS4JwevI.
In PHP it would look like this:
crypt('thepassword', ('$1$'.'thesalt')); # this gives the same output as above
I'm trying to achieve the same format in Ruby 1.9. I've been told Ruby's String#crypt will do this but it does not. I've looked everywhere for an answer, but I've come across nothing.
If it helps anything, I'm trying to do this on Windows XP.
Ruby version: ruby 1.9.3p0 (2011-10-30) [i386-mingw32]
Just to keep away the comments telling me to use something other than MD5 or whatever else, I would if I could. This choice isn't up to me.
Thanks.
Edit: I want to do this without shelling out to openssl because that would be too slow for what I need.

If all else fails, you could call the openssl executable using backticks:
password = "thepassword"
salt = "thesalt"
hashed = `openssl passwd -1 -salt #{salt} #{password}`
puts hashed # => $1$thesalt$HAWpBmvUCutuyTS4JwevI.

Darn. I was hoping for the same thing.
see also Generate openssl password with Ruby for the reason why it is not in ruby.

Related

How can I determine what the current stable version of Ruby is?

I want to write a Ruby method that does two things:
Determine what the current stable version of Ruby is. My first thought is to get the response from https://www.ruby-lang.org/en/downloads/ and use RegEx to isolate the phrase The current stable version is [x]. Is there is an API I'm not aware of?
Get the URL to download the .tar.gz of that release. For this I was thinking the same thing, get it from the output of the site URL.
I'm looking for advice about the best way to go about it, or direction if there's something in place I might use to determine my desired results.
Ruby code to fetch the download page, then parse the current version and the link URL:
html = Net::HTTP.get(URI("https://www.ruby-lang.org/en/downloads/"))
vers = html[/http.*ruby-(.*).tar.gz/,1]
link = html[/http.*ruby-.*.tar.gz/]
GitHub code: ruby-stable-version.rb
Shell code:
ruby-stable-version
If you are using rbenv you can use ruby-build to get a list of ruby versions and then grep against that.
ruby-build --definitions | tail -r | grep -x -G -m 1 '[0-9]\.[0-9].[0-9]\-*[p0-9*]*'
You can then use that within your code like so:
version = `ruby-build --definitions | tail -r | grep -x -G -m 1 '[0-9]\.[0-9].[0-9]\-*[p0-9*]*'`.strip
You can then use this value to get the download URL.
url = "http://cache.ruby-lang.org/pub/ruby/#{version[0..2]}/ruby-#{version}.tar.gz"
And then download the file:
require 'open-uri'
open("ruby-#{version}.tar.gz", 'wb') do |file|
file << open(url).read
end
Learn more about rbenv here and ruby-build here.
Another possibility would be to use the Ruby source repository. Check version.h in every branch, filter by RUBY_PATCHLEVEL > -1 (-1 is used for -dev versions), sort by RUBY_VERSION and take the latest one.
You can use:
Ruby's built-in OpenURI, and Nokogiri, to read a page, parse it, search for certain tags, extract a parameter such as a "src" or "href".
OpenURI to read the URL, or curl or wget at the command-line to retrieve the file.
Nokogiri's tutorials including showing how to use OpenURI to retrieve the page and hand it off to Nokogiri.
OpenURI's docs show how to "open" URLs and retrieve their content using read. Once you've done that, the data will be easy to save to disk using something like this for text files:
File.write('some_file', open('http://www.example.com/').read)
or for binary:
File.open('some_file', 'wb') { |fo| fo.write(open('http://www.example.com/').read) }
There are examples of using both Nokogiri and OpenURI for this all over Stack Overflow.

Ruby on Rails passing a salt to Digest::SHA512

what is the equivalent in Rails of this (PHP):
hash_hmac('sha512', $password . $salt, $siteSalt);
I got as far as this:
Digest::SHA512.hexdigest(password + salt)
But have no idea how to incorporate the site salt into the equation, all online examples I've seen do not pass the salt to the hexdigest method. When I've tried it I get an error for too many arguments.
And this notation with a colon (which I saw somewhere):
salted = password + salt
Digest::SHA512.hexdigest("#{salted}:site_salt")
Doesn't produce the same hash.
Thanks
Edit
I stumbled upon this that looks closer to what I need (sorry, I'm very new to the whole hashing thing):
OpenSSL::HMAC.hexdigest('sha512', site_salt, salted)
But it still produces a different hash than the one stored in the database.
I'm using Rails 4 and #brian's rails code didn't compile for me.
Here is what worked for me.
Rails shell:
2.1.2 :001 > Digest::HMAC.hexdigest("password"+"salt","siteSalt",Digest::SHA512)
=> "15b45385a00b10eb25c3aa8198d747862575a796a89a6c79b5a0b8ea332a8d75b1ec0dc1f0c9f7930d30c9359279e86df29067bbbc5d9bcf87839f855ac7a677"
PHP (from command line)
$ php -r 'print hash_hmac("sha512", "password" . "salt", "siteSalt") . "\n";'
15b45385a00b10eb25c3aa8198d747862575a796a89a6c79b5a0b8ea332a8d75b1ec0dc1f0c9f7930d30c9359279e86df29067bbbc5d9bcf87839f855ac7a677
I think this will do what you want:
HMAC::SHA512.hexdigest(site_salt, password + salt)
It looks like the PHP code you're referencing is using the siteSalt as the key for the HMAC function, with the password and salt concatenated specified as the value to be hashed.
I checked this by running this code in PHP:
% php -r 'print hash_hmac("sha512", "password" . "salt", "siteSalt") . "\n";'
15b45385a00b10eb25c3aa8198d747862575a796a89a6c79b5a0b8ea332a8d75b1ec0dc1f0c9f7930d30c9359279e86df29067bbbc5d9bcf87839f855ac7a677
And then in the Rails shell:
>> HMAC::SHA512.hexdigest('siteSalt', 'password' + 'salt')
=> "15b45385a00b10eb25c3aa8198d747862575a796a89a6c79b5a0b8ea332a8d75b1ec0dc1f0c9f7930d30c9359279e86df29067bbbc5d9bcf87839f855ac7a677"
It turns out the salt was empty in the PHP code, hence the discrepancy. But now both methods return the same.

Find latest available RVM version number

I can't seem to find an easy way to identify the latest release of RVM from command line or rvm.beginrescueend.com!?!
I currently type rvm get latest every few days or so to update RVM. If version is same, RVM goes through the download & update process regardless. I'd like to be able to first 'see' if there's an update to get.
Anyone know how? I'm sure I'm missing the obvious...
you could use this one liner to check version:
$ curl -sS https://api.github.com/repos/wayneeseguin/rvm/git/refs/tags | awk -F": |\"" '$2=="ref"{sub(/.*\//,"",$5); print $5}' | sort -V | tail -n 1
1.15.8
or a pure ruby one liner:
$ ruby -ropen-uri -rjson -e 'open("https://api.github.com/repos/wayneeseguin/rvm/git/refs/tags"){|r| puts JSON.parse(r.read).map{|l| l["ref"].gsub(/.*\//,"").split(".").map(&:to_i)}.sort.last.join(".") }'
1.15.8
but the simplest thing to do is:
$ curl https://raw.github.com/wayneeseguin/rvm/stable/VERSION
1.15.8
Curl the rvm repository like this:
curl https://raw.githubusercontent.com/rvm/rvm/master/VERSION
Ok, magic :)
Place this into some .rb file :)
require 'open-uri'
require 'openssl'
regex = Regexp.new(/data-name="([0-9]+).([0-9]+).([0-9]+)"/)
f=open("https://github.com/wayneeseguin/rvm",:ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE)
v = []
f.each_line do |l|
regex.match(l) {|m| v << {:full => m[0], :major => m[1].to_i, :minor => m[2].to_i, :inc => m[3].to_i} }
end
v.sort_by{|m| [m[:major],m[:minor],m[:inc]] }
v=v.first
puts "#{v[:major]}.#{v[:minor]}.#{v[:inc]}"
I have no idea why I just did that.
I used:
$ rvm get head && rvm reload
It ran fast and seemed to do the job. I had installed rvm the week before, rvm 1.15.5, and already there was a newer version, rvm 1.15.8.
This was recommended on:
The Ruby on Rails Tutorial by Michael Hartl
http://ruby.railstutorial.org/ruby-on-rails-tutorial-book#sec-install_ruby

Using ruby to generate SHA512 crypt-style hashes formatted for /etc/shadow?

I want to generate SHA512 hashed passwords for inclusion directly into a /etc/shadow file for use with chef's user resource. Normally I'd go to the stdlib's Digest library for this, but it doesn't generate the hash in the right format:
ruby-1.9.2-p136 :001 > require 'digest/sha2'
=> true
ruby-1.9.2-p136 :002 > Digest::SHA512.hexdigest('test')
=> "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"
The format that the shadow file wants is:
$6$/ShPQNXV$HJnibH9lw01qtYqyJQiBf81ggJB2BGUvKA7.kv39HGCeE.gD4C/SS9zAf5BrwOv3VJzvl99FpHYli9E8jykRC0
Things I've looked at:
The openssl "dgst" module returns the same format as .hexdigest, and its "passwd" module doesn't include SHA512 support.
String#crypt, but that does not support SHA512. (edit: this is only the case on OSX - modern Linux distros will work if you specify "$6$somesalt" as the salt)
ruby-crypt gem, but it does not support SHA512
For comparison, something that does return the proper format is PHP's crypt, but I'd rather not have to exec out to PHP for something that should be simple.
After further research:
The mkpasswd command, which on debian is in the whois package (weird):
mkpasswd -m sha-512
String#crypt does actually call the platform's native crypt() call, however OSX (up to 10.6) does not include support for alternate ciphers. "password".crypt('$6$somesalt') will work on Linux platforms.

Equivalent of cURL for Ruby?

Is there a cURL library for Ruby?
Curb and Curl::Multi provide cURL bindings for Ruby.
If you like it less low-level, there is also Typhoeus, which is built on top of Curl::Multi.
Use OpenURI and
open("http://...", :http_basic_authentication=>[user, password])
accessing sites/pages/resources that require HTTP authentication.
Curb-fu is a wrapper around Curb which in turn uses libcurl. What does Curb-fu offer over Curb? Just a lot of syntactic sugar - but that can be often what you need.
HTTP clients is a good page to help you make decisions about the various clients.
You might also have a look at Rest-Client
If you know how to write your request as a curl command, there is an online tool that can turn it into ruby (2.0+) code: curl-to-ruby
Currently, it knows the following options: -d/--data, -H/--header, -I/--head, -u/--user, --url, and -X/--request. It is open to contributions.
the eat gem is a "replacement" for OpenURI, so you need to install the gem eat in the first place
$ gem install eat
Now you can use it
require 'eat'
eat('http://yahoo.com') #=> String
eat('/home/seamus/foo.txt') #=> String
eat('file:///home/seamus/foo.txt') #=> String
It uses HTTPClient under the hood. It also has some options:
eat('http://yahoo.com', :timeout => 10) # timeout after 10 seconds
eat('http://yahoo.com', :limit => 1024) # only read the first 1024 chars
eat('https://yahoo.com', :openssl_verify_mode => 'none') # don't bother verifying SSL certificate
Here's a little program I wrote to get some files with.
base = "http://media.pragprog.com/titles/ruby3/code/samples/tutthreads_"
for i in 1..50
url = "#{ base }#{ i }.rb"
file = "tutthreads_#{i}.rb"
File.open(file, 'w') do |f|
system "curl -o #{f.path} #{url}"
end
end
I know it could be a little more eloquent but it serves it purpose. Check it out. I just cobbled it together today because I got tired of going to each URL to get the code for the book that was not included in the source download.
There's also Mechanize, which is a very high-level web scraping client that uses Nokogiri for HTML parsing.
Adding a more recent answer, HTTPClient is another Ruby library that uses libcurl, supports parallel threads and lots of the curl goodies. I use HTTPClient and Typhoeus for any non-trivial apps.
To state the maybe-too-obvious, tick marks execute shell code in Ruby as well. Provided your Ruby code is running in a shell that has curl:
puts `curl http://www.google.com?q=hello`
or
result = `
curl -X POST https://www.myurl.com/users \
-d "name=pat" \
-d "age=21"
`
puts result
A nice minimal reproducible example to copy/paste into your rails console:
require 'open-uri'
require 'nokogiri'
url = "https://www.example.com"
html_file = URI.open(url)
doc = Nokogiri::HTML(html_file)
doc.css("h1").text
# => "Example Domain"

Resources