mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-26 13:43:47 +03:00
ci: Use golangci's github action for linting (#3794)
* ci: Use golangci's github action for linting Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix most of the staticcheck lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the prealloc lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the misspell lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the varcheck lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the errcheck lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the bodyclose lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the deadcode lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the unused lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the gosec lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the gosimple lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the ineffassign lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Fix the staticcheck lint errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Revert the misspell change, use a neutral English Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Remove broken golangci-lint CI job Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Re-add errantly-removed weakrand initialization Signed-off-by: Dave Henderson <dhenderson@gmail.com> * don't break the loop and return * Removing extra handling for null rootKey * unignore RegisterModule/RegisterAdapter Co-authored-by: Mohammed Al Sahaf <msaa1990@gmail.com> * single-line log message Co-authored-by: Matt Holt <mholt@users.noreply.github.com> * Fix lint after a1808b0dbf209c615e438a496d257ce5e3acdce2 was merged Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Revert ticker change, ignore it instead Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Ignore some of the write errors Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Remove blank line Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Use lifetime Signed-off-by: Dave Henderson <dhenderson@gmail.com> * close immediately Co-authored-by: Matt Holt <mholt@users.noreply.github.com> * Preallocate configVals Signed-off-by: Dave Henderson <dhenderson@gmail.com> * Update modules/caddytls/distributedstek/distributedstek.go Co-authored-by: Mohammed Al Sahaf <msaa1990@gmail.com> Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
This commit is contained in:
parent
1e480b818b
commit
bd17eb205d
41 changed files with 256 additions and 199 deletions
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
|
@ -148,20 +148,6 @@ jobs:
|
||||||
env:
|
env:
|
||||||
SSH_KEY: ${{ secrets.S390X_SSH_KEY }}
|
SSH_KEY: ${{ secrets.S390X_SSH_KEY }}
|
||||||
|
|
||||||
# From https://github.com/reviewdog/action-golangci-lint
|
|
||||||
golangci-lint:
|
|
||||||
name: runner / golangci-lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code into the Go module directory
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Run golangci-lint
|
|
||||||
uses: reviewdog/action-golangci-lint@v1
|
|
||||||
# uses: docker://reviewdog/action-golangci-lint:v1 # pre-build docker image
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.github_token }}
|
|
||||||
|
|
||||||
goreleaser-check:
|
goreleaser-check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
23
.github/workflows/lint.yml
vendored
Normal file
23
.github/workflows/lint.yml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
name: Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# From https://github.com/golangci/golangci-lint-action
|
||||||
|
golangci:
|
||||||
|
name: lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: golangci-lint
|
||||||
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
with:
|
||||||
|
version: v1.31
|
||||||
|
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||||
|
# only-new-issues: true
|
|
@ -1,21 +1,68 @@
|
||||||
linters-settings:
|
linters-settings:
|
||||||
errcheck:
|
errcheck:
|
||||||
ignore: fmt:.*,io/ioutil:^Read.*,github.com/caddyserver/caddy/v2/caddyconfig:RegisterAdapter,github.com/caddyserver/caddy/v2:RegisterModule
|
ignore: fmt:.*,io/ioutil:^Read.*,go.uber.org/zap/zapcore:^Add.*
|
||||||
ignoretests: true
|
ignoretests: true
|
||||||
misspell:
|
|
||||||
locale: US
|
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
|
disable-all: true
|
||||||
enable:
|
enable:
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- prealloc
|
- deadcode
|
||||||
- unconvert
|
|
||||||
- errcheck
|
- errcheck
|
||||||
- gofmt
|
- gofmt
|
||||||
- goimports
|
- goimports
|
||||||
- gosec
|
- gosec
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- misspell
|
- misspell
|
||||||
|
- prealloc
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unused
|
||||||
|
- varcheck
|
||||||
|
# these are implicitly disabled:
|
||||||
|
# - asciicheck
|
||||||
|
# - depguard
|
||||||
|
# - dogsled
|
||||||
|
# - dupl
|
||||||
|
# - exhaustive
|
||||||
|
# - exportloopref
|
||||||
|
# - funlen
|
||||||
|
# - gci
|
||||||
|
# - gochecknoglobals
|
||||||
|
# - gochecknoinits
|
||||||
|
# - gocognit
|
||||||
|
# - goconst
|
||||||
|
# - gocritic
|
||||||
|
# - gocyclo
|
||||||
|
# - godot
|
||||||
|
# - godox
|
||||||
|
# - goerr113
|
||||||
|
# - gofumpt
|
||||||
|
# - goheader
|
||||||
|
# - golint
|
||||||
|
# - gomnd
|
||||||
|
# - gomodguard
|
||||||
|
# - goprintffuncname
|
||||||
|
# - interfacer
|
||||||
|
# - lll
|
||||||
|
# - maligned
|
||||||
|
# - nakedret
|
||||||
|
# - nestif
|
||||||
|
# - nlreturn
|
||||||
|
# - noctx
|
||||||
|
# - nolintlint
|
||||||
|
# - rowserrcheck
|
||||||
|
# - scopelint
|
||||||
|
# - sqlclosecheck
|
||||||
|
# - stylecheck
|
||||||
|
# - testpackage
|
||||||
|
# - unparam
|
||||||
|
# - whitespace
|
||||||
|
# - wsl
|
||||||
|
|
||||||
run:
|
run:
|
||||||
# default concurrency is a available CPU number.
|
# default concurrency is a available CPU number.
|
||||||
|
|
7
admin.go
7
admin.go
|
@ -398,7 +398,10 @@ func (h adminHandler) handleError(w http.ResponseWriter, r *http.Request, err er
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(apiErr.Code)
|
w.WriteHeader(apiErr.Code)
|
||||||
json.NewEncoder(w).Encode(apiErr)
|
encErr := json.NewEncoder(w).Encode(apiErr)
|
||||||
|
if encErr != nil {
|
||||||
|
Log().Named("admin.api").Error("failed to encode error response", zap.Error(encErr))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkHost returns a handler that wraps next such that
|
// checkHost returns a handler that wraps next such that
|
||||||
|
@ -838,7 +841,7 @@ var (
|
||||||
// will get deleted before the process gracefully exits.
|
// will get deleted before the process gracefully exits.
|
||||||
func PIDFile(filename string) error {
|
func PIDFile(filename string) error {
|
||||||
pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
|
pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
|
||||||
err := ioutil.WriteFile(filename, pid, 0644)
|
err := ioutil.WriteFile(filename, pid, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,7 +356,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin building the final config values
|
// begin building the final config values
|
||||||
var configVals []ConfigValue
|
configVals := []ConfigValue{}
|
||||||
|
|
||||||
// certificate loaders
|
// certificate loaders
|
||||||
if len(fileLoader) > 0 {
|
if len(fileLoader) > 0 {
|
||||||
|
|
|
@ -124,10 +124,10 @@ func (tc *Tester) initServer(rawConfig string, configType string) error {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
body, _ := ioutil.ReadAll(res.Body)
|
||||||
|
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
json.Indent(&out, body, "", " ")
|
_ = json.Indent(&out, body, "", " ")
|
||||||
tc.t.Logf("----------- failed with config -----------\n%s", out.String())
|
tc.t.Logf("----------- failed with config -----------\n%s", out.String())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -221,10 +221,11 @@ func isCaddyAdminRunning() error {
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Timeout: Default.LoadRequestTimeout,
|
Timeout: Default.LoadRequestTimeout,
|
||||||
}
|
}
|
||||||
_, err := client.Get(fmt.Sprintf("http://localhost:%d/config/", Default.AdminPort))
|
resp, err := client.Get(fmt.Sprintf("http://localhost:%d/config/", Default.AdminPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("caddy integration test caddy server not running. Expected to be listening on localhost:2019")
|
return errors.New("caddy integration test caddy server not running. Expected to be listening on localhost:2019")
|
||||||
}
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -272,7 +273,7 @@ func CreateTestingTransport() *http.Transport {
|
||||||
IdleConnTimeout: 90 * time.Second,
|
IdleConnTimeout: 90 * time.Second,
|
||||||
TLSHandshakeTimeout: 5 * time.Second,
|
TLSHandshakeTimeout: 5 * time.Second,
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ func cmdStart(fl Flags) (int, error) {
|
||||||
// started yet, and writing synchronously would result
|
// started yet, and writing synchronously would result
|
||||||
// in a deadlock
|
// in a deadlock
|
||||||
go func() {
|
go func() {
|
||||||
stdinpipe.Write(expect)
|
_, _ = stdinpipe.Write(expect)
|
||||||
stdinpipe.Close()
|
stdinpipe.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -236,6 +236,7 @@ func watchConfigFile(filename, adapterName string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin poller
|
// begin poller
|
||||||
|
//nolint:staticcheck
|
||||||
for range time.Tick(1 * time.Second) {
|
for range time.Tick(1 * time.Second) {
|
||||||
// get the file info
|
// get the file info
|
||||||
info, err := os.Stat(filename)
|
info, err := os.Stat(filename)
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package caddycmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func gracefullyStopProcess(pid int) error {
|
|
||||||
fmt.Print("Graceful stop... ")
|
|
||||||
err := syscall.Kill(pid, syscall.SIGINT)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("kill: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getProcessName() string {
|
|
||||||
return filepath.Base(os.Args[0])
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package caddycmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
func gracefullyStopProcess(pid int) error {
|
|
||||||
fmt.Print("Forceful stop... ")
|
|
||||||
// process on windows will not stop unless forced with /f
|
|
||||||
cmd := exec.Command("taskkill", "/pid", strconv.Itoa(pid), "/f")
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
return fmt.Errorf("taskkill: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// On Windows the app name passed in os.Args[0] will match how
|
|
||||||
// caddy was started eg will match caddy or caddy.exe.
|
|
||||||
// So return appname with .exe for consistency
|
|
||||||
func getProcessName() string {
|
|
||||||
base := filepath.Base(os.Args[0])
|
|
||||||
if filepath.Ext(base) == "" {
|
|
||||||
return base + ".exe"
|
|
||||||
}
|
|
||||||
return base
|
|
||||||
}
|
|
2
go.sum
2
go.sum
|
@ -354,6 +354,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/libdns/libdns v0.1.0 h1:0ctCOrVJsVzj53mop1angHp/pE3hmAhP7KiHvR0HD04=
|
github.com/libdns/libdns v0.1.0 h1:0ctCOrVJsVzj53mop1angHp/pE3hmAhP7KiHvR0HD04=
|
||||||
github.com/libdns/libdns v0.1.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
github.com/libdns/libdns v0.1.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
|
github.com/lucas-clemente/quic-go v0.19.2 h1:w8BBYUx5Z+kNpeaOeQW/KzcNsKWhh4O6PeQhb0nURPg=
|
||||||
|
github.com/lucas-clemente/quic-go v0.19.2/go.mod h1:ZUygOqIoai0ASXXLJ92LTnKdbqh9MHCLTX6Nr1jUrK0=
|
||||||
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
|
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
|
||||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||||
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
|
|
@ -129,9 +129,9 @@ func (fcl *fakeCloseListener) Accept() (net.Conn, error) {
|
||||||
if *fcl.deadline {
|
if *fcl.deadline {
|
||||||
switch ln := fcl.Listener.(type) {
|
switch ln := fcl.Listener.(type) {
|
||||||
case *net.TCPListener:
|
case *net.TCPListener:
|
||||||
ln.SetDeadline(time.Time{})
|
_ = ln.SetDeadline(time.Time{})
|
||||||
case *net.UnixListener:
|
case *net.UnixListener:
|
||||||
ln.SetDeadline(time.Time{})
|
_ = ln.SetDeadline(time.Time{})
|
||||||
}
|
}
|
||||||
*fcl.deadline = false
|
*fcl.deadline = false
|
||||||
}
|
}
|
||||||
|
@ -167,9 +167,9 @@ func (fcl *fakeCloseListener) Close() error {
|
||||||
if !*fcl.deadline {
|
if !*fcl.deadline {
|
||||||
switch ln := fcl.Listener.(type) {
|
switch ln := fcl.Listener.(type) {
|
||||||
case *net.TCPListener:
|
case *net.TCPListener:
|
||||||
ln.SetDeadline(time.Now().Add(-1 * time.Minute))
|
_ = ln.SetDeadline(time.Now().Add(-1 * time.Minute))
|
||||||
case *net.UnixListener:
|
case *net.UnixListener:
|
||||||
ln.SetDeadline(time.Now().Add(-1 * time.Minute))
|
_ = ln.SetDeadline(time.Now().Add(-1 * time.Minute))
|
||||||
}
|
}
|
||||||
*fcl.deadline = true
|
*fcl.deadline = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -458,7 +458,7 @@ func (cl *CustomLog) buildCore() {
|
||||||
if cl.Sampling.Thereafter == 0 {
|
if cl.Sampling.Thereafter == 0 {
|
||||||
cl.Sampling.Thereafter = 100
|
cl.Sampling.Thereafter = 100
|
||||||
}
|
}
|
||||||
c = zapcore.NewSampler(c, cl.Sampling.Interval,
|
c = zapcore.NewSamplerWithOptions(c, cl.Sampling.Interval,
|
||||||
cl.Sampling.First, cl.Sampling.Thereafter)
|
cl.Sampling.First, cl.Sampling.Thereafter)
|
||||||
}
|
}
|
||||||
cl.core = c
|
cl.core = c
|
||||||
|
|
|
@ -363,6 +363,7 @@ func (app *App) Start() error {
|
||||||
ErrorLog: serverLogger,
|
ErrorLog: serverLogger,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
//nolint:errcheck
|
||||||
go h3srv.Serve(h3ln)
|
go h3srv.Serve(h3ln)
|
||||||
app.h3servers = append(app.h3servers, h3srv)
|
app.h3servers = append(app.h3servers, h3srv)
|
||||||
app.h3listeners = append(app.h3listeners, h3ln)
|
app.h3listeners = append(app.h3listeners, h3ln)
|
||||||
|
@ -391,6 +392,7 @@ func (app *App) Start() error {
|
||||||
zap.Bool("tls", useTLS),
|
zap.Bool("tls", useTLS),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:errcheck
|
||||||
go s.Serve(ln)
|
go s.Serve(ln)
|
||||||
app.servers = append(app.servers, s)
|
app.servers = append(app.servers, s)
|
||||||
}
|
}
|
||||||
|
|
|
@ -523,7 +523,10 @@ func (app *App) createAutomationPolicies(ctx caddy.Context, internalNames []stri
|
||||||
// our base/catch-all policy - this will serve the
|
// our base/catch-all policy - this will serve the
|
||||||
// public-looking names as well as any other names
|
// public-looking names as well as any other names
|
||||||
// that don't match any other policy
|
// that don't match any other policy
|
||||||
app.tlsApp.AddAutomationPolicy(basePolicy)
|
err := app.tlsApp.AddAutomationPolicy(basePolicy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// a base policy already existed; we might have
|
// a base policy already existed; we might have
|
||||||
// changed it, so re-provision it
|
// changed it, so re-provision it
|
||||||
|
|
|
@ -240,6 +240,7 @@ func (c *Cache) makeRoom() {
|
||||||
// map with less code, this is a heavily skewed eviction
|
// map with less code, this is a heavily skewed eviction
|
||||||
// strategy; generating random numbers is cheap and
|
// strategy; generating random numbers is cheap and
|
||||||
// ensures a much better distribution.
|
// ensures a much better distribution.
|
||||||
|
//nolint:gosec
|
||||||
rnd := weakrand.Intn(len(c.cache))
|
rnd := weakrand.Intn(len(c.cache))
|
||||||
i := 0
|
i := 0
|
||||||
for key := range c.cache {
|
for key := range c.cache {
|
||||||
|
|
|
@ -18,18 +18,14 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
weakrand "math/rand"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
weakrand.Seed(time.Now().UnixNano())
|
|
||||||
|
|
||||||
caddy.RegisterModule(tlsPlaceholderWrapper{})
|
caddy.RegisterModule(tlsPlaceholderWrapper{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ func acceptedEncodings(r *http.Request) []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var prefs []encodingPreference
|
prefs := []encodingPreference{}
|
||||||
|
|
||||||
for _, accepted := range strings.Split(acceptEncHeader, ",") {
|
for _, accepted := range strings.Split(acceptEncHeader, ",") {
|
||||||
parts := strings.Split(accepted, ";")
|
parts := strings.Split(accepted, ";")
|
||||||
|
|
|
@ -16,14 +16,19 @@ package caddyhttp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
mathrand "math/rand"
|
weakrand "math/rand"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
weakrand.Seed(time.Now().UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
// Error is a convenient way for a Handler to populate the
|
// Error is a convenient way for a Handler to populate the
|
||||||
// essential fields of a HandlerError. If err is itself a
|
// essential fields of a HandlerError. If err is itself a
|
||||||
// HandlerError, then any essential fields that are not
|
// HandlerError, then any essential fields that are not
|
||||||
|
@ -92,7 +97,8 @@ func randString(n int, sameCase bool) string {
|
||||||
}
|
}
|
||||||
b := make([]byte, n)
|
b := make([]byte, n)
|
||||||
for i := range b {
|
for i := range b {
|
||||||
b[i] = dict[mathrand.Int63()%int64(len(dict))]
|
//nolint:gosec
|
||||||
|
b[i] = dict[weakrand.Int63()%int64(len(dict))]
|
||||||
}
|
}
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ func (fsrv *FileServer) serveBrowse(dirPath string, w http.ResponseWriter, r *ht
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteTo(w)
|
_, _ = buf.WriteTo(w)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,8 @@ import (
|
||||||
func (fsrv *FileServer) directoryListing(files []os.FileInfo, canGoUp bool, urlPath string, repl *caddy.Replacer) browseListing {
|
func (fsrv *FileServer) directoryListing(files []os.FileInfo, canGoUp bool, urlPath string, repl *caddy.Replacer) browseListing {
|
||||||
filesToHide := fsrv.transformHidePaths(repl)
|
filesToHide := fsrv.transformHidePaths(repl)
|
||||||
|
|
||||||
var (
|
var dirCount, fileCount int
|
||||||
fileInfos []fileInfo
|
fileInfos := []fileInfo{}
|
||||||
dirCount, fileCount int
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
name := f.Name()
|
name := f.Name()
|
||||||
|
@ -109,10 +107,8 @@ type browseListing struct {
|
||||||
// Breadcrumbs returns l.Path where every element maps
|
// Breadcrumbs returns l.Path where every element maps
|
||||||
// the link to the text to display.
|
// the link to the text to display.
|
||||||
func (l browseListing) Breadcrumbs() []crumb {
|
func (l browseListing) Breadcrumbs() []crumb {
|
||||||
var result []crumb
|
|
||||||
|
|
||||||
if len(l.Path) == 0 {
|
if len(l.Path) == 0 {
|
||||||
return result
|
return []crumb{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip trailing slash
|
// skip trailing slash
|
||||||
|
@ -122,13 +118,13 @@ func (l browseListing) Breadcrumbs() []crumb {
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.Split(lpath, "/")
|
parts := strings.Split(lpath, "/")
|
||||||
for i := range parts {
|
result := make([]crumb, len(parts))
|
||||||
txt := parts[i]
|
for i, p := range parts {
|
||||||
if i == 0 && parts[i] == "" {
|
if i == 0 && p == "" {
|
||||||
txt = "/"
|
p = "/"
|
||||||
}
|
}
|
||||||
lnk := strings.Repeat("../", len(parts)-i-1)
|
lnk := strings.Repeat("../", len(parts)-i-1)
|
||||||
result = append(result, crumb{Link: lnk, Text: txt})
|
result[i] = crumb{Link: lnk, Text: p}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
40
modules/caddyhttp/fileserver/browselisting_test.go
Normal file
40
modules/caddyhttp/fileserver/browselisting_test.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package fileserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBreadcrumbs(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
path string
|
||||||
|
expected []crumb
|
||||||
|
}{
|
||||||
|
{"", []crumb{}},
|
||||||
|
{"/", []crumb{{Text: "/"}}},
|
||||||
|
{"foo/bar/baz", []crumb{
|
||||||
|
{Link: "../../", Text: "foo"},
|
||||||
|
{Link: "../", Text: "bar"},
|
||||||
|
{Link: "", Text: "baz"},
|
||||||
|
}},
|
||||||
|
{"/qux/quux/corge/", []crumb{
|
||||||
|
{Link: "../../../", Text: "/"},
|
||||||
|
{Link: "../../", Text: "qux"},
|
||||||
|
{Link: "../", Text: "quux"},
|
||||||
|
{Link: "", Text: "corge"},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range testdata {
|
||||||
|
l := browseListing{Path: d.path}
|
||||||
|
actual := l.Breadcrumbs()
|
||||||
|
if len(actual) != len(d.expected) {
|
||||||
|
t.Errorf("wrong size output, got %d elements but expected %d", len(actual), len(d.expected))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i, c := range actual {
|
||||||
|
if c != d.expected[i] {
|
||||||
|
t.Errorf("got %#v but expected %#v at index %d", c, d.expected[i], i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -249,7 +249,7 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
|
||||||
}
|
}
|
||||||
w.WriteHeader(statusCode)
|
w.WriteHeader(statusCode)
|
||||||
if r.Method != http.MethodHead {
|
if r.Method != http.MethodHead {
|
||||||
io.Copy(w, file)
|
_, _ = io.Copy(w, file)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -278,6 +278,7 @@ func (fsrv *FileServer) openFile(filename string, w http.ResponseWriter) (*os.Fi
|
||||||
}
|
}
|
||||||
// maybe the server is under load and ran out of file descriptors?
|
// maybe the server is under load and ran out of file descriptors?
|
||||||
// have client wait arbitrary seconds to help prevent a stampede
|
// have client wait arbitrary seconds to help prevent a stampede
|
||||||
|
//nolint:gosec
|
||||||
backoff := weakrand.Intn(maxBackoff-minBackoff) + minBackoff
|
backoff := weakrand.Intn(maxBackoff-minBackoff) + minBackoff
|
||||||
w.Header().Set("Retry-After", strconv.Itoa(backoff))
|
w.Header().Set("Retry-After", strconv.Itoa(backoff))
|
||||||
return nil, caddyhttp.Error(http.StatusServiceUnavailable, err)
|
return nil, caddyhttp.Error(http.StatusServiceUnavailable, err)
|
||||||
|
|
|
@ -75,7 +75,8 @@ func (t LoggableTLSConnState) MarshalLogObject(enc zapcore.ObjectEncoder) error
|
||||||
enc.AddUint16("version", t.Version)
|
enc.AddUint16("version", t.Version)
|
||||||
enc.AddUint16("cipher_suite", t.CipherSuite)
|
enc.AddUint16("cipher_suite", t.CipherSuite)
|
||||||
enc.AddString("proto", t.NegotiatedProtocol)
|
enc.AddString("proto", t.NegotiatedProtocol)
|
||||||
enc.AddBool("proto_mutual", t.NegotiatedProtocolIsMutual)
|
// NegotiatedProtocolIsMutual is deprecated - it's always true
|
||||||
|
enc.AddBool("proto_mutual", true)
|
||||||
enc.AddString("server_name", t.ServerName)
|
enc.AddString("server_name", t.ServerName)
|
||||||
if len(t.PeerCertificates) > 0 {
|
if len(t.PeerCertificates) > 0 {
|
||||||
enc.AddString("client_common_name", t.PeerCertificates[0].Subject.CommonName)
|
enc.AddString("client_common_name", t.PeerCertificates[0].Subject.CommonName)
|
||||||
|
|
|
@ -362,7 +362,8 @@ func getReqTLSReplacement(req *http.Request, key string) (interface{}, bool) {
|
||||||
case "proto":
|
case "proto":
|
||||||
return req.TLS.NegotiatedProtocol, true
|
return req.TLS.NegotiatedProtocol, true
|
||||||
case "proto_mutual":
|
case "proto_mutual":
|
||||||
return req.TLS.NegotiatedProtocolIsMutual, true
|
// req.TLS.NegotiatedProtocolIsMutual is deprecated - it's always true.
|
||||||
|
return true, true
|
||||||
case "server_name":
|
case "server_name":
|
||||||
return req.TLS.ServerName, true
|
return req.TLS.ServerName, true
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,13 +242,6 @@ func (c *FCGIClient) writeBeginRequest(role uint16, flags uint8) error {
|
||||||
return c.writeRecord(BeginRequest, b[:])
|
return c.writeRecord(BeginRequest, b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FCGIClient) writeEndRequest(appStatus int, protocolStatus uint8) error {
|
|
||||||
b := make([]byte, 8)
|
|
||||||
binary.BigEndian.PutUint32(b, uint32(appStatus))
|
|
||||||
b[4] = protocolStatus
|
|
||||||
return c.writeRecord(EndRequest, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *FCGIClient) writePairs(recType uint8, pairs map[string]string) error {
|
func (c *FCGIClient) writePairs(recType uint8, pairs map[string]string) error {
|
||||||
w := newWriter(c, recType)
|
w := newWriter(c, recType)
|
||||||
b := make([]byte, 8)
|
b := make([]byte, 8)
|
||||||
|
|
|
@ -263,7 +263,7 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, host H
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
// drain any remaining body so connection could be re-used
|
// drain any remaining body so connection could be re-used
|
||||||
io.Copy(ioutil.Discard, body)
|
_, _ = io.Copy(ioutil.Discard, body)
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,7 @@ func (h *HTTPTransport) NewTransport(ctx caddy.Context) (*http.Transport, error)
|
||||||
dialer.Resolver = &net.Resolver{
|
dialer.Resolver = &net.Resolver{
|
||||||
PreferGo: true,
|
PreferGo: true,
|
||||||
Dial: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
Dial: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||||
|
//nolint:gosec
|
||||||
addr := h.Resolver.netAddrs[weakrand.Intn(len(h.Resolver.netAddrs))]
|
addr := h.Resolver.netAddrs[weakrand.Intn(len(h.Resolver.netAddrs))]
|
||||||
return d.DialContext(ctx, addr.Network, addr.JoinHostPort(0))
|
return d.DialContext(ctx, addr.Network, addr.JoinHostPort(0))
|
||||||
},
|
},
|
||||||
|
|
|
@ -314,7 +314,7 @@ func (h *Handler) Cleanup() error {
|
||||||
|
|
||||||
// remove hosts from our config from the pool
|
// remove hosts from our config from the pool
|
||||||
for _, upstream := range h.Upstreams {
|
for _, upstream := range h.Upstreams {
|
||||||
hosts.Delete(upstream.String())
|
_, _ = hosts.Delete(upstream.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -339,7 +339,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
|
||||||
buf := bufPool.Get().(*bytes.Buffer)
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
defer bufPool.Put(buf)
|
defer bufPool.Put(buf)
|
||||||
io.Copy(buf, r.Body)
|
_, _ = io.Copy(buf, r.Body)
|
||||||
r.Body.Close()
|
r.Body.Close()
|
||||||
r.Body = ioutil.NopCloser(buf)
|
r.Body = ioutil.NopCloser(buf)
|
||||||
}
|
}
|
||||||
|
@ -518,7 +518,8 @@ func (h Handler) prepareRequest(req *http.Request) error {
|
||||||
// (This method is mostly the beginning of what was borrowed from the net/http/httputil package in the
|
// (This method is mostly the beginning of what was borrowed from the net/http/httputil package in the
|
||||||
// Go standard library which was used as the foundation.)
|
// Go standard library which was used as the foundation.)
|
||||||
func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, di DialInfo, next caddyhttp.Handler) error {
|
func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, di DialInfo, next caddyhttp.Handler) error {
|
||||||
di.Upstream.Host.CountRequest(1)
|
_ = di.Upstream.Host.CountRequest(1)
|
||||||
|
//nolint:errcheck
|
||||||
defer di.Upstream.Host.CountRequest(-1)
|
defer di.Upstream.Host.CountRequest(-1)
|
||||||
|
|
||||||
// point the request to this upstream
|
// point the request to this upstream
|
||||||
|
@ -742,16 +743,6 @@ func copyHeader(dst, src http.Header) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cloneHeader(h http.Header) http.Header {
|
|
||||||
h2 := make(http.Header, len(h))
|
|
||||||
for k, vv := range h {
|
|
||||||
vv2 := make([]string, len(vv))
|
|
||||||
copy(vv2, vv)
|
|
||||||
h2[k] = vv2
|
|
||||||
}
|
|
||||||
return h2
|
|
||||||
}
|
|
||||||
|
|
||||||
func upgradeType(h http.Header) string {
|
func upgradeType(h http.Header) string {
|
||||||
if !httpguts.HeaderValuesContainsToken(h["Connection"], "Upgrade") {
|
if !httpguts.HeaderValuesContainsToken(h["Connection"], "Upgrade") {
|
||||||
return ""
|
return ""
|
||||||
|
@ -759,18 +750,6 @@ func upgradeType(h http.Header) string {
|
||||||
return strings.ToLower(h.Get("Upgrade"))
|
return strings.ToLower(h.Get("Upgrade"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func singleJoiningSlash(a, b string) string {
|
|
||||||
aslash := strings.HasSuffix(a, "/")
|
|
||||||
bslash := strings.HasPrefix(b, "/")
|
|
||||||
switch {
|
|
||||||
case aslash && bslash:
|
|
||||||
return a + b[1:]
|
|
||||||
case !aslash && !bslash:
|
|
||||||
return a + "/" + b
|
|
||||||
}
|
|
||||||
return a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
// removeConnectionHeaders removes hop-by-hop headers listed in the "Connection" header of h.
|
// removeConnectionHeaders removes hop-by-hop headers listed in the "Connection" header of h.
|
||||||
// See RFC 7230, section 6.1
|
// See RFC 7230, section 6.1
|
||||||
func removeConnectionHeaders(h http.Header) {
|
func removeConnectionHeaders(h http.Header) {
|
||||||
|
|
|
@ -536,7 +536,7 @@ func hostByHashing(pool []*Upstream, s string) *Upstream {
|
||||||
// hash calculates a fast hash based on s.
|
// hash calculates a fast hash based on s.
|
||||||
func hash(s string) uint32 {
|
func hash(s string) uint32 {
|
||||||
h := fnv.New32a()
|
h := fnv.New32a()
|
||||||
h.Write([]byte(s))
|
_, _ = h.Write([]byte(s))
|
||||||
return h.Sum32()
|
return h.Sum32()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,9 +138,9 @@ func (h Handler) copyResponse(dst io.Writer, src io.Reader, flushInterval time.D
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := streamingBufPool.Get().([]byte)
|
buf := streamingBufPool.Get().(*[]byte)
|
||||||
defer streamingBufPool.Put(buf)
|
defer streamingBufPool.Put(buf)
|
||||||
_, err := h.copyBuffer(dst, src, buf)
|
_, err := h.copyBuffer(dst, src, *buf)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +255,12 @@ func (c switchProtocolCopier) copyToBackend(errc chan<- error) {
|
||||||
|
|
||||||
var streamingBufPool = sync.Pool{
|
var streamingBufPool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
return make([]byte, defaultBufferSize)
|
// The Pool's New function should generally only return pointer
|
||||||
|
// types, since a pointer can be put into the return interface
|
||||||
|
// value without an allocation
|
||||||
|
// - (from the package docs)
|
||||||
|
b := make([]byte, defaultBufferSize)
|
||||||
|
return &b
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
30
modules/caddyhttp/reverseproxy/streaming_test.go
Normal file
30
modules/caddyhttp/reverseproxy/streaming_test.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package reverseproxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHandlerCopyResponse(t *testing.T) {
|
||||||
|
h := Handler{}
|
||||||
|
testdata := []string{
|
||||||
|
"",
|
||||||
|
strings.Repeat("a", defaultBufferSize),
|
||||||
|
strings.Repeat("123456789 123456789 123456789 12", 3000),
|
||||||
|
}
|
||||||
|
dst := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
for _, d := range testdata {
|
||||||
|
src := bytes.NewBuffer([]byte(d))
|
||||||
|
dst.Reset()
|
||||||
|
err := h.copyResponse(dst, src, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed with error: %v", err)
|
||||||
|
}
|
||||||
|
out := dst.String()
|
||||||
|
if out != d {
|
||||||
|
t.Errorf("bad read: got %q", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -270,7 +270,10 @@ func (templateContext) funcMarkdown(input interface{}) (string, error) {
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
defer bufPool.Put(buf)
|
defer bufPool.Put(buf)
|
||||||
|
|
||||||
md.Convert([]byte(inputStr), buf)
|
err := md.Convert([]byte(inputStr), buf)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,11 +132,11 @@ func (ash *Handler) Provision(ctx caddy.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
acmeAuth, err := acme.NewAuthority(
|
acmeAuth, err := acme.New(auth, acme.AuthorityOptions{
|
||||||
auth.GetDatabase().(nosql.DB), // stores all the server state
|
DB: auth.GetDatabase().(nosql.DB), // stores all the server state
|
||||||
ash.Host, // used for directory links; TODO: not needed
|
DNS: ash.Host, // used for directory links; TODO: not needed
|
||||||
strings.Trim(ash.PathPrefix, "/"), // used for directory links
|
Prefix: strings.Trim(ash.PathPrefix, "/"), // used for directory links
|
||||||
auth) // configures the signing authority
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -309,14 +309,6 @@ func (ca CA) loadOrGenIntermediate(rootCert *x509.Certificate, rootKey interface
|
||||||
func (ca CA) genIntermediate(rootCert *x509.Certificate, rootKey interface{}) (interCert *x509.Certificate, interKey interface{}, err error) {
|
func (ca CA) genIntermediate(rootCert *x509.Certificate, rootKey interface{}) (interCert *x509.Certificate, interKey interface{}, err error) {
|
||||||
repl := ca.newReplacer()
|
repl := ca.newReplacer()
|
||||||
|
|
||||||
rootKeyPEM, err := ca.storage.Load(ca.storageKeyRootKey())
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("loading root key to sign new intermediate: %v", err)
|
|
||||||
}
|
|
||||||
rootKey, err = pemDecodePrivateKey(rootKeyPEM)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("decoding root key: %v", err)
|
|
||||||
}
|
|
||||||
interCert, interKey, err = generateIntermediate(repl.ReplaceAll(ca.IntermediateCommonName, ""), rootCert, rootKey)
|
interCert, interKey, err = generateIntermediate(repl.ReplaceAll(ca.IntermediateCommonName, ""), rootCert, rootKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("generating CA intermediate: %v", err)
|
return nil, nil, fmt.Errorf("generating CA intermediate: %v", err)
|
||||||
|
|
|
@ -80,6 +80,7 @@ func (cp ConnectionPolicies) TLSConfig(ctx caddy.Context) *tls.Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &tls.Config{
|
return &tls.Config{
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
GetConfigForClient: func(hello *tls.ClientHelloInfo) (*tls.Config, error) {
|
GetConfigForClient: func(hello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||||
// filter policies by SNI first, if possible, to speed things up
|
// filter policies by SNI first, if possible, to speed things up
|
||||||
// when there may be lots of policies
|
// when there may be lots of policies
|
||||||
|
|
|
@ -145,7 +145,12 @@ func (s *Provider) storeSTEK(dstek distributedSTEK) error {
|
||||||
// current STEK is outdated (NextRotation time is in the past),
|
// current STEK is outdated (NextRotation time is in the past),
|
||||||
// then it is rotated and persisted. The resulting STEK is returned.
|
// then it is rotated and persisted. The resulting STEK is returned.
|
||||||
func (s *Provider) getSTEK() (distributedSTEK, error) {
|
func (s *Provider) getSTEK() (distributedSTEK, error) {
|
||||||
s.storage.Lock(s.ctx, stekLockName)
|
err := s.storage.Lock(s.ctx, stekLockName)
|
||||||
|
if err != nil {
|
||||||
|
return distributedSTEK{}, fmt.Errorf("failed to acquire storage lock: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:errcheck
|
||||||
defer s.storage.Unlock(stekLockName)
|
defer s.storage.Unlock(stekLockName)
|
||||||
|
|
||||||
// load the current STEKs from storage
|
// load the current STEKs from storage
|
||||||
|
|
|
@ -97,26 +97,38 @@ func x509CertFromCertAndKeyPEMFile(fpath string) (tls.Certificate, error) {
|
||||||
|
|
||||||
if derBlock.Type == "CERTIFICATE" {
|
if derBlock.Type == "CERTIFICATE" {
|
||||||
// Re-encode certificate as PEM, appending to certificate chain
|
// Re-encode certificate as PEM, appending to certificate chain
|
||||||
pem.Encode(certBuilder, derBlock)
|
err = pem.Encode(certBuilder, derBlock)
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, err
|
||||||
|
}
|
||||||
} else if derBlock.Type == "EC PARAMETERS" {
|
} else if derBlock.Type == "EC PARAMETERS" {
|
||||||
// EC keys generated from openssl can be composed of two blocks:
|
// EC keys generated from openssl can be composed of two blocks:
|
||||||
// parameters and key (parameter block should come first)
|
// parameters and key (parameter block should come first)
|
||||||
if !foundKey {
|
if !foundKey {
|
||||||
// Encode parameters
|
// Encode parameters
|
||||||
pem.Encode(keyBuilder, derBlock)
|
err = pem.Encode(keyBuilder, derBlock)
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, err
|
||||||
|
}
|
||||||
|
|
||||||
// Key must immediately follow
|
// Key must immediately follow
|
||||||
derBlock, bundle = pem.Decode(bundle)
|
derBlock, bundle = pem.Decode(bundle)
|
||||||
if derBlock == nil || derBlock.Type != "EC PRIVATE KEY" {
|
if derBlock == nil || derBlock.Type != "EC PRIVATE KEY" {
|
||||||
return tls.Certificate{}, fmt.Errorf("%s: expected elliptic private key to immediately follow EC parameters", fpath)
|
return tls.Certificate{}, fmt.Errorf("%s: expected elliptic private key to immediately follow EC parameters", fpath)
|
||||||
}
|
}
|
||||||
pem.Encode(keyBuilder, derBlock)
|
err = pem.Encode(keyBuilder, derBlock)
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, err
|
||||||
|
}
|
||||||
foundKey = true
|
foundKey = true
|
||||||
}
|
}
|
||||||
} else if derBlock.Type == "PRIVATE KEY" || strings.HasSuffix(derBlock.Type, " PRIVATE KEY") {
|
} else if derBlock.Type == "PRIVATE KEY" || strings.HasSuffix(derBlock.Type, " PRIVATE KEY") {
|
||||||
// RSA key
|
// RSA key
|
||||||
if !foundKey {
|
if !foundKey {
|
||||||
pem.Encode(keyBuilder, derBlock)
|
err = pem.Encode(keyBuilder, derBlock)
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, err
|
||||||
|
}
|
||||||
foundKey = true
|
foundKey = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/caddyserver/caddy/v2/modules/caddypki"
|
"github.com/caddyserver/caddy/v2/modules/caddypki"
|
||||||
"github.com/caddyserver/certmagic"
|
"github.com/caddyserver/certmagic"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -51,7 +52,8 @@ type InternalIssuer struct {
|
||||||
// validate certificate chains.
|
// validate certificate chains.
|
||||||
SignWithRoot bool `json:"sign_with_root,omitempty"`
|
SignWithRoot bool `json:"sign_with_root,omitempty"`
|
||||||
|
|
||||||
ca *caddypki.CA
|
ca *caddypki.CA
|
||||||
|
logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaddyModule returns the Caddy module information.
|
// CaddyModule returns the Caddy module information.
|
||||||
|
@ -64,6 +66,8 @@ func (InternalIssuer) CaddyModule() caddy.ModuleInfo {
|
||||||
|
|
||||||
// Provision sets up the issuer.
|
// Provision sets up the issuer.
|
||||||
func (iss *InternalIssuer) Provision(ctx caddy.Context) error {
|
func (iss *InternalIssuer) Provision(ctx caddy.Context) error {
|
||||||
|
iss.logger = ctx.Logger(iss)
|
||||||
|
|
||||||
// get a reference to the configured CA
|
// get a reference to the configured CA
|
||||||
appModule, err := ctx.App("pki")
|
appModule, err := ctx.App("pki")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -115,11 +119,15 @@ func (iss InternalIssuer) Issue(ctx context.Context, csr *x509.CertificateReques
|
||||||
// ensure issued certificate does not expire later than its issuer
|
// ensure issued certificate does not expire later than its issuer
|
||||||
lifetime := time.Duration(iss.Lifetime)
|
lifetime := time.Duration(iss.Lifetime)
|
||||||
if time.Now().Add(lifetime).After(issuerCert.NotAfter) {
|
if time.Now().Add(lifetime).After(issuerCert.NotAfter) {
|
||||||
// TODO: log this
|
lifetime = time.Until(issuerCert.NotAfter)
|
||||||
lifetime = issuerCert.NotAfter.Sub(time.Now())
|
iss.logger.Warn("cert lifetime would exceed issuer NotAfter, clamping lifetime",
|
||||||
|
zap.Duration("orig_lifetime", time.Duration(iss.Lifetime)),
|
||||||
|
zap.Duration("lifetime", lifetime),
|
||||||
|
zap.Time("not_after", issuerCert.NotAfter),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
certChain, err := auth.Sign(csr, provisioner.SignOptions{}, customCertLifetime(iss.Lifetime))
|
certChain, err := auth.Sign(csr, provisioner.SignOptions{}, customCertLifetime(caddy.Duration(lifetime)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -498,8 +498,6 @@ var (
|
||||||
storageCleanMu sync.Mutex
|
storageCleanMu sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
const automateKey = "automate"
|
|
||||||
|
|
||||||
// Interface guards
|
// Interface guards
|
||||||
var (
|
var (
|
||||||
_ caddy.App = (*TLS)(nil)
|
_ caddy.App = (*TLS)(nil)
|
||||||
|
|
|
@ -122,6 +122,7 @@ var SupportedProtocols = map[string]uint16{
|
||||||
// unsupportedProtocols is a map of unsupported protocols.
|
// unsupportedProtocols is a map of unsupported protocols.
|
||||||
// Used for logging only, not enforcement.
|
// Used for logging only, not enforcement.
|
||||||
var unsupportedProtocols = map[string]uint16{
|
var unsupportedProtocols = map[string]uint16{
|
||||||
|
//nolint:staticcheck
|
||||||
"ssl3.0": tls.VersionSSL30,
|
"ssl3.0": tls.VersionSSL30,
|
||||||
"tls1.0": tls.VersionTLS10,
|
"tls1.0": tls.VersionTLS10,
|
||||||
"tls1.1": tls.VersionTLS11,
|
"tls1.1": tls.VersionTLS11,
|
||||||
|
|
Loading…
Reference in a new issue