forked from TrueCloudLab/lego
chore: update to go1.20 (#1993)
This commit is contained in:
parent
c365d7efc8
commit
b37d60c033
13 changed files with 144 additions and 92 deletions
2
.github/workflows/documentation.yml
vendored
2
.github/workflows/documentation.yml
vendored
|
@ -11,7 +11,7 @@ jobs:
|
|||
name: Build and deploy documentation
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO_VERSION: '1.20'
|
||||
GO_VERSION: stable
|
||||
HUGO_VERSION: '0.117.0'
|
||||
CGO_ENABLED: 0
|
||||
|
||||
|
|
28
.github/workflows/go-cross.yml
vendored
28
.github/workflows/go-cross.yml
vendored
|
@ -16,37 +16,19 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.19', '1.20', 1.x ]
|
||||
go-version: [ stable, oldstable ]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
# https://github.com/marketplace/actions/setup-go-environment
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
# https://github.com/marketplace/actions/checkout
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# https://github.com/marketplace/actions/cache
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
# https://github.com/marketplace/actions/setup-go-environment
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
# In order:
|
||||
# * Module download cache
|
||||
# * Build cache (Linux)
|
||||
# * Build cache (Mac)
|
||||
# * Build cache (Windows)
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
~/Library/Caches/go-build
|
||||
%LocalAppData%\go-build
|
||||
key: ${{ runner.os }}-${{ matrix.go-version }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.go-version }}-go-
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Test
|
||||
run: go test -v -cover ./...
|
||||
|
|
21
.github/workflows/pr.yml
vendored
21
.github/workflows/pr.yml
vendored
|
@ -12,8 +12,8 @@ jobs:
|
|||
name: Main Process
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO_VERSION: '1.20'
|
||||
GOLANGCI_LINT_VERSION: v1.53.1
|
||||
GO_VERSION: stable
|
||||
GOLANGCI_LINT_VERSION: v1.54.1
|
||||
HUGO_VERSION: '0.117.0'
|
||||
CGO_ENABLED: 0
|
||||
LEGO_E2E_TESTS: CI
|
||||
|
@ -21,26 +21,17 @@ jobs:
|
|||
|
||||
steps:
|
||||
|
||||
# https://github.com/marketplace/actions/setup-go-environment
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
# https://github.com/marketplace/actions/checkout
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# https://github.com/marketplace/actions/cache
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
# https://github.com/marketplace/actions/setup-go-environment
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Check and get dependencies
|
||||
run: |
|
||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -11,7 +11,7 @@ jobs:
|
|||
name: Release version
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO_VERSION: '1.20'
|
||||
GO_VERSION: stable
|
||||
CGO_ENABLED: 0
|
||||
|
||||
steps:
|
||||
|
|
|
@ -35,13 +35,14 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
|
|||
}
|
||||
|
||||
var responses []acme.Authorization
|
||||
failures := make(obtainError)
|
||||
|
||||
failures := newObtainError()
|
||||
for i := 0; i < len(order.Authorizations); i++ {
|
||||
select {
|
||||
case res := <-resc:
|
||||
responses = append(responses, res)
|
||||
case err := <-errc:
|
||||
failures[err.Domain] = err.Error
|
||||
failures.Add(err.Domain, err.Error)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,12 +53,7 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
|
|||
close(resc)
|
||||
close(errc)
|
||||
|
||||
// be careful to not return an empty failures map;
|
||||
// even if empty, they become non-nil error values
|
||||
if len(failures) > 0 {
|
||||
return responses, failures
|
||||
}
|
||||
return responses, nil
|
||||
return responses, failures.Join()
|
||||
}
|
||||
|
||||
func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder, force bool) {
|
||||
|
|
|
@ -149,11 +149,11 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
|
|||
|
||||
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
|
||||
|
||||
failures := make(obtainError)
|
||||
failures := newObtainError()
|
||||
cert, err := c.getForOrder(domains, order, request.Bundle, request.PrivateKey, request.MustStaple, request.PreferredChain)
|
||||
if err != nil {
|
||||
for _, auth := range authz {
|
||||
failures[challenge.GetTargetedDomain(auth)] = err
|
||||
failures.Add(challenge.GetTargetedDomain(auth), err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,12 +161,7 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
|
|||
c.deactivateAuthorizations(order, true)
|
||||
}
|
||||
|
||||
// Do not return an empty failures map, because
|
||||
// it would still be a non-nil error value
|
||||
if len(failures) > 0 {
|
||||
return cert, failures
|
||||
}
|
||||
return cert, nil
|
||||
return cert, failures.Join()
|
||||
}
|
||||
|
||||
// ObtainForCSR tries to obtain a certificate matching the CSR passed into it.
|
||||
|
@ -219,11 +214,11 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
|
|||
|
||||
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
|
||||
|
||||
failures := make(obtainError)
|
||||
failures := newObtainError()
|
||||
cert, err := c.getForCSR(domains, order, request.Bundle, request.CSR.Raw, nil, request.PreferredChain)
|
||||
if err != nil {
|
||||
for _, auth := range authz {
|
||||
failures[challenge.GetTargetedDomain(auth)] = err
|
||||
failures.Add(challenge.GetTargetedDomain(auth), err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,12 +231,7 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
|
|||
cert.CSR = certcrypto.PEMEncode(request.CSR)
|
||||
}
|
||||
|
||||
// Do not return an empty failures map,
|
||||
// because it would still be a non-nil error value
|
||||
if len(failures) > 0 {
|
||||
return cert, failures
|
||||
}
|
||||
return cert, nil
|
||||
return cert, failures.Join()
|
||||
}
|
||||
|
||||
func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, bundle bool, privateKey crypto.PrivateKey, mustStaple bool, preferredChain string) (*Resource, error) {
|
||||
|
|
|
@ -1,27 +1,37 @@
|
|||
package certificate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// obtainError is returned when there are specific errors available per domain.
|
||||
type obtainError map[string]error
|
||||
type obtainError struct {
|
||||
data map[string]error
|
||||
}
|
||||
|
||||
func (e obtainError) Error() string {
|
||||
buffer := bytes.NewBufferString("error: one or more domains had a problem:\n")
|
||||
func newObtainError() *obtainError {
|
||||
return &obtainError{data: make(map[string]error)}
|
||||
}
|
||||
|
||||
var domains []string
|
||||
for domain := range e {
|
||||
domains = append(domains, domain)
|
||||
func (e *obtainError) Add(domain string, err error) {
|
||||
e.data[domain] = err
|
||||
}
|
||||
|
||||
func (e *obtainError) Join() error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
sort.Strings(domains)
|
||||
|
||||
for _, domain := range domains {
|
||||
_, _ = fmt.Fprintf(buffer, "[%s] %s\n", domain, e[domain])
|
||||
if len(e.data) == 0 {
|
||||
return nil
|
||||
}
|
||||
return buffer.String()
|
||||
|
||||
var err error
|
||||
for d, e := range e.data {
|
||||
err = errors.Join(err, fmt.Errorf("%s: %w", d, e))
|
||||
}
|
||||
|
||||
return fmt.Errorf("error: one or more domains had a problem:\n%w", err)
|
||||
}
|
||||
|
||||
type domainError struct {
|
||||
|
|
70
certificate/errors_test.go
Normal file
70
certificate/errors_test.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
package certificate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type TomatoError struct{}
|
||||
|
||||
func (t TomatoError) Error() string {
|
||||
return "tomato"
|
||||
}
|
||||
|
||||
type CarrotError struct{}
|
||||
|
||||
func (t CarrotError) Error() string {
|
||||
return "carrot"
|
||||
}
|
||||
|
||||
func Test_obtainError_Join(t *testing.T) {
|
||||
failures := newObtainError()
|
||||
|
||||
failures.Add("example.com", &TomatoError{})
|
||||
|
||||
err := failures.Join()
|
||||
|
||||
to := &TomatoError{}
|
||||
assert.ErrorAs(t, err, &to)
|
||||
}
|
||||
|
||||
func Test_obtainError_Join_multiple_domains(t *testing.T) {
|
||||
failures := newObtainError()
|
||||
|
||||
failures.Add("example.com", &TomatoError{})
|
||||
failures.Add("example.org", &CarrotError{})
|
||||
|
||||
err := failures.Join()
|
||||
|
||||
to := &TomatoError{}
|
||||
assert.ErrorAs(t, err, &to)
|
||||
|
||||
ca := &CarrotError{}
|
||||
assert.ErrorAs(t, err, &ca)
|
||||
}
|
||||
|
||||
func Test_obtainError_Join_no_error(t *testing.T) {
|
||||
failures := newObtainError()
|
||||
|
||||
assert.NoError(t, failures.Join())
|
||||
}
|
||||
|
||||
func Test_obtainError_Join_same_domain(t *testing.T) {
|
||||
failures := newObtainError()
|
||||
|
||||
failures.Add("example.com", &TomatoError{})
|
||||
failures.Add("example.com", &CarrotError{})
|
||||
|
||||
err := failures.Join()
|
||||
|
||||
to := &TomatoError{}
|
||||
if errors.As(err, &to) {
|
||||
require.Fail(t, "TomatoError should be overridden by CarrotError")
|
||||
}
|
||||
|
||||
ca := &CarrotError{}
|
||||
assert.ErrorAs(t, err, &ca)
|
||||
}
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
|||
module github.com/go-acme/lego/v4
|
||||
|
||||
go 1.19
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.2.3
|
||||
|
|
|
@ -11,26 +11,26 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const defaultBaseURL = "https://ipv64.net"
|
||||
|
||||
const authorizationHeader = "Authorization"
|
||||
|
||||
type Client struct {
|
||||
apiKey string
|
||||
|
||||
baseURL *url.URL
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
func NewClient(apiKey string) *Client {
|
||||
func NewClient(hc *http.Client) *Client {
|
||||
baseURL, _ := url.Parse(defaultBaseURL)
|
||||
|
||||
if hc == nil {
|
||||
hc = &http.Client{Timeout: 15 * time.Second}
|
||||
}
|
||||
|
||||
return &Client{
|
||||
apiKey: apiKey,
|
||||
baseURL: baseURL,
|
||||
HTTPClient: &http.Client{Timeout: 15 * time.Second},
|
||||
HTTPClient: hc,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,8 +91,6 @@ func (c Client) DeleteRecord(ctx context.Context, domain, prefix, recordType, co
|
|||
}
|
||||
|
||||
func (c Client) do(req *http.Request, result any) error {
|
||||
req.Header.Set(authorizationHeader, fmt.Sprintf("Bearer %s", c.apiKey))
|
||||
|
||||
if req.Method != http.MethodGet {
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
|
@ -140,3 +138,16 @@ func parseError(req *http.Request, resp *http.Response) error {
|
|||
|
||||
return errAPI
|
||||
}
|
||||
|
||||
func OAuthStaticAccessToken(client *http.Client, accessToken string) *http.Client {
|
||||
if client == nil {
|
||||
client = &http.Client{Timeout: 15 * time.Second}
|
||||
}
|
||||
|
||||
client.Transport = &oauth2.Transport{
|
||||
Source: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: accessToken}),
|
||||
Base: client.Transport,
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
|
|
@ -15,12 +15,14 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const testAPIKey = "secret"
|
||||
|
||||
func setupTest(t *testing.T, handler http.HandlerFunc) *Client {
|
||||
t.Helper()
|
||||
|
||||
server := httptest.NewServer(handler)
|
||||
|
||||
client := NewClient("secret")
|
||||
client := NewClient(OAuthStaticAccessToken(server.Client(), testAPIKey))
|
||||
client.HTTPClient = server.Client()
|
||||
client.baseURL, _ = url.Parse(server.URL)
|
||||
|
||||
|
@ -34,8 +36,8 @@ func testHandler(method, filename string, statusCode int) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
auth := req.Header.Get(authorizationHeader)
|
||||
if auth != "Bearer secret" {
|
||||
auth := req.Header.Get("Authorization")
|
||||
if auth != "Bearer "+testAPIKey {
|
||||
http.Error(rw, fmt.Sprintf("invalid API key: %s", auth), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, errors.New("ipv64: credentials missing")
|
||||
}
|
||||
|
||||
client := internal.NewClient(config.APIKey)
|
||||
client := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.APIKey))
|
||||
|
||||
if config.HTTPClient != nil {
|
||||
client.HTTPClient = config.HTTPClient
|
||||
|
|
Loading…
Reference in a new issue