mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-09-20 06:46:19 +08:00
Lint: Fix ST1005: error strings should not be capitalized (#834)
This commit is contained in:
parent
ca136992f8
commit
de308c0952
|
@ -58,7 +58,7 @@ func checkGoFmt() error {
|
|||
if fList == "" {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("The following files need to have gofmt run on them:\n%s", fList)
|
||||
return fmt.Errorf("the following files need to have gofmt run on them:\n%s", fList)
|
||||
}
|
||||
|
||||
func checkGoGenerate() error {
|
||||
|
|
|
@ -116,7 +116,7 @@ func parseargs(args []string) (zonename string, filename string, r io.Reader, er
|
|||
filename = flag.Arg(1)
|
||||
r, err = os.Open(filename)
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("Could not open file: %s: %w", filename, err)
|
||||
return "", "", nil, fmt.Errorf("could not open file: %s: %w", filename, err)
|
||||
}
|
||||
} else {
|
||||
return "", "", nil, fmt.Errorf("too many command line parameters")
|
||||
|
|
|
@ -126,7 +126,7 @@ func preloadProviders(cfg *models.DNSConfig, err error) (*models.DNSConfig, erro
|
|||
for _, d := range cfg.Domains {
|
||||
reg, ok := cfg.RegistrarsByName[d.RegistrarName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Registrar named %s expected for %s, but never registered", d.RegistrarName, d.Name)
|
||||
return nil, fmt.Errorf("registrar named %s expected for %s, but never registered", d.RegistrarName, d.Name)
|
||||
}
|
||||
d.RegistrarInstance = &models.RegistrarInstance{
|
||||
ProviderBase: models.ProviderBase{
|
||||
|
|
|
@ -126,10 +126,10 @@ func GetCerts(args GetCertsArgs) error {
|
|||
fmt.Println(args.JSFile)
|
||||
// check agree flag
|
||||
if !args.AgreeTOS {
|
||||
return fmt.Errorf("You must agree to the Let's Encrypt Terms of Service by using -agreeTOS")
|
||||
return fmt.Errorf("you must agree to the Let's Encrypt Terms of Service by using -agreeTOS")
|
||||
}
|
||||
if args.Email == "" {
|
||||
return fmt.Errorf("Must provide email to use for Let's Encrypt registration")
|
||||
return fmt.Errorf("must provide email to use for Let's Encrypt registration")
|
||||
}
|
||||
|
||||
// load dns config
|
||||
|
@ -139,7 +139,7 @@ func GetCerts(args GetCertsArgs) error {
|
|||
}
|
||||
errs := normalize.ValidateAndNormalizeConfig(cfg)
|
||||
if PrintValidationErrors(errs) {
|
||||
return fmt.Errorf("Exiting due to validation errors")
|
||||
return fmt.Errorf("exiting due to validation errors")
|
||||
}
|
||||
notifier, err := InitializeProviders(args.CredsFile, cfg, args.Notify)
|
||||
if err != nil {
|
||||
|
@ -163,7 +163,7 @@ func GetCerts(args GetCertsArgs) error {
|
|||
return err
|
||||
}
|
||||
if len(certList) == 0 {
|
||||
return fmt.Errorf("Must provide at least one certificate to issue in cert configuration")
|
||||
return fmt.Errorf("must provide at least one certificate to issue in cert configuration")
|
||||
}
|
||||
if err = validateCertificateList(certList, cfg); err != nil {
|
||||
return err
|
||||
|
|
|
@ -101,7 +101,7 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
|||
}
|
||||
errs := normalize.ValidateAndNormalizeConfig(cfg)
|
||||
if PrintValidationErrors(errs) {
|
||||
return fmt.Errorf("Exiting due to validation errors")
|
||||
return fmt.Errorf("exiting due to validation errors")
|
||||
}
|
||||
// TODO:
|
||||
notifier, err := InitializeProviders(args.CredsFile, cfg, args.Notify)
|
||||
|
@ -169,10 +169,10 @@ DomainLoop:
|
|||
notifier.Done()
|
||||
out.Printf("Done. %d corrections.\n", totalCorrections)
|
||||
if anyErrors {
|
||||
return fmt.Errorf("Completed with errors")
|
||||
return fmt.Errorf("completed with errors")
|
||||
}
|
||||
if totalCorrections != 0 && args.WarnChanges {
|
||||
return fmt.Errorf("There are pending changes")
|
||||
return fmt.Errorf("there are pending changes")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ func PrintIR(args PrintIRArgs) error {
|
|||
if !args.Raw {
|
||||
errs := normalize.ValidateAndNormalizeConfig(cfg)
|
||||
if PrintValidationErrors(errs) {
|
||||
return fmt.Errorf("Exiting due to validation errors")
|
||||
return fmt.Errorf("exiting due to validation errors")
|
||||
}
|
||||
}
|
||||
return PrintJSON(args.PrintJSONArgs, cfg)
|
||||
|
@ -98,12 +98,12 @@ func PrintValidationErrors(errs []error) (fatal bool) {
|
|||
// ExecuteDSL executes the dnsconfig.js contents.
|
||||
func ExecuteDSL(args ExecuteDSLArgs) (*models.DNSConfig, error) {
|
||||
if args.JSFile == "" {
|
||||
return nil, fmt.Errorf("No config specified")
|
||||
return nil, fmt.Errorf("no config specified")
|
||||
}
|
||||
|
||||
dnsConfig, err := js.ExecuteJavascript(args.JSFile, args.DevMode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Executing javascript in %s: %s", args.JSFile, err)
|
||||
return nil, fmt.Errorf("executing javascript in %s: %s", args.JSFile, err)
|
||||
}
|
||||
return dnsConfig, nil
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -51,7 +51,7 @@ require (
|
|||
github.com/vultr/govultr v0.2.0
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207 // indirect
|
||||
golang.org/x/tools v0.0.0-20200828161849-5deb26317202 // indirect
|
||||
google.golang.org/api v0.28.0
|
||||
google.golang.org/appengine v1.6.6 // indirect
|
||||
gopkg.in/ini.v1 v1.42.0 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -477,6 +477,8 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
|
|||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207 h1:8Kg+JssU1jBZs8GIrL5pl4nVyaqyyhdmHAR4D1zGErg=
|
||||
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200828161849-5deb26317202 h1:DrWbY9UUFi/sl/3HkNVoBjDbGfIPZZfgoGsGxOL1EU8=
|
||||
golang.org/x/tools v0.0.0-20200828161849-5deb26317202/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -24,13 +24,13 @@ func (r *RecordConfig) PopulateFromString(rtype, contents, origin string) error
|
|||
case "A":
|
||||
ip := net.ParseIP(contents)
|
||||
if ip == nil || ip.To4() == nil {
|
||||
return fmt.Errorf("A record with invalid IP: %s", contents)
|
||||
return fmt.Errorf("invalid IP in A record: %s", contents)
|
||||
}
|
||||
return r.SetTargetIP(ip) // Reformat to canonical form.
|
||||
case "AAAA":
|
||||
ip := net.ParseIP(contents)
|
||||
if ip == nil || ip.To16() == nil {
|
||||
return fmt.Errorf("AAAA record with invalid IP: %s", contents)
|
||||
return fmt.Errorf("invalid IP in AAAA record: %s", contents)
|
||||
}
|
||||
return r.SetTargetIP(ip) // Reformat to canonical form.
|
||||
case "ANAME", "CNAME", "NS", "PTR":
|
||||
|
@ -54,7 +54,7 @@ func (r *RecordConfig) PopulateFromString(rtype, contents, origin string) error
|
|||
case "TXT":
|
||||
return r.SetTargetTXTString(contents)
|
||||
default:
|
||||
return fmt.Errorf("Unknown rtype (%s) when parsing (%s) domain=(%s)",
|
||||
return fmt.Errorf("unknown rtype (%s) when parsing (%s) domain=(%s)",
|
||||
rtype, contents, origin)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ func (c *certManager) IssueOrRenewCert(cfg *CertConfig, renewUnder int, verbose
|
|||
func getCertInfo(pemBytes []byte) (names []string, remaining float64, err error) {
|
||||
block, _ := pem.Decode(pemBytes)
|
||||
if block == nil {
|
||||
return nil, 0, fmt.Errorf("Invalid certificate pem data")
|
||||
return nil, 0, fmt.Errorf("invalid certificate PEM data")
|
||||
}
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
|
@ -252,7 +252,7 @@ func (c *certManager) ensureNoPendingCorrections(d *models.DomainConfig) error {
|
|||
for _, c := range corrections {
|
||||
fmt.Println(c.Msg)
|
||||
}
|
||||
return fmt.Errorf("Found %d pending corrections for %s. Not going to proceed issuing certificates", len(corrections), d.Name)
|
||||
return fmt.Errorf("found %d pending corrections for %s. Not going to proceed issuing certificates", len(corrections), d.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ func (d directoryStorage) GetAccount(acmeHost string) (*Account, error) {
|
|||
}
|
||||
keyBlock, _ := pem.Decode(keyBytes)
|
||||
if keyBlock == nil {
|
||||
return nil, fmt.Errorf("Error decoding account private key")
|
||||
return nil, fmt.Errorf("error decoding account private key")
|
||||
}
|
||||
acct.key, err = x509.ParseECPrivateKey(keyBlock.Bytes)
|
||||
if err != nil {
|
||||
|
|
|
@ -68,11 +68,11 @@ func (v *vaultStorage) GetCertificate(name string) (*certificate.Resource, error
|
|||
func (v *vaultStorage) getString(key string, data map[string]interface{}, path string) ([]byte, error) {
|
||||
dat, ok := data[key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Secret at %s does not have key %s", path, key)
|
||||
return nil, fmt.Errorf("secret at %s does not have key %s", path, key)
|
||||
}
|
||||
str, ok := dat.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Secret at %s is not string", path)
|
||||
return nil, fmt.Errorf("secret at %s is not string", path)
|
||||
}
|
||||
return []byte(str), nil
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ func (v *vaultStorage) GetAccount(acmeHost string) (*Account, error) {
|
|||
if dat, err = v.getString("tls.key", secret.Data, path); err != nil {
|
||||
return nil, err
|
||||
} else if block, _ = pem.Decode(dat); block == nil {
|
||||
return nil, fmt.Errorf("Error decoding account private key")
|
||||
return nil, fmt.Errorf("error decoding account private key")
|
||||
} else if key, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -108,9 +108,9 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
|
|||
}
|
||||
for _, dr := range desired {
|
||||
if d.matchIgnoredName(dr.GetLabel()) {
|
||||
return nil, nil, nil, nil, fmt.Errorf("Trying to update/add IGNORE_NAMEd record: %s %s", dr.GetLabel(), dr.Type)
|
||||
return nil, nil, nil, nil, fmt.Errorf("trying to update/add IGNORE_NAMEd record: %s %s", dr.GetLabel(), dr.Type)
|
||||
} else if d.matchIgnoredTarget(dr.GetTargetField(), dr.Type) {
|
||||
return nil, nil, nil, nil, fmt.Errorf("Trying to update/add IGNORE_TARGETd record: %s %s", dr.GetLabel(), dr.Type)
|
||||
return nil, nil, nil, nil, fmt.Errorf("trying to update/add IGNORE_TARGETd record: %s %s", dr.GetLabel(), dr.Type)
|
||||
} else {
|
||||
k := dr.Key()
|
||||
desiredByNameAndType[k] = append(desiredByNameAndType[k], dr)
|
||||
|
|
|
@ -3,13 +3,14 @@ package js
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/robertkrimen/otto" // load underscore js into vm by default
|
||||
_ "github.com/robertkrimen/otto/underscore" // required by otto
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/robertkrimen/otto" // load underscore js into vm by default
|
||||
_ "github.com/robertkrimen/otto/underscore" // required by otto
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/transform"
|
||||
|
@ -27,7 +28,7 @@ var currentDirectory string
|
|||
func ExecuteJavascript(file string, devMode bool) (*models.DNSConfig, error) {
|
||||
script, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Reading js file %s: %s", file, err)
|
||||
return nil, fmt.Errorf("reading js file %s: %s", file, err)
|
||||
}
|
||||
|
||||
// Record the directory path leading up to this file.
|
||||
|
|
|
@ -69,7 +69,7 @@ func flattenSPFs(cfg *models.DNSConfig) []error {
|
|||
}
|
||||
|
||||
if !strings.Contains(split, "%d") {
|
||||
errs = append(errs, Warning{fmt.Errorf("Split format `%s` in `%s` is not proper format (should have %%d in it)", split, txt.GetLabelFQDN())})
|
||||
errs = append(errs, Warning{fmt.Errorf("split format `%s` in `%s` is not proper format (missing %%d)", split, txt.GetLabelFQDN())})
|
||||
continue
|
||||
}
|
||||
recs := rec.TXTSplit(split+"."+domain.Name, overhead1, txtMaxSize)
|
||||
|
|
|
@ -69,11 +69,11 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
|
|||
if !ok {
|
||||
cType := providers.GetCustomRecordType(rec.Type)
|
||||
if cType == nil {
|
||||
return fmt.Errorf("Unsupported record type (%v) domain=%v name=%v", rec.Type, domain, rec.GetLabel())
|
||||
return fmt.Errorf("unsupported record type (%v) domain=%v name=%v", rec.Type, domain, rec.GetLabel())
|
||||
}
|
||||
for _, providerType := range pTypes {
|
||||
if providerType != cType.Provider {
|
||||
return fmt.Errorf("Custom record type %s is not compatible with provider type %s", rec.Type, providerType)
|
||||
return fmt.Errorf("custom record type %s is not compatible with provider type %s", rec.Type, providerType)
|
||||
}
|
||||
}
|
||||
// it is ok. Lets replace the type with real type and add metadata to say we checked it
|
||||
|
@ -152,7 +152,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
|||
target := rec.GetTargetField()
|
||||
check := func(e error) {
|
||||
if e != nil {
|
||||
err := fmt.Errorf("In %s %s.%s: %s", rec.Type, rec.GetLabel(), domain, e.Error())
|
||||
err := fmt.Errorf("in %s %s.%s: %s", rec.Type, rec.GetLabel(), domain, e.Error())
|
||||
if _, ok := e.(Warning); ok {
|
||||
err = Warning{err}
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) {
|
|||
// Validate FQDN consistency
|
||||
for _, r := range d.Records {
|
||||
if r.NameFQDN == "" || !strings.HasSuffix(r.NameFQDN, d.Name) {
|
||||
errs = append(errs, fmt.Errorf("Record named '%s' does not have correct FQDN in domain '%s'. FQDN: %s", r.Name, d.Name, r.NameFQDN))
|
||||
errs = append(errs, fmt.Errorf("record named '%s' does not have correct FQDN for domain '%s'. FQDN: %s", r.Name, d.Name, r.NameFQDN))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -419,14 +419,14 @@ func checkCNAMEs(dc *models.DomainConfig) (errs []error) {
|
|||
for _, r := range dc.Records {
|
||||
if r.Type == "CNAME" {
|
||||
if cnames[r.GetLabel()] {
|
||||
errs = append(errs, fmt.Errorf("Cannot have multiple CNAMEs with same name: %s", r.GetLabelFQDN()))
|
||||
errs = append(errs, fmt.Errorf("cannot have multiple CNAMEs with same name: %s", r.GetLabelFQDN()))
|
||||
}
|
||||
cnames[r.GetLabel()] = true
|
||||
}
|
||||
}
|
||||
for _, r := range dc.Records {
|
||||
if cnames[r.GetLabel()] && r.Type != "CNAME" {
|
||||
errs = append(errs, fmt.Errorf("Cannot have CNAME and %s record with same name: %s", r.Type, r.GetLabelFQDN()))
|
||||
errs = append(errs, fmt.Errorf("cannot have CNAME and %s record with same name: %s", r.Type, r.GetLabelFQDN()))
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -437,7 +437,7 @@ func checkDuplicates(records []*models.RecordConfig) (errs []error) {
|
|||
for _, r := range records {
|
||||
diffable := fmt.Sprintf("%s %s %s", r.GetLabelFQDN(), r.Type, r.ToDiffable())
|
||||
if seen[diffable] != nil {
|
||||
errs = append(errs, fmt.Errorf("Exact duplicate record found: %s", diffable))
|
||||
errs = append(errs, fmt.Errorf("exact duplicate record found: %s", diffable))
|
||||
}
|
||||
seen[diffable] = r
|
||||
}
|
||||
|
@ -545,7 +545,7 @@ func checkProviderCapabilities(dc *models.DomainConfig) error {
|
|||
for _, provider := range dc.DNSProviderInstances {
|
||||
// fmt.Printf(" (checking if %q can %q for domain %q)\n", provider.ProviderType, ty.rType, dc.Name)
|
||||
if !providerHasAtLeastOneCapability(provider.ProviderType, ty.caps...) {
|
||||
return fmt.Errorf("Domain %s uses %s records, but DNS provider type %s does not support them", dc.Name, ty.rType, provider.ProviderType)
|
||||
return fmt.Errorf("domain %s uses %s records, but DNS provider type %s does not support them", dc.Name, ty.rType, provider.ProviderType)
|
||||
}
|
||||
|
||||
if ty.checkFunc != nil {
|
||||
|
|
|
@ -44,7 +44,7 @@ var qualifiers = map[byte]bool{
|
|||
// Parse parses a raw SPF record.
|
||||
func Parse(text string, dnsres Resolver) (*SPFRecord, error) {
|
||||
if !strings.HasPrefix(text, "v=spf1 ") {
|
||||
return nil, fmt.Errorf("Not an spf record")
|
||||
return nil, fmt.Errorf("not an SPF record")
|
||||
}
|
||||
parts := strings.Split(text, " ")
|
||||
rec := &SPFRecord{}
|
||||
|
@ -89,13 +89,13 @@ func Parse(text string, dnsres Resolver) (*SPFRecord, error) {
|
|||
}
|
||||
p.IncludeRecord, err = Parse(subRecord, dnsres)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("In included spf: %s", err)
|
||||
return nil, fmt.Errorf("in included SPF: %s", err)
|
||||
}
|
||||
}
|
||||
} else if strings.HasPrefix(part, "exists:") || strings.HasPrefix(part, "ptr:") {
|
||||
p.IsLookup = true
|
||||
} else {
|
||||
return nil, fmt.Errorf("Unsupported spf part %s", part)
|
||||
return nil, fmt.Errorf("unsupported SPF part %s", part)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ func ReverseDomainName(cidr string) (string, error) {
|
|||
bits, total := c.Mask.Size()
|
||||
var toTrim int
|
||||
if bits == 0 {
|
||||
return "", fmt.Errorf("Cannot use /0 in reverse cidr")
|
||||
return "", fmt.Errorf("cannot use /0 in reverse CIDR")
|
||||
}
|
||||
|
||||
// Handle IPv4 "Classless in-addr.arpa delegation" RFC2317:
|
||||
|
@ -48,7 +48,7 @@ func ReverseDomainName(cidr string) (string, error) {
|
|||
}
|
||||
toTrim = (total - bits) / 4
|
||||
} else {
|
||||
return "", fmt.Errorf("Address is not IPv4 or IPv6: %v", cidr)
|
||||
return "", fmt.Errorf("invalid address (not IPv4 or IPv6): %v", cidr)
|
||||
}
|
||||
|
||||
parts := strings.SplitN(base, ".", toTrim+1)
|
||||
|
|
|
@ -92,7 +92,7 @@ func IP(address net.IP, transforms []IPConversion) (net.IP, error) {
|
|||
return nil, err
|
||||
}
|
||||
if len(ips) != 1 {
|
||||
return nil, fmt.Errorf("Expect exactly one ip for IP result. Got: %s", ips)
|
||||
return nil, fmt.Errorf("exactly one IP expected. Got: %s", ips)
|
||||
}
|
||||
return ips[0], err
|
||||
}
|
||||
|
|
|
@ -136,10 +136,10 @@ func (c *adProvider) logHelper(s string) error {
|
|||
}
|
||||
_, err = fmt.Fprintln(logfile, s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Append to %#v failed: %v", c.psLog, err)
|
||||
return fmt.Errorf("append to %#v failed: %v", c.psLog, err)
|
||||
}
|
||||
if logfile.Close() != nil {
|
||||
return fmt.Errorf("Closing %#v failed: %v", c.psLog, err)
|
||||
return fmt.Errorf("closing %#v failed: %v", c.psLog, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ func (c *CloudflareAPI) GetNameservers(domain string) ([]*models.Nameserver, err
|
|||
}
|
||||
ns, ok := c.nameservers[domain]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Nameservers for %s not found in cloudflare account", domain)
|
||||
return nil, fmt.Errorf("nameservers for %s not found in cloudflare account", domain)
|
||||
}
|
||||
return models.ToNameservers(ns)
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ const (
|
|||
func checkProxyVal(v string) (string, error) {
|
||||
v = strings.ToLower(v)
|
||||
if v != "on" && v != "off" && v != "full" {
|
||||
return "", fmt.Errorf("Bad metadata value for cloudflare_proxy: '%s'. Use on/off/full", v)
|
||||
return "", fmt.Errorf("bad metadata value for cloudflare_proxy: '%s'. Use on/off/full", v)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
@ -376,7 +376,7 @@ func (c *CloudflareAPI) preprocessConfig(dc *models.DomainConfig) error {
|
|||
}
|
||||
parts := strings.Split(rec.GetTargetField(), ",")
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("Invalid data specified for cloudflare redirect record")
|
||||
return fmt.Errorf("invalid data specified for cloudflare redirect record")
|
||||
}
|
||||
code := 301
|
||||
if rec.Type == "CF_TEMP_REDIRECT" {
|
||||
|
|
|
@ -31,10 +31,10 @@ func (c *CloudflareAPI) fetchDomainList() error {
|
|||
zr := &zoneResponse{}
|
||||
url := fmt.Sprintf("%s?page=%d&per_page=50", zonesURL, page)
|
||||
if err := c.get(url, zr); err != nil {
|
||||
return fmt.Errorf("Error fetching domain list from cloudflare: %s", err)
|
||||
return fmt.Errorf("failed fetching domain list from cloudflare: %s", err)
|
||||
}
|
||||
if !zr.Success {
|
||||
return fmt.Errorf("Error fetching domain list from cloudflare: %s", stringifyErrors(zr.Errors))
|
||||
return fmt.Errorf("failed fetching domain list from cloudflare: %s", stringifyErrors(zr.Errors))
|
||||
}
|
||||
for _, zone := range zr.Result {
|
||||
c.domainIndex[zone.Name] = zone.ID
|
||||
|
@ -60,10 +60,10 @@ func (c *CloudflareAPI) getRecordsForDomain(id string, domain string) ([]*models
|
|||
reqURL := fmt.Sprintf("%s?page=%d&per_page=100", url, page)
|
||||
var data recordsResponse
|
||||
if err := c.get(reqURL, &data); err != nil {
|
||||
return nil, fmt.Errorf("Error fetching record list from cloudflare: %s", err)
|
||||
return nil, fmt.Errorf("failed fetching record list from cloudflare: %s", err)
|
||||
}
|
||||
if !data.Success {
|
||||
return nil, fmt.Errorf("Error fetching record list cloudflare: %s", stringifyErrors(data.Errors))
|
||||
return nil, fmt.Errorf("failed fetching record list cloudflare: %s", stringifyErrors(data.Errors))
|
||||
}
|
||||
for _, rec := range data.Result {
|
||||
// fmt.Printf("REC: %+v\n", rec)
|
||||
|
@ -362,7 +362,7 @@ func handleActionResponse(resp *http.Response, err error) (id string, e error) {
|
|||
result := &basicResponse{}
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
if err = decoder.Decode(result); err != nil {
|
||||
return "", fmt.Errorf("Unknown error. Status code: %d", resp.StatusCode)
|
||||
return "", fmt.Errorf("unknown error. Status code: %d", resp.StatusCode)
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return "", fmt.Errorf(stringifyErrors(result.Errors))
|
||||
|
@ -404,10 +404,10 @@ func (c *CloudflareAPI) getPageRules(id string, domain string) ([]*models.Record
|
|||
url := fmt.Sprintf(pageRulesURL, id)
|
||||
data := pageRuleResponse{}
|
||||
if err := c.get(url, &data); err != nil {
|
||||
return nil, fmt.Errorf("Error fetching page rule list from cloudflare: %s", err)
|
||||
return nil, fmt.Errorf("failed fetching page rule list from cloudflare: %s", err)
|
||||
}
|
||||
if !data.Success {
|
||||
return nil, fmt.Errorf("Error fetching page rule list cloudflare: %s", stringifyErrors(data.Errors))
|
||||
return nil, fmt.Errorf("failed fetching page rule list cloudflare: %s", stringifyErrors(data.Errors))
|
||||
}
|
||||
recs := []*models.RecordConfig{}
|
||||
for _, pr := range data.Result {
|
||||
|
|
|
@ -86,7 +86,7 @@ func (c *api) fetchAvailableNameservers() error {
|
|||
|
||||
var bodyString, err = c.get("/dns/available-name-servers.json", requestParams{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error fetching available nameservers list from ClouDNS: %s", err)
|
||||
return fmt.Errorf("failed fetching available nameservers list from ClouDNS: %s", err)
|
||||
}
|
||||
|
||||
var nr nameserverResponse
|
||||
|
@ -114,7 +114,7 @@ func (c *api) fetchDomainList() error {
|
|||
endpoint := "/dns/list-zones.json"
|
||||
var bodyString, err = c.get(endpoint, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error fetching domain list from ClouDNS: %s", err)
|
||||
return fmt.Errorf("failed fetching domain list from ClouDNS: %s", err)
|
||||
}
|
||||
json.Unmarshal(bodyString, &dr)
|
||||
|
||||
|
@ -135,7 +135,7 @@ func (c *api) createDomain(domain string) error {
|
|||
"zone-type": "master",
|
||||
}
|
||||
if _, err := c.get("/dns/register.json", params); err != nil {
|
||||
return fmt.Errorf("Error create domain ClouDNS: %s", err)
|
||||
return fmt.Errorf("failed create domain (ClouDNS): %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ func (c *api) createDomain(domain string) error {
|
|||
func (c *api) createRecord(domainID string, rec requestParams) error {
|
||||
rec["domain-name"] = domainID
|
||||
if _, err := c.get("/dns/add-record.json", rec); err != nil {
|
||||
return fmt.Errorf("Error create record ClouDNS: %s", err)
|
||||
return fmt.Errorf("failed create record (ClouDNS): %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ func (c *api) deleteRecord(domainID string, recordID string) error {
|
|||
"record-id": recordID,
|
||||
}
|
||||
if _, err := c.get("/dns/delete-record.json", params); err != nil {
|
||||
return fmt.Errorf("Error delete record ClouDNS: %s", err)
|
||||
return fmt.Errorf("failed delete record (ClouDNS): %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ func (c *api) modifyRecord(domainID string, recordID string, rec requestParams)
|
|||
rec["domain-name"] = domainID
|
||||
rec["record-id"] = recordID
|
||||
if _, err := c.get("/dns/mod-record.json", rec); err != nil {
|
||||
return fmt.Errorf("Error create update ClouDNS: %s", err)
|
||||
return fmt.Errorf("failed update (ClouDNS): %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ func (c *api) getRecords(id string) ([]domainRecord, error) {
|
|||
|
||||
var bodyString, err = c.get("/dns/records.json", params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error fetching record list from ClouDNS: %s", err)
|
||||
return nil, fmt.Errorf("failed fetching record list from ClouDNS: %s", err)
|
||||
}
|
||||
|
||||
var dr recordResponse
|
||||
|
|
|
@ -24,13 +24,13 @@ func LoadProviderConfigs(fname string) (map[string]map[string]string, error) {
|
|||
fmt.Printf("INFO: Config file %q does not exist. Skipping.\n", fname)
|
||||
return results, nil
|
||||
}
|
||||
return nil, fmt.Errorf("While reading provider credentials file %v: %v", fname, err)
|
||||
return nil, fmt.Errorf("failed reading provider credentials file %v: %v", fname, err)
|
||||
}
|
||||
s := string(dat)
|
||||
r := JsonConfigReader.New(strings.NewReader(s))
|
||||
err = json.NewDecoder(r).Decode(&results)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("While parsing provider credentials file %v: %v", fname, err)
|
||||
return nil, fmt.Errorf("failed parsing provider credentials file %v: %v", fname, err)
|
||||
}
|
||||
if err = replaceEnvVars(results); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -65,7 +65,7 @@ func (c *api) fetchDomainList() error {
|
|||
endpoint := "/domains/"
|
||||
var bodyString, err = c.get(endpoint, "GET")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error fetching domain list from deSEC: %s", err)
|
||||
return fmt.Errorf("failed fetching domain list (deSEC): %s", err)
|
||||
}
|
||||
err = json.Unmarshal(bodyString, &dr)
|
||||
if err != nil {
|
||||
|
@ -85,7 +85,7 @@ func (c *api) getRecords(domain string) ([]resourceRecord, error) {
|
|||
var rrsNew []resourceRecord
|
||||
var bodyString, err = c.get(fmt.Sprintf(endpoint, domain), "GET")
|
||||
if err != nil {
|
||||
return rrsNew, fmt.Errorf("Error fetching records from deSEC for domain %s: %s", domain, err)
|
||||
return rrsNew, fmt.Errorf("failed fetching records for domain %s (deSEC): %s", domain, err)
|
||||
}
|
||||
err = json.Unmarshal(bodyString, &rrs)
|
||||
if err != nil {
|
||||
|
@ -112,7 +112,7 @@ func (c *api) createDomain(domain string) error {
|
|||
var resp []byte
|
||||
var err error
|
||||
if resp, err = c.post(endpoint, "POST", byt); err != nil {
|
||||
return fmt.Errorf("Error create domain deSEC: %v", err)
|
||||
return fmt.Errorf("failed domain create (deSEC): %v", err)
|
||||
}
|
||||
dm := domainObject{}
|
||||
err = json.Unmarshal(resp, &dm)
|
||||
|
@ -129,7 +129,7 @@ func (c *api) upsertRR(rr []resourceRecord, domain string) error {
|
|||
endpoint := fmt.Sprintf("/domains/%s/rrsets/", domain)
|
||||
byt, _ := json.Marshal(rr)
|
||||
if _, err := c.post(endpoint, "PUT", byt); err != nil {
|
||||
return fmt.Errorf("Error create rrset deSEC: %v", err)
|
||||
return fmt.Errorf("failed create rrset (deSEC): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ func (c *api) upsertRR(rr []resourceRecord, domain string) error {
|
|||
func (c *api) deleteRR(domain, shortname, t string) error {
|
||||
endpoint := fmt.Sprintf("/domains/%s/rrsets/%s/%s/", domain, shortname, t)
|
||||
if _, err := c.get(endpoint, "DELETE"); err != nil {
|
||||
return fmt.Errorf("Error delete rrset deSEC: %v", err)
|
||||
return fmt.Errorf("failed delete rrset (deSEC): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ func (n *HXClient) getNameserversRaw(domain string) ([]string, error) {
|
|||
}
|
||||
nsColumn := r.GetColumn("NAMESERVER")
|
||||
if nsColumn == nil {
|
||||
return nil, fmt.Errorf("Error getting NAMESERVER column for domain: %s", domain)
|
||||
return nil, fmt.Errorf("error getting NAMESERVER column for domain: %s", domain)
|
||||
}
|
||||
ns := nsColumn.GetData()
|
||||
sort.Strings(ns)
|
||||
|
|
|
@ -57,7 +57,7 @@ func (n *HXClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Corr
|
|||
|
||||
for _, rec := range dc.Records {
|
||||
if rec.Type == "ALIAS" {
|
||||
return nil, fmt.Errorf("We support realtime ALIAS RR over our X-DNS service, please get in touch with us")
|
||||
return nil, fmt.Errorf("we support realtime ALIAS RR over our X-DNS service, please get in touch with us")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ func (n *HXClient) getRecords(domain string) ([]*HXRecord, error) {
|
|||
}
|
||||
rrColumn := r.GetColumn("RR")
|
||||
if rrColumn == nil {
|
||||
return nil, fmt.Errorf("Error getting RR column for domain: %s", domain)
|
||||
return nil, fmt.Errorf("failed getting RR column for domain: %s", domain)
|
||||
}
|
||||
rrs := rrColumn.GetData()
|
||||
for _, rr := range rrs {
|
||||
|
|
|
@ -31,7 +31,7 @@ type domainRecord struct {
|
|||
func (c *api) getNameservers(domain string) ([]string, error) {
|
||||
var bodyString, err = c.get("/Domain/Info", requestParams{"Domain": domain})
|
||||
if err != nil {
|
||||
return []string{}, fmt.Errorf("Error fetching nameservers list from Internet.bs: %s", err)
|
||||
return []string{}, fmt.Errorf("failed fetching nameservers list (Internet.bs): %s", err)
|
||||
}
|
||||
var dr domainRecord
|
||||
json.Unmarshal(bodyString, &dr)
|
||||
|
@ -47,7 +47,7 @@ func (c *api) updateNameservers(ns []string, domain string) error {
|
|||
rec["Domain"] = domain
|
||||
rec["Ns_list"] = strings.Join(ns, ",")
|
||||
if _, err := c.get("/Domain/Update", rec); err != nil {
|
||||
return fmt.Errorf("Internet.ns: Error update NS : %s", err)
|
||||
return fmt.Errorf("failed NS update (Internet.bs): %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ func (c *api) get(endpoint string, params requestParams) ([]byte, error) {
|
|||
return []byte{}, err
|
||||
}
|
||||
if errResp.Status == "FAILURE" {
|
||||
return bodyString, fmt.Errorf("Internet.bs API error: %s code: %d transactid: %s URL:%s%s ",
|
||||
return bodyString, fmt.Errorf("failed API (Internet.bs): %s code: %d transactid: %s URL:%s%s ",
|
||||
errResp.Message, errResp.Code, errResp.TransactID,
|
||||
req.Host, req.URL.RequestURI())
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func (c *LinodeAPI) fetchDomainList() error {
|
|||
dr := &domainResponse{}
|
||||
endpoint := fmt.Sprintf("%s?page=%d", domainsPath, page)
|
||||
if err := c.get(endpoint, dr); err != nil {
|
||||
return fmt.Errorf("Error fetching domain list from Linode: %s", err)
|
||||
return fmt.Errorf("failed fetching domain list (Linode): %s", err)
|
||||
}
|
||||
for _, domain := range dr.Data {
|
||||
c.domainIndex[domain.Domain] = domain.ID
|
||||
|
@ -42,7 +42,7 @@ func (c *LinodeAPI) getRecords(id int) ([]domainRecord, error) {
|
|||
dr := &recordResponse{}
|
||||
endpoint := fmt.Sprintf("%s/%d/records?page=%d", domainsPath, id, page)
|
||||
if err := c.get(endpoint, dr); err != nil {
|
||||
return nil, fmt.Errorf("Error fetching record list from Linode: %s", err)
|
||||
return nil, fmt.Errorf("failed fetching record list (Linode): %s", err)
|
||||
}
|
||||
|
||||
records = append(records, dr.Data...)
|
||||
|
|
|
@ -61,7 +61,7 @@ var defaultNameServerNames = []string{
|
|||
// NewLinode creates the provider.
|
||||
func NewLinode(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
if m["token"] == "" {
|
||||
return nil, fmt.Errorf("Missing Linode token")
|
||||
return nil, fmt.Errorf("missing Linode token")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
@ -72,7 +72,7 @@ func NewLinode(m map[string]string, metadata json.RawMessage) (providers.DNSServ
|
|||
|
||||
baseURL, err := url.Parse(defaultBaseURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Linode base URL not valid")
|
||||
return nil, fmt.Errorf("invalid base URL for Linode")
|
||||
}
|
||||
|
||||
api := &LinodeAPI{client: client, baseURL: baseURL}
|
||||
|
|
|
@ -85,7 +85,7 @@ func (api *api) getRecords(domain string) ([]record, error) {
|
|||
}
|
||||
rawJSON, err := api.get("infoDnsRecords", data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error while trying to login to netcup: %s", err)
|
||||
return nil, fmt.Errorf("failed while trying to login (netcup): %s", err)
|
||||
}
|
||||
|
||||
resp := &records{}
|
||||
|
@ -101,7 +101,7 @@ func (api *api) login(apikey, password, customernumber string) error {
|
|||
}
|
||||
rawJSON, err := api.get("login", data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error while trying to login to netcup: %s", err)
|
||||
return fmt.Errorf("failed while trying to login to (netcup): %s", err)
|
||||
}
|
||||
|
||||
resp := &responseLogin{}
|
||||
|
@ -120,7 +120,7 @@ func (api *api) logout() error {
|
|||
}
|
||||
_, err := api.get("logout", data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error while trying to logout from netcup: %s", err)
|
||||
return fmt.Errorf("failed to logout from netcup: %s", err)
|
||||
}
|
||||
api.credentials.apikey, api.credentials.sessionID, api.credentials.customernumber = "", "", ""
|
||||
return nil
|
||||
|
|
|
@ -99,7 +99,7 @@ func (c *OpenSRSApi) getNameservers(domainName string) ([]string, error) {
|
|||
}
|
||||
return dom.Attributes.NameserverList.ToString(), nil
|
||||
}
|
||||
return nil, errors.New("Domain is locked")
|
||||
return nil, errors.New("domain is locked")
|
||||
}
|
||||
|
||||
// Returns a function that can be invoked to change the delegation of the domain to the given name server names.
|
||||
|
|
|
@ -149,7 +149,7 @@ func (c *ovhProvider) updateRecordFunc(old *Record, rc *models.RecordConfig, fqd
|
|||
|
||||
err := c.client.CallAPI("PUT", fmt.Sprintf("/domain/zone/%s/record/%d", fqdn, old.ID), &record, &Void{}, true)
|
||||
if err != nil && rc.Type == "DKIM" && strings.Contains(err.Error(), "alter read-only properties: fieldType") {
|
||||
err = fmt.Errorf("This usually occurs when DKIM value is longer than the TXT record limit what OVH allows. Delete the TXT record to get past this limitation. [Original error: %s]", err.Error())
|
||||
err = fmt.Errorf("this usually occurs when DKIM value is longer than the TXT record limit what OVH allows. Delete the TXT record to get past this limitation. [Original error: %s]", err.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
@ -5,15 +5,16 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/diff"
|
||||
"github.com/StackExchange/dnscontrol/v3/providers"
|
||||
"github.com/miekg/dns/dnsutil"
|
||||
"github.com/mittwald/go-powerdns"
|
||||
pdns "github.com/mittwald/go-powerdns"
|
||||
"github.com/mittwald/go-powerdns/apis/zones"
|
||||
"github.com/mittwald/go-powerdns/pdnshttp"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var features = providers.DocumentationNotes{
|
||||
|
@ -246,7 +247,7 @@ func toRecordConfig(domain string, r zones.Record, ttl int, name string, rtype s
|
|||
case "TXT":
|
||||
// Remove quotes if it is a TXT record.
|
||||
if !strings.HasPrefix(content, `"`) || !strings.HasSuffix(content, `"`) {
|
||||
return nil, errors.New("Unexpected lack of quotes in TXT record from PowerDNS")
|
||||
return nil, errors.New("unexpected lack of quotes in TXT record from PowerDNS")
|
||||
}
|
||||
return rc, rc.SetTargetTXT(content[1 : len(content)-1])
|
||||
default:
|
||||
|
|
|
@ -132,7 +132,7 @@ func (r *route53Provider) getZones() error {
|
|||
return err
|
||||
})
|
||||
if err != nil && strings.Contains(err.Error(), "is not authorized") {
|
||||
return errors.New("Check your credentials, your not authorized to perform actions on Route 53 AWS Service")
|
||||
return errors.New("check your credentials, you're not authorized to perform actions on Route 53 AWS Service")
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ func (r *route53Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
|
|||
}
|
||||
}
|
||||
if rrset == nil {
|
||||
return nil, fmt.Errorf("No record set found to delete. Name: '%s'. Type: '%s'", k.NameFQDN, k.Type)
|
||||
return nil, fmt.Errorf("no record set found to delete. Name: '%s'. Type: '%s'", k.NameFQDN, k.Type)
|
||||
}
|
||||
} else {
|
||||
changes = append(changes, chg)
|
||||
|
|
|
@ -118,9 +118,9 @@ func (s *SoftLayer) getDomain(name *string) (*datatypes.Dns_Domain, error) {
|
|||
}
|
||||
|
||||
if len(domains) == 0 {
|
||||
return nil, fmt.Errorf("Didn't find a domain matching %s", *name)
|
||||
return nil, fmt.Errorf("didn't find a domain matching %s", *name)
|
||||
} else if len(domains) > 1 {
|
||||
return nil, fmt.Errorf("Found %d domains matching %s", len(domains), *name)
|
||||
return nil, fmt.Errorf("found %d domains matching %s", len(domains), *name)
|
||||
}
|
||||
|
||||
return &domains[0], nil
|
||||
|
|
|
@ -57,7 +57,7 @@ var defaultNS = []string{
|
|||
func NewProvider(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
token := m["token"]
|
||||
if token == "" {
|
||||
return nil, fmt.Errorf("Vultr API token is required")
|
||||
return nil, fmt.Errorf("missing Vultr API token")
|
||||
}
|
||||
|
||||
client := govultr.NewClient(nil, token)
|
||||
|
@ -200,7 +200,7 @@ func toRecordConfig(domain string, r *govultr.DNSRecord) (*models.RecordConfig,
|
|||
case "TXT":
|
||||
// Remove quotes if it is a TXT record.
|
||||
if !strings.HasPrefix(data, `"`) || !strings.HasSuffix(data, `"`) {
|
||||
return nil, errors.New("Unexpected lack of quotes in TXT record from Vultr")
|
||||
return nil, errors.New("unexpected lack of quotes in TXT record from Vultr")
|
||||
}
|
||||
return rc, rc.SetTargetTXT(data[1 : len(data)-1])
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue