feat: add DNS credential management with Web UI

- New config/credential_store.go: persistent credential storage (credentials.json)
- New API: CRUD for DNS credentials + credential-types endpoint
- Certificate model now supports credential_id reference
- Create certificate auto-resolves credential_id to DNS config
- New Vue page: Credentials.vue for managing saved DNS keys
- CertCreate.vue: select existing credential or manual input + save as new
- Secrets masked in API responses, never exposed in list
This commit is contained in:
2026-07-24 18:56:03 +08:00
parent adebf82aaa
commit bdb3ca856f
16 changed files with 1032 additions and 139 deletions
+21
View File
@@ -26,6 +26,7 @@ type CreateCertRequest struct {
ChallengeType string `json:"challenge_type"`
DNSProvider string `json:"dns_provider"`
DNSConfig string `json:"dns_config"`
CredentialID *uint `json:"credential_id"`
AutoRenew *bool `json:"auto_renew"`
RenewDays *int `json:"renew_days"`
}
@@ -51,6 +52,19 @@ func (h *CertHandler) GetCertificate(c *gin.Context) {
c.JSON(http.StatusOK, cert)
}
// resolveCredential fills DNSConfig from credential reference if credential_id is set
func resolveCredential(req *CreateCertRequest) error {
if req.CredentialID != nil && *req.CredentialID > 0 {
cred := config.CredStore.GetByID(*req.CredentialID)
if cred == nil {
return fmt.Errorf("credential not found")
}
req.DNSProvider = string(cred.Type)
req.DNSConfig = cred.Data
}
return nil
}
// CreateCertificate creates a new certificate entry and starts issuance
func (h *CertHandler) CreateCertificate(c *gin.Context) {
var req CreateCertRequest
@@ -68,6 +82,12 @@ func (h *CertHandler) CreateCertificate(c *gin.Context) {
req.Domain = strings.TrimSpace(req.Domain)
// Resolve credential reference
if err := resolveCredential(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
autoRenew := true
renewDays := 30
if req.AutoRenew != nil {
@@ -120,6 +140,7 @@ func (h *CertHandler) CreateCertificate(c *gin.Context) {
ChallengeType: req.ChallengeType,
DNSProvider: req.DNSProvider,
DNSConfig: req.DNSConfig,
CredentialID: req.CredentialID,
Status: "pending",
AutoRenew: autoRenew,
RenewDays: renewDays,