Portiert mail-gateway/internal/license (Verify, Cache, Trial, Signature) + DB-Mirror (internal/services/license) + REST-Handler (status/verify/key/clear) + UI-Page /license (Activate, Status, Limits, Features, Re-verify) + <LicenseBanner /> neben UpdateBanner (trial-expiring, expired, verify-failed) + Scheduler: täglich Re-verify (24h-Tick) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
1.7 KiB
Go
53 lines
1.7 KiB
Go
package license
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"encoding/base64"
|
|
"log/slog"
|
|
)
|
|
|
|
// SignatureKey is an Ed25519 public key used to verify license-server
|
|
// responses. Shipped as hardcoded base64 constants; multiple keys allow
|
|
// rotation.
|
|
type SignatureKey = ed25519.PublicKey
|
|
|
|
// Default signing keys, base64 of the raw 32-byte Ed25519 public key.
|
|
// These must match the keys used by license.netcell-it.com to sign the
|
|
// verify response's X-Signature header — they are intentionally identical
|
|
// to the enconf/netcell-webpanel keys (same licensing backend).
|
|
const (
|
|
signingKeyPrimaryB64 = "uyXQLl8hFgI4rvvr5pfyF0SmFw1j2R849OL3HUZov5I="
|
|
signingKeyNextB64 = "zSdKn799Fmu1KaZPYfkB5gDVqeU2doIUFWvmvXigN6M="
|
|
)
|
|
|
|
// DefaultSigningKeys decodes the embedded base64 keys into Ed25519 public
|
|
// keys. Invalid entries are skipped with a warning.
|
|
func DefaultSigningKeys() []SignatureKey {
|
|
var out []SignatureKey
|
|
for _, b64 := range []string{signingKeyPrimaryB64, signingKeyNextB64} {
|
|
raw, err := base64.StdEncoding.DecodeString(b64)
|
|
if err != nil || len(raw) != ed25519.PublicKeySize {
|
|
slog.Error("license: invalid embedded signing key", "base64", b64)
|
|
continue
|
|
}
|
|
out = append(out, ed25519.PublicKey(raw))
|
|
}
|
|
return out
|
|
}
|
|
|
|
// VerifySignature accepts base64-encoded Ed25519 signatures in the
|
|
// X-Signature header of a license response and checks them against all
|
|
// provided keys — success on any match.
|
|
func VerifySignature(keys []SignatureKey, body []byte, signatureB64 string) bool {
|
|
sig, err := base64.StdEncoding.DecodeString(signatureB64)
|
|
if err != nil || len(sig) != ed25519.SignatureSize {
|
|
return false
|
|
}
|
|
for _, pk := range keys {
|
|
if ed25519.Verify(pk, body, sig) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|