mirror of
https://github.com/pocket-id/pocket-id.git
synced 2025-12-07 05:43:02 +03:00
191 lines
4.5 KiB
Go
191 lines
4.5 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/lestrrat-go/jwx/v3/jwa"
|
|
"github.com/lestrrat-go/jwx/v3/jwk"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/pocket-id/pocket-id/backend/internal/service"
|
|
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
|
)
|
|
|
|
func TestMigrateKey(t *testing.T) {
|
|
// Create a temporary directory for testing
|
|
tempDir := t.TempDir()
|
|
|
|
t.Run("no keys exist", func(t *testing.T) {
|
|
// Test when no keys exist
|
|
err := migrateKeyInternal(tempDir)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("jwk already exists", func(t *testing.T) {
|
|
// Create a JWK file
|
|
jwkPath := filepath.Join(tempDir, service.PrivateKeyFile)
|
|
key, err := createTestRSAKey()
|
|
require.NoError(t, err)
|
|
err = service.SaveKeyJWK(key, jwkPath)
|
|
require.NoError(t, err)
|
|
|
|
// Run migration - should do nothing
|
|
err = migrateKeyInternal(tempDir)
|
|
require.NoError(t, err)
|
|
|
|
// Check the file still exists
|
|
exists, err := utils.FileExists(jwkPath)
|
|
require.NoError(t, err)
|
|
assert.True(t, exists)
|
|
|
|
// Delete for next test
|
|
err = os.Remove(jwkPath)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("migrate pem to jwk", func(t *testing.T) {
|
|
// Create a PEM file
|
|
pemPath := filepath.Join(tempDir, privateKeyFilePem)
|
|
jwkPath := filepath.Join(tempDir, service.PrivateKeyFile)
|
|
|
|
// Generate RSA key and save as PEM
|
|
createRSAPrivateKeyPEM(t, pemPath)
|
|
|
|
// Run migration
|
|
err := migrateKeyInternal(tempDir)
|
|
require.NoError(t, err)
|
|
|
|
// Check PEM file is gone
|
|
exists, err := utils.FileExists(pemPath)
|
|
require.NoError(t, err)
|
|
assert.False(t, exists)
|
|
|
|
// Check JWK file exists
|
|
exists, err = utils.FileExists(jwkPath)
|
|
require.NoError(t, err)
|
|
assert.True(t, exists)
|
|
|
|
// Verify the JWK can be loaded
|
|
data, err := os.ReadFile(jwkPath)
|
|
require.NoError(t, err)
|
|
|
|
_, err = jwk.ParseKey(data)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestLoadKeyPEM(t *testing.T) {
|
|
// Create a temporary directory for testing
|
|
tempDir := t.TempDir()
|
|
|
|
t.Run("successfully load PEM key", func(t *testing.T) {
|
|
pemPath := filepath.Join(tempDir, "test_key.pem")
|
|
|
|
// Generate RSA key and save as PEM
|
|
createRSAPrivateKeyPEM(t, pemPath)
|
|
|
|
// Load the key
|
|
key, err := loadKeyPEM(pemPath)
|
|
require.NoError(t, err)
|
|
|
|
// Verify key properties
|
|
assert.NotEmpty(t, key)
|
|
|
|
// Check key ID is set
|
|
var keyID string
|
|
err = key.Get(jwk.KeyIDKey, &keyID)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, keyID)
|
|
|
|
// Check algorithm is set
|
|
var alg jwa.SignatureAlgorithm
|
|
err = key.Get(jwk.AlgorithmKey, &alg)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, alg)
|
|
|
|
// Check key usage is set
|
|
var keyUsage string
|
|
err = key.Get(jwk.KeyUsageKey, &keyUsage)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, service.KeyUsageSigning, keyUsage)
|
|
})
|
|
|
|
t.Run("file not found", func(t *testing.T) {
|
|
key, err := loadKeyPEM(filepath.Join(tempDir, "nonexistent.pem"))
|
|
require.Error(t, err)
|
|
assert.Nil(t, key)
|
|
})
|
|
|
|
t.Run("invalid file content", func(t *testing.T) {
|
|
invalidPath := filepath.Join(tempDir, "invalid.pem")
|
|
err := os.WriteFile(invalidPath, []byte("not a valid PEM"), 0600)
|
|
require.NoError(t, err)
|
|
|
|
key, err := loadKeyPEM(invalidPath)
|
|
require.Error(t, err)
|
|
assert.Nil(t, key)
|
|
})
|
|
}
|
|
|
|
func TestGenerateKeyID(t *testing.T) {
|
|
key, err := createTestRSAKey()
|
|
require.NoError(t, err)
|
|
|
|
keyID, err := generateKeyID(key)
|
|
require.NoError(t, err)
|
|
|
|
// Key ID should be non-empty
|
|
assert.NotEmpty(t, keyID)
|
|
|
|
// Generate another key ID to prove it depends on the key
|
|
key2, err := createTestRSAKey()
|
|
require.NoError(t, err)
|
|
|
|
keyID2, err := generateKeyID(key2)
|
|
require.NoError(t, err)
|
|
|
|
// The two key IDs should be different
|
|
assert.NotEqual(t, keyID, keyID2)
|
|
}
|
|
|
|
// Helper functions
|
|
|
|
func createTestRSAKey() (jwk.Key, error) {
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key, err := jwk.Import(privateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return key, nil
|
|
}
|
|
|
|
// createRSAPrivateKeyPEM generates an RSA private key and returns its PEM-encoded form
|
|
func createRSAPrivateKeyPEM(t *testing.T, pemPath string) ([]byte, *rsa.PrivateKey) {
|
|
// Generate RSA key
|
|
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
require.NoError(t, err)
|
|
|
|
// Encode to PEM format
|
|
pemData := pem.EncodeToMemory(&pem.Block{
|
|
Type: "RSA PRIVATE KEY",
|
|
Bytes: x509.MarshalPKCS1PrivateKey(privKey),
|
|
})
|
|
|
|
err = os.WriteFile(pemPath, pemData, 0600)
|
|
require.NoError(t, err)
|
|
|
|
return pemData, privKey
|
|
}
|