Skip to content

Instantly share code, notes, and snippets.

@a-h
Created July 4, 2016 21:45
Show Gist options
  • Select an option

  • Save a-h/1e808eff8bf795130bb656cbeb9a4db0 to your computer and use it in GitHub Desktop.

Select an option

Save a-h/1e808eff8bf795130bb656cbeb9a4db0 to your computer and use it in GitHub Desktop.
Middleware to Hash a HTTP Request
package sign
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"io/ioutil"
"net/http"
"net/http/httptest"
)
// Handler is the http.Handler implementation for the Signature Handler.
type Handler struct {
next http.Handler
saltExtractor func(body string) (salt string)
}
// NewHandler creates a HTTP handler which receives the request and wraps the next handler.
// The output is modified to include a signature header.
func NewHandler(extraData string, next http.Handler) *Handler {
return &Handler{
next: next,
saltExtractor: defaultSaltExtractor,
}
}
func defaultSaltExtractor(body string) string {
return body
}
func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Read the body in.
buf, _ := ioutil.ReadAll(req.Body)
body := string(buf)
salt := h.saltExtractor(body)
// Set the body again for the next handler.
req.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
//TODO: Read the request and pull out the signature source id from the header or JSON body.
// Record the response.
// Based on https://justinas.org/writing-http-middleware-in-go/
rec := httptest.NewRecorder()
h.next.ServeHTTP(rec, req)
// Copy the response from the recording, with the modifications.
for k, v := range rec.Header() {
w.Header()[k] = v
}
// Add the hash of the response body.
//TODO: Turn this into a signature of the salt + body.
hash := calculateHash(rec.Body.Bytes(), []byte(salt))
w.Header().Set("X-Hash", hash)
// Then the status code, as this call writes out the headers
w.WriteHeader(rec.Code)
// Write out the original body.
w.Write(rec.Body.Bytes())
}
func calculateHash(body []byte, salt []byte) string {
combined := append(body, salt...)
hash := sha256.Sum256(combined)
return hex.EncodeToString(hash[:])
}
package main
import (
"net/http"
"github.com/a-h/gosign/sign"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
handler := &testHandler{}
signer := sign.NewHandler("test", handler)
r.Handle("/", signer)
http.ListenAndServe(":8080", r)
}
type testHandler struct {
}
func (th *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("This is a catch-all route"))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment