first commit
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (d *DB) ListDomains() ([]Domain, error) {
|
||||
rows, err := d.Query(`SELECT ` + domainColumns + ` FROM esrv_domains ORDER BY domain_name`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []Domain
|
||||
for rows.Next() {
|
||||
var dm Domain
|
||||
var createdAt string
|
||||
var verifiedAt *string
|
||||
if err := rows.Scan(&dm.ID, &dm.DomainName, &dm.IsActive, &createdAt, &dm.VerificationToken, &dm.IsVerified, &verifiedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dm.CreatedAt, _ = parseTime(createdAt)
|
||||
if verifiedAt != nil {
|
||||
t, _ := parseTime(*verifiedAt)
|
||||
dm.VerifiedAt = &t
|
||||
}
|
||||
out = append(out, dm)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// ListActiveDomains mirrors the `domains` query used to populate <select> lists on the
|
||||
// add/edit sender and IP forms.
|
||||
func (d *DB) ListActiveDomains() ([]Domain, error) {
|
||||
all, err := d.ListDomains()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []Domain
|
||||
for _, dm := range all {
|
||||
if dm.IsActive {
|
||||
out = append(out, dm)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (d *DB) CountActiveDomains() (int, error) {
|
||||
var n int
|
||||
err := d.QueryRow(`SELECT COUNT(*) FROM esrv_domains WHERE is_active = 1`).Scan(&n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// generateVerificationToken returns a random 32-hex-char token for the DNS TXT
|
||||
// ownership check, mirroring the randomness quality already used for DKIM selectors.
|
||||
func generateVerificationToken() string {
|
||||
b := make([]byte, 16)
|
||||
rand.Read(b)
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
// CreateDomain inserts a new, unverified domain with a freshly generated DNS
|
||||
// verification token.
|
||||
func (d *DB) CreateDomain(name string) (int64, error) {
|
||||
res, err := d.Exec(`INSERT INTO esrv_domains (domain_name, is_active, verification_token, is_verified) VALUES (?, 1, ?, 0)`,
|
||||
name, generateVerificationToken())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
func (d *DB) UpdateDomain(id int64, name string, requiresAuth bool) error {
|
||||
_, err := d.Exec(`UPDATE esrv_domains SET domain_name = ? WHERE id = ?`, name, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *DB) SetDomainActive(id int64, active bool) error {
|
||||
_, err := d.Exec(`UPDATE esrv_domains SET is_active = ? WHERE id = ?`, active, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// SetDomainVerified mirrors marking a domain as DNS-ownership-verified (or reverting
|
||||
// it, e.g. if an admin wants to force re-verification).
|
||||
func (d *DB) SetDomainVerified(id int64, verified bool) error {
|
||||
if verified {
|
||||
_, err := d.Exec(`UPDATE esrv_domains SET is_verified = 1, verified_at = ? WHERE id = ?`, time.Now(), id)
|
||||
return err
|
||||
}
|
||||
_, err := d.Exec(`UPDATE esrv_domains SET is_verified = 0, verified_at = NULL WHERE id = ?`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// RegenerateVerificationToken mirrors resetting a domain back to a fresh, unverified
|
||||
// token — used if an admin wants a new TXT value (e.g. suspected leak, or restarting
|
||||
// the ownership proof).
|
||||
func (d *DB) RegenerateVerificationToken(id int64) (string, error) {
|
||||
token := generateVerificationToken()
|
||||
_, err := d.Exec(`UPDATE esrv_domains SET verification_token = ?, is_verified = 0, verified_at = NULL WHERE id = ?`, token, id)
|
||||
return token, err
|
||||
}
|
||||
|
||||
// RemoveDomainCascade hard-deletes a domain and every row that references it, mirroring
|
||||
// domains.remove_domain. Returns counts removed for the flash message.
|
||||
func (d *DB) RemoveDomainCascade(id int64) (senders, ips, dkimKeys, headers int, err error) {
|
||||
tx, err := d.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
for table, count := range map[string]*int{
|
||||
"esrv_senders": &senders,
|
||||
"esrv_whitelisted_ips": &ips,
|
||||
"esrv_dkim_keys": &dkimKeys,
|
||||
"esrv_custom_headers": &headers,
|
||||
} {
|
||||
row := tx.QueryRow(`SELECT COUNT(*) FROM `+table+` WHERE domain_id = ?`, id)
|
||||
if err = row.Scan(count); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = tx.Exec(`DELETE FROM `+table+` WHERE domain_id = ?`, id); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if _, err = tx.Exec(`DELETE FROM esrv_domains WHERE id = ?`, id); err != nil {
|
||||
return
|
||||
}
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user