-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
go-github: add utilities for processing payload messages #294
Conversation
c386db0
to
579682b
Compare
// GenSignature generates a signature for the given payload. | ||
// hashType possible values are "sha1", "sha256", "sha512". | ||
// If hashType is empty or invalid, "sha1" is used. | ||
func GenSignature(payload, secretKey []byte, hashType string) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need this function? I can't think of a case where a user of the go-github library should ever need to generate a signature. I know that you're using it in tests below, but I actually think we should use hardcoded, known signature values for tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM. I'll remove it.
Files updated. PTAL. |
would love to use this. |
Remove most of messages/* when google/go-github#294 ships.
@willnorris Any update here? 🙏 FWIW, I am using this code and it works brilliantly. I'd just love to see it in |
sha256Prefix = "sha256" | ||
sha512Prefix = "sha512" | ||
// eventHeader is the Github header key used to pass the event type. | ||
eventHeader = "X-Github-Event" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this should be X-GitHub-Event
, with the capital H
in GitHub
. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same change should probably be applied to the comments too; the canonical brand name spelling is "GitHub", not "Github". But if that's a wider problem than just in this PR, it might be acceptable to address it in a different PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@parkr - It turns out that canonical headers don't work that way. You can verify this yourself using curl
or bat
.
Here is an example response I just got from the GitHub API:
X-Github-Request-Id : 68840050:7F91:291081F8:5755B423
X-Github-Media-Type : github.v3
I tried searching for the RFC
that defines this but came up empty. I'm sure it is out there somewhere.
As for the comments correcting the brand name spelling... yes, that could all be cleaned up by someone.
edit: I'll go ahead and clean that up for this new PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out that with all the code I removed from the PR, that those header constants were no longer needed anyway, so I removed them.
81e76a2
to
1cb50ac
Compare
@shurcooL - when you get a chance, could you PTAL? |
|
||
// ValidatedPayload validates an incoming GitHub Webhook event request | ||
// and returns the (JSON) payload. | ||
// secretKey is the GitHub Webhook secret message. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a lot of context on how ValidatedPayload
is meant to be used (perhaps it's a good idea to provide an example). So I have the following question.
The client must close the response body when finished with it
Looking at the implementation, I see that ValidatedPayload reads the request body. It does not close the request body.
Is the user expected to close the request body after calling ValidatedPayload
?
Also, ValidatedPayload
is not documented in a way that makes it clear it will read the request body. Perhaps it can be inferred from "validates the request, returns JSON payload". But maybe it should be explicitly stated that it reads the request body and doesn't close it, if it's indeed the user's responsibility to close it?
Or should it close the request body itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, obviously some more comments are needed. ValidatePayload
will be used by a server and GitHub will send events to it. A server does not close the response body... only clients do that, and in this case, GitHub is the client.
Edit: that was poorly worded. I should have said that the http.Server
will close the request body for us, so the handler doesn't need to.
How about if I add the comment:
// ValidatePayload is called by the server and therefore does not need to close the request body.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but here we're talking about a request body, not a response body. Isn't it the server's job to close that when finished reading? I'm not sure how strict that needs to be with requests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In https://godoc.corp.google.com/pkg/net/http it says:
// For server requests the Request Body is always non-nil
// but will return EOF immediately when no body is present.
// The Server will close the request body. The ServeHTTP
// Handler does not need to.
So I don't think it needs closing. Do you agree?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, I agree. That sounds pretty clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I completely missed that this is being done on inbound server requests. Right, this is for webhooks, so GitHub is making the request to user code, and this func is used to validate GitHub's incoming request.
How about if I add the comment:
// ValidatePayload is called by the server and therefore does not need to close the request body.
Do you think this comment is helpful and clear? I'm not sure. It almost raises more questions than answers, like "by what server"? It could be the HTTP server that the user is running, or GitHub's server.
If you think it's clear, then feel free to leave it as is.
Otherwise, I think it's completely fine to just remove it. The net/http
package covers this pretty well, so I don't think it's needed to repeat it. As long as people realize that ValidatePayload
is used to validate requests coming from GitHub. To that end, if issue #361 is going to be resolved by adding a short example of ValidatePayload
being used somewhere, then that's even more reason to leave this out. I think seeing ValidatePayload
used in context of http.HandleFunc
makes it very clear:
http.HandleFunc("/hook", func(w http.ResponseWriter, req *http.Request) {
payload, err := github.ValidatePayload(req, ghWebhookSignature)
if err != nil {
log.Println(err)
http.Error(w, "invalid signature", http.StatusForbidden)
return
}
// Process payload ...
})
This is really nitpicky so feel free to ignore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM. I've removed the unclear text and replaced with an example to address #361.
I've spotted one issue with the request body and/or documentation. Aside from that, I'm not seeing any other issues. I think if we resolve that, this will have my LGTM. |
return errors.New("payload signature check failed") | ||
} | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, what's the difference between ValidatedPayload
and ValidateSignature
? Is it intentional that one uses adjective "validated" and the other uses verb "validate"? It seems unintentional, since they are both phrased as "X validates ...":
// ValidatedPayload validates ...
// ValidateSignature validates ...
The more exported symbols there are, the harder the API is to learn and to use (users will need to learn both, and figure out which one is more appropriate for them to use). Is it beneficial to have both of them exported, or can we make one of them unexported?
ValidatedPayload
looks to be a simple wrapper on top of ValidateSignature
and does not really do anything different. It really looks to me that we can make one of them unexported and improve the API. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM. I will stop exporting validateSignature
and rename the other to ValidatePayload
.
@shurcooL - I believe I addressed your comments. PTAL. |
I've looked at the updates, and all changes look great. I've left one more comment about the request body closing misunderstanding here. You can optionally address that. LGTM. |
Cool, thanks for your reviews, @shurcooL - I appreciate it! |
Fixes google#361. Change-Id: I1c80b8eb7816efc9b83e6b8be956430c68809d5e
Change-Id: I1c80b8eb7816efc9b83e6b8be956430c68809d5e