dal-license-server/internal/service/crypto_service_test.go
djuka dc0114e4b7 Inicijalni commit: kompletna implementacija + dokumentacija + testovi
- Kompletna Go implementacija licencnog servera (19 Go fajlova)
- Klijentski API: activate, deactivate, validate
- Admin API: CRUD licence, stats, audit log
- Admin dashboard: htmx + Go templates
- RSA-2048 potpisivanje licencnih podataka
- Rate limiting i API key autentifikacija
- MySQL migracije i seed podaci (ESIR, ARV, LIGHT_TICKET)
- Unit testovi: keygen, crypto, model, middleware (24 testa)
- Dokumentacija: SPEC.md, ARCHITECTURE.md, SETUP.md, API.md, TESTING.md, README.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 07:42:25 +00:00

148 lines
3.3 KiB
Go

package service
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"os"
"path/filepath"
"strings"
"testing"
)
func setupTestKey(t *testing.T) (string, *rsa.PrivateKey) {
t.Helper()
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatal(err)
}
dir := t.TempDir()
path := filepath.Join(dir, "test_private.pem")
keyBytes := x509.MarshalPKCS1PrivateKey(key)
block := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes}
f, err := os.Create(path)
if err != nil {
t.Fatal(err)
}
pem.Encode(f, block)
f.Close()
return path, key
}
func TestNewCryptoService(t *testing.T) {
path, _ := setupTestKey(t)
svc, err := NewCryptoService(path)
if err != nil {
t.Fatalf("NewCryptoService error: %v", err)
}
if svc == nil {
t.Fatal("CryptoService je nil")
}
}
func TestNewCryptoService_InvalidPath(t *testing.T) {
_, err := NewCryptoService("/nonexistent/path.pem")
if err == nil {
t.Error("ocekivana greska za nepostojeci fajl")
}
}
func TestNewCryptoService_InvalidPEM(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "bad.pem")
os.WriteFile(path, []byte("not a pem file"), 0600)
_, err := NewCryptoService(path)
if err == nil {
t.Error("ocekivana greska za nevalidan PEM")
}
}
func TestSign_Format(t *testing.T) {
path, _ := setupTestKey(t)
svc, _ := NewCryptoService(path)
sig, err := svc.Sign([]byte("test data"))
if err != nil {
t.Fatalf("Sign error: %v", err)
}
if !strings.HasPrefix(sig, "RSA-SHA256:") {
t.Errorf("potpis nema RSA-SHA256: prefix: %s", sig)
}
// Verify base64 part is valid
b64 := strings.TrimPrefix(sig, "RSA-SHA256:")
_, err = base64.StdEncoding.DecodeString(b64)
if err != nil {
t.Errorf("base64 deo potpisa nije validan: %v", err)
}
}
func TestSign_VerifyWithPublicKey(t *testing.T) {
path, privKey := setupTestKey(t)
svc, _ := NewCryptoService(path)
data := []byte(`{"license_key":"LT-TEST-1234","product":"LIGHT_TICKET"}`)
sig, err := svc.Sign(data)
if err != nil {
t.Fatal(err)
}
// Extract base64 signature
b64 := strings.TrimPrefix(sig, "RSA-SHA256:")
sigBytes, _ := base64.StdEncoding.DecodeString(b64)
// Verify with public key
hash := sha256.Sum256(data)
err = rsa.VerifyPKCS1v15(&privKey.PublicKey, crypto.SHA256, hash[:], sigBytes)
if err != nil {
t.Errorf("potpis nije validan: %v", err)
}
}
func TestSign_TamperedData(t *testing.T) {
path, privKey := setupTestKey(t)
svc, _ := NewCryptoService(path)
data := []byte(`{"license_key":"LT-TEST-1234"}`)
sig, _ := svc.Sign(data)
b64 := strings.TrimPrefix(sig, "RSA-SHA256:")
sigBytes, _ := base64.StdEncoding.DecodeString(b64)
// Tamper with data
tampered := []byte(`{"license_key":"LT-FAKE-9999"}`)
hash := sha256.Sum256(tampered)
err := rsa.VerifyPKCS1v15(&privKey.PublicKey, crypto.SHA256, hash[:], sigBytes)
if err == nil {
t.Error("tampered data ne sme proci verifikaciju")
}
}
func TestPublicKeyPEM(t *testing.T) {
path, _ := setupTestKey(t)
svc, _ := NewCryptoService(path)
pubPEM, err := svc.PublicKeyPEM()
if err != nil {
t.Fatal(err)
}
if !strings.Contains(pubPEM, "BEGIN PUBLIC KEY") {
t.Error("public key PEM nema ocekivani header")
}
if !strings.Contains(pubPEM, "END PUBLIC KEY") {
t.Error("public key PEM nema ocekivani footer")
}
}