1
0
Fork 0
mirror of https://github.com/imjasonh/webpush synced 2026-07-06 23:52:25 +00:00
webpush/keys/file_test.go
copilot-swe-agent[bot] 78bd40dc88 Implement Web Push API Go library with VAPID support and pluggable storage
Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
2025-11-24 21:19:16 +00:00

197 lines
4.8 KiB
Go

package keys
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"os"
"path/filepath"
"testing"
)
func TestNewFileSigner(t *testing.T) {
// Generate a test key
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("GenerateKey() error = %v", err)
}
// Create temp file
tmpDir := t.TempDir()
keyPath := filepath.Join(tmpDir, "test.pem")
// Marshal and write
privKeyBytes, err := x509.MarshalECPrivateKey(privKey)
if err != nil {
t.Fatalf("MarshalECPrivateKey() error = %v", err)
}
block := &pem.Block{
Type: "EC PRIVATE KEY",
Bytes: privKeyBytes,
}
if err := os.WriteFile(keyPath, pem.EncodeToMemory(block), 0600); err != nil {
t.Fatalf("WriteFile() error = %v", err)
}
// Test loading
signer, err := NewFileSigner(keyPath)
if err != nil {
t.Fatalf("NewFileSigner() error = %v", err)
}
// Verify public key is 65 bytes (uncompressed P-256)
if len(signer.PublicKey()) != 65 {
t.Errorf("PublicKey() length = %d, want 65", len(signer.PublicKey()))
}
// Test signing
data := []byte("test data hash")
sig, err := signer.Sign(context.Background(), data)
if err != nil {
t.Fatalf("Sign() error = %v", err)
}
// Verify signature is 64 bytes (r || s)
if len(sig) != 64 {
t.Errorf("Sign() signature length = %d, want 64", len(sig))
}
}
func TestNewFileSignerFromBase64(t *testing.T) {
// Generate a key
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("GenerateKey() error = %v", err)
}
// Get private key as 32-byte big-endian
privKeyBytes := privKey.D.Bytes()
paddedPrivKey := make([]byte, 32)
copy(paddedPrivKey[32-len(privKeyBytes):], privKeyBytes)
privKeyB64 := base64.RawURLEncoding.EncodeToString(paddedPrivKey)
// Create signer
signer, err := NewFileSignerFromBase64(privKeyB64)
if err != nil {
t.Fatalf("NewFileSignerFromBase64() error = %v", err)
}
// Verify public key
if len(signer.PublicKey()) != 65 {
t.Errorf("PublicKey() length = %d, want 65", len(signer.PublicKey()))
}
// Test signing
data := []byte("test data hash")
sig, err := signer.Sign(context.Background(), data)
if err != nil {
t.Fatalf("Sign() error = %v", err)
}
if len(sig) != 64 {
t.Errorf("Sign() signature length = %d, want 64", len(sig))
}
}
func TestGenerateKey(t *testing.T) {
tmpDir := t.TempDir()
keyPath := filepath.Join(tmpDir, "generated.pem")
signer, err := GenerateKey(keyPath)
if err != nil {
t.Fatalf("GenerateKey() error = %v", err)
}
// Verify file was created
if _, err := os.Stat(keyPath); os.IsNotExist(err) {
t.Error("Key file was not created")
}
// Verify public key
if len(signer.PublicKey()) != 65 {
t.Errorf("PublicKey() length = %d, want 65", len(signer.PublicKey()))
}
// Verify we can load the key back
signer2, err := NewFileSigner(keyPath)
if err != nil {
t.Fatalf("NewFileSigner() error = %v", err)
}
if string(signer.PublicKey()) != string(signer2.PublicKey()) {
t.Error("Loaded key doesn't match generated key")
}
}
func TestGenerateKeyPair(t *testing.T) {
privKeyB64, pubKeyB64, err := GenerateKeyPair()
if err != nil {
t.Fatalf("GenerateKeyPair() error = %v", err)
}
// Decode and verify private key length
privKey, err := base64.RawURLEncoding.DecodeString(privKeyB64)
if err != nil {
t.Fatalf("DecodeString(privateKey) error = %v", err)
}
if len(privKey) != 32 {
t.Errorf("Private key length = %d, want 32", len(privKey))
}
// Decode and verify public key length
pubKey, err := base64.RawURLEncoding.DecodeString(pubKeyB64)
if err != nil {
t.Fatalf("DecodeString(publicKey) error = %v", err)
}
if len(pubKey) != 65 {
t.Errorf("Public key length = %d, want 65", len(pubKey))
}
// Verify we can create a signer from the private key
signer, err := NewFileSignerFromBase64(privKeyB64)
if err != nil {
t.Fatalf("NewFileSignerFromBase64() error = %v", err)
}
// Verify public keys match
signerPubKeyB64 := signer.PublicKeyBase64()
if signerPubKeyB64 != pubKeyB64 {
t.Errorf("PublicKeyBase64() = %q, want %q", signerPubKeyB64, pubKeyB64)
}
}
func TestNewFileSigner_InvalidFile(t *testing.T) {
_, err := NewFileSigner("/nonexistent/path")
if err == nil {
t.Error("NewFileSigner() expected error for nonexistent file")
}
}
func TestNewFileSigner_InvalidPEM(t *testing.T) {
tmpDir := t.TempDir()
keyPath := filepath.Join(tmpDir, "invalid.pem")
if err := os.WriteFile(keyPath, []byte("not a pem file"), 0600); err != nil {
t.Fatalf("WriteFile() error = %v", err)
}
_, err := NewFileSigner(keyPath)
if err == nil {
t.Error("NewFileSigner() expected error for invalid PEM")
}
}
func TestNewFileSignerFromBase64_InvalidLength(t *testing.T) {
// Too short
_, err := NewFileSignerFromBase64("AAAA")
if err == nil {
t.Error("NewFileSignerFromBase64() expected error for invalid length")
}
}