Files
certigo/backend/providers/acme_provider.go

183 lines
4.9 KiB
Go

package providers
import (
"encoding/json"
"os"
"path/filepath"
"sync"
)
// ACMEProvider Interface für ACME-basierte Certificate Authorities
type ACMEProvider interface {
// GetName gibt den Namen des ACME-Providers zurück
GetName() string
// GetDisplayName gibt den Anzeigenamen zurück
GetDisplayName() string
// GetDescription gibt eine Beschreibung zurück
GetDescription() string
// GetDirectoryURL gibt die ACME Directory URL zurück
GetDirectoryURL() string
// GetRenewalInfoURL gibt die RenewalInfo API URL zurück (optional)
GetRenewalInfoURL() string
// ValidateConfig validiert die Konfiguration
ValidateConfig(settings map[string]interface{}) error
// TestConnection testet die Verbindung zum ACME-Server
TestConnection(settings map[string]interface{}) error
// GetRequiredSettings gibt die erforderlichen Einstellungen zurück
GetRequiredSettings() []SettingField
}
// ACMEProviderConfig enthält die Konfiguration eines ACME-Providers
type ACMEProviderConfig struct {
Enabled bool `json:"enabled"`
Settings map[string]interface{} `json:"settings"`
}
// ACMEProviderManager verwaltet alle ACME-Provider
type ACMEProviderManager struct {
providers map[string]ACMEProvider
configs map[string]*ACMEProviderConfig
configDir string
mu sync.RWMutex
}
var acmeManager *ACMEProviderManager
var acmeOnce sync.Once
// GetACMEManager gibt die Singleton-Instanz des ACMEProviderManagers zurück
func GetACMEManager() *ACMEProviderManager {
acmeOnce.Do(func() {
acmeManager = &ACMEProviderManager{
providers: make(map[string]ACMEProvider),
configs: make(map[string]*ACMEProviderConfig),
configDir: "./config/providers",
}
acmeManager.loadAllConfigs()
})
return acmeManager
}
// RegisterACMEProvider registriert einen neuen ACME-Provider
func (pm *ACMEProviderManager) RegisterACMEProvider(provider ACMEProvider) {
pm.mu.Lock()
defer pm.mu.Unlock()
providerID := provider.GetName()
pm.providers[providerID] = provider
// Lade Konfiguration falls vorhanden
if pm.configs[providerID] == nil {
pm.configs[providerID] = &ACMEProviderConfig{
Enabled: false,
Settings: make(map[string]interface{}),
}
}
}
// GetACMEProvider gibt einen ACME-Provider zurück
func (pm *ACMEProviderManager) GetACMEProvider(id string) (ACMEProvider, bool) {
pm.mu.RLock()
defer pm.mu.RUnlock()
provider, exists := pm.providers[id]
return provider, exists
}
// GetAllACMEProviders gibt alle registrierten ACME-Provider zurück
func (pm *ACMEProviderManager) GetAllACMEProviders() map[string]ACMEProvider {
pm.mu.RLock()
defer pm.mu.RUnlock()
result := make(map[string]ACMEProvider)
for id, provider := range pm.providers {
result[id] = provider
}
return result
}
// GetACMEProviderConfig gibt die Konfiguration eines ACME-Providers zurück
func (pm *ACMEProviderManager) GetACMEProviderConfig(id string) (*ACMEProviderConfig, error) {
pm.mu.RLock()
defer pm.mu.RUnlock()
config, exists := pm.configs[id]
if !exists {
return &ACMEProviderConfig{
Enabled: false,
Settings: make(map[string]interface{}),
}, nil
}
return config, nil
}
// SetACMEProviderEnabled aktiviert/deaktiviert einen ACME-Provider
func (pm *ACMEProviderManager) SetACMEProviderEnabled(id string, enabled bool) error {
pm.mu.Lock()
defer pm.mu.Unlock()
if pm.configs[id] == nil {
pm.configs[id] = &ACMEProviderConfig{
Enabled: enabled,
Settings: make(map[string]interface{}),
}
} else {
pm.configs[id].Enabled = enabled
}
return pm.saveConfig(id, pm.configs[id])
}
// loadAllConfigs lädt alle Konfigurationsdateien
func (pm *ACMEProviderManager) loadAllConfigs() {
// Stelle sicher, dass das Verzeichnis existiert
os.MkdirAll(pm.configDir, 0755)
// Lade alle JSON-Dateien im Konfigurationsverzeichnis
files, err := filepath.Glob(filepath.Join(pm.configDir, "*.json"))
if err != nil {
return
}
for _, file := range files {
id := filepath.Base(file[:len(file)-5]) // Entferne .json
// Nur ACME-Provider-Konfigurationen laden (beginnen mit "letsencrypt")
if id == "letsencrypt-production" || id == "letsencrypt-staging" {
config, err := pm.loadConfig(id)
if err == nil {
pm.configs[id] = config
}
}
}
}
// loadConfig lädt eine Konfigurationsdatei
func (pm *ACMEProviderManager) loadConfig(id string) (*ACMEProviderConfig, error) {
filePath := filepath.Join(pm.configDir, id+".json")
data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
var config ACMEProviderConfig
if err := json.Unmarshal(data, &config); err != nil {
return nil, err
}
return &config, nil
}
// saveConfig speichert eine Konfiguration in eine Datei
func (pm *ACMEProviderManager) saveConfig(id string, config *ACMEProviderConfig) error {
// Stelle sicher, dass das Verzeichnis existiert
os.MkdirAll(pm.configDir, 0755)
filePath := filepath.Join(pm.configDir, id+".json")
data, err := json.MarshalIndent(config, "", " ")
if err != nil {
return err
}
return os.WriteFile(filePath, data, 0644)
}