Skip to content

Commit eecff7e

Browse files
committed
feature: add hmac auth and exception handling
1 parent bcf7ca8 commit eecff7e

File tree

2 files changed

+55
-22
lines changed

2 files changed

+55
-22
lines changed

deps.edn

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{:deps {org.clojure/clojure {:mvn/version "1.10.3"}
22
org.clojure/core.match {:mvn/version "1.0.0"}
3-
org.clojure/tools.logging {:mvn/version "1.2.4"}
3+
com.taoensso/timbre {:mvn/version "5.2.1"}
44
cheshire/cheshire {:mvn/version "5.10.2"}
55
http-kit/http-kit {:mvn/version "2.5.3"}
66
twitter-api/twitter-api {:mvn/version "1.8.0"}
7-
jarohen/chime {:mvn/version "0.3.3"}}
7+
jarohen/chime {:mvn/version "0.3.3"}
8+
failjure/failjure {:mvn/version "2.2.0"}}
89
:aliases {:deploy {:extra-deps {slipset/deps-deploy {:mvn/version "0.2.0"}}
910
:main-opts ["-m" "deps-deploy.deps-deploy" "deploy" "replikativ-datahike.jar"]}
1011

@@ -25,5 +26,6 @@
2526
:sha "a83ee8da47d56a80b6380cbb6b4b9274048067bd"}
2627
babashka/babashka.curl {:mvn/version "0.1.1"}
2728
babashka/fs {:mvn/version "0.1.2"}
29+
com.google.cloud.tools/jib-core {:mvn/version "0.20.0"}
2830
cheshire/cheshire {:mvn/version "5.10.2"}}
2931
:ns-default build}}}

src/souffleuse/core.clj

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33
[org.httpkit.server :as srv]
44
[org.httpkit.client :as clnt]
55
[clojure.core.match :refer [match]]
6-
[clojure.tools.logging :as log]
6+
[taoensso.timbre :as log]
77
[clojure.string :as str]
88
[cheshire.core :as json]
99
[twitter.oauth :as oauth]
10-
[twitter.api.restful :as r]))
10+
[twitter.api.restful :as r]
11+
[failjure.core :as f])
12+
(:import (javax.crypto Mac)
13+
(javax.crypto.spec SecretKeySpec)))
1114

1215
(def port 3000)
1316

17+
(def github-token (System/getenv "GITHUB_TOKEN"))
18+
1419
(def slack-hook-url (System/getenv "SLACK_HOOK_URL"))
1520
(def slack-channel "#datahike")
1621

@@ -28,6 +33,26 @@
2833
(log/info "Received webhook" d)
2934
d)
3035

36+
(defn hmac-sha-256
37+
"Takes the webhook body as string
38+
Takes the secret webhook token as string
39+
Computes an HMAC
40+
Returns HMAC as string
41+
https://stackoverflow.com/a/15444056"
42+
[^String body-str ^String key-str]
43+
(let [key-spec (SecretKeySpec. (.getBytes key-str) "HmacSHA256")
44+
hmac (doto (Mac/getInstance "HmacSHA256") (.init key-spec))
45+
result (.doFinal hmac (.getBytes body-str))]
46+
(apply str (map #(format "%02x" %) result))))
47+
48+
(defn check-hmac [body-str {:keys [headers]}]
49+
(let [hmac (str "sha256=" (hmac-sha-256 body-str github-token))
50+
header (get headers "x-hub-signature-256")]
51+
(if (not= hmac header)
52+
(throw (ex-info "HMAC does not match" {:hmac hmac
53+
:header header}))
54+
body-str)))
55+
3156
(defn trigger-slack-reminder [_]
3257
(if slack-hook-url
3358
(let [message "In a quarter hour we will have our weekly open-source meeting
@@ -41,9 +66,10 @@
4166
(log/debug "Weekly OSS meeting announcement triggered"))
4267
(log/error "Slack Hook URL not provided")))
4368

44-
(defn trigger-slack-announcement [[release repository :as d]]
69+
(defn trigger-slack-announcement [body]
4570
(if slack-hook-url
46-
(let [message (format "Version %s of %s was just released. Find the changelog or get in contact with us <%s|over on GitHub.>"
71+
(let [[release repository] (juxt body :release :repository)
72+
message (format "Version %s of %s was just released. Find the changelog or get in contact with us <%s|over on GitHub.>"
4773
(:tag_name release)
4874
(:name repository)
4975
(:html_url release))
@@ -53,30 +79,36 @@
5379
(clnt/post slack-hook-url {:headers {"content-type" "application/json"}
5480
:body json}))
5581
(log/error "Slack Hook URL not provided"))
56-
d)
82+
body)
5783

58-
(defn trigger-twitter-announcement [[release repository :as d]]
59-
(let [message (format "Version %s of %s was just released. Take a look at the changelog over on GitHub: %s"
84+
(defn trigger-twitter-announcement [body]
85+
(let [[release repository] (juxt body :release :repository)
86+
message (format "Version %s of %s was just released. Take a look at the changelog over on GitHub: %s"
6087
(:tag_name release)
6188
(:name repository)
6289
(:html_url release))]
6390
(if (not-any? nil? [twitter-api-key twitter-api-secret twitter-access-token twitter-access-token-secret])
6491
(r/statuses-update :oauth-creds twitter-creds
6592
:params {:status message})
6693
(log/error "Twitter secrets not provided")))
67-
d)
94+
body)
6895

6996
;;;;;;;;;;;;;;;;;;;;;;;;;;
7097
;; Handlers
7198
;;;;;;;;;;;;;;;;;;;;;;;;;;
7299

73-
(defn github-hook [{body :body :as req}]
74-
(-> (slurp body)
75-
(json/parse-string true)
76-
log-request
77-
((juxt :release :repository))
78-
trigger-slack-announcement
79-
trigger-twitter-announcement))
100+
(defn github-hook [{:keys [body headers] :as req}]
101+
(let [result (f/ok-> (slurp body)
102+
(check-hmac req)
103+
(json/parse-string true)
104+
log-request
105+
trigger-slack-announcement
106+
trigger-twitter-announcement)]
107+
(if (f/failed? result)
108+
(do (log/error (f/message result) {:delivery (get headers "X-GitHub-Delivery")
109+
:event (get headers "X-GitHub-Event")})
110+
{:status 500 :body (f/message result)})
111+
{:status 201})))
80112

81113
;;;;;;;;;;;;;;;;;;;;;;;;;;
82114
;; Routes
@@ -85,23 +117,22 @@
85117
(defn routes [{:keys [request-method uri] :as req}]
86118
(let [path (vec (rest (str/split uri #"/")))]
87119
(match [request-method path]
88-
[:post ["github" "release"]] {:body (github-hook req)}
120+
[:post ["github" "release"]] (github-hook req)
89121
:else {:status 404 :body "Error 404: Page not found"})))
90122

91123
;;;;;;;;;;;;;;;;;;;;;;;;;;
92124
;; Server
93125
;;;;;;;;;;;;;;;;;;;;;;;;;;
94126

95127
(def server (let [url (str "http://localhost:" port "/")]
96-
(srv/run-server #'routes {:port port})
97-
(println "serving" url)))
128+
(println "serving" url)
129+
(srv/run-server #'routes {:port port})))
98130

99131
(def scheduler (s/start-scheduler trigger-slack-reminder))
100132

101133
(comment
102134
(def payload (json/parse-string (slurp "test/payload.sample.json") true))
103135

104-
(defonce server (atom nil))
105-
(reset! server (srv/run-server #'routes {:port port}))
136+
(srv/server-stop! @server)
106137

107138
@(clnt/post "http://localhost:3000/github/release" {:headers {"Content-Type" "application/json"} :body (slurp "test/payload.sample.json")}))

0 commit comments

Comments
 (0)