Matt Moriarity

October 2018



Apparently today's the day I try to figure out if I can bring up my own Kubernetes cluster from scratch. I'm terrified.



I started going through the Elixir tutorial last night. This is a very cool language with interesting ideas. Processes seem like a really cool way to model state.


Is it just me or are the Archie plots in Riverdale always the worst?


Never in my life would I have predicted that Elon Musk would go this far off the rails. You couldn't write this into a TV show and have it be even remotely believable.


Just finished my mission of finishing every single shrine in Breath of the Wild!


Destroying those first two things is half the point of single payer; it's a feature!


A big gap in Swift right now is I/O. Seems like there should be a good protocol-based solution for it, but it's not there right now: everything is in Foundation, and it doesn't feel super-Swifty.


Got my Scrabble keycaps and they look amazing. Once I'm less sick, I'll take a good picture and post it.



GitHub Universe did totally get me sick, so I'm going to have to be sick on a plane and that sounds like no fun.



Apparently AirBnB's frontend auth service is called "Hunter2" and that is just 👌


If you're at GitHub Universe, stop by the Travis CI lounge and say hi!



Okay how do I merge cells in NSGridView in Interface Builder? The option is always grayed out. I'm admitting defeat, please help.


This new twenty one pilots album is really good, and only getting better with more listens.



I'm slowly but surely cobbling together a Fastlane setup for distributing a Mac app on Travis CI. Learning many lessons along the way. This is really painful, though: there's a lot of opportunity to make this so much easier.


I had no idea how few resources are out there for distributing Mac apps in a CI/CD workflow. Everything is for iOS!


It seems to be completely random whether Ctrl-C in docker-compose will (a) stop the containers, (b) kill the containers, or (c) abort docker-compose entirely. Wat?


Muffins are just getting away with eating literal cake for breakfast.




Taking good care of yourself is surprisingly challenging sometimes.


Using Stripe Checkout in an Elm 0.19 App

I'm currently working on a web project whose frontend is written in Elm. The project uses Stripe for handling payments. I ❤️ Stripe: it makes billing much easier for me and lets me mostly focus on the more unique aspects of the project.

For now, I'm using Stripe Checkout, the simplest way to get payment details into Stripe. With Stripe Checkout, Stripe's JavaScript creates the form for getting payment details from the user, and it shows that form in a modal window over your page. When the user submits the form, it talks to Stripe, gives you a token representing the payment details, and sends that to an endpoint on your server.

Integrating Stripe Checkout in Elm 0.18

The simplest way to use Stripe Checkout is to make an HTML form and put a script tag inside it, with data attributes to customize the payment form. This is what I was doing with my app when I was using Elm 0.18:

stripeButton : Model -> Html Message
stripeButton model =
    Html.form
        [ action "/subscribe"
        , method "POST"
        ]
        [ node "script"
            [ src "https://checkout.stripe.com/checkout.js"
            , class "stripe-button"
            , attribute "data-key" model.stripeKey
            , attribute "data-name" "My Product"
            , attribute "data-description" "Description of my product"
            , attribute "data-amount" "500"
            , attribute "data-zip-code" "true"
            ]
            []
        , button [ type_ "submit", class "button is-link is-medium" ]
            [ icon Solid "credit-card"
            , span [] [ text "Subscribe for $5/mo" ]
            ]
        ]

Using a custom HTML node to include a script tag in an Elm app is admittedly pretty dirty. But it's relatively contained and it was working fine. The button there is actually a bit of a hack. Stripe Checkout will render its own button in the form, but it doesn't look great with the rest of my UI, so there's CSS to hide the Stripe button. As long as this button submits the same form, it's just as good, and I can customize it to look how I want.

Elm 0.19 ruins the fun

Elm 0.19 is pretty disruptive: it changes a lot about how the language and many of its core libraries work. I went through the pretty gnarly upgrade process and thought I was in the clear. After all, one of the nice things about Elm is that once you get it compiling, you've usually caught most of your problems.

In this one case, though, the upgrade had introduced a silent failure: my payment button didn't work anymore! Instead of opening Stripe's payment form, clicking the button just submitted the form (without any payment info), which then gave an error. Not what I wanted at all.

I'll spare you the hours of diagnosis and just tell you what the problem was: Elm 0.19 is fundamentally incapable of putting a script tag in HTML. A script node will get silently converted to a p node to prevent cross-site scripting attacks at the language level. Since the virtual-dom is generated with a Native module, and in Elm 0.19 third-party Native modules are no longer supported, there's no way around this limitation. It's a deliberate design decision. Even if we could work around it, we'd be fighting the future of the language, so instead let's figure out a way to use Stripe Checkout without fighting Elm.

Ports to the rescue!

Elm does have a way to work with normal JavaScript code, and it's pretty clever. It's called "ports," and it's clever because it provides a way to send messages to and from JavaScript without breaking the functional nature and safety of Elm. Incoming messages from JavaScript become Messages which you handle in your update function, just like the ones your app creates to handle DOM events and HTTP responses. Outgoing messages are sent as commands, just like sending HTTP requests.

To implement Stripe Checkout, we can declare our Main module as a port module, and declare two ports for our page:

port module Page.Account.Main exposing (main)

{- imports here -}

port openPaymentForm : () -> Cmd msg
port createSubscription : (Encode.Value -> msg) -> Sub msg

openPaymentForm is an outgoing port, which will tell our JavaScript code to open the Stripe Checkout payment form. createSubscription is an incoming port: JavaScript code will send us messages through this port when the

These are just declarations, though. Elm will synthesize implementations to handle the interaction with the JavaScript code. But even so, these are just pure functions as they are. They won't do anything until we use them in our app.

Before we can do that, we'll need two messages in our Message type:

type Message
    = ...
    | OpenPaymentForm
    | CreateSubscription Encode.Value
    | ...

OpenPaymentForm gives our view a way to send the openPaymentForm command. CreateSubscription is the message we'll receive with payment data from Stripe's JavaScript.

We now need to add cases for these messages to our update function:

update message model =
    case message of
        ...

        OpenPaymentForm ->
            ( model, openPaymentForm () )

        CreateSubscription value ->
            handleCreateSubscription value model

        ...

The OpenPaymentForm message just fires off the openPaymentForm command for our port. Handling the CreateSubscription message is more complex, mostly due to having to decode JSON data coming from JavaScript:

paymentDecoder : Decoder ( String, String )
paymentDecoder =
    Decode.map2 Tuple.pair
        (Decode.field "email" Decode.string)
        (Decode.field "id" Decode.string)


handleCreateSubscription : Encode.Value -> Model -> ( Model, Cmd Message )
handleCreateSubscription value model =
    case Decode.decodeValue paymentDecoder value of
        Ok ( email, token ) ->
            ( model
            , Http.send SubscriptionCreated
                (Request.User.createSubscription email token)
            )

        Err _ ->
            ( model, Cmd.none )

We create a JSON decoder for the data we expect to receive from our createSubscription port. In this case, it's a JSON object with two fields we care about: id and email. These are provided to us by Stripe Checkout. We decode these into a pair of values, and then send off an HTTP request to our backend server to create the subscription using the information we got from Stripe. The implementation of Request.User.createSubscription isn't super important here: it's normal Elm HTTP request code.

Finally, in order to actually receive CreateSubscription messages, we need to add the port to our page's subscriptions:

subscriptions model =
    createSubscription CreateSubscription

Note that we provide a constructor function to the port to be able to build a message of our app's message type from the provided JSON-encoded value coming in from the port.

That's all we have to do on the Elm side of things, but of course, nothing will happen from this until we actually write some JavaScript.

Sprinkle in some JavaScript

Stripe Checkout actually supports being used in two different ways. The first is what we did in Elm 0.18: create a form and embed a script inside it that will wire up some events for us. We could technically still use that here, but there's a much cleaner way now that we're in a position to write a little bit of JavaScript.

Stripe Checkout provides a small JavaScript API to both open a payment form and define how to handle the generated payment token. Those two things correspond to the ports we declared for our Elm page, so let's wire those together:

const stripeKey = "<your stripe publishable key>"
const flags = { stripeKey }
const app = Elm.Page.Account.Main.init({ flags })

const handler = StripeCheckout.configure({
  key: stripeKey,
  locale: 'auto',
  zipCode: true,
  token(token) {
    app.ports.createSubscription.send(token)
  }
})

app.ports.openPaymentForm.subscribe(() => {
  handler.open({
    name: 'My Product',
    description: 'Description of my product',
    amount: 500
  })
})

Each port we declared in our Main module becomes a JavaScript object on app.ports. For a port going from Elm to JavaScript, like openPaymentForm, we can use the subscribe method in JavaScript to be notified when the command is sent from Elm. We use this to tell Stripe Checkout to open the payment form.

For a port going from JavaScript to Elm, like createSubscription, we use the send method to feed data into the subscription on the Elm side. We use this in the token callback we provide to Stripe Checkout, which is called when the user submits the payment form. This gives us the data we need to be able to tell our Elm app to create a new subscription for the user.

That's it! That's all the JavaScript we need to write for this.

Is this an improvement?

We may have been forced to make this change due to new restrictions in Elm, but I think it's worth asking: is our code better than when we started? Yes it is! Despite being more code, I think this Elm 0.19 solution is better than the Elm 0.18 version for a number of reasons:

  • There is no DOM manipulation happening outside of Elm.
  • All of our page interactions are going through Messages and Commands.
  • Elm gets to handle the API request for subscribing, rather than having to use an HTML form submission.
  • The separation of concerns is clearer, as the view code no longer needs to know how the payment form is opened or where to submit it.

The main benefit here is consistency. Before this change, getting payment info was a huge special case in the app, implemented completely differently from things that should have been similar. Now the implementation is much more like any other interaction happening in the app. The small piece that needs to be different is tucked away in a little JavaScript behind a small façade. That's a huge improvement.

Having done it both ways, I would recommend using the ports approach even if you are still using Elm 0.18. It's a better design that I think will serve you well, and it shouldn't require any changes from what I've described here.


Finished Ancillary Sword the other day and I gotta say it was way more exciting than Ancillary Justice. That world and it's characters took an entire book to warm up, and then book 2 got to be this amazing thrill ride. Loved it!


How I fixed my Apache SSL redirect

Today, I finally fixed a longstanding issue with this website. I figured it would be a good idea to document it since I could not find this solution in any of my Googling to try to figure out what was wrong.

mattmoriarity.com is canonically served over SSL, but it's supposed to have a redirect from plain HTTP URLs to the corresponding HTTPS URL. For a long time now, if you went to http://mattmoriarity.com, instead of getting redirected, you would get a nice big 403 Forbidden error from my Apache server.

When this error occurred, an entry would appear in Apache's error.log:

[Sat Oct 06 16:43:20.907682 2018] [authz_core:error] [pid 5372] [client 123.123.123.123:12345] AH01630: client denied by server configuration: /var/www/html/

I banged my head against this for a while, because in theory, my virtual host for the site was configured as expected:

<VirtualHost *:80>
    ServerName mattmoriarity.com
    ServerAlias www.mattmoriarity.com

    Redirect permanent / https://mattmoriarity.com/
</VirtualHost>

Searching the error code from the log above gave many results, but all of those results suggested one main cause: in Apache 2.4, the configuration directives for allowing and denying access to directories changed. For instance, Allow from all becomes Require all granted and so on. This was not my problem, though: all of my configuration was using the correct Apache 2.4 syntax.

My best clue was the fact that the redirect worked fine if I accessed it from www.mattmoriarity.com. It only failed when I left off the www.. This was good: it means that the virtual host was working correctly when it matched. It just wasn't matching when should.

It turns out that the global configuration for Apache essentially forms its own virtual host. So I found the issue in a tiny file called /etc/apache2/conf-enabled/fqdn.conf, which contained only this line:

ServerName mattmoriarity.com

By declaring the ServerName globally, the global virtual host was matching requests for the host mattmoriarity.com on port 80 instead of my declared virtual host. And now the error in the log made sense: /var/www/html/ was the DocumentRoot declared globally.

By removing this line of configuration, my declared virtual host now matched, and the redirect started working.

Hopefully this helps someone else who finds themselves with the same problem!


I forgot how obnoxious Andy is on The Office when he's introduced to the show.



I can't imagine being an educator right now trying to teach kids about checks and balances like that's a real thing we actually have in this country and not pure fantasy to help us sleep at night.


Every single app uses way too much memory. All of them. Every single one.


Feeling pretty bad at computers when I can't even make Go copy a file correctly.

Update: Turns out that Go puts the arguments to copy with the destination first. Since Files are readers and writers, getting them backwards is not a type error.


Oh no! Elm 0.19 automatically converts script tags to p tags in its virtual DOM, which totally broke my Stripe Checkout button. I don't see a way around it, so I think I have to switch to using ports and Stripe.js for the payment form.




It took me half a day but I managed to upgrade my Elm app to Elm 0.19. I had to ditch some dependencies along the way, but honestly it's better for it in the end.