Fork me on GitHub
#ring
<
2016-07-24
>
ska16:07:15

Has anyone written a ring middleware to validate github webhook calls as described on https://developer.github.com/webhooks/securing/ ?

ska16:07:52

@malabarba: I found your question regarding the hmac computation in Clojure on SO. Could you please tell me how you hooked it into your webapp? I currently have ring.middleware.defaults/wrap-defaults and ring.middleware.json/wrap-json-body on my handler. I guess that makes hmac computation fail as I need the original body.

malabarba16:07:36

@ska my memory fails me 🙂 Could you link to the question?

malabarba17:07:45

I think you just need to do your hmac computation outside other middlewares

malabarba17:07:52

before the body is parsed

malabarba17:07:56

that's what I did

ska17:07:03

I think, I am already getting close to it. Would you like to join a tiny project on github to provide that middleware?

malabarba17:07:07

Here's the function I wrote:

malabarba17:07:31

I always mess up slack's code-blocks

malabarba17:07:46

(defn wrap-hub-signature
  "Middleware that checks if a page asked for authentication."
  [handler]
  (fn [{:keys [headers request-method], :as request}]
    (if (and (= request-method :post)
             (headers "x-hub-signature"))
      (let [body (slurp (:body request))]
        (or (when (= (hmac body) (headers "x-hub-signature"))
              (when-let [json-body (try (json/parse-string body true)
                                        (catch JsonParseException e nil))]
                (handler (assoc request :hub-signature-verified true
                                :body json-body
                                :params json-body))))
            {:status  400
             :headers {"Content-Type" "text/plain"}
             :body    "Malformed JSON in request body."}))
      (handler request))))

malabarba17:07:59

Note that I (slurp (:body request)) manually

malabarba17:07:33

obviously this only works if the body hasn't been slurped yet

ska17:07:44

Yeah, seen it. Crossing our fingers it will never OOm

malabarba17:07:21

If I'm not mistaken, I just borrowed the code used by the default ring middlware

ska17:07:53

I am writing my own because I need to cover the case that the webapp can have several secret tokens configured.

malabarba17:07:56

Though we're talking 1 year ago, and my memory has a half-life of 1 month

malabarba17:07:02

that complicates things

malabarba17:07:16

several secret tokens for github signing?

malabarba17:07:21

How do you decide which to use?

ska17:07:20

I don't mind as long as anyone validates 🙂

ska17:07:29

I am preparing a gist at the moment...

malabarba17:07:13

Have you tested it?

malabarba17:07:26

I'm not sure if calling .getBytes multiple times on the body will work

malabarba17:07:34

Some streams can only be retrieved once

ska18:07:57

No, not tested a single run. That is 45 lines or written-only code so far 🙂 My testing setup is more complex. I need to deploy an uberjar to an EC2 instance and make sure that I get all information I need to test it. 😉

ska18:07:54

I do have some old recorded requests but only after wrap-json and stuff. Does not help a lot for this.

ska18:07:33

If I make my handler the first in the chain, reading the body is a problem: the :body element is a org.eclipse.jetty.server.HttpInputOverHTTP which does not have a .getBytes method.

malabarba19:07:04

In my case I just slurped the body, and called getBytes on the string

malabarba19:07:51

Might be safest to specify an Encoding for the string

malabarba19:07:08

but for me it Just Worked ™️

ska21:07:13

I think, I can make it work for my reduced use-case. Turning it into something generic and a library would be more work, though. I wonder how the JSON middleware gets away with just slurping the string.

malabarba21:07:04

maybe ring itself handles any length issues directly in the input stream

malabarba21:07:36

You could post an issue asking about that

malabarba21:07:48

Though I'd recomend to actually check their code first

malabarba21:07:11

I *think* I borrowed that slurp from the middleware, but I wouldn't bet my life on it. 🙂