mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
fix(license): harden release key validation and fingerprint logging
(cherry picked from commit f253ed2778)
This commit is contained in:
@@ -2,6 +2,7 @@ package license
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -14,6 +15,14 @@ import (
|
||||
// Example: go build -ldflags "-X github.com/rcourtman/pulse-go-rewrite/internal/license.EmbeddedPublicKey=BASE64_KEY"
|
||||
var EmbeddedPublicKey string = ""
|
||||
|
||||
func publicKeyFingerprint(key ed25519.PublicKey) string {
|
||||
if len(key) == 0 {
|
||||
return ""
|
||||
}
|
||||
sum := sha256.Sum256(key)
|
||||
return "SHA256:" + base64.StdEncoding.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
// InitPublicKey initializes the public key for license validation.
|
||||
// Priority:
|
||||
// 1. PULSE_LICENSE_PUBLIC_KEY environment variable (base64 encoded)
|
||||
@@ -30,7 +39,10 @@ func InitPublicKey() {
|
||||
// Fall through to try embedded key instead of returning
|
||||
} else {
|
||||
SetPublicKey(key)
|
||||
log.Info().Msg("License public key loaded from environment")
|
||||
log.Info().
|
||||
Str("source", "environment").
|
||||
Str("fingerprint", publicKeyFingerprint(key)).
|
||||
Msg("License public key loaded")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -42,7 +54,10 @@ func InitPublicKey() {
|
||||
log.Error().Err(err).Msg("Failed to decode embedded public key")
|
||||
} else {
|
||||
SetPublicKey(key)
|
||||
log.Info().Msg("License public key loaded from embedded key")
|
||||
log.Info().
|
||||
Str("source", "embedded").
|
||||
Str("fingerprint", publicKeyFingerprint(key)).
|
||||
Msg("License public key loaded")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package license
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -115,3 +117,22 @@ func TestDecodePublicKey(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicKeyFingerprint(t *testing.T) {
|
||||
pub, _, _ := ed25519.GenerateKey(nil)
|
||||
|
||||
got := publicKeyFingerprint(pub)
|
||||
if !strings.HasPrefix(got, "SHA256:") {
|
||||
t.Fatalf("expected SHA256 prefix, got %q", got)
|
||||
}
|
||||
|
||||
sum := sha256.Sum256(pub)
|
||||
want := "SHA256:" + base64.StdEncoding.EncodeToString(sum[:])
|
||||
if got != want {
|
||||
t.Fatalf("fingerprint mismatch: got %q want %q", got, want)
|
||||
}
|
||||
|
||||
if empty := publicKeyFingerprint(nil); empty != "" {
|
||||
t.Fatalf("expected empty fingerprint for nil key, got %q", empty)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,41 @@ RELEASE_DIR="release"
|
||||
|
||||
echo "Building Pulse v${VERSION}..."
|
||||
|
||||
# Optional public key embedding for license validation
|
||||
# Require public key embedding for release-grade license validation.
|
||||
# Explicitly opt out with PULSE_ALLOW_MISSING_LICENSE_KEY=true (not recommended).
|
||||
LICENSE_LDFLAGS=""
|
||||
if [[ -n "${PULSE_LICENSE_PUBLIC_KEY:-}" ]]; then
|
||||
LICENSE_LDFLAGS="-X github.com/rcourtman/pulse-go-rewrite/internal/license.EmbeddedPublicKey=${PULSE_LICENSE_PUBLIC_KEY}"
|
||||
if [[ -z "${PULSE_LICENSE_PUBLIC_KEY:-}" ]]; then
|
||||
if [[ "${PULSE_ALLOW_MISSING_LICENSE_KEY:-false}" == "true" ]]; then
|
||||
echo "Warning: PULSE_LICENSE_PUBLIC_KEY not set; continuing because PULSE_ALLOW_MISSING_LICENSE_KEY=true."
|
||||
else
|
||||
echo "Error: PULSE_LICENSE_PUBLIC_KEY is required for release builds." >&2
|
||||
echo "Set PULSE_ALLOW_MISSING_LICENSE_KEY=true only for local non-release debugging." >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Warning: PULSE_LICENSE_PUBLIC_KEY not set; Pulse Pro license activation will fail for release binaries."
|
||||
decoded_key_len=$(printf '%s' "${PULSE_LICENSE_PUBLIC_KEY}" | openssl base64 -d -A 2>/dev/null | wc -c | tr -d ' ')
|
||||
if [[ "${decoded_key_len}" != "32" ]]; then
|
||||
echo "Error: PULSE_LICENSE_PUBLIC_KEY must decode to 32 bytes (Ed25519 public key)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "${PULSE_LICENSE_PUBLIC_KEY_FINGERPRINT:-}" ]]; then
|
||||
expected_fingerprint="${PULSE_LICENSE_PUBLIC_KEY_FINGERPRINT#SHA256:}"
|
||||
actual_fingerprint=$(printf '%s' "${PULSE_LICENSE_PUBLIC_KEY}" | openssl base64 -d -A 2>/dev/null | openssl dgst -sha256 -binary | openssl base64 -A)
|
||||
if [[ -z "${actual_fingerprint}" ]]; then
|
||||
echo "Error: Failed to compute fingerprint for PULSE_LICENSE_PUBLIC_KEY." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${actual_fingerprint}" != "${expected_fingerprint}" ]]; then
|
||||
echo "Error: PULSE_LICENSE_PUBLIC_KEY fingerprint mismatch." >&2
|
||||
echo "Expected: SHA256:${expected_fingerprint}" >&2
|
||||
echo "Actual: SHA256:${actual_fingerprint}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Verified license public key fingerprint: SHA256:${actual_fingerprint}"
|
||||
fi
|
||||
|
||||
LICENSE_LDFLAGS="-X github.com/rcourtman/pulse-go-rewrite/internal/license.EmbeddedPublicKey=${PULSE_LICENSE_PUBLIC_KEY}"
|
||||
fi
|
||||
|
||||
# Clean previous builds
|
||||
|
||||
Reference in New Issue
Block a user