<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Note to Self &#187; Ruby</title>
	<atom:link href="http://notetoself.vrensk.com/tag/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://notetoself.vrensk.com</link>
	<description>lest I forget</description>
	<lastBuildDate>Fri, 23 Feb 2018 12:54:38 +0000</lastBuildDate>
	<language>sv-SE</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Verified HTTPS in Ruby</title>
		<link>http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/</link>
		<comments>http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/#comments</comments>
		<pubDate>Sun, 07 Sep 2008 22:06:32 +0000</pubDate>
		<dc:creator>David Vrensk</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Certificate Authorities]]></category>
		<category><![CDATA[HTTPS]]></category>
		<category><![CDATA[peer validation]]></category>
		<category><![CDATA[SSL]]></category>

		<guid isPermaLink="false">http://notetoself.vrensk.com/?p=28</guid>
		<description><![CDATA[I need to pick up an XML file from a server every 30 minutes and process it. I’ve done similar things before, and using Hpricot it is a pleasure: #! /usr/bin/env ruby require 'rubygems' require 'hpricot' require 'open-uri' doc = Hpricot(open("http://example.com/the_file.xml")) (doc / :person).each { &#124;person&#124; ... } Couldn’t be simpler. This time, there is [...]]]></description>
				<content:encoded><![CDATA[<p>I need to pick up an XML file from a server every 30 minutes and process it.  I’ve done similar things before, and using <a href="http://code.whytheluckystiff.net/hpricot/" onclick="pageTracker._trackPageview('/outgoing/code.whytheluckystiff.net/hpricot/?referer=');">Hpricot</a> it is a pleasure:</p>
<pre><code>#! /usr/bin/env ruby
require 'rubygems'
require 'hpricot'
require 'open-uri'

doc = Hpricot(open("http://example.com/the_file.xml"))
(doc / :person).each { |person| ... }
</code></pre>
<p>Couldn’t be simpler.  This time, there is a snag: the file is sensitive, so the connection is encrypted using HTTPS.  For this article, let’s say we’re talking about <a href="http://www.cert.org/" onclick="pageTracker._trackPageview('/outgoing/www.cert.org/?referer=');">Cert’s</a> list of new vulnerabilities, which can be found at <a href="https://www.cert.org/blogs/vuls/rss.xml" onclick="pageTracker._trackPageview('/outgoing/www.cert.org/blogs/vuls/rss.xml?referer=');">https://www.cert.org/blogs/vuls/rss.xml</a>.  <code>open-uri</code> supports HTTPS, so it shouldn’t be a problem, but it is:</p>
<pre><code>doc = Hpricot(open("https://www.cert.org/blogs/vuls/rss.xml"))
# =&gt;
/usr/lib/ruby/1.8/net/http.rb:590:in `connect': certificate verify failed (OpenSSL::SSL::SSLError)
</code></pre>
<p><code>OpenSSL</code>, which <code>open-uri</code> uses behind the scenes, fails to verify Cert’s certificate and halts execution.</p>
<h2>Solution 1: skip verification</h2>
<p>Let’s assume that I don’t care much about the verification; all I want is the data, and it just so happens that it is only available through HTTPS.  <code>open-uri</code> doesn’t let me turn off verification so I have to dig deeper.</p>
<p><code>open-uri</code> is just a clever wrapper around Ruby’s comprehensive, but insufficiently documented, networking library that handles a variety of protocols, including HTTPS.  To fetch a web page over a secure connection, you can use something like this sample client (from <code>net/https.rb</code>):</p>
<pre><code>#! /usr/bin/env ruby
require 'net/https'
require 'uri'

uri = URI.parse(ARGV[0] || 'https://localhost/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == "https"  # enable SSL/TLS
http.start {
  http.request_get(uri.path) {|res|
    print res.body
  }
}
</code></pre>
<p>There are three things to note in the sample client:</p>
<ol>
<li>You should <code>require</code> <code>net/https</code>, not <code>net/http</code>.</li>
<li>You create the client with <code>Net::HTTP.new</code>, not <code>Net::HTTPS.new</code>. (There is no <code>HTTPS</code> class despite the fact that you <code>require 'net/https'</code>.)</li>
<li>You need to set <code>use_ssl = true</code> explicitly.  The <code>URI</code> library is clever enough to set its port attribute to 443 when it parses a URI that starts with <code>https</code>, but <code>Net::HTTP</code> isn’t quite as clever.</li>
</ol>
<p>If you put the above code in <code>webclient.rb</code> and run it, you’ll see this:</p>
<pre><code>$ ruby webclient.rb https://www.cert.org/blogs/vuls/rss.xml
warning: peer certificate won't be verified in this SSL session
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;rss version="2.0"&gt;
    &lt;channel&gt;
        &lt;title&gt;Vulnerability Analysis Blog&lt;/title&gt;
[...]
</code></pre>
<p>Yes, it will fetch and print the RSS XML, but it will also warn you that it doesn’t verify the host’s certificate.  Let’s turn off the warning by telling <code>Net::HTTP</code> that we don’t expect it to perform any verification:</p>
<pre><code>uri = URI.parse(ARGV[0] || 'https://localhost/')
http = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == "https"  # enable SSL/TLS
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
http.start { ... }
</code></pre>
<p>Run this, and you get the same result without the warning.</p>
<h2>Solution 2: add verification</h2>
<p>Solution 1 is not enough for my current needs.  I want encryption, but I also want to know that I’m talking to the right server.  To turn on verification, I change <code>VERIFY_NONE</code> to <code>VERIFY_PEER</code> and run again.  Now I’m back on square one with <code>OpenSSL::SSL::SSLError: certificate verify failed</code>.  Uh-huh.  So what’s wrong with that one?  It works in my browser without problems.</p>
<p>I’m not going to go into how HTTPS and certificate validation works.  Suffice it so say that my browser is more trusting than <code>OpenSSL</code>.  And it’s not blind trust either; the browser knows more Certificate Authorities.  So how do I add them to Ruby and <code>OpenSSL</code>?  I looked around and found a solution to a similar problem, <a href="http://blog.seagul.co.uk/articles/2006-10-24-connecting-to-gmail-with-ruby-or-connecting-to-pop3-servers-over-ssl-with-ruby" onclick="pageTracker._trackPageview('/outgoing/blog.seagul.co.uk/articles/2006-10-24-connecting-to-gmail-with-ruby-or-connecting-to-pop3-servers-over-ssl-with-ruby?referer=');">Connecting to POP3 servers over SSL with Ruby</a>.  Adapting that to my HTTPS problem, it becomes a two-step solution:</p>
<ol>
<li>Download the <a href="http://curl.haxx.se/ca/cacert.pem" onclick="pageTracker._trackPageview('/outgoing/curl.haxx.se/ca/cacert.pem?referer=');">CA Root Certificates bundle</a> from haxx.se, the creators of <code>curl</code>.  Store the file in the same directory as <code>webclient.rb</code> and make sure that it’s called <code>cacert.pem</code>.  (But please see the discussion below on <em>Too much trust</em>.)</li>
<li>Make <code>webclient.rb</code> use this file instead of whatever is bundled with <code>OpenSSL</code>.</li>
</ol>
<p>Now we can tell <code>Net::HTTP</code> to use this CA file:</p>
<pre><code>uri = URI.parse(ARGV[0] || 'https://localhost/')
http = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == "https"  # enable SSL/TLS
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.ca_file = File.join(File.dirname(__FILE__), "cacert.pem")
end
http.start { ... }
</code></pre>
<p>Look, it works!  It gives the expected output, and it is verifying… something.  But what?  Time to look under the hood again.  It turns out that with these settings, <code>OpenSSL</code> checks that the server certificate is signed by a known CA and has not expired, which is good, but not everything I’m looking for.  I also want it to check that the certificate belongs to the server that I’m talking to.  To see an example, go to <a href="https://google.com/" onclick="pageTracker._trackPageview('/outgoing/google.com/?referer=');">https://google.com/</a>.  In Firefox 3, you should get an iconic policeman telling you it’s a Page Load Error.  The certificate belongs to <code>www.google.com</code>, not <code>google.com</code>.  But our script is not quite as discerning:</p>
<pre><code>$ ruby webclient.rb https://google.com/
hostname was not match with the server certificate
&lt;HTML&gt;&lt;HEAD&gt;&lt;meta http-equiv="content-type" content="text/html;charset=utf-8"&gt;
&lt;TITLE&gt;302 Moved&lt;/TITLE&gt;&lt;/HEAD&gt;&lt;BODY&gt;
&lt;H1&gt;302 Moved&lt;/H1&gt;
The document has moved
&lt;A HREF="http://www.google.com"&gt;here&lt;/A&gt;.
&lt;/BODY&gt;&lt;/HTML&gt;
</code></pre>
<p>Note the warning on the first line of output.  Apparently <code>Net::HTTP</code> checks to see if the certificate belongs to the host, but it’s not a fatal error.  To change this, we need to enable the “post-connection check”.  So here is the final version of the script:</p>
<pre><code>#! /usr/bin/env ruby
require 'net/https'
require 'uri'

uri = URI.parse(ARGV[0] || 'https://localhost/')
http = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == "https"  # enable SSL/TLS
  http.use_ssl = true
  http.enable_post_connection_check = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.ca_file = File.join(File.dirname(__FILE__), "cacert.pem")
end
http.start {
  http.request_get(uri.path) {|res|
    print res.body
  }
}
</code></pre>
<p>Now it will fail for <code>https://google.com/</code> but succeed for <code>https://www.google.com/</code>.  Done!</p>
<h2>Too much trust</h2>
<p>OK, I should admit that downloading a file from someplace called <code>haxx.se</code> doesn’t seem like the best way to raise security.  If you really want to know who you will be trusting, you should download Root Certificates from each of the CA’s that you trust.  That’s way too much work for the application I’m working on right now, but it might be a requirement for you.  If you don’t want to go mad, though, try doing it the same way the haxx people did.  They wrote a little tool to extract the Root Certificates from the source files of Mozilla, and they even have a tool for extracting it from your binary installation.  Check out <a href="http://curl.haxx.se/docs/caextract.html" onclick="pageTracker._trackPageview('/outgoing/curl.haxx.se/docs/caextract.html?referer=');">their documentation</a> for a full description and links to the tools (source code).</p>
<p><strong>[Update: </strong>John in comment 16 has written up an instruction on how to get the certificates file using https.  Turtles all the way down.]</p>
]]></content:encoded>
			<wfw:commentRss>http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Escaping single quotes in Ruby harder than expected</title>
		<link>http://notetoself.vrensk.com/2008/08/escaping-single-quotes-in-ruby-harder-than-expected/</link>
		<comments>http://notetoself.vrensk.com/2008/08/escaping-single-quotes-in-ruby-harder-than-expected/#comments</comments>
		<pubDate>Wed, 06 Aug 2008 14:23:22 +0000</pubDate>
		<dc:creator>David Vrensk</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[gotcha]]></category>
		<category><![CDATA[regexp]]></category>
		<category><![CDATA[SQL escape]]></category>

		<guid isPermaLink="false">http://notetoself.vrensk.com/?p=15</guid>
		<description><![CDATA[So I was writing this tool to create a bunch of SQL statements from a data dump. Simple enough, right. And as always when you generate SQL statements, you have to make sure that the data doesn’t interfere with the SQL syntax by escaping the single quotes (and generally any binary data, but I didn’t [...]]]></description>
				<content:encoded><![CDATA[<p>So I was writing this tool to create a bunch of SQL statements from a data dump.  Simple enough, right.  And as always when you generate SQL statements, you have to make sure that the data doesn’t interfere with the SQL syntax by escaping the single quotes (and generally any binary data, but I didn’t have that).  Any database gem/module/library has that built-in, of course, but I didn’t want to use that.  So I said <strong>[Note: this doesn't work. Read on for the solution.]</strong></p>
<pre><code>def quote (str)
  str.gsub('\\','\\\\').gsub('\'','\\\'')
end
</code></pre>
<p>I read this as “replace all backslashes with double backslashes, and then replace all single quotes with a backslash and a single quote”.  I added a simple test for it (yay TestUnit!):</p>
<pre><code>def setup
  @m = Migrate.new
end

def test_quote
  assert_equal("I\\'m home", @m.quote("I'm home"))
end

</code></pre>
<p>But imagine my surprise when I got</p>
<pre><code>  1) Failure:
test_quote(TestMigrate) [migration/test_migrate.rb:29]:
&lt; "I\\'m home"&gt; expected but was
&lt; "Im homem home"&gt;.
</code></pre>
<p>Ooookay.  What’s wrong here?  Have I misunderstood the rules for escaping the escape sequence?  It’s supposed to be easier with single quotes, but maybe I got it wrong.  So I tried with double quotes:</p>
<pre><code>def quote (str)
  str.gsub("\\","\\\\").gsub("'","\\'")
end
</code></pre>
<p>Surely this would work?  Nope, it gives the exact same error.  Time to look up <code>gsub</code> in the <a href="http://www.ruby-doc.org/core/classes/String.html#M000749" onclick="pageTracker._trackPageview('/outgoing/www.ruby-doc.org/core/classes/String.html_M000749?referer=');">manual</a>:</p>
<blockquote><p><strong>str.gsub(pattern, replacement) =&gt; new_str<br />
str.gsub(pattern) {|match| block } =&gt; new_str</strong></p>
<p>[…] If a string is used as the replacement, special variables from the match (such as $&amp; and $1) cannot be substituted into it, as substitution into the string occurs before the pattern match starts. However, the sequences \1, \2, <strong>and so on</strong> [my emphasis] may be used to interpolate successive groups in the match.</p></blockquote>
<p>“And so on”?  Oh, so obviously <code>\'</code> (escaped <code>\\'</code> in the string literal) is the replacement string equivalent of <code>$'</code>, which means everything afther the match (as all regexp hackers know).  So I need to escape the backslash for regexp engine too:</p>
<pre><code>def quote (str)
  str.gsub("\\","\\\\").gsub("'","\\\\'")
end
</code></pre>
<p>OK, the tests pass.  But the code looks wrong.  Four backslashes can’t work for both cases, can they?  Let’s add a test case:</p>
<pre><code>def test_quote
  assert_equal("I\\'m home", @m.quote("I'm home"))
  assert_equal("S\\\\N", @m.quote("S\\N"))
end

</code></pre>
<p>Nope, that fails.  So we need this:</p>
<pre><code>def quote (str)
  str.gsub("\\","\\\\\\\\").gsub("'","\\\\'")
end
</code></pre>
<p>Eight backslashes.  Yes, the test passes, but is it worth it?  Is it understandable?  I don’t want comments to explain my code.  Comments are good to provide a raison d’être for something, but not to explain its looks.  Let’s switch to the other form of gsub:</p>
<pre><code>def quote (str)
  str.gsub(/\\|'/) { |c| "\\#{c}" }
end
</code></pre>
<p>“If you see a backslash or a single quote, replace it with a backslash and whatever you saw.”  That’s what I wanted to say anyway.</p>
<p>Good.  But I wrote this in <a href="http://daringfireball.net/projects/markdown/syntax" onclick="pageTracker._trackPageview('/outgoing/daringfireball.net/projects/markdown/syntax?referer=');">Markdown</a>, so now I have to generate the HTML and the go through it and make sure that I restore whatever backslashes Markdown ate. (It turns out it didn&#8217;t eat any.  TextMate has a Markdown Preview function that ate a lot of backslashes, but when I said &#8220;Convert to HTML&#8221; it didn&#8217;t eat any at all.  Go figure.)</p>
]]></content:encoded>
			<wfw:commentRss>http://notetoself.vrensk.com/2008/08/escaping-single-quotes-in-ruby-harder-than-expected/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Mysql gem on OS X Leopard</title>
		<link>http://notetoself.vrensk.com/2008/07/mysql-gem-on-os-x-leopard/</link>
		<comments>http://notetoself.vrensk.com/2008/07/mysql-gem-on-os-x-leopard/#comments</comments>
		<pubDate>Sun, 27 Jul 2008 14:03:54 +0000</pubDate>
		<dc:creator>David Vrensk</dc:creator>
				<category><![CDATA[Developer Client]]></category>
		<category><![CDATA[gem]]></category>
		<category><![CDATA[Leopard]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[works for me]]></category>

		<guid isPermaLink="false">http://notetoself.vrensk.com/?p=9</guid>
		<description><![CDATA[Installing the mysql gem for Ruby is almost always a mess, as witnessed by the large number of hits one get when googling for &#8220;mysql gem leopard&#8221;.  To make the gem work with your platform, you need to ensure that the &#8216;make&#8217; command run internally by &#8216;gem&#8217; has the right ARCHFLAGS, which most of the [...]]]></description>
				<content:encoded><![CDATA[<p>Installing the mysql gem for Ruby is almost always a mess, as witnessed by the <a href="http://www.notsostupid.com/blog/2007/10/25/ruby-leopard-and-gems/" onclick="pageTracker._trackPageview('/outgoing/www.notsostupid.com/blog/2007/10/25/ruby-leopard-and-gems/?referer=');">large</a> <a href="http://www.schmidp.com/2007/9/29/rails-mysql-and-leopard" onclick="pageTracker._trackPageview('/outgoing/www.schmidp.com/2007/9/29/rails-mysql-and-leopard?referer=');">number</a> <a href="http://www.rubyhead.com/2007/10/29/mysql-gem-in-leopard/" onclick="pageTracker._trackPageview('/outgoing/www.rubyhead.com/2007/10/29/mysql-gem-in-leopard/?referer=');">of</a> <a href="http://weblog.rubyonrails.org/2007/10/26/today-is-leopard-day" onclick="pageTracker._trackPageview('/outgoing/weblog.rubyonrails.org/2007/10/26/today-is-leopard-day?referer=');">hits</a> one get when googling for &#8220;mysql gem leopard&#8221;.  To make the gem work with your platform, you need to ensure that the &#8216;make&#8217; command run internally by &#8216;gem&#8217; has the right ARCHFLAGS, which most of the web pages will tell you about.  So</p>
<pre>sudo env ARCHFLAGS='-arch i386' gem install mysql</pre>
<p>should handle it, more or less.  But since Leopard (the client version) does not have mysql, you will have had to install that on your own (I installed the MySQL binary package for 10.4, from <a href="http://dev.mysql.com/downloads/mysql/5.0.html#macosx-dmg" onclick="pageTracker._trackPageview('/outgoing/dev.mysql.com/downloads/mysql/5.0.html_macosx-dmg?referer=');">dev.mysql.com</a>, because there was no 10.5 package available the day after I Leopard was released), and &#8216;gem&#8217; isn&#8217;t good at guessing where it is.  So I need to say</p>
<pre>sudo env ARCHFLAGS='-arch i386' gem install mysql -- --with-mysql-dir=/usr/local/mysql</pre>
<p>But for some reason that is not quite enough either.  I get this error:</p>
<pre>/Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle:
dlopen(/Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle, 9):
Library not loaded: /usr/local/mysql/lib/mysql/libmysqlclient.15.dylib (LoadError)

  Referenced from: /Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle

  Reason: image not found - /Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle
      from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:32:in `require'
      from my_script.rb:6</pre>
<p>Hey, look at that.  It actually tries to load the lib from `/usr/local/mysql/lib/mysql` rather than `/usr/local/mysql/lib`.  Why?  I don&#8217;t know.  I couldn&#8217;t be bothered to dive into the code, so I went for the quick workaround:</p>
<pre>sudo ln -s . /usr/local/mysql/lib/mysql</pre>
<p>Silly, and perhaps not the cleanest way to do it, but it works for me.</p>
]]></content:encoded>
			<wfw:commentRss>http://notetoself.vrensk.com/2008/07/mysql-gem-on-os-x-leopard/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
