Move signature validation for websub to own file
This commit is contained in:
parent
2d39edac8e
commit
dc557efde9
|
|
@ -2,15 +2,14 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha1"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
"p83.nl/go/ekster/pkg/websub"
|
||||||
)
|
)
|
||||||
|
|
||||||
type incomingHandler struct {
|
type incomingHandler struct {
|
||||||
|
|
@ -85,8 +84,9 @@ func (h *incomingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
// match signature
|
// match signature
|
||||||
sig := r.Header.Get("X-Hub-Signature")
|
sig := r.Header.Get("X-Hub-Signature")
|
||||||
if sig != "" {
|
if sig != "" {
|
||||||
if err := isHubSignatureValid(sig, feedContent, secret); err != nil {
|
if err := websub.ValidateHubSignature(sig, feedContent, []byte(secret)); err != nil {
|
||||||
http.Error(w, fmt.Sprintf("Error in signature: %s", err), 400)
|
log.Printf("could not validate signature: %+v", err)
|
||||||
|
http.Error(w, fmt.Sprintf("could not validate signature: %s", err), 400)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -94,32 +94,9 @@ func (h *incomingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
ct := r.Header.Get("Content-Type")
|
ct := r.Header.Get("Content-Type")
|
||||||
err = h.Backend.UpdateFeed(feed, ct, bytes.NewBuffer(feedContent))
|
err = h.Backend.UpdateFeed(feed, ct, bytes.NewBuffer(feedContent))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, fmt.Sprintf("Unknown format of body: %s (%s)", ct, err), 400)
|
http.Error(w, fmt.Sprintf("could not update feed: %s (%s)", ct, err), 400)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func isHubSignatureValid(sig string, feedContent []byte, secret string) error {
|
|
||||||
parts := strings.Split(sig, "=")
|
|
||||||
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return fmt.Errorf("signature format is not like sha1=signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
if parts[0] != "sha1" {
|
|
||||||
return fmt.Errorf("signature format is not like sha1=signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
// verification
|
|
||||||
mac := hmac.New(sha1.New, []byte(secret))
|
|
||||||
mac.Write(feedContent)
|
|
||||||
signature := mac.Sum(nil)
|
|
||||||
|
|
||||||
if fmt.Sprintf("%x", signature) != parts[1] {
|
|
||||||
return fmt.Errorf("signature does not match feed %s %s", signature, parts[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
41
pkg/websub/signature.go
Normal file
41
pkg/websub/signature.go
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
package websub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateHubSignature validate a sha1 signature that could be send with the
|
||||||
|
// hub as an extra header
|
||||||
|
func ValidateHubSignature(sig string, feedContent, secret []byte) error {
|
||||||
|
parts := strings.Split(sig, "=")
|
||||||
|
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return errors.New("signature format is not like sha1=signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
if parts[0] != "sha1" {
|
||||||
|
return errors.New("signature format is not like sha1=signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
// verification
|
||||||
|
mac := hmac.New(sha1.New, secret)
|
||||||
|
mac.Write(feedContent)
|
||||||
|
signature := mac.Sum(nil)
|
||||||
|
|
||||||
|
signature2, err := hex.DecodeString(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "could not decode signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hmac.Equal(signature, signature2) {
|
||||||
|
return fmt.Errorf("signature does not match feed %s %s", signature, parts[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
22
pkg/websub/signature_test.go
Normal file
22
pkg/websub/signature_test.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package websub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateHubSignature(t *testing.T) {
|
||||||
|
secret := []byte("this is a test secret")
|
||||||
|
feedContent := []byte("hello world")
|
||||||
|
|
||||||
|
mac := hmac.New(sha1.New, secret)
|
||||||
|
mac.Write(feedContent)
|
||||||
|
signature := mac.Sum(nil)
|
||||||
|
|
||||||
|
err := ValidateHubSignature(fmt.Sprintf("sha1=%x", signature), feedContent, secret)
|
||||||
|
assert.NoError(t, err, "error should be nil")
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user