Self-contained HTTP/HTTPS/TCP/UDP reverse proxy manager written in Go, with SQLite storage, a Bootstrap 5 admin UI (Go templates, no JS framework), and a REST API under /api/v1. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QTXFrNP1imCW7jtfL5SZrw
110 lines
3.4 KiB
Go
110 lines
3.4 KiB
Go
package database
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/owen/vibeproxy/internal/models"
|
|
)
|
|
|
|
func scanCertificate(rs rowScanner) (models.Certificate, error) {
|
|
var c models.Certificate
|
|
var domainsJSON string
|
|
var challengeType, dnsProvider, certPath, keyPath, notBefore, notAfter, lastRenewed, lastErr sql.NullString
|
|
var autoRenew int
|
|
var created, updated string
|
|
err := rs.Scan(&c.ID, &c.Name, &c.Type, &domainsJSON, &challengeType, &dnsProvider, &certPath, &keyPath,
|
|
¬Before, ¬After, &lastRenewed, &lastErr, &autoRenew, &created, &updated)
|
|
if err != nil {
|
|
return c, err
|
|
}
|
|
json.Unmarshal([]byte(domainsJSON), &c.Domains)
|
|
c.ChallengeType = models.ChallengeType(challengeType.String)
|
|
c.DNSProvider = dnsProvider.String
|
|
c.CertPath = certPath.String
|
|
c.KeyPath = keyPath.String
|
|
if notBefore.Valid {
|
|
t := parseTime(notBefore.String)
|
|
c.NotBefore = &t
|
|
}
|
|
if notAfter.Valid {
|
|
t := parseTime(notAfter.String)
|
|
c.NotAfter = &t
|
|
}
|
|
if lastRenewed.Valid {
|
|
t := parseTime(lastRenewed.String)
|
|
c.LastRenewedAt = &t
|
|
}
|
|
c.LastError = lastErr.String
|
|
c.AutoRenew = autoRenew == 1
|
|
c.CreatedAt = parseTime(created)
|
|
c.UpdatedAt = parseTime(updated)
|
|
return c, nil
|
|
}
|
|
|
|
const certCols = `id, name, type, domains, challenge_type, dns_provider, cert_path, key_path, not_before, not_after, last_renewed_at, last_error, auto_renew, created_at, updated_at`
|
|
|
|
func ListCertificates(db *sql.DB) ([]models.Certificate, error) {
|
|
rows, err := db.Query(`SELECT ` + certCols + ` FROM certificates ORDER BY id`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var out []models.Certificate
|
|
for rows.Next() {
|
|
c, err := scanCertificate(rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out = append(out, c)
|
|
}
|
|
return out, rows.Err()
|
|
}
|
|
|
|
func GetCertificate(db *sql.DB, id int64) (*models.Certificate, error) {
|
|
row := db.QueryRow(`SELECT `+certCols+` FROM certificates WHERE id = ?`, id)
|
|
c, err := scanCertificate(row)
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return nil, ErrNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return &c, nil
|
|
}
|
|
|
|
func SaveCertificate(db *sql.DB, c *models.Certificate) (int64, error) {
|
|
domainsJSON, _ := json.Marshal(c.Domains)
|
|
if c.ID == 0 {
|
|
res, err := db.Exec(`INSERT INTO certificates (name, type, domains, challenge_type, dns_provider, cert_path, key_path,
|
|
not_before, not_after, last_renewed_at, last_error, auto_renew) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)`,
|
|
c.Name, c.Type, string(domainsJSON), string(c.ChallengeType), c.DNSProvider, c.CertPath, c.KeyPath,
|
|
timeOrNil(c.NotBefore), timeOrNil(c.NotAfter), timeOrNil(c.LastRenewedAt), c.LastError, boolToInt(c.AutoRenew))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
id, err := res.LastInsertId()
|
|
c.ID = id
|
|
return id, err
|
|
}
|
|
_, err := db.Exec(`UPDATE certificates SET name=?, type=?, domains=?, challenge_type=?, dns_provider=?, cert_path=?,
|
|
key_path=?, not_before=?, not_after=?, last_renewed_at=?, last_error=?, auto_renew=?, updated_at=strftime('%Y-%m-%dT%H:%M:%fZ','now')
|
|
WHERE id=?`, c.Name, c.Type, string(domainsJSON), string(c.ChallengeType), c.DNSProvider, c.CertPath, c.KeyPath,
|
|
timeOrNil(c.NotBefore), timeOrNil(c.NotAfter), timeOrNil(c.LastRenewedAt), c.LastError, boolToInt(c.AutoRenew), c.ID)
|
|
return c.ID, err
|
|
}
|
|
|
|
func DeleteCertificate(db *sql.DB, id int64) error {
|
|
_, err := db.Exec(`DELETE FROM certificates WHERE id = ?`, id)
|
|
return err
|
|
}
|
|
|
|
func timeOrNil(t *time.Time) any {
|
|
if t == nil {
|
|
return nil
|
|
}
|
|
return t.UTC().Format(timeFmt)
|
|
}
|