blob: bdd8a27ce6d2aef36e0bc0797f5bd47f492f88be [file] [log] [blame]
package webhook
import (
"bytes"
"net/http"
"net/url"
"os"
"testing"
expect "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.skia.org/infra/go/util"
)
const (
TEST_SALT = "notverysecret"
TEST_SALT_BASE64 = "bm90dmVyeXNlY3JldA=="
INVALID_BASE64 = "bm90dmVyeXNlY3JldA!!"
)
func TestSetRequestSaltFromBase64Success(t *testing.T) {
expect.Nil(t, setRequestSaltFromBase64([]byte(TEST_SALT_BASE64)))
expect.Equal(t, []byte(TEST_SALT), requestSalt)
}
func TestSetRequestSaltFromBase64Corrupt(t *testing.T) {
err := setRequestSaltFromBase64([]byte(INVALID_BASE64))
require.Error(t, err)
expect.Contains(t, err.Error(), "illegal base64 data")
}
func TestMustInitRequestSaltFromFileSuccess(t *testing.T) {
f, err := os.CreateTemp("", "webhook_test_salt")
require.NoError(t, err)
defer util.Remove(f.Name())
_, err = f.WriteString(TEST_SALT_BASE64)
require.NoError(t, err)
MustInitRequestSaltFromFile(f.Name())
expect.Equal(t, []byte(TEST_SALT), requestSalt)
}
func TestComputeAuthHashBase64Success(t *testing.T) {
require.NoError(t, setRequestSaltFromBase64([]byte(TEST_SALT_BASE64)))
test := func(input, expected string) {
actual, err := ComputeAuthHashBase64([]byte(input))
expect.NoError(t, err)
expect.Equal(t, expected, actual, "Auth hash of %#v with salt %#v", input, TEST_SALT)
}
// Expected result obtained via:
// $ echo -n '<input>notverysecret' | sha512sum | xxd -r -p | base64
test("", "F+ZnkgguWrbUsJheE3l8fGPacy+Ugf1H9m5y2EyWWC70LihVcDkY7d+Yyx/AQaZdpvHK/oAkFPdzjTe7PuSI6w==")
test(`{"id": 20}`, "gYIoDyh7VUbHbTQ8SRsnLeOQbqSs+mzlyxEanfqAs9yN6IVYdwvUBrU4rpTtisUoxJg5zU/jVNmp3AJGl6m1fA==")
test(`\`, "ThSNhyrg99Ms/lxQvgfDVI3X+wMUtNDdRH2xrz48oR3rrjnoHkYI/6bFu4Du4x3QPX0Cz+1pEqvmpWz5G3rtDQ==")
// From rmistry on skiabot hangout.
test("QA Engineer walks into a bar. Orders a beer. Orders 0 beers. Orders 999999999 beers. Orders a lizard. Orders -1 beers. Orders a sfdeljknesv.",
"mLGGNv+vJV8TBGyU+j+tRPifccuB50fDIi+TxIPPeP1au59Y3ngkQwsLb1cXkDFB26TbES1dixVhtolxY5vobA==")
}
func TestComputeAuthHashBase64NotInitialized(t *testing.T) {
requestSalt = nil
_, err := ComputeAuthHashBase64([]byte("foo"))
require.Error(t, err)
expect.Contains(t, err.Error(), "requestSalt is uninitialized")
}
func TestAuthenticateRequestSuccess(t *testing.T) {
require.NoError(t, setRequestSaltFromBase64([]byte(TEST_SALT_BASE64)))
test := func(bodyStr string) {
body := []byte(bodyStr)
req, err := http.NewRequest("POST", "http://invalid.", bytes.NewReader(body))
require.NoError(t, err)
hash, err := ComputeAuthHashBase64(body)
require.NoError(t, err)
req.Header.Set(REQUEST_AUTH_HASH_HEADER, hash)
actual, err := AuthenticateRequest(req)
expect.NoError(t, err)
expect.Equal(t, body, actual)
}
test("")
test("foo")
postData := url.Values{}
postData.Set("key", "17")
postData.Add("foo", "bar")
postData.Add("foo", "baz")
test(postData.Encode())
}
func TestAuthenticateRequestNoHeader(t *testing.T) {
require.NoError(t, setRequestSaltFromBase64([]byte(TEST_SALT_BASE64)))
body := []byte("my data")
req, err := http.NewRequest("POST", "http://invalid.", bytes.NewReader(body))
require.NoError(t, err)
actual, err := AuthenticateRequest(req)
require.Error(t, err)
expect.Contains(t, err.Error(), "No authentication header")
// Still returns body even though there was an authentication error.
expect.Equal(t, body, actual)
}
func TestAuthenticateRequestErrorComputingHash(t *testing.T) {
requestSalt = nil
body := []byte("my data")
req, err := http.NewRequest("POST", "http://invalid.", bytes.NewReader(body))
require.NoError(t, err)
req.Header.Set(REQUEST_AUTH_HASH_HEADER, "unused")
actual, err := AuthenticateRequest(req)
require.Error(t, err)
expect.Contains(t, err.Error(), "requestSalt is uninitialized")
// Still returns body even though there was an authentication error.
expect.Equal(t, body, actual)
}
func TestAuthenticateRequestWrongHeader(t *testing.T) {
require.NoError(t, setRequestSaltFromBase64([]byte(TEST_SALT_BASE64)))
body := []byte("my data")
req, err := http.NewRequest("POST", "http://invalid.", bytes.NewReader(body))
require.NoError(t, err)
req.Header.Set(REQUEST_AUTH_HASH_HEADER, INVALID_BASE64)
actual, err := AuthenticateRequest(req)
require.Error(t, err)
expect.Contains(t, err.Error(), "did not match")
// Still returns body even though there was an authentication error.
expect.Equal(t, body, actual)
}