This commit is contained in:
parent
eaf2f1d39a
commit
a9f86307d5
1
go.mod
1
go.mod
@ -8,6 +8,7 @@ require (
|
|||||||
github.com/julienschmidt/httprouter v1.3.0
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
github.com/miekg/dns v1.1.29
|
github.com/miekg/dns v1.1.29
|
||||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014
|
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014
|
||||||
|
github.com/oze4/godaddygo v1.3.17
|
||||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||||
github.com/syndtr/goleveldb v1.0.0
|
github.com/syndtr/goleveldb v1.0.0
|
||||||
github.com/yuin/goldmark v1.1.30
|
github.com/yuin/goldmark v1.1.30
|
||||||
|
2
go.sum
2
go.sum
@ -25,6 +25,8 @@ github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
|||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 h1:37VE5TYj2m/FLA9SNr4z0+A0JefvTmR60Zwf8XSEV7c=
|
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 h1:37VE5TYj2m/FLA9SNr4z0+A0JefvTmR60Zwf8XSEV7c=
|
||||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
||||||
|
github.com/oze4/godaddygo v1.3.17 h1:J7LKj8a2XXYI7O/MJIhsscvaRf8/xlRDA9KAq0uY9Z4=
|
||||||
|
github.com/oze4/godaddygo v1.3.17/go.mod h1:8mlHQ5YqhPASKePDoR17pMLhz1i0w4jRJE4wbMlGD60=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
|
1
main.go
1
main.go
@ -54,6 +54,7 @@ import (
|
|||||||
_ "git.happydns.org/happydns/sources/alwaysdata"
|
_ "git.happydns.org/happydns/sources/alwaysdata"
|
||||||
_ "git.happydns.org/happydns/sources/ddns"
|
_ "git.happydns.org/happydns/sources/ddns"
|
||||||
_ "git.happydns.org/happydns/sources/gandi"
|
_ "git.happydns.org/happydns/sources/gandi"
|
||||||
|
_ "git.happydns.org/happydns/sources/godaddy"
|
||||||
_ "git.happydns.org/happydns/sources/ovh"
|
_ "git.happydns.org/happydns/sources/ovh"
|
||||||
|
|
||||||
_ "git.happydns.org/happydns/services/providers/google"
|
_ "git.happydns.org/happydns/services/providers/google"
|
||||||
|
BIN
sources/godaddy/GoDaddyAPI.png
Normal file
BIN
sources/godaddy/GoDaddyAPI.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
286
sources/godaddy/source.go
Normal file
286
sources/godaddy/source.go
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
// Copyright or © or Copr. happyDNS (2021)
|
||||||
|
//
|
||||||
|
// contact@happydns.org
|
||||||
|
//
|
||||||
|
// This software is a computer program whose purpose is to provide a modern
|
||||||
|
// interface to interact with DNS systems.
|
||||||
|
//
|
||||||
|
// This software is governed by the CeCILL license under French law and abiding
|
||||||
|
// by the rules of distribution of free software. You can use, modify and/or
|
||||||
|
// redistribute the software under the terms of the CeCILL license as
|
||||||
|
// circulated by CEA, CNRS and INRIA at the following URL
|
||||||
|
// "http://www.cecill.info".
|
||||||
|
//
|
||||||
|
// As a counterpart to the access to the source code and rights to copy, modify
|
||||||
|
// and redistribute granted by the license, users are provided only with a
|
||||||
|
// limited warranty and the software's author, the holder of the economic
|
||||||
|
// rights, and the successive licensors have only limited liability.
|
||||||
|
//
|
||||||
|
// In this respect, the user's attention is drawn to the risks associated with
|
||||||
|
// loading, using, modifying and/or developing or reproducing the software by
|
||||||
|
// the user in light of its specific status of free software, that may mean
|
||||||
|
// that it is complicated to manipulate, and that also therefore means that it
|
||||||
|
// is reserved for developers and experienced professionals having in-depth
|
||||||
|
// computer knowledge. Users are therefore encouraged to load and test the
|
||||||
|
// software's suitability as regards their requirements in conditions enabling
|
||||||
|
// the security of their systems and/or data to be ensured and, more generally,
|
||||||
|
// to use and operate it in the same conditions as regards security.
|
||||||
|
//
|
||||||
|
// The fact that you are presently reading this means that you have had
|
||||||
|
// knowledge of the CeCILL license and that you accept its terms.
|
||||||
|
|
||||||
|
package godaddy // import "happydns.org/sources/godaddy"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
"github.com/oze4/godaddygo"
|
||||||
|
|
||||||
|
"git.happydns.org/happydns/model"
|
||||||
|
"git.happydns.org/happydns/sources"
|
||||||
|
"git.happydns.org/happydns/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GoDaddyAPI struct {
|
||||||
|
ApiKey string `json:"apiKey,omitempty" happydns:"label=Api Key,placeholder=xxxxxxxxxx,required"`
|
||||||
|
ApiSecret string `json:"apiSecret,omitempty" happydns:"label=Api Secret,placeholder=xxxxxxxxxx,required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoDaddyAPI) ListAvailableTypes() (types []uint16) {
|
||||||
|
return []uint16{
|
||||||
|
dns.TypeA,
|
||||||
|
dns.TypeAAAA,
|
||||||
|
dns.TypeCNAME,
|
||||||
|
dns.TypeMX,
|
||||||
|
dns.TypeNS,
|
||||||
|
dns.TypeSOA,
|
||||||
|
dns.TypeSRV,
|
||||||
|
dns.TypeTXT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoDaddyAPI) newClient() (godaddygo.API, error) {
|
||||||
|
return godaddygo.NewProduction(
|
||||||
|
s.ApiKey,
|
||||||
|
s.ApiSecret,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoDaddyAPI) ListDomains() (zones []string, err error) {
|
||||||
|
var client godaddygo.API
|
||||||
|
client, err = s.newClient()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var domains []godaddygo.DomainSummary
|
||||||
|
domains, err = client.V1().ListDomains(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, domain := range domains {
|
||||||
|
zones = append(zones, dns.Fqdn(domain.Domain))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoDaddyAPI) Validate() error {
|
||||||
|
var client godaddygo.API
|
||||||
|
client, err := s.newClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
avlb, err := client.V1().CheckAvailability(context.Background(), "happydns.org", false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if avlb.Domain != "happydns.org" {
|
||||||
|
return fmt.Errorf("GoDaddy API doesn't returns something usefull. Try update happyDNS or report bug.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoDaddyAPI) DomainExists(fqdn string) (err error) {
|
||||||
|
var client godaddygo.API
|
||||||
|
client, err = s.newClient()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.V1().Domain(strings.TrimSuffix(fqdn, ".")).GetDetails(context.Background())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRR(r *godaddygo.Record, origin string) (dns.RR, error) {
|
||||||
|
if r.Name == "@" {
|
||||||
|
r.Name = origin
|
||||||
|
} else {
|
||||||
|
r.Name = r.Name + "." + origin
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Protocol != "" {
|
||||||
|
r.Name = r.Protocol + "." + r.Name
|
||||||
|
}
|
||||||
|
if r.Service != "" {
|
||||||
|
r.Name = r.Service + "." + r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Type == "TXT" {
|
||||||
|
r.Data = "\"" + r.Data + "\""
|
||||||
|
}
|
||||||
|
|
||||||
|
str := fmt.Sprintf("$ORIGIN .\n%s %d IN %s ", r.Name, r.TTL, r.Type)
|
||||||
|
|
||||||
|
if r.Type == "SRV" {
|
||||||
|
str += fmt.Sprintf("%d %d %d %s", r.Priority, r.Weight, r.Port, r.Data)
|
||||||
|
} else if r.Type == "MX" {
|
||||||
|
str += fmt.Sprintf("%d %s", r.Priority, r.Data)
|
||||||
|
} else {
|
||||||
|
str += r.Data
|
||||||
|
}
|
||||||
|
|
||||||
|
return dns.NewRR(str)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoDaddyAPI) ImportZone(dn *happydns.Domain) (rrs []dns.RR, err error) {
|
||||||
|
var client godaddygo.API
|
||||||
|
client, err = s.newClient()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var records []godaddygo.Record
|
||||||
|
records, err = client.V1().Domain(strings.TrimSuffix(dn.DomainName, ".")).Records().List(context.Background())
|
||||||
|
|
||||||
|
for _, r := range records {
|
||||||
|
var rr dns.RR
|
||||||
|
rr, err = toRR(&r, dn.DomainName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rrs = append(rrs, rr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSubdomain(dn *happydns.Domain, rr dns.RR) string {
|
||||||
|
str := strings.TrimSuffix(strings.TrimSuffix(rr.Header().Name, dn.DomainName), ".")
|
||||||
|
if len(str) == 0 {
|
||||||
|
return "@"
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
func createGoDaddyRecord(rr dns.RR, dn *happydns.Domain) godaddygo.Record {
|
||||||
|
record := godaddygo.Record{
|
||||||
|
Name: getSubdomain(dn, rr),
|
||||||
|
TTL: int(rr.Header().Ttl),
|
||||||
|
Type: dns.Type(rr.Header().Rrtype).String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if mx, ok := rr.(*dns.MX); ok {
|
||||||
|
record.Priority = int(mx.Preference)
|
||||||
|
record.Data = strings.TrimSuffix(utils.DomainFQDN(mx.Mx, dn.DomainName), ".")
|
||||||
|
} else if srv, ok := rr.(*dns.SRV); ok {
|
||||||
|
record.Priority = int(srv.Priority)
|
||||||
|
record.Weight = int(srv.Weight)
|
||||||
|
record.Port = int(srv.Port)
|
||||||
|
record.Data = strings.TrimSuffix(utils.DomainFQDN(srv.Target, dn.DomainName), ".")
|
||||||
|
|
||||||
|
sname := strings.SplitN(record.Name, ".", 3)
|
||||||
|
if len(sname) == 3 && sname[0][0] == '_' && sname[1][0] == '_' {
|
||||||
|
record.Service = sname[0]
|
||||||
|
record.Protocol = sname[1]
|
||||||
|
record.Name = sname[2]
|
||||||
|
} else if len(sname) == 2 && sname[0][0] == '_' && sname[1][0] == '_' {
|
||||||
|
record.Service = sname[0]
|
||||||
|
record.Protocol = sname[1]
|
||||||
|
record.Name = "@"
|
||||||
|
}
|
||||||
|
} else if cname, ok := rr.(*dns.CNAME); ok {
|
||||||
|
record.Data = strings.TrimSuffix(utils.DomainFQDN(cname.Target, dn.DomainName), ".")
|
||||||
|
} else if ns, ok := rr.(*dns.NS); ok {
|
||||||
|
record.Data = strings.TrimSuffix(utils.DomainFQDN(ns.Ns, dn.DomainName), ".")
|
||||||
|
} else {
|
||||||
|
record.Data = strings.TrimPrefix(rr.String(), rr.Header().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return record
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoDaddyAPI) AddRR(dn *happydns.Domain, rr dns.RR) (err error) {
|
||||||
|
var client godaddygo.API
|
||||||
|
client, err = s.newClient()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sup := createGoDaddyRecord(rr, dn)
|
||||||
|
|
||||||
|
err = client.V1().Domain(strings.TrimSuffix(dn.DomainName, ".")).Records().Add(context.Background(), []godaddygo.Record{sup})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoDaddyAPI) DeleteRR(dn *happydns.Domain, rr dns.RR) (err error) {
|
||||||
|
var client godaddygo.API
|
||||||
|
client, err = s.newClient()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
del := createGoDaddyRecord(rr, dn)
|
||||||
|
|
||||||
|
// Apparently, we can't pass an empty array to ReplaceByType when Name=@, this doesn't delete the last record.
|
||||||
|
// So, passing the entire domain each time...
|
||||||
|
var records []godaddygo.Record
|
||||||
|
records, err = client.V1().Domain(strings.TrimSuffix(dn.DomainName, ".")).Records().List(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println(records)
|
||||||
|
// Find the right record
|
||||||
|
for i, rec := range records {
|
||||||
|
if rec.Name == del.Name &&
|
||||||
|
rec.Data == del.Data &&
|
||||||
|
rec.Port == del.Port &&
|
||||||
|
rec.Priority == del.Priority &&
|
||||||
|
rec.Protocol == del.Protocol &&
|
||||||
|
rec.Service == del.Service &&
|
||||||
|
rec.Type == del.Type &&
|
||||||
|
rec.Weight == del.Weight {
|
||||||
|
records = append(records[:i], records[i+1:]...)
|
||||||
|
err = client.V1().Domain(strings.TrimSuffix(dn.DomainName, ".")).Records().Update(context.Background(), records)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fmt.Errorf("Unable to find the good record to delete in the zone.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoDaddyAPI) UpdateSOA(dn *happydns.Domain, newSOA *dns.SOA, refreshSerial bool) (err error) {
|
||||||
|
return fmt.Errorf("Not implemented yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
sources.RegisterSource(func() happydns.Source {
|
||||||
|
return &GoDaddyAPI{}
|
||||||
|
}, sources.SourceInfos{
|
||||||
|
Name: "GoDaddy",
|
||||||
|
Description: "American hosting provider.",
|
||||||
|
})
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user