[新增] 添加 ACME 和 DNS 账号管理功能,支持证书申请与续期

This commit is contained in:
ryan
2026-05-25 14:02:05 +08:00
parent c6a055d5d3
commit 7afe4e5d78
32 changed files with 1796 additions and 76 deletions
+41
View File
@@ -0,0 +1,41 @@
package model
import "time"
type AcmeAccount struct {
ID uint `json:"id" gorm:"primaryKey"`
Email string `json:"email" gorm:"size:255"`
URL string `json:"url" gorm:"size:255"`
PrivateKey string `json:"-" gorm:"type:text;not null"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func GetAcmeAccountByID(id uint) (*AcmeAccount, error) {
account := &AcmeAccount{}
err := DB.First(account, id).Error
return account, err
}
func GetDefaultAcmeAccount() (*AcmeAccount, error) {
account := &AcmeAccount{}
err := DB.Order("id asc").First(account).Error
if err != nil {
// Auto-create a default account placeholder if none exists
account.Email = "admin@openflare.dev"
err = DB.Create(account).Error
}
return account, err
}
func (account *AcmeAccount) Insert() error {
return DB.Create(account).Error
}
func (account *AcmeAccount) Update() error {
return DB.Save(account).Error
}
func (account *AcmeAccount) Delete() error {
return DB.Delete(account).Error
}
@@ -4,7 +4,7 @@ import "time"
const (
legacyDatabaseSchemaVersion = 1
currentDatabaseSchemaVersion = 10
currentDatabaseSchemaVersion = 11
databaseSchemaVersionRowID = 1
)
+35
View File
@@ -0,0 +1,35 @@
package model
import "time"
type DnsAccount struct {
ID uint `json:"id" gorm:"primaryKey"`
Name string `json:"name" gorm:"size:255;not null"`
Type string `json:"type" gorm:"size:64;not null"`
Authorization string `json:"-" gorm:"type:text;not null"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func ListDnsAccounts() (accounts []*DnsAccount, err error) {
err = DB.Order("id desc").Find(&accounts).Error
return accounts, err
}
func GetDnsAccountByID(id uint) (*DnsAccount, error) {
account := &DnsAccount{}
err := DB.First(account, id).Error
return account, err
}
func (account *DnsAccount) Insert() error {
return DB.Create(account).Error
}
func (account *DnsAccount) Update() error {
return DB.Save(account).Error
}
func (account *DnsAccount) Delete() error {
return DB.Delete(account).Error
}
+2
View File
@@ -41,6 +41,8 @@ func registeredModels() []any {
&NodeHealthEvent{},
&TLSCertificate{},
&ManagedDomain{},
&AcmeAccount{},
&DnsAccount{},
}
}
+1 -1
View File
@@ -863,7 +863,7 @@ func TestRunDatabaseSchemaMigrationDoesNotAdvanceVersionWhenValidationFails(t *t
err := runDatabaseSchemaMigration(db, "sqlite", databaseSchemaMigration{
fromVersion: legacyDatabaseSchemaVersion,
toVersion: currentDatabaseSchemaVersion,
toVersion: 11,
migrate: func(tx *gorm.DB, backend string) error {
return autoMigrateSchemaMetadata(tx)
},
+27 -1
View File
@@ -1344,6 +1344,31 @@ func validateDatabaseSchemaV10(db *gorm.DB, backend string) error {
return nil
}
// migrateV11 adds acme and dns accounts and extends tls_certificates.
func migrateV11(db *gorm.DB, backend string) error {
if err := applyCurrentSchema(db, backend); err != nil {
return err
}
// Default values will be applied by gorm for new columns automatically during AutoMigrate.
return nil
}
func validateDatabaseSchemaV11(db *gorm.DB, backend string) error {
if err := validateDatabaseSchemaV10(db, backend); err != nil {
return err
}
if !db.Migrator().HasTable(&AcmeAccount{}) {
return fmt.Errorf("table acme_accounts is missing")
}
if !db.Migrator().HasTable(&DnsAccount{}) {
return fmt.Errorf("table dns_accounts is missing")
}
if !db.Migrator().HasColumn(&TLSCertificate{}, "provider") {
return fmt.Errorf("column tls_certificates.provider is missing")
}
return nil
}
func databaseSchemaMigrations() []databaseSchemaMigration {
return []databaseSchemaMigration{
{fromVersion: 1, toVersion: 2, migrate: migrateV2, validate: validateDatabaseSchemaV2},
@@ -1355,6 +1380,7 @@ func databaseSchemaMigrations() []databaseSchemaMigration {
{fromVersion: 7, toVersion: 8, migrate: migrateV8, validate: validateDatabaseSchemaV8},
{fromVersion: 8, toVersion: 9, migrate: migrateV9, validate: validateDatabaseSchemaV9},
{fromVersion: 9, toVersion: 10, migrate: migrateV10, validate: validateDatabaseSchemaV10},
{fromVersion: 10, toVersion: 11, migrate: migrateV11, validate: validateDatabaseSchemaV11},
}
}
@@ -1440,7 +1466,7 @@ func initializeFreshDatabaseSchema(db *gorm.DB, backend string) error {
if err := ensureDefaultGitHubAuthSource(db); err != nil {
return err
}
if err := validateDatabaseSchemaV10(db, backend); err != nil {
if err := validateDatabaseSchemaV11(db, backend); err != nil {
return err
}
return saveDatabaseSchemaVersion(db, currentDatabaseSchemaVersion)
+22 -9
View File
@@ -3,15 +3,28 @@ package model
import "time"
type TLSCertificate struct {
ID uint `json:"id" gorm:"primaryKey"`
Name string `json:"name" gorm:"uniqueIndex;size:255;not null"`
CertPEM string `json:"-" gorm:"type:text;not null"`
KeyPEM string `json:"-" gorm:"type:text;not null"`
NotBefore time.Time `json:"not_before"`
NotAfter time.Time `json:"not_after"`
Remark string `json:"remark" gorm:"size:255"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ID uint `json:"id" gorm:"primaryKey"`
Name string `json:"name" gorm:"uniqueIndex;size:255;not null"`
CertPEM string `json:"-" gorm:"type:text;not null"`
KeyPEM string `json:"-" gorm:"type:text;not null"`
NotBefore time.Time `json:"not_before"`
NotAfter time.Time `json:"not_after"`
Remark string `json:"remark" gorm:"size:255"`
Provider string `json:"provider" gorm:"size:64;default:'upload'"` // upload, acme
AcmeAccountID uint `json:"acme_account_id"`
DnsAccountID uint `json:"dns_account_id"`
KeyAlgorithm string `json:"key_algorithm" gorm:"size:32"`
AutoRenew bool `json:"auto_renew"`
PrimaryDomain string `json:"primary_domain" gorm:"size:255"`
OtherDomains string `json:"other_domains" gorm:"type:text"`
DisableCNAME bool `json:"disable_cname"`
SkipDNS bool `json:"skip_dns"`
DNS1 string `json:"dns1" gorm:"size:128"`
DNS2 string `json:"dns2" gorm:"size:128"`
ApplyStatus string `json:"apply_status" gorm:"size:64;default:'ready'"`
ApplyMessage string `json:"apply_message" gorm:"type:text"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func ListTLSCertificates() (certificates []*TLSCertificate, err error) {