Update lego.
This commit is contained in:
parent
63c3ed3931
commit
0034bef6b9
27 changed files with 1663 additions and 14 deletions
36
Gopkg.lock
generated
36
Gopkg.lock
generated
|
@ -606,7 +606,7 @@
|
||||||
revision = "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
revision = "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:68a7713d996a30a8394715220e779bbcbc880a18b1e0ab0e12fd1fbbf9c711e6"
|
digest = "1:d82b2dc81c551e7c15f31523a2cc8ee9121b39cfbf63174d98a0bc8edf2d3c5e"
|
||||||
name = "github.com/go-acme/lego"
|
name = "github.com/go-acme/lego"
|
||||||
packages = [
|
packages = [
|
||||||
"acme",
|
"acme",
|
||||||
|
@ -630,6 +630,7 @@
|
||||||
"providers/dns/alidns",
|
"providers/dns/alidns",
|
||||||
"providers/dns/auroradns",
|
"providers/dns/auroradns",
|
||||||
"providers/dns/azure",
|
"providers/dns/azure",
|
||||||
|
"providers/dns/bindman",
|
||||||
"providers/dns/bluecat",
|
"providers/dns/bluecat",
|
||||||
"providers/dns/cloudflare",
|
"providers/dns/cloudflare",
|
||||||
"providers/dns/cloudns",
|
"providers/dns/cloudns",
|
||||||
|
@ -648,6 +649,7 @@
|
||||||
"providers/dns/dreamhost",
|
"providers/dns/dreamhost",
|
||||||
"providers/dns/duckdns",
|
"providers/dns/duckdns",
|
||||||
"providers/dns/dyn",
|
"providers/dns/dyn",
|
||||||
|
"providers/dns/easydns",
|
||||||
"providers/dns/exec",
|
"providers/dns/exec",
|
||||||
"providers/dns/exoscale",
|
"providers/dns/exoscale",
|
||||||
"providers/dns/fastdns",
|
"providers/dns/fastdns",
|
||||||
|
@ -660,6 +662,7 @@
|
||||||
"providers/dns/httpreq",
|
"providers/dns/httpreq",
|
||||||
"providers/dns/iij",
|
"providers/dns/iij",
|
||||||
"providers/dns/inwx",
|
"providers/dns/inwx",
|
||||||
|
"providers/dns/joker",
|
||||||
"providers/dns/lightsail",
|
"providers/dns/lightsail",
|
||||||
"providers/dns/linode",
|
"providers/dns/linode",
|
||||||
"providers/dns/linodev4",
|
"providers/dns/linodev4",
|
||||||
|
@ -691,8 +694,8 @@
|
||||||
"registration",
|
"registration",
|
||||||
]
|
]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "3d13faf68920543a393ad6cdfdea429627af2d34"
|
revision = "01903cdfb9869df45cf5274c53226823a2532f2d"
|
||||||
version = "v2.5.0"
|
version = "v2.6.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "fork-containous"
|
branch = "fork-containous"
|
||||||
|
@ -703,6 +706,14 @@
|
||||||
revision = "ca0bf163426aa183d03fd4949101785c0347f273"
|
revision = "ca0bf163426aa183d03fd4949101785c0347f273"
|
||||||
source = "github.com/containous/check"
|
source = "github.com/containous/check"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:ea1d5bfdb4ec5c2ee48c97865e6de1a28fa8c4849a3f56b27d521aa619038e06"
|
||||||
|
name = "github.com/go-errors/errors"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "a6af135bd4e28680facf08a3d206b454abc877a4"
|
||||||
|
version = "v1.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:5e92676b56ce4c69edf9ee1f6343c56f637e30af11b9d8b5edd1b6530f3fbc3d"
|
digest = "1:5e92676b56ce4c69edf9ee1f6343c56f637e30af11b9d8b5edd1b6530f3fbc3d"
|
||||||
name = "github.com/go-ini/ini"
|
name = "github.com/go-ini/ini"
|
||||||
|
@ -1022,6 +1033,25 @@
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
|
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:1082aeb059ff66b4fb6da53f9e7591726c6a81901f05ce48a470091784b23914"
|
||||||
|
name = "github.com/labbsr0x/bindman-dns-webhook"
|
||||||
|
packages = [
|
||||||
|
"src/client",
|
||||||
|
"src/types",
|
||||||
|
]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "234ca2a50eebc2095f42a884709a6e9013366d86"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:ad2a63b2d6dfe7d66bf14c01f1171a3951abef6e0fb136170359c3f7c4f51615"
|
||||||
|
name = "github.com/labbsr0x/goh"
|
||||||
|
packages = ["gohclient"]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "60aa50bcbca768de1b8d37d7185daab4cf023ed2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:5a96e1f04259484b3dd183ca95d1e7bff768b1bab36c530e308a8d56243b50c7"
|
digest = "1:5a96e1f04259484b3dd183ca95d1e7bff768b1bab36c530e308a8d56243b50c7"
|
||||||
|
|
|
@ -194,7 +194,7 @@ required = [
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/go-acme/lego"
|
name = "github.com/go-acme/lego"
|
||||||
version = "2.5.0"
|
version = "2.6.0"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "google.golang.org/grpc"
|
name = "google.golang.org/grpc"
|
||||||
|
|
2
vendor/github.com/go-acme/lego/acme/api/internal/sender/useragent.go
generated
vendored
2
vendor/github.com/go-acme/lego/acme/api/internal/sender/useragent.go
generated
vendored
|
@ -5,7 +5,7 @@ package sender
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ourUserAgent is the User-Agent of this underlying library package.
|
// ourUserAgent is the User-Agent of this underlying library package.
|
||||||
ourUserAgent = "xenolf-acme/2.5.0"
|
ourUserAgent = "xenolf-acme/2.6.0"
|
||||||
|
|
||||||
// ourUserAgentComment is part of the UA comment linked to the version status of this underlying library package.
|
// ourUserAgentComment is part of the UA comment linked to the version status of this underlying library package.
|
||||||
// values: detach|release
|
// values: detach|release
|
||||||
|
|
27
vendor/github.com/go-acme/lego/certificate/certificates.go
generated
vendored
27
vendor/github.com/go-acme/lego/certificate/certificates.go
generated
vendored
|
@ -464,6 +464,33 @@ func (c *Certifier) GetOCSP(bundle []byte) ([]byte, *ocsp.Response, error) {
|
||||||
return ocspResBytes, ocspRes, nil
|
return ocspResBytes, ocspRes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get attempts to fetch the certificate at the supplied URL.
|
||||||
|
// The URL is the same as what would normally be supplied at the Resource's CertURL.
|
||||||
|
//
|
||||||
|
// The returned Resource will not have the PrivateKey and CSR fields populated as these will not be available.
|
||||||
|
//
|
||||||
|
// If bundle is true, the Certificate field in the returned Resource includes the issuer certificate.
|
||||||
|
func (c *Certifier) Get(url string, bundle bool) (*Resource, error) {
|
||||||
|
cert, issuer, err := c.core.Certificates.Get(url, bundle)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the returned cert bundle so that we can grab the domain from the common name.
|
||||||
|
x509Certs, err := certcrypto.ParsePEMBundle(cert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Resource{
|
||||||
|
Domain: x509Certs[0].Subject.CommonName,
|
||||||
|
Certificate: cert,
|
||||||
|
IssuerCertificate: issuer,
|
||||||
|
CertURL: url,
|
||||||
|
CertStableURL: url,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func checkOrderStatus(order acme.Order) (bool, error) {
|
func checkOrderStatus(order acme.Order) (bool, error) {
|
||||||
switch order.Status {
|
switch order.Status {
|
||||||
case acme.StatusValid:
|
case acme.StatusValid:
|
||||||
|
|
7
vendor/github.com/go-acme/lego/challenge/dns01/dns_challenge_manual.go
generated
vendored
7
vendor/github.com/go-acme/lego/challenge/dns01/dns_challenge_manual.go
generated
vendored
|
@ -4,6 +4,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -50,3 +51,9 @@ func (*DNSProviderManual) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sequential All DNS challenges for this provider will be resolved sequentially.
|
||||||
|
// Returns the interval between each iteration.
|
||||||
|
func (d *DNSProviderManual) Sequential() time.Duration {
|
||||||
|
return DefaultPropagationTimeout
|
||||||
|
}
|
||||||
|
|
2
vendor/github.com/go-acme/lego/platform/config/env/env.go
generated
vendored
2
vendor/github.com/go-acme/lego/platform/config/env/env.go
generated
vendored
|
@ -159,5 +159,5 @@ func GetOrFile(envVar string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(fileContents)
|
return strings.TrimSuffix(string(fileContents), "\n")
|
||||||
}
|
}
|
||||||
|
|
99
vendor/github.com/go-acme/lego/providers/dns/bindman/bindman.go
generated
vendored
Normal file
99
vendor/github.com/go-acme/lego/providers/dns/bindman/bindman.go
generated
vendored
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
// Package bindman implements a DNS provider for solving the DNS-01 challenge.
|
||||||
|
package bindman
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/challenge/dns01"
|
||||||
|
"github.com/go-acme/lego/platform/config/env"
|
||||||
|
"github.com/labbsr0x/bindman-dns-webhook/src/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config is used to configure the creation of the DNSProvider
|
||||||
|
type Config struct {
|
||||||
|
PropagationTimeout time.Duration
|
||||||
|
PollingInterval time.Duration
|
||||||
|
BaseURL string
|
||||||
|
HTTPClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||||
|
func NewDefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
PropagationTimeout: env.GetOrDefaultSecond("BINDMAN_PROPAGATION_TIMEOUT", dns01.DefaultPropagationTimeout),
|
||||||
|
PollingInterval: env.GetOrDefaultSecond("BINDMAN_POLLING_INTERVAL", dns01.DefaultPollingInterval),
|
||||||
|
HTTPClient: &http.Client{
|
||||||
|
Timeout: env.GetOrDefaultSecond("BINDMAN_HTTP_TIMEOUT", time.Minute),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSProvider is an implementation of the acme.ChallengeProvider interface that uses
|
||||||
|
// Bindman's Address Manager REST API to manage TXT records for a domain.
|
||||||
|
type DNSProvider struct {
|
||||||
|
config *Config
|
||||||
|
client *client.DNSWebhookClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProvider returns a DNSProvider instance configured for Bindman.
|
||||||
|
// BINDMAN_MANAGER_ADDRESS should have the scheme, hostname, and port (if required) of the authoritative Bindman Manager server.
|
||||||
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
|
values, err := env.Get("BINDMAN_MANAGER_ADDRESS")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("bindman: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.BaseURL = values["BINDMAN_MANAGER_ADDRESS"]
|
||||||
|
|
||||||
|
return NewDNSProviderConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProviderConfig return a DNSProvider instance configured for Bindman.
|
||||||
|
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("bindman: the configuration of the DNS provider is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.BaseURL == "" {
|
||||||
|
return nil, fmt.Errorf("bindman: bindman manager address missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
bClient, err := client.New(config.BaseURL, config.HTTPClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("bindman: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DNSProvider{config: config, client: bClient}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Present creates a TXT record using the specified parameters.
|
||||||
|
// This will *not* create a subzone to contain the TXT record,
|
||||||
|
// so make sure the FQDN specified is within an extant zone.
|
||||||
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
|
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
|
if err := d.client.AddRecord(fqdn, "TXT", value); err != nil {
|
||||||
|
return fmt.Errorf("bindman: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanUp removes the TXT record matching the specified parameters.
|
||||||
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
fqdn, _ := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
|
if err := d.client.RemoveRecord(fqdn, "TXT"); err != nil {
|
||||||
|
return fmt.Errorf("bindman: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||||
|
// Adjusting here to cope with spikes in propagation times.
|
||||||
|
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||||
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
|
}
|
6
vendor/github.com/go-acme/lego/providers/dns/digitalocean/client.go
generated
vendored
6
vendor/github.com/go-acme/lego/providers/dns/digitalocean/client.go
generated
vendored
|
@ -57,10 +57,10 @@ func (d *DNSProvider) removeTxtRecord(domain string, recordID int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) addTxtRecord(domain, fqdn, value string) (*txtRecordResponse, error) {
|
func (d *DNSProvider) addTxtRecord(fqdn, value string) (*txtRecordResponse, error) {
|
||||||
authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
|
authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(fqdn))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not determine zone for domain: '%s'. %s", domain, err)
|
return nil, fmt.Errorf("could not determine zone for domain: '%s'. %s", fqdn, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
reqData := record{Type: "TXT", Name: fqdn, Data: value, TTL: d.config.TTL}
|
reqData := record{Type: "TXT", Name: fqdn, Data: value, TTL: d.config.TTL}
|
||||||
|
|
9
vendor/github.com/go-acme/lego/providers/dns/digitalocean/digitalocean.go
generated
vendored
9
vendor/github.com/go-acme/lego/providers/dns/digitalocean/digitalocean.go
generated
vendored
|
@ -88,7 +88,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
respData, err := d.addTxtRecord(domain, fqdn, value)
|
respData, err := d.addTxtRecord(fqdn, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("digitalocean: %v", err)
|
return fmt.Errorf("digitalocean: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,11 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
fqdn, _ := dns01.GetRecord(domain, keyAuth)
|
fqdn, _ := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
|
authZone, err := dns01.FindZoneByFqdn(fqdn)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("digitalocean: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// get the record's unique ID from when we created it
|
// get the record's unique ID from when we created it
|
||||||
d.recordIDsMu.Lock()
|
d.recordIDsMu.Lock()
|
||||||
recordID, ok := d.recordIDs[fqdn]
|
recordID, ok := d.recordIDs[fqdn]
|
||||||
|
@ -112,7 +117,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
return fmt.Errorf("digitalocean: unknown record ID for '%s'", fqdn)
|
return fmt.Errorf("digitalocean: unknown record ID for '%s'", fqdn)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := d.removeTxtRecord(domain, recordID)
|
err = d.removeTxtRecord(authZone, recordID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("digitalocean: %v", err)
|
return fmt.Errorf("digitalocean: %v", err)
|
||||||
}
|
}
|
||||||
|
|
9
vendor/github.com/go-acme/lego/providers/dns/dns_providers.go
generated
vendored
9
vendor/github.com/go-acme/lego/providers/dns/dns_providers.go
generated
vendored
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/go-acme/lego/providers/dns/alidns"
|
"github.com/go-acme/lego/providers/dns/alidns"
|
||||||
"github.com/go-acme/lego/providers/dns/auroradns"
|
"github.com/go-acme/lego/providers/dns/auroradns"
|
||||||
"github.com/go-acme/lego/providers/dns/azure"
|
"github.com/go-acme/lego/providers/dns/azure"
|
||||||
|
"github.com/go-acme/lego/providers/dns/bindman"
|
||||||
"github.com/go-acme/lego/providers/dns/bluecat"
|
"github.com/go-acme/lego/providers/dns/bluecat"
|
||||||
"github.com/go-acme/lego/providers/dns/cloudflare"
|
"github.com/go-acme/lego/providers/dns/cloudflare"
|
||||||
"github.com/go-acme/lego/providers/dns/cloudns"
|
"github.com/go-acme/lego/providers/dns/cloudns"
|
||||||
|
@ -23,6 +24,7 @@ import (
|
||||||
"github.com/go-acme/lego/providers/dns/dreamhost"
|
"github.com/go-acme/lego/providers/dns/dreamhost"
|
||||||
"github.com/go-acme/lego/providers/dns/duckdns"
|
"github.com/go-acme/lego/providers/dns/duckdns"
|
||||||
"github.com/go-acme/lego/providers/dns/dyn"
|
"github.com/go-acme/lego/providers/dns/dyn"
|
||||||
|
"github.com/go-acme/lego/providers/dns/easydns"
|
||||||
"github.com/go-acme/lego/providers/dns/exec"
|
"github.com/go-acme/lego/providers/dns/exec"
|
||||||
"github.com/go-acme/lego/providers/dns/exoscale"
|
"github.com/go-acme/lego/providers/dns/exoscale"
|
||||||
"github.com/go-acme/lego/providers/dns/fastdns"
|
"github.com/go-acme/lego/providers/dns/fastdns"
|
||||||
|
@ -35,6 +37,7 @@ import (
|
||||||
"github.com/go-acme/lego/providers/dns/httpreq"
|
"github.com/go-acme/lego/providers/dns/httpreq"
|
||||||
"github.com/go-acme/lego/providers/dns/iij"
|
"github.com/go-acme/lego/providers/dns/iij"
|
||||||
"github.com/go-acme/lego/providers/dns/inwx"
|
"github.com/go-acme/lego/providers/dns/inwx"
|
||||||
|
"github.com/go-acme/lego/providers/dns/joker"
|
||||||
"github.com/go-acme/lego/providers/dns/lightsail"
|
"github.com/go-acme/lego/providers/dns/lightsail"
|
||||||
"github.com/go-acme/lego/providers/dns/linode"
|
"github.com/go-acme/lego/providers/dns/linode"
|
||||||
"github.com/go-acme/lego/providers/dns/linodev4"
|
"github.com/go-acme/lego/providers/dns/linodev4"
|
||||||
|
@ -72,6 +75,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
|
||||||
return azure.NewDNSProvider()
|
return azure.NewDNSProvider()
|
||||||
case "auroradns":
|
case "auroradns":
|
||||||
return auroradns.NewDNSProvider()
|
return auroradns.NewDNSProvider()
|
||||||
|
case "bindman":
|
||||||
|
return bindman.NewDNSProvider()
|
||||||
case "bluecat":
|
case "bluecat":
|
||||||
return bluecat.NewDNSProvider()
|
return bluecat.NewDNSProvider()
|
||||||
case "cloudflare":
|
case "cloudflare":
|
||||||
|
@ -102,6 +107,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
|
||||||
return dyn.NewDNSProvider()
|
return dyn.NewDNSProvider()
|
||||||
case "fastdns":
|
case "fastdns":
|
||||||
return fastdns.NewDNSProvider()
|
return fastdns.NewDNSProvider()
|
||||||
|
case "easydns":
|
||||||
|
return easydns.NewDNSProvider()
|
||||||
case "exec":
|
case "exec":
|
||||||
return exec.NewDNSProvider()
|
return exec.NewDNSProvider()
|
||||||
case "exoscale":
|
case "exoscale":
|
||||||
|
@ -124,6 +131,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
|
||||||
return iij.NewDNSProvider()
|
return iij.NewDNSProvider()
|
||||||
case "inwx":
|
case "inwx":
|
||||||
return inwx.NewDNSProvider()
|
return inwx.NewDNSProvider()
|
||||||
|
case "joker":
|
||||||
|
return joker.NewDNSProvider()
|
||||||
case "lightsail":
|
case "lightsail":
|
||||||
return lightsail.NewDNSProvider()
|
return lightsail.NewDNSProvider()
|
||||||
case "linode":
|
case "linode":
|
||||||
|
|
97
vendor/github.com/go-acme/lego/providers/dns/easydns/client.go
generated
vendored
Normal file
97
vendor/github.com/go-acme/lego/providers/dns/easydns/client.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package easydns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultEndpoint = "https://rest.easydns.net"
|
||||||
|
|
||||||
|
type zoneRecord struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
TTL string `json:"ttl"`
|
||||||
|
Prio string `json:"prio"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Rdata string `json:"rdata"`
|
||||||
|
LastMod string `json:"last_mod,omitempty"`
|
||||||
|
Revoked int `json:"revoked,omitempty"`
|
||||||
|
NewHost string `json:"new_host,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type addRecordResponse struct {
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Tm int `json:"tm"`
|
||||||
|
Data zoneRecord `json:"data"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) addRecord(domain string, record interface{}) (string, error) {
|
||||||
|
pathAdd := path.Join("/zones/records/add", domain, "TXT")
|
||||||
|
|
||||||
|
response := &addRecordResponse{}
|
||||||
|
err := d.doRequest(http.MethodPut, pathAdd, record, response)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordID := response.Data.ID
|
||||||
|
|
||||||
|
return recordID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) deleteRecord(domain, recordID string) error {
|
||||||
|
pathDelete := path.Join("/zones/records", domain, recordID)
|
||||||
|
|
||||||
|
return d.doRequest(http.MethodDelete, pathDelete, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) doRequest(method, path string, requestMsg, responseMsg interface{}) error {
|
||||||
|
reqBody := &bytes.Buffer{}
|
||||||
|
if requestMsg != nil {
|
||||||
|
err := json.NewEncoder(reqBody).Encode(requestMsg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint, err := d.config.Endpoint.Parse(path + "?format=json")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
request, err := http.NewRequest(method, endpoint.String(), reqBody)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Header.Set("Content-Type", "application/json")
|
||||||
|
request.Header.Set("Accept", "application/json")
|
||||||
|
request.SetBasicAuth(d.config.Token, d.config.Key)
|
||||||
|
|
||||||
|
response, err := d.config.HTTPClient.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
if response.StatusCode >= http.StatusBadRequest {
|
||||||
|
body, err := ioutil.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%d: failed to read response body: %v", response.StatusCode, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("%d: request failed: %v", response.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
if responseMsg != nil {
|
||||||
|
return json.NewDecoder(response.Body).Decode(responseMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
165
vendor/github.com/go-acme/lego/providers/dns/easydns/easydns.go
generated
vendored
Normal file
165
vendor/github.com/go-acme/lego/providers/dns/easydns/easydns.go
generated
vendored
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
// Package easydns implements a DNS provider for solving the DNS-01 challenge using EasyDNS API.
|
||||||
|
package easydns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/challenge/dns01"
|
||||||
|
"github.com/go-acme/lego/platform/config/env"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config is used to configure the creation of the DNSProvider
|
||||||
|
type Config struct {
|
||||||
|
Endpoint *url.URL
|
||||||
|
Token string
|
||||||
|
Key string
|
||||||
|
TTL int
|
||||||
|
HTTPClient *http.Client
|
||||||
|
PropagationTimeout time.Duration
|
||||||
|
PollingInterval time.Duration
|
||||||
|
SequenceInterval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||||
|
func NewDefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
PropagationTimeout: env.GetOrDefaultSecond("EASYDNS_PROPAGATION_TIMEOUT", dns01.DefaultPropagationTimeout),
|
||||||
|
SequenceInterval: env.GetOrDefaultSecond("EASYDNS_SEQUENCE_INTERVAL", dns01.DefaultPropagationTimeout),
|
||||||
|
PollingInterval: env.GetOrDefaultSecond("EASYDNS_POLLING_INTERVAL", dns01.DefaultPollingInterval),
|
||||||
|
TTL: env.GetOrDefaultInt("EASYDNS_TTL", dns01.DefaultTTL),
|
||||||
|
HTTPClient: &http.Client{
|
||||||
|
Timeout: env.GetOrDefaultSecond("EASYDNS_HTTP_TIMEOUT", 30*time.Second),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSProvider describes a provider for acme-proxy
|
||||||
|
type DNSProvider struct {
|
||||||
|
config *Config
|
||||||
|
recordIDs map[string]string
|
||||||
|
recordIDsMu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProvider returns a DNSProvider instance.
|
||||||
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
|
||||||
|
endpoint, err := url.Parse(env.GetOrDefaultString("EASYDNS_ENDPOINT", defaultEndpoint))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("easydns: %v", err)
|
||||||
|
}
|
||||||
|
config.Endpoint = endpoint
|
||||||
|
|
||||||
|
values, err := env.Get("EASYDNS_TOKEN", "EASYDNS_KEY")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("easydns: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Token = values["EASYDNS_TOKEN"]
|
||||||
|
config.Key = values["EASYDNS_KEY"]
|
||||||
|
|
||||||
|
return NewDNSProviderConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProviderConfig return a DNSProvider .
|
||||||
|
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("easydns: the configuration of the DNS provider is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Token == "" {
|
||||||
|
return nil, errors.New("easydns: the API token is missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Key == "" {
|
||||||
|
return nil, errors.New("easydns: the API key is missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DNSProvider{config: config, recordIDs: map[string]string{}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Present creates a TXT record to fulfill the dns-01 challenge
|
||||||
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
|
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
|
apiHost, apiDomain := splitFqdn(fqdn)
|
||||||
|
record := &zoneRecord{
|
||||||
|
Domain: apiDomain,
|
||||||
|
Host: apiHost,
|
||||||
|
Type: "TXT",
|
||||||
|
Rdata: value,
|
||||||
|
TTL: strconv.Itoa(d.config.TTL),
|
||||||
|
Prio: "0",
|
||||||
|
}
|
||||||
|
|
||||||
|
recordID, err := d.addRecord(apiDomain, record)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("easydns: error adding zone record: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key := getMapKey(fqdn, value)
|
||||||
|
|
||||||
|
d.recordIDsMu.Lock()
|
||||||
|
d.recordIDs[key] = recordID
|
||||||
|
d.recordIDsMu.Unlock()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanUp removes the TXT record matching the specified parameters
|
||||||
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
fqdn, challenge := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
|
key := getMapKey(fqdn, challenge)
|
||||||
|
recordID, exists := d.recordIDs[key]
|
||||||
|
if !exists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, apiDomain := splitFqdn(fqdn)
|
||||||
|
err := d.deleteRecord(apiDomain, recordID)
|
||||||
|
|
||||||
|
d.recordIDsMu.Lock()
|
||||||
|
defer delete(d.recordIDs, key)
|
||||||
|
d.recordIDsMu.Unlock()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("easydns: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||||
|
// Adjusting here to cope with spikes in propagation times.
|
||||||
|
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||||
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sequential All DNS challenges for this provider will be resolved sequentially.
|
||||||
|
// Returns the interval between each iteration.
|
||||||
|
func (d *DNSProvider) Sequential() time.Duration {
|
||||||
|
return d.config.SequenceInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitFqdn(fqdn string) (host, domain string) {
|
||||||
|
parts := dns.SplitDomainName(fqdn)
|
||||||
|
length := len(parts)
|
||||||
|
|
||||||
|
host = strings.Join(parts[0:length-2], ".")
|
||||||
|
domain = strings.Join(parts[length-2:length], ".")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMapKey(fqdn, value string) string {
|
||||||
|
return fqdn + "|" + value
|
||||||
|
}
|
6
vendor/github.com/go-acme/lego/providers/dns/exec/exec.go
generated
vendored
6
vendor/github.com/go-acme/lego/providers/dns/exec/exec.go
generated
vendored
|
@ -105,3 +105,9 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sequential All DNS challenges for this provider will be resolved sequentially.
|
||||||
|
// Returns the interval between each iteration.
|
||||||
|
func (d *DNSProvider) Sequential() time.Duration {
|
||||||
|
return d.config.PropagationTimeout
|
||||||
|
}
|
||||||
|
|
6
vendor/github.com/go-acme/lego/providers/dns/gcloud/googlecloud.go
generated
vendored
6
vendor/github.com/go-acme/lego/providers/dns/gcloud/googlecloud.go
generated
vendored
|
@ -156,7 +156,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
zone, err := d.getHostedZone(domain)
|
zone, err := d.getHostedZone(fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("googlecloud: %v", err)
|
return fmt.Errorf("googlecloud: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ func (d *DNSProvider) applyChanges(zone string, change *dns.Change) error {
|
||||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
fqdn, _ := dns01.GetRecord(domain, keyAuth)
|
fqdn, _ := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
zone, err := d.getHostedZone(domain)
|
zone, err := d.getHostedZone(fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("googlecloud: %v", err)
|
return fmt.Errorf("googlecloud: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ func (d *DNSProvider) getHostedZone(domain string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, z := range zones.ManagedZones {
|
for _, z := range zones.ManagedZones {
|
||||||
if z.Visibility == "public" {
|
if z.Visibility == "public" || z.Visibility == "" {
|
||||||
return z.Name, nil
|
return z.Name, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
197
vendor/github.com/go-acme/lego/providers/dns/joker/client.go
generated
vendored
Normal file
197
vendor/github.com/go-acme/lego/providers/dns/joker/client.go
generated
vendored
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
package joker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/challenge/dns01"
|
||||||
|
"github.com/go-acme/lego/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultBaseURL = "https://dmapi.joker.com/request/"
|
||||||
|
|
||||||
|
// Joker DMAPI Response
|
||||||
|
type response struct {
|
||||||
|
Headers url.Values
|
||||||
|
Body string
|
||||||
|
StatusCode int
|
||||||
|
StatusText string
|
||||||
|
AuthSid string
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseResponse parses HTTP response body
|
||||||
|
func parseResponse(message string) *response {
|
||||||
|
r := &response{Headers: url.Values{}, StatusCode: -1}
|
||||||
|
|
||||||
|
parts := strings.SplitN(message, "\n\n", 2)
|
||||||
|
|
||||||
|
for _, line := range strings.Split(parts[0], "\n") {
|
||||||
|
if strings.TrimSpace(line) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
kv := strings.SplitN(line, ":", 2)
|
||||||
|
|
||||||
|
val := ""
|
||||||
|
if len(kv) == 2 {
|
||||||
|
val = strings.TrimSpace(kv[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Headers.Add(kv[0], val)
|
||||||
|
|
||||||
|
switch kv[0] {
|
||||||
|
case "Status-Code":
|
||||||
|
i, err := strconv.Atoi(val)
|
||||||
|
if err == nil {
|
||||||
|
r.StatusCode = i
|
||||||
|
}
|
||||||
|
case "Status-Text":
|
||||||
|
r.StatusText = val
|
||||||
|
case "Auth-Sid":
|
||||||
|
r.AuthSid = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(parts) > 1 {
|
||||||
|
r.Body = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// login performs a login to Joker's DMAPI
|
||||||
|
func (d *DNSProvider) login() (*response, error) {
|
||||||
|
if d.config.AuthSid != "" {
|
||||||
|
// already logged in
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := d.postRequest("login", url.Values{"api-key": {d.config.APIKey}})
|
||||||
|
if err != nil {
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if response == nil {
|
||||||
|
return nil, fmt.Errorf("login returned nil response")
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.AuthSid == "" {
|
||||||
|
return response, fmt.Errorf("login did not return valid Auth-Sid")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.config.AuthSid = response.AuthSid
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// logout closes authenticated session with Joker's DMAPI
|
||||||
|
func (d *DNSProvider) logout() (*response, error) {
|
||||||
|
if d.config.AuthSid == "" {
|
||||||
|
return nil, fmt.Errorf("already logged out")
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := d.postRequest("logout", url.Values{})
|
||||||
|
if err == nil {
|
||||||
|
d.config.AuthSid = ""
|
||||||
|
}
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// getZone returns content of DNS zone for domain
|
||||||
|
func (d *DNSProvider) getZone(domain string) (*response, error) {
|
||||||
|
if d.config.AuthSid == "" {
|
||||||
|
return nil, fmt.Errorf("must be logged in to get zone")
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.postRequest("dns-zone-get", url.Values{"domain": {dns01.UnFqdn(domain)}})
|
||||||
|
}
|
||||||
|
|
||||||
|
// putZone uploads DNS zone to Joker DMAPI
|
||||||
|
func (d *DNSProvider) putZone(domain, zone string) (*response, error) {
|
||||||
|
if d.config.AuthSid == "" {
|
||||||
|
return nil, fmt.Errorf("must be logged in to put zone")
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.postRequest("dns-zone-put", url.Values{"domain": {dns01.UnFqdn(domain)}, "zone": {strings.TrimSpace(zone)}})
|
||||||
|
}
|
||||||
|
|
||||||
|
// postRequest performs actual HTTP request
|
||||||
|
func (d *DNSProvider) postRequest(cmd string, data url.Values) (*response, error) {
|
||||||
|
uri := d.config.BaseURL + cmd
|
||||||
|
|
||||||
|
if d.config.AuthSid != "" {
|
||||||
|
data.Set("auth-sid", d.config.AuthSid)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.config.Debug {
|
||||||
|
log.Infof("postRequest:\n\tURL: %q\n\tData: %v", uri, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := d.config.HTTPClient.PostForm(uri, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return nil, fmt.Errorf("HTTP error %d [%s]: %v", resp.StatusCode, http.StatusText(resp.StatusCode), string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseResponse(string(body)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporary workaround, until it get fixed on API side
|
||||||
|
func fixTxtLines(line string) string {
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
|
||||||
|
if len(fields) < 6 || fields[1] != "TXT" {
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
if fields[3][0] == '"' && fields[4] == `"` {
|
||||||
|
fields[3] = strings.TrimSpace(fields[3]) + `"`
|
||||||
|
fields = append(fields[:4], fields[5:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(fields, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeTxtEntryFromZone clean-ups all TXT records with given name
|
||||||
|
func removeTxtEntryFromZone(zone, relative string) (string, bool) {
|
||||||
|
prefix := fmt.Sprintf("%s TXT 0 ", relative)
|
||||||
|
|
||||||
|
modified := false
|
||||||
|
var zoneEntries []string
|
||||||
|
for _, line := range strings.Split(zone, "\n") {
|
||||||
|
if strings.HasPrefix(line, prefix) {
|
||||||
|
modified = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
zoneEntries = append(zoneEntries, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(strings.Join(zoneEntries, "\n")), modified
|
||||||
|
}
|
||||||
|
|
||||||
|
// addTxtEntryToZone returns DNS zone with added TXT record
|
||||||
|
func addTxtEntryToZone(zone, relative, value string, ttl int) string {
|
||||||
|
var zoneEntries []string
|
||||||
|
|
||||||
|
for _, line := range strings.Split(zone, "\n") {
|
||||||
|
zoneEntries = append(zoneEntries, fixTxtLines(line))
|
||||||
|
}
|
||||||
|
|
||||||
|
newZoneEntry := fmt.Sprintf("%s TXT 0 %q %d", relative, value, ttl)
|
||||||
|
zoneEntries = append(zoneEntries, newZoneEntry)
|
||||||
|
|
||||||
|
return strings.TrimSpace(strings.Join(zoneEntries, "\n"))
|
||||||
|
}
|
174
vendor/github.com/go-acme/lego/providers/dns/joker/joker.go
generated
vendored
Normal file
174
vendor/github.com/go-acme/lego/providers/dns/joker/joker.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
// Package joker implements a DNS provider for solving the DNS-01 challenge using joker.com DMAPI.
|
||||||
|
package joker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/challenge/dns01"
|
||||||
|
"github.com/go-acme/lego/log"
|
||||||
|
"github.com/go-acme/lego/platform/config/env"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config is used to configure the creation of the DNSProvider.
|
||||||
|
type Config struct {
|
||||||
|
Debug bool
|
||||||
|
BaseURL string
|
||||||
|
APIKey string
|
||||||
|
PropagationTimeout time.Duration
|
||||||
|
PollingInterval time.Duration
|
||||||
|
TTL int
|
||||||
|
HTTPClient *http.Client
|
||||||
|
AuthSid string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||||
|
func NewDefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
BaseURL: defaultBaseURL,
|
||||||
|
Debug: env.GetOrDefaultBool("JOKER_DEBUG", false),
|
||||||
|
TTL: env.GetOrDefaultInt("JOKER_TTL", dns01.DefaultTTL),
|
||||||
|
PropagationTimeout: env.GetOrDefaultSecond("JOKER_PROPAGATION_TIMEOUT", dns01.DefaultPropagationTimeout),
|
||||||
|
PollingInterval: env.GetOrDefaultSecond("JOKER_POLLING_INTERVAL", dns01.DefaultPollingInterval),
|
||||||
|
HTTPClient: &http.Client{
|
||||||
|
Timeout: env.GetOrDefaultSecond("JOKER_HTTP_TIMEOUT", 60*time.Second),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSProvider is an implementation of the ChallengeProviderTimeout interface
|
||||||
|
// that uses Joker's DMAPI to manage TXT records for a domain.
|
||||||
|
type DNSProvider struct {
|
||||||
|
config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProvider returns a DNSProvider instance configured for Joker DMAPI.
|
||||||
|
// Credentials must be passed in the environment variable JOKER_API_KEY.
|
||||||
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
|
values, err := env.Get("JOKER_API_KEY")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("joker: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.APIKey = values["JOKER_API_KEY"]
|
||||||
|
|
||||||
|
return NewDNSProviderConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProviderConfig return a DNSProvider instance configured for Joker DMAPI.
|
||||||
|
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("joker: the configuration of the DNS provider is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.APIKey == "" {
|
||||||
|
return nil, fmt.Errorf("joker: credentials missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasSuffix(config.BaseURL, "/") {
|
||||||
|
config.BaseURL += "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DNSProvider{config: config}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||||
|
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||||
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
// Present installs a TXT record for the DNS challenge.
|
||||||
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
|
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
|
zone, err := dns01.FindZoneByFqdn(fqdn)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("joker: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
relative := getRelative(fqdn, zone)
|
||||||
|
|
||||||
|
if d.config.Debug {
|
||||||
|
log.Infof("[%s] joker: adding TXT record %q to zone %q with value %q", domain, relative, zone, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := d.login()
|
||||||
|
if err != nil {
|
||||||
|
return formatResponseError(response, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err = d.getZone(zone)
|
||||||
|
if err != nil || response.StatusCode != 0 {
|
||||||
|
return formatResponseError(response, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dnsZone := addTxtEntryToZone(response.Body, relative, value, d.config.TTL)
|
||||||
|
|
||||||
|
response, err = d.putZone(zone, dnsZone)
|
||||||
|
if err != nil || response.StatusCode != 0 {
|
||||||
|
return formatResponseError(response, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanUp removes a TXT record used for a previous DNS challenge.
|
||||||
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
fqdn, _ := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
|
zone, err := dns01.FindZoneByFqdn(fqdn)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("joker: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
relative := getRelative(fqdn, zone)
|
||||||
|
|
||||||
|
if d.config.Debug {
|
||||||
|
log.Infof("[%s] joker: removing entry %q from zone %q", domain, relative, zone)
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := d.login()
|
||||||
|
if err != nil {
|
||||||
|
return formatResponseError(response, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
// Try to logout in case of errors
|
||||||
|
_, _ = d.logout()
|
||||||
|
}()
|
||||||
|
|
||||||
|
response, err = d.getZone(zone)
|
||||||
|
if err != nil || response.StatusCode != 0 {
|
||||||
|
return formatResponseError(response, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dnsZone, modified := removeTxtEntryFromZone(response.Body, relative)
|
||||||
|
if modified {
|
||||||
|
response, err = d.putZone(zone, dnsZone)
|
||||||
|
if err != nil || response.StatusCode != 0 {
|
||||||
|
return formatResponseError(response, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err = d.logout()
|
||||||
|
if err != nil {
|
||||||
|
return formatResponseError(response, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRelative(fqdn, zone string) string {
|
||||||
|
return dns01.UnFqdn(strings.TrimSuffix(fqdn, dns01.ToFqdn(zone)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatResponseError formats error with optional details from DMAPI response
|
||||||
|
func formatResponseError(response *response, err error) error {
|
||||||
|
if response != nil {
|
||||||
|
return fmt.Errorf("joker: DMAPI error: %v Response: %v", err, response.Headers)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("joker: DMAPI error: %v", err)
|
||||||
|
}
|
7
vendor/github.com/go-errors/errors/LICENSE.MIT
generated
vendored
Normal file
7
vendor/github.com/go-errors/errors/LICENSE.MIT
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Copyright (c) 2015 Conrad Irwin <conrad@bugsnag.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
217
vendor/github.com/go-errors/errors/error.go
generated
vendored
Normal file
217
vendor/github.com/go-errors/errors/error.go
generated
vendored
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
// Package errors provides errors that have stack-traces.
|
||||||
|
//
|
||||||
|
// This is particularly useful when you want to understand the
|
||||||
|
// state of execution when an error was returned unexpectedly.
|
||||||
|
//
|
||||||
|
// It provides the type *Error which implements the standard
|
||||||
|
// golang error interface, so you can use this library interchangably
|
||||||
|
// with code that is expecting a normal error return.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// package crashy
|
||||||
|
//
|
||||||
|
// import "github.com/go-errors/errors"
|
||||||
|
//
|
||||||
|
// var Crashed = errors.Errorf("oh dear")
|
||||||
|
//
|
||||||
|
// func Crash() error {
|
||||||
|
// return errors.New(Crashed)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This can be called as follows:
|
||||||
|
//
|
||||||
|
// package main
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// "crashy"
|
||||||
|
// "fmt"
|
||||||
|
// "github.com/go-errors/errors"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// func main() {
|
||||||
|
// err := crashy.Crash()
|
||||||
|
// if err != nil {
|
||||||
|
// if errors.Is(err, crashy.Crashed) {
|
||||||
|
// fmt.Println(err.(*errors.Error).ErrorStack())
|
||||||
|
// } else {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This package was original written to allow reporting to Bugsnag,
|
||||||
|
// but after I found similar packages by Facebook and Dropbox, it
|
||||||
|
// was moved to one canonical location so everyone can benefit.
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The maximum number of stackframes on any error.
|
||||||
|
var MaxStackDepth = 50
|
||||||
|
|
||||||
|
// Error is an error with an attached stacktrace. It can be used
|
||||||
|
// wherever the builtin error interface is expected.
|
||||||
|
type Error struct {
|
||||||
|
Err error
|
||||||
|
stack []uintptr
|
||||||
|
frames []StackFrame
|
||||||
|
prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New makes an Error from the given value. If that value is already an
|
||||||
|
// error then it will be used directly, if not, it will be passed to
|
||||||
|
// fmt.Errorf("%v"). The stacktrace will point to the line of code that
|
||||||
|
// called New.
|
||||||
|
func New(e interface{}) *Error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch e := e.(type) {
|
||||||
|
case error:
|
||||||
|
err = e
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("%v", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
stack := make([]uintptr, MaxStackDepth)
|
||||||
|
length := runtime.Callers(2, stack[:])
|
||||||
|
return &Error{
|
||||||
|
Err: err,
|
||||||
|
stack: stack[:length],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap makes an Error from the given value. If that value is already an
|
||||||
|
// error then it will be used directly, if not, it will be passed to
|
||||||
|
// fmt.Errorf("%v"). The skip parameter indicates how far up the stack
|
||||||
|
// to start the stacktrace. 0 is from the current call, 1 from its caller, etc.
|
||||||
|
func Wrap(e interface{}, skip int) *Error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch e := e.(type) {
|
||||||
|
case *Error:
|
||||||
|
return e
|
||||||
|
case error:
|
||||||
|
err = e
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("%v", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
stack := make([]uintptr, MaxStackDepth)
|
||||||
|
length := runtime.Callers(2+skip, stack[:])
|
||||||
|
return &Error{
|
||||||
|
Err: err,
|
||||||
|
stack: stack[:length],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapPrefix makes an Error from the given value. If that value is already an
|
||||||
|
// error then it will be used directly, if not, it will be passed to
|
||||||
|
// fmt.Errorf("%v"). The prefix parameter is used to add a prefix to the
|
||||||
|
// error message when calling Error(). The skip parameter indicates how far
|
||||||
|
// up the stack to start the stacktrace. 0 is from the current call,
|
||||||
|
// 1 from its caller, etc.
|
||||||
|
func WrapPrefix(e interface{}, prefix string, skip int) *Error {
|
||||||
|
|
||||||
|
err := Wrap(e, 1+skip)
|
||||||
|
|
||||||
|
if err.prefix != "" {
|
||||||
|
prefix = fmt.Sprintf("%s: %s", prefix, err.prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Error{
|
||||||
|
Err: err.Err,
|
||||||
|
stack: err.stack,
|
||||||
|
prefix: prefix,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is detects whether the error is equal to a given error. Errors
|
||||||
|
// are considered equal by this function if they are the same object,
|
||||||
|
// or if they both contain the same error inside an errors.Error.
|
||||||
|
func Is(e error, original error) bool {
|
||||||
|
|
||||||
|
if e == original {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if e, ok := e.(*Error); ok {
|
||||||
|
return Is(e.Err, original)
|
||||||
|
}
|
||||||
|
|
||||||
|
if original, ok := original.(*Error); ok {
|
||||||
|
return Is(e, original.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf creates a new error with the given message. You can use it
|
||||||
|
// as a drop-in replacement for fmt.Errorf() to provide descriptive
|
||||||
|
// errors in return values.
|
||||||
|
func Errorf(format string, a ...interface{}) *Error {
|
||||||
|
return Wrap(fmt.Errorf(format, a...), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the underlying error's message.
|
||||||
|
func (err *Error) Error() string {
|
||||||
|
|
||||||
|
msg := err.Err.Error()
|
||||||
|
if err.prefix != "" {
|
||||||
|
msg = fmt.Sprintf("%s: %s", err.prefix, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stack returns the callstack formatted the same way that go does
|
||||||
|
// in runtime/debug.Stack()
|
||||||
|
func (err *Error) Stack() []byte {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
|
||||||
|
for _, frame := range err.StackFrames() {
|
||||||
|
buf.WriteString(frame.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callers satisfies the bugsnag ErrorWithCallerS() interface
|
||||||
|
// so that the stack can be read out.
|
||||||
|
func (err *Error) Callers() []uintptr {
|
||||||
|
return err.stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorStack returns a string that contains both the
|
||||||
|
// error message and the callstack.
|
||||||
|
func (err *Error) ErrorStack() string {
|
||||||
|
return err.TypeName() + " " + err.Error() + "\n" + string(err.Stack())
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackFrames returns an array of frames containing information about the
|
||||||
|
// stack.
|
||||||
|
func (err *Error) StackFrames() []StackFrame {
|
||||||
|
if err.frames == nil {
|
||||||
|
err.frames = make([]StackFrame, len(err.stack))
|
||||||
|
|
||||||
|
for i, pc := range err.stack {
|
||||||
|
err.frames[i] = NewStackFrame(pc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err.frames
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeName returns the type this error. e.g. *errors.stringError.
|
||||||
|
func (err *Error) TypeName() string {
|
||||||
|
if _, ok := err.Err.(uncaughtPanic); ok {
|
||||||
|
return "panic"
|
||||||
|
}
|
||||||
|
return reflect.TypeOf(err.Err).String()
|
||||||
|
}
|
127
vendor/github.com/go-errors/errors/parse_panic.go
generated
vendored
Normal file
127
vendor/github.com/go-errors/errors/parse_panic.go
generated
vendored
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type uncaughtPanic struct{ message string }
|
||||||
|
|
||||||
|
func (p uncaughtPanic) Error() string {
|
||||||
|
return p.message
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsePanic allows you to get an error object from the output of a go program
|
||||||
|
// that panicked. This is particularly useful with https://github.com/mitchellh/panicwrap.
|
||||||
|
func ParsePanic(text string) (*Error, error) {
|
||||||
|
lines := strings.Split(text, "\n")
|
||||||
|
|
||||||
|
state := "start"
|
||||||
|
|
||||||
|
var message string
|
||||||
|
var stack []StackFrame
|
||||||
|
|
||||||
|
for i := 0; i < len(lines); i++ {
|
||||||
|
line := lines[i]
|
||||||
|
|
||||||
|
if state == "start" {
|
||||||
|
if strings.HasPrefix(line, "panic: ") {
|
||||||
|
message = strings.TrimPrefix(line, "panic: ")
|
||||||
|
state = "seek"
|
||||||
|
} else {
|
||||||
|
return nil, Errorf("bugsnag.panicParser: Invalid line (no prefix): %s", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if state == "seek" {
|
||||||
|
if strings.HasPrefix(line, "goroutine ") && strings.HasSuffix(line, "[running]:") {
|
||||||
|
state = "parsing"
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if state == "parsing" {
|
||||||
|
if line == "" {
|
||||||
|
state = "done"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
createdBy := false
|
||||||
|
if strings.HasPrefix(line, "created by ") {
|
||||||
|
line = strings.TrimPrefix(line, "created by ")
|
||||||
|
createdBy = true
|
||||||
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
|
|
||||||
|
if i >= len(lines) {
|
||||||
|
return nil, Errorf("bugsnag.panicParser: Invalid line (unpaired): %s", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
frame, err := parsePanicFrame(line, lines[i], createdBy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stack = append(stack, *frame)
|
||||||
|
if createdBy {
|
||||||
|
state = "done"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if state == "done" || state == "parsing" {
|
||||||
|
return &Error{Err: uncaughtPanic{message}, frames: stack}, nil
|
||||||
|
}
|
||||||
|
return nil, Errorf("could not parse panic: %v", text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The lines we're passing look like this:
|
||||||
|
//
|
||||||
|
// main.(*foo).destruct(0xc208067e98)
|
||||||
|
// /0/go/src/github.com/bugsnag/bugsnag-go/pan/main.go:22 +0x151
|
||||||
|
func parsePanicFrame(name string, line string, createdBy bool) (*StackFrame, error) {
|
||||||
|
idx := strings.LastIndex(name, "(")
|
||||||
|
if idx == -1 && !createdBy {
|
||||||
|
return nil, Errorf("bugsnag.panicParser: Invalid line (no call): %s", name)
|
||||||
|
}
|
||||||
|
if idx != -1 {
|
||||||
|
name = name[:idx]
|
||||||
|
}
|
||||||
|
pkg := ""
|
||||||
|
|
||||||
|
if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 {
|
||||||
|
pkg += name[:lastslash] + "/"
|
||||||
|
name = name[lastslash+1:]
|
||||||
|
}
|
||||||
|
if period := strings.Index(name, "."); period >= 0 {
|
||||||
|
pkg += name[:period]
|
||||||
|
name = name[period+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
name = strings.Replace(name, "·", ".", -1)
|
||||||
|
|
||||||
|
if !strings.HasPrefix(line, "\t") {
|
||||||
|
return nil, Errorf("bugsnag.panicParser: Invalid line (no tab): %s", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = strings.LastIndex(line, ":")
|
||||||
|
if idx == -1 {
|
||||||
|
return nil, Errorf("bugsnag.panicParser: Invalid line (no line number): %s", line)
|
||||||
|
}
|
||||||
|
file := line[1:idx]
|
||||||
|
|
||||||
|
number := line[idx+1:]
|
||||||
|
if idx = strings.Index(number, " +"); idx > -1 {
|
||||||
|
number = number[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
lno, err := strconv.ParseInt(number, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return nil, Errorf("bugsnag.panicParser: Invalid line (bad line number): %s", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StackFrame{
|
||||||
|
File: file,
|
||||||
|
LineNumber: int(lno),
|
||||||
|
Package: pkg,
|
||||||
|
Name: name,
|
||||||
|
}, nil
|
||||||
|
}
|
102
vendor/github.com/go-errors/errors/stackframe.go
generated
vendored
Normal file
102
vendor/github.com/go-errors/errors/stackframe.go
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A StackFrame contains all necessary information about to generate a line
|
||||||
|
// in a callstack.
|
||||||
|
type StackFrame struct {
|
||||||
|
// The path to the file containing this ProgramCounter
|
||||||
|
File string
|
||||||
|
// The LineNumber in that file
|
||||||
|
LineNumber int
|
||||||
|
// The Name of the function that contains this ProgramCounter
|
||||||
|
Name string
|
||||||
|
// The Package that contains this function
|
||||||
|
Package string
|
||||||
|
// The underlying ProgramCounter
|
||||||
|
ProgramCounter uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStackFrame popoulates a stack frame object from the program counter.
|
||||||
|
func NewStackFrame(pc uintptr) (frame StackFrame) {
|
||||||
|
|
||||||
|
frame = StackFrame{ProgramCounter: pc}
|
||||||
|
if frame.Func() == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
frame.Package, frame.Name = packageAndName(frame.Func())
|
||||||
|
|
||||||
|
// pc -1 because the program counters we use are usually return addresses,
|
||||||
|
// and we want to show the line that corresponds to the function call
|
||||||
|
frame.File, frame.LineNumber = frame.Func().FileLine(pc - 1)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Func returns the function that contained this frame.
|
||||||
|
func (frame *StackFrame) Func() *runtime.Func {
|
||||||
|
if frame.ProgramCounter == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return runtime.FuncForPC(frame.ProgramCounter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the stackframe formatted in the same way as go does
|
||||||
|
// in runtime/debug.Stack()
|
||||||
|
func (frame *StackFrame) String() string {
|
||||||
|
str := fmt.Sprintf("%s:%d (0x%x)\n", frame.File, frame.LineNumber, frame.ProgramCounter)
|
||||||
|
|
||||||
|
source, err := frame.SourceLine()
|
||||||
|
if err != nil {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
return str + fmt.Sprintf("\t%s: %s\n", frame.Name, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SourceLine gets the line of code (from File and Line) of the original source if possible.
|
||||||
|
func (frame *StackFrame) SourceLine() (string, error) {
|
||||||
|
data, err := ioutil.ReadFile(frame.File)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", New(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := bytes.Split(data, []byte{'\n'})
|
||||||
|
if frame.LineNumber <= 0 || frame.LineNumber >= len(lines) {
|
||||||
|
return "???", nil
|
||||||
|
}
|
||||||
|
// -1 because line-numbers are 1 based, but our array is 0 based
|
||||||
|
return string(bytes.Trim(lines[frame.LineNumber-1], " \t")), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func packageAndName(fn *runtime.Func) (string, string) {
|
||||||
|
name := fn.Name()
|
||||||
|
pkg := ""
|
||||||
|
|
||||||
|
// The name includes the path name to the package, which is unnecessary
|
||||||
|
// since the file name is already included. Plus, it has center dots.
|
||||||
|
// That is, we see
|
||||||
|
// runtime/debug.*T·ptrmethod
|
||||||
|
// and want
|
||||||
|
// *T.ptrmethod
|
||||||
|
// Since the package path might contains dots (e.g. code.google.com/...),
|
||||||
|
// we first remove the path prefix if there is one.
|
||||||
|
if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 {
|
||||||
|
pkg += name[:lastslash] + "/"
|
||||||
|
name = name[lastslash+1:]
|
||||||
|
}
|
||||||
|
if period := strings.Index(name, "."); period >= 0 {
|
||||||
|
pkg += name[:period]
|
||||||
|
name = name[period+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
name = strings.Replace(name, "·", ".", -1)
|
||||||
|
return pkg, name
|
||||||
|
}
|
21
vendor/github.com/labbsr0x/bindman-dns-webhook/LICENSE
generated
vendored
Normal file
21
vendor/github.com/labbsr0x/bindman-dns-webhook/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Labbs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
113
vendor/github.com/labbsr0x/bindman-dns-webhook/src/client/client.go
generated
vendored
Normal file
113
vendor/github.com/labbsr0x/bindman-dns-webhook/src/client/client.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/labbsr0x/bindman-dns-webhook/src/types"
|
||||||
|
"github.com/labbsr0x/goh/gohclient"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const recordsPath = "/records"
|
||||||
|
|
||||||
|
// DNSWebhookClient defines the basic structure of a DNS Listener
|
||||||
|
type DNSWebhookClient struct {
|
||||||
|
ClientAPI gohclient.API
|
||||||
|
}
|
||||||
|
|
||||||
|
// New builds the client to communicate with the dns manager
|
||||||
|
func New(managerAddress string, httpClient *http.Client) (*DNSWebhookClient, error) {
|
||||||
|
if strings.TrimSpace(managerAddress) == "" {
|
||||||
|
return nil, errors.New("managerAddress parameter must be a non-empty string")
|
||||||
|
}
|
||||||
|
client, err := gohclient.New(httpClient, managerAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
client.Accept = "application/json"
|
||||||
|
client.ContentType = "application/json"
|
||||||
|
client.UserAgent = "bindman-dns-webhook-client"
|
||||||
|
|
||||||
|
return &DNSWebhookClient{
|
||||||
|
ClientAPI: client,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRecords communicates with the dns manager and gets the DNS Records
|
||||||
|
func (l *DNSWebhookClient) GetRecords() (result []types.DNSRecord, err error) {
|
||||||
|
resp, data, err := l.ClientAPI.Get(recordsPath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
err = json.Unmarshal(data, &result)
|
||||||
|
} else {
|
||||||
|
err = parseResponseBodyToError(data)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRecord communicates with the dns manager and gets a DNS Record
|
||||||
|
func (l *DNSWebhookClient) GetRecord(name, recordType string) (result types.DNSRecord, err error) {
|
||||||
|
resp, data, err := l.ClientAPI.Get(fmt.Sprintf(recordsPath+"/%s/%s", name, recordType))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
err = json.Unmarshal(data, &result)
|
||||||
|
} else {
|
||||||
|
err = parseResponseBodyToError(data)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRecord adds a DNS record
|
||||||
|
func (l *DNSWebhookClient) AddRecord(name string, recordType string, value string) error {
|
||||||
|
return l.addOrUpdateRecord(&types.DNSRecord{Value: value, Name: name, Type: recordType}, l.ClientAPI.Post)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRecord is a function that calls the defined webhook to update a specific dns record
|
||||||
|
func (l *DNSWebhookClient) UpdateRecord(record *types.DNSRecord) error {
|
||||||
|
return l.addOrUpdateRecord(record, l.ClientAPI.Put)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addOrUpdateRecord .
|
||||||
|
func (l *DNSWebhookClient) addOrUpdateRecord(record *types.DNSRecord, action func(url string, body []byte) (*http.Response, []byte, error)) error {
|
||||||
|
if errs := record.Check(); errs != nil {
|
||||||
|
return fmt.Errorf("invalid DNS Record: %v", strings.Join(errs, ", "))
|
||||||
|
}
|
||||||
|
mr, err := json.Marshal(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp, data, err := action(recordsPath, mr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return parseResponseBodyToError(data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveRecord is a function that calls the defined webhook to remove a specific dns record
|
||||||
|
func (l *DNSWebhookClient) RemoveRecord(name, recordType string) error {
|
||||||
|
resp, data, err := l.ClientAPI.Delete(fmt.Sprintf(recordsPath+"/%s/%s", name, recordType))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusNoContent {
|
||||||
|
return parseResponseBodyToError(data)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseResponseBodyToError(data []byte) error {
|
||||||
|
var err types.Error
|
||||||
|
if errUnmarshal := json.Unmarshal(data, &err); errUnmarshal != nil {
|
||||||
|
return errUnmarshal
|
||||||
|
}
|
||||||
|
return &err
|
||||||
|
}
|
20
vendor/github.com/labbsr0x/bindman-dns-webhook/src/types/dnsmanager.go
generated
vendored
Normal file
20
vendor/github.com/labbsr0x/bindman-dns-webhook/src/types/dnsmanager.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
// DNSManager defines the operations a DNS Manager provider should implement
|
||||||
|
type DNSManager interface {
|
||||||
|
|
||||||
|
// GetDNSRecords retrieves all the dns records being managed
|
||||||
|
GetDNSRecords() ([]DNSRecord, error)
|
||||||
|
|
||||||
|
// GetDNSRecord retrieves the dns record identified by name
|
||||||
|
GetDNSRecord(name, recordType string) (*DNSRecord, error)
|
||||||
|
|
||||||
|
// RemoveDNSRecord removes a DNS record
|
||||||
|
RemoveDNSRecord(name, recordType string) error
|
||||||
|
|
||||||
|
// AddDNSRecord adds a new DNS record
|
||||||
|
AddDNSRecord(record DNSRecord) error
|
||||||
|
|
||||||
|
// UpdateDNSRecord updates an existing DNS record
|
||||||
|
UpdateDNSRecord(record DNSRecord) error
|
||||||
|
}
|
40
vendor/github.com/labbsr0x/bindman-dns-webhook/src/types/dnsrecord.go
generated
vendored
Normal file
40
vendor/github.com/labbsr0x/bindman-dns-webhook/src/types/dnsrecord.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DNSRecord defines what we understand as a DNSRecord
|
||||||
|
type DNSRecord struct {
|
||||||
|
// Name the DNS host name
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Value the value of this record
|
||||||
|
Value string `json:"value"`
|
||||||
|
|
||||||
|
// Type the record type
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check verifies if the DNS record satisfies certain conditions
|
||||||
|
func (record *DNSRecord) Check() []string {
|
||||||
|
logrus.Infof("Record to check: '%v'", record)
|
||||||
|
emptyValueErrorMessage := "the value of field '%s' cannot be empty"
|
||||||
|
var errs []string
|
||||||
|
|
||||||
|
if strings.TrimSpace(record.Name) == "" {
|
||||||
|
errs = append(errs, fmt.Sprintf(emptyValueErrorMessage, "name"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.TrimSpace(record.Value) == "" {
|
||||||
|
errs = append(errs, fmt.Sprintf(emptyValueErrorMessage, "value"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.TrimSpace(record.Type) == "" {
|
||||||
|
errs = append(errs, fmt.Sprintf(emptyValueErrorMessage, "type"))
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
51
vendor/github.com/labbsr0x/bindman-dns-webhook/src/types/error.go
generated
vendored
Normal file
51
vendor/github.com/labbsr0x/bindman-dns-webhook/src/types/error.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error groups together information that defines an error. Should always be used to
|
||||||
|
type Error struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
Details []string `json:"details,omitempty"`
|
||||||
|
Err error `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error() gives a string representing the error; also, forces the Error type to comply with the error interface
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
msg := fmt.Sprintf("ERROR (%v): %s; \n Inner error: %s", e.Code, e.Message, e.Err)
|
||||||
|
logrus.Debug(msg)
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// BadRequestError create an Error instance with http.StatusBadRequest code
|
||||||
|
func BadRequestError(message string, err error, details ...string) *Error {
|
||||||
|
return &Error{Message: message, Err: err, Code: http.StatusBadRequest, Details: details}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BadRequestError create an Error instance with http.StatusNotFound code
|
||||||
|
func NotFoundError(message string, err error, details ...string) *Error {
|
||||||
|
return &Error{Message: message, Err: err, Code: http.StatusNotFound, Details: details}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BadRequestError create an Error instance with http.StatusInternalServerError code
|
||||||
|
func InternalServerError(message string, err error, details ...string) *Error {
|
||||||
|
return &Error{Message: message, Err: err, Code: http.StatusInternalServerError, Details: details}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PanicIfError is just a wrapper to a panic call that propagates error when it's not nil
|
||||||
|
func PanicIfError(e error) {
|
||||||
|
if e != nil {
|
||||||
|
logrus.Errorf(e.Error())
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panic wraps a panic call propagating the given error parameter
|
||||||
|
func Panic(e Error) {
|
||||||
|
logrus.Errorf(e.Error())
|
||||||
|
panic(e)
|
||||||
|
}
|
21
vendor/github.com/labbsr0x/goh/LICENSE
generated
vendored
Normal file
21
vendor/github.com/labbsr0x/goh/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Abilio Esteves
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
114
vendor/github.com/labbsr0x/goh/gohclient/gohclient.go
generated
vendored
Normal file
114
vendor/github.com/labbsr0x/goh/gohclient/gohclient.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package gohclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// API defines an interface for helper methods that encapsulates http requests complexities
|
||||||
|
type API interface {
|
||||||
|
Put(url string, data []byte) (*http.Response, []byte, error)
|
||||||
|
Post(url string, data []byte) (*http.Response, []byte, error)
|
||||||
|
Get(url string) (*http.Response, []byte, error)
|
||||||
|
Delete(url string) (*http.Response, []byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default defines a struct that handles with HTTP requests for a bindman webhook client
|
||||||
|
type Default struct {
|
||||||
|
// User agent used when communicating with the API
|
||||||
|
UserAgent string
|
||||||
|
// Request content type used when communicating with the API
|
||||||
|
ContentType string
|
||||||
|
Accept string
|
||||||
|
BaseURL *url.URL
|
||||||
|
HTTPClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// New instantiates a default goh client
|
||||||
|
// If a nil httpClient is provided, http.DefaultClient will be used.
|
||||||
|
func New(httpClient *http.Client, baseURL string) (*Default, error) {
|
||||||
|
if httpClient == nil {
|
||||||
|
httpClient = http.DefaultClient
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(baseURL) == "" {
|
||||||
|
return nil, errors.New("base URL cannot be an empty string")
|
||||||
|
}
|
||||||
|
parsedURL, err := url.Parse(baseURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Default{
|
||||||
|
BaseURL: parsedURL,
|
||||||
|
HTTPClient: httpClient,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put wraps the call to http.NewRequest apis and properly submits a new HTTP POST request
|
||||||
|
func (c *Default) Put(path string, data []byte) (*http.Response, []byte, error) {
|
||||||
|
return c.request(path, "PUT", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post wraps the call to http.NewRequest apis and properly submits a new HTTP POST request
|
||||||
|
func (c *Default) Post(path string, data []byte) (*http.Response, []byte, error) {
|
||||||
|
return c.request(path, "POST", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get wraps the call to http.NewRequest apis and properly submits a new HTTP GET request
|
||||||
|
func (c *Default) Get(path string) (*http.Response, []byte, error) {
|
||||||
|
return c.request(path, "GET", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete wraps the call to http.NewRequest apis and properly submits a new HTTP DELETE request
|
||||||
|
func (c *Default) Delete(path string) (*http.Response, []byte, error) {
|
||||||
|
return c.request(path, "DELETE", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// request defines a generic method to execute http requests
|
||||||
|
func (c *Default) request(path, method string, body []byte) (resp *http.Response, data []byte, err error) {
|
||||||
|
u, err := c.BaseURL.Parse(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, u.String(), bytes.NewBuffer(body))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("HTTP request creation failed. err=%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if body != nil && strings.TrimSpace(c.ContentType) != "" {
|
||||||
|
req.Header.Set("Content-Type", c.ContentType)
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(c.Accept) != "" {
|
||||||
|
req.Header.Set("Accept", c.Accept)
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(c.UserAgent) != "" {
|
||||||
|
req.Header.Set("User-Agent", c.UserAgent)
|
||||||
|
}
|
||||||
|
logrus.Debugf("%v request=%v", method, req)
|
||||||
|
|
||||||
|
resp, err = c.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("HTTP %v request invocation failed. err=%v", method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer dClose(resp.Body)
|
||||||
|
logrus.Debugf("Response: %v", resp)
|
||||||
|
data, err = ioutil.ReadAll(resp.Body)
|
||||||
|
logrus.Debugf("Response body: %v", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func dClose(c io.Closer) {
|
||||||
|
if err := c.Close(); err != nil {
|
||||||
|
logrus.Errorf("HTTP response body close invocation failed. err=%v", err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue