ring

Crispin 2020-09-11T04:21:48.006Z

Hi there everyone. I'm trying to write a ring middleware that will check a stripe webhook callback's signature. The signature is in the header. Can get that fine. But I need to verify it by comparing it with the raw body, as that is what is signed. The raw body is json. Then if it passes, future middleware will decode the json.

Crispin 2020-09-11T04:22:31.006800Z

The issue is that body is presented as a stream. And if I slurp the stream, then future json middleware gets an empty body content, and the stream has been consumed

Crispin 2020-09-11T04:23:04.007300Z

how do I verify a header signature against the raw body contents, without consuming the stream?

Crispin 2020-09-11T04:23:11.007600Z

any ideas on the best approach?

Crispin 2020-09-11T04:27:36.008100Z

is the best way to create a new stream and push the contents back onto it? or is there an easier way?

Crispin 2020-09-11T04:55:39.008500Z

Ok. I made this test and it seems to work:

Crispin 2020-09-11T04:56:46.008800Z

(defn wrap-test [handler]
  (fn
    ([request]
     (log/info "wrap-test/1")
     (let [content (slurp (:body request))]
       (log/info "body is" content)
       (handler (assoc request :body (io/input-stream (.getBytes content))))))
    ([request respond raise]
     (log/info "wrap-test/3")
     (let [content (slurp (:body request))]
       (log/info "body is" content)
       (handler (assoc request :body (io/input-stream (.getBytes content))) respond raise)))))

Crispin 2020-09-11T04:57:31.009600Z

slurps the body... but then creates a new body for subsequent processing by creating a input-stream from the contents

Crispin 2020-09-11T04:57:46.010Z

I will proceed with this, but if there is a better way please let me know

Crispin 2020-09-11T05:20:44.010700Z

I guess I would have to be careful of a DoS attack with this of someone sending a multi terrabyte body...?

jumar 2020-09-11T14:27:54.011400Z

Why don't you validate only after it's read as JSON? And do you really need a middleware? Do you have more than one stripe webhook route?

Crispin 2020-09-12T12:13:31.018400Z

> Why don't you validate only after it's read as JSON?

Crispin 2020-09-12T12:13:42.018600Z

because I have no access to the raw body at that stage

Crispin 2020-09-12T12:14:31.018800Z

and the signature is of the raw body, not of the decoded json. Even if I re-encoded the json, its not garunteed to be byte for byte identical

Crispin 2020-09-12T12:14:54.019Z

> Do you have more than one stripe webhook route?

Crispin 2020-09-12T12:14:56.019200Z

yes

Crispin 2020-09-12T12:15:04.019400Z

actually no.

Crispin 2020-09-12T12:15:21.019600Z

sorry. only one route. but multiple messages

Crispin 2020-09-12T12:15:53.019800Z

I guess I could just process it raw then without any middleware at all... :thinking_face: