CI / ci (push) Successful in 8m31s
Co-authored-by: orchestrator-agent <20+orchestrator-agent@code.cubecraftcreations.com>
102 lines
5.3 KiB
Go
102 lines
5.3 KiB
Go
package chat
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
const (
|
|
testKey = "AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI"
|
|
testToken = "q0Lz3kV9Yw8pXcRtN2bHsJdFgA7uEmKiOlP1nZxQ%3D"
|
|
testSpace = "AAQA1b2C3d4"
|
|
testHook = "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?key=" + testKey + "&token=" + testToken
|
|
)
|
|
|
|
func TestParseWebhookAccepts(t *testing.T) {
|
|
t.Parallel()
|
|
for _, raw := range []string{
|
|
testHook,
|
|
"https://chat.googleapis.com/v1/spaces/AAAA_x-y/messages?key=" + testKey + "&token=" + testToken,
|
|
} {
|
|
hook, err := ParseWebhook(raw)
|
|
if err != nil {
|
|
t.Errorf("ParseWebhook(%q) = %v, want accepted", raw, err)
|
|
continue
|
|
}
|
|
if hook.String() != raw {
|
|
t.Errorf("String() = %q, want %q", hook.String(), raw)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseWebhookRejects(t *testing.T) {
|
|
t.Parallel()
|
|
q := "?key=" + testKey + "&token=" + testToken
|
|
for name, raw := range map[string]string{
|
|
"empty": "",
|
|
"http": "http://chat.googleapis.com/v1/spaces/" + testSpace + "/messages" + q,
|
|
"upper-case scheme": "HTTPS://chat.googleapis.com/v1/spaces/" + testSpace + "/messages" + q,
|
|
"lookalike suffix": "https://chat.googleapis.com.evil.example/v1/spaces/" + testSpace + "/messages" + q,
|
|
"lookalike prefix": "https://evilchat.googleapis.com/v1/spaces/" + testSpace + "/messages" + q,
|
|
"other google host": "https://www.googleapis.com/v1/spaces/" + testSpace + "/messages" + q,
|
|
"upper-case host": "https://CHAT.googleapis.com/v1/spaces/" + testSpace + "/messages" + q,
|
|
"port": "https://chat.googleapis.com:443/v1/spaces/" + testSpace + "/messages" + q,
|
|
"user info": "https://user@chat.googleapis.com/v1/spaces/" + testSpace + "/messages" + q,
|
|
"trailing dot host": "https://chat.googleapis.com./v1/spaces/" + testSpace + "/messages" + q,
|
|
"no space": "https://chat.googleapis.com/v1/spaces//messages" + q,
|
|
"extra path": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages/x" + q,
|
|
"other version": "https://chat.googleapis.com/v2/spaces/" + testSpace + "/messages" + q,
|
|
"members path": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/members" + q,
|
|
"escaped path": "https://chat.googleapis.com/v1/spaces/AA%2FQA/messages" + q,
|
|
"dot segment": "https://chat.googleapis.com/v1/spaces/../messages" + q,
|
|
"no query": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages",
|
|
"no key": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?token=" + testToken,
|
|
"no token": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?key=" + testKey,
|
|
"empty token": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?key=" + testKey + "&token=",
|
|
"short key": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?key=abc&token=" + testToken,
|
|
"token first": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?token=" + testToken + "&key=" + testKey,
|
|
"empty segment": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?key=" + testKey + "&&token=" + testToken,
|
|
"leading ampersand": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?&" + q[1:],
|
|
"trailing ampersand": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages" + q + "&",
|
|
"second question": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages" + q + "?x",
|
|
"multi-byte token": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?key=" + testKey + "&token=" + strings.Repeat("%F0%9F%98%80", 4),
|
|
"multi-byte key": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?key=" + strings.Repeat("%F0%9F%98%80", 4) + "&token=" + testToken,
|
|
"plus in token": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?key=" + testKey + "&token=" + testToken + "+",
|
|
"repeated key": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages" + q + "&key=" + testKey,
|
|
"extra parameter": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages" + q + "&threadKey=x",
|
|
"bad escape in query": "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages" + q + "%zz",
|
|
"fragment": testHook + "#frag",
|
|
"space": testHook + " ",
|
|
"newline": testHook + "\n",
|
|
"too long": testHook + strings.Repeat("A", MaxWebhookURLLength),
|
|
"not a URL": "chat webhook please",
|
|
} {
|
|
_, err := ParseWebhook(raw)
|
|
if err == nil {
|
|
t.Errorf("%s: ParseWebhook(%q) accepted", name, raw)
|
|
continue
|
|
}
|
|
for _, secret := range []string{testKey, testToken, testSpace} {
|
|
if strings.Contains(err.Error(), secret) {
|
|
t.Errorf("%s: error %q quotes the URL", name, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWebhookMasked(t *testing.T) {
|
|
t.Parallel()
|
|
hook, err := ParseWebhook(testHook)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// The tail is of the token as it decodes: "%3D" is "=".
|
|
want := "https://chat.googleapis.com/v1/spaces/" + testSpace + "/messages?key=…&token=…ZxQ="
|
|
if got := hook.Masked(); got != want {
|
|
t.Errorf("Masked() = %q, want %q", got, want)
|
|
}
|
|
if m := hook.Masked(); strings.Contains(m, testKey) || strings.Contains(m, testToken) || strings.Contains(m, testToken[:8]) {
|
|
t.Errorf("Masked() = %q holds the key or token", m)
|
|
}
|
|
}
|