<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/feed.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
  <channel>
    <feedpress:locale>en</feedpress:locale>
    <feedpress:newsletterId>jc00ke</feedpress:newsletterId>
    <atom:link rel="hub" href="http://feedpress.superfeedr.com/"/>
    <title>Musings of something or another</title>
    <description>Technology for good, like yesterday.</description>
    <link>http://jc00ke.com/</link>
    <atom:link href="https://feedpress.me/jc00ke" rel="self" type="application/rss+xml"/>
    <item>
      <title>Forward SMS to email via Twilio and Mailgun</title>
      <description><![CDATA[<p>Back in 2017 <a href="https://twitter.com/philnash">Phil Nash</a> wrote a very nice blog post for Twilio
called <a href="https://www.twilio.com/blog/2017/07/forward-incoming-sms-messages-to-email-with-node-js-sendgrid-and-twilio-functions.html">Forward incoming SMS messages to email with Node.js, SendGrid and Twilio 
Functions</a>. 
I used this exact setup this year for <a href="https://ratiopbc.com">Ratio</a> because I wanted a dedicated phone number 
for the business. Voice calls are forwarded directly to my mobile using <code class="language-plaintext highlighter-rouge">TwiML Bins</code> via the following simple 
  bin:</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="nt">&lt;Response&gt;</span>
  <span class="nt">&lt;Dial&gt;</span>+1971221xxxx<span class="nt">&lt;/Dial&gt;</span>
<span class="nt">&lt;/Response&gt;</span></code></pre></figure>

<p>Back to SMS forwarding… we don’t get many SMS messages and instead of warning us via email, SendGrid just 
closed the account. So for some months we weren’t getting SMS messages forwarded to our Google Group inbox.
Even though I added a credit card, they could not reactivate it, so here I am with a port 
to <a href="https://www.mailgun.com/">Mailgun</a>.</p>

<p>So, same basic steps as Phil’s blog post except <code class="language-plaintext highlighter-rouge">Functions/Functions</code> are now <code class="language-plaintext highlighter-rouge">Functions/Services</code> which you
can find 
<a href="https://console.twilio.com/us1/develop/functions/services?frameUrl=/console/functions/overview/services">here</a>.</p>

<p>Create a new function at path <code class="language-plaintext highlighter-rouge">/forward</code>.</p>

<p>Under <code class="language-plaintext highlighter-rouge">Dependencies</code> add <code class="language-plaintext highlighter-rouge">mailgun.js</code> version 4.1.1 and <code class="language-plaintext highlighter-rouge">form-data</code> version 4.0.0.</p>

<p>Under <code class="language-plaintext highlighter-rouge">Environment Variables</code> add <code class="language-plaintext highlighter-rouge">MAILGUN_DOMAIN</code>, <code class="language-plaintext highlighter-rouge">MAILGUN_API_KEY</code>, <code class="language-plaintext highlighter-rouge">FROM_EMAIL_ADDRESS</code>, and 
<code class="language-plaintext highlighter-rouge">TO_EMAIL_ADDRESS</code>.</p>

<p>I based this function body on the <a href="https://documentation.mailgun.com/en/latest/quickstart-sending.html#send-via-api">Mailgun 
example</a>:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">exports</span><span class="p">.</span><span class="nx">handler</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">event</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">API_KEY</span> <span class="o">=</span> <span class="nx">context</span><span class="p">.</span><span class="nx">MAILGUN_API_KEY</span><span class="p">;</span>
  <span class="kd">const</span> <span class="nx">DOMAIN</span> <span class="o">=</span> <span class="nx">context</span><span class="p">.</span><span class="nx">MAILGUN_DOMAIN</span><span class="p">;</span>

  <span class="kd">const</span> <span class="nx">formData</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">form-data</span><span class="dl">'</span><span class="p">);</span>
  <span class="kd">const</span> <span class="nx">Mailgun</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">mailgun.js</span><span class="dl">'</span><span class="p">);</span>

  <span class="kd">const</span> <span class="nx">mailgun</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Mailgun</span><span class="p">(</span><span class="nx">formData</span><span class="p">);</span>
  <span class="kd">const</span> <span class="nx">client</span> <span class="o">=</span> <span class="nx">mailgun</span><span class="p">.</span><span class="nx">client</span><span class="p">({</span><span class="na">username</span><span class="p">:</span> <span class="dl">'</span><span class="s1">api</span><span class="dl">'</span><span class="p">,</span> <span class="na">key</span><span class="p">:</span> <span class="nx">API_KEY</span><span class="p">});</span>

  <span class="kd">const</span> <span class="nx">messageData</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">from</span><span class="p">:</span> <span class="nx">context</span><span class="p">.</span><span class="nx">FROM_EMAIL_ADDRESS</span><span class="p">,</span>
    <span class="na">to</span><span class="p">:</span> <span class="nx">context</span><span class="p">.</span><span class="nx">TO_EMAIL_ADDRESS</span><span class="p">,</span>
    <span class="na">subject</span><span class="p">:</span> <span class="s2">`New SMS message from: </span><span class="p">${</span><span class="nx">event</span><span class="p">.</span><span class="nx">From</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span>
    <span class="na">text</span><span class="p">:</span> <span class="nx">event</span><span class="p">.</span><span class="nx">Body</span>
  <span class="p">};</span>

  <span class="nx">client</span><span class="p">.</span><span class="nx">messages</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">DOMAIN</span><span class="p">,</span> <span class="nx">messageData</span><span class="p">)</span>
  <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
      <span class="kd">let</span> <span class="nx">twiml</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Twilio</span><span class="p">.</span><span class="nx">twiml</span><span class="p">.</span><span class="nx">MessagingResponse</span><span class="p">();</span>
      <span class="nx">callback</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">twiml</span><span class="p">);</span>
  <span class="p">})</span>
  <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">err</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
    <span class="nx">callback</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
  <span class="p">});</span>
<span class="p">};</span></code></pre></figure>

<p>Make sure you hooked it up to the correct phone number, then test it out by sending an SMS message to your 
Twilio number. If you need to debug, look in the <a href="https://console.twilio.com/us1/monitor/logs/sms?frameUrl=%2Fconsole%2Fsms%2Flogs%3Fx-target-region%3Dus1">Messaging 
logs</a> 
in Twilio and the Mailgun <code class="language-plaintext highlighter-rouge">Sending/Logs</code>.</p>

<p>If you run into issues or have feedback, please don’t hesitate to send me an email if you know it, or mention 
<a href="https://twitter.com/jc00ke">me on Twitter</a>. Thanks!</p>
]]></description>
      <pubDate>Mon, 13 Dec 2021 00:00:00 -0800</pubDate>
      <link>http://jc00ke.com/2021/12/13/forward-sms-to-email-via-twilio-and-mailgun/</link>
      <guid isPermaLink="true">http://jc00ke.com/2021/12/13/forward-sms-to-email-via-twilio-and-mailgun/</guid>
    </item>
    <item>
      <title>Automatically sort Tailwind classes in Neovim with rustywind and efm-langserver</title>
      <description><![CDATA[<p>Neovim 0.5 has a built-in language server client (LSP) that’s easily extensible
with the <a href="https://github.com/mattn/efm-langserver">efm-langserver</a>. Inspired by Dr. Nic’s
<a href="https://dev.to/drnic/automatically-sorting-your-tailwind-css-class-names-4gej">recent post on dev.to</a>
I wanted to get <a href="https://github.com/avencera/rustywind">rustywind</a>
working with efm-langserver. I don’t even use Tailwind… yet,
but I’ve been a fan for quite a while.</p>

<p>I’ll leave it to the reader to get efm-langserver installed, but I wanted to share my config.
I use <code class="language-plaintext highlighter-rouge">~/.config/efm-langserver/config.yaml</code> to configure formatters &amp; linters, and I configure
<code class="language-plaintext highlighter-rouge">efm</code> in Neovim in <code class="language-plaintext highlighter-rouge">~/.config/nvim/init.lua</code>. Here are the relevant parts:</p>

<h4 id="efm-langserver-config">efm-langserver config</h4>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">version</span><span class="pi">:</span> <span class="m">2</span>

<span class="na">tools</span><span class="pi">:</span>
  <span class="na">tailwind-class-sort</span><span class="pi">:</span> <span class="nl">&amp;tailwind-class-sort</span>
    <span class="na">format-command</span><span class="pi">:</span> <span class="s1">'</span><span class="s">rustywind</span><span class="nv"> </span><span class="s">--stdin'</span>
    <span class="na">format-stdin</span><span class="pi">:</span> <span class="no">true</span>

<span class="na">languages</span><span class="pi">:</span>
  <span class="na">html</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">&lt;&lt;</span><span class="pi">:</span> <span class="nv">*tailwind-class-sort</span></code></pre></figure>

<h4 id="neovim-lua-config">neovim lua config</h4>

<figure class="highlight"><pre><code class="language-lua" data-lang="lua"><span class="n">lspconfig</span><span class="p">.</span><span class="n">efm</span><span class="p">.</span><span class="n">setup</span><span class="p">({</span>
  <span class="n">filetypes</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"html"</span><span class="p">},</span>
  <span class="n">init_options</span> <span class="o">=</span> <span class="p">{</span><span class="n">documentFormatting</span> <span class="o">=</span> <span class="kc">true</span><span class="p">},</span>
<span class="p">})</span></code></pre></figure>

<p>Check out my <a href="https://github.com/jc00ke/dotfiles/commit/dbe31441fedf4325572d622c8c940ce47b1e292e?branch=dbe31441fedf4325572d622c8c940ce47b1e292e&amp;diff=unified">dotfiles repo 
commit</a>
and you can view more of the files to see how they’re all put together. Now, when you write the file,
you’ll get automatic class sorting. Fun stuff!</p>
]]></description>
      <pubDate>Tue, 08 Jun 2021 00:00:00 -0700</pubDate>
      <link>http://jc00ke.com/2021/06/08/tailwind-sorting-with-rustywind-and-efm-langserver-for-neovim/</link>
      <guid isPermaLink="true">http://jc00ke.com/2021/06/08/tailwind-sorting-with-rustywind-and-efm-langserver-for-neovim/</guid>
    </item>
    <item>
      <title>Setting your Hex org auth key with the Heroku Elixir buildpack</title>
      <description><![CDATA[<p>I’ve been working on an Elixir application for the last year, and overall it’s been a smooth, pleasant
experience. I’ve been meaning to write more, so here we go.</p>

<p><a href="https://hex.pm/">Hex</a>, the package manager for <a href="https://elixir-lang.org">Elixir</a> is very well thought out,
but there are things I’m still being introduced to, like <a href="https://hex.pm/docs/private">private organizations</a>.
There’s a beta I’m trying out, and it requires me to use a hex org key, which is fine, but how do I securely
store it in Heroku such that it’s available when installing packages?</p>

<p>My first attempt was to set the <code class="language-plaintext highlighter-rouge">hook_pre_fetch_dependencies</code> hook of the excellent <a href="https://github.com/HashNuke/heroku-buildpack-elixir">buildpack for
Heroku</a> like so:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">hook_pre_fetch_dependencies</span><span class="o">=</span><span class="s2">"mix hex.organization auth acme --key </span><span class="nv">$HEX_ORG_KEY_FOR_ACME</span><span class="s2">"</span>
</code></pre></div></div>

<p>I pushed to Heroku and…</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">-----</span><span class="o">&gt;</span> Executing hook before fetching app dependencies: mix hex.organization auth acme <span class="nt">--key</span>

<span class="k">**</span> <span class="o">(</span>Mix<span class="o">)</span> Could not invoke task <span class="s2">"hex.organization"</span>: 1 error found!

<span class="nt">--key</span> : Missing argument of <span class="nb">type </span>string
</code></pre></div></div>

<p>Luckily, I had already set up a <code class="language-plaintext highlighter-rouge">postdeploy</code> script for Heroku’s <code class="language-plaintext highlighter-rouge">app.json</code> so I had that method in mind,
however, there wasn’t a hook in that lifecycle that made sense for me to use. But, mixing the two approaches
did seem like something worth trying, and this is what ended up working.</p>

<p>In <code class="language-plaintext highlighter-rouge">./bin/predeps</code></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

mix hex.organization auth acme <span class="nt">--key</span> <span class="s2">"</span><span class="nv">$HEX_ORG_KEY_FOR_ACME</span><span class="s2">"</span>
</code></pre></div></div>

<p>In <code class="language-plaintext highlighter-rouge">elixir_buildpack.config</code></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">hook_pre_fetch_dependencies</span><span class="o">=</span><span class="s2">"./bin/predeps"</span>
</code></pre></div></div>

<p>Worked, and feels clean enough!</p>
]]></description>
      <pubDate>Mon, 28 Oct 2019 00:00:00 -0700</pubDate>
      <link>http://jc00ke.com/2019/10/28/hex-auth-key-elixir-buildpack-heroku/</link>
      <guid isPermaLink="true">http://jc00ke.com/2019/10/28/hex-auth-key-elixir-buildpack-heroku/</guid>
    </item>
    <item>
      <title>Replacing Nginx with Træfik for local development</title>
      <description><![CDATA[<p>At <a href="https://inquicker.com/">$work</a> most of the team uses Docker to develop our core Rails app. Before that,
they used Vagrant. This is fine, for them. I strongly dislike working with these tools, so I always
set up my projects to also run locally. Using processes. And commands. And things that are not black boxes.
But this can be a bit of a PITA when you work on an app that requires both subdomains and SSL.</p>

<h2 id="previously">Previously</h2>

<p>I would turn to Nginx, where I would <code class="language-plaintext highlighter-rouge">apt-get install nginx</code> and then go install
<a href="https://github.com/perusio/nginx_ensite">nginx_ensite</a> then setup a config and some SSL certs, like so:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/sites-enabled/inquicker</span>

<span class="k">server</span> <span class="p">{</span>
  <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
  <span class="kn">server_name</span> <span class="s">inquickerlocal.com</span><span class="p">;</span>

  <span class="kn">return</span> <span class="mi">301</span> <span class="s">https://iqapp.inquickerlocal.com</span><span class="nv">$request_uri</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">server</span> <span class="p">{</span>
  <span class="kn">listen</span> <span class="mi">80</span><span class="p">;</span>
  <span class="kn">server_name</span> <span class="s">*.inquickerlocal.com</span><span class="p">;</span>

  <span class="kn">return</span> <span class="mi">301</span> <span class="s">https://</span>$<span class="p">{</span><span class="kn">host</span><span class="err">}</span>$<span class="p">{</span><span class="kn">request_uri</span><span class="err">}</span><span class="p">;</span>
<span class="p">}</span>

<span class="kn">server</span> <span class="p">{</span>
  <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
  <span class="kn">server_name</span> <span class="s">inquickerlocal.com</span> <span class="s">www.inquickerlocal.com</span><span class="p">;</span>

  <span class="kn">include</span> <span class="n">/etc/nginx/iqapp-ssl-settings.conf</span><span class="p">;</span>

  <span class="kn">return</span> <span class="mi">301</span> <span class="s">https://iqapp.inquickerlocal.com</span><span class="nv">$request_uri</span><span class="p">;</span>
<span class="p">}</span>

<span class="kn">server</span> <span class="p">{</span>
  <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span>
  <span class="kn">server_name</span> <span class="s">*.inquickerlocal.com</span><span class="p">;</span>

  <span class="kn">include</span> <span class="n">/etc/nginx/iqapp-ssl-settings.conf</span><span class="p">;</span>

  <span class="kn">root</span> <span class="n">/path/to/iqapp/public</span><span class="p">;</span>
  <span class="kn">try_files</span> <span class="nv">$uri</span> <span class="nv">$uri</span><span class="n">/index.html</span> <span class="s">@app</span><span class="p">;</span>

  <span class="kn">location</span> <span class="s">@app</span> <span class="p">{</span>
    <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
    <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-Proto</span> <span class="s">https</span><span class="p">;</span>
    <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
    <span class="kn">proxy_redirect</span> <span class="no">off</span><span class="p">;</span>
    <span class="kn">proxy_pass</span> <span class="s">http://localhost:3000</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I’d then have to go into that file and change things to work with my local setup, like</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">root</span> <span class="n">/path/to/iqapp/public</span><span class="p">;</span>
</code></pre></div></div>

<p>Ain’t nobody got time for that.</p>

<h2 id="enter-træfik">Enter Træfik.</h2>

<blockquote>
  <p>Træfik (pronounced like traffic) is a modern HTTP reverse proxy and load balancer made
to deploy microservices with ease.</p>
</blockquote>

<p>It’s quite powerful, and you can find out all about it <a href="https://traefik.io/">here</a>. I’ll save you some time if
you just want to set up a reverse proxy that also serves your local development site over SSL. This is our
setup for a typical Rails app:</p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[web]</span>
<span class="py">address</span> <span class="p">=</span> <span class="s">":8080"</span>

<span class="py">traefikLogsFile</span> <span class="p">=</span> <span class="s">"log/traefik.log"</span>
<span class="py">accessLogsFile</span> <span class="p">=</span> <span class="s">"log/access.log"</span>

<span class="py">defaultEntryPoints</span> <span class="p">=</span> <span class="p">[</span><span class="s">"http"</span><span class="p">,</span> <span class="s">"https"</span><span class="p">]</span>
<span class="nn">[entryPoints]</span>
  <span class="nn">[entryPoints.http]</span>
  <span class="py">address</span> <span class="p">=</span> <span class="s">":80"</span>
    <span class="nn">[entryPoints.http.redirect]</span>
    <span class="py">entryPoint</span> <span class="p">=</span> <span class="s">"https"</span>
  <span class="nn">[entryPoints.https]</span>
  <span class="py">address</span> <span class="p">=</span> <span class="s">":443"</span>
    <span class="nn">[entryPoints.https.tls]</span>
      <span class="nn">[[entryPoints.https.tls.certificates]]</span>
      <span class="py">certFile</span> <span class="p">=</span> <span class="s">"config/development-cert.pem"</span>
      <span class="py">keyFile</span> <span class="p">=</span> <span class="s">"config/development-key.pem"</span>

<span class="nn">[file]</span>

<span class="nn">[backends]</span>
  <span class="nn">[backends.puma]</span>
    <span class="nn">[backends.puma.servers.rails]</span>
      <span class="py">url</span> <span class="p">=</span> <span class="s">"http://127.0.0.1:3000"</span>

<span class="nn">[frontends]</span>
  <span class="nn">[frontends.my_app]</span>
  <span class="py">entrypoints</span> <span class="p">=</span> <span class="nn">["https"]</span>
  <span class="py">backend</span> <span class="p">=</span> <span class="s">"puma"</span>
  <span class="py">passHostHeader</span> <span class="p">=</span> <span class="kc">true</span>
    <span class="nn">[frontends.my_app.routes.all]</span>
      <span class="py">rule</span> <span class="p">=</span> <span class="s">"HostRegexp:{subdomain:[a-z]+}.myapp.dev"</span>
</code></pre></div></div>

<p>You can then run it with <code class="language-plaintext highlighter-rouge">sudo traefik -c config/traefik.toml</code>. You need the <code class="language-plaintext highlighter-rouge">sudo</code> to run on the privileged
ports <code class="language-plaintext highlighter-rouge">80</code> and <code class="language-plaintext highlighter-rouge">443</code>.</p>

<p>Let’s step through this, as it was a bit confusing to get it right.</p>

<h3 id="admin-interface">Admin interface</h3>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[web]</span>
<span class="py">address</span> <span class="p">=</span> <span class="s">":8080"</span>
</code></pre></div></div>

<p>Add this and you can browse to <a href="http://localhost:8080">http://localhost:8080</a> to see Træfik’s web interface,
which was actually handy in debugging this whole thing.</p>

<h3 id="log-files">Log files</h3>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">traefikLogsFile</span> <span class="p">=</span> <span class="s">"log/traefik.log"</span>
<span class="py">accessLogsFile</span> <span class="p">=</span> <span class="s">"log/access.log"</span>
</code></pre></div></div>

<p>I had a typo (<code class="language-plaintext highlighter-rouge">frontend.my_app</code> instead of <code class="language-plaintext highlighter-rouge">frontends.my_app</code>) and the access log file would show me the
<code class="language-plaintext highlighter-rouge">404</code>.</p>

<h3 id="entrypoints">Entrypoints</h3>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">defaultEntryPoints</span> <span class="p">=</span> <span class="p">[</span><span class="s">"http"</span><span class="p">,</span> <span class="s">"https"</span><span class="p">]</span>
<span class="nn">[entryPoints]</span>
  <span class="nn">[entryPoints.http]</span>
  <span class="py">address</span> <span class="p">=</span> <span class="s">":80"</span>
    <span class="nn">[entryPoints.http.redirect]</span>
    <span class="py">entryPoint</span> <span class="p">=</span> <span class="s">"https"</span>
  <span class="nn">[entryPoints.https]</span>
  <span class="py">address</span> <span class="p">=</span> <span class="s">":443"</span>
    <span class="nn">[entryPoints.https.tls]</span>
      <span class="nn">[[entryPoints.https.tls.certificates]]</span>
      <span class="py">certFile</span> <span class="p">=</span> <span class="s">"config/development-cert.pem"</span>
      <span class="py">keyFile</span> <span class="p">=</span> <span class="s">"config/development-key.pem"</span>
</code></pre></div></div>

<p>Define 2 entries, one that’s unsecured and redirects to the other secured one, and the secured one, secured by
local cert and key files. We already had these dev certs (both in <code class="language-plaintext highlighter-rouge">.pem</code> formats) checked into our repo, so
was simple to config. No need to <code class="language-plaintext highlighter-rouge">sudo cp</code> the files to somewhere in <code class="language-plaintext highlighter-rouge">/etc/nginx/</code>. Read more about
entrypoints <a href="https://docs.traefik.io/basics/#entrypoints">here</a>.</p>

<h3 id="configuration-backends">Configuration backends</h3>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[file]</span>
</code></pre></div></div>

<p>This took me a bit to figure out. I needed to specify that this file was where I was going to be defining the
<code class="language-plaintext highlighter-rouge">backends</code> and <code class="language-plaintext highlighter-rouge">frontends</code>. Read more about it <a href="https://docs.traefik.io/toml/#configuration-backends">here</a>.</p>

<h3 id="backends">Backends</h3>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[backends]</span>
  <span class="nn">[backends.puma]</span>
    <span class="nn">[backends.puma.servers.rails]</span>
      <span class="py">url</span> <span class="p">=</span> <span class="s">"http://127.0.0.1:3000"</span>
</code></pre></div></div>

<p>This section defines where traffic will be sent. I would start up Rails with a simple <code class="language-plaintext highlighter-rouge">bundle exec rails s</code>
which defaults to port <code class="language-plaintext highlighter-rouge">3000</code>. The <code class="language-plaintext highlighter-rouge">puma</code> and <code class="language-plaintext highlighter-rouge">rails</code> parts to the name are arbitrary. You can read more about
backends <a href="https://docs.traefik.io/basics/#backends">here</a>.</p>

<h3 id="frontends">Frontends</h3>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[frontends]</span>
  <span class="nn">[frontends.my_app]</span>
  <span class="py">entrypoints</span> <span class="p">=</span> <span class="nn">["https"]</span>
  <span class="py">backend</span> <span class="p">=</span> <span class="s">"puma"</span>
  <span class="py">passHostHeader</span> <span class="p">=</span> <span class="kc">true</span>
    <span class="nn">[frontends.my_app.routes.all]</span>
      <span class="py">rule</span> <span class="p">=</span> <span class="s">"HostRegexp:{subdomain:[a-z]+}.inquickerlocal.com"</span>
</code></pre></div></div>

<p>So this took me a bit to figure out. I had to manually define the <code class="language-plaintext highlighter-rouge">entrypoints</code> which I thought would have
been handled by <code class="language-plaintext highlighter-rouge">defaultEntryPoints</code>. Setting the <code class="language-plaintext highlighter-rouge">backend</code> makes sense, no problems there. <code class="language-plaintext highlighter-rouge">passHostHeader</code>
is something we’ve had to do for a while, and the equivalent in <code class="language-plaintext highlighter-rouge">Nginx</code> is <code class="language-plaintext highlighter-rouge">proxy_set_header Host $host;</code>.</p>

<p>Now the frontend matchers… those are powerful. I chose the <code class="language-plaintext highlighter-rouge">HostRegexp</code> since I wanted to match on the
subdomains. I lifted that straight from the docs, which you can find
<a href="https://docs.traefik.io/basics/#frontends">here</a>.</p>

<h3 id="fin">Fin</h3>

<p>I really like this setup, and while it is one more thing to run (<code class="language-plaintext highlighter-rouge">sudo traefik</code>) it’s all closer to the app and
not some system-wide thing that’s in <code class="language-plaintext highlighter-rouge">/etc</code>. While <code class="language-plaintext highlighter-rouge">Nginx</code> has served me well for years, when it comes to
local development I feel that Træfik is easier to set up and more powerful. It has fantastic Docker
integration too, so one day I may need to explore that. Until then, I’m happy with this.</p>

<p>If you have any comments or suggestions, ping me on <a href="https://twitter.com/jc00ke">Twitter</a>.</p>
]]></description>
      <pubDate>Tue, 30 May 2017 00:00:00 -0700</pubDate>
      <link>http://jc00ke.com/2017/05/30/replacing-nginx-with-traefik-for-local-development/</link>
      <guid isPermaLink="true">http://jc00ke.com/2017/05/30/replacing-nginx-with-traefik-for-local-development/</guid>
    </item>
    <item>
      <title>Securely connecting to XFINITY hotspot on Linux</title>
      <description><![CDATA[<p>I’ve been coming to this coffee shop with this same network and same laptop for almost 2 years now. Today, for
some reason, my laptop decided it didn’t want to play nicely with the network. I could connect to both the 2.4
and 5GHz networks but I couldn’t ping anything… DNS issue?</p>

<p>The first thing I tried was setting my connection to use Google’s DNS: <code class="language-plaintext highlighter-rouge">8.8.8.8</code> and <code class="language-plaintext highlighter-rouge">8.8.4.4</code> for <code class="language-plaintext highlighter-rouge">ipv4</code> and
<code class="language-plaintext highlighter-rouge">2001:4860:4860:8888</code> and <code class="language-plaintext highlighter-rouge">2001:4860:4860:8844</code> for <code class="language-plaintext highlighter-rouge">ipv6</code>.</p>

<p>No bueno.</p>

<p>Next step? Restart my computer.</p>

<p>No bueno.</p>

<p>I look around and see that there’s <code class="language-plaintext highlighter-rouge">xfinitywifi</code> and <code class="language-plaintext highlighter-rouge">XFINITY</code> networks, and I’m reminded that I can connect
and that the <code class="language-plaintext highlighter-rouge">XFINITY</code> has a secure connection capability. Some googlin’ brings me to <a href="https://www.xfinity.com/support/internet/about-xfinity-wifi-internet/#secure_support">this support
page</a>. Well shit, Linux
isn’t supported. I decide to give it a go anyway, and I’m presented with this screen:</p>

<p><img alt="Network settings dialog in GNOME" src="http://jc00ke.com/assets/posts/securely-connecting-to-xfinity-hotspot-on-linux/network-settings-dialog.png" style="width: 100%;" /></p>

<p>I filled in those values based on the <a href="https://www.xfinity.com/support/internet/connect-manually-secure-xfinity-wifi-hotspots/">suggestions for Android
from</a>.</p>

<p>Well, initially I had <code class="language-plaintext highlighter-rouge">No CA certificate is required</code> but that didn’t feel right, so, more googlin’ and I
found <a href="https://askubuntu.com/a/781026">this AskUbuntu answer</a> that suggested the <code class="language-plaintext highlighter-rouge">AddTrust_External_Root.ca</code>.</p>

<p>Lo and behold, it worked!</p>

<p>Now, am I 100% certain this is the same security level as what XFINITY is claiming on other platforms? No, but
I’m like 95% and that’s good enough for the next few hours.</p>

<p><em>Update</em> - Thanks to <a href="https://twitter.com/variuxdavid/status/1433208622901772288">@variuxdavid</a> for letting
me know there’s a new <code class="language-plaintext highlighter-rouge">CA certificate</code> for later versions of Ubuntu: <code class="language-plaintext highlighter-rouge">COMODO_RSA_Certification_Authority.crt</code>.
Screenshot updated!</p>

<p><em>Update</em> - Chris Lopes reached out suggesting some improvements to this post. I’ve not been on Comcast for years,
but this post keeps coming up in searches so I want to include his advice:</p>

<blockquote>
  <p>It seems that although GTC inner authentication works in order to connect to the hotspot, it does not (any longer?)
allow actual use of the network without first logging in to the captive portal (Xfinity web login page),
which is often hard to get to, believe it or not. The solution seems to be to use PAP instead, which solves this.</p>
</blockquote>

<p>He also sent a <a href="https://askubuntu.com/a/1385684">link to an AskUbuntu answer</a> that I hope can be helpful.</p>

<p>For those on Apple devices that might find their way here, I want to include Chris’s side note:</p>

<blockquote>
  <p>I also checked, and the .mobileconfig automatic <a href="https://developer.apple.com/business/documentation/Configuration-Profile-Reference.pdf">configuration profiles</a>
that Xfinity provides to MacOS
and iOS devices for use with the Hotspots now also list PAP as the inner authentication.
There are files that you download and “install” on Apple devices to provision similar settings automatically as the ones we are discussing here.
Xfinity interestingly generates some sort of separate credentials that are just for this purpose
(totally different username/password than the one you would normally use).
You can test this via the captive portal if you spoof your User Agent to be an apple device and have it generate the profile for you to download.</p>
</blockquote>

<p>Some terms that I hope help you find your way here according to Chris:</p>

<ul>
  <li>GTC</li>
  <li>PAP</li>
  <li>Tunneled TLS and TTLS</li>
  <li><a href="https://en.wikipedia.org/wiki/Extensible_Authentication_Protocol#EAP-TTLS">EAP-TTLS</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Hotspot_(Wi-Fi)#Hotspot_2.0">Passpoint / Hotspot 2.0</a></li>
</ul>

<p>I love receiving updates for this post! You keep sending them and I’ll keep updating.</p>
]]></description>
      <pubDate>Fri, 12 May 2017 00:00:00 -0700</pubDate>
      <link>http://jc00ke.com/2017/05/12/securely-connecting-to-xfinity-hotspot-on-linux/</link>
      <guid isPermaLink="true">http://jc00ke.com/2017/05/12/securely-connecting-to-xfinity-hotspot-on-linux/</guid>
    </item>
    <item>
      <title>Testing Elixir Mix tasks</title>
      <description><![CDATA[<p>What’s the best way to test your <a href="https://hexdocs.pm/mix/Mix.Task.html">Mix tasks</a>? I needed
to write a custom <code class="language-plaintext highlighter-rouge">Mix</code> task yesterday, and I wanted to start off right by
writing a test. I wanted to reuse some code that generates &amp; verifies a <a href="https://jwt.io">JWT</a> and
spits it out in the terminal.</p>

<p>The code has always been relatively simple:</p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">Mix</span><span class="o">.</span><span class="no">Tasks</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="no">Gen</span> <span class="k">do</span>
  <span class="kn">use</span> <span class="no">Mix</span><span class="o">.</span><span class="no">Task</span>

  <span class="nv">@shortdoc</span> <span class="s2">"Generates a JWT"</span>

  <span class="nv">@moduledoc</span> <span class="sd">"""
  Generates a JWT far far into the future.

      mix jwt.gen
  """</span>

  <span class="k">def</span> <span class="n">run</span><span class="p">(</span><span class="n">_argv</span><span class="p">)</span> <span class="k">do</span>
    <span class="n">exp</span> <span class="o">=</span>   <span class="no">Joken</span><span class="o">.</span><span class="n">current_time</span> <span class="o">+</span> <span class="mi">1_000_000</span>
    <span class="n">jti</span> <span class="o">=</span>   <span class="ss">:rand</span><span class="o">.</span><span class="n">uniform</span>
    <span class="n">iss</span> <span class="o">=</span>   <span class="s2">"Jesse"</span>

    <span class="n">jwt</span> <span class="o">=</span> <span class="no">Jwt</span><span class="o">.</span><span class="n">generate_jwt</span><span class="p">(%{</span><span class="ss">exp:</span> <span class="n">exp</span><span class="p">,</span> <span class="ss">jti:</span> <span class="n">jti</span><span class="p">,</span> <span class="ss">iss:</span> <span class="n">iss</span><span class="p">)</span>
    <span class="no">Mix</span><span class="o">.</span><span class="n">shell</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">jwt</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>My test started off looking like this:</p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">Mix</span><span class="o">.</span><span class="no">Tasks</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="no">GenTest</span> <span class="k">do</span>
  <span class="kn">use</span> <span class="no">ExUnit</span><span class="o">.</span><span class="no">Case</span><span class="p">,</span> <span class="ss">async:</span> <span class="no">true</span>
  <span class="kn">import</span> <span class="no">ExUnit</span><span class="o">.</span><span class="no">CaptureIO</span>

  <span class="n">describe</span> <span class="s2">"run/1"</span> <span class="k">do</span>
    <span class="n">test</span> <span class="s2">"prints a valid JWT"</span> <span class="k">do</span>
      <span class="n">jwt</span> <span class="o">=</span> <span class="n">capture_io</span><span class="p">(</span><span class="k">fn</span> <span class="o">-&gt;</span>
        <span class="no">Mix</span><span class="o">.</span><span class="no">Tasks</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="no">Gen</span><span class="o">.</span><span class="n">run</span><span class="p">([])</span>
      <span class="k">end</span><span class="p">)</span> <span class="o">|&gt;</span> <span class="no">String</span><span class="o">.</span><span class="n">trim</span>

      <span class="n">token</span> <span class="o">=</span> <span class="no">Jwt</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">jwt</span><span class="p">)</span>
      <span class="n">refute</span> <span class="n">token</span><span class="o">.</span><span class="n">errors</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>OK, this is fine, but there was an annoying side effect: the JWT was printed to <code class="language-plaintext highlighter-rouge">:stdio</code>
when I ran the tests. I thought <code class="language-plaintext highlighter-rouge">capture_io</code> was supposed to actually capture <em>and</em> suppress
the output… I was wrong. Or, I was missing something, and that ended up being the case.</p>

<p>I figured the best guidance I could get would be to see what <a href="http://www.phoenixframework.org/">Phoenix</a> did,
and I found an example in the <a href="https://github.com/phoenixframework/phoenix/blob/b6db9a268e68cb2c975dde20f9c103e6442a8265/test/mix/tasks/phx.routes_test.exs#L17">routes task
test</a>:</p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">test</span> <span class="s2">"format routes for specific router"</span> <span class="k">do</span>
  <span class="no">Mix</span><span class="o">.</span><span class="no">Tasks</span><span class="o">.</span><span class="no">Phx</span><span class="o">.</span><span class="no">Routes</span><span class="o">.</span><span class="n">run</span><span class="p">([</span><span class="s2">"PhoenixTest.Web.Router"</span><span class="p">])</span>
  <span class="n">assert_received</span> <span class="p">{</span><span class="ss">:mix_shell</span><span class="p">,</span> <span class="ss">:info</span><span class="p">,</span> <span class="p">[</span><span class="n">routes</span><span class="p">]}</span>               <span class="c1"># &lt;---- ooh!</span>
  <span class="n">assert</span> <span class="n">routes</span> <span class="o">=~</span> <span class="s2">"page_path  GET  /  PageController :index"</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Yes, <a href="https://hexdocs.pm/ex_unit/ExUnit.Assertions.html#assert_received/2">assert_received</a> seems like a
cleaner way to go. How did this change my tests?</p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">Mix</span><span class="o">.</span><span class="no">Tasks</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="no">GenTest</span> <span class="k">do</span>
  <span class="kn">use</span> <span class="no">ExUnit</span><span class="o">.</span><span class="no">Case</span><span class="p">,</span> <span class="ss">async:</span> <span class="no">true</span>

  <span class="n">describe</span> <span class="s2">"run/1"</span> <span class="k">do</span>
    <span class="n">test</span> <span class="s2">"prints a valid JWT"</span> <span class="k">do</span>
      <span class="no">Mix</span><span class="o">.</span><span class="no">Tasks</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="no">Gen</span><span class="o">.</span><span class="n">run</span><span class="p">([])</span>

      <span class="n">assert_received</span> <span class="p">{</span><span class="ss">:mix_shell</span><span class="p">,</span> <span class="ss">:info</span><span class="p">,</span> <span class="p">[</span><span class="n">jwt</span><span class="p">]}</span>    <span class="c1"># pattern matching FTW</span>

      <span class="n">token</span> <span class="o">=</span> <span class="no">Jwt</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">jwt</span><span class="p">)</span>
      <span class="n">refute</span> <span class="n">token</span><span class="o">.</span><span class="n">errors</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Much nicer!</p>

<p>Still though, the JWT was being printed to <code class="language-plaintext highlighter-rouge">:stdio</code>! I didn’t even know where to begin
searching for how to handle this, so I went back to the Phoenix tests and noticed a helper
was being required.</p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Code</span><span class="o">.</span><span class="n">require_file</span> <span class="s2">"../../../installer/test/mix_helper.exs"</span><span class="p">,</span> <span class="n">__DIR__</span>
</code></pre></div></div>

<p>The key was at the <a href="https://github.com/phoenixframework/phoenix/blob/b6db9a268e68cb2c975dde20f9c103e6442a8265/installer/test/mix_helper.exs#L1-L3">top of that
file!</a></p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Get Mix output sent to the current</span>
<span class="c1"># process to avoid polluting tests.</span>
<span class="no">Mix</span><span class="o">.</span><span class="n">shell</span><span class="p">(</span><span class="no">Mix</span><span class="o">.</span><span class="no">Shell</span><span class="o">.</span><span class="no">Process</span><span class="p">)</span>
</code></pre></div></div>

<p>Once I changed my tests to include that, the unwanted output went away and I was happy
with the shape of the tests.</p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Get Mix output sent to the current</span>
<span class="c1"># process to avoid polluting tests.</span>
<span class="no">Mix</span><span class="o">.</span><span class="n">shell</span><span class="p">(</span><span class="no">Mix</span><span class="o">.</span><span class="no">Shell</span><span class="o">.</span><span class="no">Process</span><span class="p">)</span>

<span class="k">defmodule</span> <span class="no">Mix</span><span class="o">.</span><span class="no">Tasks</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="no">GenTest</span> <span class="k">do</span>
  <span class="kn">use</span> <span class="no">ExUnit</span><span class="o">.</span><span class="no">Case</span><span class="p">,</span> <span class="ss">async:</span> <span class="no">true</span>

  <span class="n">describe</span> <span class="s2">"run/1"</span> <span class="k">do</span>
    <span class="n">test</span> <span class="s2">"prints a valid JWT"</span> <span class="k">do</span>
      <span class="no">Mix</span><span class="o">.</span><span class="no">Tasks</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="no">Gen</span><span class="o">.</span><span class="n">run</span><span class="p">([])</span>

      <span class="n">assert_received</span> <span class="p">{</span><span class="ss">:mix_shell</span><span class="p">,</span> <span class="ss">:info</span><span class="p">,</span> <span class="p">[</span><span class="n">jwt</span><span class="p">]}</span>    <span class="c1"># pattern matching FTW</span>

      <span class="n">token</span> <span class="o">=</span> <span class="no">Jwt</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">jwt</span><span class="p">)</span>
      <span class="n">refute</span> <span class="n">token</span><span class="o">.</span><span class="n">errors</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>I hope this saves you some trouble, and I’d love to hear how you test your tasks. Mention
me on <a href="https://twitter.com/jc00ke">Twitter</a> with a link to a Gist and I’ll add it here.</p>

<h3 id="on-options">On options</h3>

<p>I ended up using <code class="language-plaintext highlighter-rouge">OptionParser</code> so I could pass in <code class="language-plaintext highlighter-rouge">exp</code>, <code class="language-plaintext highlighter-rouge">iss</code> and <code class="language-plaintext highlighter-rouge">jti</code>. My final test looked like this:</p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Code</span><span class="o">.</span><span class="n">require_file</span><span class="p">(</span><span class="s2">"../mix_test_helper.exs"</span><span class="p">,</span> <span class="n">__DIR__</span><span class="p">)</span>

<span class="k">defmodule</span> <span class="no">Cerebro</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="no">GenTest</span> <span class="k">do</span>
  <span class="kn">use</span> <span class="no">ExUnit</span><span class="o">.</span><span class="no">Case</span><span class="p">,</span> <span class="ss">async:</span> <span class="no">true</span>

  <span class="n">alias</span> <span class="no">Mix</span><span class="o">.</span><span class="no">Tasks</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="no">Gen</span>

  <span class="n">describe</span> <span class="s2">"run/1"</span> <span class="k">do</span>

    <span class="n">setup</span> <span class="n">context</span> <span class="k">do</span>
      <span class="no">Gen</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">context</span><span class="p">[</span><span class="ss">:argv</span><span class="p">])</span>

      <span class="n">assert_received</span> <span class="p">{</span><span class="ss">:mix_shell</span><span class="p">,</span> <span class="ss">:info</span><span class="p">,</span> <span class="p">[</span><span class="n">jwt</span><span class="p">]}</span>

      <span class="n">token</span> <span class="o">=</span> <span class="no">Cerebro</span><span class="o">.</span><span class="no">Jwt</span><span class="o">.</span><span class="n">verify_jwt</span><span class="p">(</span><span class="n">jwt</span><span class="p">)</span>

      <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="ss">claims:</span> <span class="n">token</span><span class="o">.</span><span class="n">claims</span><span class="p">,</span> <span class="ss">token:</span> <span class="n">token</span><span class="p">}</span>
    <span class="k">end</span>

    <span class="nv">@tag</span> <span class="ss">argv:</span> <span class="p">[]</span>
    <span class="n">test</span> <span class="s2">"prints a valid JWT with no args"</span><span class="p">,</span> <span class="p">%{</span><span class="ss">token:</span> <span class="n">token</span><span class="p">}</span> <span class="k">do</span>
      <span class="n">refute</span> <span class="n">token</span><span class="o">.</span><span class="n">error</span>
    <span class="k">end</span>

    <span class="nv">@tag</span> <span class="ss">argv:</span> <span class="p">[</span><span class="s2">"--exp"</span><span class="p">,</span> <span class="s2">"123"</span><span class="p">]</span>
    <span class="n">test</span> <span class="s2">"prints a valid JWT when passed an expiration"</span><span class="p">,</span> <span class="p">%{</span><span class="ss">claims:</span> <span class="n">claims</span><span class="p">}</span> <span class="k">do</span>
      <span class="n">assert_in_delta</span> <span class="n">claims</span><span class="p">[</span><span class="s2">"exp"</span><span class="p">],</span> <span class="no">Joken</span><span class="o">.</span><span class="n">current_time</span><span class="p">,</span> <span class="mi">124</span>
    <span class="k">end</span>

    <span class="nv">@tag</span> <span class="ss">argv:</span> <span class="p">[</span><span class="s2">"--jti"</span><span class="p">,</span> <span class="s2">"fdsa"</span><span class="p">]</span>
    <span class="n">test</span> <span class="s2">"prints a valid JWT when passed a jti"</span><span class="p">,</span> <span class="p">%{</span><span class="ss">claims:</span> <span class="n">claims</span><span class="p">}</span> <span class="k">do</span>
      <span class="n">assert</span> <span class="n">claims</span><span class="p">[</span><span class="s2">"jti"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"fdsa"</span>
    <span class="k">end</span>

    <span class="nv">@tag</span> <span class="ss">argv:</span> <span class="p">[</span><span class="s2">"--iss"</span><span class="p">,</span> <span class="s2">"logan"</span><span class="p">]</span>
    <span class="n">test</span> <span class="s2">"prints a valid JWT when passed an iss"</span><span class="p">,</span> <span class="p">%{</span><span class="ss">claims:</span> <span class="n">claims</span><span class="p">}</span> <span class="k">do</span>
      <span class="n">assert</span> <span class="n">claims</span><span class="p">[</span><span class="s2">"iss"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"logan"</span>
    <span class="k">end</span>

    <span class="nv">@tag</span> <span class="ss">argv:</span> <span class="p">[</span><span class="s2">"--token"</span><span class="p">,</span> <span class="s2">"asdf"</span><span class="p">]</span>
    <span class="n">test</span> <span class="s2">"prints a valid JWT when passed a token"</span><span class="p">,</span> <span class="p">%{</span><span class="ss">claims:</span> <span class="n">claims</span><span class="p">}</span> <span class="k">do</span>
      <span class="n">assert</span> <span class="n">claims</span><span class="p">[</span><span class="s2">"token"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"asdf"</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>I’m really happy with the way that turned out.</p>

<h2 id="update">Update</h2>

<p><a href="https://github.com/kelvinst">Kelvin Stinghen</a> <a href="https://elixirforum.com/t/testing-mix-tasks/4471/2?u=jc00ke">clarified</a>
how one might use this <code class="language-plaintext highlighter-rouge">Mix.shell(Mix.Shell.Process)</code> from an
<a href="http://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-apps.html#umbrella-projects">umbrella</a>
application.</p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">setup</span> <span class="k">do</span>
  <span class="no">Mix</span><span class="o">.</span><span class="n">shell</span><span class="p">(</span><span class="no">Mix</span><span class="o">.</span><span class="no">Shell</span><span class="o">.</span><span class="no">Process</span><span class="p">)</span>
  <span class="n">on_exit</span> <span class="k">fn</span> <span class="o">-&gt;</span>
    <span class="no">Mix</span><span class="o">.</span><span class="n">shell</span><span class="p">(</span><span class="no">Mix</span><span class="o">.</span><span class="no">Shell</span><span class="o">.</span><span class="no">IO</span><span class="p">)</span>
  <span class="k">end</span>

  <span class="ss">:ok</span>
<span class="k">end</span>
</code></pre></div></div>
]]></description>
      <pubDate>Wed, 05 Apr 2017 00:00:00 -0700</pubDate>
      <link>http://jc00ke.com/2017/04/05/testing-elixir-mix-tasks/</link>
      <guid isPermaLink="true">http://jc00ke.com/2017/04/05/testing-elixir-mix-tasks/</guid>
    </item>
    <item>
      <title>Primitive obsession</title>
      <description><![CDATA[<p>I’ve been wanting to write about primitive obsession, specifically in Ruby, for a long time. A bug that made
its way to production last week has given me the kick I need to get this post out.</p>

<p>So, what is primitive obsession? Taken from <a href="http://wiki.c2.com/?PrimitiveObsession">C2 Wiki</a></p>

<blockquote>
  <p>Primitive Obsession is using primitive data types to represent domain ideas.
For example, we use a String to represent a message, an Integer to represent an amount of money,
or a Struct/Dictionary/Hash to represent a specific object.</p>
</blockquote>

<p>We’re all guilty of this because in general we’re all kinda lazy. It’s certainly not a “rookie mistake”.
Here it is in the latest version of
<a href="https://github.com/redis/redis-rb/blob/27759c01626762c818e6699e8d1a781530fe7d39/lib/redis.rb#L1395">redis.rb</a></p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># Get all the members in a set.</span>
<span class="c1">#</span>
<span class="c1"># @param [String] key</span>
<span class="c1"># @return [Array&lt;String&gt;]</span>
<span class="k">def</span> <span class="nf">smembers</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
  <span class="n">synchronize</span> <span class="k">do</span> <span class="o">|</span><span class="n">client</span><span class="o">|</span>
    <span class="n">client</span><span class="p">.</span><span class="nf">call</span><span class="p">([</span><span class="ss">:smembers</span><span class="p">,</span> <span class="n">key</span><span class="p">])</span>
  <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

<p>Spot the issue?</p>

<p>Members of a set are a subset. A set’s members, by definition, are unique from one another. An <code class="language-plaintext highlighter-rouge">Array</code> is
not a collection that enforces uniqueness. Have you ever done the following?</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">array_of_things</span> <span class="o">&lt;&lt;</span> <span class="n">thing</span> <span class="k">unless</span> <span class="n">array_of_things</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span><span class="n">thing</span><span class="p">)</span></code></pre></figure>

<p>Congratulations, you’ve just recreated Ruby’s <code class="language-plaintext highlighter-rouge">Set</code> class. That’s not a good thing. One reason why that’s not
a good thing is (with the caveat that you should always do your own benchmarks) that checking to see if an
array includes an object is <code class="language-plaintext highlighter-rouge">O(n)</code> where checking to see if a <code class="language-plaintext highlighter-rouge">Set</code> includes an object is <code class="language-plaintext highlighter-rouge">O(1)</code>.</p>

<p>Let me clarify: at <em>best</em> and at <em>worst</em> an array is <code class="language-plaintext highlighter-rouge">O(n)</code> because it’s always <code class="language-plaintext highlighter-rouge">O(n)</code> for search. At <em>best</em> a
<code class="language-plaintext highlighter-rouge">Set</code>, <a href="https://github.com/ruby/ruby/blob/7e8b910a5629fe025137e890ec6d57e538fd7811/lib/set.rb#L84">backed by a
<code class="language-plaintext highlighter-rouge">Hash</code></a>,
is <code class="language-plaintext highlighter-rouge">O(1)</code> which is quite good, <code class="language-plaintext highlighter-rouge">O(n)</code> at <em>worst</em>.</p>

<p>So there are consequences to using the wrong type, not just from a congnitive point of view but performance as
well. Ok, let’s leave <code class="language-plaintext highlighter-rouge">Array/Set</code> alone for now. If you’re curious, read up on the <a href="https://spin.atomicobject.com/2012/09/04/when-is-a-set-better-than-an-array-in-ruby/">Atomic
Object</a> blog, that’s a
great writeup.</p>

<p>Back to primitive obsession. I think that Ruby developers are lucky but burdened by Rails, specifically when
it comes to “good OO”. <code class="language-plaintext highlighter-rouge">ActiveSupport</code> is a rad library, and I fondly remember reading the Rails book in 2006
and being blown away by the ability to do <code class="language-plaintext highlighter-rouge">2.days.from_now</code>.</p>

<p>One of the things I appreciate from <code class="language-plaintext highlighter-rouge">Arel</code> is that when you make a query you get back an instance of
<code class="language-plaintext highlighter-rouge">ActiveRecord_Relation</code> not an <code class="language-plaintext highlighter-rouge">Array</code>. You can ask this relation questions you couldn’t, and shouldn’t, ask
an <code class="language-plaintext highlighter-rouge">Array</code>. This brings me to something I don’t often see in Ruby… collection classes.</p>

<p>A collection class is a class that represents a collection of objects. Why might you use a collection class
over an <code class="language-plaintext highlighter-rouge">Array</code> or a <code class="language-plaintext highlighter-rouge">Hash</code>, or even a <code class="language-plaintext highlighter-rouge">Set</code>? Most likely because you want to ask that collection questions
that <code class="language-plaintext highlighter-rouge">Array</code>, <code class="language-plaintext highlighter-rouge">Hash</code>, and even <code class="language-plaintext highlighter-rouge">Set</code> have no idea about. We reach for these custom classes because a
primitive is too simple, too basic, and we end up asking questions in the wrong places.</p>

<p>I had to interact with a remote API that did not give back good error messages. An example of how this works:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">WidgetCollection</span>
  <span class="kp">include</span> <span class="no">Enumerable</span>

  <span class="nb">attr_accessor</span> <span class="ss">:errors</span>

  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">widgets</span><span class="p">)</span>
    <span class="vi">@widgets</span> <span class="o">=</span> <span class="no">Set</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">widgets</span><span class="p">)</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">each</span>
    <span class="k">return</span> <span class="n">enum_for</span><span class="p">(</span><span class="ss">:each</span><span class="p">)</span> <span class="k">unless</span> <span class="nb">block_given?</span>

    <span class="vi">@widgets</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">widget</span><span class="o">|</span>
      <span class="k">yield</span> <span class="n">widget</span>
    <span class="k">end</span>

    <span class="nb">self</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">invalid_widget_present?</span>
    <span class="k">return</span> <span class="kp">false</span> <span class="k">unless</span> <span class="n">errors</span>
    <span class="o">!!</span><span class="sr">/some pattern that we hope works for a long time/</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="n">errors</span><span class="p">.</span><span class="nf">to_s</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="k">class</span> <span class="nc">Widget</span>
  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">fetch</span>
    <span class="n">api_results</span> <span class="o">=</span> <span class="no">Fetch</span><span class="p">.</span><span class="nf">call</span>
    <span class="no">WidgetCollection</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">api_results</span><span class="p">).</span><span class="nf">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">widgets</span><span class="o">|</span>
      <span class="n">widgets</span><span class="p">.</span><span class="nf">errors</span> <span class="o">=</span> <span class="n">api_results</span><span class="p">.</span><span class="nf">fault_code</span> <span class="c1"># a string, could be anything :(</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="c1"># elsewhere...</span>

<span class="n">widgets</span> <span class="o">=</span> <span class="no">Widget</span><span class="p">.</span><span class="nf">fetch</span>
<span class="n">log</span><span class="p">(</span><span class="n">a_message</span><span class="p">)</span> <span class="k">if</span> <span class="n">widgets</span><span class="p">.</span><span class="nf">invalid_widget_present?</span></code></pre></figure>

<p>It’s unfortunate that the remote API gives us a fault code like that, but at least we can hide it in a class
and keep our code a bit cleaner. Granted, there are more moving parts in our production code, but this way of
dealing with the remote API feels like the right way. Much better than using an <code class="language-plaintext highlighter-rouge">Array</code> and checking the
status further out. That’s certainly not “good” <code class="language-plaintext highlighter-rouge">OO</code>!</p>

<p>What would that code have looked like?</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># elsewhere...</span>

<span class="n">widgets</span> <span class="o">=</span> <span class="no">Widget</span><span class="p">.</span><span class="nf">fetch</span>
<span class="n">log</span><span class="p">(</span><span class="n">a_message</span><span class="p">)</span> <span class="k">if</span> <span class="no">WidgetCollection</span><span class="o">::</span><span class="no">ERROR_MESSAGE</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="n">widgets</span><span class="p">.</span><span class="nf">errors</span><span class="p">)</span></code></pre></figure>

<p>That requires you to know way too much, and it’s a sign that you’re relying too heavily on primitives.</p>

<p>Respecting the boundaries is an important part of practicing object oriented programming. When you don’t
create classes, especially for collections, you push responsibility out instead of pulling it in. This got
a bit longer than I expected, so I’ll kick the actual production bug to a separate post.</p>

<p>Stay tuned!</p>
]]></description>
      <pubDate>Mon, 26 Dec 2016 00:00:00 -0800</pubDate>
      <link>http://jc00ke.com/2016/12/26/primitive-obsession/</link>
      <guid isPermaLink="true">http://jc00ke.com/2016/12/26/primitive-obsession/</guid>
    </item>
    <item>
      <title>Going native: Pidgin, Geary and California</title>
      <description><![CDATA[<p>For years I’ve had 2 Gmail tabs pinned in Chrome: personal and work. This took
care of email, IM and calendar, which was quite convenient. I’m tired of waiting
for those 2 tabs to load when I spin up my browser, and I also WANT MY RAM BACK!</p>

<p>So, I’ve decided to go native for a bit. 3 concerns:</p>

<h2 id="instant-message">Instant Message</h2>

<p>Pidgin is king here, especially on Linux. While the buddy list is overpopulated
with people I don’t chat with, or have never chatted with, it’s easy to clean it
up. I need to learn the keyboard shortcuts, otherwise I think it’ll work out
well.</p>

<p>The only thing I’d like to add is SMS support. I already use MightyText and
luckily there is already a
<a href="https://github.com/tubaman/pidgin-mightytext">pidgin-mightytext</a> plugin. Just
need to compile it and get it set up. Hopefully it works.</p>

<h2 id="email">Email</h2>

<p>Gmail is fast and powerful. Evolution and Thunderbird are both too bloated and
ugly for my tastes, so I’m left with <a href="https://wiki.gnome.org/Apps/Geary">Geary</a>
from the <a href="http://yorba.org">Yorba Foundation</a>. I installed it via the daily PPA
and easily set up my 2 email accounts.</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">sudo </span>add-apt-repository ppa:yorba/daily-builds
<span class="nb">sudo </span>apt-get update
<span class="nb">sudo </span>apt-get <span class="nb">install </span>geary california</code></pre></figure>

<h2 id="calendar">Calendar</h2>

<p>Again, Evolution was too bloated and ugly, so I’m giving
<a href="https://wiki.gnome.org/Apps/California">California</a> a whirl. It’s fast, sleek,
and has natural language parsing like the quick add in Google Calendar.</p>

<p>It was simple to get it set up with a normal Gmail app, but in order to get it
working with my Google Apps acct for <code class="language-plaintext highlighter-rouge">jc00ke.com</code> I had to install Evolution. I
got that tip from <a href="https://bugzilla.gnome.org/show_bug.cgi?id=740656">this bug
report</a>. The crux is to leave
Evolution alone once set up. If you remove it, your Google Apps integration with
California will also disappear. I’m sure it’ll get fixed soon.</p>

<h2 id="outro">Outro</h2>

<p>So far I’m enjoying the speed and minimal system resources by switching to
Pidgin, Geary and California. The native notifications have been missed too!</p>

<p><img src="http://jc00ke.com/assets/posts/going-native-pidgin-geary-and-california/notification-example.png" alt="notify-send
example" /></p>
]]></description>
      <pubDate>Thu, 26 Mar 2015 00:00:00 -0700</pubDate>
      <link>http://jc00ke.com/2015/03/26/going-native-pidgin-geary-and-california/</link>
      <guid isPermaLink="true">http://jc00ke.com/2015/03/26/going-native-pidgin-geary-and-california/</guid>
    </item>
    <item>
      <title>Fixing preferred browser in XFCE</title>
      <description><![CDATA[<p>At some point my preferred browser got out of sync. By this I mean I installed
Chrome unstable and Firefox, and different apps would open different browsers.
Clicking on a link in the terminal would open Firefox even though (stable)
Chrome was my preferred browser.</p>

<p>After a little digging I found <a href="https://bugs.launchpad.net/ubuntu/+source/chromium-browser/+bug/794720/comments/22">this
comment</a>
on the Ubuntu bug tracker and it helped sort out my preferences.</p>

<figure class="highlight"><pre><code class="language-diff" data-lang="diff"><span class="gd">--- /usr/share/applications/defaults-old.list 2015-03-25 10:25:14.905796546 -0700
</span><span class="gi">+++ /usr/share/applications/defaults.list 2015-03-25 10:27:02.195005915 -0700
</span><span class="p">@@ -271,6 +271,6 @@</span>
 text/xml=firefox.desktop;google-chrome.desktop;google-chrome-unstable.desktop
 application/xhtml_xml=google-chrome.desktop;;google-chrome-unstable.desktop
 image/webp=google-chrome.desktop;;google-chrome-unstable.desktop
<span class="gd">-x-scheme-handler/http=firefox.desktop;google-chrome.desktop;google-chrome-unstable.desktop
-x-scheme-handler/https=firefox.desktop;google-chrome.desktop;google-chrome-unstable.desktop
</span><span class="gi">+x-scheme-handler/http=google-chrome-unstable.desktop;google-chrome.desktop;firefox.desktop
+x-scheme-handler/https=google-chrome-unstable.desktop;google-chrome.desktop;firefox.desktop
</span> x-scheme-handler/ftp=google-chrome.desktop;;google-chrome-unstable.desktop</code></pre></figure>

<figure class="highlight"><pre><code class="language-diff" data-lang="diff"><span class="gd">--- /etc/gnome/defaults-old.list 2015-03-25 10:24:45.492371994 -0700
</span><span class="gi">+++ /etc/gnome/defaults.list 2015-03-25 10:26:01.676061182 -0700
</span><span class="p">@@ -259,6 +259,6 @@</span>
 x-content/image-picturecd=shotwell.desktop
 zz-application/zz-winassoc-xls=libreoffice-calc.desktop
 x-scheme-handler/apt=ubuntu-software-center.desktop
<span class="gd">-x-scheme-handler/http=firefox.desktop
-x-scheme-handler/https=firefox.desktop
</span><span class="gi">+x-scheme-handler/http=google-chrome-unstable.desktop
+x-scheme-handler/https=google-chrome-unstable.desktop
</span> x-scheme-handler/mailto=thunderbird.desktop</code></pre></figure>

<p>I also noticed that Firefox had taken over <code class="language-plaintext highlighter-rouge">text/xml</code> and that Chrome was set to
open <code class="language-plaintext highlighter-rouge">image/webp</code> so I fixed those too. This is all a bit of a PITA, and
counter-intuitive to how preferred apps should work. I should set them in one
place and all apps should read from that source.</p>

<p>Anyway, hope this helps.</p>

<h2 id="update">Update</h2>

<p>Turns out Firefox kept hold of certain things, so I uninstalled it. Didn’t use
it much anyway.</p>
]]></description>
      <pubDate>Wed, 25 Mar 2015 00:00:00 -0700</pubDate>
      <link>http://jc00ke.com/2015/03/25/fixing-preferred-browser-in-xfce/</link>
      <guid isPermaLink="true">http://jc00ke.com/2015/03/25/fixing-preferred-browser-in-xfce/</guid>
    </item>
    <item>
      <title>Patching xdg-open for magnet links</title>
      <description><![CDATA[<p><code class="language-plaintext highlighter-rouge">xdg-open</code> doesn’t set the correct <code class="language-plaintext highlighter-rouge">$DE</code> variable, so the wrong open function
gets called. Here’s a simple patch to <code class="language-plaintext highlighter-rouge">/usr/bin/xdg-open</code> to fix it.</p>

<p><img src="http://jc00ke.com/assets/posts/patching-xdg-open-for-magnet-links/xdg-open-gist-diff.png" alt="diff" /></p>

<p>Apologies for the image, I could’t figure out how to embed just the relevant
diff. <a href="https://gist.github.com/jc00ke/26a97113bcf21b8e05a7/revisions">Here’s</a> the whole
shebang.</p>
]]></description>
      <pubDate>Sun, 22 Mar 2015 00:00:00 -0700</pubDate>
      <link>http://jc00ke.com/2015/03/22/patching-xdg-open-for-magnet-links/</link>
      <guid isPermaLink="true">http://jc00ke.com/2015/03/22/patching-xdg-open-for-magnet-links/</guid>
    </item>
  </channel>
</rss>
