mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-07 17:19:57 +00:00
193 lines
5.5 KiB
Go
193 lines
5.5 KiB
Go
package licensing
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"encoding/base64"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
)
|
|
|
|
func TestDecodeEd25519PrivateKey(t *testing.T) {
|
|
pub, priv, err := ed25519.GenerateKey(nil)
|
|
if err != nil {
|
|
t.Fatalf("GenerateKey: %v", err)
|
|
}
|
|
_ = pub
|
|
|
|
seed := priv.Seed()
|
|
seedEncoded := base64.StdEncoding.EncodeToString(seed)
|
|
gotSeedKey, err := DecodeEd25519PrivateKey(seedEncoded)
|
|
if err != nil {
|
|
t.Fatalf("DecodeEd25519PrivateKey(seed): %v", err)
|
|
}
|
|
if len(gotSeedKey) != ed25519.PrivateKeySize {
|
|
t.Fatalf("seed decoded key length=%d, want %d", len(gotSeedKey), ed25519.PrivateKeySize)
|
|
}
|
|
|
|
fullEncoded := base64.StdEncoding.EncodeToString(priv)
|
|
gotFullKey, err := DecodeEd25519PrivateKey(fullEncoded)
|
|
if err != nil {
|
|
t.Fatalf("DecodeEd25519PrivateKey(full): %v", err)
|
|
}
|
|
if string(gotFullKey) != string(priv) {
|
|
t.Fatalf("decoded full private key mismatch")
|
|
}
|
|
}
|
|
|
|
func TestSignAndVerifyTrialActivationToken(t *testing.T) {
|
|
pub, priv, err := ed25519.GenerateKey(nil)
|
|
if err != nil {
|
|
t.Fatalf("GenerateKey: %v", err)
|
|
}
|
|
|
|
token, err := SignTrialActivationToken(priv, TrialActivationClaims{
|
|
OrgID: "default",
|
|
Email: "owner@example.com",
|
|
InstanceHost: "pulse.example.com",
|
|
ReturnURL: "https://pulse.example.com/auth/trial-activate",
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(5 * time.Minute)),
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SignTrialActivationToken: %v", err)
|
|
}
|
|
|
|
claims, err := VerifyTrialActivationToken(token, pub, "pulse.example.com", time.Now())
|
|
if err != nil {
|
|
t.Fatalf("VerifyTrialActivationToken: %v", err)
|
|
}
|
|
if claims.OrgID != "default" {
|
|
t.Fatalf("claims.OrgID=%q, want %q", claims.OrgID, "default")
|
|
}
|
|
if claims.InstanceHost != "pulse.example.com" {
|
|
t.Fatalf("claims.InstanceHost=%q, want %q", claims.InstanceHost, "pulse.example.com")
|
|
}
|
|
}
|
|
|
|
func TestVerifyTrialActivationToken_HostMismatch(t *testing.T) {
|
|
pub, priv, err := ed25519.GenerateKey(nil)
|
|
if err != nil {
|
|
t.Fatalf("GenerateKey: %v", err)
|
|
}
|
|
|
|
token, err := SignTrialActivationToken(priv, TrialActivationClaims{
|
|
OrgID: "default",
|
|
InstanceHost: "pulse-a.example.com",
|
|
ReturnURL: "https://pulse-a.example.com/auth/trial-activate",
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(5 * time.Minute)),
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SignTrialActivationToken: %v", err)
|
|
}
|
|
|
|
_, err = VerifyTrialActivationToken(token, pub, "pulse-b.example.com", time.Now())
|
|
if !errors.Is(err, ErrTrialActivationHostMismatch) {
|
|
t.Fatalf("VerifyTrialActivationToken() error=%v, want %v", err, ErrTrialActivationHostMismatch)
|
|
}
|
|
}
|
|
|
|
func TestValidateTrialActivationReturnURL(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
raw string
|
|
expectedHost string
|
|
wantHost string
|
|
wantErr error
|
|
}{
|
|
{
|
|
name: "https public host",
|
|
raw: "https://pulse.example.com/auth/trial-activate",
|
|
expectedHost: "pulse.example.com",
|
|
wantHost: "pulse.example.com",
|
|
},
|
|
{
|
|
name: "http localhost allowed",
|
|
raw: "http://localhost:7655/auth/trial-activate",
|
|
wantHost: "localhost",
|
|
},
|
|
{
|
|
name: "missing return url",
|
|
raw: "",
|
|
wantErr: ErrTrialActivationReturnURLMissing,
|
|
},
|
|
{
|
|
name: "http public host rejected",
|
|
raw: "http://pulse.example.com/auth/trial-activate",
|
|
wantErr: ErrTrialActivationReturnURLInvalid,
|
|
},
|
|
{
|
|
name: "query string rejected",
|
|
raw: "https://pulse.example.com/auth/trial-activate?token=x",
|
|
wantErr: ErrTrialActivationReturnURLInvalid,
|
|
},
|
|
{
|
|
name: "host mismatch rejected",
|
|
raw: "https://pulse.example.com/auth/trial-activate",
|
|
expectedHost: "other.example.com",
|
|
wantErr: ErrTrialActivationHostMismatch,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
gotHost, err := ValidateTrialActivationReturnURL(tt.raw, tt.expectedHost)
|
|
if !errors.Is(err, tt.wantErr) {
|
|
t.Fatalf("ValidateTrialActivationReturnURL() error=%v, want %v", err, tt.wantErr)
|
|
}
|
|
if gotHost != tt.wantHost {
|
|
t.Fatalf("ValidateTrialActivationReturnURL() host=%q, want %q", gotHost, tt.wantHost)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSignTrialActivationToken_RequiresReturnURL(t *testing.T) {
|
|
_, priv, err := ed25519.GenerateKey(nil)
|
|
if err != nil {
|
|
t.Fatalf("GenerateKey: %v", err)
|
|
}
|
|
|
|
_, err = SignTrialActivationToken(priv, TrialActivationClaims{
|
|
OrgID: "default",
|
|
InstanceHost: "pulse.example.com",
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(5 * time.Minute)),
|
|
},
|
|
})
|
|
if !errors.Is(err, ErrTrialActivationReturnURLMissing) {
|
|
t.Fatalf("SignTrialActivationToken() error=%v, want %v", err, ErrTrialActivationReturnURLMissing)
|
|
}
|
|
}
|
|
|
|
func TestTrialActivationPublicKey_EnvOverride(t *testing.T) {
|
|
pub, _, err := ed25519.GenerateKey(nil)
|
|
if err != nil {
|
|
t.Fatalf("GenerateKey: %v", err)
|
|
}
|
|
|
|
t.Setenv(TrialActivationPublicKeyEnvVar, base64.StdEncoding.EncodeToString(pub))
|
|
embeddedBefore := EmbeddedPublicKey
|
|
t.Cleanup(func() { EmbeddedPublicKey = embeddedBefore })
|
|
EmbeddedPublicKey = ""
|
|
|
|
got, err := TrialActivationPublicKey()
|
|
if err != nil {
|
|
t.Fatalf("TrialActivationPublicKey: %v", err)
|
|
}
|
|
if string(got) != string(pub) {
|
|
t.Fatalf("TrialActivationPublicKey mismatch")
|
|
}
|
|
}
|
|
|
|
func TestAllowTrialActivationPublicKeyEnvOverride_HostedMode(t *testing.T) {
|
|
t.Setenv("PULSE_HOSTED_MODE", "true")
|
|
if !allowTrialActivationPublicKeyEnvOverride() {
|
|
t.Fatal("allowTrialActivationPublicKeyEnvOverride() = false, want true in hosted mode")
|
|
}
|
|
}
|