Skip to content

Commit 9488332

Browse files
committed
move webhook signature checking logic out of parse_exn
With repo-specific secrets, we'll need the repo name in order to obtain the webhook token used for signature validation. So parsing the request body for a GH payload needs to happen before, not after, the signature check.
1 parent 40b3c1d commit 9488332

File tree

3 files changed

+14
-11
lines changed

3 files changed

+14
-11
lines changed

lib/action.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,12 @@ module Action (Github_api : Api.Github) (Slack_api : Api.Slack) = struct
208208
let process_github_notification (ctx : Context.t) headers body =
209209
try%lwt
210210
let secrets = Context.get_secrets_exn ctx in
211-
match Github.parse_exn ~secret:secrets.gh_hook_token headers body with
211+
match Github.parse_exn headers body with
212212
| exception exn -> Exn_lwt.fail ~exn "failed to parse payload"
213213
| payload ->
214+
match Github.validate_signature ?signing_key:secrets.gh_hook_token ~headers body with
215+
| Error e -> action_error e
216+
| Ok () ->
214217
( match%lwt refresh_repo_config ctx payload with
215218
| Error e -> action_error e
216219
| Ok () ->

lib/github.ml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,16 @@ let is_valid_signature ~secret headers_sig body =
6464
let (`Hex request_hash) = Hex.of_string request_hash in
6565
String.equal headers_sig (sprintf "sha1=%s" request_hash)
6666

67+
let validate_signature ?signing_key ~headers body =
68+
match signing_key with
69+
| None -> Ok ()
70+
| Some secret ->
71+
match List.Assoc.find headers "x-hub-signature" ~equal:String.equal with
72+
| None -> Error "unable to find header x-hub-signature"
73+
| Some signature -> if is_valid_signature ~secret signature body then Ok () else Error "signatures don't match"
74+
6775
(* Parse a payload. The type of the payload is detected from the headers. *)
68-
let parse_exn ~secret headers body =
69-
begin
70-
match secret with
71-
| None -> ()
72-
| Some secret ->
73-
match List.Assoc.find headers "x-hub-signature" ~equal:String.equal with
74-
| None -> Exn.fail "unable to find header x-hub-signature"
75-
| Some req_sig -> if not @@ is_valid_signature ~secret req_sig body then failwith "request signature invalid"
76-
end;
76+
let parse_exn headers body =
7777
match List.Assoc.find_exn headers "x-github-event" ~equal:String.equal with
7878
| exception exn -> Exn.fail ~exn "unable to read x-github-event"
7979
| "push" -> Push (commit_pushed_notification_of_string body)

test/test.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ let get_mock_payloads () =
2222
let process ~(secrets : Config_t.secrets) ~config (kind, path, state_path) =
2323
let headers = [ "x-github-event", kind ] in
2424
let make_test_context event =
25-
let repo = Github.repo_of_notification @@ Github.parse_exn ~secret:secrets.gh_token headers event in
25+
let repo = Github.repo_of_notification @@ Github.parse_exn headers event in
2626
let ctx = Context.make () in
2727
ctx.secrets <- Some secrets;
2828
ignore (State.find_or_add_repo ctx.state repo.url);

0 commit comments

Comments
 (0)