a73x

internal/joinblob/joinblob_test.go

Ref:   Size: 2.7 KiB   History

package joinblob

import (
	"encoding/base64"
	"strings"
	"testing"
)

const goodFP = "18f2977d77dfea1b74aee14533bd21c34f789139e949c57023b7364894b7e5e9"

func TestEncodeDecodeRoundTrip(t *testing.T) {
	blob, err := Encode("http://192.168.0.190:8080", "192.168.0.190:8443", "tok123", goodFP)
	if err != nil {
		t.Fatalf("Encode: %v", err)
	}
	if !strings.HasPrefix(blob, Prefix) {
		t.Fatalf("blob %q missing prefix %q", blob, Prefix)
	}
	got, err := Decode(blob)
	if err != nil {
		t.Fatalf("Decode: %v", err)
	}
	want := Fields{HTTPURL: "http://192.168.0.190:8080", QUICAddr: "192.168.0.190:8443", Token: "tok123", CertFP: goodFP}
	if got != want {
		t.Fatalf("round-trip mismatch:\n got %+v\nwant %+v", got, want)
	}
}

func TestDecodeTrimsWhitespace(t *testing.T) {
	blob, _ := Encode("http://h:8080", "h:8443", "t", goodFP)
	if _, err := Decode("  " + blob + "\n"); err != nil {
		t.Fatalf("Decode with surrounding whitespace: %v", err)
	}
}

func TestEncodeRejectsBadInputs(t *testing.T) {
	cases := map[string][4]string{
		"http missing scheme": {"192.168.0.190:8080", "h:8443", "t", goodFP},
		"quic not host:port":  {"http://h:8080", "hostonly", "t", goodFP},
		"empty token":         {"http://h:8080", "h:8443", "", goodFP},
		"short fp":            {"http://h:8080", "h:8443", "t", "abc"},
		"uppercase fp":        {"http://h:8080", "h:8443", "t", strings.ToUpper(goodFP)},
		"http with path":      {"http://h:8080/foo", "h:8443", "t", goodFP},
	}
	for name, in := range cases {
		if _, err := Encode(in[0], in[1], in[2], in[3]); err == nil {
			t.Errorf("%s: expected error, got nil", name)
		}
	}
}

func TestDecodeRejectsWrongVersion(t *testing.T) {
	// A well-formed blob whose version is not 1 must be rejected. Built by hand
	// because Encode only ever emits the current version.
	raw := `{"v":2,"h":"http://h:8080","q":"h:8443","t":"t","f":"` + goodFP + `"}`
	blob := Prefix + base64.RawURLEncoding.EncodeToString([]byte(raw))
	if _, err := Decode(blob); err == nil {
		t.Fatal("expected version-mismatch error, got nil")
	}
}

func TestDecodeRejectsTrailingSlash(t *testing.T) {
	raw := `{"v":1,"h":"http://h:8080/","q":"h:8443","t":"t","f":"` + goodFP + `"}`
	blob := Prefix + base64.RawURLEncoding.EncodeToString([]byte(raw))
	if _, err := Decode(blob); err == nil {
		t.Fatal("expected trailing-slash rejection, got nil")
	}
}

func TestDecodeRejectsMalformed(t *testing.T) {
	good, _ := Encode("http://h:8080", "h:8443", "t", goodFP)
	cases := map[string]string{
		"no prefix":    strings.TrimPrefix(good, Prefix),
		"bad base64":   Prefix + "!!!not-base64!!!",
		"bad json":     Prefix + "YWJj", // base64url of "abc"
		"empty string": "",
	}
	for name, blob := range cases {
		if _, err := Decode(blob); err == nil {
			t.Errorf("%s: expected error, got nil", name)
		}
	}
}