111 lines
3.2 KiB
Go
111 lines
3.2 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
type SSLCertificate struct {
|
|
ID int64 `json:"id"`
|
|
DomainID int64 `json:"domain_id"`
|
|
Type string `json:"type"`
|
|
Status string `json:"status"`
|
|
Issuer *string `json:"issuer,omitempty"`
|
|
ErrorMessage *string `json:"error_message,omitempty"`
|
|
IssuedAt *time.Time `json:"issued_at,omitempty"`
|
|
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
|
AutoRenew bool `json:"auto_renew"`
|
|
}
|
|
|
|
type SSLRepository struct {
|
|
pool *pgxpool.Pool
|
|
}
|
|
|
|
func NewSSLRepository(pool *pgxpool.Pool) *SSLRepository {
|
|
return &SSLRepository{pool: pool}
|
|
}
|
|
|
|
func (r *SSLRepository) CreatePending(ctx context.Context, domainID int64) (int64, error) {
|
|
const q = `
|
|
INSERT INTO ssl_certificates (domain_id, type, status, auto_renew)
|
|
VALUES ($1, 'letsencrypt', 'pending', true)
|
|
RETURNING id
|
|
`
|
|
var id int64
|
|
err := r.pool.QueryRow(ctx, q, domainID).Scan(&id)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("create ssl cert: %w", err)
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func (r *SSLRepository) MarkActive(ctx context.Context, id int64, issuer, certPEM, keyPEM, chainPEM string, issuedAt, expiresAt time.Time) error {
|
|
const q = `
|
|
UPDATE ssl_certificates
|
|
SET status = 'active', issuer = $2, cert_pem = $3, key_pem = $4, chain_pem = $5,
|
|
issued_at = $6, expires_at = $7, error_message = NULL, updated_at = now()
|
|
WHERE id = $1
|
|
`
|
|
_, err := r.pool.Exec(ctx, q, id, issuer, certPEM, keyPEM, chainPEM, issuedAt, expiresAt)
|
|
return err
|
|
}
|
|
|
|
func (r *SSLRepository) MarkError(ctx context.Context, id int64, msg string) error {
|
|
const q = `
|
|
UPDATE ssl_certificates
|
|
SET status = 'error', error_message = $2, updated_at = now()
|
|
WHERE id = $1
|
|
`
|
|
_, err := r.pool.Exec(ctx, q, id, msg)
|
|
return err
|
|
}
|
|
|
|
func (r *SSLRepository) GetByDomainID(ctx context.Context, domainID int64) (*SSLCertificate, error) {
|
|
const q = `
|
|
SELECT id, domain_id, type::text, status::text, issuer, error_message, issued_at, expires_at, auto_renew
|
|
FROM ssl_certificates WHERE domain_id = $1 ORDER BY id DESC LIMIT 1
|
|
`
|
|
var c SSLCertificate
|
|
err := r.pool.QueryRow(ctx, q, domainID).Scan(
|
|
&c.ID, &c.DomainID, &c.Type, &c.Status, &c.Issuer, &c.ErrorMessage,
|
|
&c.IssuedAt, &c.ExpiresAt, &c.AutoRenew,
|
|
)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &c, nil
|
|
}
|
|
|
|
func (r *SSLRepository) GetDomainInfo(ctx context.Context, domainID int64) (domain string, webroot string, err error) {
|
|
const q = `
|
|
SELECT d.domain::text, s.document_root
|
|
FROM domains d
|
|
JOIN sites s ON s.id = d.site_id
|
|
WHERE d.id = $1
|
|
`
|
|
err = r.pool.QueryRow(ctx, q, domainID).Scan(&domain, &webroot)
|
|
return
|
|
}
|
|
|
|
func (r *SSLRepository) GetSiteOwner(ctx context.Context, siteID int64) (int64, error) {
|
|
var ownerID int64
|
|
err := r.pool.QueryRow(ctx, `SELECT owner_id FROM sites WHERE id = $1`, siteID).Scan(&ownerID)
|
|
return ownerID, err
|
|
}
|
|
|
|
func (r *SSLRepository) GetDomainIDBySite(ctx context.Context, siteID int64) (int64, error) {
|
|
var id int64
|
|
err := r.pool.QueryRow(ctx, `
|
|
SELECT id FROM domains WHERE site_id = $1 AND is_primary = true LIMIT 1
|
|
`, siteID).Scan(&id)
|
|
return id, err
|
|
}
|