implemented LE and ACME and fixed some bugs

This commit is contained in:
2025-11-27 04:20:09 +01:00
parent ec1e0da9d5
commit 145dfd3d7c
36 changed files with 10583 additions and 1107 deletions

79
backend/testing/README.md Normal file
View File

@@ -0,0 +1,79 @@
# Testing Tools
Dieser Ordner enthält Test-Skripte für die Renewal-Funktion.
## Struktur
- `scripts/test_renewal.go` - Skript zum Erstellen von Test-Queue-Einträgen
**Hinweis**: Die Test-Handler (`renewal_test_handlers.go`) befinden sich im Hauptverzeichnis (`backend/`), da sie Teil des `package main` sein müssen, um von `main.go` aufgerufen werden zu können.
## Test-Handler
Die Test-Handler werden automatisch in `main.go` registriert und sind nur für Administratoren zugänglich:
- `POST /api/renewal-queue/test/create` - Erstellt einen Test-Queue-Eintrag
- `POST /api/renewal-queue/test/trigger` - Führt die Queue-Verarbeitung manuell aus
## Test-Skript
Das Test-Skript erstellt Test-Queue-Einträge mit verschiedenen Zeitstempeln:
```bash
cd backend/testing/scripts
go run test_renewal.go
```
Das Skript:
- Findet existierende FQDNs mit Zertifikaten
- Erstellt Test-Queue-Einträge mit verschiedenen Zeitstempeln
- Zeigt den aktuellen Queue-Status an
## Manuelle Tests über API
### 1. Test-Queue-Eintrag erstellen:
```bash
curl -X POST "http://localhost:8080/api/renewal-queue/test/create" \
-u admin:admin \
-H "Content-Type: application/json" \
-d '{
"certificateId": "CERT_ID",
"fqdnId": "FQDN_ID",
"spaceId": "SPACE_ID",
"minutesFromNow": -5
}'
```
**Hinweis**: `minutesFromNow: -5` bedeutet, dass der Eintrag vor 5 Minuten geplant war (also sofort fällig).
### 2. Queue-Verarbeitung manuell auslösen:
```bash
curl -X POST "http://localhost:8080/api/renewal-queue/test/trigger" \
-u admin:admin \
-H "Content-Type: application/json"
```
Dies führt `processRenewalQueue()` direkt aus, ohne auf den Scheduler zu warten.
### 3. Queue-Status abrufen:
```bash
curl -X GET "http://localhost:8080/api/renewal-queue" \
-u admin:admin
```
## Aufräumen
Test-Queue-Einträge können über SQL gelöscht werden:
```sql
DELETE FROM renewal_queue WHERE id LIKE 'test-%';
```
Oder über die Datenbank:
```bash
sqlite3 spaces.db "DELETE FROM renewal_queue WHERE id LIKE 'test-%';"
```

View File

@@ -0,0 +1,223 @@
package main
import (
"context"
"database/sql"
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net/http"
"time"
_ "github.com/mattn/go-sqlite3"
)
// Test-Skript für Renewal-Funktion
// Erstellt Test-Queue-Einträge mit vergangenen Zeitstempeln, um sofortige Tests zu ermöglichen
func main() {
// Konfiguration
// Datenbankpfad relativ zum backend-Verzeichnis (2 Ebenen höher)
dbPath := "../../spaces.db"
apiURL := "http://localhost:8080"
username := "admin"
password := "admin"
// Öffne Datenbank
db, err := sql.Open("sqlite3", dbPath+"?_foreign_keys=1&_journal_mode=WAL")
if err != nil {
log.Fatalf("Fehler beim Öffnen der Datenbank: %v", err)
}
defer db.Close()
// Teste Verbindung
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
log.Fatalf("Fehler beim Verbinden mit der Datenbank: %v", err)
}
fmt.Println("=== Renewal Test-Skript ===")
fmt.Println()
// 1. Hole existierende FQDNs mit Zertifikaten
fmt.Println("1. Suche nach FQDNs mit Zertifikaten...")
rows, err := db.QueryContext(ctx, `
SELECT DISTINCT
f.id as fqdn_id,
f.space_id,
f.fqdn,
c.id as cert_id
FROM fqdns f
INNER JOIN certificates c ON c.fqdn_id = f.id
WHERE f.acme_provider_id = 'certigo-acmeproxy'
LIMIT 5
`)
if err != nil {
log.Fatalf("Fehler beim Abfragen der FQDNs: %v", err)
}
defer rows.Close()
var fqdns []map[string]string
for rows.Next() {
var fqdnID, spaceID, fqdn, certID string
if err := rows.Scan(&fqdnID, &spaceID, &fqdn, &certID); err != nil {
log.Printf("Fehler beim Scannen: %v", err)
continue
}
fqdns = append(fqdns, map[string]string{
"fqdnId": fqdnID,
"spaceId": spaceID,
"fqdn": fqdn,
"certId": certID,
})
}
if len(fqdns) == 0 {
log.Fatal("Keine FQDNs mit Zertifikaten gefunden. Bitte erstelle zuerst ein Zertifikat.")
}
fmt.Printf(" Gefunden: %d FQDNs\n", len(fqdns))
for _, f := range fqdns {
fmt.Printf(" - %s (FQDN ID: %s, Cert ID: %s)\n", f["fqdn"], f["fqdnId"], f["certId"])
}
fmt.Println()
// 2. Erstelle Test-Queue-Einträge mit vergangenen Zeitstempeln
fmt.Println("2. Erstelle Test-Queue-Einträge...")
now := time.Now().UTC()
// Erstelle Einträge mit verschiedenen Zeitstempeln:
// - Einer sofort fällig (vor 1 Minute)
// - Einer in 5 Minuten
// - Einer in 10 Minuten
testTimes := []time.Time{
now.Add(-1 * time.Minute), // Sofort fällig
now.Add(5 * time.Minute), // In 5 Minuten
now.Add(10 * time.Minute), // In 10 Minuten
}
createdCount := 0
for i, fqdn := range fqdns {
if i >= len(testTimes) {
break
}
scheduledAt := testTimes[i]
scheduledAtStr := scheduledAt.Format("2006-01-02 15:04:05")
queueID := fmt.Sprintf("test-%d-%d", time.Now().Unix(), i)
createdAt := now.Format("2006-01-02 15:04:05")
// Prüfe ob Eintrag bereits existiert
var exists bool
err = db.QueryRowContext(ctx, "SELECT EXISTS(SELECT 1 FROM renewal_queue WHERE id = ?)", queueID).Scan(&exists)
if err != nil {
log.Printf("Fehler beim Prüfen: %v", err)
continue
}
if exists {
// Lösche existierenden Eintrag
_, err = db.ExecContext(ctx, "DELETE FROM renewal_queue WHERE id = ?", queueID)
if err != nil {
log.Printf("Fehler beim Löschen: %v", err)
continue
}
}
// Erstelle neuen Eintrag
_, err = db.ExecContext(ctx, `
INSERT INTO renewal_queue (id, certificate_id, fqdn_id, space_id, scheduled_at, status, created_at)
VALUES (?, ?, ?, ?, ?, 'pending', ?)
`, queueID, fqdn["certId"], fqdn["fqdnId"], fqdn["spaceId"], scheduledAtStr, createdAt)
if err != nil {
log.Printf("Fehler beim Erstellen des Queue-Eintrags: %v", err)
continue
}
fmt.Printf(" ✓ Queue-Eintrag erstellt: %s für %s (geplant: %s)\n", queueID, fqdn["fqdn"], scheduledAtStr)
createdCount++
}
fmt.Printf("\n %d Queue-Einträge erstellt\n", createdCount)
fmt.Println()
// 3. Zeige Queue-Status
fmt.Println("3. Aktuelle Queue-Status:")
queueRows, err := db.QueryContext(ctx, `
SELECT
rq.id,
rq.scheduled_at,
rq.status,
f.fqdn
FROM renewal_queue rq
LEFT JOIN fqdns f ON rq.fqdn_id = f.id
WHERE rq.id LIKE 'test-%'
ORDER BY rq.scheduled_at ASC
`)
if err != nil {
log.Printf("Fehler beim Abfragen der Queue: %v", err)
} else {
defer queueRows.Close()
for queueRows.Next() {
var id, scheduledAt, status, fqdn string
if err := queueRows.Scan(&id, &scheduledAt, &status, &fqdn); err != nil {
continue
}
fmt.Printf(" - %s: %s (Status: %s, FQDN: %s)\n", id, scheduledAt, status, fqdn)
}
}
fmt.Println()
// 4. Teste API-Endpunkt (manueller Trigger)
fmt.Println("4. Teste manuellen Queue-Trigger über API...")
fmt.Println(" (Dies würde normalerweise automatisch vom Scheduler ausgeführt)")
fmt.Println()
// Erstelle Basic Auth Header
auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password)))
// Teste Queue-Status über API
client := &http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequest("GET", apiURL+"/api/renewal-queue", nil)
if err != nil {
log.Printf("Fehler beim Erstellen des Requests: %v", err)
} else {
req.Header.Set("Authorization", fmt.Sprintf("Basic %s", auth))
resp, err := client.Do(req)
if err != nil {
log.Printf("Fehler beim Abrufen der Queue: %v", err)
} else {
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
var result struct {
Success bool `json:"success"`
Queue []map[string]interface{} `json:"queue"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err == nil {
fmt.Printf(" ✓ API-Antwort erhalten: %d Einträge in der Queue\n", len(result.Queue))
for _, item := range result.Queue {
if id, ok := item["id"].(string); ok && len(id) > 5 && id[:5] == "test-" {
fmt.Printf(" - Test-Eintrag: %s (Status: %v, Scheduled: %v)\n",
id, item["status"], item["scheduledAt"])
}
}
}
}
}
}
fmt.Println()
fmt.Println("=== Test abgeschlossen ===")
fmt.Println()
fmt.Println("Nächste Schritte:")
fmt.Println("1. Der Scheduler sollte automatisch die fälligen Einträge verarbeiten (alle 5 Minuten)")
fmt.Println("2. Oder warte auf die nächste Scheduler-Ausführung")
fmt.Println("3. Prüfe die Logs für Verarbeitungsdetails")
fmt.Println()
fmt.Println("Zum Aufräumen der Test-Einträge:")
fmt.Println(" DELETE FROM renewal_queue WHERE id LIKE 'test-%';")
}