<?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>George MacKerron: code blog &#187; Ruby</title>
	<atom:link href="http://blog.mackerron.com/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.mackerron.com</link>
	<description>GIS, software development, and other snippets</description>
	<lastBuildDate>Fri, 03 Feb 2012 18:35:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>MySQL gem for Ruby 1.9.1/1.9.2 on Snow Leopard (Mac OS X 10.6)</title>
		<link>http://blog.mackerron.com/2011/08/04/mysql-gem-snow-leopard/</link>
		<comments>http://blog.mackerron.com/2011/08/04/mysql-gem-snow-leopard/#comments</comments>
		<pubDate>Thu, 04 Aug 2011 14:47:11 +0000</pubDate>
		<dc:creator>George</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[System admin]]></category>

		<guid isPermaLink="false">http://blog.mackerron.com/?p=844</guid>
		<description><![CDATA[The secret to getting the MySQL gem to install and function with Ruby 1.9.1/1.9.2 on Snow Leopard is: Install MySQL using the 64-bit .DMG package installer from dev.mysql.com Install Ruby using RVM (that&#8217;s Ruby 1.9.2 or 1.9.1-p378 &#8212; at the time of writing the latest 1.9.1, p429, is buggy) Add these to lines to ~/.bash_login [...]]]></description>
			<content:encoded><![CDATA[<p><strong>The secret to getting the MySQL gem to install and function with Ruby 1.9.1/1.9.2 on Snow Leopard is:</strong></p>


<ul>
<li>Install MySQL using the 64-bit .DMG package installer from <a href="http://dev.mysql.com/downloads/mysql/">dev.mysql.com</a></li>
<li>Install Ruby using <a href="http://redmine.ruby-lang.org/issues/show/2404"><span class="caps">RVM</span></a> (that&#8217;s Ruby 1.9.2 or 1.9.1-p378 &#8212; at the time of writing the latest 1.9.1, p429, is <a href="http://redmine.ruby-lang.org/issues/show/2404">buggy</a>)</li>
<li>Add these to lines to <code>~/.bash_login</code> or <code>~/.bashrc</code>:</li>
</ul>




<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">PATH</span>=<span style="color: #ff0000;">&quot;/usr/local/mysql/bin:<span style="color: #007800;">$PATH</span>&quot;</span>
<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">DYLD_LIBRARY_PATH</span>=<span style="color: #ff0000;">&quot;/usr/local/mysql/lib:<span style="color: #007800;">$DYLD_LIBRARY_PATH</span>&quot;</span></pre></div></div>





<ul>
<li>In a new shell (Terminal window), type <code>gem install mysql</code> as normal.</li>
</ul>



<p>I&#8217;m posting this mainly as a record for myself, having wasted a lot of time in the past trying strange incantations from comments on various other blogs posts.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.mackerron.com/2011/08/04/mysql-gem-snow-leopard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blocking the weakest passwords</title>
		<link>http://blog.mackerron.com/2010/12/14/death-to-weak-passwords/</link>
		<comments>http://blog.mackerron.com/2010/12/14/death-to-weak-passwords/#comments</comments>
		<pubDate>Tue, 14 Dec 2010 12:24:04 +0000</pubDate>
		<dc:creator>George</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[System admin]]></category>
		<category><![CDATA[Web design]]></category>

		<guid isPermaLink="false">http://blog.mackerron.com/?p=429</guid>
		<description><![CDATA[The recent Gawker passwords leak once again highlights the widespread use of passwords that offer essentially no security. Some years ago, when working on a secure web app for a large organisation &#8212; let&#8217;s call them Secret Testing Ltd &#8212; I was keen that people shouldn&#8217;t choose hopelessly weak passwords. I was particularly concerned by [...]]]></description>
			<content:encoded><![CDATA[<p>The recent <a href="http://gawker.com/5712615/commenting-accounts-compromised-++-change-your-passwords">Gawker passwords leak</a> once again highlights the widespread use of passwords that offer essentially no security.</p>

<p>Some years ago, when working on a secure web app for a large organisation &#8212; let&#8217;s call them Secret Testing Ltd &#8212; I was keen that people shouldn&#8217;t choose hopelessly weak passwords. I was particularly concerned by my sysadmin colleague&#8217;s fondness for passwords of the form &#8216;p/\55w0rd&#8217; or &#8216;S3cr3t-T35t|ng&#8217;.</p>

<p><span id="more-429"></span></p>

<p>I therefore wrote some simple Ruby code to try to catch very weak passwords:</p>


<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> PasswordUtils
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">look_and_sound_alikes</span><span style="color:#006600; font-weight:bold;">&#40;</span>original<span style="color:#006600; font-weight:bold;">&#41;</span>
    look_or_sound_alikes = <span style="color:#006600; font-weight:bold;">&#123;</span> \
      <span style="color:#996600;">'0'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'o'</span><span style="color:#006600; font-weight:bold;">&#93;</span> ,
      <span style="color:#996600;">'1'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'i'</span>, <span style="color:#996600;">'l'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'2'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'to'</span>, <span style="color:#996600;">'too'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'3'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'e'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'4'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'a'</span>, <span style="color:#996600;">'for'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'5'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'s'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'6'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'g'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'8'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'b'</span>, <span style="color:#996600;">'ate'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'9'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'g'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'i'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'i'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'$'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'s'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'|'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'i'</span>, <span style="color:#996600;">'l'</span>, <span style="color:#996600;">''</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'!'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'i'</span>, <span style="color:#996600;">'l'</span>, <span style="color:#996600;">''</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'@'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'g'</span>, <span style="color:#996600;">'a'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'('</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'c'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'['</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'c'</span>, <span style="color:#996600;">'e'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'{'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'e'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'&amp;'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'and'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'*'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'star'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">')'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'d'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'^'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'a'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'/'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'a'</span>, <span style="color:#996600;">'v'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'<span style="color:#000099;">\\</span>'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">''</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
      <span style="color:#996600;">'&lt;'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'k'</span><span style="color:#006600; font-weight:bold;">&#93;</span>
    <span style="color:#006600; font-weight:bold;">&#125;</span> 
    <span style="color:#008000; font-style:italic;"># the penultimate two substitutions catch /\ (A) and \/ (V), albeit without</span>
    <span style="color:#008000; font-style:italic;"># distinguishing them, and the last (in conjunction with the empty options </span>
    <span style="color:#008000; font-style:italic;"># for ! and |) catches !&lt; and |&lt; (K)</span>
    versions = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">''</span><span style="color:#006600; font-weight:bold;">&#93;</span>
    original.<span style="color:#9900CC;">downcase</span>.<span style="color:#9900CC;">each_char</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>c<span style="color:#006600; font-weight:bold;">|</span>
      versions.<span style="color:#9900CC;">collect</span>! <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>v<span style="color:#006600; font-weight:bold;">|</span>
        alikes = look_or_sound_alikes<span style="color:#006600; font-weight:bold;">&#91;</span>c<span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span> <span style="color:#006600; font-weight:bold;">&#91;</span>c<span style="color:#006600; font-weight:bold;">&#93;</span>
        alikes.<span style="color:#9900CC;">collect</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>c1<span style="color:#006600; font-weight:bold;">|</span> v <span style="color:#006600; font-weight:bold;">+</span> c1 <span style="color:#006600; font-weight:bold;">&#125;</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
      versions.<span style="color:#9900CC;">flatten</span>!
    <span style="color:#9966CC; font-weight:bold;">end</span>
    versions
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">obvious</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>password, custom_banned_list = <span style="color:#996600;">''</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    standard_banned_list = <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">read</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;#{RAILS_ROOT}/config/banned_password_words.txt&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    banned_words = standard_banned_list.<span style="color:#9900CC;">downcase</span>.<span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">/</span>\W<span style="color:#006600; font-weight:bold;">+/</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">+</span> 
      custom_banned_list.<span style="color:#9900CC;">downcase</span>.<span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">/</span>\W<span style="color:#006600; font-weight:bold;">+/</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">delete_if</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>w<span style="color:#006600; font-weight:bold;">|</span> w.<span style="color:#9900CC;">length</span> <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006666;">4</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
    alike_words = <span style="color:#006600; font-weight:bold;">&#91;</span>password.<span style="color:#9900CC;">downcase</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">+</span> PasswordUtils.<span style="color:#9900CC;">look_and_sound_alikes</span><span style="color:#006600; font-weight:bold;">&#40;</span>password<span style="color:#006600; font-weight:bold;">&#41;</span>
    banned_words.<span style="color:#9900CC;">any</span>? <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>banned_word<span style="color:#006600; font-weight:bold;">|</span>
      alike_words.<span style="color:#9900CC;">any</span>? <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>alike_word<span style="color:#006600; font-weight:bold;">|</span> alike_word.<span style="color:#9966CC; font-weight:bold;">include</span>? banned_word <span style="color:#006600; font-weight:bold;">&#125;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>




<p>The first method of the class undoes some common substitutions:</p>


<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#006600; font-weight:bold;">&gt;</span> PasswordUtils.<span style="color:#9900CC;">look_and_sound_alikes</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'p/<span style="color:#000099;">\5</span>5w0rd'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;password&quot;</span>, <span style="color:#996600;">&quot;pvssword&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
<span style="color:#006600; font-weight:bold;">&gt;</span>  PasswordUtils.<span style="color:#9900CC;">look_and_sound_alikes</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'S3cr3t-T35t|ng'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;secret-testing&quot;</span>, <span style="color:#996600;">&quot;secret-testlng&quot;</span>, <span style="color:#996600;">&quot;secret-testng&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span></pre></div></div>




<p>And the second method uses this in conjunction with a list of banned words to check that an entered password isn&#8217;t hopelessly weak.</p>


<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#006600; font-weight:bold;">&gt;</span> PasswordUtils.<span style="color:#9900CC;">obvious</span>?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'p/<span style="color:#000099;">\5</span>5w0rd'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
<span style="color:#006600; font-weight:bold;">&gt;</span>  PasswordUtils.<span style="color:#9900CC;">obvious</span>?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'S3cr3t-T35t|ng'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
<span style="color:#006600; font-weight:bold;">&gt;</span> PasswordUtils.<span style="color:#9900CC;">obvious</span>?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'gkAsd76!o'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span></pre></div></div>




<p>Obviously, you need a good banned words list &#8212; perhaps starting with some <a href="http://www.buzzfeed.com/gavon/top-25-gawker-passwords">top N passwords lists</a>, and including the name of your company, the web app, and words related to the area of business, local pubs, and so on.</p>

<p>It&#8217;s also a good idea to include custom banned words for individual users. For example:</p>


<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">custom_banned_list = <span style="color:#996600;">&quot;#{first_names} #{surname} #{department} #{organisation} #{email}&quot;</span>
PasswordUtils.<span style="color:#9900CC;">password_obvious</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>password, custom_banned_list<span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>




<p>Passing these tests isn&#8217;t a sufficient condition for ruling out a weak password, but it&#8217;s arguably a necessary one, and a good start.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.mackerron.com/2010/12/14/death-to-weak-passwords/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Four things I&#8217;ve learned using Push Notifications</title>
		<link>http://blog.mackerron.com/2010/09/11/4-things-apns/</link>
		<comments>http://blog.mackerron.com/2010/09/11/4-things-apns/#comments</comments>
		<pubDate>Sat, 11 Sep 2010 14:32:06 +0000</pubDate>
		<dc:creator>George</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.mackerron.com/?p=386</guid>
		<description><![CDATA[My current iPhone app/research project, mappiness, is heavily reliant on Apple&#8217;s Push Notification Service (APNS). We&#8217;re now sending about one million notifications a month, and it&#8217;s working beautifully. The obvious alternative &#8212; using SMS messages &#8212; would be costing us tens of thousands of pounds a month. If you&#8217;re using or contemplating using Push Notifications, [...]]]></description>
			<content:encoded><![CDATA[<p>My current iPhone app/research project, <a href="http://www.mappiness.org.uk">mappiness</a>, is heavily reliant on Apple&#8217;s Push Notification Service (APNS). </p>

<p>We&#8217;re now sending about one million notifications a month, and it&#8217;s working beautifully. The obvious alternative &#8212; using <span class="caps">SMS </span>messages &#8212; would be costing us tens of thousands of pounds a month.</p>

<p>If you&#8217;re using or contemplating using Push Notifications, you may find these four points of interest:</p>


<ol>
<li><a href="http://urbanairship.com">Urban Airship</a> offer a well-though-out and reliable service. But if you&#8217;re using them just as an intermediary in telling the <span class="caps">APNS </span>to beep users X, Y and Z right now &#8212; not making use of their scheduling or broadcast features, for example &#8212; it might well not be worth it. You&#8217;ll cut out a layer of indirection, and save money if you get big enough for it to matter, by talking to Apple directly.</li>
<li>There&#8217;s a surprising dearth of viable-looking open-source options for interfacing with the <span class="caps">APNS. </span>(APNS uses a binary protocol over a secure connection, and doesn&#8217;t like this connection torn down and reopened too often, so you can&#8217;t easily interface with it directly from a web app or cron job). But there is <a href="http://pyapns.org/">pyapns</a>, an <span class="caps">XML</span>-RPC-speaking <span class="caps">APNS </span>provider built on Python&#8217;s Twisted networking framework, with client libraries for Python and Ruby. I&#8217;ve found this straightforward and rock-solid.</li>
<li>The <span class="caps">APNS </span>feedback service sometimes reports device tokens as inactive for no obvious reason, so make sure you&#8217;re prepared to hear from and reactivate users you&#8217;ve previously inactivated. (mappiness got bitten by this early on: a few dozen people were unable to authenticate to our server because they&#8217;d been reported as inactive and we&#8217;d assumed they were never coming back, despite that fact they had the app installed and Push Notifications switched on).</li>
<li>The app delegate method <code>application:didRegisterForRemoteNotificationsWithDeviceToken:</code> seems occasionally to return phantom zero-length device tokens &#8212; so don&#8217;t let your app or server get flummoxed by these. (We suffered from this on mappiness too: the bad device token got added to the front of a queue for sending from the app to our server; the server wouldn&#8217;t accept it; and this blocked all further data getting sent back until we fixed the server to silently ignore the bad tokens).</li>
</ol>

]]></content:encoded>
			<wfw:commentRss>http://blog.mackerron.com/2010/09/11/4-things-apns/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using OS Code-Point Polygons in PostGIS</title>
		<link>http://blog.mackerron.com/2009/11/14/code-point-polygons-postgis/</link>
		<comments>http://blog.mackerron.com/2009/11/14/code-point-polygons-postgis/#comments</comments>
		<pubDate>Sat, 14 Nov 2009 12:13:43 +0000</pubDate>
		<dc:creator>George</dc:creator>
				<category><![CDATA[GIS]]></category>
		<category><![CDATA[PostGIS]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://blog.mackerron.com/?p=193</guid>
		<description><![CDATA[Ordnance Survey&#8217;s Code-Point with Polygons &#8220;provides a precise geographical location for each postcode unit in Great Britain&#8221;. It&#8217;s available in various formats, including ESRI .shp files. Many UK academics can access the data via institutional subscription to EDINA Digimap. I&#8217;m using it in my research into subjective wellbeing and environmental quality. This post shows how [...]]]></description>
			<content:encoded><![CDATA[<p>Ordnance Survey&#8217;s <a href="http://www.ordnancesurvey.co.uk/oswebsite/products/codepointpolygons/">Code-Point with Polygons</a> &#8220;provides a precise geographical location for each postcode unit in Great Britain&#8221;. It&#8217;s available in various formats, including <span class="caps">ESRI</span> .shp files. </p>

<p>Many UK academics can access the data via institutional subscription to <a href="http://edina.ac.uk/digimap/"><span class="caps">EDINA</span> Digimap</a>. I&#8217;m using it in <a href="http://personal.lse.ac.uk/MACKERRO/">my research into subjective wellbeing and environmental quality</a>.</p>

<p>This post shows how to:</p>


<ol>
<li><strong>import the data files</strong> into a <a href="http://postgis.refractions.net/">PostGIS</a> database; and</li>
<li><strong>de-normalise the data into a single table</strong>, where there&#8217;s a one-to-one mapping of postcodes to rows, and each row contains either all geographical locations covered by a postcode (as a single geometry column, of type multipolygon) or the reason why no such location is available</li>
</ol>



<p><span id="more-193"></span></p>

<h3>Why de-normalise?</h3>

<p>Step 2 above is required for my purposes because Code-Point data is supplied in a number of separate files per postcode area: </p>


<ul>
<li>a .shp file (and associated .shx and .dbf) mapping postcodes and &#8216;vertical streets&#8217; to the locations they cover;</li>
<li>an accompanying text file mapping postcodes to &#8216;vertical streets&#8217;; and</li>
<li>another text file listing postcodes with no associated locations, either because they represent PO boxes or because the data just isn&#8217;t available.</li>
</ul>



<p>Vertical streets generally represent high-rise buildings, where one location in 2D space may be associated with multiple postcodes. Vertical streets are also a serious pain: not only may one vertical street be associated with many postcodes, but one postcode may be associated with many vertical streets <em>and</em> with non-vertical-street locations too. </p>

<h2>Import the data files</h2>

<p>Download and unzip the Code-Point with Polygons data, in <span class="caps">ESRI</span> .shp format, for the regions you want (where indicative query timings are provided later, these are for whole-UK data &#8212; 120 postcode areas &#8212; on a 2Ghz Intel iMac).</p>

<p>Dump everything in the same directory. For each postcode area XX you should have the following five files:</p>


<ul>
<li><span class="caps">XX.</span>shp, <span class="caps">XX.</span>shx and <span class="caps">XX.</span>dbf</li>
<li>XX_vstreet_lookup.txt</li>
<li>XX_discard.txt</li>
</ul>



<p>If you don&#8217;t already have one you want to use for this purpose, create a PostGIS-enabled PostgreSQL database (in this post, the database is named <code>geo</code>). If you&#8217;re not running PostgreSQL 8.4 or later you may need to fiddle with some fsm_ settings in the Postgres .conf file in order to cope with a data set this large.</p>

<p>Execute the following <span class="caps">SQL </span>to create the tables for discards and vertical streets (e.g. from within pgAdmin):</p>


<div class="wp_syntax"><div class="code"><pre class="postgresql" style="font-family:monospace;"><span style="color: #005500;">create</span> <span style="color: #005500;">table</span> cpp_vertical_streets <span style="color: #66cc66;">&#40;</span>
  postcode <span style="color: #993333;">character</span> varying<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">8</span><span style="color: #66cc66;">&#41;</span>,
  vstreet <span style="color: #993333;">character</span> varying<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">8</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #005500;">create</span> <span style="color: #005500;">table</span> cpp_discards <span style="color: #66cc66;">&#40;</span>
  postcode <span style="color: #993333;">character</span> varying<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">8</span><span style="color: #66cc66;">&#41;</span>,
  reason <span style="color: #993333;">character</span> varying<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">7</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;</pre></div></div>




<p>Next we need to create the table for the .shp-file polygons. We <strong>switch to Ruby</strong> for this &#8212; you can just enter the commands in an <span class="caps">IRB </span>terminal session:</p>


<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">path = <span style="color:#996600;">'/path/to/CodePoint polygons'</span>
<span style="color:#996600;">`/usr/local/pgsql/bin/shp2pgsql -p -D -s 27700 &quot;#{path}/ab.shp&quot; cpp_polygons | /usr/local/pgsql/bin/psql -d geo -U postgres`</span></pre></div></div>




<p>The -p flag to <code>shp2pgsql</code> just creates a table structure, and the -s 27700 gives it the <span class="caps">EPSG </span>code to tell it we&#8217;re using the <span class="caps">OSGB36 </span>datum. You can use any of the .shp files you&#8217;ve downloaded &#8212; it need not be the AB area one.</p>

<p><strong>Now to do the import</strong> into the three tables. Still in Ruby, execute the following loop:</p>


<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#CC00FF; font-weight:bold;">Dir</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;#{path}/*.shp&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>f<span style="color:#006600; font-weight:bold;">|</span>
  <span style="color:#CC0066; font-weight:bold;">puts</span> f
  <span style="color:#996600;">`/usr/local/pgsql/bin/shp2pgsql -a -D -s 27700 &quot;#{f}&quot; cpp_polygons | /usr/local/pgsql/bin/psql -d geo -U postgres`</span>
  <span style="color:#996600;">`echo &quot;copy cpp_vertical_streets from '#{f.sub(/<span style="color:#000099;">\.</span>shp$/, '_vstreet_lookup.txt')}' csv;&quot; | /usr/local/pgsql/bin/psql geo postgres`</span>
  <span style="color:#996600;">`echo &quot;copy cpp_discards from '#{f.sub(/<span style="color:#000099;">\.</span>shp$/, '_discard.txt')}' csv;&quot; | /usr/local/pgsql/bin/psql geo postgres`</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>




<p>Back in <span class="caps">SQL, </span>add some boolean flags we&#8217;ll use later on, then create an index on the postcode column, which will save a <strong>lot</strong> of time later:</p>


<div class="wp_syntax"><div class="code"><pre class="postgresql" style="font-family:monospace;"><span style="color: #005500;">alter</span> <span style="color: #005500;">table</span> cpp_polygons <span style="color: #005500;">add</span> <span style="color: #005500;">column</span> <span style="color: #005500;">discard</span> <span style="color: #993333;">boolean</span>;
<span style="color: #005500;">alter</span> <span style="color: #005500;">table</span> cpp_polygons <span style="color: #005500;">add</span> <span style="color: #005500;">column</span> vstreet <span style="color: #993333;">boolean</span>;
<span style="color: #005500;">alter</span> <span style="color: #005500;">table</span> cpp_polygons <span style="color: #005500;">add</span> <span style="color: #005500;">column</span> vstreet_and_std <span style="color: #993333;">boolean</span>;
&nbsp;
<span style="color: #005500;">create</span> <span style="color: #005500;">index</span> pc_index <span style="color: #005500;">on</span> cpp_polygons <span style="color: #66cc66;">&#40;</span>postcode<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #005500;">vacuum</span> <span style="color: #005500;">analyze</span> cpp_polygons;</pre></div></div>




<p>If you like, you can confirm here that there&#8217;s only one row per postcode &#8212; this query <strong>should return nothing</strong>:</p>


<div class="wp_syntax"><div class="code"><pre class="postgresql" style="font-family:monospace;"><span style="color: #005500;">select</span> * 
<span style="color: #005500;">from</span> cpp_polygons a 
<span style="color: #005500;">inner</span> <span style="color: #005500;">join</span> cpp_polygons b 
<span style="color: #005500;">on</span> a.postcode <span style="color: #66cc66;">=</span> b.postcode 
<span style="color: #005500;">where</span> a.gid <span style="color: #66cc66;">&lt;&gt;</span> b.gid;</pre></div></div>




<p>So, we now have all the OS data held in three separate tables. In the rest of the post, we&#8217;ll be merging the data in the discards and vertical streets tables into the main table, cpp_polygons.</p>

<h2>Discards</h2>

<p>We&#8217;re going to create a new table, with the same structure as cpp_polygons, to hold the discarded postcode data. These postcodes will have a <span class="caps">NULL </span>geometry column, and a <span class="caps">TRUE </span>discard column (one of the booleans we added earlier). Later, we&#8217;ll insert the contents of this table into cpp_polygons.</p>

<p>Run the following <span class="caps">SQL</span>:</p>


<div class="wp_syntax"><div class="code"><pre class="postgresql" style="font-family:monospace;"><span style="color: #005500;">create</span> <span style="color: #005500;">sequence</span> cpp_discard_seq <span style="color: #005500;">start</span> <span style="color: #005500;">with</span> <span style="color: #cc66cc;">2000000</span>;
&nbsp;
<span style="color: #005500;">create</span> <span style="color: #005500;">table</span> cpp_discard_polys <span style="color: #005500;">as</span> <span style="color: #66cc66;">&#40;</span>
<span style="color: #005500;">select</span> 
  <span style="color: #333399;">nextval</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'cpp_discard_seq'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> gid, 
  postcode,
  cast<span style="color: #66cc66;">&#40;</span><span style="color: #005500;">null</span> <span style="color: #005500;">as</span> <span style="color: #993333;">character</span> varying<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">20</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> upp, 
  <span style="color: #333399;">substring</span><span style="color: #66cc66;">&#40;</span>postcode <span style="color: #005500;">from</span> <span style="color: #ff0000;">'^[A-Z][A-Z]?'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> pc_area, 
  cast<span style="color: #66cc66;">&#40;</span><span style="color: #005500;">null</span> <span style="color: #005500;">as</span> <span style="color: #993333;">geometry</span><span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> the_geom, 
  <span style="color: #005500;">true</span> <span style="color: #005500;">as</span> <span style="color: #005500;">discard</span>, 
  <span style="color: #005500;">false</span> <span style="color: #005500;">as</span> vstreet,
  <span style="color: #005500;">false</span> <span style="color: #005500;">as</span> vstreet_and_std
<span style="color: #005500;">from</span> cpp_discards
<span style="color: #66cc66;">&#41;</span>;</pre></div></div>




<h2>Vertical streets</h2>

<p>Similarly, we&#8217;re now going to create a new table with the same structure as cpp_polygons to map vertical street postcodes to the right polygons. This requires a left join of the vertical streets data with some of the geometry data in cpp_polygons.</p>


<div class="wp_syntax"><div class="code"><pre class="postgresql" style="font-family:monospace;"><span style="color: #005500;">set</span> enable_seqscan <span style="color: #66cc66;">=</span> <span style="color: #005500;">false</span>; 
<span style="color: #808080; font-style: italic;">-- (otherwise pg sometimes fails to use the index)</span>
&nbsp;
<span style="color: #005500;">create</span> <span style="color: #005500;">sequence</span> cpp_vstreet_seq <span style="color: #005500;">start</span> <span style="color: #005500;">with</span> <span style="color: #cc66cc;">3000000</span>;
&nbsp;
<span style="color: #005500;">create</span> <span style="color: #005500;">table</span> cpp_vstreet_polys <span style="color: #005500;">as</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #005500;">select</span> 
    <span style="color: #333399;">nextval</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'cpp_vstreet_seq'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> gid, 
    <span style="color: #333399;">max</span><span style="color: #66cc66;">&#40;</span>v.postcode<span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> postcode, 
    cast<span style="color: #66cc66;">&#40;</span><span style="color: #005500;">null</span> <span style="color: #005500;">as</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">20</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> upp, 
    <span style="color: #333399;">max</span><span style="color: #66cc66;">&#40;</span>pc_area<span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> pc_area, 
    st_union<span style="color: #66cc66;">&#40;</span>the_geom<span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> the_geom, 
    <span style="color: #005500;">false</span> <span style="color: #005500;">as</span> <span style="color: #005500;">discard</span>,
    <span style="color: #005500;">true</span> <span style="color: #005500;">as</span> vstreet,
    <span style="color: #005500;">false</span> <span style="color: #005500;">as</span> vstreet_and_std
  <span style="color: #005500;">from</span> cpp_vertical_streets v 
  <span style="color: #005500;">left</span> <span style="color: #005500;">join</span> cpp_polygons p 
  <span style="color: #005500;">on</span> v.vstreet <span style="color: #66cc66;">=</span> p.postcode
  <span style="color: #005500;">group</span> <span style="color: #005500;">by</span> v.postcode
<span style="color: #66cc66;">&#41;</span>;</pre></div></div>




<p>Our last new table is for postcodes that are associated with both standard polygons <strong>and</strong> vertical street polygons.</p>


<div class="wp_syntax"><div class="code"><pre class="postgresql" style="font-family:monospace;"><span style="color: #005500;">create</span> <span style="color: #005500;">sequence</span> cpp_vstreet_and_std_seq <span style="color: #005500;">start</span> <span style="color: #005500;">with</span> <span style="color: #cc66cc;">4000000</span>;
&nbsp;
<span style="color: #005500;">create</span> <span style="color: #005500;">table</span> cpp_vstreet_and_std_polys <span style="color: #005500;">as</span> <span style="color: #66cc66;">&#40;</span>
<span style="color: #005500;">select</span> 
  <span style="color: #333399;">nextval</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'cpp_vstreet_and_std_seq'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> gid, 
  p.postcode <span style="color: #005500;">as</span> postcode,
  cast<span style="color: #66cc66;">&#40;</span><span style="color: #005500;">null</span> <span style="color: #005500;">as</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">20</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> upp, 
  p.pc_area <span style="color: #005500;">as</span> pc_area,
  st_multi<span style="color: #66cc66;">&#40;</span>st_union<span style="color: #66cc66;">&#40;</span>p.the_geom, v.the_geom<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #005500;">as</span> the_geom, 
  <span style="color: #005500;">false</span> <span style="color: #005500;">as</span> <span style="color: #005500;">discard</span>, 
  <span style="color: #005500;">false</span> <span style="color: #005500;">as</span> vstreet,
  <span style="color: #005500;">true</span> <span style="color: #005500;">as</span> vstreet_and_std
<span style="color: #005500;">from</span> cpp_polygons p
<span style="color: #005500;">inner</span> <span style="color: #005500;">join</span> cpp_vstreet_polys v
<span style="color: #005500;">on</span> p.postcode <span style="color: #66cc66;">=</span> v.postcode
<span style="color: #66cc66;">&#41;</span>;</pre></div></div>




<h2>Cleaning and merging</h2>

<p>Now we need to remove the vertical streets and polygons we just merged into a new table from their respective source tables.</p>


<div class="wp_syntax"><div class="code"><pre class="postgresql" style="font-family:monospace;"><span style="color: #005500;">delete</span> <span style="color: #005500;">from</span> cpp_polygons <span style="color: #005500;">where</span> postcode <span style="color: #005500;">in</span> <span style="color: #66cc66;">&#40;</span><span style="color: #005500;">select</span> postcode <span style="color: #005500;">from</span> cpp_vstreet_and_std_polys<span style="color: #66cc66;">&#41;</span>;
<span style="color: #808080; font-style: italic;">-- the above could take around 25 mins</span>
<span style="color: #005500;">delete</span> <span style="color: #005500;">from</span> cpp_vstreet_polys <span style="color: #005500;">where</span> postcode <span style="color: #005500;">in</span> <span style="color: #66cc66;">&#40;</span><span style="color: #005500;">select</span> postcode <span style="color: #005500;">from</span> cpp_vstreet_and_std_polys<span style="color: #66cc66;">&#41;</span>;</pre></div></div>




<p>And, finally, to merge our three new tables into the main table.</p>


<div class="wp_syntax"><div class="code"><pre class="postgresql" style="font-family:monospace;"><span style="color: #005500;">insert</span> <span style="color: #005500;">into</span> cpp_polygons <span style="color: #005500;">select</span> * <span style="color: #005500;">from</span> cpp_discard_polys;
<span style="color: #005500;">insert</span> <span style="color: #005500;">into</span> cpp_polygons <span style="color: #005500;">select</span> * <span style="color: #005500;">from</span> cpp_vstreet_polys;
<span style="color: #005500;">insert</span> <span style="color: #005500;">into</span> cpp_polygons <span style="color: #005500;">select</span> * <span style="color: #005500;">from</span> cpp_vstreet_and_std_polys;</pre></div></div>




<p>In order to join my own data with this data, I find it easiest to format the postcodes on which the join is made with no spaces. So I add and index the following extra column.</p>


<div class="wp_syntax"><div class="code"><pre class="postgresql" style="font-family:monospace;"><span style="color: #005500;">alter</span> <span style="color: #005500;">table</span> cpp_polygons <span style="color: #005500;">add</span> <span style="color: #005500;">column</span> postcode_no_sp <span style="color: #993333;">character</span> varying<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">8</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #005500;">update</span> cpp_polygons <span style="color: #005500;">set</span> postcode_no_sp <span style="color: #66cc66;">=</span> replace<span style="color: #66cc66;">&#40;</span>postcode, <span style="color: #ff0000;">' '</span>, <span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span>; 
<span style="color: #808080; font-style: italic;">-- the above could take 10 - 15 mins</span>
<span style="color: #005500;">create</span> <span style="color: #005500;">index</span> pcns_index <span style="color: #005500;">on</span> cpp_polygons <span style="color: #66cc66;">&#40;</span>postcode_no_sp<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #005500;">vacuum</span> <span style="color: #005500;">analyze</span> cpp_polygons;</pre></div></div>




<p>You might also want to remove the original vertical street rows, where the postcode column begins with a &#8216;V&#8217;, from the cpp_polygons table &#8212; I didn&#8217;t have any need for this.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.mackerron.com/2009/11/14/code-point-polygons-postgis/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Signing Amazon Product Advertising API calls in Ruby</title>
		<link>http://blog.mackerron.com/2009/08/22/sign-aws-api-in-ruby/</link>
		<comments>http://blog.mackerron.com/2009/08/22/sign-aws-api-in-ruby/#comments</comments>
		<pubDate>Sat, 22 Aug 2009 11:04:23 +0000</pubDate>
		<dc:creator>George</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Web design]]></category>

		<guid isPermaLink="false">http://blog.mackerron.com/?p=182</guid>
		<description><![CDATA[I have a simple site that generates covers for CDs I burn from iTunes purchases and so on (it pre-dates widespread use of JS libraries, and is in much need of prettifying). The site uses Amazon Product Advertising API calls to search and retrieve album cover art and track listings. Since earlier this month, such [...]]]></description>
			<content:encoded><![CDATA[<p>I have <a href="http://mackerron.com/cdcovers/">a simple site</a> that generates covers for CDs I burn from iTunes purchases and so on (it pre-dates widespread use of JS libraries, and is in much need of prettifying). The site uses <a href="https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html">Amazon Product Advertising <span class="caps">API</span></a> calls to search and retrieve album cover art and track listings. Since earlier this month, such <span class="caps">API </span>calls have to be cryptographically signed.</p>

<p>This is somewhat annoying &#8212; the site&#8217;s original design has it communicating independently with Amazon (using Amazon&#8217;s <span class="caps">XSLT API </span>feature to transform their <span class="caps">XML </span>data into <span class="caps">JSON</span>), and that&#8217;s no longer possible with the use of a private key. But it&#8217;s not unfixable. The site now sends its <span class="caps">API </span>call first to my server, which returns a signed version, and then forwards the signed call on to Amazon.</p>

<p>I found most of what I needed for this on <a href="http://chrisroos.co.uk/blog/2009-01-31-implementing-version-2-of-the-amazon-aws-http-request-signature-in-ruby">Chris Roos&#8217; blog</a>, but his version still wasn&#8217;t quite working for me (the two problems I recall are that Ruby&#8217;s <span class="caps">CGI.</span>escape doesn&#8217;t quite follow Amazon&#8217;s requirements, and that times need converting to <span class="caps">GMT</span>).</p>

<p><span id="more-182"></span></p>

<p>Anyway, in case you&#8217;re looking to do the same, here&#8217;s what I ended up with:</p>


<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#008000; font-style:italic;">#!/usr/bin/env ruby</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># Note: You need hmac.rb and hmac-sha2.rb from http://deisui.org/~ueno/ruby/hmac.html </span>
<span style="color:#008000; font-style:italic;"># somewhere in your require paths. ruby-hmac is currently broken under Ruby 1.9.</span>
&nbsp;
<span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">&#40;</span>rubygems cgi time hmac<span style="color:#006600; font-weight:bold;">-</span>sha2 base64<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>lib<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#CC0066; font-weight:bold;">require</span> lib <span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
ACCESS_IDENTIFIER = <span style="color:#996600;">'YOUR_PUBLIC_ID'</span>
SECRET_IDENTIFIER = <span style="color:#996600;">'YOUR_PRIVATE_ID'</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">def</span> aws_escape<span style="color:#006600; font-weight:bold;">&#40;</span>s<span style="color:#006600; font-weight:bold;">&#41;</span>
  s.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">/</span><span style="color:#006600; font-weight:bold;">&#91;</span>^A<span style="color:#006600; font-weight:bold;">-</span>Za<span style="color:#006600; font-weight:bold;">-</span>z0<span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">9</span>_.~<span style="color:#006600; font-weight:bold;">-</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">/</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>c<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#996600;">'%'</span> <span style="color:#006600; font-weight:bold;">+</span> c<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">to_s</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">16</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">upcase</span> <span style="color:#006600; font-weight:bold;">&#125;</span>  
  <span style="color:#008000; font-style:italic;"># for 1.9, you'd replace [0] with .ord -- but ruby-hmac seems broken under 1.9</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
cgi = <span style="color:#CC00FF; font-weight:bold;">CGI</span>.<span style="color:#9900CC;">new</span>
params = cgi.<span style="color:#9900CC;">params</span>.<span style="color:#9900CC;">dup</span>
&nbsp;
amazon_endpoint = params.<span style="color:#9900CC;">delete</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'amazon_endpoint'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
amazon_path = params.<span style="color:#9900CC;">delete</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'amazon_path'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
js_callback = params.<span style="color:#9900CC;">delete</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'js_callback'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
signing_params = <span style="color:#006600; font-weight:bold;">&#123;</span>
  <span style="color:#996600;">'AWSAccessKeyId'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> ACCESS_IDENTIFIER,
  <span style="color:#996600;">'Timestamp'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>.<span style="color:#9900CC;">gmtime</span>.<span style="color:#9900CC;">iso8601</span>
<span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
params.<span style="color:#9900CC;">merge</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>signing_params<span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
canonical_querystring = params.<span style="color:#9900CC;">sort</span>.<span style="color:#9900CC;">collect</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>key, value<span style="color:#006600; font-weight:bold;">|</span> 
  <span style="color:#006600; font-weight:bold;">&#91;</span>aws_escape<span style="color:#006600; font-weight:bold;">&#40;</span>key.<span style="color:#9900CC;">to_s</span><span style="color:#006600; font-weight:bold;">&#41;</span>, aws_escape<span style="color:#006600; font-weight:bold;">&#40;</span>value.<span style="color:#9900CC;">to_s</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'='</span><span style="color:#006600; font-weight:bold;">&#41;</span> 
<span style="color:#9966CC; font-weight:bold;">end</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'&amp;'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
string_to_sign = <span style="color:#996600;">&quot;GET<span style="color:#000099;">\n</span>#{amazon_endpoint}<span style="color:#000099;">\n</span>#{amazon_path}<span style="color:#000099;">\n</span>#{canonical_querystring}&quot;</span>
&nbsp;
hmac = <span style="color:#6666ff; font-weight:bold;">HMAC::SHA256</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>SECRET_IDENTIFIER<span style="color:#006600; font-weight:bold;">&#41;</span>
hmac.<span style="color:#9900CC;">update</span><span style="color:#006600; font-weight:bold;">&#40;</span>string_to_sign<span style="color:#006600; font-weight:bold;">&#41;</span>
signature = <span style="color:#CC00FF; font-weight:bold;">Base64</span>.<span style="color:#9900CC;">encode64</span><span style="color:#006600; font-weight:bold;">&#40;</span>hmac.<span style="color:#9900CC;">digest</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#CC0066; font-weight:bold;">chomp</span>
&nbsp;
params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'Signature'</span><span style="color:#006600; font-weight:bold;">&#93;</span> = signature
querystring = params.<span style="color:#9900CC;">sort</span>.<span style="color:#9900CC;">collect</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>key, value<span style="color:#006600; font-weight:bold;">|</span> 
  <span style="color:#006600; font-weight:bold;">&#91;</span>aws_escape<span style="color:#006600; font-weight:bold;">&#40;</span>key.<span style="color:#9900CC;">to_s</span><span style="color:#006600; font-weight:bold;">&#41;</span>, aws_escape<span style="color:#006600; font-weight:bold;">&#40;</span>value.<span style="color:#9900CC;">to_s</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'='</span><span style="color:#006600; font-weight:bold;">&#41;</span> 
<span style="color:#9966CC; font-weight:bold;">end</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'&amp;'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
signed_url = <span style="color:#996600;">&quot;http://#{amazon_endpoint}#{amazon_path}?#{querystring}&quot;</span>
&nbsp;
cgi.<span style="color:#9900CC;">out</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'type'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'text/javascript'</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#996600;">&quot;#{js_callback}('#{signed_url}');&quot;</span> <span style="color:#006600; font-weight:bold;">&#125;</span></pre></div></div>




<p>You can test this locally by feeding key/value parameters to <span class="caps">CGI, </span>followed by Ctrl-D. These, for example:</p>



<pre>amazon_endpoint=ecs.amazonaws.com
amazon_path=/onca/xml
js_callback=do_stuff
Service=AWSECommerceService
Version=2009-03-31
Operation=ItemSearch
SearchIndex=Books
Keywords=george+monbiot</pre>]]></content:encoded>
			<wfw:commentRss>http://blog.mackerron.com/2009/08/22/sign-aws-api-in-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
<!-- This Quick Cache file was built for (  blog.mackerron.com/category/ruby/feed/ ) in 0.97773 seconds, on Feb 5th, 2012 at 2:53 am UTC. -->
<!-- This Quick Cache file will automatically expire ( and be re-built automatically ) on Feb 5th, 2012 at 3:53 am UTC -->
