191 lines
5 KiB
Go
191 lines
5 KiB
Go
package provider
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"git.maurice.fr/thomas/mailout/pkg/config"
|
|
"git.maurice.fr/thomas/mailout/pkg/models"
|
|
"git.maurice.fr/thomas/mailout/pkg/utils"
|
|
ovhgo "github.com/ovh/go-ovh/ovh"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type OVHProvider struct {
|
|
client *ovhgo.Client
|
|
}
|
|
|
|
func NewOVHProvider(cfg *config.Config) (Provider, error) {
|
|
config := cfg.Providers.OVH
|
|
|
|
if config == nil {
|
|
return nil, fmt.Errorf("no ovh configuration specified")
|
|
}
|
|
|
|
c, err := ovhgo.NewClient(
|
|
config.Endpoint,
|
|
config.ApplicationKey,
|
|
config.ApplicationSecret,
|
|
config.ConsumerKey,
|
|
)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &OVHProvider{
|
|
client: c,
|
|
}, nil
|
|
}
|
|
|
|
func (p *OVHProvider) AddDKIMRecord(dkimkey *models.DKIMKey) error {
|
|
logger := logrus.WithFields(logrus.Fields{
|
|
"dkimkey": dkimkey.ID,
|
|
"selector": dkimkey.Selector,
|
|
})
|
|
|
|
zone, err := utils.GetZone(dkimkey.DomainName)
|
|
if err != nil {
|
|
return fmt.Errorf("could not determine zone: %w", err)
|
|
}
|
|
|
|
subdomain, err := utils.GetSubdomain(dkimkey.DomainName)
|
|
if err != nil {
|
|
return fmt.Errorf("could not determine subdomain: %w", err)
|
|
}
|
|
|
|
if subdomain == "" {
|
|
subdomain = zone
|
|
}
|
|
|
|
logger = logger.WithFields(logrus.Fields{
|
|
"zone": zone,
|
|
"subdomain": subdomain,
|
|
})
|
|
|
|
dkimSub := fmt.Sprintf("%s._domainkey.%s", dkimkey.Selector, subdomain)
|
|
result := make([]int, 0)
|
|
|
|
err = p.client.Get(fmt.Sprintf("/domain/zone/%s/record?fieldType=TXT&subDomain=%s", zone, dkimSub), &result)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("could not lookup records: %w", err)
|
|
}
|
|
|
|
type createParams struct {
|
|
FieldType string `json:"fieldType"`
|
|
SubDomain string `json:"subDomain"`
|
|
Target string `json:"target"`
|
|
TTL int `json:"ttl"`
|
|
}
|
|
|
|
type updateParams struct {
|
|
SubDomain string `json:"subDomain"`
|
|
Target string `json:"target"`
|
|
TTL int `json:"ttl"`
|
|
}
|
|
|
|
if len(result) == 0 {
|
|
logger.Info("no DKIM records found, creating a new one")
|
|
|
|
c := createParams{
|
|
FieldType: "TXT",
|
|
SubDomain: fmt.Sprintf("%s._domainkey.%s", dkimkey.Selector, subdomain),
|
|
Target: fmt.Sprintf("v=DKIM1; k=rsa; p=%s", dkimkey.PublicKey),
|
|
TTL: 60,
|
|
}
|
|
|
|
err = p.client.Post(fmt.Sprintf("/domain/zone/%s/record", zone), &c, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("could not create new record: %w", err)
|
|
}
|
|
logger.Info("created new DKIM record")
|
|
|
|
err = p.client.Post(fmt.Sprintf("/domain/zone/%s/refresh", zone), nil, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("could not refresh the zone: %w", err)
|
|
}
|
|
logger.Info("refreshed zone")
|
|
} else if len(result) == 1 {
|
|
logger.Info("found one record, updating it")
|
|
|
|
u := updateParams{
|
|
SubDomain: fmt.Sprintf("%s._domainkey.%s", dkimkey.Selector, subdomain),
|
|
Target: fmt.Sprintf("v=DKIM1; k=rsa; p=%s", dkimkey.PublicKey),
|
|
TTL: 60,
|
|
}
|
|
|
|
err = p.client.Put(fmt.Sprintf("/domain/zone/%s/record/%d", zone, result[0]), &u, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("could not update record: %w", err)
|
|
}
|
|
logger.Info("updated existing record")
|
|
|
|
err = p.client.Post(fmt.Sprintf("/domain/zone/%s/refresh", zone), nil, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("could not refresh the zone: %w", err)
|
|
}
|
|
logger.Info("refreshed zone")
|
|
} else {
|
|
logrus.Error("more than 1 records matched the query, it is unsafe for me to proceed, check the DNS zone manually")
|
|
return fmt.Errorf("more than one record returned for update/creation")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *OVHProvider) DeleteDKIMRecord(dkimkey *models.DKIMKey) error {
|
|
logger := logrus.WithFields(logrus.Fields{
|
|
"dkimkey": dkimkey.ID,
|
|
"selector": dkimkey.Selector,
|
|
})
|
|
|
|
zone, err := utils.GetZone(dkimkey.DomainName)
|
|
if err != nil {
|
|
return fmt.Errorf("could not determine zone: %w", err)
|
|
}
|
|
subdomain, err := utils.GetSubdomain(dkimkey.DomainName)
|
|
if err != nil {
|
|
return fmt.Errorf("could not determine subdomain: %w", err)
|
|
}
|
|
|
|
if subdomain == "" {
|
|
subdomain = zone
|
|
}
|
|
|
|
logger = logger.WithFields(logrus.Fields{
|
|
"zone": zone,
|
|
"subdomain": subdomain,
|
|
})
|
|
|
|
dkimSub := fmt.Sprintf("%s._domainkey.%s", dkimkey.Selector, subdomain)
|
|
result := make([]int, 0)
|
|
|
|
err = p.client.Get(fmt.Sprintf("/domain/zone/%s/record?fieldType=TXT&subDomain=%s", zone, dkimSub), &result)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("could not lookup records: %w", err)
|
|
}
|
|
|
|
if len(result) == 0 {
|
|
logger.Info("no DKIM records found, no need to do anything")
|
|
} else if len(result) == 1 {
|
|
logger.Info("found one record, deleting it")
|
|
|
|
err = p.client.Delete(fmt.Sprintf("/domain/zone/%s/record/%d", zone, result[0]), nil)
|
|
if err != nil {
|
|
return fmt.Errorf("could not delete record: %w", err)
|
|
}
|
|
logger.Info("deleted existing record")
|
|
|
|
err = p.client.Post(fmt.Sprintf("/domain/zone/%s/refresh", zone), nil, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("could not refresh the zone: %w", err)
|
|
}
|
|
logger.Info("refreshed zone")
|
|
} else {
|
|
logrus.Error("more than 1 records matched the query, it is unsafe for me to proceed, check the DNS zone manually")
|
|
return fmt.Errorf("more than one record returned for deletion")
|
|
}
|
|
|
|
return nil
|
|
}
|