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 }