Compare commits
No commits in common. "master" and "0.1.0" have entirely different histories.
157
.drone.yml
157
.drone.yml
@ -1,70 +1,89 @@
|
|||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
type: docker
|
type: docker
|
||||||
name: build-linux
|
name: cleanup-before
|
||||||
|
|
||||||
environment:
|
|
||||||
GOOS: linux
|
|
||||||
GOOPTIONS: -mod=vendor
|
|
||||||
SRCFILES: cmd/pki/*.go
|
|
||||||
PROJECTNAME: pki
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build-linux-amd64
|
- name: clean
|
||||||
image: golang
|
image: alpine
|
||||||
commands:
|
commands:
|
||||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
- rm -rf /build/*
|
||||||
environment:
|
volumes:
|
||||||
GOARCH: amd64
|
- name: build
|
||||||
|
path: /build
|
||||||
when:
|
when:
|
||||||
event:
|
event: tag
|
||||||
exclude:
|
|
||||||
- tag
|
volumes:
|
||||||
- name: build-linux-arm64
|
- name: build
|
||||||
image: golang
|
host:
|
||||||
commands:
|
path: /tmp/pki/build
|
||||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
|
||||||
environment:
|
|
||||||
GOARCH: arm64
|
|
||||||
when:
|
|
||||||
event:
|
|
||||||
exclude:
|
|
||||||
- tag
|
|
||||||
|
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
type: docker
|
type: docker
|
||||||
name: gitea-release-linux
|
name: default-linux-amd64
|
||||||
|
|
||||||
environment:
|
|
||||||
GOOS: linux
|
|
||||||
GOOPTIONS: -mod=vendor
|
|
||||||
SRCFILES: cmd/pki/*.go
|
|
||||||
PROJECTNAME: pki
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build-linux-amd64
|
- name: build
|
||||||
image: golang
|
image: golang
|
||||||
commands:
|
commands:
|
||||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
- ./ci-build.sh build
|
||||||
- tar -czvf $PROJECTNAME-$DRONE_TAG-$GOOS-$GOARCH.tar.gz $PROJECTNAME
|
|
||||||
- echo $PROJECTNAME $DRONE_TAG > VERSION
|
|
||||||
environment:
|
environment:
|
||||||
|
GOOS: linux
|
||||||
GOARCH: amd64
|
GOARCH: amd64
|
||||||
when:
|
volumes:
|
||||||
event:
|
- name: build
|
||||||
- tag
|
path: /build
|
||||||
- name: build-linux-arm64
|
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
host:
|
||||||
|
path: /tmp/pki/build
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- cleanup-before
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: default-linux-arm64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build
|
||||||
image: golang
|
image: golang
|
||||||
commands:
|
commands:
|
||||||
- go build -o $PROJECTNAME $GOOPTIONS $SRCFILES
|
- ./ci-build.sh build
|
||||||
- tar -czvf $PROJECTNAME-$DRONE_TAG-$GOOS-$GOARCH.tar.gz $PROJECTNAME
|
|
||||||
- echo $PROJECTNAME $DRONE_TAG > VERSION
|
|
||||||
environment:
|
environment:
|
||||||
|
GOOS: linux
|
||||||
GOARCH: arm64
|
GOARCH: arm64
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /build
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
host:
|
||||||
|
path: /tmp/pki/build
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- cleanup-before
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: gitea-release
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: move
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- mv build/* ./
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /drone/src/build
|
||||||
when:
|
when:
|
||||||
event:
|
event: tag
|
||||||
- tag
|
|
||||||
- name: release
|
- name: release
|
||||||
image: plugins/gitea-release
|
image: plugins/gitea-release
|
||||||
settings:
|
settings:
|
||||||
@ -76,6 +95,50 @@ steps:
|
|||||||
- sha256
|
- sha256
|
||||||
- sha512
|
- sha512
|
||||||
title: VERSION
|
title: VERSION
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /drone/src/build
|
||||||
when:
|
when:
|
||||||
event:
|
event: tag
|
||||||
- tag
|
- name: ls
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- find .
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /drone/src/build
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
host:
|
||||||
|
path: /tmp/pki/build
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- default-linux-amd64
|
||||||
|
- default-linux-arm64
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: cleanup-after
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: clean
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- rm -rf /build/*
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /build
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
host:
|
||||||
|
path: /tmp/pki/build
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- gitea-release
|
||||||
|
18
Makefile
Normal file
18
Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# pki Makefile
|
||||||
|
|
||||||
|
GOCMD=go
|
||||||
|
GOBUILDCMD=${GOCMD} build
|
||||||
|
GOOPTIONS=-mod=vendor -ldflags="-s -w"
|
||||||
|
|
||||||
|
RMCMD=rm
|
||||||
|
BINNAME=pki
|
||||||
|
|
||||||
|
SRCFILES=cmd/pki/*.go
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
build:
|
||||||
|
${GOBUILDCMD} ${GOOPTIONS} ${SRCFILES}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
${RMCMD} -f ${BINNAME}
|
@ -10,7 +10,7 @@ PKI is a centralized Letsencrypt database server and renewer for certificate man
|
|||||||
### Build
|
### Build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go build cmd/pki/pki.go
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
### Sample config in pki.ini
|
### Sample config in pki.ini
|
||||||
@ -40,7 +40,7 @@ ovhck=
|
|||||||
## License
|
## License
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Copyright (c) 2020, 2021, 2022 PaulBSD
|
Copyright (c) 2020 PaulBSD
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
60
ci-build.sh
Executable file
60
ci-build.sh
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PROJECTNAME=pki
|
||||||
|
RELEASENAME=${PROJECTNAME}
|
||||||
|
VERSION="0"
|
||||||
|
|
||||||
|
GOOPTIONS="-mod=vendor"
|
||||||
|
SRCFILES=cmd/pki/*.go
|
||||||
|
|
||||||
|
build() {
|
||||||
|
echo "Begin of build"
|
||||||
|
if [[ ! -z $DRONE_TAG ]]
|
||||||
|
then
|
||||||
|
echo "Drone tag set, let's do a release"
|
||||||
|
VERSION=$DRONE_TAG
|
||||||
|
echo "${PROJECTNAME} ${VERSION}" > /build/VERSION
|
||||||
|
elif [[ ! -z $DRONE_TAG ]]
|
||||||
|
then
|
||||||
|
echo "Drone not set, let's only do a build"
|
||||||
|
VERSION=$DRONE_COMMIT
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -z $VERSION && ! -z $GOOS && ! -z $GOARCH ]]
|
||||||
|
then
|
||||||
|
echo "Let's set a release name"
|
||||||
|
RELEASENAME=${PROJECTNAME}-${VERSION}-${GOOS}-${GOARCH}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building project"
|
||||||
|
go build -o ${PROJECTNAME} ${GOOPTIONS} ${SRCFILES}
|
||||||
|
|
||||||
|
if [[ ! -z $DRONE_TAG ]]
|
||||||
|
then
|
||||||
|
echo "Let's make archives"
|
||||||
|
mkdir -p /build
|
||||||
|
tar -czvf /build/${RELEASENAME}.tar.gz ${PROJECTNAME}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Removing binary file"
|
||||||
|
rm ${PROJECTNAME}
|
||||||
|
|
||||||
|
echo "End of build"
|
||||||
|
}
|
||||||
|
|
||||||
|
clean() {
|
||||||
|
rm -rf $RELEASEDIR
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
"build")
|
||||||
|
build
|
||||||
|
;;
|
||||||
|
"clean")
|
||||||
|
clean
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "No options choosen"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
43
go.mod
43
go.mod
@ -1,42 +1,11 @@
|
|||||||
module git.paulbsd.com/paulbsd/pki
|
module git.paulbsd.com/paulbsd/pki
|
||||||
|
|
||||||
go 1.23
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-acme/lego/v4 v4.17.4
|
github.com/go-acme/lego/v4 v4.1.0
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/labstack/echo/v4 v4.1.17
|
||||||
github.com/labstack/echo/v4 v4.12.0
|
github.com/lib/pq v1.8.0
|
||||||
github.com/lib/pq v1.10.9
|
gopkg.in/ini.v1 v1.62.0
|
||||||
github.com/miekg/dns v1.1.62 // indirect
|
xorm.io/xorm v1.0.5
|
||||||
github.com/onsi/ginkgo v1.16.0 // indirect
|
|
||||||
github.com/onsi/gomega v1.11.0 // indirect
|
|
||||||
golang.org/x/crypto v0.26.0 // indirect
|
|
||||||
golang.org/x/net v0.28.0 // indirect
|
|
||||||
golang.org/x/sys v0.24.0 // indirect
|
|
||||||
golang.org/x/text v0.17.0 // indirect
|
|
||||||
golang.org/x/time v0.6.0 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.67.0
|
|
||||||
xorm.io/builder v0.3.13 // indirect
|
|
||||||
xorm.io/xorm v1.3.9
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
|
||||||
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
|
||||||
github.com/goccy/go-json v0.10.3 // indirect
|
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
|
||||||
github.com/labstack/gommon v0.4.2 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
|
||||||
github.com/ovh/go-ovh v1.6.0 // indirect
|
|
||||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
|
||||||
golang.org/x/mod v0.20.0 // indirect
|
|
||||||
golang.org/x/oauth2 v0.22.0 // indirect
|
|
||||||
golang.org/x/sync v0.8.0 // indirect
|
|
||||||
golang.org/x/tools v0.24.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
678
go.sum
678
go.sum
@ -1,228 +1,558 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
|
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||||
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
|
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
|
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||||
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
|
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||||
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
|
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
||||||
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U=
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||||
|
github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
|
||||||
|
github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
|
||||||
|
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||||
|
github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
|
||||||
|
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||||
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.18/go.mod h1:L+HB2uBoDgi3+r1pJEJcbGwyyHhd2QXaGsKLbDwtm8Q=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v1.61.458/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
|
||||||
|
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||||
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/aws/aws-sdk-go v1.30.20/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.0.2 h1:JIufpQLbh4DkbQoii76ItQIUFzevQSqOLZca4eamEDs=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudflare/cloudflare-go v0.13.2/go.mod h1:27kfc1apuifUmJhp069y0+hwlKDg4bd8LWlu7oKeZvM=
|
||||||
|
github.com/cpu/goacmedns v0.0.3/go.mod h1:4MipLkI+qScwqtVxcNO6okBhbgRrr7/tKXUSgSL0teQ=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||||
|
github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||||
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/exoscale/egoscale v0.23.0/go.mod h1:hRo78jkjkCDKpivQdRBEpNYF5+cVpCJCPDg2/r45KaY=
|
||||||
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/go-acme/lego/v4 v4.1.0 h1:/9pMjaeaLq6m0n+io+kv2ySs2ZfrmH6eazuMoN18GHo=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/go-acme/lego/v4 v4.1.0/go.mod h1:pIFm5tWkXSgiAEfJ/XQCQIvX1cEvHFwbgLZyx8OVSUE=
|
||||||
github.com/go-acme/lego/v4 v4.16.1 h1:JxZ93s4KG0jL27rZ30UsIgxap6VGzKuREsSkkyzeoCQ=
|
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||||
github.com/go-acme/lego/v4 v4.16.1/go.mod h1:AVvwdPned/IWpD/ihHhMsKnveF7HHYAz/CmtXi7OZoE=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-acme/lego/v4 v4.17.4 h1:h0nePd3ObP6o7kAkndtpTzCw8shOZuWckNYeUQwo36Q=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-acme/lego/v4 v4.17.4/go.mod h1:dU94SvPNqimEeb7EVilGGSnS0nU1O5Exir0pQ4QFL4U=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
|
||||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/gophercloud/gophercloud v0.6.1-0.20191122030953-d8ac278c1c9d/go.mod h1:ozGNgr9KYOVATV5jsgHl/ceCDXGuguqOZAzoQ/2vcNM=
|
||||||
|
github.com/gophercloud/gophercloud v0.7.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss=
|
||||||
|
github.com/gophercloud/utils v0.0.0-20200508015959-b0167b94122c/go.mod h1:ehWUbLQJPqS0Ep+CxeD559hsm9pthPXadJNKwZkp43w=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
|
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
||||||
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||||
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
github.com/labstack/echo v1.4.4 h1:1bEiBNeGSUKxcPDGfZ/7IgdhJJZx8wV/pICJh4W2NJI=
|
||||||
|
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
||||||
|
github.com/labstack/echo/v4 v4.1.17 h1:PQIBaRplyRy3OjwILGkPg89JRtH2x5bssi59G2EL3fo=
|
||||||
|
github.com/labstack/echo/v4 v4.1.17/go.mod h1:Tn2yRQL/UclUalpb5rPdXDevbkJ+lp/2svdyFBg6CHQ=
|
||||||
|
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
|
||||||
|
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||||
|
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||||
|
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/linode/linodego v0.21.0/go.mod h1:UTpq1JUZD0CZsJ8rt+0CRkqbzrp1MbGakVPt2DXY5Mk=
|
||||||
|
github.com/liquidweb/liquidweb-go v1.6.1/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
|
||||||
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
|
||||||
|
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||||
|
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
|
||||||
|
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
||||||
|
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||||
|
github.com/nrdcg/auroradns v1.0.1/go.mod h1:y4pc0i9QXYlFCWrhWrUSIETnZgrf4KuwjDIWmmXo3JI=
|
||||||
|
github.com/nrdcg/desec v0.5.0/go.mod h1:2ejvMazkav1VdDbv2HeQO7w+Ta1CGHqzQr27ZBYTuEQ=
|
||||||
|
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
|
||||||
|
github.com/nrdcg/goinwx v0.8.1/go.mod h1:tILVc10gieBp/5PMvbcYeXM6pVQ+c9jxDZnpaR1UW7c=
|
||||||
|
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||||
github.com/onsi/ginkgo v1.16.0 h1:NBrNLB37exjJLxXtFOktx6CISBdS1aF8+7MwKlTV8U4=
|
|
||||||
github.com/onsi/ginkgo v1.16.0/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/oracle/oci-go-sdk v24.2.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||||
github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug=
|
github.com/ovh/go-ovh v1.1.0 h1:bHXZmw8nTgZin4Nv7JuaLs0KG5x54EQR7migYTd1zrk=
|
||||||
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
|
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
||||||
github.com/ovh/go-ovh v1.5.1 h1:P8O+7H+NQuFK9P/j4sFW5C0fvSS2DnHYGPwdVCp45wI=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/ovh/go-ovh v1.5.1/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/ovh/go-ovh v1.6.0 h1:ixLOwxQdzYDx296sXcgS35TOPEahJkpjMGtzPadCjQI=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/ovh/go-ovh v1.6.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||||
|
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
|
github.com/transip/gotransip/v6 v6.2.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
|
||||||
|
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
||||||
|
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
|
github.com/vultr/govultr v0.5.0/go.mod h1:wZZXZbYbqyY1n3AldoeYNZK4Wnmmoq6dNFkvd5TV3ss=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||||
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
||||||
|
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||||
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
|
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8=
|
||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
|
||||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
|
||||||
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
|
||||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
|
||||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
|
||||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
golang.org/x/tools v0.0.0-20191203134012-c197fd4bf371/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||||
|
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ns1/ns1-go.v2 v2.4.2/go.mod h1:GMnKY+ZuoJ+lVLL+78uSTjwTz2jMazq6AfGKQOYhsPk=
|
||||||
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
modernc.org/libc v1.22.2 h1:4U7v51GyhlWqQmwCHj28Rdq2Yzwk55ovjFrdPjs8Hb0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI=
|
||||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||||
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
|
xorm.io/xorm v1.0.5 h1:LRr5PfOUb4ODPR63YwbowkNDwcolT2LnkwP/TUaMaB0=
|
||||||
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
xorm.io/xorm v1.0.5/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4=
|
||||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
|
||||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
|
||||||
modernc.org/sqlite v1.20.4 h1:J8+m2trkN+KKoE7jglyHYYYiaq5xmz2HoHJIiBlRzbE=
|
|
||||||
modernc.org/sqlite v1.20.4/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A=
|
|
||||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
|
||||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
|
||||||
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
|
|
||||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
|
||||||
xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
|
|
||||||
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
|
||||||
xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU=
|
|
||||||
xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw=
|
|
||||||
|
@ -2,18 +2,15 @@ package cert
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
func (e *Entry) Z() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry is the main struct for stored certificates
|
// Entry is the main struct for stored certificates
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
ID int `xorm:"pk autoincr"`
|
ID int `xorm:"pk autoincr"`
|
||||||
Domain string `xorm:"notnull"`
|
Domain string `xorm:"notnull"`
|
||||||
Certificate string `xorm:"text notnull"`
|
Certificate string `xorm:"text notnull"`
|
||||||
PrivateKey string `xorm:"text notnull"`
|
PrivateKey string `xorm:"text notnull"`
|
||||||
AuthURL string `xorm:"notnull"`
|
AuthURL string
|
||||||
ValidityBegin time.Time `xorm:"notnull"`
|
ValidityBegin time.Time
|
||||||
ValidityEnd time.Time `xorm:"notnull"`
|
ValidityEnd time.Time
|
||||||
Created time.Time `xorm:"created notnull"`
|
Created time.Time `xorm:"created notnull"`
|
||||||
Updated time.Time `xorm:"updated notnull"`
|
Updated time.Time `xorm:"updated notnull"`
|
||||||
}
|
}
|
||||||
|
@ -60,13 +60,10 @@ func (cfg *Config) GetConfig() error {
|
|||||||
options["ovhas"] = pkisection.Key("ovhas").MustString("")
|
options["ovhas"] = pkisection.Key("ovhas").MustString("")
|
||||||
options["ovhck"] = pkisection.Key("ovhck").MustString("")
|
options["ovhck"] = pkisection.Key("ovhck").MustString("")
|
||||||
|
|
||||||
options["pdnsapiurl"] = pkisection.Key("pdnsapiurl").MustString("")
|
|
||||||
options["pdnsapikey"] = pkisection.Key("pdnsapikey").MustString("")
|
|
||||||
|
|
||||||
cfg.ACME.ProviderOptions = options
|
cfg.ACME.ProviderOptions = options
|
||||||
for key, value := range options {
|
for k, v := range options {
|
||||||
if value == "" {
|
if v == "" {
|
||||||
utils.Advice(fmt.Sprintf("Provider parameter %s not set", key))
|
utils.Advice(fmt.Sprintf("OVH provider parameter %s not set", k))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,8 +72,6 @@ func (cfg *Config) GetConfig() error {
|
|||||||
cfg.ACME.AuthURL = lego.LEDirectoryProduction
|
cfg.ACME.AuthURL = lego.LEDirectoryProduction
|
||||||
case "staging":
|
case "staging":
|
||||||
cfg.ACME.AuthURL = lego.LEDirectoryStaging
|
cfg.ACME.AuthURL = lego.LEDirectoryStaging
|
||||||
default:
|
|
||||||
cfg.ACME.AuthURL = lego.LEDirectoryStaging
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"git.paulbsd.com/paulbsd/pki/src/cert"
|
"git.paulbsd.com/paulbsd/pki/src/cert"
|
||||||
"git.paulbsd.com/paulbsd/pki/src/config"
|
"git.paulbsd.com/paulbsd/pki/src/config"
|
||||||
"git.paulbsd.com/paulbsd/pki/src/domain"
|
|
||||||
"git.paulbsd.com/paulbsd/pki/src/pki"
|
"git.paulbsd.com/paulbsd/pki/src/pki"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
@ -18,7 +17,7 @@ import (
|
|||||||
func Init(cfg *config.Config) (err error) {
|
func Init(cfg *config.Config) (err error) {
|
||||||
var databaseEngine = "postgres"
|
var databaseEngine = "postgres"
|
||||||
tables := []interface{}{cert.Entry{},
|
tables := []interface{}{cert.Entry{},
|
||||||
pki.User{}, domain.Domain{}}
|
pki.User{}}
|
||||||
|
|
||||||
cfg.Db, err = xorm.NewEngine(databaseEngine,
|
cfg.Db, err = xorm.NewEngine(databaseEngine,
|
||||||
fmt.Sprintf("%s://%s:%s@%s/%s",
|
fmt.Sprintf("%s://%s:%s@%s/%s",
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package domain
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// Domain describes a domain
|
|
||||||
type Domain struct {
|
|
||||||
ID int `xorm:"pk autoincr"`
|
|
||||||
Domain string `xorm:"text notnull unique(domain_provider)"`
|
|
||||||
Provider string `xorm:"text notnull unique(domain_provider)"`
|
|
||||||
Created time.Time `xorm:"created notnull"`
|
|
||||||
Updated time.Time `xorm:"updated notnull"`
|
|
||||||
}
|
|
@ -12,10 +12,8 @@ import (
|
|||||||
|
|
||||||
"git.paulbsd.com/paulbsd/pki/src/cert"
|
"git.paulbsd.com/paulbsd/pki/src/cert"
|
||||||
"git.paulbsd.com/paulbsd/pki/src/config"
|
"git.paulbsd.com/paulbsd/pki/src/config"
|
||||||
"git.paulbsd.com/paulbsd/pki/src/domain"
|
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
"github.com/go-acme/lego/v4/certificate"
|
"github.com/go-acme/lego/v4/certificate"
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
|
||||||
"github.com/go-acme/lego/v4/lego"
|
"github.com/go-acme/lego/v4/lego"
|
||||||
"github.com/go-acme/lego/v4/registration"
|
"github.com/go-acme/lego/v4/registration"
|
||||||
)
|
)
|
||||||
@ -30,14 +28,10 @@ func (u *User) Init(cfg *config.Config) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetEntry returns requested acme ressource in database relative to domain
|
// GetEntry returns requested acme ressource in database relative to domain
|
||||||
func (u *User) GetEntry(cfg *config.Config, domain *string) (Entry cert.Entry, err error) {
|
func (u *User) GetEntry(cfg *config.Config, domain string) (Entry cert.Entry, err error) {
|
||||||
has, err := cfg.Db.Where("domain = ?", domain).And(
|
has, err := cfg.Db.Where("domain = ?", domain).Get(&Entry)
|
||||||
"auth_url = ?", cfg.ACME.AuthURL).And(
|
|
||||||
fmt.Sprintf("validity_end::timestamp-'%d DAY'::INTERVAL >= now()", cfg.ACME.MaxDaysBefore)).Desc(
|
|
||||||
"id").Get(&Entry)
|
|
||||||
|
|
||||||
if !has {
|
if !has {
|
||||||
err = fmt.Errorf("entry doesn't exists")
|
err = fmt.Errorf("Entry doesn't exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -66,50 +60,21 @@ func (u *User) HandleRegistration(cfg *config.Config, client *lego.Client) (err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RequestNewCert returns a newly requested certificate to letsencrypt
|
// RequestNewCert returns a newly requested certificate to letsencrypt
|
||||||
func (u *User) RequestNewCert(cfg *config.Config, domainnames *[]string) (certs *certificate.Resource, err error) {
|
func (u *User) RequestNewCert(cfg *config.Config, domain string) (certificates *certificate.Resource, err error) {
|
||||||
legoconfig := lego.NewConfig(u)
|
legoconfig := lego.NewConfig(u)
|
||||||
legoconfig.CADirURL = cfg.ACME.AuthURL
|
legoconfig.CADirURL = cfg.ACME.AuthURL
|
||||||
legoconfig.Certificate.KeyType = certcrypto.RSA2048
|
legoconfig.Certificate.KeyType = certcrypto.RSA2048
|
||||||
|
|
||||||
var dom domain.Domain
|
ovhprovider, err := initProvider(cfg)
|
||||||
var has bool
|
|
||||||
for _, d := range *domainnames {
|
|
||||||
dom = domain.Domain{Domain: d}
|
|
||||||
if has, err = cfg.Db.Get(&dom); has {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has {
|
|
||||||
err = fmt.Errorf("supplied domain not in allowed domains")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var provider challenge.Provider
|
|
||||||
|
|
||||||
switch dom.Provider {
|
|
||||||
case "ovh":
|
|
||||||
provider, err = initOVHProvider(cfg)
|
|
||||||
case "pdns":
|
|
||||||
provider, err = initPowerDNSProvider(cfg)
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := lego.NewClient(legoconfig)
|
client, err := lego.NewClient(legoconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = client.Challenge.SetDNS01Provider(provider)
|
err = client.Challenge.SetDNS01Provider(ovhprovider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If PKICtx doesn't exists, get existing of fetch registration
|
// If PKICtx doesn't exists, get existing of fetch registration
|
||||||
@ -121,15 +86,14 @@ func (u *User) RequestNewCert(cfg *config.Config, domainnames *[]string) (certs
|
|||||||
}
|
}
|
||||||
|
|
||||||
request := certificate.ObtainRequest{
|
request := certificate.ObtainRequest{
|
||||||
Domains: *domainnames,
|
Domains: []string{domain},
|
||||||
Bundle: true,
|
Bundle: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
certs, err = client.Certificate.Obtain(request)
|
certificates, err = client.Certificate.Obtain(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
package pki
|
package pki
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"git.paulbsd.com/paulbsd/pki/src/config"
|
"git.paulbsd.com/paulbsd/pki/src/config"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/ovh"
|
"github.com/go-acme/lego/v4/providers/dns/ovh"
|
||||||
"github.com/go-acme/lego/v4/providers/dns/pdns"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// initOVHProvider initialize DNS provider configuration
|
// initProvider initialize DNS provider configuration
|
||||||
func initOVHProvider(cfg *config.Config) (ovhprovider *ovh.DNSProvider, err error) {
|
func initProvider(cfg *config.Config) (ovhprovider *ovh.DNSProvider, err error) {
|
||||||
ovhconfig := ovh.NewDefaultConfig()
|
ovhconfig := ovh.NewDefaultConfig()
|
||||||
|
|
||||||
ovhconfig.APIEndpoint = cfg.ACME.ProviderOptions["ovhendpoint"]
|
ovhconfig.APIEndpoint = cfg.ACME.ProviderOptions["ovhendpoint"]
|
||||||
@ -19,24 +15,6 @@ func initOVHProvider(cfg *config.Config) (ovhprovider *ovh.DNSProvider, err erro
|
|||||||
ovhconfig.ConsumerKey = cfg.ACME.ProviderOptions["ovhck"]
|
ovhconfig.ConsumerKey = cfg.ACME.ProviderOptions["ovhck"]
|
||||||
|
|
||||||
ovhprovider, err = ovh.NewDNSProviderConfig(ovhconfig)
|
ovhprovider, err = ovh.NewDNSProviderConfig(ovhconfig)
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// initPowerDNSProvider initialize DNS provider configuration
|
|
||||||
func initPowerDNSProvider(cfg *config.Config) (pdnsprovider *pdns.DNSProvider, err error) {
|
|
||||||
pdnsconfig := pdns.NewDefaultConfig()
|
|
||||||
|
|
||||||
pdnsconfig.Host, err = url.Parse(cfg.ACME.ProviderOptions["pdnsapiurl"])
|
|
||||||
pdnsconfig.APIKey = cfg.ACME.ProviderOptions["pdnsapikey"]
|
|
||||||
|
|
||||||
pdnsprovider, err = pdns.NewDNSProviderConfig(pdnsconfig)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -27,30 +27,25 @@ func RunServer(cfg *config.Config) (err error) {
|
|||||||
e.HideBanner = cfg.Options.HideBanner
|
e.HideBanner = cfg.Options.HideBanner
|
||||||
|
|
||||||
e.GET("/", func(c echo.Context) error {
|
e.GET("/", func(c echo.Context) error {
|
||||||
return c.String(http.StatusOK, "Welcome to PKI software (https://git.paulbsd.com/paulbsd/pki)")
|
username := c.Get("username")
|
||||||
|
return c.String(http.StatusOK, fmt.Sprintf("username: %s", username))
|
||||||
})
|
})
|
||||||
e.POST("/cert", func(c echo.Context) (err error) {
|
e.GET("/domain/:domain", func(c echo.Context) (err error) {
|
||||||
var request = new(EntryRequest)
|
var result EntryResponse
|
||||||
var result = make(map[string]EntryResponse)
|
log.Println(fmt.Sprintf("Providing %s to user %s at %s", c.Param("domain"), c.Get("username"), c.RealIP()))
|
||||||
err = c.Bind(&request)
|
result, err = GetCertificate(cfg, c.Get("user").(*pki.User), c.Param("domain"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
return c.String(http.StatusInternalServerError, fmt.Sprintf("%s %s", result, err))
|
||||||
return c.JSON(http.StatusInternalServerError, "error parsing request")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Providing %s to user %s at %s\n", request.Domains, c.Get("username"), c.RealIP())
|
|
||||||
|
|
||||||
result, err = GetCertificate(cfg, c.Get("user").(*pki.User), &request.Domains)
|
|
||||||
if err != nil {
|
|
||||||
return c.String(http.StatusInternalServerError, fmt.Sprintf("%s", err))
|
|
||||||
}
|
}
|
||||||
return c.JSON(http.StatusOK, result)
|
return c.JSON(http.StatusOK, result)
|
||||||
})
|
})
|
||||||
|
e.GET("/config", func(c echo.Context) (err error) {
|
||||||
|
if ConfigAccess(*cfg, c.RealIP()) {
|
||||||
|
return c.JSON(http.StatusOK, cfg)
|
||||||
|
}
|
||||||
|
return c.String(http.StatusForbidden, "Forbidden")
|
||||||
|
})
|
||||||
|
|
||||||
e.Logger.Fatal(
|
e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", cfg.Switchs.Port)))
|
||||||
e.Start(
|
|
||||||
fmt.Sprintf(":%d",
|
|
||||||
cfg.Switchs.Port)))
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -13,24 +13,18 @@ import (
|
|||||||
"git.paulbsd.com/paulbsd/pki/src/pki"
|
"git.paulbsd.com/paulbsd/pki/src/pki"
|
||||||
)
|
)
|
||||||
|
|
||||||
const timeformatstring string = "2006-01-02 15:04:05"
|
|
||||||
|
|
||||||
var domainRegex, err = regexp.Compile(`^[a-z0-9\*]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$`)
|
|
||||||
|
|
||||||
// GetCertificate get certificate from database if exists, of request it from ACME
|
// GetCertificate get certificate from database if exists, of request it from ACME
|
||||||
func GetCertificate(cfg *config.Config, user *pki.User, domains *[]string) (result map[string]EntryResponse, err error) {
|
func GetCertificate(cfg *config.Config, user *pki.User, domain string) (result EntryResponse, err error) {
|
||||||
err = CheckDomains(domains)
|
err = CheckDomain(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
result = make(map[string]EntryResponse)
|
|
||||||
|
|
||||||
firstdomain := (*domains)[0]
|
entry, err := user.GetEntry(cfg, domain)
|
||||||
entry, err := user.GetEntry(cfg, &firstdomain)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
certs, err := user.RequestNewCert(cfg, domains)
|
certs, err := user.RequestNewCert(cfg, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error fetching new certificate %s\n", err)
|
log.Println(fmt.Sprintf("Error fetching new certificate %s", err))
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
NotBefore, NotAfter, err := GetDates(certs.Certificate)
|
NotBefore, NotAfter, err := GetDates(certs.Certificate)
|
||||||
@ -38,36 +32,25 @@ func GetCertificate(cfg *config.Config, user *pki.User, domains *[]string) (resu
|
|||||||
log.Println("Error where parsing dates")
|
log.Println("Error where parsing dates")
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
entry := cert.Entry{Domain: certs.Domain,
|
entry := cert.Entry{Domain: domain,
|
||||||
Certificate: string(certs.Certificate),
|
Certificate: string(certs.Certificate),
|
||||||
PrivateKey: string(certs.PrivateKey),
|
PrivateKey: string(certs.PrivateKey),
|
||||||
ValidityBegin: NotBefore,
|
ValidityBegin: NotBefore,
|
||||||
ValidityEnd: NotAfter,
|
ValidityEnd: NotAfter,
|
||||||
AuthURL: cfg.ACME.AuthURL}
|
AuthURL: cfg.ACME.AuthURL}
|
||||||
cfg.Db.Insert(&entry)
|
cfg.Db.Insert(entry)
|
||||||
result[firstdomain] = convertEntryToResponse(entry)
|
result = convertEntryToResponse(entry)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
result[firstdomain] = convertEntryToResponse(entry)
|
result = convertEntryToResponse(entry)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckDomains check if requested domains are valid
|
// CheckDomain check if requested domain is valid
|
||||||
func CheckDomains(domains *[]string) (err error) {
|
func CheckDomain(domain string) (err error) {
|
||||||
for _, domain := range *domains {
|
res, err := regexp.Match(`^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}$`, []byte(domain))
|
||||||
err = CheckDomain(&domain)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckDomain check if requested domain are valid
|
|
||||||
func CheckDomain(domain *string) (err error) {
|
|
||||||
res := domainRegex.Match([]byte(*domain))
|
|
||||||
if !res {
|
if !res {
|
||||||
return fmt.Errorf("Domain %s has not a valid syntax %s, please verify", *domain, err)
|
return fmt.Errorf("Domain has not a valid syntax")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -78,7 +61,7 @@ func GetDates(cert []byte) (NotBefore time.Time, NotAfter time.Time, err error)
|
|||||||
if block.Type == "CERTIFICATE" {
|
if block.Type == "CERTIFICATE" {
|
||||||
ce, err := x509.ParseCertificate(block.Bytes)
|
ce, err := x509.ParseCertificate(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error when parsing certificate")
|
log.Fatal("Error when parsing certificate")
|
||||||
}
|
}
|
||||||
NotBefore = ce.NotBefore
|
NotBefore = ce.NotBefore
|
||||||
NotAfter = ce.NotAfter
|
NotAfter = ce.NotAfter
|
||||||
@ -86,27 +69,27 @@ func GetDates(cert []byte) (NotBefore time.Time, NotAfter time.Time, err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NeedRenewal is an unimplemented method
|
||||||
|
func NeedRenewal(cfg config.Config) (res bool, err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// convertEntryToResponse converts database ACME entry to JSON ACME entry
|
// convertEntryToResponse converts database ACME entry to JSON ACME entry
|
||||||
func convertEntryToResponse(in cert.Entry) (out EntryResponse) {
|
func convertEntryToResponse(in cert.Entry) (out EntryResponse) {
|
||||||
out.Domains = append(out.Domains, in.Domain)
|
out.Domain = in.Domain
|
||||||
out.Certificate = in.Certificate
|
out.Certificate = in.Certificate
|
||||||
out.PrivateKey = in.PrivateKey
|
out.PrivateKey = in.PrivateKey
|
||||||
out.ValidityBegin = in.ValidityBegin.Format(timeformatstring)
|
out.ValidityBegin = in.ValidityBegin
|
||||||
out.ValidityEnd = in.ValidityEnd.Format(timeformatstring)
|
out.ValidityEnd = in.ValidityEnd
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// EntryRequest
|
|
||||||
type EntryRequest struct {
|
|
||||||
Domains []string `json:"domains"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// EntryResponse is the struct defining JSON response from webservice
|
// EntryResponse is the struct defining JSON response from webservice
|
||||||
type EntryResponse struct {
|
type EntryResponse struct {
|
||||||
Domains []string `json:"domains"`
|
Domain string `json:"domain"`
|
||||||
Certificate string `json:"certificate"`
|
Certificate string `json:"certificate"`
|
||||||
PrivateKey string `json:"privatekey"`
|
PrivateKey string `json:"privatekey"`
|
||||||
ValidityBegin string `json:"validitybegin"`
|
ValidityBegin time.Time `json:"validitybegin"`
|
||||||
ValidityEnd string `json:"validityend"`
|
ValidityEnd time.Time `json:"validityend"`
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
// Auth make authentication to webservice
|
// Auth make authentication to webservice
|
||||||
func Auth(cfg *config.Config, username string, password string, c echo.Context) (res bool, user *pki.User, err error) {
|
func Auth(cfg *config.Config, username string, password string, c echo.Context) (res bool, user *pki.User, err error) {
|
||||||
user = &pki.User{Username: username}
|
user = &pki.User{Username: username}
|
||||||
|
|
||||||
_, err = cfg.Db.Get(user)
|
_, err = cfg.Db.Get(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res = false
|
res = false
|
||||||
|
3
vendor/github.com/cenkalti/backoff/v4/.gitignore
generated
vendored
3
vendor/github.com/cenkalti/backoff/v4/.gitignore
generated
vendored
@ -20,6 +20,3 @@ _cgo_export.*
|
|||||||
_testmain.go
|
_testmain.go
|
||||||
|
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
# IDEs
|
|
||||||
.idea/
|
|
||||||
|
10
vendor/github.com/cenkalti/backoff/v4/.travis.yml
generated
vendored
Normal file
10
vendor/github.com/cenkalti/backoff/v4/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.12
|
||||||
|
- 1.x
|
||||||
|
- tip
|
||||||
|
before_install:
|
||||||
|
- go get github.com/mattn/goveralls
|
||||||
|
- go get golang.org/x/tools/cmd/cover
|
||||||
|
script:
|
||||||
|
- $HOME/gopath/bin/goveralls -service=travis-ci
|
11
vendor/github.com/cenkalti/backoff/v4/README.md
generated
vendored
11
vendor/github.com/cenkalti/backoff/v4/README.md
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Coverage Status][coveralls image]][coveralls]
|
# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls]
|
||||||
|
|
||||||
This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
|
This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
|
||||||
|
|
||||||
@ -11,7 +11,8 @@ The retries exponentially increase and stop increasing when a certain threshold
|
|||||||
|
|
||||||
Import path is `github.com/cenkalti/backoff/v4`. Please note the version part at the end.
|
Import path is `github.com/cenkalti/backoff/v4`. Please note the version part at the end.
|
||||||
|
|
||||||
Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation.
|
godoc.org does not support modules yet,
|
||||||
|
so you can use https://godoc.org/gopkg.in/cenkalti/backoff.v4 to view the documentation.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
@ -19,12 +20,14 @@ Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation.
|
|||||||
* Please don't send a PR without opening an issue and discussing it first.
|
* Please don't send a PR without opening an issue and discussing it first.
|
||||||
* If proposed change is not a common use case, I will probably not accept it.
|
* If proposed change is not a common use case, I will probably not accept it.
|
||||||
|
|
||||||
[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v4
|
[godoc]: https://godoc.org/github.com/cenkalti/backoff
|
||||||
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
|
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
|
||||||
|
[travis]: https://travis-ci.org/cenkalti/backoff
|
||||||
|
[travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master
|
||||||
[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
|
[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
|
||||||
[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
|
[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
|
||||||
|
|
||||||
[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
|
[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
|
||||||
[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
|
[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
|
||||||
|
|
||||||
[advanced example]: https://pkg.go.dev/github.com/cenkalti/backoff/v4?tab=doc#pkg-examples
|
[advanced example]: https://godoc.org/github.com/cenkalti/backoff#example_
|
||||||
|
6
vendor/github.com/cenkalti/backoff/v4/context.go
generated
vendored
6
vendor/github.com/cenkalti/backoff/v4/context.go
generated
vendored
@ -57,6 +57,10 @@ func (b *backOffContext) NextBackOff() time.Duration {
|
|||||||
case <-b.ctx.Done():
|
case <-b.ctx.Done():
|
||||||
return Stop
|
return Stop
|
||||||
default:
|
default:
|
||||||
return b.BackOff.NextBackOff()
|
|
||||||
}
|
}
|
||||||
|
next := b.BackOff.NextBackOff()
|
||||||
|
if deadline, ok := b.ctx.Deadline(); ok && deadline.Sub(time.Now()) < next { // nolint: gosimple
|
||||||
|
return Stop
|
||||||
|
}
|
||||||
|
return next
|
||||||
}
|
}
|
||||||
|
60
vendor/github.com/cenkalti/backoff/v4/exponential.go
generated
vendored
60
vendor/github.com/cenkalti/backoff/v4/exponential.go
generated
vendored
@ -71,9 +71,6 @@ type Clock interface {
|
|||||||
Now() time.Time
|
Now() time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExponentialBackOffOpts is a function type used to configure ExponentialBackOff options.
|
|
||||||
type ExponentialBackOffOpts func(*ExponentialBackOff)
|
|
||||||
|
|
||||||
// Default values for ExponentialBackOff.
|
// Default values for ExponentialBackOff.
|
||||||
const (
|
const (
|
||||||
DefaultInitialInterval = 500 * time.Millisecond
|
DefaultInitialInterval = 500 * time.Millisecond
|
||||||
@ -84,7 +81,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
||||||
func NewExponentialBackOff(opts ...ExponentialBackOffOpts) *ExponentialBackOff {
|
func NewExponentialBackOff() *ExponentialBackOff {
|
||||||
b := &ExponentialBackOff{
|
b := &ExponentialBackOff{
|
||||||
InitialInterval: DefaultInitialInterval,
|
InitialInterval: DefaultInitialInterval,
|
||||||
RandomizationFactor: DefaultRandomizationFactor,
|
RandomizationFactor: DefaultRandomizationFactor,
|
||||||
@ -94,62 +91,10 @@ func NewExponentialBackOff(opts ...ExponentialBackOffOpts) *ExponentialBackOff {
|
|||||||
Stop: Stop,
|
Stop: Stop,
|
||||||
Clock: SystemClock,
|
Clock: SystemClock,
|
||||||
}
|
}
|
||||||
for _, fn := range opts {
|
|
||||||
fn(b)
|
|
||||||
}
|
|
||||||
b.Reset()
|
b.Reset()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithInitialInterval sets the initial interval between retries.
|
|
||||||
func WithInitialInterval(duration time.Duration) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.InitialInterval = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithRandomizationFactor sets the randomization factor to add jitter to intervals.
|
|
||||||
func WithRandomizationFactor(randomizationFactor float64) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.RandomizationFactor = randomizationFactor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMultiplier sets the multiplier for increasing the interval after each retry.
|
|
||||||
func WithMultiplier(multiplier float64) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.Multiplier = multiplier
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMaxInterval sets the maximum interval between retries.
|
|
||||||
func WithMaxInterval(duration time.Duration) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.MaxInterval = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMaxElapsedTime sets the maximum total time for retries.
|
|
||||||
func WithMaxElapsedTime(duration time.Duration) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.MaxElapsedTime = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithRetryStopDuration sets the duration after which retries should stop.
|
|
||||||
func WithRetryStopDuration(duration time.Duration) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.Stop = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithClockProvider sets the clock used to measure time.
|
|
||||||
func WithClockProvider(clock Clock) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.Clock = clock
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type systemClock struct{}
|
type systemClock struct{}
|
||||||
|
|
||||||
func (t systemClock) Now() time.Time {
|
func (t systemClock) Now() time.Time {
|
||||||
@ -202,9 +147,6 @@ func (b *ExponentialBackOff) incrementCurrentInterval() {
|
|||||||
// Returns a random value from the following interval:
|
// Returns a random value from the following interval:
|
||||||
// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
|
// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
|
||||||
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
|
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
|
||||||
if randomizationFactor == 0 {
|
|
||||||
return currentInterval // make sure no randomness is used when randomizationFactor is 0.
|
|
||||||
}
|
|
||||||
var delta = randomizationFactor * float64(currentInterval)
|
var delta = randomizationFactor * float64(currentInterval)
|
||||||
var minInterval = float64(currentInterval) - delta
|
var minInterval = float64(currentInterval) - delta
|
||||||
var maxInterval = float64(currentInterval) + delta
|
var maxInterval = float64(currentInterval) + delta
|
||||||
|
3
vendor/github.com/cenkalti/backoff/v4/go.mod
generated
vendored
Normal file
3
vendor/github.com/cenkalti/backoff/v4/go.mod
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module github.com/cenkalti/backoff/v4
|
||||||
|
|
||||||
|
go 1.12
|
70
vendor/github.com/cenkalti/backoff/v4/retry.go
generated
vendored
70
vendor/github.com/cenkalti/backoff/v4/retry.go
generated
vendored
@ -1,24 +1,11 @@
|
|||||||
package backoff
|
package backoff
|
||||||
|
|
||||||
import (
|
import "time"
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An OperationWithData is executing by RetryWithData() or RetryNotifyWithData().
|
|
||||||
// The operation will be retried using a backoff policy if it returns an error.
|
|
||||||
type OperationWithData[T any] func() (T, error)
|
|
||||||
|
|
||||||
// An Operation is executing by Retry() or RetryNotify().
|
// An Operation is executing by Retry() or RetryNotify().
|
||||||
// The operation will be retried using a backoff policy if it returns an error.
|
// The operation will be retried using a backoff policy if it returns an error.
|
||||||
type Operation func() error
|
type Operation func() error
|
||||||
|
|
||||||
func (o Operation) withEmptyData() OperationWithData[struct{}] {
|
|
||||||
return func() (struct{}, error) {
|
|
||||||
return struct{}{}, o()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify is a notify-on-error function. It receives an operation error and
|
// Notify is a notify-on-error function. It receives an operation error and
|
||||||
// backoff delay if the operation failed (with an error).
|
// backoff delay if the operation failed (with an error).
|
||||||
//
|
//
|
||||||
@ -38,41 +25,18 @@ func Retry(o Operation, b BackOff) error {
|
|||||||
return RetryNotify(o, b, nil)
|
return RetryNotify(o, b, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetryWithData is like Retry but returns data in the response too.
|
|
||||||
func RetryWithData[T any](o OperationWithData[T], b BackOff) (T, error) {
|
|
||||||
return RetryNotifyWithData(o, b, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetryNotify calls notify function with the error and wait duration
|
// RetryNotify calls notify function with the error and wait duration
|
||||||
// for each failed attempt before sleep.
|
// for each failed attempt before sleep.
|
||||||
func RetryNotify(operation Operation, b BackOff, notify Notify) error {
|
func RetryNotify(operation Operation, b BackOff, notify Notify) error {
|
||||||
return RetryNotifyWithTimer(operation, b, notify, nil)
|
return RetryNotifyWithTimer(operation, b, notify, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetryNotifyWithData is like RetryNotify but returns data in the response too.
|
|
||||||
func RetryNotifyWithData[T any](operation OperationWithData[T], b BackOff, notify Notify) (T, error) {
|
|
||||||
return doRetryNotify(operation, b, notify, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer
|
// RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer
|
||||||
// for each failed attempt before sleep.
|
// for each failed attempt before sleep.
|
||||||
// A default timer that uses system timer is used when nil is passed.
|
// A default timer that uses system timer is used when nil is passed.
|
||||||
func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error {
|
func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error {
|
||||||
_, err := doRetryNotify(operation.withEmptyData(), b, notify, t)
|
var err error
|
||||||
return err
|
var next time.Duration
|
||||||
}
|
|
||||||
|
|
||||||
// RetryNotifyWithTimerAndData is like RetryNotifyWithTimer but returns data in the response too.
|
|
||||||
func RetryNotifyWithTimerAndData[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
|
|
||||||
return doRetryNotify(operation, b, notify, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
next time.Duration
|
|
||||||
res T
|
|
||||||
)
|
|
||||||
if t == nil {
|
if t == nil {
|
||||||
t = &defaultTimer{}
|
t = &defaultTimer{}
|
||||||
}
|
}
|
||||||
@ -85,22 +49,16 @@ func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Noti
|
|||||||
|
|
||||||
b.Reset()
|
b.Reset()
|
||||||
for {
|
for {
|
||||||
res, err = operation()
|
if err = operation(); err == nil {
|
||||||
if err == nil {
|
return nil
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var permanent *PermanentError
|
if permanent, ok := err.(*PermanentError); ok {
|
||||||
if errors.As(err, &permanent) {
|
return permanent.Err
|
||||||
return res, permanent.Err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if next = b.NextBackOff(); next == Stop {
|
if next = b.NextBackOff(); next == Stop {
|
||||||
if cerr := ctx.Err(); cerr != nil {
|
return err
|
||||||
return res, cerr
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if notify != nil {
|
if notify != nil {
|
||||||
@ -111,7 +69,7 @@ func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Noti
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return res, ctx.Err()
|
return ctx.Err()
|
||||||
case <-t.C():
|
case <-t.C():
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,16 +88,8 @@ func (e *PermanentError) Unwrap() error {
|
|||||||
return e.Err
|
return e.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PermanentError) Is(target error) bool {
|
|
||||||
_, ok := target.(*PermanentError)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Permanent wraps the given err in a *PermanentError.
|
// Permanent wraps the given err in a *PermanentError.
|
||||||
func Permanent(err error) error {
|
func Permanent(err error) *PermanentError {
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &PermanentError{
|
return &PermanentError{
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
bin
|
bin
|
||||||
.idea/
|
|
||||||
|
|
13
vendor/github.com/dgrijalva/jwt-go/.travis.yml
generated
vendored
Normal file
13
vendor/github.com/dgrijalva/jwt-go/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go vet ./...
|
||||||
|
- go test -v ./...
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- 1.7
|
||||||
|
- tip
|
@ -1,5 +1,4 @@
|
|||||||
Copyright (c) 2012 Dave Grijalva
|
Copyright (c) 2012 Dave Grijalva
|
||||||
Copyright (c) 2021 golang-jwt maintainers
|
|
||||||
|
|
||||||
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:
|
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:
|
||||||
|
|
97
vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md
generated
vendored
Normal file
97
vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
## Migration Guide from v2 -> v3
|
||||||
|
|
||||||
|
Version 3 adds several new, frequently requested features. To do so, it introduces a few breaking changes. We've worked to keep these as minimal as possible. This guide explains the breaking changes and how you can quickly update your code.
|
||||||
|
|
||||||
|
### `Token.Claims` is now an interface type
|
||||||
|
|
||||||
|
The most requested feature from the 2.0 verison of this library was the ability to provide a custom type to the JSON parser for claims. This was implemented by introducing a new interface, `Claims`, to replace `map[string]interface{}`. We also included two concrete implementations of `Claims`: `MapClaims` and `StandardClaims`.
|
||||||
|
|
||||||
|
`MapClaims` is an alias for `map[string]interface{}` with built in validation behavior. It is the default claims type when using `Parse`. The usage is unchanged except you must type cast the claims property.
|
||||||
|
|
||||||
|
The old example for parsing a token looked like this..
|
||||||
|
|
||||||
|
```go
|
||||||
|
if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
|
||||||
|
fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
is now directly mapped to...
|
||||||
|
|
||||||
|
```go
|
||||||
|
if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
|
||||||
|
claims := token.Claims.(jwt.MapClaims)
|
||||||
|
fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`StandardClaims` is designed to be embedded in your custom type. You can supply a custom claims type with the new `ParseWithClaims` function. Here's an example of using a custom claims type.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MyCustomClaims struct {
|
||||||
|
User string
|
||||||
|
*StandardClaims
|
||||||
|
}
|
||||||
|
|
||||||
|
if token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, keyLookupFunc); err == nil {
|
||||||
|
claims := token.Claims.(*MyCustomClaims)
|
||||||
|
fmt.Printf("Token for user %v expires %v", claims.User, claims.StandardClaims.ExpiresAt)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `ParseFromRequest` has been moved
|
||||||
|
|
||||||
|
To keep this library focused on the tokens without becoming overburdened with complex request processing logic, `ParseFromRequest` and its new companion `ParseFromRequestWithClaims` have been moved to a subpackage, `request`. The method signatues have also been augmented to receive a new argument: `Extractor`.
|
||||||
|
|
||||||
|
`Extractors` do the work of picking the token string out of a request. The interface is simple and composable.
|
||||||
|
|
||||||
|
This simple parsing example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
if token, err := jwt.ParseFromRequest(tokenString, req, keyLookupFunc); err == nil {
|
||||||
|
fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
is directly mapped to:
|
||||||
|
|
||||||
|
```go
|
||||||
|
if token, err := request.ParseFromRequest(req, request.OAuth2Extractor, keyLookupFunc); err == nil {
|
||||||
|
claims := token.Claims.(jwt.MapClaims)
|
||||||
|
fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
There are several concrete `Extractor` types provided for your convenience:
|
||||||
|
|
||||||
|
* `HeaderExtractor` will search a list of headers until one contains content.
|
||||||
|
* `ArgumentExtractor` will search a list of keys in request query and form arguments until one contains content.
|
||||||
|
* `MultiExtractor` will try a list of `Extractors` in order until one returns content.
|
||||||
|
* `AuthorizationHeaderExtractor` will look in the `Authorization` header for a `Bearer` token.
|
||||||
|
* `OAuth2Extractor` searches the places an OAuth2 token would be specified (per the spec): `Authorization` header and `access_token` argument
|
||||||
|
* `PostExtractionFilter` wraps an `Extractor`, allowing you to process the content before it's parsed. A simple example is stripping the `Bearer ` text from a header
|
||||||
|
|
||||||
|
|
||||||
|
### RSA signing methods no longer accept `[]byte` keys
|
||||||
|
|
||||||
|
Due to a [critical vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/), we've decided the convenience of accepting `[]byte` instead of `rsa.PublicKey` or `rsa.PrivateKey` isn't worth the risk of misuse.
|
||||||
|
|
||||||
|
To replace this behavior, we've added two helper methods: `ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error)` and `ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error)`. These are just simple helpers for unpacking PEM encoded PKCS1 and PKCS8 keys. If your keys are encoded any other way, all you need to do is convert them to the `crypto/rsa` package's types.
|
||||||
|
|
||||||
|
```go
|
||||||
|
func keyLookupFunc(*Token) (interface{}, error) {
|
||||||
|
// Don't forget to validate the alg is what you expect:
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
||||||
|
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up key
|
||||||
|
key, err := lookupPublicKey(token.Header["kid"])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unpack key from PEM encoded PKCS8
|
||||||
|
return jwt.ParseRSAPublicKeyFromPEM(key)
|
||||||
|
}
|
||||||
|
```
|
@ -1,34 +1,25 @@
|
|||||||
# jwt-go
|
# jwt-go
|
||||||
|
|
||||||
[](https://github.com/golang-jwt/jwt/actions/workflows/build.yml)
|
[](https://travis-ci.org/dgrijalva/jwt-go)
|
||||||
[](https://pkg.go.dev/github.com/golang-jwt/jwt)
|
[](https://godoc.org/github.com/dgrijalva/jwt-go)
|
||||||
|
|
||||||
A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](https://datatracker.ietf.org/doc/html/rfc7519).
|
A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html)
|
||||||
|
|
||||||
**IMPORT PATH CHANGE:** Starting from [v3.2.1](https://github.com/golang-jwt/jwt/releases/tag/v3.2.1), the import path has changed from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt`. After the original author of the library suggested migrating the maintenance of `jwt-go`, a dedicated team of open source maintainers decided to clone the existing library into this repository. See [dgrijalva/jwt-go#462](https://github.com/dgrijalva/jwt-go/issues/462) for a detailed discussion on this topic.
|
**NEW VERSION COMING:** There have been a lot of improvements suggested since the version 3.0.0 released in 2016. I'm working now on cutting two different releases: 3.2.0 will contain any non-breaking changes or enhancements. 4.0.0 will follow shortly which will include breaking changes. See the 4.0.0 milestone to get an idea of what's coming. If you have other ideas, or would like to participate in 4.0.0, now's the time. If you depend on this library and don't want to be interrupted, I recommend you use your dependency mangement tool to pin to version 3.
|
||||||
|
|
||||||
Future releases will be using the `github.com/golang-jwt/jwt` import path and continue the existing versioning scheme of `v3.x.x+incompatible`. Backwards-compatible patches and fixes will be done on the `v3` release branch, where as new build-breaking features will be developed in a `v4` release, possibly including a SIV-style import path.
|
**SECURITY NOTICE:** Some older versions of Go have a security issue in the cryotp/elliptic. Recommendation is to upgrade to at least 1.8.3. See issue #216 for more detail.
|
||||||
|
|
||||||
**SECURITY NOTICE:** Some older versions of Go have a security issue in the crypto/elliptic. Recommendation is to upgrade to at least 1.15 See issue [dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more detail.
|
**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided.
|
||||||
|
|
||||||
**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided.
|
|
||||||
|
|
||||||
### Supported Go versions
|
|
||||||
|
|
||||||
Our support of Go versions is aligned with Go's [version release policy](https://golang.org/doc/devel/release#policy).
|
|
||||||
So we will support a major version of Go until there are two newer major releases.
|
|
||||||
We no longer support building jwt-go with unsupported Go versions, as these contain security vulnerabilities
|
|
||||||
which will not be fixed.
|
|
||||||
|
|
||||||
## What the heck is a JWT?
|
## What the heck is a JWT?
|
||||||
|
|
||||||
JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens.
|
JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens.
|
||||||
|
|
||||||
In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](https://datatracker.ietf.org/doc/html/rfc4648) encoded. The last part is the signature, encoded the same way.
|
In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](http://tools.ietf.org/html/rfc4648) encoded. The last part is the signature, encoded the same way.
|
||||||
|
|
||||||
The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used.
|
The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used.
|
||||||
|
|
||||||
The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519) for information about reserved keys and the proper way to add your own.
|
The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [the RFC](http://self-issued.info/docs/draft-jones-json-web-token.html) for information about reserved keys and the proper way to add your own.
|
||||||
|
|
||||||
## What's in the box?
|
## What's in the box?
|
||||||
|
|
||||||
@ -36,31 +27,31 @@ This library supports the parsing and verification as well as the generation and
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
See [the project documentation](https://pkg.go.dev/github.com/golang-jwt/jwt) for examples of usage:
|
See [the project documentation](https://godoc.org/github.com/dgrijalva/jwt-go) for examples of usage:
|
||||||
|
|
||||||
* [Simple example of parsing and validating a token](https://pkg.go.dev/github.com/golang-jwt/jwt#example-Parse-Hmac)
|
* [Simple example of parsing and validating a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac)
|
||||||
* [Simple example of building and signing a token](https://pkg.go.dev/github.com/golang-jwt/jwt#example-New-Hmac)
|
* [Simple example of building and signing a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-New--Hmac)
|
||||||
* [Directory of Examples](https://pkg.go.dev/github.com/golang-jwt/jwt#pkg-examples)
|
* [Directory of Examples](https://godoc.org/github.com/dgrijalva/jwt-go#pkg-examples)
|
||||||
|
|
||||||
## Extensions
|
## Extensions
|
||||||
|
|
||||||
This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`.
|
This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`.
|
||||||
|
|
||||||
Here's an example of an extension that integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS): https://github.com/someone1/gcp-jwt-go
|
Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go
|
||||||
|
|
||||||
## Compliance
|
## Compliance
|
||||||
|
|
||||||
This library was last reviewed to comply with [RTF 7519](https://datatracker.ietf.org/doc/html/rfc7519) dated May 2015 with a few notable differences:
|
This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences:
|
||||||
|
|
||||||
* In order to protect against accidental use of [Unsecured JWTs](https://datatracker.ietf.org/doc/html/rfc7519#section-6), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key.
|
* In order to protect against accidental use of [Unsecured JWTs](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#UnsecuredJWT), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key.
|
||||||
|
|
||||||
## Project Status & Versioning
|
## Project Status & Versioning
|
||||||
|
|
||||||
This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason).
|
This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason).
|
||||||
|
|
||||||
This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `main`. Periodically, versions will be tagged from `main`. You can find all the releases on [the project releases page](https://github.com/golang-jwt/jwt/releases).
|
This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `master`. Periodically, versions will be tagged from `master`. You can find all the releases on [the project releases page](https://github.com/dgrijalva/jwt-go/releases).
|
||||||
|
|
||||||
While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/golang-jwt/jwt.v3`. It will do the right thing WRT semantic versioning.
|
While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v3`. It will do the right thing WRT semantic versioning.
|
||||||
|
|
||||||
**BREAKING CHANGES:***
|
**BREAKING CHANGES:***
|
||||||
* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code.
|
* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code.
|
||||||
@ -88,9 +79,9 @@ Asymmetric signing methods, such as RSA, use different keys for signing and veri
|
|||||||
|
|
||||||
Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones:
|
Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones:
|
||||||
|
|
||||||
* The [HMAC signing method](https://pkg.go.dev/github.com/golang-jwt/jwt#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation
|
* The [HMAC signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation
|
||||||
* The [RSA signing method](https://pkg.go.dev/github.com/golang-jwt/jwt#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation
|
* The [RSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation
|
||||||
* The [ECDSA signing method](https://pkg.go.dev/github.com/golang-jwt/jwt#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation
|
* The [ECDSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation
|
||||||
|
|
||||||
### JWT and OAuth
|
### JWT and OAuth
|
||||||
|
|
||||||
@ -102,12 +93,8 @@ Without going too far down the rabbit hole, here's a description of the interact
|
|||||||
* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
|
* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
|
||||||
* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
|
* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
|
||||||
|
|
||||||
### Troubleshooting
|
|
||||||
|
|
||||||
This library uses descriptive error messages whenever possible. If you are not getting the expected result, have a look at the errors. The most common place people get stuck is providing the correct type of key to the parser. See the above section on signing methods and key types.
|
|
||||||
|
|
||||||
## More
|
## More
|
||||||
|
|
||||||
Documentation can be found [on pkg.go.dev](https://pkg.go.dev/github.com/golang-jwt/jwt).
|
Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
|
||||||
|
|
||||||
The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation.
|
The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation.
|
@ -1,18 +1,5 @@
|
|||||||
## `jwt-go` Version History
|
## `jwt-go` Version History
|
||||||
|
|
||||||
#### 3.2.2
|
|
||||||
|
|
||||||
* Starting from this release, we are adopting the policy to support the most 2 recent versions of Go currently available. By the time of this release, this is Go 1.15 and 1.16 ([#28](https://github.com/golang-jwt/jwt/pull/28)).
|
|
||||||
* Fixed a potential issue that could occur when the verification of `exp`, `iat` or `nbf` was not required and contained invalid contents, i.e. non-numeric/date. Thanks for @thaJeztah for making us aware of that and @giorgos-f3 for originally reporting it to the formtech fork ([#40](https://github.com/golang-jwt/jwt/pull/40)).
|
|
||||||
* Added support for EdDSA / ED25519 ([#36](https://github.com/golang-jwt/jwt/pull/36)).
|
|
||||||
* Optimized allocations ([#33](https://github.com/golang-jwt/jwt/pull/33)).
|
|
||||||
|
|
||||||
#### 3.2.1
|
|
||||||
|
|
||||||
* **Import Path Change**: See MIGRATION_GUIDE.md for tips on updating your code
|
|
||||||
* Changed the import path from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt`
|
|
||||||
* Fixed type confusing issue between `string` and `[]string` in `VerifyAudience` ([#12](https://github.com/golang-jwt/jwt/pull/12)). This fixes CVE-2020-26160
|
|
||||||
|
|
||||||
#### 3.2.0
|
#### 3.2.0
|
||||||
|
|
||||||
* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
|
* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
|
||||||
@ -128,4 +115,4 @@ It is likely the only integration change required here will be to change `func(t
|
|||||||
* First versioned release
|
* First versioned release
|
||||||
* API stabilized
|
* API stabilized
|
||||||
* Supports creating, signing, parsing, and validating JWT tokens
|
* Supports creating, signing, parsing, and validating JWT tokens
|
||||||
* Supports RS256 and HS256 signing methods
|
* Supports RS256 and HS256 signing methods
|
@ -35,18 +35,18 @@ func (c StandardClaims) Valid() error {
|
|||||||
|
|
||||||
// The claims below are optional, by default, so if they are set to the
|
// The claims below are optional, by default, so if they are set to the
|
||||||
// default value in Go, let's not fail the verification for them.
|
// default value in Go, let's not fail the verification for them.
|
||||||
if !c.VerifyExpiresAt(now, false) {
|
if c.VerifyExpiresAt(now, false) == false {
|
||||||
delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0))
|
delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0))
|
||||||
vErr.Inner = fmt.Errorf("token is expired by %v", delta)
|
vErr.Inner = fmt.Errorf("token is expired by %v", delta)
|
||||||
vErr.Errors |= ValidationErrorExpired
|
vErr.Errors |= ValidationErrorExpired
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.VerifyIssuedAt(now, false) {
|
if c.VerifyIssuedAt(now, false) == false {
|
||||||
vErr.Inner = fmt.Errorf("Token used before issued")
|
vErr.Inner = fmt.Errorf("Token used before issued")
|
||||||
vErr.Errors |= ValidationErrorIssuedAt
|
vErr.Errors |= ValidationErrorIssuedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.VerifyNotBefore(now, false) {
|
if c.VerifyNotBefore(now, false) == false {
|
||||||
vErr.Inner = fmt.Errorf("token is not valid yet")
|
vErr.Inner = fmt.Errorf("token is not valid yet")
|
||||||
vErr.Errors |= ValidationErrorNotValidYet
|
vErr.Errors |= ValidationErrorNotValidYet
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ func (c StandardClaims) Valid() error {
|
|||||||
// Compares the aud claim against cmp.
|
// Compares the aud claim against cmp.
|
||||||
// If required is false, this method will return true if the value matches or is unset
|
// If required is false, this method will return true if the value matches or is unset
|
||||||
func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
|
func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
|
||||||
return verifyAud([]string{c.Audience}, cmp, req)
|
return verifyAud(c.Audience, cmp, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compares the exp claim against cmp.
|
// Compares the exp claim against cmp.
|
||||||
@ -90,27 +90,15 @@ func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
|
|||||||
|
|
||||||
// ----- helpers
|
// ----- helpers
|
||||||
|
|
||||||
func verifyAud(aud []string, cmp string, required bool) bool {
|
func verifyAud(aud string, cmp string, required bool) bool {
|
||||||
if len(aud) == 0 {
|
if aud == "" {
|
||||||
return !required
|
return !required
|
||||||
}
|
}
|
||||||
// use a var here to keep constant time compare when looping over a number of claims
|
if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 {
|
||||||
result := false
|
return true
|
||||||
|
} else {
|
||||||
var stringClaims string
|
return false
|
||||||
for _, a := range aud {
|
|
||||||
if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 {
|
|
||||||
result = true
|
|
||||||
}
|
|
||||||
stringClaims = stringClaims + a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// case where "" is sent in one or many aud claims
|
|
||||||
if len(stringClaims) == 0 {
|
|
||||||
return !required
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyExp(exp int64, now int64, required bool) bool {
|
func verifyExp(exp int64, now int64, required bool) bool {
|
0
vendor/github.com/golang-jwt/jwt/doc.go → vendor/github.com/dgrijalva/jwt-go/doc.go
generated
vendored
0
vendor/github.com/golang-jwt/jwt/doc.go → vendor/github.com/dgrijalva/jwt-go/doc.go
generated
vendored
24
vendor/github.com/golang-jwt/jwt/ecdsa.go → vendor/github.com/dgrijalva/jwt-go/ecdsa.go
generated
vendored
24
vendor/github.com/golang-jwt/jwt/ecdsa.go → vendor/github.com/dgrijalva/jwt-go/ecdsa.go
generated
vendored
@ -88,11 +88,11 @@ func (m *SigningMethodECDSA) Verify(signingString, signature string, key interfa
|
|||||||
hasher.Write([]byte(signingString))
|
hasher.Write([]byte(signingString))
|
||||||
|
|
||||||
// Verify the signature
|
// Verify the signature
|
||||||
if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus {
|
if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus == true {
|
||||||
return nil
|
return nil
|
||||||
|
} else {
|
||||||
|
return ErrECDSAVerification
|
||||||
}
|
}
|
||||||
|
|
||||||
return ErrECDSAVerification
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements the Sign method from SigningMethod
|
// Implements the Sign method from SigningMethod
|
||||||
@ -128,12 +128,18 @@ func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string
|
|||||||
keyBytes += 1
|
keyBytes += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// We serialize the outputs (r and s) into big-endian byte arrays
|
// We serialize the outpus (r and s) into big-endian byte arrays and pad
|
||||||
// padded with zeros on the left to make sure the sizes work out.
|
// them with zeros on the left to make sure the sizes work out. Both arrays
|
||||||
// Output must be 2*keyBytes long.
|
// must be keyBytes long, and the output must be 2*keyBytes long.
|
||||||
out := make([]byte, 2*keyBytes)
|
rBytes := r.Bytes()
|
||||||
r.FillBytes(out[0:keyBytes]) // r is assigned to the first half of output.
|
rBytesPadded := make([]byte, keyBytes)
|
||||||
s.FillBytes(out[keyBytes:]) // s is assigned to the second half of output.
|
copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
|
||||||
|
|
||||||
|
sBytes := s.Bytes()
|
||||||
|
sBytesPadded := make([]byte, keyBytes)
|
||||||
|
copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
|
||||||
|
|
||||||
|
out := append(rBytesPadded, sBytesPadded...)
|
||||||
|
|
||||||
return EncodeSegment(out), nil
|
return EncodeSegment(out), nil
|
||||||
} else {
|
} else {
|
@ -25,9 +25,7 @@ func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
|
|||||||
// Parse the key
|
// Parse the key
|
||||||
var parsedKey interface{}
|
var parsedKey interface{}
|
||||||
if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
|
if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
|
||||||
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var pkey *ecdsa.PrivateKey
|
var pkey *ecdsa.PrivateKey
|
@ -10,59 +10,37 @@ import (
|
|||||||
// This is the default claims type if you don't supply one
|
// This is the default claims type if you don't supply one
|
||||||
type MapClaims map[string]interface{}
|
type MapClaims map[string]interface{}
|
||||||
|
|
||||||
// VerifyAudience Compares the aud claim against cmp.
|
// Compares the aud claim against cmp.
|
||||||
// If required is false, this method will return true if the value matches or is unset
|
// If required is false, this method will return true if the value matches or is unset
|
||||||
func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
|
func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
|
||||||
var aud []string
|
aud, _ := m["aud"].(string)
|
||||||
switch v := m["aud"].(type) {
|
|
||||||
case string:
|
|
||||||
aud = append(aud, v)
|
|
||||||
case []string:
|
|
||||||
aud = v
|
|
||||||
case []interface{}:
|
|
||||||
for _, a := range v {
|
|
||||||
vs, ok := a.(string)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
aud = append(aud, vs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return verifyAud(aud, cmp, req)
|
return verifyAud(aud, cmp, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compares the exp claim against cmp.
|
// Compares the exp claim against cmp.
|
||||||
// If required is false, this method will return true if the value matches or is unset
|
// If required is false, this method will return true if the value matches or is unset
|
||||||
func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
|
func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
|
||||||
exp, ok := m["exp"]
|
switch exp := m["exp"].(type) {
|
||||||
if !ok {
|
|
||||||
return !req
|
|
||||||
}
|
|
||||||
switch expType := exp.(type) {
|
|
||||||
case float64:
|
case float64:
|
||||||
return verifyExp(int64(expType), cmp, req)
|
return verifyExp(int64(exp), cmp, req)
|
||||||
case json.Number:
|
case json.Number:
|
||||||
v, _ := expType.Int64()
|
v, _ := exp.Int64()
|
||||||
return verifyExp(v, cmp, req)
|
return verifyExp(v, cmp, req)
|
||||||
}
|
}
|
||||||
return false
|
return req == false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compares the iat claim against cmp.
|
// Compares the iat claim against cmp.
|
||||||
// If required is false, this method will return true if the value matches or is unset
|
// If required is false, this method will return true if the value matches or is unset
|
||||||
func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
|
func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
|
||||||
iat, ok := m["iat"]
|
switch iat := m["iat"].(type) {
|
||||||
if !ok {
|
|
||||||
return !req
|
|
||||||
}
|
|
||||||
switch iatType := iat.(type) {
|
|
||||||
case float64:
|
case float64:
|
||||||
return verifyIat(int64(iatType), cmp, req)
|
return verifyIat(int64(iat), cmp, req)
|
||||||
case json.Number:
|
case json.Number:
|
||||||
v, _ := iatType.Int64()
|
v, _ := iat.Int64()
|
||||||
return verifyIat(v, cmp, req)
|
return verifyIat(v, cmp, req)
|
||||||
}
|
}
|
||||||
return false
|
return req == false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compares the iss claim against cmp.
|
// Compares the iss claim against cmp.
|
||||||
@ -75,18 +53,14 @@ func (m MapClaims) VerifyIssuer(cmp string, req bool) bool {
|
|||||||
// Compares the nbf claim against cmp.
|
// Compares the nbf claim against cmp.
|
||||||
// If required is false, this method will return true if the value matches or is unset
|
// If required is false, this method will return true if the value matches or is unset
|
||||||
func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
|
func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
|
||||||
nbf, ok := m["nbf"]
|
switch nbf := m["nbf"].(type) {
|
||||||
if !ok {
|
|
||||||
return !req
|
|
||||||
}
|
|
||||||
switch nbfType := nbf.(type) {
|
|
||||||
case float64:
|
case float64:
|
||||||
return verifyNbf(int64(nbfType), cmp, req)
|
return verifyNbf(int64(nbf), cmp, req)
|
||||||
case json.Number:
|
case json.Number:
|
||||||
v, _ := nbfType.Int64()
|
v, _ := nbf.Int64()
|
||||||
return verifyNbf(v, cmp, req)
|
return verifyNbf(v, cmp, req)
|
||||||
}
|
}
|
||||||
return false
|
return req == false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validates time based claims "exp, iat, nbf".
|
// Validates time based claims "exp, iat, nbf".
|
||||||
@ -97,17 +71,17 @@ func (m MapClaims) Valid() error {
|
|||||||
vErr := new(ValidationError)
|
vErr := new(ValidationError)
|
||||||
now := TimeFunc().Unix()
|
now := TimeFunc().Unix()
|
||||||
|
|
||||||
if !m.VerifyExpiresAt(now, false) {
|
if m.VerifyExpiresAt(now, false) == false {
|
||||||
vErr.Inner = errors.New("Token is expired")
|
vErr.Inner = errors.New("Token is expired")
|
||||||
vErr.Errors |= ValidationErrorExpired
|
vErr.Errors |= ValidationErrorExpired
|
||||||
}
|
}
|
||||||
|
|
||||||
if !m.VerifyIssuedAt(now, false) {
|
if m.VerifyIssuedAt(now, false) == false {
|
||||||
vErr.Inner = errors.New("Token used before issued")
|
vErr.Inner = errors.New("Token used before issued")
|
||||||
vErr.Errors |= ValidationErrorIssuedAt
|
vErr.Errors |= ValidationErrorIssuedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
if !m.VerifyNotBefore(now, false) {
|
if m.VerifyNotBefore(now, false) == false {
|
||||||
vErr.Inner = errors.New("Token is not valid yet")
|
vErr.Inner = errors.New("Token is not valid yet")
|
||||||
vErr.Errors |= ValidationErrorNotValidYet
|
vErr.Errors |= ValidationErrorNotValidYet
|
||||||
}
|
}
|
0
vendor/github.com/golang-jwt/jwt/rsa.go → vendor/github.com/dgrijalva/jwt-go/rsa.go
generated
vendored
0
vendor/github.com/golang-jwt/jwt/rsa.go → vendor/github.com/dgrijalva/jwt-go/rsa.go
generated
vendored
@ -12,14 +12,9 @@ import (
|
|||||||
type SigningMethodRSAPSS struct {
|
type SigningMethodRSAPSS struct {
|
||||||
*SigningMethodRSA
|
*SigningMethodRSA
|
||||||
Options *rsa.PSSOptions
|
Options *rsa.PSSOptions
|
||||||
// VerifyOptions is optional. If set overrides Options for rsa.VerifyPPS.
|
|
||||||
// Used to accept tokens signed with rsa.PSSSaltLengthAuto, what doesn't follow
|
|
||||||
// https://tools.ietf.org/html/rfc7518#section-3.5 but was used previously.
|
|
||||||
// See https://github.com/dgrijalva/jwt-go/issues/285#issuecomment-437451244 for details.
|
|
||||||
VerifyOptions *rsa.PSSOptions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specific instances for RS/PS and company.
|
// Specific instances for RS/PS and company
|
||||||
var (
|
var (
|
||||||
SigningMethodPS256 *SigningMethodRSAPSS
|
SigningMethodPS256 *SigningMethodRSAPSS
|
||||||
SigningMethodPS384 *SigningMethodRSAPSS
|
SigningMethodPS384 *SigningMethodRSAPSS
|
||||||
@ -29,15 +24,13 @@ var (
|
|||||||
func init() {
|
func init() {
|
||||||
// PS256
|
// PS256
|
||||||
SigningMethodPS256 = &SigningMethodRSAPSS{
|
SigningMethodPS256 = &SigningMethodRSAPSS{
|
||||||
SigningMethodRSA: &SigningMethodRSA{
|
&SigningMethodRSA{
|
||||||
Name: "PS256",
|
Name: "PS256",
|
||||||
Hash: crypto.SHA256,
|
Hash: crypto.SHA256,
|
||||||
},
|
},
|
||||||
Options: &rsa.PSSOptions{
|
&rsa.PSSOptions{
|
||||||
SaltLength: rsa.PSSSaltLengthEqualsHash,
|
|
||||||
},
|
|
||||||
VerifyOptions: &rsa.PSSOptions{
|
|
||||||
SaltLength: rsa.PSSSaltLengthAuto,
|
SaltLength: rsa.PSSSaltLengthAuto,
|
||||||
|
Hash: crypto.SHA256,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod {
|
RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod {
|
||||||
@ -46,15 +39,13 @@ func init() {
|
|||||||
|
|
||||||
// PS384
|
// PS384
|
||||||
SigningMethodPS384 = &SigningMethodRSAPSS{
|
SigningMethodPS384 = &SigningMethodRSAPSS{
|
||||||
SigningMethodRSA: &SigningMethodRSA{
|
&SigningMethodRSA{
|
||||||
Name: "PS384",
|
Name: "PS384",
|
||||||
Hash: crypto.SHA384,
|
Hash: crypto.SHA384,
|
||||||
},
|
},
|
||||||
Options: &rsa.PSSOptions{
|
&rsa.PSSOptions{
|
||||||
SaltLength: rsa.PSSSaltLengthEqualsHash,
|
|
||||||
},
|
|
||||||
VerifyOptions: &rsa.PSSOptions{
|
|
||||||
SaltLength: rsa.PSSSaltLengthAuto,
|
SaltLength: rsa.PSSSaltLengthAuto,
|
||||||
|
Hash: crypto.SHA384,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod {
|
RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod {
|
||||||
@ -63,15 +54,13 @@ func init() {
|
|||||||
|
|
||||||
// PS512
|
// PS512
|
||||||
SigningMethodPS512 = &SigningMethodRSAPSS{
|
SigningMethodPS512 = &SigningMethodRSAPSS{
|
||||||
SigningMethodRSA: &SigningMethodRSA{
|
&SigningMethodRSA{
|
||||||
Name: "PS512",
|
Name: "PS512",
|
||||||
Hash: crypto.SHA512,
|
Hash: crypto.SHA512,
|
||||||
},
|
},
|
||||||
Options: &rsa.PSSOptions{
|
&rsa.PSSOptions{
|
||||||
SaltLength: rsa.PSSSaltLengthEqualsHash,
|
|
||||||
},
|
|
||||||
VerifyOptions: &rsa.PSSOptions{
|
|
||||||
SaltLength: rsa.PSSSaltLengthAuto,
|
SaltLength: rsa.PSSSaltLengthAuto,
|
||||||
|
Hash: crypto.SHA512,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod {
|
RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod {
|
||||||
@ -105,12 +94,7 @@ func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interf
|
|||||||
hasher := m.Hash.New()
|
hasher := m.Hash.New()
|
||||||
hasher.Write([]byte(signingString))
|
hasher.Write([]byte(signingString))
|
||||||
|
|
||||||
opts := m.Options
|
return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, m.Options)
|
||||||
if m.VerifyOptions != nil {
|
|
||||||
opts = m.VerifyOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, opts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements the Sign method from SigningMethod
|
// Implements the Sign method from SigningMethod
|
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be a PEM encoded PKCS1 or PKCS8 key")
|
ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key")
|
||||||
ErrNotRSAPrivateKey = errors.New("Key is not a valid RSA private key")
|
ErrNotRSAPrivateKey = errors.New("Key is not a valid RSA private key")
|
||||||
ErrNotRSAPublicKey = errors.New("Key is not a valid RSA public key")
|
ErrNotRSAPublicKey = errors.New("Key is not a valid RSA public key")
|
||||||
)
|
)
|
10
vendor/github.com/golang-jwt/jwt/token.go → vendor/github.com/dgrijalva/jwt-go/token.go
generated
vendored
10
vendor/github.com/golang-jwt/jwt/token.go → vendor/github.com/dgrijalva/jwt-go/token.go
generated
vendored
@ -65,7 +65,7 @@ func (t *Token) SignedString(key interface{}) (string, error) {
|
|||||||
func (t *Token) SigningString() (string, error) {
|
func (t *Token) SigningString() (string, error) {
|
||||||
var err error
|
var err error
|
||||||
parts := make([]string, 2)
|
parts := make([]string, 2)
|
||||||
for i := range parts {
|
for i, _ := range parts {
|
||||||
var jsonValue []byte
|
var jsonValue []byte
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
if jsonValue, err = json.Marshal(t.Header); err != nil {
|
if jsonValue, err = json.Marshal(t.Header); err != nil {
|
||||||
@ -95,10 +95,14 @@ func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token
|
|||||||
|
|
||||||
// Encode JWT specific base64url encoding with padding stripped
|
// Encode JWT specific base64url encoding with padding stripped
|
||||||
func EncodeSegment(seg []byte) string {
|
func EncodeSegment(seg []byte) string {
|
||||||
return base64.RawURLEncoding.EncodeToString(seg)
|
return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode JWT specific base64url encoding with padding stripped
|
// Decode JWT specific base64url encoding with padding stripped
|
||||||
func DecodeSegment(seg string) ([]byte, error) {
|
func DecodeSegment(seg string) ([]byte, error) {
|
||||||
return base64.RawURLEncoding.DecodeString(seg)
|
if l := len(seg) % 4; l > 0 {
|
||||||
|
seg += strings.Repeat("=", 4-l)
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.URLEncoding.DecodeString(seg)
|
||||||
}
|
}
|
8
vendor/github.com/go-acme/lego/v4/acme/api/account.go
generated
vendored
8
vendor/github.com/go-acme/lego/v4/acme/api/account.go
generated
vendored
@ -16,7 +16,7 @@ func (a *AccountService) New(req acme.Account) (acme.ExtendedAccount, error) {
|
|||||||
resp, err := a.core.post(a.core.GetDirectory().NewAccountURL, req, &account)
|
resp, err := a.core.post(a.core.GetDirectory().NewAccountURL, req, &account)
|
||||||
location := getLocation(resp)
|
location := getLocation(resp)
|
||||||
|
|
||||||
if location != "" {
|
if len(location) > 0 {
|
||||||
a.core.jws.SetKid(location)
|
a.core.jws.SetKid(location)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ func (a *AccountService) NewEAB(accMsg acme.Account, kid, hmacEncoded string) (a
|
|||||||
|
|
||||||
// Get Retrieves an account.
|
// Get Retrieves an account.
|
||||||
func (a *AccountService) Get(accountURL string) (acme.Account, error) {
|
func (a *AccountService) Get(accountURL string) (acme.Account, error) {
|
||||||
if accountURL == "" {
|
if len(accountURL) == 0 {
|
||||||
return acme.Account{}, errors.New("account[get]: empty URL")
|
return acme.Account{}, errors.New("account[get]: empty URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ func (a *AccountService) Get(accountURL string) (acme.Account, error) {
|
|||||||
|
|
||||||
// Update Updates an account.
|
// Update Updates an account.
|
||||||
func (a *AccountService) Update(accountURL string, req acme.Account) (acme.Account, error) {
|
func (a *AccountService) Update(accountURL string, req acme.Account) (acme.Account, error) {
|
||||||
if accountURL == "" {
|
if len(accountURL) == 0 {
|
||||||
return acme.Account{}, errors.New("account[update]: empty URL")
|
return acme.Account{}, errors.New("account[update]: empty URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ func (a *AccountService) Update(accountURL string, req acme.Account) (acme.Accou
|
|||||||
|
|
||||||
// Deactivate Deactivates an account.
|
// Deactivate Deactivates an account.
|
||||||
func (a *AccountService) Deactivate(accountURL string) error {
|
func (a *AccountService) Deactivate(accountURL string) error {
|
||||||
if accountURL == "" {
|
if len(accountURL) == 0 {
|
||||||
return errors.New("account[deactivate]: empty URL")
|
return errors.New("account[deactivate]: empty URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
vendor/github.com/go-acme/lego/v4/acme/api/api.go
generated
vendored
12
vendor/github.com/go-acme/lego/v4/acme/api/api.go
generated
vendored
@ -2,6 +2,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@ -70,7 +71,7 @@ func (a *Core) post(uri string, reqBody, response interface{}) (*http.Response,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// postAsGet performs an HTTP POST ("POST-as-GET") request.
|
// postAsGet performs an HTTP POST ("POST-as-GET") request.
|
||||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-6.3
|
// https://tools.ietf.org/html/rfc8555#section-6.3
|
||||||
func (a *Core) postAsGet(uri string, response interface{}) (*http.Response, error) {
|
func (a *Core) postAsGet(uri string, response interface{}) (*http.Response, error) {
|
||||||
return a.retrievablePost(uri, []byte{}, response)
|
return a.retrievablePost(uri, []byte{}, response)
|
||||||
}
|
}
|
||||||
@ -82,6 +83,8 @@ func (a *Core) retrievablePost(uri string, content []byte, response interface{})
|
|||||||
bo.MaxInterval = 5 * time.Second
|
bo.MaxInterval = 5 * time.Second
|
||||||
bo.MaxElapsedTime = 20 * time.Second
|
bo.MaxElapsedTime = 20 * time.Second
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
var err error
|
var err error
|
||||||
@ -93,7 +96,8 @@ func (a *Core) retrievablePost(uri string, content []byte, response interface{})
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return backoff.Permanent(err)
|
cancel()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -103,7 +107,7 @@ func (a *Core) retrievablePost(uri string, content []byte, response interface{})
|
|||||||
log.Infof("retry due to: %v", err)
|
log.Infof("retry due to: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := backoff.RetryNotify(operation, bo, notify)
|
err := backoff.RetryNotify(operation, backoff.WithContext(bo, ctx), notify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
@ -117,7 +121,7 @@ func (a *Core) signedPost(uri string, content []byte, response interface{}) (*ht
|
|||||||
return nil, fmt.Errorf("failed to post JWS message: failed to sign content: %w", err)
|
return nil, fmt.Errorf("failed to post JWS message: failed to sign content: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
signedBody := bytes.NewBufferString(signedContent.FullSerialize())
|
signedBody := bytes.NewBuffer([]byte(signedContent.FullSerialize()))
|
||||||
|
|
||||||
resp, err := a.doer.Post(uri, signedBody, "application/jose+json", response)
|
resp, err := a.doer.Post(uri, signedBody, "application/jose+json", response)
|
||||||
|
|
||||||
|
4
vendor/github.com/go-acme/lego/v4/acme/api/authorization.go
generated
vendored
4
vendor/github.com/go-acme/lego/v4/acme/api/authorization.go
generated
vendored
@ -10,7 +10,7 @@ type AuthorizationService service
|
|||||||
|
|
||||||
// Get Gets an authorization.
|
// Get Gets an authorization.
|
||||||
func (c *AuthorizationService) Get(authzURL string) (acme.Authorization, error) {
|
func (c *AuthorizationService) Get(authzURL string) (acme.Authorization, error) {
|
||||||
if authzURL == "" {
|
if len(authzURL) == 0 {
|
||||||
return acme.Authorization{}, errors.New("authorization[get]: empty URL")
|
return acme.Authorization{}, errors.New("authorization[get]: empty URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ func (c *AuthorizationService) Get(authzURL string) (acme.Authorization, error)
|
|||||||
|
|
||||||
// Deactivate Deactivates an authorization.
|
// Deactivate Deactivates an authorization.
|
||||||
func (c *AuthorizationService) Deactivate(authzURL string) error {
|
func (c *AuthorizationService) Deactivate(authzURL string) error {
|
||||||
if authzURL == "" {
|
if len(authzURL) == 0 {
|
||||||
return errors.New("authorization[deactivate]: empty URL")
|
return errors.New("authorization[deactivate]: empty URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
117
vendor/github.com/go-acme/lego/v4/acme/api/certificate.go
generated
vendored
117
vendor/github.com/go-acme/lego/v4/acme/api/certificate.go
generated
vendored
@ -1,11 +1,10 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/acme"
|
"github.com/go-acme/lego/v4/acme"
|
||||||
@ -21,87 +20,19 @@ type CertificateService service
|
|||||||
// Get Returns the certificate and the issuer certificate.
|
// Get Returns the certificate and the issuer certificate.
|
||||||
// 'bundle' is only applied if the issuer is provided by the 'up' link.
|
// 'bundle' is only applied if the issuer is provided by the 'up' link.
|
||||||
func (c *CertificateService) Get(certURL string, bundle bool) ([]byte, []byte, error) {
|
func (c *CertificateService) Get(certURL string, bundle bool) ([]byte, []byte, error) {
|
||||||
cert, _, err := c.get(certURL, bundle)
|
cert, up, err := c.get(certURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return cert.Cert, cert.Issuer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAll the certificates and the alternate certificates.
|
|
||||||
// bundle' is only applied if the issuer is provided by the 'up' link.
|
|
||||||
func (c *CertificateService) GetAll(certURL string, bundle bool) (map[string]*acme.RawCertificate, error) {
|
|
||||||
cert, headers, err := c.get(certURL, bundle)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
certs := map[string]*acme.RawCertificate{certURL: cert}
|
|
||||||
|
|
||||||
// URLs of "alternate" link relation
|
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4.2
|
|
||||||
alts := getLinks(headers, "alternate")
|
|
||||||
|
|
||||||
for _, alt := range alts {
|
|
||||||
altCert, _, err := c.get(alt, bundle)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
certs[alt] = altCert
|
|
||||||
}
|
|
||||||
|
|
||||||
return certs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Revoke Revokes a certificate.
|
|
||||||
func (c *CertificateService) Revoke(req acme.RevokeCertMessage) error {
|
|
||||||
_, err := c.core.post(c.core.GetDirectory().RevokeCertURL, req, nil)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// get Returns the certificate and the "up" link.
|
|
||||||
func (c *CertificateService) get(certURL string, bundle bool) (*acme.RawCertificate, http.Header, error) {
|
|
||||||
if certURL == "" {
|
|
||||||
return nil, nil, errors.New("certificate[get]: empty URL")
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.core.postAsGet(certURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := io.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
|
||||||
if err != nil {
|
|
||||||
return nil, resp.Header, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cert := c.getCertificateChain(data, resp.Header, bundle, certURL)
|
|
||||||
|
|
||||||
return cert, resp.Header, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCertificateChain Returns the certificate and the issuer certificate.
|
|
||||||
func (c *CertificateService) getCertificateChain(cert []byte, headers http.Header, bundle bool, certURL string) *acme.RawCertificate {
|
|
||||||
// Get issuerCert from bundled response from Let's Encrypt
|
// Get issuerCert from bundled response from Let's Encrypt
|
||||||
// See https://community.letsencrypt.org/t/acme-v2-no-up-link-in-response/64962
|
// See https://community.letsencrypt.org/t/acme-v2-no-up-link-in-response/64962
|
||||||
_, issuer := pem.Decode(cert)
|
_, issuer := pem.Decode(cert)
|
||||||
if issuer != nil {
|
if issuer != nil {
|
||||||
// If bundle is false, we want to return a single certificate.
|
return cert, issuer, nil
|
||||||
// To do this, we remove the issuer cert(s) from the issued cert.
|
|
||||||
if !bundle {
|
|
||||||
cert = bytes.TrimSuffix(cert, issuer)
|
|
||||||
}
|
|
||||||
return &acme.RawCertificate{Cert: cert, Issuer: issuer}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The issuer certificate link may be supplied via an "up" link
|
issuer, err = c.getIssuerFromLink(up)
|
||||||
// in the response headers of a new certificate.
|
|
||||||
// See https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4.2
|
|
||||||
up := getLink(headers, "up")
|
|
||||||
|
|
||||||
issuer, err := c.getIssuerFromLink(up)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If we fail to acquire the issuer cert, return the issued certificate - do not fail.
|
// If we fail to acquire the issuer cert, return the issued certificate - do not fail.
|
||||||
log.Warnf("acme: Could not bundle issuer certificate [%s]: %v", certURL, err)
|
log.Warnf("acme: Could not bundle issuer certificate [%s]: %v", certURL, err)
|
||||||
@ -113,26 +44,56 @@ func (c *CertificateService) getCertificateChain(cert []byte, headers http.Heade
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &acme.RawCertificate{Cert: cert, Issuer: issuer}
|
return cert, issuer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revoke Revokes a certificate.
|
||||||
|
func (c *CertificateService) Revoke(req acme.RevokeCertMessage) error {
|
||||||
|
_, err := c.core.post(c.core.GetDirectory().RevokeCertURL, req, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// get Returns the certificate and the "up" link.
|
||||||
|
func (c *CertificateService) get(certURL string) ([]byte, string, error) {
|
||||||
|
if len(certURL) == 0 {
|
||||||
|
return nil, "", errors.New("certificate[get]: empty URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.core.postAsGet(certURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := ioutil.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The issuer certificate link may be supplied via an "up" link
|
||||||
|
// in the response headers of a new certificate.
|
||||||
|
// See https://tools.ietf.org/html/rfc8555#section-7.4.2
|
||||||
|
up := getLink(resp.Header, "up")
|
||||||
|
|
||||||
|
return cert, up, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getIssuerFromLink requests the issuer certificate.
|
// getIssuerFromLink requests the issuer certificate.
|
||||||
func (c *CertificateService) getIssuerFromLink(up string) ([]byte, error) {
|
func (c *CertificateService) getIssuerFromLink(up string) ([]byte, error) {
|
||||||
if up == "" {
|
if len(up) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("acme: Requesting issuer cert from %s", up)
|
log.Infof("acme: Requesting issuer cert from %s", up)
|
||||||
|
|
||||||
cert, _, err := c.get(up, false)
|
cert, _, err := c.get(up)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = x509.ParseCertificate(cert.Cert)
|
_, err = x509.ParseCertificate(cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return certcrypto.PEMEncode(certcrypto.DERCertificateBytes(cert.Cert)), nil
|
return certcrypto.PEMEncode(certcrypto.DERCertificateBytes(cert)), nil
|
||||||
}
|
}
|
||||||
|
4
vendor/github.com/go-acme/lego/v4/acme/api/challenge.go
generated
vendored
4
vendor/github.com/go-acme/lego/v4/acme/api/challenge.go
generated
vendored
@ -10,7 +10,7 @@ type ChallengeService service
|
|||||||
|
|
||||||
// New Creates a challenge.
|
// New Creates a challenge.
|
||||||
func (c *ChallengeService) New(chlgURL string) (acme.ExtendedChallenge, error) {
|
func (c *ChallengeService) New(chlgURL string) (acme.ExtendedChallenge, error) {
|
||||||
if chlgURL == "" {
|
if len(chlgURL) == 0 {
|
||||||
return acme.ExtendedChallenge{}, errors.New("challenge[new]: empty URL")
|
return acme.ExtendedChallenge{}, errors.New("challenge[new]: empty URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ func (c *ChallengeService) New(chlgURL string) (acme.ExtendedChallenge, error) {
|
|||||||
|
|
||||||
// Get Gets a challenge.
|
// Get Gets a challenge.
|
||||||
func (c *ChallengeService) Get(chlgURL string) (acme.ExtendedChallenge, error) {
|
func (c *ChallengeService) Get(chlgURL string) (acme.ExtendedChallenge, error) {
|
||||||
if chlgURL == "" {
|
if len(chlgURL) == 0 {
|
||||||
return acme.ExtendedChallenge{}, errors.New("challenge[get]: empty URL")
|
return acme.ExtendedChallenge{}, errors.New("challenge[get]: empty URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
vendor/github.com/go-acme/lego/v4/acme/api/internal/nonces/nonce_manager.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/acme/api/internal/nonces/nonce_manager.go
generated
vendored
@ -63,7 +63,7 @@ func (n *Manager) getNonce() (string, error) {
|
|||||||
return GetFromResponse(resp)
|
return GetFromResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFromResponse Extracts a nonce from an HTTP response.
|
// GetFromResponse Extracts a nonce from a HTTP response.
|
||||||
func GetFromResponse(resp *http.Response) (string, error) {
|
func GetFromResponse(resp *http.Response) (string, error) {
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
return "", errors.New("nil response")
|
return "", errors.New("nil response")
|
||||||
|
2
vendor/github.com/go-acme/lego/v4/acme/api/internal/secure/jws.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/acme/api/internal/secure/jws.go
generated
vendored
@ -9,7 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/acme/api/internal/nonces"
|
"github.com/go-acme/lego/v4/acme/api/internal/nonces"
|
||||||
jose "github.com/go-jose/go-jose/v4"
|
jose "gopkg.in/square/go-jose.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// JWS Represents a JWS.
|
// JWS Represents a JWS.
|
||||||
|
9
vendor/github.com/go-acme/lego/v4/acme/api/internal/sender/sender.go
generated
vendored
9
vendor/github.com/go-acme/lego/v4/acme/api/internal/sender/sender.go
generated
vendored
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
@ -95,7 +96,7 @@ func (d *Doer) do(req *http.Request, response interface{}) (*http.Response, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
if response != nil {
|
if response != nil {
|
||||||
raw, err := io.ReadAll(resp.Body)
|
raw, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
@ -119,7 +120,7 @@ func (d *Doer) formatUserAgent() string {
|
|||||||
|
|
||||||
func checkError(req *http.Request, resp *http.Response) error {
|
func checkError(req *http.Request, resp *http.Response) error {
|
||||||
if resp.StatusCode >= http.StatusBadRequest {
|
if resp.StatusCode >= http.StatusBadRequest {
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%d :: %s :: %s :: %w", resp.StatusCode, req.Method, req.URL, err)
|
return fmt.Errorf("%d :: %s :: %s :: %w", resp.StatusCode, req.Method, req.URL, err)
|
||||||
}
|
}
|
||||||
@ -133,10 +134,6 @@ func checkError(req *http.Request, resp *http.Response) error {
|
|||||||
errorDetails.Method = req.Method
|
errorDetails.Method = req.Method
|
||||||
errorDetails.URL = req.URL.String()
|
errorDetails.URL = req.URL.String()
|
||||||
|
|
||||||
if errorDetails.HTTPStatus == 0 {
|
|
||||||
errorDetails.HTTPStatus = resp.StatusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for errors we handle specifically
|
// Check for errors we handle specifically
|
||||||
if errorDetails.HTTPStatus == http.StatusBadRequest && errorDetails.Type == acme.BadNonceErr {
|
if errorDetails.HTTPStatus == http.StatusBadRequest && errorDetails.Type == acme.BadNonceErr {
|
||||||
return &acme.NonceError{ProblemDetails: errorDetails}
|
return &acme.NonceError{ProblemDetails: errorDetails}
|
||||||
|
2
vendor/github.com/go-acme/lego/v4/acme/api/internal/sender/useragent.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/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/4.17.4"
|
ourUserAgent = "xenolf-acme/4.1.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
|
||||||
|
60
vendor/github.com/go-acme/lego/v4/acme/api/order.go
generated
vendored
60
vendor/github.com/go-acme/lego/v4/acme/api/order.go
generated
vendored
@ -3,58 +3,21 @@ package api
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/acme"
|
"github.com/go-acme/lego/v4/acme"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OrderOptions used to create an order (optional).
|
|
||||||
type OrderOptions struct {
|
|
||||||
NotBefore time.Time
|
|
||||||
NotAfter time.Time
|
|
||||||
// A string uniquely identifying a previously-issued certificate which this
|
|
||||||
// order is intended to replace.
|
|
||||||
// - https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-5
|
|
||||||
ReplacesCertID string
|
|
||||||
}
|
|
||||||
|
|
||||||
type OrderService service
|
type OrderService service
|
||||||
|
|
||||||
// New Creates a new order.
|
// New Creates a new order.
|
||||||
func (o *OrderService) New(domains []string) (acme.ExtendedOrder, error) {
|
func (o *OrderService) New(domains []string) (acme.ExtendedOrder, error) {
|
||||||
return o.NewWithOptions(domains, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWithOptions Creates a new order.
|
|
||||||
func (o *OrderService) NewWithOptions(domains []string, opts *OrderOptions) (acme.ExtendedOrder, error) {
|
|
||||||
var identifiers []acme.Identifier
|
var identifiers []acme.Identifier
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
ident := acme.Identifier{Value: domain, Type: "dns"}
|
identifiers = append(identifiers, acme.Identifier{Type: "dns", Value: domain})
|
||||||
|
|
||||||
if net.ParseIP(domain) != nil {
|
|
||||||
ident.Type = "ip"
|
|
||||||
}
|
|
||||||
|
|
||||||
identifiers = append(identifiers, ident)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
orderReq := acme.Order{Identifiers: identifiers}
|
orderReq := acme.Order{Identifiers: identifiers}
|
||||||
|
|
||||||
if opts != nil {
|
|
||||||
if !opts.NotAfter.IsZero() {
|
|
||||||
orderReq.NotAfter = opts.NotAfter.Format(time.RFC3339)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !opts.NotBefore.IsZero() {
|
|
||||||
orderReq.NotBefore = opts.NotBefore.Format(time.RFC3339)
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.core.GetDirectory().RenewalInfo != "" {
|
|
||||||
orderReq.Replaces = opts.ReplacesCertID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var order acme.Order
|
var order acme.Order
|
||||||
resp, err := o.core.post(o.core.GetDirectory().NewOrderURL, orderReq, &order)
|
resp, err := o.core.post(o.core.GetDirectory().NewOrderURL, orderReq, &order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -62,24 +25,28 @@ func (o *OrderService) NewWithOptions(domains []string, opts *OrderOptions) (acm
|
|||||||
}
|
}
|
||||||
|
|
||||||
return acme.ExtendedOrder{
|
return acme.ExtendedOrder{
|
||||||
Order: order,
|
Order: order,
|
||||||
Location: resp.Header.Get("Location"),
|
Location: resp.Header.Get("Location"),
|
||||||
|
AlternateChainLinks: getLinks(resp.Header, "alternate"),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Gets an order.
|
// Get Gets an order.
|
||||||
func (o *OrderService) Get(orderURL string) (acme.ExtendedOrder, error) {
|
func (o *OrderService) Get(orderURL string) (acme.ExtendedOrder, error) {
|
||||||
if orderURL == "" {
|
if len(orderURL) == 0 {
|
||||||
return acme.ExtendedOrder{}, errors.New("order[get]: empty URL")
|
return acme.ExtendedOrder{}, errors.New("order[get]: empty URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
var order acme.Order
|
var order acme.Order
|
||||||
_, err := o.core.postAsGet(orderURL, &order)
|
resp, err := o.core.postAsGet(orderURL, &order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return acme.ExtendedOrder{}, err
|
return acme.ExtendedOrder{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return acme.ExtendedOrder{Order: order}, nil
|
return acme.ExtendedOrder{
|
||||||
|
Order: order,
|
||||||
|
AlternateChainLinks: getLinks(resp.Header, "alternate"),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateForCSR Updates an order for a CSR.
|
// UpdateForCSR Updates an order for a CSR.
|
||||||
@ -89,7 +56,7 @@ func (o *OrderService) UpdateForCSR(orderURL string, csr []byte) (acme.ExtendedO
|
|||||||
}
|
}
|
||||||
|
|
||||||
var order acme.Order
|
var order acme.Order
|
||||||
_, err := o.core.post(orderURL, csrMsg, &order)
|
resp, err := o.core.post(orderURL, csrMsg, &order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return acme.ExtendedOrder{}, err
|
return acme.ExtendedOrder{}, err
|
||||||
}
|
}
|
||||||
@ -98,5 +65,8 @@ func (o *OrderService) UpdateForCSR(orderURL string, csr []byte) (acme.ExtendedO
|
|||||||
return acme.ExtendedOrder{}, order.Error
|
return acme.ExtendedOrder{}, order.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
return acme.ExtendedOrder{Order: order}, nil
|
return acme.ExtendedOrder{
|
||||||
|
Order: order,
|
||||||
|
AlternateChainLinks: getLinks(resp.Header, "alternate"),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
28
vendor/github.com/go-acme/lego/v4/acme/api/renewal.go
generated
vendored
28
vendor/github.com/go-acme/lego/v4/acme/api/renewal.go
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrNoARI is returned when the server does not advertise a renewal info endpoint.
|
|
||||||
var ErrNoARI = errors.New("renewalInfo[get/post]: server does not advertise a renewal info endpoint")
|
|
||||||
|
|
||||||
// GetRenewalInfo GETs renewal information for a certificate from the renewalInfo endpoint.
|
|
||||||
// This is used to determine if a certificate needs to be renewed.
|
|
||||||
//
|
|
||||||
// Note: this endpoint is part of a draft specification, not all ACME servers will implement it.
|
|
||||||
// This method will return api.ErrNoARI if the server does not advertise a renewal info endpoint.
|
|
||||||
//
|
|
||||||
// https://datatracker.ietf.org/doc/draft-ietf-acme-ari
|
|
||||||
func (c *CertificateService) GetRenewalInfo(certID string) (*http.Response, error) {
|
|
||||||
if c.core.GetDirectory().RenewalInfo == "" {
|
|
||||||
return nil, ErrNoARI
|
|
||||||
}
|
|
||||||
|
|
||||||
if certID == "" {
|
|
||||||
return nil, errors.New("renewalInfo[get]: 'certID' cannot be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.core.HTTPClient.Get(c.core.GetDirectory().RenewalInfo + "/" + certID)
|
|
||||||
}
|
|
124
vendor/github.com/go-acme/lego/v4/acme/commons.go
generated
vendored
124
vendor/github.com/go-acme/lego/v4/acme/commons.go
generated
vendored
@ -1,5 +1,5 @@
|
|||||||
// Package acme contains all objects related the ACME endpoints.
|
// Package acme contains all objects related the ACME endpoints.
|
||||||
// https://www.rfc-editor.org/rfc/rfc8555.html
|
// https://tools.ietf.org/html/rfc8555
|
||||||
package acme
|
package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -7,38 +7,20 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ACME status values of Account, Order, Authorization and Challenge objects.
|
// Challenge statuses
|
||||||
// See https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.6 for details.
|
// https://tools.ietf.org/html/rfc8555#section-7.1.6
|
||||||
const (
|
const (
|
||||||
|
StatusPending = "pending"
|
||||||
|
StatusInvalid = "invalid"
|
||||||
|
StatusValid = "valid"
|
||||||
|
StatusProcessing = "processing"
|
||||||
StatusDeactivated = "deactivated"
|
StatusDeactivated = "deactivated"
|
||||||
StatusExpired = "expired"
|
StatusExpired = "expired"
|
||||||
StatusInvalid = "invalid"
|
|
||||||
StatusPending = "pending"
|
|
||||||
StatusProcessing = "processing"
|
|
||||||
StatusReady = "ready"
|
|
||||||
StatusRevoked = "revoked"
|
StatusRevoked = "revoked"
|
||||||
StatusUnknown = "unknown"
|
|
||||||
StatusValid = "valid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CRL reason codes as defined in RFC 5280.
|
|
||||||
// https://datatracker.ietf.org/doc/html/rfc5280#section-5.3.1
|
|
||||||
const (
|
|
||||||
CRLReasonUnspecified uint = 0
|
|
||||||
CRLReasonKeyCompromise uint = 1
|
|
||||||
CRLReasonCACompromise uint = 2
|
|
||||||
CRLReasonAffiliationChanged uint = 3
|
|
||||||
CRLReasonSuperseded uint = 4
|
|
||||||
CRLReasonCessationOfOperation uint = 5
|
|
||||||
CRLReasonCertificateHold uint = 6
|
|
||||||
CRLReasonRemoveFromCRL uint = 8
|
|
||||||
CRLReasonPrivilegeWithdrawn uint = 9
|
|
||||||
CRLReasonAACompromise uint = 10
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Directory the ACME directory object.
|
// Directory the ACME directory object.
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.1
|
// - https://tools.ietf.org/html/rfc8555#section-7.1.1
|
||||||
// - https://datatracker.ietf.org/doc/draft-ietf-acme-ari/
|
|
||||||
type Directory struct {
|
type Directory struct {
|
||||||
NewNonceURL string `json:"newNonce"`
|
NewNonceURL string `json:"newNonce"`
|
||||||
NewAccountURL string `json:"newAccount"`
|
NewAccountURL string `json:"newAccount"`
|
||||||
@ -47,11 +29,10 @@ type Directory struct {
|
|||||||
RevokeCertURL string `json:"revokeCert"`
|
RevokeCertURL string `json:"revokeCert"`
|
||||||
KeyChangeURL string `json:"keyChange"`
|
KeyChangeURL string `json:"keyChange"`
|
||||||
Meta Meta `json:"meta"`
|
Meta Meta `json:"meta"`
|
||||||
RenewalInfo string `json:"renewalInfo"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Meta the ACME meta object (related to Directory).
|
// Meta the ACME meta object (related to Directory).
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.1
|
// - https://tools.ietf.org/html/rfc8555#section-7.1.1
|
||||||
type Meta struct {
|
type Meta struct {
|
||||||
// termsOfService (optional, string):
|
// termsOfService (optional, string):
|
||||||
// A URL identifying the current terms of service.
|
// A URL identifying the current terms of service.
|
||||||
@ -71,12 +52,12 @@ type Meta struct {
|
|||||||
|
|
||||||
// externalAccountRequired (optional, boolean):
|
// externalAccountRequired (optional, boolean):
|
||||||
// If this field is present and set to "true",
|
// If this field is present and set to "true",
|
||||||
// then the CA requires that all new-account requests include an "externalAccountBinding" field
|
// then the CA requires that all new- account requests include an "externalAccountBinding" field
|
||||||
// associating the new account with an external account.
|
// associating the new account with an external account.
|
||||||
ExternalAccountRequired bool `json:"externalAccountRequired"`
|
ExternalAccountRequired bool `json:"externalAccountRequired"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtendedAccount an extended Account.
|
// ExtendedAccount a extended Account.
|
||||||
type ExtendedAccount struct {
|
type ExtendedAccount struct {
|
||||||
Account
|
Account
|
||||||
// Contains the value of the response header `Location`
|
// Contains the value of the response header `Location`
|
||||||
@ -84,14 +65,14 @@ type ExtendedAccount struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Account the ACME account Object.
|
// Account the ACME account Object.
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.2
|
// - https://tools.ietf.org/html/rfc8555#section-7.1.2
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.3
|
// - https://tools.ietf.org/html/rfc8555#section-7.3
|
||||||
type Account struct {
|
type Account struct {
|
||||||
// status (required, string):
|
// status (required, string):
|
||||||
// The status of this account.
|
// The status of this account.
|
||||||
// Possible values are: "valid", "deactivated", and "revoked".
|
// Possible values are: "valid", "deactivated", and "revoked".
|
||||||
// The value "deactivated" should be used to indicate client-initiated deactivation
|
// The value "deactivated" should be used to indicate client-initiated deactivation
|
||||||
// whereas "revoked" should be used to indicate server-initiated deactivation. (See Section 7.1.6)
|
// whereas "revoked" should be used to indicate server- initiated deactivation. (See Section 7.1.6)
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
|
|
||||||
// contact (optional, array of string):
|
// contact (optional, array of string):
|
||||||
@ -125,13 +106,17 @@ type Account struct {
|
|||||||
// ExtendedOrder a extended Order.
|
// ExtendedOrder a extended Order.
|
||||||
type ExtendedOrder struct {
|
type ExtendedOrder struct {
|
||||||
Order
|
Order
|
||||||
|
|
||||||
// The order URL, contains the value of the response header `Location`
|
// The order URL, contains the value of the response header `Location`
|
||||||
Location string `json:"-"`
|
Location string `json:"-"`
|
||||||
|
|
||||||
|
// AlternateChainLinks (optional, array of string):
|
||||||
|
// URLs of "alternate" link relation
|
||||||
|
// - https://tools.ietf.org/html/rfc8555#section-7.4.2
|
||||||
|
AlternateChainLinks []string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order the ACME order Object.
|
// Order the ACME order Object.
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.3
|
// - https://tools.ietf.org/html/rfc8555#section-7.1.3
|
||||||
type Order struct {
|
type Order struct {
|
||||||
// status (required, string):
|
// status (required, string):
|
||||||
// The status of this order.
|
// The status of this order.
|
||||||
@ -181,16 +166,10 @@ type Order struct {
|
|||||||
// certificate (optional, string):
|
// certificate (optional, string):
|
||||||
// A URL for the certificate that has been issued in response to this order
|
// A URL for the certificate that has been issued in response to this order
|
||||||
Certificate string `json:"certificate,omitempty"`
|
Certificate string `json:"certificate,omitempty"`
|
||||||
|
|
||||||
// replaces (optional, string):
|
|
||||||
// replaces (string, optional): A string uniquely identifying a
|
|
||||||
// previously-issued certificate which this order is intended to replace.
|
|
||||||
// - https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-5
|
|
||||||
Replaces string `json:"replaces,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorization the ACME authorization object.
|
// Authorization the ACME authorization object.
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.4
|
// - https://tools.ietf.org/html/rfc8555#section-7.1.4
|
||||||
type Authorization struct {
|
type Authorization struct {
|
||||||
// status (required, string):
|
// status (required, string):
|
||||||
// The status of this authorization.
|
// The status of this authorization.
|
||||||
@ -232,8 +211,8 @@ type ExtendedChallenge struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Challenge the ACME challenge object.
|
// Challenge the ACME challenge object.
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.5
|
// - https://tools.ietf.org/html/rfc8555#section-7.1.5
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-8
|
// - https://tools.ietf.org/html/rfc8555#section-8
|
||||||
type Challenge struct {
|
type Challenge struct {
|
||||||
// type (required, string):
|
// type (required, string):
|
||||||
// The type of challenge encoded in the object.
|
// The type of challenge encoded in the object.
|
||||||
@ -266,23 +245,23 @@ type Challenge struct {
|
|||||||
// It MUST NOT contain any characters outside the base64url alphabet,
|
// It MUST NOT contain any characters outside the base64url alphabet,
|
||||||
// and MUST NOT include base64 padding characters ("=").
|
// and MUST NOT include base64 padding characters ("=").
|
||||||
// See [RFC4086] for additional information on randomness requirements.
|
// See [RFC4086] for additional information on randomness requirements.
|
||||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-8.3
|
// https://tools.ietf.org/html/rfc8555#section-8.3
|
||||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-8.4
|
// https://tools.ietf.org/html/rfc8555#section-8.4
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
|
||||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-8.1
|
// https://tools.ietf.org/html/rfc8555#section-8.1
|
||||||
KeyAuthorization string `json:"keyAuthorization"`
|
KeyAuthorization string `json:"keyAuthorization"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identifier the ACME identifier object.
|
// Identifier the ACME identifier object.
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-9.7.7
|
// - https://tools.ietf.org/html/rfc8555#section-9.7.7
|
||||||
type Identifier struct {
|
type Identifier struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CSRMessage Certificate Signing Request.
|
// CSRMessage Certificate Signing Request
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4
|
// - https://tools.ietf.org/html/rfc8555#section-7.4
|
||||||
type CSRMessage struct {
|
type CSRMessage struct {
|
||||||
// csr (required, string):
|
// csr (required, string):
|
||||||
// A CSR encoding the parameters for the certificate being requested [RFC2986].
|
// A CSR encoding the parameters for the certificate being requested [RFC2986].
|
||||||
@ -291,9 +270,9 @@ type CSRMessage struct {
|
|||||||
Csr string `json:"csr"`
|
Csr string `json:"csr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RevokeCertMessage a certificate revocation message.
|
// RevokeCertMessage a certificate revocation message
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.6
|
// - https://tools.ietf.org/html/rfc8555#section-7.6
|
||||||
// - https://www.rfc-editor.org/rfc/rfc5280.html#section-5.3.1
|
// - https://tools.ietf.org/html/rfc5280#section-5.3.1
|
||||||
type RevokeCertMessage struct {
|
type RevokeCertMessage struct {
|
||||||
// certificate (required, string):
|
// certificate (required, string):
|
||||||
// The certificate to be revoked, in the base64url-encoded version of the DER format.
|
// The certificate to be revoked, in the base64url-encoded version of the DER format.
|
||||||
@ -308,42 +287,3 @@ type RevokeCertMessage struct {
|
|||||||
// The problem document detail SHOULD indicate which reasonCodes are allowed.
|
// The problem document detail SHOULD indicate which reasonCodes are allowed.
|
||||||
Reason *uint `json:"reason,omitempty"`
|
Reason *uint `json:"reason,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawCertificate raw data of a certificate.
|
|
||||||
type RawCertificate struct {
|
|
||||||
Cert []byte
|
|
||||||
Issuer []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Window is a window of time.
|
|
||||||
type Window struct {
|
|
||||||
Start time.Time `json:"start"`
|
|
||||||
End time.Time `json:"end"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewalInfoResponse is the response to GET requests made the renewalInfo endpoint.
|
|
||||||
// - (4.1. Getting Renewal Information) https://datatracker.ietf.org/doc/draft-ietf-acme-ari/
|
|
||||||
type RenewalInfoResponse struct {
|
|
||||||
// SuggestedWindow contains two fields, start and end,
|
|
||||||
// whose values are timestamps which bound the window of time in which the CA recommends renewing the certificate.
|
|
||||||
SuggestedWindow Window `json:"suggestedWindow"`
|
|
||||||
// ExplanationURL is an optional URL pointing to a page which may explain why the suggested renewal window is what it is.
|
|
||||||
// For example, it may be a page explaining the CA's dynamic load-balancing strategy,
|
|
||||||
// or a page documenting which certificates are affected by a mass revocation event.
|
|
||||||
// Callers SHOULD provide this URL to their operator, if present.
|
|
||||||
ExplanationURL string `json:"explanationURL"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewalInfoUpdateRequest is the JWS payload for POST requests made to the renewalInfo endpoint.
|
|
||||||
// - (4.2. RenewalInfo Objects) https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-4.2
|
|
||||||
type RenewalInfoUpdateRequest struct {
|
|
||||||
// CertID is a composite string in the format: base64url(AKI) || '.' || base64url(Serial), where AKI is the
|
|
||||||
// certificate's authority key identifier and Serial is the certificate's serial number. For details, see:
|
|
||||||
// https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-4.1
|
|
||||||
CertID string `json:"certID"`
|
|
||||||
// Replaced is required and indicates whether or not the client considers the certificate to have been replaced.
|
|
||||||
// A certificate is considered replaced when its revocation would not disrupt any ongoing services,
|
|
||||||
// for instance because it has been renewed and the new certificate is in use, or because it is no longer in use.
|
|
||||||
// Clients SHOULD NOT send a request where this value is false.
|
|
||||||
Replaced bool `json:"replaced"`
|
|
||||||
}
|
|
||||||
|
14
vendor/github.com/go-acme/lego/v4/acme/errors.go
generated
vendored
14
vendor/github.com/go-acme/lego/v4/acme/errors.go
generated
vendored
@ -10,9 +10,9 @@ const (
|
|||||||
BadNonceErr = errNS + "badNonce"
|
BadNonceErr = errNS + "badNonce"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProblemDetails the problem details object.
|
// ProblemDetails the problem details object
|
||||||
// - https://www.rfc-editor.org/rfc/rfc7807.html#section-3.1
|
// - https://tools.ietf.org/html/rfc7807#section-3.1
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.3.3
|
// - https://tools.ietf.org/html/rfc8555#section-7.3.3
|
||||||
type ProblemDetails struct {
|
type ProblemDetails struct {
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
Detail string `json:"detail,omitempty"`
|
Detail string `json:"detail,omitempty"`
|
||||||
@ -25,8 +25,8 @@ type ProblemDetails struct {
|
|||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubProblem a "subproblems".
|
// SubProblem a "subproblems"
|
||||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-6.7.1
|
// - https://tools.ietf.org/html/rfc8555#section-6.7.1
|
||||||
type SubProblem struct {
|
type SubProblem struct {
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
Detail string `json:"detail,omitempty"`
|
Detail string `json:"detail,omitempty"`
|
||||||
@ -35,7 +35,7 @@ type SubProblem struct {
|
|||||||
|
|
||||||
func (p ProblemDetails) Error() string {
|
func (p ProblemDetails) Error() string {
|
||||||
msg := fmt.Sprintf("acme: error: %d", p.HTTPStatus)
|
msg := fmt.Sprintf("acme: error: %d", p.HTTPStatus)
|
||||||
if p.Method != "" || p.URL != "" {
|
if len(p.Method) != 0 || len(p.URL) != 0 {
|
||||||
msg += fmt.Sprintf(" :: %s :: %s", p.Method, p.URL)
|
msg += fmt.Sprintf(" :: %s :: %s", p.Method, p.URL)
|
||||||
}
|
}
|
||||||
msg += fmt.Sprintf(" :: %s :: %s", p.Type, p.Detail)
|
msg += fmt.Sprintf(" :: %s :: %s", p.Type, p.Detail)
|
||||||
@ -44,7 +44,7 @@ func (p ProblemDetails) Error() string {
|
|||||||
msg += fmt.Sprintf(", problem: %q :: %s", sub.Type, sub.Detail)
|
msg += fmt.Sprintf(", problem: %q :: %s", sub.Type, sub.Detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Instance != "" {
|
if len(p.Instance) == 0 {
|
||||||
msg += ", url: " + p.Instance
|
msg += ", url: " + p.Instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
84
vendor/github.com/go-acme/lego/v4/certcrypto/crypto.go
generated
vendored
84
vendor/github.com/go-acme/lego/v4/certcrypto/crypto.go
generated
vendored
@ -14,8 +14,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
|
||||||
"slices"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -27,7 +25,6 @@ const (
|
|||||||
EC256 = KeyType("P256")
|
EC256 = KeyType("P256")
|
||||||
EC384 = KeyType("P384")
|
EC384 = KeyType("P384")
|
||||||
RSA2048 = KeyType("2048")
|
RSA2048 = KeyType("2048")
|
||||||
RSA3072 = KeyType("3072")
|
|
||||||
RSA4096 = KeyType("4096")
|
RSA4096 = KeyType("4096")
|
||||||
RSA8192 = KeyType("8192")
|
RSA8192 = KeyType("8192")
|
||||||
)
|
)
|
||||||
@ -85,12 +82,9 @@ func ParsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
|
|||||||
// ParsePEMPrivateKey parses a private key from key, which is a PEM block.
|
// ParsePEMPrivateKey parses a private key from key, which is a PEM block.
|
||||||
// Borrowed from Go standard library, to handle various private key and PEM block types.
|
// Borrowed from Go standard library, to handle various private key and PEM block types.
|
||||||
// https://github.com/golang/go/blob/693748e9fa385f1e2c3b91ca9acbb6c0ad2d133d/src/crypto/tls/tls.go#L291-L308
|
// https://github.com/golang/go/blob/693748e9fa385f1e2c3b91ca9acbb6c0ad2d133d/src/crypto/tls/tls.go#L291-L308
|
||||||
// https://github.com/golang/go/blob/693748e9fa385f1e2c3b91ca9acbb6c0ad2d133d/src/crypto/tls/tls.go#L238
|
// https://github.com/golang/go/blob/693748e9fa385f1e2c3b91ca9acbb6c0ad2d133d/src/crypto/tls/tls.go#L238)
|
||||||
func ParsePEMPrivateKey(key []byte) (crypto.PrivateKey, error) {
|
func ParsePEMPrivateKey(key []byte) (crypto.PrivateKey, error) {
|
||||||
keyBlockDER, _ := pem.Decode(key)
|
keyBlockDER, _ := pem.Decode(key)
|
||||||
if keyBlockDER == nil {
|
|
||||||
return nil, errors.New("invalid PEM block")
|
|
||||||
}
|
|
||||||
|
|
||||||
if keyBlockDER.Type != "PRIVATE KEY" && !strings.HasSuffix(keyBlockDER.Type, " PRIVATE KEY") {
|
if keyBlockDER.Type != "PRIVATE KEY" && !strings.HasSuffix(keyBlockDER.Type, " PRIVATE KEY") {
|
||||||
return nil, fmt.Errorf("unknown PEM header %q", keyBlockDER.Type)
|
return nil, fmt.Errorf("unknown PEM header %q", keyBlockDER.Type)
|
||||||
@ -124,8 +118,6 @@ func GeneratePrivateKey(keyType KeyType) (crypto.PrivateKey, error) {
|
|||||||
return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||||
case RSA2048:
|
case RSA2048:
|
||||||
return rsa.GenerateKey(rand.Reader, 2048)
|
return rsa.GenerateKey(rand.Reader, 2048)
|
||||||
case RSA3072:
|
|
||||||
return rsa.GenerateKey(rand.Reader, 3072)
|
|
||||||
case RSA4096:
|
case RSA4096:
|
||||||
return rsa.GenerateKey(rand.Reader, 4096)
|
return rsa.GenerateKey(rand.Reader, 4096)
|
||||||
case RSA8192:
|
case RSA8192:
|
||||||
@ -136,20 +128,9 @@ func GeneratePrivateKey(keyType KeyType) (crypto.PrivateKey, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GenerateCSR(privateKey crypto.PrivateKey, domain string, san []string, mustStaple bool) ([]byte, error) {
|
func GenerateCSR(privateKey crypto.PrivateKey, domain string, san []string, mustStaple bool) ([]byte, error) {
|
||||||
var dnsNames []string
|
|
||||||
var ipAddresses []net.IP
|
|
||||||
for _, altname := range san {
|
|
||||||
if ip := net.ParseIP(altname); ip != nil {
|
|
||||||
ipAddresses = append(ipAddresses, ip)
|
|
||||||
} else {
|
|
||||||
dnsNames = append(dnsNames, altname)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template := x509.CertificateRequest{
|
template := x509.CertificateRequest{
|
||||||
Subject: pkix.Name{CommonName: domain},
|
Subject: pkix.Name{CommonName: domain},
|
||||||
DNSNames: dnsNames,
|
DNSNames: san,
|
||||||
IPAddresses: ipAddresses,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if mustStaple {
|
if mustStaple {
|
||||||
@ -192,13 +173,13 @@ func pemDecode(data []byte) (*pem.Block, error) {
|
|||||||
return pemBlock, nil
|
return pemBlock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PemDecodeTox509CSR(data []byte) (*x509.CertificateRequest, error) {
|
func PemDecodeTox509CSR(pem []byte) (*x509.CertificateRequest, error) {
|
||||||
pemBlock, err := pemDecode(data)
|
pemBlock, err := pemDecode(pem)
|
||||||
if pemBlock == nil {
|
if pemBlock == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if pemBlock.Type != "CERTIFICATE REQUEST" && pemBlock.Type != "NEW CERTIFICATE REQUEST" {
|
if pemBlock.Type != "CERTIFICATE REQUEST" {
|
||||||
return nil, errors.New("PEM block is not a certificate request")
|
return nil, errors.New("PEM block is not a certificate request")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,26 +198,6 @@ func ParsePEMCertificate(cert []byte) (*x509.Certificate, error) {
|
|||||||
return x509.ParseCertificate(pemBlock.Bytes)
|
return x509.ParseCertificate(pemBlock.Bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCertificateMainDomain(cert *x509.Certificate) (string, error) {
|
|
||||||
return getMainDomain(cert.Subject, cert.DNSNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetCSRMainDomain(cert *x509.CertificateRequest) (string, error) {
|
|
||||||
return getMainDomain(cert.Subject, cert.DNSNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMainDomain(subject pkix.Name, dnsNames []string) (string, error) {
|
|
||||||
if subject.CommonName == "" && len(dnsNames) == 0 {
|
|
||||||
return "", errors.New("missing domain")
|
|
||||||
}
|
|
||||||
|
|
||||||
if subject.CommonName != "" {
|
|
||||||
return subject.CommonName, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return dnsNames[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExtractDomains(cert *x509.Certificate) []string {
|
func ExtractDomains(cert *x509.Certificate) []string {
|
||||||
var domains []string
|
var domains []string
|
||||||
if cert.Subject.CommonName != "" {
|
if cert.Subject.CommonName != "" {
|
||||||
@ -251,13 +212,6 @@ func ExtractDomains(cert *x509.Certificate) []string {
|
|||||||
domains = append(domains, sanDomain)
|
domains = append(domains, sanDomain)
|
||||||
}
|
}
|
||||||
|
|
||||||
commonNameIP := net.ParseIP(cert.Subject.CommonName)
|
|
||||||
for _, sanIP := range cert.IPAddresses {
|
|
||||||
if !commonNameIP.Equal(sanIP) {
|
|
||||||
domains = append(domains, sanIP.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return domains
|
return domains
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +223,7 @@ func ExtractDomainsCSR(csr *x509.CertificateRequest) []string {
|
|||||||
|
|
||||||
// loop over the SubjectAltName DNS names
|
// loop over the SubjectAltName DNS names
|
||||||
for _, sanName := range csr.DNSNames {
|
for _, sanName := range csr.DNSNames {
|
||||||
if slices.Contains(domains, sanName) {
|
if containsSAN(domains, sanName) {
|
||||||
// Duplicate; skip this name
|
// Duplicate; skip this name
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -278,14 +232,16 @@ func ExtractDomainsCSR(csr *x509.CertificateRequest) []string {
|
|||||||
domains = append(domains, sanName)
|
domains = append(domains, sanName)
|
||||||
}
|
}
|
||||||
|
|
||||||
cnip := net.ParseIP(csr.Subject.CommonName)
|
return domains
|
||||||
for _, sanIP := range csr.IPAddresses {
|
}
|
||||||
if !cnip.Equal(sanIP) {
|
|
||||||
domains = append(domains, sanIP.String())
|
func containsSAN(domains []string, sanName string) bool {
|
||||||
|
for _, existingName := range domains {
|
||||||
|
if existingName == sanName {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
return domains
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GeneratePemCert(privateKey *rsa.PrivateKey, domain string, extensions []pkix.Extension) ([]byte, error) {
|
func GeneratePemCert(privateKey *rsa.PrivateKey, domain string, extensions []pkix.Extension) ([]byte, error) {
|
||||||
@ -305,7 +261,7 @@ func generateDerCert(privateKey *rsa.PrivateKey, expiration time.Time, domain st
|
|||||||
}
|
}
|
||||||
|
|
||||||
if expiration.IsZero() {
|
if expiration.IsZero() {
|
||||||
expiration = time.Now().AddDate(1, 0, 0)
|
expiration = time.Now().Add(365)
|
||||||
}
|
}
|
||||||
|
|
||||||
template := x509.Certificate{
|
template := x509.Certificate{
|
||||||
@ -318,15 +274,9 @@ func generateDerCert(privateKey *rsa.PrivateKey, expiration time.Time, domain st
|
|||||||
|
|
||||||
KeyUsage: x509.KeyUsageKeyEncipherment,
|
KeyUsage: x509.KeyUsageKeyEncipherment,
|
||||||
BasicConstraintsValid: true,
|
BasicConstraintsValid: true,
|
||||||
|
DNSNames: []string{domain},
|
||||||
ExtraExtensions: extensions,
|
ExtraExtensions: extensions,
|
||||||
}
|
}
|
||||||
|
|
||||||
// handling SAN filling as type suspected
|
|
||||||
if ip := net.ParseIP(domain); ip != nil {
|
|
||||||
template.IPAddresses = []net.IP{ip}
|
|
||||||
} else {
|
|
||||||
template.DNSNames = []string{domain}
|
|
||||||
}
|
|
||||||
|
|
||||||
return x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
return x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||||
}
|
}
|
||||||
|
19
vendor/github.com/go-acme/lego/v4/certificate/authorization.go
generated
vendored
19
vendor/github.com/go-acme/lego/v4/certificate/authorization.go
generated
vendored
@ -12,7 +12,6 @@ const (
|
|||||||
// limited on the "new-reg", "new-authz" and "new-cert" endpoints.
|
// limited on the "new-reg", "new-authz" and "new-cert" endpoints.
|
||||||
// From the documentation the limitation is 20 requests per second,
|
// From the documentation the limitation is 20 requests per second,
|
||||||
// but using 20 as value doesn't work but 18 do.
|
// but using 20 as value doesn't work but 18 do.
|
||||||
// https://letsencrypt.org/docs/rate-limits/
|
|
||||||
overallRequestLimit = 18
|
overallRequestLimit = 18
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,14 +35,13 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
|
|||||||
}
|
}
|
||||||
|
|
||||||
var responses []acme.Authorization
|
var responses []acme.Authorization
|
||||||
|
failures := make(obtainError)
|
||||||
failures := newObtainError()
|
for i := 0; i < len(order.Authorizations); i++ {
|
||||||
for range len(order.Authorizations) {
|
|
||||||
select {
|
select {
|
||||||
case res := <-resc:
|
case res := <-resc:
|
||||||
responses = append(responses, res)
|
responses = append(responses, res)
|
||||||
case err := <-errc:
|
case err := <-errc:
|
||||||
failures.Add(err.Domain, err.Error)
|
failures[err.Domain] = err.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,10 +52,15 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
|
|||||||
close(resc)
|
close(resc)
|
||||||
close(errc)
|
close(errc)
|
||||||
|
|
||||||
return responses, failures.Join()
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder, force bool) {
|
func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder) {
|
||||||
for _, authzURL := range order.Authorizations {
|
for _, authzURL := range order.Authorizations {
|
||||||
auth, err := c.core.Authorizations.Get(authzURL)
|
auth, err := c.core.Authorizations.Get(authzURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -65,7 +68,7 @@ func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder, force boo
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if auth.Status == acme.StatusValid && !force {
|
if auth.Status == acme.StatusValid {
|
||||||
log.Infof("Skipping deactivating of valid auth: %s", authzURL)
|
log.Infof("Skipping deactivating of valid auth: %s", authzURL)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
251
vendor/github.com/go-acme/lego/v4/certificate/certificates.go
generated
vendored
251
vendor/github.com/go-acme/lego/v4/certificate/certificates.go
generated
vendored
@ -7,7 +7,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -49,44 +49,22 @@ type Resource struct {
|
|||||||
// If you do not want that you can supply your own private key in the privateKey parameter.
|
// If you do not want that you can supply your own private key in the privateKey parameter.
|
||||||
// If this parameter is non-nil it will be used instead of generating a new one.
|
// If this parameter is non-nil it will be used instead of generating a new one.
|
||||||
//
|
//
|
||||||
// If `Bundle` is true, the `[]byte` contains both the issuer certificate and your issued certificate as a bundle.
|
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
|
||||||
//
|
|
||||||
// If `AlwaysDeactivateAuthorizations` is true, the authorizations are also relinquished if the obtain request was successful.
|
|
||||||
// See https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.2.
|
|
||||||
type ObtainRequest struct {
|
type ObtainRequest struct {
|
||||||
Domains []string
|
Domains []string
|
||||||
PrivateKey crypto.PrivateKey
|
Bundle bool
|
||||||
MustStaple bool
|
PrivateKey crypto.PrivateKey
|
||||||
|
MustStaple bool
|
||||||
NotBefore time.Time
|
PreferredChain string
|
||||||
NotAfter time.Time
|
|
||||||
Bundle bool
|
|
||||||
PreferredChain string
|
|
||||||
AlwaysDeactivateAuthorizations bool
|
|
||||||
// A string uniquely identifying a previously-issued certificate which this
|
|
||||||
// order is intended to replace.
|
|
||||||
// - https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-5
|
|
||||||
ReplacesCertID string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObtainForCSRRequest The request to obtain a certificate matching the CSR passed into it.
|
// ObtainForCSRRequest The request to obtain a certificate matching the CSR passed into it.
|
||||||
//
|
//
|
||||||
// If `Bundle` is true, the `[]byte` contains both the issuer certificate and your issued certificate as a bundle.
|
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
|
||||||
//
|
|
||||||
// If `AlwaysDeactivateAuthorizations` is true, the authorizations are also relinquished if the obtain request was successful.
|
|
||||||
// See https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.2.
|
|
||||||
type ObtainForCSRRequest struct {
|
type ObtainForCSRRequest struct {
|
||||||
CSR *x509.CertificateRequest
|
CSR *x509.CertificateRequest
|
||||||
|
Bundle bool
|
||||||
NotBefore time.Time
|
PreferredChain string
|
||||||
NotAfter time.Time
|
|
||||||
Bundle bool
|
|
||||||
PreferredChain string
|
|
||||||
AlwaysDeactivateAuthorizations bool
|
|
||||||
// A string uniquely identifying a previously-issued certificate which this
|
|
||||||
// order is intended to replace.
|
|
||||||
// - https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-5
|
|
||||||
ReplacesCertID string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type resolver interface {
|
type resolver interface {
|
||||||
@ -131,13 +109,7 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
|
|||||||
log.Infof("[%s] acme: Obtaining SAN certificate", strings.Join(domains, ", "))
|
log.Infof("[%s] acme: Obtaining SAN certificate", strings.Join(domains, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
orderOpts := &api.OrderOptions{
|
order, err := c.core.Orders.New(domains)
|
||||||
NotBefore: request.NotBefore,
|
|
||||||
NotAfter: request.NotAfter,
|
|
||||||
ReplacesCertID: request.ReplacesCertID,
|
|
||||||
}
|
|
||||||
|
|
||||||
order, err := c.core.Orders.NewWithOptions(domains, orderOpts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -145,32 +117,33 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
|
|||||||
authz, err := c.getAuthorizations(order)
|
authz, err := c.getAuthorizations(order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If any challenge fails, return. Do not generate partial SAN certificates.
|
// If any challenge fails, return. Do not generate partial SAN certificates.
|
||||||
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
|
c.deactivateAuthorizations(order)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.resolver.Solve(authz)
|
err = c.resolver.Solve(authz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If any challenge fails, return. Do not generate partial SAN certificates.
|
// If any challenge fails, return. Do not generate partial SAN certificates.
|
||||||
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
|
c.deactivateAuthorizations(order)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
|
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
|
||||||
|
|
||||||
failures := newObtainError()
|
failures := make(obtainError)
|
||||||
cert, err := c.getForOrder(domains, order, request.Bundle, request.PrivateKey, request.MustStaple, request.PreferredChain)
|
cert, err := c.getForOrder(domains, order, request.Bundle, request.PrivateKey, request.MustStaple, request.PreferredChain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
for _, auth := range authz {
|
for _, auth := range authz {
|
||||||
failures.Add(challenge.GetTargetedDomain(auth), err)
|
failures[challenge.GetTargetedDomain(auth)] = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.AlwaysDeactivateAuthorizations {
|
// Do not return an empty failures map, because
|
||||||
c.deactivateAuthorizations(order, true)
|
// 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.
|
// ObtainForCSR tries to obtain a certificate matching the CSR passed into it.
|
||||||
@ -197,13 +170,7 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
|
|||||||
log.Infof("[%s] acme: Obtaining SAN certificate given a CSR", strings.Join(domains, ", "))
|
log.Infof("[%s] acme: Obtaining SAN certificate given a CSR", strings.Join(domains, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
orderOpts := &api.OrderOptions{
|
order, err := c.core.Orders.New(domains)
|
||||||
NotBefore: request.NotBefore,
|
|
||||||
NotAfter: request.NotAfter,
|
|
||||||
ReplacesCertID: request.ReplacesCertID,
|
|
||||||
}
|
|
||||||
|
|
||||||
order, err := c.core.Orders.NewWithOptions(domains, orderOpts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -211,37 +178,38 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
|
|||||||
authz, err := c.getAuthorizations(order)
|
authz, err := c.getAuthorizations(order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If any challenge fails, return. Do not generate partial SAN certificates.
|
// If any challenge fails, return. Do not generate partial SAN certificates.
|
||||||
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
|
c.deactivateAuthorizations(order)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.resolver.Solve(authz)
|
err = c.resolver.Solve(authz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If any challenge fails, return. Do not generate partial SAN certificates.
|
// If any challenge fails, return. Do not generate partial SAN certificates.
|
||||||
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
|
c.deactivateAuthorizations(order)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
|
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
|
||||||
|
|
||||||
failures := newObtainError()
|
failures := make(obtainError)
|
||||||
cert, err := c.getForCSR(domains, order, request.Bundle, request.CSR.Raw, nil, request.PreferredChain)
|
cert, err := c.getForCSR(domains, order, request.Bundle, request.CSR.Raw, nil, request.PreferredChain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
for _, auth := range authz {
|
for _, auth := range authz {
|
||||||
failures.Add(challenge.GetTargetedDomain(auth), err)
|
failures[challenge.GetTargetedDomain(auth)] = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.AlwaysDeactivateAuthorizations {
|
|
||||||
c.deactivateAuthorizations(order, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cert != nil {
|
if cert != nil {
|
||||||
// Add the CSR to the certificate so that it can be used for renewals.
|
// Add the CSR to the certificate so that it can be used for renewals.
|
||||||
cert.CSR = certcrypto.PEMEncode(request.CSR)
|
cert.CSR = certcrypto.PEMEncode(request.CSR)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cert, failures.Join()
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, bundle bool, privateKey crypto.PrivateKey, mustStaple bool, preferredChain string) (*Resource, error) {
|
func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, bundle bool, privateKey crypto.PrivateKey, mustStaple bool, preferredChain string) (*Resource, error) {
|
||||||
@ -253,23 +221,16 @@ func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, bund
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commonName := ""
|
// Determine certificate name(s) based on the authorization resources
|
||||||
if len(domains[0]) <= 64 {
|
commonName := domains[0]
|
||||||
commonName = domains[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC8555 Section 7.4 "Applying for Certificate Issuance"
|
// RFC8555 Section 7.4 "Applying for Certificate Issuance"
|
||||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4
|
// https://tools.ietf.org/html/rfc8555#section-7.4
|
||||||
// says:
|
// says:
|
||||||
// Clients SHOULD NOT make any assumptions about the sort order of
|
// Clients SHOULD NOT make any assumptions about the sort order of
|
||||||
// "identifiers" or "authorizations" elements in the returned order
|
// "identifiers" or "authorizations" elements in the returned order
|
||||||
// object.
|
// object.
|
||||||
|
san := []string{commonName}
|
||||||
var san []string
|
|
||||||
if commonName != "" {
|
|
||||||
san = append(san, commonName)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, auth := range order.Identifiers {
|
for _, auth := range order.Identifiers {
|
||||||
if auth.Value != commonName {
|
if auth.Value != commonName {
|
||||||
san = append(san, auth.Value)
|
san = append(san, auth.Value)
|
||||||
@ -291,14 +252,15 @@ func (c *Certifier) getForCSR(domains []string, order acme.ExtendedOrder, bundle
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commonName := domains[0]
|
||||||
certRes := &Resource{
|
certRes := &Resource{
|
||||||
Domain: domains[0],
|
Domain: commonName,
|
||||||
CertURL: respOrder.Certificate,
|
CertURL: respOrder.Certificate,
|
||||||
PrivateKey: privateKeyPem,
|
PrivateKey: privateKeyPem,
|
||||||
}
|
}
|
||||||
|
|
||||||
if respOrder.Status == acme.StatusValid {
|
if respOrder.Status == acme.StatusValid {
|
||||||
// if the certificate is available right away, shortcut!
|
// if the certificate is available right away, short cut!
|
||||||
ok, errR := c.checkResponse(respOrder, certRes, bundle, preferredChain)
|
ok, errR := c.checkResponse(respOrder, certRes, bundle, preferredChain)
|
||||||
if errR != nil {
|
if errR != nil {
|
||||||
return nil, errR
|
return nil, errR
|
||||||
@ -345,25 +307,29 @@ func (c *Certifier) checkResponse(order acme.ExtendedOrder, certRes *Resource, b
|
|||||||
return valid, err
|
return valid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
certs, err := c.core.Certificates.GetAll(order.Certificate, bundle)
|
links := append([]string{order.Certificate}, order.AlternateChainLinks...)
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the default certificate
|
for i, link := range links {
|
||||||
certRes.IssuerCertificate = certs[order.Certificate].Issuer
|
cert, issuer, err := c.core.Certificates.Get(link, bundle)
|
||||||
certRes.Certificate = certs[order.Certificate].Cert
|
if err != nil {
|
||||||
certRes.CertURL = order.Certificate
|
return false, err
|
||||||
certRes.CertStableURL = order.Certificate
|
}
|
||||||
|
|
||||||
if preferredChain == "" {
|
// Set the default certificate
|
||||||
log.Infof("[%s] Server responded with a certificate.", certRes.Domain)
|
if i == 0 {
|
||||||
|
certRes.IssuerCertificate = issuer
|
||||||
|
certRes.Certificate = cert
|
||||||
|
certRes.CertURL = link
|
||||||
|
certRes.CertStableURL = link
|
||||||
|
}
|
||||||
|
|
||||||
return true, nil
|
if preferredChain == "" {
|
||||||
}
|
log.Infof("[%s] Server responded with a certificate.", certRes.Domain)
|
||||||
|
|
||||||
for link, cert := range certs {
|
return true, nil
|
||||||
ok, err := hasPreferredChain(cert.Issuer, preferredChain)
|
}
|
||||||
|
|
||||||
|
ok, err := hasPreferredChain(issuer, preferredChain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -371,8 +337,8 @@ func (c *Certifier) checkResponse(order acme.ExtendedOrder, certRes *Resource, b
|
|||||||
if ok {
|
if ok {
|
||||||
log.Infof("[%s] Server responded with a certificate for the preferred certificate chains %q.", certRes.Domain, preferredChain)
|
log.Infof("[%s] Server responded with a certificate for the preferred certificate chains %q.", certRes.Domain, preferredChain)
|
||||||
|
|
||||||
certRes.IssuerCertificate = cert.Issuer
|
certRes.IssuerCertificate = issuer
|
||||||
certRes.Certificate = cert.Cert
|
certRes.Certificate = cert
|
||||||
certRes.CertURL = link
|
certRes.CertURL = link
|
||||||
certRes.CertStableURL = link
|
certRes.CertStableURL = link
|
||||||
|
|
||||||
@ -387,11 +353,6 @@ func (c *Certifier) checkResponse(order acme.ExtendedOrder, certRes *Resource, b
|
|||||||
|
|
||||||
// Revoke takes a PEM encoded certificate or bundle and tries to revoke it at the CA.
|
// Revoke takes a PEM encoded certificate or bundle and tries to revoke it at the CA.
|
||||||
func (c *Certifier) Revoke(cert []byte) error {
|
func (c *Certifier) Revoke(cert []byte) error {
|
||||||
return c.RevokeWithReason(cert, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RevokeWithReason takes a PEM encoded certificate or bundle and tries to revoke it at the CA.
|
|
||||||
func (c *Certifier) RevokeWithReason(cert []byte, reason *uint) error {
|
|
||||||
certificates, err := certcrypto.ParsePEMBundle(cert)
|
certificates, err := certcrypto.ParsePEMBundle(cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -404,24 +365,11 @@ func (c *Certifier) RevokeWithReason(cert []byte, reason *uint) error {
|
|||||||
|
|
||||||
revokeMsg := acme.RevokeCertMessage{
|
revokeMsg := acme.RevokeCertMessage{
|
||||||
Certificate: base64.RawURLEncoding.EncodeToString(x509Cert.Raw),
|
Certificate: base64.RawURLEncoding.EncodeToString(x509Cert.Raw),
|
||||||
Reason: reason,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.core.Certificates.Revoke(revokeMsg)
|
return c.core.Certificates.Revoke(revokeMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenewOptions options used by Certifier.RenewWithOptions.
|
|
||||||
type RenewOptions struct {
|
|
||||||
NotBefore time.Time
|
|
||||||
NotAfter time.Time
|
|
||||||
// If true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
|
|
||||||
Bundle bool
|
|
||||||
PreferredChain string
|
|
||||||
AlwaysDeactivateAuthorizations bool
|
|
||||||
// Not supported for CSR request.
|
|
||||||
MustStaple bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renew takes a Resource and tries to renew the certificate.
|
// Renew takes a Resource and tries to renew the certificate.
|
||||||
//
|
//
|
||||||
// If the renewal process succeeds, the new certificate will be returned in a new CertResource.
|
// If the renewal process succeeds, the new certificate will be returned in a new CertResource.
|
||||||
@ -432,26 +380,7 @@ type RenewOptions struct {
|
|||||||
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
|
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
|
||||||
//
|
//
|
||||||
// For private key reuse the PrivateKey property of the passed in Resource should be non-nil.
|
// For private key reuse the PrivateKey property of the passed in Resource should be non-nil.
|
||||||
// Deprecated: use RenewWithOptions instead.
|
|
||||||
func (c *Certifier) Renew(certRes Resource, bundle, mustStaple bool, preferredChain string) (*Resource, error) {
|
func (c *Certifier) Renew(certRes Resource, bundle, mustStaple bool, preferredChain string) (*Resource, error) {
|
||||||
return c.RenewWithOptions(certRes, &RenewOptions{
|
|
||||||
Bundle: bundle,
|
|
||||||
PreferredChain: preferredChain,
|
|
||||||
MustStaple: mustStaple,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewWithOptions takes a Resource and tries to renew the certificate.
|
|
||||||
//
|
|
||||||
// If the renewal process succeeds, the new certificate will be returned in a new CertResource.
|
|
||||||
// Please be aware that this function will return a new certificate in ANY case that is not an error.
|
|
||||||
// If the server does not provide us with a new cert on a GET request to the CertURL
|
|
||||||
// this function will start a new-cert flow where a new certificate gets generated.
|
|
||||||
//
|
|
||||||
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
|
|
||||||
//
|
|
||||||
// For private key reuse the PrivateKey property of the passed in Resource should be non-nil.
|
|
||||||
func (c *Certifier) RenewWithOptions(certRes Resource, options *RenewOptions) (*Resource, error) {
|
|
||||||
// Input certificate is PEM encoded.
|
// Input certificate is PEM encoded.
|
||||||
// Decode it here as we may need the decoded cert later on in the renewal process.
|
// Decode it here as we may need the decoded cert later on in the renewal process.
|
||||||
// The input may be a bundle or a single certificate.
|
// The input may be a bundle or a single certificate.
|
||||||
@ -478,17 +407,11 @@ func (c *Certifier) RenewWithOptions(certRes Resource, options *RenewOptions) (*
|
|||||||
return nil, errP
|
return nil, errP
|
||||||
}
|
}
|
||||||
|
|
||||||
request := ObtainForCSRRequest{CSR: csr}
|
return c.ObtainForCSR(ObtainForCSRRequest{
|
||||||
|
CSR: csr,
|
||||||
if options != nil {
|
Bundle: bundle,
|
||||||
request.NotBefore = options.NotBefore
|
PreferredChain: preferredChain,
|
||||||
request.NotAfter = options.NotAfter
|
})
|
||||||
request.Bundle = options.Bundle
|
|
||||||
request.PreferredChain = options.PreferredChain
|
|
||||||
request.AlwaysDeactivateAuthorizations = options.AlwaysDeactivateAuthorizations
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.ObtainForCSR(request)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var privateKey crypto.PrivateKey
|
var privateKey crypto.PrivateKey
|
||||||
@ -499,21 +422,13 @@ func (c *Certifier) RenewWithOptions(certRes Resource, options *RenewOptions) (*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
request := ObtainRequest{
|
query := ObtainRequest{
|
||||||
Domains: certcrypto.ExtractDomains(x509Cert),
|
Domains: certcrypto.ExtractDomains(x509Cert),
|
||||||
|
Bundle: bundle,
|
||||||
PrivateKey: privateKey,
|
PrivateKey: privateKey,
|
||||||
|
MustStaple: mustStaple,
|
||||||
}
|
}
|
||||||
|
return c.Obtain(query)
|
||||||
if options != nil {
|
|
||||||
request.MustStaple = options.MustStaple
|
|
||||||
request.NotBefore = options.NotBefore
|
|
||||||
request.NotAfter = options.NotAfter
|
|
||||||
request.Bundle = options.Bundle
|
|
||||||
request.PreferredChain = options.PreferredChain
|
|
||||||
request.AlwaysDeactivateAuthorizations = options.AlwaysDeactivateAuthorizations
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.Obtain(request)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOCSP takes a PEM encoded cert or cert bundle returning the raw OCSP response,
|
// GetOCSP takes a PEM encoded cert or cert bundle returning the raw OCSP response,
|
||||||
@ -554,7 +469,7 @@ func (c *Certifier) GetOCSP(bundle []byte) ([]byte, *ocsp.Response, error) {
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
issuerBytes, errC := io.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
issuerBytes, errC := ioutil.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
||||||
if errC != nil {
|
if errC != nil {
|
||||||
return nil, nil, errC
|
return nil, nil, errC
|
||||||
}
|
}
|
||||||
@ -583,7 +498,7 @@ func (c *Certifier) GetOCSP(bundle []byte) ([]byte, *ocsp.Response, error) {
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
ocspResBytes, err := io.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
ocspResBytes, err := ioutil.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -614,13 +529,8 @@ func (c *Certifier) Get(url string, bundle bool) (*Resource, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
domain, err := certcrypto.GetCertificateMainDomain(x509Certs[0])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Resource{
|
return &Resource{
|
||||||
Domain: domain,
|
Domain: x509Certs[0].Subject.CommonName,
|
||||||
Certificate: cert,
|
Certificate: cert,
|
||||||
IssuerCertificate: issuer,
|
IssuerCertificate: issuer,
|
||||||
CertURL: url,
|
CertURL: url,
|
||||||
@ -634,10 +544,10 @@ func hasPreferredChain(issuer []byte, preferredChain string) (bool, error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
topCert := certs[len(certs)-1]
|
for _, cert := range certs {
|
||||||
|
if cert.Issuer.CommonName == preferredChain {
|
||||||
if topCert.Issuer.CommonName == preferredChain {
|
return true, nil
|
||||||
return true, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -654,11 +564,12 @@ func checkOrderStatus(order acme.ExtendedOrder) (bool, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.4
|
// https://tools.ietf.org/html/rfc8555#section-7.1.4
|
||||||
// The domain name MUST be encoded in the form in which it would appear in a certificate.
|
// The domain name MUST be encoded
|
||||||
// That is, it MUST be encoded according to the rules in Section 7 of [RFC5280].
|
// in the form in which it would appear in a certificate. That is, it
|
||||||
|
// MUST be encoded according to the rules in Section 7 of [RFC5280].
|
||||||
//
|
//
|
||||||
// https://www.rfc-editor.org/rfc/rfc5280.html#section-7
|
// https://tools.ietf.org/html/rfc5280#section-7
|
||||||
func sanitizeDomain(domains []string) []string {
|
func sanitizeDomain(domains []string) []string {
|
||||||
var sanitizedDomains []string
|
var sanitizedDomains []string
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
|
36
vendor/github.com/go-acme/lego/v4/certificate/errors.go
generated
vendored
36
vendor/github.com/go-acme/lego/v4/certificate/errors.go
generated
vendored
@ -1,37 +1,27 @@
|
|||||||
package certificate
|
package certificate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
type obtainError struct {
|
// obtainError is returned when there are specific errors available per domain.
|
||||||
data map[string]error
|
type obtainError map[string]error
|
||||||
}
|
|
||||||
|
|
||||||
func newObtainError() *obtainError {
|
func (e obtainError) Error() string {
|
||||||
return &obtainError{data: make(map[string]error)}
|
buffer := bytes.NewBufferString("error: one or more domains had a problem:\n")
|
||||||
}
|
|
||||||
|
|
||||||
func (e *obtainError) Add(domain string, err error) {
|
var domains []string
|
||||||
e.data[domain] = err
|
for domain := range e {
|
||||||
}
|
domains = append(domains, domain)
|
||||||
|
|
||||||
func (e *obtainError) Join() error {
|
|
||||||
if e == nil {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
sort.Strings(domains)
|
||||||
|
|
||||||
if len(e.data) == 0 {
|
for _, domain := range domains {
|
||||||
return nil
|
buffer.WriteString(fmt.Sprintf("[%s] %s\n", domain, e[domain]))
|
||||||
}
|
}
|
||||||
|
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 {
|
type domainError struct {
|
||||||
|
129
vendor/github.com/go-acme/lego/v4/certificate/renewal.go
generated
vendored
129
vendor/github.com/go-acme/lego/v4/certificate/renewal.go
generated
vendored
@ -1,129 +0,0 @@
|
|||||||
package certificate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/asn1"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/acme"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RenewalInfoRequest contains the necessary renewal information.
|
|
||||||
type RenewalInfoRequest struct {
|
|
||||||
Cert *x509.Certificate
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewalInfoResponse is a wrapper around acme.RenewalInfoResponse that provides a method for determining when to renew a certificate.
|
|
||||||
type RenewalInfoResponse struct {
|
|
||||||
acme.RenewalInfoResponse
|
|
||||||
|
|
||||||
// RetryAfter header indicating the polling interval that the ACME server recommends.
|
|
||||||
// Conforming clients SHOULD query the renewalInfo URL again after the RetryAfter period has passed,
|
|
||||||
// as the server may provide a different suggestedWindow.
|
|
||||||
// https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-4.2
|
|
||||||
RetryAfter time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShouldRenewAt determines the optimal renewal time based on the current time (UTC),renewal window suggest by ARI, and the client's willingness to sleep.
|
|
||||||
// It returns a pointer to a time.Time value indicating when the renewal should be attempted or nil if deferred until the next normal wake time.
|
|
||||||
// This method implements the RECOMMENDED algorithm described in draft-ietf-acme-ari.
|
|
||||||
//
|
|
||||||
// - (4.1-11. Getting Renewal Information) https://datatracker.ietf.org/doc/draft-ietf-acme-ari/
|
|
||||||
func (r *RenewalInfoResponse) ShouldRenewAt(now time.Time, willingToSleep time.Duration) *time.Time {
|
|
||||||
// Explicitly convert all times to UTC.
|
|
||||||
now = now.UTC()
|
|
||||||
start := r.SuggestedWindow.Start.UTC()
|
|
||||||
end := r.SuggestedWindow.End.UTC()
|
|
||||||
|
|
||||||
// Select a uniform random time within the suggested window.
|
|
||||||
window := end.Sub(start)
|
|
||||||
randomDuration := time.Duration(rand.Int63n(int64(window)))
|
|
||||||
rt := start.Add(randomDuration)
|
|
||||||
|
|
||||||
// If the selected time is in the past, attempt renewal immediately.
|
|
||||||
if rt.Before(now) {
|
|
||||||
return &now
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, if the client can schedule itself to attempt renewal at exactly the selected time, do so.
|
|
||||||
willingToSleepUntil := now.Add(willingToSleep)
|
|
||||||
if willingToSleepUntil.After(rt) || willingToSleepUntil.Equal(rt) {
|
|
||||||
return &rt
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Otherwise, if the selected time is before the next time that the client would wake up normally, attempt renewal immediately.
|
|
||||||
|
|
||||||
// Otherwise, sleep until the next normal wake time, re-check ARI, and return to Step 1.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRenewalInfo sends a request to the ACME server's renewalInfo endpoint to obtain a suggested renewal window.
|
|
||||||
// The caller MUST provide the certificate and issuer certificate for the certificate they wish to renew.
|
|
||||||
// The caller should attempt to renew the certificate at the time indicated by the ShouldRenewAt method of the returned RenewalInfoResponse object.
|
|
||||||
//
|
|
||||||
// Note: this endpoint is part of a draft specification, not all ACME servers will implement it.
|
|
||||||
// This method will return api.ErrNoARI if the server does not advertise a renewal info endpoint.
|
|
||||||
//
|
|
||||||
// https://datatracker.ietf.org/doc/draft-ietf-acme-ari
|
|
||||||
func (c *Certifier) GetRenewalInfo(req RenewalInfoRequest) (*RenewalInfoResponse, error) {
|
|
||||||
certID, err := MakeARICertID(req.Cert)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error making certID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.core.Certificates.GetRenewalInfo(certID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
var info RenewalInfoResponse
|
|
||||||
err = json.NewDecoder(resp.Body).Decode(&info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if retry := resp.Header.Get("Retry-After"); retry != "" {
|
|
||||||
info.RetryAfter, err = time.ParseDuration(retry + "s")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeARICertID constructs a certificate identifier as described in draft-ietf-acme-ari-03, section 4.1.
|
|
||||||
func MakeARICertID(leaf *x509.Certificate) (string, error) {
|
|
||||||
if leaf == nil {
|
|
||||||
return "", errors.New("leaf certificate is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal the Serial Number into DER.
|
|
||||||
der, err := asn1.Marshal(leaf.SerialNumber)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the DER encoded bytes are sufficient (at least 3 bytes: tag,
|
|
||||||
// length, and value).
|
|
||||||
if len(der) < 3 {
|
|
||||||
return "", errors.New("invalid DER encoding of serial number")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract only the integer bytes from the DER encoded Serial Number
|
|
||||||
// Skipping the first 2 bytes (tag and length).
|
|
||||||
serial := base64.RawURLEncoding.EncodeToString(der[2:])
|
|
||||||
|
|
||||||
// Convert the Authority Key Identifier to base64url encoding without
|
|
||||||
// padding.
|
|
||||||
aki := base64.RawURLEncoding.EncodeToString(leaf.AuthorityKeyId)
|
|
||||||
|
|
||||||
// Construct the final identifier by concatenating AKI and Serial Number.
|
|
||||||
return fmt.Sprintf("%s.%s", aki, serial), nil
|
|
||||||
}
|
|
6
vendor/github.com/go-acme/lego/v4/challenge/challenges.go
generated
vendored
6
vendor/github.com/go-acme/lego/v4/challenge/challenges.go
generated
vendored
@ -10,15 +10,15 @@ import (
|
|||||||
type Type string
|
type Type string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// HTTP01 is the "http-01" ACME challenge https://www.rfc-editor.org/rfc/rfc8555.html#section-8.3
|
// HTTP01 is the "http-01" ACME challenge https://tools.ietf.org/html/rfc8555#section-8.3
|
||||||
// Note: ChallengePath returns the URL path to fulfill this challenge.
|
// Note: ChallengePath returns the URL path to fulfill this challenge.
|
||||||
HTTP01 = Type("http-01")
|
HTTP01 = Type("http-01")
|
||||||
|
|
||||||
// DNS01 is the "dns-01" ACME challenge https://www.rfc-editor.org/rfc/rfc8555.html#section-8.4
|
// DNS01 is the "dns-01" ACME challenge https://tools.ietf.org/html/rfc8555#section-8.4
|
||||||
// Note: GetRecord returns a DNS record which will fulfill this challenge.
|
// Note: GetRecord returns a DNS record which will fulfill this challenge.
|
||||||
DNS01 = Type("dns-01")
|
DNS01 = Type("dns-01")
|
||||||
|
|
||||||
// TLSALPN01 is the "tls-alpn-01" ACME challenge https://www.rfc-editor.org/rfc/rfc8737.html
|
// TLSALPN01 is the "tls-alpn-01" ACME challenge https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-07
|
||||||
TLSALPN01 = Type("tls-alpn-01")
|
TLSALPN01 = Type("tls-alpn-01")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/cname.go
generated
vendored
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/cname.go
generated
vendored
@ -1,16 +1,12 @@
|
|||||||
package dns01
|
package dns01
|
||||||
|
|
||||||
import (
|
import "github.com/miekg/dns"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Update FQDN with CNAME if any.
|
// Update FQDN with CNAME if any.
|
||||||
func updateDomainWithCName(r *dns.Msg, fqdn string) string {
|
func updateDomainWithCName(r *dns.Msg, fqdn string) string {
|
||||||
for _, rr := range r.Answer {
|
for _, rr := range r.Answer {
|
||||||
if cn, ok := rr.(*dns.CNAME); ok {
|
if cn, ok := rr.(*dns.CNAME); ok {
|
||||||
if strings.EqualFold(cn.Hdr.Name, fqdn) {
|
if cn.Hdr.Name == fqdn {
|
||||||
return cn.Target
|
return cn.Target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
69
vendor/github.com/go-acme/lego/v4/challenge/dns01/dns_challenge.go
generated
vendored
69
vendor/github.com/go-acme/lego/v4/challenge/dns01/dns_challenge.go
generated
vendored
@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/acme"
|
"github.com/go-acme/lego/v4/acme"
|
||||||
@ -115,7 +114,7 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := GetChallengeInfo(authz.Identifier.Value, keyAuth)
|
fqdn, value := GetRecord(authz.Identifier.Value, keyAuth)
|
||||||
|
|
||||||
var timeout, interval time.Duration
|
var timeout, interval time.Duration
|
||||||
switch provider := c.provider.(type) {
|
switch provider := c.provider.(type) {
|
||||||
@ -125,12 +124,12 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
|||||||
timeout, interval = DefaultPropagationTimeout, DefaultPollingInterval
|
timeout, interval = DefaultPropagationTimeout, DefaultPollingInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("[%s] acme: Checking DNS record propagation. [nameservers=%s]", domain, strings.Join(recursiveNameservers, ","))
|
log.Infof("[%s] acme: Checking DNS record propagation using %+v", domain, recursiveNameservers)
|
||||||
|
|
||||||
time.Sleep(interval)
|
time.Sleep(interval)
|
||||||
|
|
||||||
err = wait.For("propagation", timeout, interval, func() (bool, error) {
|
err = wait.For("propagation", timeout, interval, func() (bool, error) {
|
||||||
stop, errP := c.preCheck.call(domain, info.EffectiveFQDN, info.Value)
|
stop, errP := c.preCheck.call(domain, fqdn, value)
|
||||||
if !stop || errP != nil {
|
if !stop || errP != nil {
|
||||||
log.Infof("[%s] acme: Waiting for DNS record propagation.", domain)
|
log.Infof("[%s] acme: Waiting for DNS record propagation.", domain)
|
||||||
}
|
}
|
||||||
@ -173,67 +172,19 @@ type sequential interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetRecord returns a DNS record which will fulfill the `dns-01` challenge.
|
// GetRecord returns a DNS record which will fulfill the `dns-01` challenge.
|
||||||
// Deprecated: use GetChallengeInfo instead.
|
|
||||||
func GetRecord(domain, keyAuth string) (fqdn, value string) {
|
func GetRecord(domain, keyAuth string) (fqdn, value string) {
|
||||||
info := GetChallengeInfo(domain, keyAuth)
|
|
||||||
|
|
||||||
return info.EffectiveFQDN, info.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChallengeInfo contains the information use to create the TXT record.
|
|
||||||
type ChallengeInfo struct {
|
|
||||||
// FQDN is the full-qualified challenge domain (i.e. `_acme-challenge.[domain].`)
|
|
||||||
FQDN string
|
|
||||||
|
|
||||||
// EffectiveFQDN contains the resulting FQDN after the CNAMEs resolutions.
|
|
||||||
EffectiveFQDN string
|
|
||||||
|
|
||||||
// Value contains the value for the TXT record.
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChallengeInfo returns information used to create a DNS record which will fulfill the `dns-01` challenge.
|
|
||||||
func GetChallengeInfo(domain, keyAuth string) ChallengeInfo {
|
|
||||||
keyAuthShaBytes := sha256.Sum256([]byte(keyAuth))
|
keyAuthShaBytes := sha256.Sum256([]byte(keyAuth))
|
||||||
// base64URL encoding without padding
|
// base64URL encoding without padding
|
||||||
value := base64.RawURLEncoding.EncodeToString(keyAuthShaBytes[:sha256.Size])
|
value = base64.RawURLEncoding.EncodeToString(keyAuthShaBytes[:sha256.Size])
|
||||||
|
fqdn = fmt.Sprintf("_acme-challenge.%s.", domain)
|
||||||
|
|
||||||
ok, _ := strconv.ParseBool(os.Getenv("LEGO_DISABLE_CNAME_SUPPORT"))
|
if ok, _ := strconv.ParseBool(os.Getenv("LEGO_EXPERIMENTAL_CNAME_SUPPORT")); ok {
|
||||||
|
|
||||||
return ChallengeInfo{
|
|
||||||
Value: value,
|
|
||||||
FQDN: getChallengeFQDN(domain, false),
|
|
||||||
EffectiveFQDN: getChallengeFQDN(domain, !ok),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getChallengeFQDN(domain string, followCNAME bool) string {
|
|
||||||
fqdn := fmt.Sprintf("_acme-challenge.%s.", domain)
|
|
||||||
|
|
||||||
if !followCNAME {
|
|
||||||
return fqdn
|
|
||||||
}
|
|
||||||
|
|
||||||
// recursion counter so it doesn't spin out of control
|
|
||||||
for range 50 {
|
|
||||||
// Keep following CNAMEs
|
|
||||||
r, err := dnsQuery(fqdn, dns.TypeCNAME, recursiveNameservers, true)
|
r, err := dnsQuery(fqdn, dns.TypeCNAME, recursiveNameservers, true)
|
||||||
|
// Check if the domain has CNAME then return that
|
||||||
if err != nil || r.Rcode != dns.RcodeSuccess {
|
if err == nil && r.Rcode == dns.RcodeSuccess {
|
||||||
// No more CNAME records to follow, exit
|
fqdn = updateDomainWithCName(r, fqdn)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the domain has CNAME then use that
|
|
||||||
cname := updateDomainWithCName(r, fqdn)
|
|
||||||
if cname == fqdn {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Found CNAME entry for %q: %q", fqdn, cname)
|
|
||||||
|
|
||||||
fqdn = cname
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fqdn
|
return
|
||||||
}
|
}
|
||||||
|
23
vendor/github.com/go-acme/lego/v4/challenge/dns01/dns_challenge_manual.go
generated
vendored
23
vendor/github.com/go-acme/lego/v4/challenge/dns01/dns_challenge_manual.go
generated
vendored
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
dnsTemplate = `%s %d IN TXT %q`
|
dnsTemplate = `%s %d IN TXT "%s"`
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNSProviderManual is an implementation of the ChallengeProvider interface.
|
// DNSProviderManual is an implementation of the ChallengeProvider interface.
|
||||||
@ -21,36 +21,33 @@ func NewDNSProviderManual() (*DNSProviderManual, error) {
|
|||||||
|
|
||||||
// Present prints instructions for manually creating the TXT record.
|
// Present prints instructions for manually creating the TXT record.
|
||||||
func (*DNSProviderManual) Present(domain, token, keyAuth string) error {
|
func (*DNSProviderManual) Present(domain, token, keyAuth string) error {
|
||||||
info := GetChallengeInfo(domain, keyAuth)
|
fqdn, value := GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
authZone, err := FindZoneByFqdn(info.EffectiveFQDN)
|
authZone, err := FindZoneByFqdn(fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("manual: could not find zone: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("lego: Please create the following TXT record in your %s zone:\n", authZone)
|
fmt.Printf("lego: Please create the following TXT record in your %s zone:\n", authZone)
|
||||||
fmt.Printf(dnsTemplate+"\n", info.EffectiveFQDN, DefaultTTL, info.Value)
|
fmt.Printf(dnsTemplate+"\n", fqdn, DefaultTTL, value)
|
||||||
fmt.Printf("lego: Press 'Enter' when you are done\n")
|
fmt.Printf("lego: Press 'Enter' when you are done\n")
|
||||||
|
|
||||||
_, err = bufio.NewReader(os.Stdin).ReadBytes('\n')
|
_, err = bufio.NewReader(os.Stdin).ReadBytes('\n')
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("manual: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CleanUp prints instructions for manually removing the TXT record.
|
// CleanUp prints instructions for manually removing the TXT record.
|
||||||
func (*DNSProviderManual) CleanUp(domain, token, keyAuth string) error {
|
func (*DNSProviderManual) CleanUp(domain, token, keyAuth string) error {
|
||||||
info := GetChallengeInfo(domain, keyAuth)
|
fqdn, _ := GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
authZone, err := FindZoneByFqdn(info.EffectiveFQDN)
|
authZone, err := FindZoneByFqdn(fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("manual: could not find zone: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("lego: You can now remove this TXT record from your %s zone:\n", authZone)
|
fmt.Printf("lego: You can now remove this TXT record from your %s zone:\n", authZone)
|
||||||
fmt.Printf(dnsTemplate+"\n", info.EffectiveFQDN, DefaultTTL, "...")
|
fmt.Printf(dnsTemplate+"\n", fqdn, DefaultTTL, "...")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
24
vendor/github.com/go-acme/lego/v4/challenge/dns01/domain.go
generated
vendored
24
vendor/github.com/go-acme/lego/v4/challenge/dns01/domain.go
generated
vendored
@ -1,24 +0,0 @@
|
|||||||
package dns01
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ExtractSubDomain extracts the subdomain part from a domain and a zone.
|
|
||||||
func ExtractSubDomain(domain, zone string) (string, error) {
|
|
||||||
canonDomain := dns.Fqdn(domain)
|
|
||||||
canonZone := dns.Fqdn(zone)
|
|
||||||
|
|
||||||
if canonDomain == canonZone {
|
|
||||||
return "", fmt.Errorf("no subdomain because the domain and the zone are identical: %s", canonDomain)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dns.IsSubDomain(canonZone, canonDomain) {
|
|
||||||
return "", fmt.Errorf("%s is not a subdomain of %s", canonDomain, canonZone)
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.TrimSuffix(canonDomain, "."+canonZone), nil
|
|
||||||
}
|
|
155
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver.go
generated
vendored
155
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver.go
generated
vendored
@ -4,9 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"slices"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -16,6 +13,9 @@ import (
|
|||||||
|
|
||||||
const defaultResolvConf = "/etc/resolv.conf"
|
const defaultResolvConf = "/etc/resolv.conf"
|
||||||
|
|
||||||
|
// dnsTimeout is used to override the default DNS timeout of 10 seconds.
|
||||||
|
var dnsTimeout = 10 * time.Second
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fqdnSoaCache = map[string]*soaCacheEntry{}
|
fqdnSoaCache = map[string]*soaCacheEntry{}
|
||||||
muFqdnSoaCache sync.Mutex
|
muFqdnSoaCache sync.Mutex
|
||||||
@ -99,12 +99,12 @@ func lookupNameservers(fqdn string) ([]string, error) {
|
|||||||
|
|
||||||
zone, err := FindZoneByFqdn(fqdn)
|
zone, err := FindZoneByFqdn(fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not find zone: %w", err)
|
return nil, fmt.Errorf("could not determine the zone: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := dnsQuery(zone, dns.TypeNS, recursiveNameservers, true)
|
r, err := dnsQuery(zone, dns.TypeNS, recursiveNameservers, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NS call failed: %w", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rr := range r.Answer {
|
for _, rr := range r.Answer {
|
||||||
@ -116,8 +116,7 @@ func lookupNameservers(fqdn string) ([]string, error) {
|
|||||||
if len(authoritativeNss) > 0 {
|
if len(authoritativeNss) > 0 {
|
||||||
return authoritativeNss, nil
|
return authoritativeNss, nil
|
||||||
}
|
}
|
||||||
|
return nil, errors.New("could not determine authoritative nameservers")
|
||||||
return nil, fmt.Errorf("[zone=%s] could not determine authoritative nameservers", zone)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindPrimaryNsByFqdn determines the primary nameserver of the zone apex for the given fqdn
|
// FindPrimaryNsByFqdn determines the primary nameserver of the zone apex for the given fqdn
|
||||||
@ -131,7 +130,7 @@ func FindPrimaryNsByFqdn(fqdn string) (string, error) {
|
|||||||
func FindPrimaryNsByFqdnCustom(fqdn string, nameservers []string) (string, error) {
|
func FindPrimaryNsByFqdnCustom(fqdn string, nameservers []string) (string, error) {
|
||||||
soa, err := lookupSoaByFqdn(fqdn, nameservers)
|
soa, err := lookupSoaByFqdn(fqdn, nameservers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("[fqdn=%s] %w", fqdn, err)
|
return "", err
|
||||||
}
|
}
|
||||||
return soa.primaryNs, nil
|
return soa.primaryNs, nil
|
||||||
}
|
}
|
||||||
@ -147,7 +146,7 @@ func FindZoneByFqdn(fqdn string) (string, error) {
|
|||||||
func FindZoneByFqdnCustom(fqdn string, nameservers []string) (string, error) {
|
func FindZoneByFqdnCustom(fqdn string, nameservers []string) (string, error) {
|
||||||
soa, err := lookupSoaByFqdn(fqdn, nameservers)
|
soa, err := lookupSoaByFqdn(fqdn, nameservers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("[fqdn=%s] %w", fqdn, err)
|
return "", err
|
||||||
}
|
}
|
||||||
return soa.zone, nil
|
return soa.zone, nil
|
||||||
}
|
}
|
||||||
@ -172,35 +171,35 @@ func lookupSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error)
|
|||||||
|
|
||||||
func fetchSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error) {
|
func fetchSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error) {
|
||||||
var err error
|
var err error
|
||||||
var r *dns.Msg
|
var in *dns.Msg
|
||||||
|
|
||||||
labelIndexes := dns.Split(fqdn)
|
labelIndexes := dns.Split(fqdn)
|
||||||
for _, index := range labelIndexes {
|
for _, index := range labelIndexes {
|
||||||
domain := fqdn[index:]
|
domain := fqdn[index:]
|
||||||
|
|
||||||
r, err = dnsQuery(domain, dns.TypeSOA, nameservers, true)
|
in, err = dnsQuery(domain, dns.TypeSOA, nameservers, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if r == nil {
|
if in == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
switch r.Rcode {
|
switch in.Rcode {
|
||||||
case dns.RcodeSuccess:
|
case dns.RcodeSuccess:
|
||||||
// Check if we got a SOA RR in the answer section
|
// Check if we got a SOA RR in the answer section
|
||||||
if len(r.Answer) == 0 {
|
if len(in.Answer) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// CNAME records cannot/should not exist at the root of a zone.
|
// CNAME records cannot/should not exist at the root of a zone.
|
||||||
// So we skip a domain when a CNAME is found.
|
// So we skip a domain when a CNAME is found.
|
||||||
if dnsMsgContainsCNAME(r) {
|
if dnsMsgContainsCNAME(in) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ans := range r.Answer {
|
for _, ans := range in.Answer {
|
||||||
if soa, ok := ans.(*dns.SOA); ok {
|
if soa, ok := ans.(*dns.SOA); ok {
|
||||||
return newSoaCacheEntry(soa), nil
|
return newSoaCacheEntry(soa), nil
|
||||||
}
|
}
|
||||||
@ -209,46 +208,36 @@ func fetchSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error) {
|
|||||||
// NXDOMAIN
|
// NXDOMAIN
|
||||||
default:
|
default:
|
||||||
// Any response code other than NOERROR and NXDOMAIN is treated as error
|
// Any response code other than NOERROR and NXDOMAIN is treated as error
|
||||||
return nil, &DNSError{Message: fmt.Sprintf("unexpected response for '%s'", domain), MsgOut: r}
|
return nil, fmt.Errorf("unexpected response code '%s' for %s", dns.RcodeToString[in.Rcode], domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, &DNSError{Message: fmt.Sprintf("could not find the start of authority for '%s'", fqdn), MsgOut: r, Err: err}
|
return nil, fmt.Errorf("could not find the start of authority for %s%s", fqdn, formatDNSError(in, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// dnsMsgContainsCNAME checks for a CNAME answer in msg.
|
// dnsMsgContainsCNAME checks for a CNAME answer in msg.
|
||||||
func dnsMsgContainsCNAME(msg *dns.Msg) bool {
|
func dnsMsgContainsCNAME(msg *dns.Msg) bool {
|
||||||
return slices.ContainsFunc(msg.Answer, func(rr dns.RR) bool {
|
for _, ans := range msg.Answer {
|
||||||
_, ok := rr.(*dns.CNAME)
|
if _, ok := ans.(*dns.CNAME); ok {
|
||||||
return ok
|
return true
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func dnsQuery(fqdn string, rtype uint16, nameservers []string, recursive bool) (*dns.Msg, error) {
|
func dnsQuery(fqdn string, rtype uint16, nameservers []string, recursive bool) (*dns.Msg, error) {
|
||||||
m := createDNSMsg(fqdn, rtype, recursive)
|
m := createDNSMsg(fqdn, rtype, recursive)
|
||||||
|
|
||||||
if len(nameservers) == 0 {
|
var in *dns.Msg
|
||||||
return nil, &DNSError{Message: "empty list of nameservers"}
|
|
||||||
}
|
|
||||||
|
|
||||||
var r *dns.Msg
|
|
||||||
var err error
|
var err error
|
||||||
var errAll error
|
|
||||||
|
|
||||||
for _, ns := range nameservers {
|
for _, ns := range nameservers {
|
||||||
r, err = sendDNSQuery(m, ns)
|
in, err = sendDNSQuery(m, ns)
|
||||||
if err == nil && len(r.Answer) > 0 {
|
if err == nil && len(in.Answer) > 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
errAll = errors.Join(errAll, err)
|
|
||||||
}
|
}
|
||||||
|
return in, err
|
||||||
if err != nil {
|
|
||||||
return r, errAll
|
|
||||||
}
|
|
||||||
|
|
||||||
return r, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createDNSMsg(fqdn string, rtype uint16, recursive bool) *dns.Msg {
|
func createDNSMsg(fqdn string, rtype uint16, recursive bool) *dns.Msg {
|
||||||
@ -264,84 +253,32 @@ func createDNSMsg(fqdn string, rtype uint16, recursive bool) *dns.Msg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sendDNSQuery(m *dns.Msg, ns string) (*dns.Msg, error) {
|
func sendDNSQuery(m *dns.Msg, ns string) (*dns.Msg, error) {
|
||||||
if ok, _ := strconv.ParseBool(os.Getenv("LEGO_EXPERIMENTAL_DNS_TCP_ONLY")); ok {
|
udp := &dns.Client{Net: "udp", Timeout: dnsTimeout}
|
||||||
tcp := &dns.Client{Net: "tcp", Timeout: dnsTimeout}
|
in, _, err := udp.Exchange(m, ns)
|
||||||
r, _, err := tcp.Exchange(m, ns)
|
|
||||||
if err != nil {
|
|
||||||
return r, &DNSError{Message: "DNS call error", MsgIn: m, NS: ns, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r, nil
|
if in != nil && in.Truncated {
|
||||||
|
tcp := &dns.Client{Net: "tcp", Timeout: dnsTimeout}
|
||||||
|
// If the TCP request succeeds, the err will reset to nil
|
||||||
|
in, _, err = tcp.Exchange(m, ns)
|
||||||
}
|
}
|
||||||
|
|
||||||
udp := &dns.Client{Net: "udp", Timeout: dnsTimeout}
|
return in, err
|
||||||
r, _, err := udp.Exchange(m, ns)
|
}
|
||||||
|
|
||||||
if r != nil && r.Truncated {
|
func formatDNSError(msg *dns.Msg, err error) string {
|
||||||
tcp := &dns.Client{Net: "tcp", Timeout: dnsTimeout}
|
var parts []string
|
||||||
// If the TCP request succeeds, the "err" will reset to nil
|
|
||||||
r, _, err = tcp.Exchange(m, ns)
|
if msg != nil {
|
||||||
|
parts = append(parts, dns.RcodeToString[msg.Rcode])
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, &DNSError{Message: "DNS call error", MsgIn: m, NS: ns, Err: err}
|
parts = append(parts, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return r, nil
|
if len(parts) > 0 {
|
||||||
}
|
return ": " + strings.Join(parts, " ")
|
||||||
|
}
|
||||||
// DNSError error related to DNS calls.
|
|
||||||
type DNSError struct {
|
return ""
|
||||||
Message string
|
|
||||||
NS string
|
|
||||||
MsgIn *dns.Msg
|
|
||||||
MsgOut *dns.Msg
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNSError) Error() string {
|
|
||||||
var details []string
|
|
||||||
if d.NS != "" {
|
|
||||||
details = append(details, "ns="+d.NS)
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.MsgIn != nil && len(d.MsgIn.Question) > 0 {
|
|
||||||
details = append(details, fmt.Sprintf("question='%s'", formatQuestions(d.MsgIn.Question)))
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.MsgOut != nil {
|
|
||||||
if d.MsgIn == nil || len(d.MsgIn.Question) == 0 {
|
|
||||||
details = append(details, fmt.Sprintf("question='%s'", formatQuestions(d.MsgOut.Question)))
|
|
||||||
}
|
|
||||||
|
|
||||||
details = append(details, "code="+dns.RcodeToString[d.MsgOut.Rcode])
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := "DNS error"
|
|
||||||
if d.Message != "" {
|
|
||||||
msg = d.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.Err != nil {
|
|
||||||
msg += ": " + d.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(details) > 0 {
|
|
||||||
msg += " [" + strings.Join(details, ", ") + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNSError) Unwrap() error {
|
|
||||||
return d.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatQuestions(questions []dns.Question) string {
|
|
||||||
var parts []string
|
|
||||||
for _, question := range questions {
|
|
||||||
parts = append(parts, strings.ReplaceAll(strings.TrimPrefix(question.String(), ";"), "\t", " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(parts, ";")
|
|
||||||
}
|
}
|
||||||
|
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver_unix.go
generated
vendored
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver_unix.go
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
//go:build !windows
|
|
||||||
|
|
||||||
package dns01
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// dnsTimeout is used to override the default DNS timeout of 10 seconds.
|
|
||||||
var dnsTimeout = 10 * time.Second
|
|
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver_windows.go
generated
vendored
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver_windows.go
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package dns01
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// dnsTimeout is used to override the default DNS timeout of 20 seconds.
|
|
||||||
var dnsTimeout = 20 * time.Second
|
|
13
vendor/github.com/go-acme/lego/v4/challenge/http01/domain_matcher.go
generated
vendored
13
vendor/github.com/go-acme/lego/v4/challenge/http01/domain_matcher.go
generated
vendored
@ -23,17 +23,14 @@ import (
|
|||||||
// RFC7239 has standardized the different forwarding headers into a single header named Forwarded.
|
// RFC7239 has standardized the different forwarding headers into a single header named Forwarded.
|
||||||
// The header value has a different format, so you should use forwardedMatcher
|
// The header value has a different format, so you should use forwardedMatcher
|
||||||
// when the http01.ProviderServer operates behind a RFC7239 compatible proxy.
|
// when the http01.ProviderServer operates behind a RFC7239 compatible proxy.
|
||||||
// https://www.rfc-editor.org/rfc/rfc7239.html
|
// https://tools.ietf.org/html/rfc7239
|
||||||
//
|
//
|
||||||
// Note: RFC7239 also reminds us, "that an HTTP list [...] may be split over multiple header fields" (section 7.1),
|
// Note: RFC7239 also reminds us, "that an HTTP list [...] may be split over multiple header fields" (section 7.1),
|
||||||
// meaning that
|
// meaning that
|
||||||
//
|
// X-Header: a
|
||||||
// X-Header: a
|
// X-Header: b
|
||||||
// X-Header: b
|
|
||||||
//
|
|
||||||
// is equal to
|
// is equal to
|
||||||
//
|
// X-Header: a, b
|
||||||
// X-Header: a, b
|
|
||||||
//
|
//
|
||||||
// All matcher implementations (explicitly not excluding arbitraryMatcher!)
|
// All matcher implementations (explicitly not excluding arbitraryMatcher!)
|
||||||
// have in common that they only match against the first value in such lists.
|
// have in common that they only match against the first value in such lists.
|
||||||
@ -69,7 +66,7 @@ func (m arbitraryMatcher) matches(r *http.Request, domain string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// forwardedMatcher checks whether the Forwarded header contains a "host" element starting with a domain name.
|
// forwardedMatcher checks whether the Forwarded header contains a "host" element starting with a domain name.
|
||||||
// See https://www.rfc-editor.org/rfc/rfc7239.html for details.
|
// See https://tools.ietf.org/html/rfc7239 for details.
|
||||||
type forwardedMatcher struct{}
|
type forwardedMatcher struct{}
|
||||||
|
|
||||||
func (m *forwardedMatcher) name() string {
|
func (m *forwardedMatcher) name() string {
|
||||||
|
31
vendor/github.com/go-acme/lego/v4/challenge/http01/http_challenge_server.go
generated
vendored
31
vendor/github.com/go-acme/lego/v4/challenge/http01/http_challenge_server.go
generated
vendored
@ -2,11 +2,9 @@ package http01
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/log"
|
"github.com/go-acme/lego/v4/log"
|
||||||
@ -16,11 +14,8 @@ import (
|
|||||||
// It may be instantiated without using the NewProviderServer function if
|
// It may be instantiated without using the NewProviderServer function if
|
||||||
// you want only to use the default values.
|
// you want only to use the default values.
|
||||||
type ProviderServer struct {
|
type ProviderServer struct {
|
||||||
address string
|
iface string
|
||||||
network string // must be valid argument to net.Listen
|
port string
|
||||||
|
|
||||||
socketMode fs.FileMode
|
|
||||||
|
|
||||||
matcher domainMatcher
|
matcher domainMatcher
|
||||||
done chan bool
|
done chan bool
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
@ -34,34 +29,24 @@ func NewProviderServer(iface, port string) *ProviderServer {
|
|||||||
port = "80"
|
port = "80"
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ProviderServer{network: "tcp", address: net.JoinHostPort(iface, port), matcher: &hostMatcher{}}
|
return &ProviderServer{iface: iface, port: port, matcher: &hostMatcher{}}
|
||||||
}
|
|
||||||
|
|
||||||
func NewUnixProviderServer(socketPath string, mode fs.FileMode) *ProviderServer {
|
|
||||||
return &ProviderServer{network: "unix", address: socketPath, socketMode: mode, matcher: &hostMatcher{}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present starts a web server and makes the token available at `ChallengePath(token)` for web requests.
|
// Present starts a web server and makes the token available at `ChallengePath(token)` for web requests.
|
||||||
func (s *ProviderServer) Present(domain, token, keyAuth string) error {
|
func (s *ProviderServer) Present(domain, token, keyAuth string) error {
|
||||||
var err error
|
var err error
|
||||||
s.listener, err = net.Listen(s.network, s.GetAddress())
|
s.listener, err = net.Listen("tcp", s.GetAddress())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not start HTTP server for challenge: %w", err)
|
return fmt.Errorf("could not start HTTP server for challenge: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.network == "unix" {
|
|
||||||
if err = os.Chmod(s.address, s.socketMode); err != nil {
|
|
||||||
return fmt.Errorf("chmod %s: %w", s.address, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.done = make(chan bool)
|
s.done = make(chan bool)
|
||||||
go s.serve(domain, token, keyAuth)
|
go s.serve(domain, token, keyAuth)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProviderServer) GetAddress() string {
|
func (s *ProviderServer) GetAddress() string {
|
||||||
return s.address
|
return net.JoinHostPort(s.iface, s.port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CleanUp closes the HTTP server and removes the token from `ChallengePath(token)`.
|
// CleanUp closes the HTTP server and removes the token from `ChallengePath(token)`.
|
||||||
@ -84,7 +69,7 @@ func (s *ProviderServer) CleanUp(domain, token, keyAuth string) error {
|
|||||||
//
|
//
|
||||||
// The exact behavior depends on the value of headerName:
|
// The exact behavior depends on the value of headerName:
|
||||||
// - "" (the empty string) and "Host" will restore the default and only check the Host header
|
// - "" (the empty string) and "Host" will restore the default and only check the Host header
|
||||||
// - "Forwarded" will look for a Forwarded header, and inspect it according to https://www.rfc-editor.org/rfc/rfc7239.html
|
// - "Forwarded" will look for a Forwarded header, and inspect it according to https://tools.ietf.org/html/rfc7239
|
||||||
// - any other value will check the header value with the same name.
|
// - any other value will check the header value with the same name.
|
||||||
func (s *ProviderServer) SetProxyHeader(headerName string) {
|
func (s *ProviderServer) SetProxyHeader(headerName string) {
|
||||||
switch h := textproto.CanonicalMIMEHeaderKey(headerName); h {
|
switch h := textproto.CanonicalMIMEHeaderKey(headerName); h {
|
||||||
@ -100,7 +85,7 @@ func (s *ProviderServer) SetProxyHeader(headerName string) {
|
|||||||
func (s *ProviderServer) serve(domain, token, keyAuth string) {
|
func (s *ProviderServer) serve(domain, token, keyAuth string) {
|
||||||
path := ChallengePath(token)
|
path := ChallengePath(token)
|
||||||
|
|
||||||
// The incoming request will be validated to prevent DNS rebind attacks.
|
// The incoming request must will be validated to prevent DNS rebind attacks.
|
||||||
// We only respond with the keyAuth, when we're receiving a GET requests with
|
// We only respond with the keyAuth, when we're receiving a GET requests with
|
||||||
// the "Host" header matching the domain (the latter is configurable though SetProxyHeader).
|
// the "Host" header matching the domain (the latter is configurable though SetProxyHeader).
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
@ -114,7 +99,7 @@ func (s *ProviderServer) serve(domain, token, keyAuth string) {
|
|||||||
}
|
}
|
||||||
log.Infof("[%s] Served key authentication", domain)
|
log.Infof("[%s] Served key authentication", domain)
|
||||||
} else {
|
} else {
|
||||||
log.Warnf("Received request for domain %s with method %s but the domain did not match any challenge. Please ensure you are passing the %s header properly.", r.Host, r.Method, s.matcher.name())
|
log.Warnf("Received request for domain %s with method %s but the domain did not match any challenge. Please ensure your are passing the %s header properly.", r.Host, r.Method, s.matcher.name())
|
||||||
_, err := w.Write([]byte("TEST"))
|
_, err := w.Write([]byte("TEST"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
2
vendor/github.com/go-acme/lego/v4/challenge/resolver/errors.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/challenge/resolver/errors.go
generated
vendored
@ -19,7 +19,7 @@ func (e obtainError) Error() string {
|
|||||||
sort.Strings(domains)
|
sort.Strings(domains)
|
||||||
|
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
_, _ = fmt.Fprintf(buffer, "[%s] %s\n", domain, e[domain])
|
buffer.WriteString(fmt.Sprintf("[%s] %s\n", domain, e[domain]))
|
||||||
}
|
}
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
2
vendor/github.com/go-acme/lego/v4/challenge/resolver/prober.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/challenge/resolver/prober.go
generated
vendored
@ -128,7 +128,7 @@ func sequentialSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
|
func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
|
||||||
// For all valid preSolvers, first submit the challenges, so they have max time to propagate
|
// For all valid preSolvers, first submit the challenges so they have max time to propagate
|
||||||
for _, authSolver := range authSolvers {
|
for _, authSolver := range authSolvers {
|
||||||
authz := authSolver.authz
|
authz := authSolver.authz
|
||||||
if solvr, ok := authSolver.solver.(preSolver); ok {
|
if solvr, ok := authSolver.solver.(preSolver); ok {
|
||||||
|
13
vendor/github.com/go-acme/lego/v4/challenge/resolver/solver_manager.go
generated
vendored
13
vendor/github.com/go-acme/lego/v4/challenge/resolver/solver_manager.go
generated
vendored
@ -1,6 +1,7 @@
|
|||||||
package resolver
|
package resolver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
@ -53,7 +54,7 @@ func (c *SolverManager) SetDNS01Provider(p challenge.Provider, opts ...dns01.Cha
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes a challenge type from the available solvers.
|
// Remove Remove a challenge type from the available solvers.
|
||||||
func (c *SolverManager) Remove(chlgType challenge.Type) {
|
func (c *SolverManager) Remove(chlgType challenge.Type) {
|
||||||
delete(c.solvers, chlgType)
|
delete(c.solvers, chlgType)
|
||||||
}
|
}
|
||||||
@ -106,17 +107,21 @@ func validate(core *api.Core, domain string, chlg acme.Challenge) error {
|
|||||||
bo.MaxInterval = 10 * initialInterval
|
bo.MaxInterval = 10 * initialInterval
|
||||||
bo.MaxElapsedTime = 100 * initialInterval
|
bo.MaxElapsedTime = 100 * initialInterval
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
// After the path is sent, the ACME server will access our server.
|
// After the path is sent, the ACME server will access our server.
|
||||||
// Repeatedly check the server for an updated status on our request.
|
// Repeatedly check the server for an updated status on our request.
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
authz, err := core.Authorizations.Get(chlng.AuthorizationURL)
|
authz, err := core.Authorizations.Get(chlng.AuthorizationURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return backoff.Permanent(err)
|
cancel()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
valid, err := checkAuthorizationStatus(authz)
|
valid, err := checkAuthorizationStatus(authz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return backoff.Permanent(err)
|
cancel()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if valid {
|
if valid {
|
||||||
@ -127,7 +132,7 @@ func validate(core *api.Core, domain string, chlg acme.Challenge) error {
|
|||||||
return errors.New("the server didn't respond to our request")
|
return errors.New("the server didn't respond to our request")
|
||||||
}
|
}
|
||||||
|
|
||||||
return backoff.Retry(operation, bo)
|
return backoff.Retry(operation, backoff.WithContext(bo, ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkChallengeStatus(chlng acme.ExtendedChallenge) (bool, error) {
|
func checkChallengeStatus(chlng acme.ExtendedChallenge) (bool, error) {
|
||||||
|
4
vendor/github.com/go-acme/lego/v4/challenge/tlsalpn01/tls_alpn_challenge.go
generated
vendored
4
vendor/github.com/go-acme/lego/v4/challenge/tlsalpn01/tls_alpn_challenge.go
generated
vendored
@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// idPeAcmeIdentifierV1 is the SMI Security for PKIX Certification Extension OID referencing the ACME extension.
|
// idPeAcmeIdentifierV1 is the SMI Security for PKIX Certification Extension OID referencing the ACME extension.
|
||||||
// Reference: https://www.rfc-editor.org/rfc/rfc8737.html#section-6.1
|
// Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-07#section-6.1
|
||||||
var idPeAcmeIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}
|
var idPeAcmeIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}
|
||||||
|
|
||||||
type ValidateFunc func(core *api.Core, domain string, chlng acme.Challenge) error
|
type ValidateFunc func(core *api.Core, domain string, chlng acme.Challenge) error
|
||||||
@ -83,7 +83,7 @@ func ChallengeBlocks(domain, keyAuth string) ([]byte, []byte, error) {
|
|||||||
|
|
||||||
// Add the keyAuth digest as the acmeValidation-v1 extension
|
// Add the keyAuth digest as the acmeValidation-v1 extension
|
||||||
// (marked as critical such that it won't be used by non-ACME software).
|
// (marked as critical such that it won't be used by non-ACME software).
|
||||||
// Reference: https://www.rfc-editor.org/rfc/rfc8737.html#section-3
|
// Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-07#section-3
|
||||||
extensions := []pkix.Extension{
|
extensions := []pkix.Extension{
|
||||||
{
|
{
|
||||||
Id: idPeAcmeIdentifierV1,
|
Id: idPeAcmeIdentifierV1,
|
||||||
|
4
vendor/github.com/go-acme/lego/v4/challenge/tlsalpn01/tls_alpn_challenge_server.go
generated
vendored
4
vendor/github.com/go-acme/lego/v4/challenge/tlsalpn01/tls_alpn_challenge_server.go
generated
vendored
@ -40,7 +40,7 @@ func (s *ProviderServer) GetAddress() string {
|
|||||||
return net.JoinHostPort(s.iface, s.port)
|
return net.JoinHostPort(s.iface, s.port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present generates a certificate with an SHA-256 digest of the keyAuth provided
|
// Present generates a certificate with a SHA-256 digest of the keyAuth provided
|
||||||
// as the acmeValidation-v1 extension value to conform to the ACME-TLS-ALPN spec.
|
// as the acmeValidation-v1 extension value to conform to the ACME-TLS-ALPN spec.
|
||||||
func (s *ProviderServer) Present(domain, token, keyAuth string) error {
|
func (s *ProviderServer) Present(domain, token, keyAuth string) error {
|
||||||
if s.port == "" {
|
if s.port == "" {
|
||||||
@ -61,7 +61,7 @@ func (s *ProviderServer) Present(domain, token, keyAuth string) error {
|
|||||||
|
|
||||||
// We must set that the `acme-tls/1` application level protocol is supported
|
// We must set that the `acme-tls/1` application level protocol is supported
|
||||||
// so that the protocol negotiation can succeed. Reference:
|
// so that the protocol negotiation can succeed. Reference:
|
||||||
// https://www.rfc-editor.org/rfc/rfc8737.html#section-6.2
|
// https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-07#section-6.2
|
||||||
tlsConf.NextProtos = []string{ACMETLS1Protocol}
|
tlsConf.NextProtos = []string{ACMETLS1Protocol}
|
||||||
|
|
||||||
// Create the listener with the created tls.Config.
|
// Create the listener with the created tls.Config.
|
||||||
|
61
vendor/github.com/go-acme/lego/v4/lego/client_config.go
generated
vendored
61
vendor/github.com/go-acme/lego/v4/lego/client_config.go
generated
vendored
@ -4,11 +4,10 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
@ -18,18 +17,13 @@ import (
|
|||||||
const (
|
const (
|
||||||
// caCertificatesEnvVar is the environment variable name that can be used to
|
// caCertificatesEnvVar is the environment variable name that can be used to
|
||||||
// specify the path to PEM encoded CA Certificates that can be used to
|
// specify the path to PEM encoded CA Certificates that can be used to
|
||||||
// authenticate an ACME server with an HTTPS certificate not issued by a CA in
|
// authenticate an ACME server with a HTTPS certificate not issued by a CA in
|
||||||
// the system-wide trusted root list.
|
// the system-wide trusted root list.
|
||||||
// Multiple file paths can be added by using os.PathListSeparator as a separator.
|
|
||||||
caCertificatesEnvVar = "LEGO_CA_CERTIFICATES"
|
caCertificatesEnvVar = "LEGO_CA_CERTIFICATES"
|
||||||
|
|
||||||
// caSystemCertPool is the environment variable name that can be used to define
|
|
||||||
// if the certificates pool must use a copy of the system cert pool.
|
|
||||||
caSystemCertPool = "LEGO_CA_SYSTEM_CERT_POOL"
|
|
||||||
|
|
||||||
// caServerNameEnvVar is the environment variable name that can be used to
|
// caServerNameEnvVar is the environment variable name that can be used to
|
||||||
// specify the CA server name that can be used to
|
// specify the CA server name that can be used to
|
||||||
// authenticate an ACME server with an HTTPS certificate not issued by a CA in
|
// authenticate an ACME server with a HTTPS certificate not issued by a CA in
|
||||||
// the system-wide trusted root list.
|
// the system-wide trusted root list.
|
||||||
caServerNameEnvVar = "LEGO_CA_SERVER_NAME"
|
caServerNameEnvVar = "LEGO_CA_SERVER_NAME"
|
||||||
|
|
||||||
@ -70,15 +64,15 @@ type CertificateConfig struct {
|
|||||||
// based on the caCertificatesEnvVar environment variable (see the `initCertPool` function).
|
// based on the caCertificatesEnvVar environment variable (see the `initCertPool` function).
|
||||||
func createDefaultHTTPClient() *http.Client {
|
func createDefaultHTTPClient() *http.Client {
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
Timeout: 2 * time.Minute,
|
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
DialContext: (&net.Dialer{
|
DialContext: (&net.Dialer{
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
KeepAlive: 30 * time.Second,
|
KeepAlive: 30 * time.Second,
|
||||||
}).DialContext,
|
}).DialContext,
|
||||||
TLSHandshakeTimeout: 30 * time.Second,
|
TLSHandshakeTimeout: 15 * time.Second,
|
||||||
ResponseHeaderTimeout: 30 * time.Second,
|
ResponseHeaderTimeout: 15 * time.Second,
|
||||||
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: &tls.Config{
|
||||||
ServerName: os.Getenv(caServerNameEnvVar),
|
ServerName: os.Getenv(caServerNameEnvVar),
|
||||||
RootCAs: initCertPool(),
|
RootCAs: initCertPool(),
|
||||||
@ -88,44 +82,23 @@ func createDefaultHTTPClient() *http.Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initCertPool creates a *x509.CertPool populated with the PEM certificates
|
// initCertPool creates a *x509.CertPool populated with the PEM certificates
|
||||||
// found in the filepath specified in the caCertificatesEnvVar OS environment variable.
|
// found in the filepath specified in the caCertificatesEnvVar OS environment
|
||||||
// If the caCertificatesEnvVar is not set then initCertPool will return nil.
|
// variable. If the caCertificatesEnvVar is not set then initCertPool will
|
||||||
// If there is an error creating a *x509.CertPool from the provided caCertificatesEnvVar value then initCertPool will panic.
|
// return nil. If there is an error creating a *x509.CertPool from the provided
|
||||||
// If the caSystemCertPool is set to a "truthy value" (`1`, `t`, `T`, `TRUE`, `true`, `True`) then a copy of system cert pool will be used.
|
// caCertificatesEnvVar value then initCertPool will panic.
|
||||||
// caSystemCertPool requires caCertificatesEnvVar to be set.
|
|
||||||
func initCertPool() *x509.CertPool {
|
func initCertPool() *x509.CertPool {
|
||||||
customCACertsPath := os.Getenv(caCertificatesEnvVar)
|
if customCACertsPath := os.Getenv(caCertificatesEnvVar); customCACertsPath != "" {
|
||||||
if customCACertsPath == "" {
|
customCAs, err := ioutil.ReadFile(customCACertsPath)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
certPool := getCertPool()
|
|
||||||
|
|
||||||
for _, customPath := range strings.Split(customCACertsPath, string(os.PathListSeparator)) {
|
|
||||||
customCAs, err := os.ReadFile(customPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error reading %s=%q: %v",
|
panic(fmt.Sprintf("error reading %s=%q: %v",
|
||||||
caCertificatesEnvVar, customPath, err))
|
caCertificatesEnvVar, customCACertsPath, err))
|
||||||
}
|
}
|
||||||
|
certPool := x509.NewCertPool()
|
||||||
if ok := certPool.AppendCertsFromPEM(customCAs); !ok {
|
if ok := certPool.AppendCertsFromPEM(customCAs); !ok {
|
||||||
panic(fmt.Sprintf("error creating x509 cert pool from %s=%q: %v",
|
panic(fmt.Sprintf("error creating x509 cert pool from %s=%q: %v",
|
||||||
caCertificatesEnvVar, customPath, err))
|
caCertificatesEnvVar, customCACertsPath, err))
|
||||||
}
|
}
|
||||||
|
return certPool
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
return certPool
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCertPool() *x509.CertPool {
|
|
||||||
useSystemCertPool, _ := strconv.ParseBool(os.Getenv(caSystemCertPool))
|
|
||||||
if !useSystemCertPool {
|
|
||||||
return x509.NewCertPool()
|
|
||||||
}
|
|
||||||
|
|
||||||
pool, err := x509.SystemCertPool()
|
|
||||||
if err == nil {
|
|
||||||
return pool
|
|
||||||
}
|
|
||||||
return x509.NewCertPool()
|
|
||||||
}
|
}
|
||||||
|
2
vendor/github.com/go-acme/lego/v4/log/logger.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/log/logger.go
generated
vendored
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Logger is an optional custom logger.
|
// Logger is an optional custom logger.
|
||||||
var Logger StdLogger = log.New(os.Stderr, "", log.LstdFlags)
|
var Logger StdLogger = log.New(os.Stdout, "", log.LstdFlags)
|
||||||
|
|
||||||
// StdLogger interface for Standard Logger.
|
// StdLogger interface for Standard Logger.
|
||||||
type StdLogger interface {
|
type StdLogger interface {
|
||||||
|
107
vendor/github.com/go-acme/lego/v4/platform/config/env/env.go
generated
vendored
107
vendor/github.com/go-acme/lego/v4/platform/config/env/env.go
generated
vendored
@ -3,6 +3,7 @@ package env
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -31,29 +32,28 @@ func Get(names ...string) (map[string]string, error) {
|
|||||||
return values, nil
|
return values, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWithFallback Get environment variable values.
|
// GetWithFallback Get environment variable values
|
||||||
// The first name in each group is use as key in the result map.
|
// The first name in each group is use as key in the result map
|
||||||
//
|
|
||||||
// case 1:
|
|
||||||
//
|
//
|
||||||
// // LEGO_ONE="ONE"
|
// // LEGO_ONE="ONE"
|
||||||
// // LEGO_TWO="TWO"
|
// // LEGO_TWO="TWO"
|
||||||
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
||||||
// // => "LEGO_ONE" = "ONE"
|
// // => "LEGO_ONE" = "ONE"
|
||||||
//
|
//
|
||||||
// case 2:
|
// ----
|
||||||
//
|
//
|
||||||
// // LEGO_ONE=""
|
// // LEGO_ONE=""
|
||||||
// // LEGO_TWO="TWO"
|
// // LEGO_TWO="TWO"
|
||||||
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
||||||
// // => "LEGO_ONE" = "TWO"
|
// // => "LEGO_ONE" = "TWO"
|
||||||
//
|
//
|
||||||
// case 3:
|
// ----
|
||||||
//
|
//
|
||||||
// // LEGO_ONE=""
|
// // LEGO_ONE=""
|
||||||
// // LEGO_TWO=""
|
// // LEGO_TWO=""
|
||||||
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
||||||
// // => error
|
// // => error
|
||||||
|
//
|
||||||
func GetWithFallback(groups ...[]string) (map[string]string, error) {
|
func GetWithFallback(groups ...[]string) (map[string]string, error) {
|
||||||
values := map[string]string{}
|
values := map[string]string{}
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ func GetWithFallback(groups ...[]string) (map[string]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
value, envVar := getOneWithFallback(names[0], names[1:]...)
|
value, envVar := getOneWithFallback(names[0], names[1:]...)
|
||||||
if value == "" {
|
if len(value) == 0 {
|
||||||
missingEnvVars = append(missingEnvVars, envVar)
|
missingEnvVars = append(missingEnvVars, envVar)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -78,26 +78,15 @@ func GetWithFallback(groups ...[]string) (map[string]string, error) {
|
|||||||
return values, nil
|
return values, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetOneWithFallback[T any](main string, defaultValue T, fn func(string) (T, error), names ...string) T {
|
|
||||||
v, _ := getOneWithFallback(main, names...)
|
|
||||||
|
|
||||||
value, err := fn(v)
|
|
||||||
if err != nil {
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOneWithFallback(main string, names ...string) (string, string) {
|
func getOneWithFallback(main string, names ...string) (string, string) {
|
||||||
value := GetOrFile(main)
|
value := GetOrFile(main)
|
||||||
if value != "" {
|
if len(value) > 0 {
|
||||||
return value, main
|
return value, main
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
value := GetOrFile(name)
|
value := GetOrFile(name)
|
||||||
if value != "" {
|
if len(value) > 0 {
|
||||||
return value, main
|
return value, main
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,32 +94,43 @@ func getOneWithFallback(main string, names ...string) (string, string) {
|
|||||||
return "", main
|
return "", main
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOrDefaultInt returns the given environment variable value as an integer.
|
||||||
|
// Returns the default if the envvar cannot be coopered to an int, or is not found.
|
||||||
|
func GetOrDefaultInt(envVar string, defaultValue int) int {
|
||||||
|
v, err := strconv.Atoi(GetOrFile(envVar))
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOrDefaultSecond returns the given environment variable value as an time.Duration (second).
|
||||||
|
// Returns the default if the envvar cannot be coopered to an int, or is not found.
|
||||||
|
func GetOrDefaultSecond(envVar string, defaultValue time.Duration) time.Duration {
|
||||||
|
v := GetOrDefaultInt(envVar, -1)
|
||||||
|
if v < 0 {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Duration(v) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
// GetOrDefaultString returns the given environment variable value as a string.
|
// GetOrDefaultString returns the given environment variable value as a string.
|
||||||
// Returns the default if the env var cannot be found.
|
// Returns the default if the envvar cannot be find.
|
||||||
func GetOrDefaultString(envVar string, defaultValue string) string {
|
func GetOrDefaultString(envVar, defaultValue string) string {
|
||||||
return getOrDefault(envVar, defaultValue, ParseString)
|
v := GetOrFile(envVar)
|
||||||
|
if len(v) == 0 {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrDefaultBool returns the given environment variable value as a boolean.
|
// GetOrDefaultBool returns the given environment variable value as a boolean.
|
||||||
// Returns the default if the env var cannot be coopered to a boolean, or is not found.
|
// Returns the default if the envvar cannot be coopered to a boolean, or is not found.
|
||||||
func GetOrDefaultBool(envVar string, defaultValue bool) bool {
|
func GetOrDefaultBool(envVar string, defaultValue bool) bool {
|
||||||
return getOrDefault(envVar, defaultValue, strconv.ParseBool)
|
v, err := strconv.ParseBool(GetOrFile(envVar))
|
||||||
}
|
|
||||||
|
|
||||||
// GetOrDefaultInt returns the given environment variable value as an integer.
|
|
||||||
// Returns the default if the env var cannot be coopered to an int, or is not found.
|
|
||||||
func GetOrDefaultInt(envVar string, defaultValue int) int {
|
|
||||||
return getOrDefault(envVar, defaultValue, strconv.Atoi)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOrDefaultSecond returns the given environment variable value as a time.Duration (second).
|
|
||||||
// Returns the default if the env var cannot be coopered to an int, or is not found.
|
|
||||||
func GetOrDefaultSecond(envVar string, defaultValue time.Duration) time.Duration {
|
|
||||||
return getOrDefault(envVar, defaultValue, ParseSecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOrDefault[T any](envVar string, defaultValue T, fn func(string) (T, error)) T {
|
|
||||||
v, err := fn(GetOrFile(envVar))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ func GetOrFile(envVar string) string {
|
|||||||
return envVarValue
|
return envVarValue
|
||||||
}
|
}
|
||||||
|
|
||||||
fileContents, err := os.ReadFile(fileVarValue)
|
fileContents, err := ioutil.ReadFile(fileVarValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to read the file %s (defined by env var %s): %s", fileVarValue, fileVar, err)
|
log.Printf("Failed to read the file %s (defined by env var %s): %s", fileVarValue, fileVar, err)
|
||||||
return ""
|
return ""
|
||||||
@ -161,26 +161,3 @@ func GetOrFile(envVar string) string {
|
|||||||
|
|
||||||
return strings.TrimSuffix(string(fileContents), "\n")
|
return strings.TrimSuffix(string(fileContents), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseSecond parses env var value (string) to a second (time.Duration).
|
|
||||||
func ParseSecond(s string) (time.Duration, error) {
|
|
||||||
v, err := strconv.Atoi(s)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if v < 0 {
|
|
||||||
return 0, fmt.Errorf("unsupported value: %d", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return time.Duration(v) * time.Second, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseString parses env var value (string) to a string but throws an error when the string is empty.
|
|
||||||
func ParseString(s string) (string, error) {
|
|
||||||
if s == "" {
|
|
||||||
return "", errors.New("empty string")
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
5
vendor/github.com/go-acme/lego/v4/platform/wait/wait.go
generated
vendored
5
vendor/github.com/go-acme/lego/v4/platform/wait/wait.go
generated
vendored
@ -16,10 +16,7 @@ func For(msg string, timeout, interval time.Duration, f func() (bool, error)) er
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-timeUp:
|
case <-timeUp:
|
||||||
if lastErr == nil {
|
return fmt.Errorf("time limit exceeded: last error: %w", lastErr)
|
||||||
return fmt.Errorf("%s: time limit exceeded", msg)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("%s: time limit exceeded: last error: %w", msg, lastErr)
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
133
vendor/github.com/go-acme/lego/v4/providers/dns/internal/errutils/client.go
generated
vendored
133
vendor/github.com/go-acme/lego/v4/providers/dns/internal/errutils/client.go
generated
vendored
@ -1,133 +0,0 @@
|
|||||||
package errutils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
const legoDebugClientVerboseError = "LEGO_DEBUG_CLIENT_VERBOSE_ERROR"
|
|
||||||
|
|
||||||
// HTTPDoError uses with `(http.Client).Do` error.
|
|
||||||
type HTTPDoError struct {
|
|
||||||
req *http.Request
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHTTPDoError creates a new HTTPDoError.
|
|
||||||
func NewHTTPDoError(req *http.Request, err error) *HTTPDoError {
|
|
||||||
return &HTTPDoError{req: req, err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HTTPDoError) Error() string {
|
|
||||||
msg := "unable to communicate with the API server:"
|
|
||||||
|
|
||||||
if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
|
|
||||||
msg += fmt.Sprintf(" [request: %s %s]", h.req.Method, h.req.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.err == nil {
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg + fmt.Sprintf(" error: %v", h.err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HTTPDoError) Unwrap() error {
|
|
||||||
return h.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadResponseError use with `io.ReadAll` when reading response body.
|
|
||||||
type ReadResponseError struct {
|
|
||||||
req *http.Request
|
|
||||||
StatusCode int
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReadResponseError creates a new ReadResponseError.
|
|
||||||
func NewReadResponseError(req *http.Request, statusCode int, err error) *ReadResponseError {
|
|
||||||
return &ReadResponseError{req: req, StatusCode: statusCode, err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r ReadResponseError) Error() string {
|
|
||||||
msg := "unable to read response body:"
|
|
||||||
|
|
||||||
if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
|
|
||||||
msg += fmt.Sprintf(" [request: %s %s]", r.req.Method, r.req.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
msg += fmt.Sprintf(" [status code: %d]", r.StatusCode)
|
|
||||||
|
|
||||||
if r.err == nil {
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg + fmt.Sprintf(" error: %v", r.err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r ReadResponseError) Unwrap() error {
|
|
||||||
return r.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalError uses with `json.Unmarshal` or `xml.Unmarshal` when reading response body.
|
|
||||||
type UnmarshalError struct {
|
|
||||||
req *http.Request
|
|
||||||
StatusCode int
|
|
||||||
Body []byte
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewUnmarshalError creates a new UnmarshalError.
|
|
||||||
func NewUnmarshalError(req *http.Request, statusCode int, body []byte, err error) *UnmarshalError {
|
|
||||||
return &UnmarshalError{req: req, StatusCode: statusCode, Body: bytes.TrimSpace(body), err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u UnmarshalError) Error() string {
|
|
||||||
msg := "unable to unmarshal response:"
|
|
||||||
|
|
||||||
if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
|
|
||||||
msg += fmt.Sprintf(" [request: %s %s]", u.req.Method, u.req.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
msg += fmt.Sprintf(" [status code: %d] body: %s", u.StatusCode, string(u.Body))
|
|
||||||
|
|
||||||
if u.err == nil {
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg + fmt.Sprintf(" error: %v", u.err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u UnmarshalError) Unwrap() error {
|
|
||||||
return u.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnexpectedStatusCodeError use when the status of the response is unexpected but there is no API error type.
|
|
||||||
type UnexpectedStatusCodeError struct {
|
|
||||||
req *http.Request
|
|
||||||
StatusCode int
|
|
||||||
Body []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewUnexpectedStatusCodeError creates a new UnexpectedStatusCodeError.
|
|
||||||
func NewUnexpectedStatusCodeError(req *http.Request, statusCode int, body []byte) *UnexpectedStatusCodeError {
|
|
||||||
return &UnexpectedStatusCodeError{req: req, StatusCode: statusCode, Body: bytes.TrimSpace(body)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUnexpectedResponseStatusCodeError(req *http.Request, resp *http.Response) *UnexpectedStatusCodeError {
|
|
||||||
raw, _ := io.ReadAll(resp.Body)
|
|
||||||
return &UnexpectedStatusCodeError{req: req, StatusCode: resp.StatusCode, Body: bytes.TrimSpace(raw)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u UnexpectedStatusCodeError) Error() string {
|
|
||||||
msg := "unexpected status code:"
|
|
||||||
|
|
||||||
if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
|
|
||||||
msg += fmt.Sprintf(" [request: %s %s]", u.req.Method, u.req.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg + fmt.Sprintf(" [status code: %d] body: %s", u.StatusCode, string(u.Body))
|
|
||||||
}
|
|
179
vendor/github.com/go-acme/lego/v4/providers/dns/ovh/ovh.go
generated
vendored
179
vendor/github.com/go-acme/lego/v4/providers/dns/ovh/ovh.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,14 +15,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// OVH API reference: https://eu.api.ovh.com/
|
// OVH API reference: https://eu.api.ovh.com/
|
||||||
// Create a Token: https://eu.api.ovh.com/createToken/
|
// Create a Token: https://eu.api.ovh.com/createToken/
|
||||||
// Create a OAuth2 client: https://eu.api.ovh.com/console-preview/?section=%2Fme&branch=v1#post-/me/api/oauth2/client
|
|
||||||
|
|
||||||
// Environment variables names.
|
// Environment variables names.
|
||||||
const (
|
const (
|
||||||
envNamespace = "OVH_"
|
envNamespace = "OVH_"
|
||||||
|
|
||||||
EnvEndpoint = envNamespace + "ENDPOINT"
|
EnvEndpoint = envNamespace + "ENDPOINT"
|
||||||
|
EnvApplicationKey = envNamespace + "APPLICATION_KEY"
|
||||||
|
EnvApplicationSecret = envNamespace + "APPLICATION_SECRET"
|
||||||
|
EnvConsumerKey = envNamespace + "CONSUMER_KEY"
|
||||||
|
|
||||||
EnvTTL = envNamespace + "TTL"
|
EnvTTL = envNamespace + "TTL"
|
||||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||||
@ -29,19 +32,6 @@ const (
|
|||||||
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Authenticate using application key.
|
|
||||||
const (
|
|
||||||
EnvApplicationKey = envNamespace + "APPLICATION_KEY"
|
|
||||||
EnvApplicationSecret = envNamespace + "APPLICATION_SECRET"
|
|
||||||
EnvConsumerKey = envNamespace + "CONSUMER_KEY"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Authenticate using OAuth2 client.
|
|
||||||
const (
|
|
||||||
EnvClientID = envNamespace + "CLIENT_ID"
|
|
||||||
EnvClientSecret = envNamespace + "CLIENT_SECRET"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Record a DNS record.
|
// Record a DNS record.
|
||||||
type Record struct {
|
type Record struct {
|
||||||
ID int64 `json:"id,omitempty"`
|
ID int64 `json:"id,omitempty"`
|
||||||
@ -52,32 +42,18 @@ type Record struct {
|
|||||||
Zone string `json:"zone,omitempty"`
|
Zone string `json:"zone,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// OAuth2Config the OAuth2 specific configuration.
|
|
||||||
type OAuth2Config struct {
|
|
||||||
ClientID string
|
|
||||||
ClientSecret string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config is used to configure the creation of the DNSProvider.
|
// Config is used to configure the creation of the DNSProvider.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
APIEndpoint string
|
APIEndpoint string
|
||||||
|
ApplicationKey string
|
||||||
ApplicationKey string
|
ApplicationSecret string
|
||||||
ApplicationSecret string
|
ConsumerKey string
|
||||||
ConsumerKey string
|
|
||||||
|
|
||||||
OAuth2Config *OAuth2Config
|
|
||||||
|
|
||||||
PropagationTimeout time.Duration
|
PropagationTimeout time.Duration
|
||||||
PollingInterval time.Duration
|
PollingInterval time.Duration
|
||||||
TTL int
|
TTL int
|
||||||
HTTPClient *http.Client
|
HTTPClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) hasAppKeyAuth() bool {
|
|
||||||
return c.ApplicationKey != "" || c.ApplicationSecret != "" || c.ConsumerKey != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDefaultConfig returns a default configuration for the DNSProvider.
|
// NewDefaultConfig returns a default configuration for the DNSProvider.
|
||||||
func NewDefaultConfig() *Config {
|
func NewDefaultConfig() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
@ -102,11 +78,17 @@ type DNSProvider struct {
|
|||||||
// Credentials must be passed in the environment variables:
|
// Credentials must be passed in the environment variables:
|
||||||
// OVH_ENDPOINT (must be either "ovh-eu" or "ovh-ca"), OVH_APPLICATION_KEY, OVH_APPLICATION_SECRET, OVH_CONSUMER_KEY.
|
// OVH_ENDPOINT (must be either "ovh-eu" or "ovh-ca"), OVH_APPLICATION_KEY, OVH_APPLICATION_SECRET, OVH_CONSUMER_KEY.
|
||||||
func NewDNSProvider() (*DNSProvider, error) {
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
config, err := createConfigFromEnvVars()
|
values, err := env.Get(EnvEndpoint, EnvApplicationKey, EnvApplicationSecret, EnvConsumerKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("ovh: %w", err)
|
return nil, fmt.Errorf("ovh: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.APIEndpoint = values[EnvEndpoint]
|
||||||
|
config.ApplicationKey = values[EnvApplicationKey]
|
||||||
|
config.ApplicationSecret = values[EnvApplicationSecret]
|
||||||
|
config.ConsumerKey = values[EnvConsumerKey]
|
||||||
|
|
||||||
return NewDNSProviderConfig(config)
|
return NewDNSProviderConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,11 +98,16 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||||||
return nil, errors.New("ovh: the configuration of the DNS provider is nil")
|
return nil, errors.New("ovh: the configuration of the DNS provider is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.OAuth2Config != nil && config.hasAppKeyAuth() {
|
if config.APIEndpoint == "" || config.ApplicationKey == "" || config.ApplicationSecret == "" || config.ConsumerKey == "" {
|
||||||
return nil, errors.New("ovh: can't use both authentication systems (ApplicationKey and OAuth2)")
|
return nil, errors.New("ovh: credentials missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := newClient(config)
|
client, err := ovh.NewClient(
|
||||||
|
config.APIEndpoint,
|
||||||
|
config.ApplicationKey,
|
||||||
|
config.ApplicationSecret,
|
||||||
|
config.ConsumerKey,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("ovh: %w", err)
|
return nil, fmt.Errorf("ovh: %w", err)
|
||||||
}
|
}
|
||||||
@ -136,23 +123,19 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||||||
|
|
||||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
// Parse domain name
|
// Parse domain name
|
||||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("ovh: could not find zone for domain %q: %w", domain, err)
|
return fmt.Errorf("ovh: could not determine zone for domain %q: %w", domain, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
authZone = dns01.UnFqdn(authZone)
|
authZone = dns01.UnFqdn(authZone)
|
||||||
|
subDomain := extractRecordName(fqdn, authZone)
|
||||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("ovh: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
reqURL := fmt.Sprintf("/domain/zone/%s/record", authZone)
|
reqURL := fmt.Sprintf("/domain/zone/%s/record", authZone)
|
||||||
reqData := Record{FieldType: "TXT", SubDomain: subDomain, Target: info.Value, TTL: d.config.TTL}
|
reqData := Record{FieldType: "TXT", SubDomain: subDomain, Target: value, TTL: d.config.TTL}
|
||||||
|
|
||||||
// Create TXT record
|
// Create TXT record
|
||||||
var respData Record
|
var respData Record
|
||||||
@ -177,19 +160,19 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||||||
|
|
||||||
// CleanUp removes the TXT record matching the specified parameters.
|
// CleanUp removes the TXT record matching the specified parameters.
|
||||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
fqdn, _ := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
// 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[token]
|
recordID, ok := d.recordIDs[token]
|
||||||
d.recordIDsMu.Unlock()
|
d.recordIDsMu.Unlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("ovh: unknown record ID for '%s'", info.EffectiveFQDN)
|
return fmt.Errorf("ovh: unknown record ID for '%s'", fqdn)
|
||||||
}
|
}
|
||||||
|
|
||||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("ovh: could not find zone for domain %q: %w", domain, err)
|
return fmt.Errorf("ovh: could not determine zone for domain %q: %w", domain, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
authZone = dns01.UnFqdn(authZone)
|
authZone = dns01.UnFqdn(authZone)
|
||||||
@ -222,94 +205,10 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
func createConfigFromEnvVars() (*Config, error) {
|
func extractRecordName(fqdn, zone string) string {
|
||||||
firstAppKeyEnvVar := findFirstValuedEnvVar(EnvApplicationKey, EnvApplicationSecret, EnvConsumerKey)
|
name := dns01.UnFqdn(fqdn)
|
||||||
firstOAuth2EnvVar := findFirstValuedEnvVar(EnvClientID, EnvClientSecret)
|
if idx := strings.Index(name, "."+zone); idx != -1 {
|
||||||
|
return name[:idx]
|
||||||
if firstAppKeyEnvVar != "" && firstOAuth2EnvVar != "" {
|
|
||||||
return nil, fmt.Errorf("can't use both %s and %s at the same time", firstAppKeyEnvVar, firstOAuth2EnvVar)
|
|
||||||
}
|
}
|
||||||
|
return name
|
||||||
config := NewDefaultConfig()
|
|
||||||
|
|
||||||
if firstOAuth2EnvVar != "" {
|
|
||||||
values, err := env.Get(EnvEndpoint, EnvClientID, EnvClientSecret)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
config.APIEndpoint = values[EnvEndpoint]
|
|
||||||
config.OAuth2Config = &OAuth2Config{
|
|
||||||
ClientID: values[EnvClientID],
|
|
||||||
ClientSecret: values[EnvClientSecret],
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
values, err := env.Get(EnvEndpoint, EnvApplicationKey, EnvApplicationSecret, EnvConsumerKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
config.APIEndpoint = values[EnvEndpoint]
|
|
||||||
|
|
||||||
config.ApplicationKey = values[EnvApplicationKey]
|
|
||||||
config.ApplicationSecret = values[EnvApplicationSecret]
|
|
||||||
config.ConsumerKey = values[EnvConsumerKey]
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func findFirstValuedEnvVar(envVars ...string) string {
|
|
||||||
for _, envVar := range envVars {
|
|
||||||
if env.GetOrFile(envVar) != "" {
|
|
||||||
return envVar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func newClient(config *Config) (*ovh.Client, error) {
|
|
||||||
if config.OAuth2Config == nil {
|
|
||||||
return newClientApplicationKey(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
return newClientOAuth2(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newClientApplicationKey(config *Config) (*ovh.Client, error) {
|
|
||||||
if config.APIEndpoint == "" || config.ApplicationKey == "" || config.ApplicationSecret == "" || config.ConsumerKey == "" {
|
|
||||||
return nil, errors.New("credentials are missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := ovh.NewClient(
|
|
||||||
config.APIEndpoint,
|
|
||||||
config.ApplicationKey,
|
|
||||||
config.ApplicationSecret,
|
|
||||||
config.ConsumerKey,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("new client: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newClientOAuth2(config *Config) (*ovh.Client, error) {
|
|
||||||
if config.APIEndpoint == "" || config.OAuth2Config.ClientID == "" || config.OAuth2Config.ClientSecret == "" {
|
|
||||||
return nil, errors.New("credentials are missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := ovh.NewOAuth2Client(
|
|
||||||
config.APIEndpoint,
|
|
||||||
config.OAuth2Config.ClientID,
|
|
||||||
config.OAuth2Config.ClientSecret,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("new OAuth2 client: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
}
|
||||||
|
37
vendor/github.com/go-acme/lego/v4/providers/dns/ovh/ovh.toml
generated
vendored
37
vendor/github.com/go-acme/lego/v4/providers/dns/ovh/ovh.toml
generated
vendored
@ -5,20 +5,11 @@ Code = "ovh"
|
|||||||
Since = "v0.4.0"
|
Since = "v0.4.0"
|
||||||
|
|
||||||
Example = '''
|
Example = '''
|
||||||
# Application Key authentication:
|
|
||||||
|
|
||||||
OVH_APPLICATION_KEY=1234567898765432 \
|
OVH_APPLICATION_KEY=1234567898765432 \
|
||||||
OVH_APPLICATION_SECRET=b9841238feb177a84330febba8a832089 \
|
OVH_APPLICATION_SECRET=b9841238feb177a84330febba8a832089 \
|
||||||
OVH_CONSUMER_KEY=256vfsd347245sdfg \
|
OVH_CONSUMER_KEY=256vfsd347245sdfg \
|
||||||
OVH_ENDPOINT=ovh-eu \
|
OVH_ENDPOINT=ovh-eu \
|
||||||
lego --email you@example.com --dns ovh --domains my.example.org run
|
lego --dns autodns --domains my.domain.com --email my@email.com run
|
||||||
|
|
||||||
# Or OAuth2:
|
|
||||||
|
|
||||||
OVH_CLIENT_ID=yyy \
|
|
||||||
OVH_CLIENT_SECRET=xxx \
|
|
||||||
OVH_ENDPOINT=ovh-eu \
|
|
||||||
lego --email you@example.com --dns ovh --domains my.example.org run
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
Additional = '''
|
Additional = '''
|
||||||
@ -26,7 +17,7 @@ Additional = '''
|
|||||||
|
|
||||||
Application key and secret can be created by following the [OVH guide](https://docs.ovh.com/gb/en/customer/first-steps-with-ovh-api/).
|
Application key and secret can be created by following the [OVH guide](https://docs.ovh.com/gb/en/customer/first-steps-with-ovh-api/).
|
||||||
|
|
||||||
When requesting the consumer key, the following configuration can be used to define access rights:
|
When requesting the consumer key, the following configuration can be use to define access rights:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@ -42,32 +33,14 @@ When requesting the consumer key, the following configuration can be used to def
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## OAuth2 Client Credentials
|
|
||||||
|
|
||||||
Another method for authentication is by using OAuth2 client credentials.
|
|
||||||
|
|
||||||
An IAM policy and service account can be created by following the [OVH guide](https://help.ovhcloud.com/csm/en-manage-service-account?id=kb_article_view&sysparm_article=KB0059343).
|
|
||||||
|
|
||||||
Following IAM policies need to be authorized for the affected domain:
|
|
||||||
|
|
||||||
* dnsZone:apiovh:record/create
|
|
||||||
* dnsZone:apiovh:record/delete
|
|
||||||
* dnsZone:apiovh:refresh
|
|
||||||
|
|
||||||
## Important Note
|
|
||||||
|
|
||||||
Both authentication methods cannot be used at the same time.
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
[Configuration]
|
[Configuration]
|
||||||
[Configuration.Credentials]
|
[Configuration.Credentials]
|
||||||
OVH_ENDPOINT = "Endpoint URL (ovh-eu or ovh-ca)"
|
OVH_ENDPOINT = "Endpoint URL (ovh-eu or ovh-ca)"
|
||||||
OVH_APPLICATION_KEY = "Application key (Application Key authentication)"
|
OVH_APPLICATION_KEY = "Application key"
|
||||||
OVH_APPLICATION_SECRET = "Application secret (Application Key authentication)"
|
OVH_APPLICATION_SECRET = "Application secret"
|
||||||
OVH_CONSUMER_KEY = "Consumer key (Application Key authentication)"
|
OVH_CONSUMER_KEY = "Consumer key"
|
||||||
OVH_CLIENT_ID = "Client ID (OAuth2)"
|
|
||||||
OVH_CLIENT_SECRET = "Client secret (OAuth2)"
|
|
||||||
[Configuration.Additional]
|
[Configuration.Additional]
|
||||||
OVH_POLLING_INTERVAL = "Time between DNS propagation check"
|
OVH_POLLING_INTERVAL = "Time between DNS propagation check"
|
||||||
OVH_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
OVH_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
||||||
|
228
vendor/github.com/go-acme/lego/v4/providers/dns/pdns/internal/client.go
generated
vendored
228
vendor/github.com/go-acme/lego/v4/providers/dns/pdns/internal/client.go
generated
vendored
@ -1,228 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Client the PowerDNS API client.
|
|
||||||
type Client struct {
|
|
||||||
serverName string
|
|
||||||
apiKey string
|
|
||||||
|
|
||||||
apiVersion int
|
|
||||||
|
|
||||||
Host *url.URL
|
|
||||||
HTTPClient *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClient creates a new Client.
|
|
||||||
func NewClient(host *url.URL, serverName string, apiVersion int, apiKey string) *Client {
|
|
||||||
return &Client{
|
|
||||||
serverName: serverName,
|
|
||||||
apiKey: apiKey,
|
|
||||||
apiVersion: apiVersion,
|
|
||||||
Host: host,
|
|
||||||
HTTPClient: &http.Client{Timeout: 5 * time.Second},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) APIVersion() int {
|
|
||||||
return c.apiVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) SetAPIVersion(ctx context.Context) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
c.apiVersion, err = c.getAPIVersion(ctx)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) getAPIVersion(ctx context.Context) (int, error) {
|
|
||||||
endpoint := c.joinPath("/", "api")
|
|
||||||
|
|
||||||
req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := c.do(req)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var versions []apiVersion
|
|
||||||
err = json.Unmarshal(result, &versions)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
latestVersion := 0
|
|
||||||
for _, v := range versions {
|
|
||||||
if v.Version > latestVersion {
|
|
||||||
latestVersion = v.Version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return latestVersion, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) GetHostedZone(ctx context.Context, authZone string) (*HostedZone, error) {
|
|
||||||
endpoint := c.joinPath("/", "servers", c.serverName, "zones", dns.Fqdn(authZone))
|
|
||||||
|
|
||||||
req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := c.do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var zone HostedZone
|
|
||||||
err = json.Unmarshal(result, &zone)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert pre-v1 API result
|
|
||||||
if len(zone.Records) > 0 {
|
|
||||||
zone.RRSets = []RRSet{}
|
|
||||||
for _, record := range zone.Records {
|
|
||||||
set := RRSet{
|
|
||||||
Name: record.Name,
|
|
||||||
Type: record.Type,
|
|
||||||
Records: []Record{record},
|
|
||||||
}
|
|
||||||
zone.RRSets = append(zone.RRSets, set)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &zone, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) UpdateRecords(ctx context.Context, zone *HostedZone, sets RRSets) error {
|
|
||||||
endpoint := c.joinPath("/", "servers", c.serverName, "zones", zone.ID)
|
|
||||||
|
|
||||||
req, err := newJSONRequest(ctx, http.MethodPatch, endpoint, sets)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = c.do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Notify(ctx context.Context, zone *HostedZone) error {
|
|
||||||
if c.apiVersion < 1 || zone.Kind != "Master" && zone.Kind != "Slave" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoint := c.joinPath("/", "servers", c.serverName, "zones", zone.ID, "notify")
|
|
||||||
|
|
||||||
req, err := newJSONRequest(ctx, http.MethodPut, endpoint, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = c.do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) joinPath(elem ...string) *url.URL {
|
|
||||||
p := path.Join(elem...)
|
|
||||||
|
|
||||||
if p != "/api" && c.apiVersion > 0 && !strings.HasPrefix(p, "/api/v") {
|
|
||||||
p = path.Join("/api", "v"+strconv.Itoa(c.apiVersion), p)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.Host.JoinPath(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) do(req *http.Request) (json.RawMessage, error) {
|
|
||||||
req.Header.Set("X-API-Key", c.apiKey)
|
|
||||||
|
|
||||||
resp, err := c.HTTPClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errutils.NewHTTPDoError(req, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() { _ = resp.Body.Close() }()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusUnprocessableEntity && (resp.StatusCode < 200 || resp.StatusCode >= 300) {
|
|
||||||
return nil, errutils.NewUnexpectedResponseStatusCodeError(req, resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
var msg json.RawMessage
|
|
||||||
err = json.NewDecoder(resp.Body).Decode(&msg)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, io.EOF) {
|
|
||||||
// empty body
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
// other error
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for PowerDNS error message
|
|
||||||
if len(msg) > 0 && msg[0] == '{' {
|
|
||||||
var errInfo apiError
|
|
||||||
err = json.Unmarshal(msg, &errInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, msg, err)
|
|
||||||
}
|
|
||||||
if errInfo.ShortMsg != "" {
|
|
||||||
return nil, fmt.Errorf("error talking to PDNS API: %w", errInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
|
|
||||||
if payload != nil {
|
|
||||||
err := json.NewEncoder(buf).Encode(payload)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create request JSON body: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, method, strings.TrimSuffix(endpoint.String(), "/"), buf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Accept", "application/json")
|
|
||||||
|
|
||||||
// PowerDNS doesn't follow HTTP convention about the "Content-Type" header.
|
|
||||||
if method != http.MethodGet && method != http.MethodDelete {
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
}
|
|
||||||
|
|
||||||
return req, nil
|
|
||||||
}
|
|
48
vendor/github.com/go-acme/lego/v4/providers/dns/pdns/internal/types.go
generated
vendored
48
vendor/github.com/go-acme/lego/v4/providers/dns/pdns/internal/types.go
generated
vendored
@ -1,48 +0,0 @@
|
|||||||
package internal
|
|
||||||
|
|
||||||
type Record struct {
|
|
||||||
Content string `json:"content"`
|
|
||||||
Disabled bool `json:"disabled"`
|
|
||||||
|
|
||||||
// pre-v1 API
|
|
||||||
Name string `json:"name"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
TTL int `json:"ttl,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HostedZone struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
Kind string `json:"kind"`
|
|
||||||
RRSets []RRSet `json:"rrsets"`
|
|
||||||
|
|
||||||
// pre-v1 API
|
|
||||||
Records []Record `json:"records"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RRSet struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Kind string `json:"kind"`
|
|
||||||
ChangeType string `json:"changetype"`
|
|
||||||
Records []Record `json:"records,omitempty"`
|
|
||||||
TTL int `json:"ttl,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RRSets struct {
|
|
||||||
RRSets []RRSet `json:"rrsets"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type apiError struct {
|
|
||||||
ShortMsg string `json:"error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a apiError) Error() string {
|
|
||||||
return a.ShortMsg
|
|
||||||
}
|
|
||||||
|
|
||||||
type apiVersion struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
Version int `json:"version"`
|
|
||||||
}
|
|
228
vendor/github.com/go-acme/lego/v4/providers/dns/pdns/pdns.go
generated
vendored
228
vendor/github.com/go-acme/lego/v4/providers/dns/pdns/pdns.go
generated
vendored
@ -1,228 +0,0 @@
|
|||||||
// Package pdns implements a DNS provider for solving the DNS-01 challenge using PowerDNS nameserver.
|
|
||||||
package pdns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
|
||||||
"github.com/go-acme/lego/v4/log"
|
|
||||||
"github.com/go-acme/lego/v4/platform/config/env"
|
|
||||||
"github.com/go-acme/lego/v4/providers/dns/pdns/internal"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Environment variables names.
|
|
||||||
const (
|
|
||||||
envNamespace = "PDNS_"
|
|
||||||
|
|
||||||
EnvAPIKey = envNamespace + "API_KEY"
|
|
||||||
EnvAPIURL = envNamespace + "API_URL"
|
|
||||||
|
|
||||||
EnvTTL = envNamespace + "TTL"
|
|
||||||
EnvAPIVersion = envNamespace + "API_VERSION"
|
|
||||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
|
||||||
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
|
||||||
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
|
||||||
EnvServerName = envNamespace + "SERVER_NAME"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Config is used to configure the creation of the DNSProvider.
|
|
||||||
type Config struct {
|
|
||||||
APIKey string
|
|
||||||
Host *url.URL
|
|
||||||
ServerName string
|
|
||||||
APIVersion int
|
|
||||||
PropagationTimeout time.Duration
|
|
||||||
PollingInterval time.Duration
|
|
||||||
TTL int
|
|
||||||
HTTPClient *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDefaultConfig returns a default configuration for the DNSProvider.
|
|
||||||
func NewDefaultConfig() *Config {
|
|
||||||
return &Config{
|
|
||||||
ServerName: env.GetOrDefaultString(EnvServerName, "localhost"),
|
|
||||||
APIVersion: env.GetOrDefaultInt(EnvAPIVersion, 0),
|
|
||||||
TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
|
|
||||||
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
|
|
||||||
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 2*time.Second),
|
|
||||||
HTTPClient: &http.Client{
|
|
||||||
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DNSProvider implements the challenge.Provider interface.
|
|
||||||
type DNSProvider struct {
|
|
||||||
config *Config
|
|
||||||
client *internal.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDNSProvider returns a DNSProvider instance configured for pdns.
|
|
||||||
// Credentials must be passed in the environment variable:
|
|
||||||
// PDNS_API_URL and PDNS_API_KEY.
|
|
||||||
func NewDNSProvider() (*DNSProvider, error) {
|
|
||||||
values, err := env.Get(EnvAPIKey, EnvAPIURL)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("pdns: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hostURL, err := url.Parse(values[EnvAPIURL])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("pdns: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config := NewDefaultConfig()
|
|
||||||
config.Host = hostURL
|
|
||||||
config.APIKey = values[EnvAPIKey]
|
|
||||||
|
|
||||||
return NewDNSProviderConfig(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDNSProviderConfig return a DNSProvider instance configured for pdns.
|
|
||||||
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|
||||||
if config == nil {
|
|
||||||
return nil, errors.New("pdns: the configuration of the DNS provider is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.APIKey == "" {
|
|
||||||
return nil, errors.New("pdns: API key missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Host == nil || config.Host.Host == "" {
|
|
||||||
return nil, errors.New("pdns: API URL missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
client := internal.NewClient(config.Host, config.ServerName, config.APIVersion, config.APIKey)
|
|
||||||
|
|
||||||
if config.APIVersion <= 0 {
|
|
||||||
err := client.SetAPIVersion(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("pdns: failed to get API version %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DNSProvider{config: config, client: client}, 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Present creates a TXT record to fulfill the dns-01 challenge.
|
|
||||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|
||||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
|
||||||
|
|
||||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("pdns: could not find zone for domain %q: %w", domain, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
zone, err := d.client.GetHostedZone(ctx, authZone)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("pdns: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
name := info.EffectiveFQDN
|
|
||||||
if d.client.APIVersion() == 0 {
|
|
||||||
// pre-v1 API wants non-fqdn
|
|
||||||
name = dns01.UnFqdn(info.EffectiveFQDN)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for existing records.
|
|
||||||
existingRRSet := findTxtRecord(zone, info.EffectiveFQDN)
|
|
||||||
|
|
||||||
// merge the existing and new records
|
|
||||||
var records []internal.Record
|
|
||||||
if existingRRSet != nil {
|
|
||||||
records = existingRRSet.Records
|
|
||||||
}
|
|
||||||
|
|
||||||
rec := internal.Record{
|
|
||||||
Content: "\"" + info.Value + "\"",
|
|
||||||
Disabled: false,
|
|
||||||
|
|
||||||
// pre-v1 API
|
|
||||||
Type: "TXT",
|
|
||||||
Name: name,
|
|
||||||
TTL: d.config.TTL,
|
|
||||||
}
|
|
||||||
|
|
||||||
rrSets := internal.RRSets{
|
|
||||||
RRSets: []internal.RRSet{
|
|
||||||
{
|
|
||||||
Name: name,
|
|
||||||
ChangeType: "REPLACE",
|
|
||||||
Type: "TXT",
|
|
||||||
Kind: "Master",
|
|
||||||
TTL: d.config.TTL,
|
|
||||||
Records: append(records, rec),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = d.client.UpdateRecords(ctx, zone, rrSets)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("pdns: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.client.Notify(ctx, zone)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CleanUp removes the TXT record matching the specified parameters.
|
|
||||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|
||||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
|
||||||
|
|
||||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("pdns: could not find zone for domain %q: %w", domain, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
zone, err := d.client.GetHostedZone(ctx, authZone)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("pdns: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
set := findTxtRecord(zone, info.EffectiveFQDN)
|
|
||||||
|
|
||||||
if set == nil {
|
|
||||||
return fmt.Errorf("pdns: no existing record found for %s", info.EffectiveFQDN)
|
|
||||||
}
|
|
||||||
|
|
||||||
rrSets := internal.RRSets{
|
|
||||||
RRSets: []internal.RRSet{
|
|
||||||
{
|
|
||||||
Name: set.Name,
|
|
||||||
Type: set.Type,
|
|
||||||
ChangeType: "DELETE",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = d.client.UpdateRecords(ctx, zone, rrSets)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("pdns: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.client.Notify(ctx, zone)
|
|
||||||
}
|
|
||||||
|
|
||||||
func findTxtRecord(zone *internal.HostedZone, fqdn string) *internal.RRSet {
|
|
||||||
for _, set := range zone.RRSets {
|
|
||||||
if set.Type == "TXT" && (set.Name == dns01.UnFqdn(fqdn) || set.Name == fqdn) {
|
|
||||||
return &set
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
37
vendor/github.com/go-acme/lego/v4/providers/dns/pdns/pdns.toml
generated
vendored
37
vendor/github.com/go-acme/lego/v4/providers/dns/pdns/pdns.toml
generated
vendored
@ -1,37 +0,0 @@
|
|||||||
Name = "PowerDNS"
|
|
||||||
Description = ''''''
|
|
||||||
URL = "https://www.powerdns.com/"
|
|
||||||
Code = "pdns"
|
|
||||||
Since = "v0.4.0"
|
|
||||||
|
|
||||||
Example = '''
|
|
||||||
PDNS_API_URL=http://pdns-server:80/ \
|
|
||||||
PDNS_API_KEY=xxxx \
|
|
||||||
lego --email you@example.com --dns pdns --domains my.example.org run
|
|
||||||
'''
|
|
||||||
|
|
||||||
Additional = '''
|
|
||||||
## Information
|
|
||||||
|
|
||||||
Tested and confirmed to work with PowerDNS authoritative server 3.4.8 and 4.0.1. Refer to [PowerDNS documentation](https://doc.powerdns.com/md/httpapi/README/) instructions on how to enable the built-in API interface.
|
|
||||||
|
|
||||||
PowerDNS Notes:
|
|
||||||
- PowerDNS API does not currently support SSL, therefore you should take care to ensure that traffic between lego and the PowerDNS API is over a trusted network, VPN etc.
|
|
||||||
- In order to have the SOA serial automatically increment each time the `_acme-challenge` record is added/modified via the API, set `SOA-EDIT-API` to `INCEPTION-INCREMENT` for the zone in the `domainmetadata` table
|
|
||||||
- Some PowerDNS servers doesn't have root API endpoints enabled and API version autodetection will not work. In that case version number can be defined using `PDNS_API_VERSION`.
|
|
||||||
'''
|
|
||||||
|
|
||||||
[Configuration]
|
|
||||||
[Configuration.Credentials]
|
|
||||||
PDNS_API_KEY = "API key"
|
|
||||||
PDNS_API_URL = "API URL"
|
|
||||||
[Configuration.Additional]
|
|
||||||
PDNS_SERVER_NAME = "Name of the server in the URL, 'localhost' by default"
|
|
||||||
PDNS_API_VERSION = "Skip API version autodetection and use the provided version number."
|
|
||||||
PDNS_POLLING_INTERVAL = "Time between DNS propagation check"
|
|
||||||
PDNS_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
|
||||||
PDNS_TTL = "The TTL of the TXT record used for the DNS challenge"
|
|
||||||
PDNS_HTTP_TIMEOUT = "API request timeout"
|
|
||||||
|
|
||||||
[Links]
|
|
||||||
API = "https://doc.powerdns.com/md/httpapi/README/"
|
|
14
vendor/github.com/go-acme/lego/v4/registration/registar.go
generated
vendored
14
vendor/github.com/go-acme/lego/v4/registration/registar.go
generated
vendored
@ -9,11 +9,9 @@ import (
|
|||||||
"github.com/go-acme/lego/v4/log"
|
"github.com/go-acme/lego/v4/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const mailTo = "mailto:"
|
|
||||||
|
|
||||||
// Resource represents all important information about a registration
|
// Resource represents all important information about a registration
|
||||||
// of which the client needs to keep track itself.
|
// of which the client needs to keep track itself.
|
||||||
// WARNING: will be removed in the future (acme.ExtendedAccount), https://github.com/go-acme/lego/issues/855.
|
// WARNING: will be remove in the future (acme.ExtendedAccount), https://github.com/go-acme/lego/issues/855.
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Body acme.Account `json:"body,omitempty"`
|
Body acme.Account `json:"body,omitempty"`
|
||||||
URI string `json:"uri,omitempty"`
|
URI string `json:"uri,omitempty"`
|
||||||
@ -54,12 +52,12 @@ func (r *Registrar) Register(options RegisterOptions) (*Resource, error) {
|
|||||||
|
|
||||||
if r.user.GetEmail() != "" {
|
if r.user.GetEmail() != "" {
|
||||||
log.Infof("acme: Registering account for %s", r.user.GetEmail())
|
log.Infof("acme: Registering account for %s", r.user.GetEmail())
|
||||||
accMsg.Contact = []string{mailTo + r.user.GetEmail()}
|
accMsg.Contact = []string{"mailto:" + r.user.GetEmail()}
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := r.core.Accounts.New(accMsg)
|
account, err := r.core.Accounts.New(accMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// seems impossible
|
// FIXME seems impossible
|
||||||
var errorDetails acme.ProblemDetails
|
var errorDetails acme.ProblemDetails
|
||||||
if !errors.As(err, &errorDetails) || errorDetails.HTTPStatus != http.StatusConflict {
|
if !errors.As(err, &errorDetails) || errorDetails.HTTPStatus != http.StatusConflict {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -78,12 +76,12 @@ func (r *Registrar) RegisterWithExternalAccountBinding(options RegisterEABOption
|
|||||||
|
|
||||||
if r.user.GetEmail() != "" {
|
if r.user.GetEmail() != "" {
|
||||||
log.Infof("acme: Registering account for %s", r.user.GetEmail())
|
log.Infof("acme: Registering account for %s", r.user.GetEmail())
|
||||||
accMsg.Contact = []string{mailTo + r.user.GetEmail()}
|
accMsg.Contact = []string{"mailto:" + r.user.GetEmail()}
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := r.core.Accounts.NewEAB(accMsg, options.Kid, options.HmacEncoded)
|
account, err := r.core.Accounts.NewEAB(accMsg, options.Kid, options.HmacEncoded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// seems impossible
|
// FIXME seems impossible
|
||||||
var errorDetails acme.ProblemDetails
|
var errorDetails acme.ProblemDetails
|
||||||
if !errors.As(err, &errorDetails) || errorDetails.HTTPStatus != http.StatusConflict {
|
if !errors.As(err, &errorDetails) || errorDetails.HTTPStatus != http.StatusConflict {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -130,7 +128,7 @@ func (r *Registrar) UpdateRegistration(options RegisterOptions) (*Resource, erro
|
|||||||
|
|
||||||
if r.user.GetEmail() != "" {
|
if r.user.GetEmail() != "" {
|
||||||
log.Infof("acme: Registering account for %s", r.user.GetEmail())
|
log.Infof("acme: Registering account for %s", r.user.GetEmail())
|
||||||
accMsg.Contact = []string{mailTo + r.user.GetEmail()}
|
accMsg.Contact = []string{"mailto:" + r.user.GetEmail()}
|
||||||
}
|
}
|
||||||
|
|
||||||
accountURL := r.user.GetRegistration().URI
|
accountURL := r.user.GetRegistration().URI
|
||||||
|
2
vendor/github.com/go-jose/go-jose/v4/.gitignore
generated
vendored
2
vendor/github.com/go-jose/go-jose/v4/.gitignore
generated
vendored
@ -1,2 +0,0 @@
|
|||||||
jose-util/jose-util
|
|
||||||
jose-util.t.err
|
|
53
vendor/github.com/go-jose/go-jose/v4/.golangci.yml
generated
vendored
53
vendor/github.com/go-jose/go-jose/v4/.golangci.yml
generated
vendored
@ -1,53 +0,0 @@
|
|||||||
# https://github.com/golangci/golangci-lint
|
|
||||||
|
|
||||||
run:
|
|
||||||
skip-files:
|
|
||||||
- doc_test.go
|
|
||||||
modules-download-mode: readonly
|
|
||||||
|
|
||||||
linters:
|
|
||||||
enable-all: true
|
|
||||||
disable:
|
|
||||||
- gochecknoglobals
|
|
||||||
- goconst
|
|
||||||
- lll
|
|
||||||
- maligned
|
|
||||||
- nakedret
|
|
||||||
- scopelint
|
|
||||||
- unparam
|
|
||||||
- funlen # added in 1.18 (requires go-jose changes before it can be enabled)
|
|
||||||
|
|
||||||
linters-settings:
|
|
||||||
gocyclo:
|
|
||||||
min-complexity: 35
|
|
||||||
|
|
||||||
issues:
|
|
||||||
exclude-rules:
|
|
||||||
- text: "don't use ALL_CAPS in Go names"
|
|
||||||
linters:
|
|
||||||
- golint
|
|
||||||
- text: "hardcoded credentials"
|
|
||||||
linters:
|
|
||||||
- gosec
|
|
||||||
- text: "weak cryptographic primitive"
|
|
||||||
linters:
|
|
||||||
- gosec
|
|
||||||
- path: json/
|
|
||||||
linters:
|
|
||||||
- dupl
|
|
||||||
- errcheck
|
|
||||||
- gocritic
|
|
||||||
- gocyclo
|
|
||||||
- golint
|
|
||||||
- govet
|
|
||||||
- ineffassign
|
|
||||||
- staticcheck
|
|
||||||
- structcheck
|
|
||||||
- stylecheck
|
|
||||||
- unused
|
|
||||||
- path: _test\.go
|
|
||||||
linters:
|
|
||||||
- scopelint
|
|
||||||
- path: jwk.go
|
|
||||||
linters:
|
|
||||||
- gocyclo
|
|
33
vendor/github.com/go-jose/go-jose/v4/.travis.yml
generated
vendored
33
vendor/github.com/go-jose/go-jose/v4/.travis.yml
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
fast_finish: true
|
|
||||||
allow_failures:
|
|
||||||
- go: tip
|
|
||||||
|
|
||||||
go:
|
|
||||||
- "1.13.x"
|
|
||||||
- "1.14.x"
|
|
||||||
- tip
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- export PATH=$HOME/.local/bin:$PATH
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- go get -u github.com/mattn/goveralls github.com/wadey/gocovmerge
|
|
||||||
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.18.0
|
|
||||||
- pip install cram --user
|
|
||||||
|
|
||||||
script:
|
|
||||||
- go test -v -covermode=count -coverprofile=profile.cov .
|
|
||||||
- go test -v -covermode=count -coverprofile=cryptosigner/profile.cov ./cryptosigner
|
|
||||||
- go test -v -covermode=count -coverprofile=cipher/profile.cov ./cipher
|
|
||||||
- go test -v -covermode=count -coverprofile=jwt/profile.cov ./jwt
|
|
||||||
- go test -v ./json # no coverage for forked encoding/json package
|
|
||||||
- golangci-lint run
|
|
||||||
- cd jose-util && go build && PATH=$PWD:$PATH cram -v jose-util.t # cram tests jose-util
|
|
||||||
- cd ..
|
|
||||||
|
|
||||||
after_success:
|
|
||||||
- gocovmerge *.cov */*.cov > merged.coverprofile
|
|
||||||
- goveralls -coverprofile merged.coverprofile -service=travis-ci
|
|
96
vendor/github.com/go-jose/go-jose/v4/CHANGELOG.md
generated
vendored
96
vendor/github.com/go-jose/go-jose/v4/CHANGELOG.md
generated
vendored
@ -1,96 +0,0 @@
|
|||||||
# v4.0.4
|
|
||||||
|
|
||||||
## Fixed
|
|
||||||
|
|
||||||
- Reverted "Allow unmarshalling JSONWebKeySets with unsupported key types" as a
|
|
||||||
breaking change. See #136 / #137.
|
|
||||||
|
|
||||||
# v4.0.3
|
|
||||||
|
|
||||||
## Changed
|
|
||||||
|
|
||||||
- Allow unmarshalling JSONWebKeySets with unsupported key types (#130)
|
|
||||||
- Document that OpaqueKeyEncrypter can't be implemented (for now) (#129)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
# v4.0.2
|
|
||||||
|
|
||||||
## Changed
|
|
||||||
|
|
||||||
- Improved documentation of Verify() to note that JSONWebKeySet is a supported
|
|
||||||
argument type (#104)
|
|
||||||
- Defined exported error values for missing x5c header and unsupported elliptic
|
|
||||||
curves error cases (#117)
|
|
||||||
|
|
||||||
# v4.0.1
|
|
||||||
|
|
||||||
## Fixed
|
|
||||||
|
|
||||||
- An attacker could send a JWE containing compressed data that used large
|
|
||||||
amounts of memory and CPU when decompressed by `Decrypt` or `DecryptMulti`.
|
|
||||||
Those functions now return an error if the decompressed data would exceed
|
|
||||||
250kB or 10x the compressed size (whichever is larger). Thanks to
|
|
||||||
Enze Wang@Alioth and Jianjun Chen@Zhongguancun Lab (@zer0yu and @chenjj)
|
|
||||||
for reporting.
|
|
||||||
|
|
||||||
# v4.0.0
|
|
||||||
|
|
||||||
This release makes some breaking changes in order to more thoroughly
|
|
||||||
address the vulnerabilities discussed in [Three New Attacks Against JSON Web
|
|
||||||
Tokens][1], "Sign/encrypt confusion", "Billion hash attack", and "Polyglot
|
|
||||||
token".
|
|
||||||
|
|
||||||
## Changed
|
|
||||||
|
|
||||||
- Limit JWT encryption types (exclude password or public key types) (#78)
|
|
||||||
- Enforce minimum length for HMAC keys (#85)
|
|
||||||
- jwt: match any audience in a list, rather than requiring all audiences (#81)
|
|
||||||
- jwt: accept only Compact Serialization (#75)
|
|
||||||
- jws: Add expected algorithms for signatures (#74)
|
|
||||||
- Require specifying expected algorithms for ParseEncrypted,
|
|
||||||
ParseSigned, ParseDetached, jwt.ParseEncrypted, jwt.ParseSigned,
|
|
||||||
jwt.ParseSignedAndEncrypted (#69, #74)
|
|
||||||
- Usually there is a small, known set of appropriate algorithms for a program
|
|
||||||
to use and it's a mistake to allow unexpected algorithms. For instance the
|
|
||||||
"billion hash attack" relies in part on programs accepting the PBES2
|
|
||||||
encryption algorithm and doing the necessary work even if they weren't
|
|
||||||
specifically configured to allow PBES2.
|
|
||||||
- Revert "Strip padding off base64 strings" (#82)
|
|
||||||
- The specs require base64url encoding without padding.
|
|
||||||
- Minimum supported Go version is now 1.21
|
|
||||||
|
|
||||||
## Added
|
|
||||||
|
|
||||||
- ParseSignedCompact, ParseSignedJSON, ParseEncryptedCompact, ParseEncryptedJSON.
|
|
||||||
- These allow parsing a specific serialization, as opposed to ParseSigned and
|
|
||||||
ParseEncrypted, which try to automatically detect which serialization was
|
|
||||||
provided. It's common to require a specific serialization for a specific
|
|
||||||
protocol - for instance JWT requires Compact serialization.
|
|
||||||
|
|
||||||
[1]: https://i.blackhat.com/BH-US-23/Presentations/US-23-Tervoort-Three-New-Attacks-Against-JSON-Web-Tokens.pdf
|
|
||||||
|
|
||||||
# v3.0.2
|
|
||||||
|
|
||||||
## Fixed
|
|
||||||
|
|
||||||
- DecryptMulti: handle decompression error (#19)
|
|
||||||
|
|
||||||
## Changed
|
|
||||||
|
|
||||||
- jwe/CompactSerialize: improve performance (#67)
|
|
||||||
- Increase the default number of PBKDF2 iterations to 600k (#48)
|
|
||||||
- Return the proper algorithm for ECDSA keys (#45)
|
|
||||||
|
|
||||||
## Added
|
|
||||||
|
|
||||||
- Add Thumbprint support for opaque signers (#38)
|
|
||||||
|
|
||||||
# v3.0.1
|
|
||||||
|
|
||||||
## Fixed
|
|
||||||
|
|
||||||
- Security issue: an attacker specifying a large "p2c" value can cause
|
|
||||||
JSONWebEncryption.Decrypt and JSONWebEncryption.DecryptMulti to consume large
|
|
||||||
amounts of CPU, causing a DoS. Thanks to Matt Schwager (@mschwager) for the
|
|
||||||
disclosure and to Tom Tervoort for originally publishing the category of attack.
|
|
||||||
https://i.blackhat.com/BH-US-23/Presentations/US-23-Tervoort-Three-New-Attacks-Against-JSON-Web-Tokens.pdf
|
|
13
vendor/github.com/go-jose/go-jose/v4/SECURITY.md
generated
vendored
13
vendor/github.com/go-jose/go-jose/v4/SECURITY.md
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
This document explains how to contact the Let's Encrypt security team to report security vulnerabilities.
|
|
||||||
|
|
||||||
## Supported Versions
|
|
||||||
| Version | Supported |
|
|
||||||
| ------- | ----------|
|
|
||||||
| >= v3 | ✓ |
|
|
||||||
| v2 | ✗ |
|
|
||||||
| v1 | ✗ |
|
|
||||||
|
|
||||||
## Reporting a vulnerability
|
|
||||||
|
|
||||||
Please see [https://letsencrypt.org/contact/#security](https://letsencrypt.org/contact/#security) for the email address to report a vulnerability. Ensure that the subject line for your report contains the word `vulnerability` and is descriptive. Your email should be acknowledged within 24 hours. If you do not receive a response within 24 hours, please follow-up again with another email.
|
|
32
vendor/github.com/goccy/go-json/.codecov.yml
generated
vendored
32
vendor/github.com/goccy/go-json/.codecov.yml
generated
vendored
@ -1,32 +0,0 @@
|
|||||||
codecov:
|
|
||||||
require_ci_to_pass: yes
|
|
||||||
|
|
||||||
coverage:
|
|
||||||
precision: 2
|
|
||||||
round: down
|
|
||||||
range: "70...100"
|
|
||||||
|
|
||||||
status:
|
|
||||||
project:
|
|
||||||
default:
|
|
||||||
target: 70%
|
|
||||||
threshold: 2%
|
|
||||||
patch: off
|
|
||||||
changes: no
|
|
||||||
|
|
||||||
parsers:
|
|
||||||
gcov:
|
|
||||||
branch_detection:
|
|
||||||
conditional: yes
|
|
||||||
loop: yes
|
|
||||||
method: no
|
|
||||||
macro: no
|
|
||||||
|
|
||||||
comment:
|
|
||||||
layout: "header,diff"
|
|
||||||
behavior: default
|
|
||||||
require_changes: no
|
|
||||||
|
|
||||||
ignore:
|
|
||||||
- internal/encoder/vm_color
|
|
||||||
- internal/encoder/vm_color_indent
|
|
2
vendor/github.com/goccy/go-json/.gitignore
generated
vendored
2
vendor/github.com/goccy/go-json/.gitignore
generated
vendored
@ -1,2 +0,0 @@
|
|||||||
cover.html
|
|
||||||
cover.out
|
|
86
vendor/github.com/goccy/go-json/.golangci.yml
generated
vendored
86
vendor/github.com/goccy/go-json/.golangci.yml
generated
vendored
@ -1,86 +0,0 @@
|
|||||||
run:
|
|
||||||
skip-files:
|
|
||||||
- encode_optype.go
|
|
||||||
- ".*_test\\.go$"
|
|
||||||
|
|
||||||
linters-settings:
|
|
||||||
govet:
|
|
||||||
enable-all: true
|
|
||||||
disable:
|
|
||||||
- shadow
|
|
||||||
|
|
||||||
linters:
|
|
||||||
enable-all: true
|
|
||||||
disable:
|
|
||||||
- dogsled
|
|
||||||
- dupl
|
|
||||||
- exhaustive
|
|
||||||
- exhaustivestruct
|
|
||||||
- errorlint
|
|
||||||
- forbidigo
|
|
||||||
- funlen
|
|
||||||
- gci
|
|
||||||
- gochecknoglobals
|
|
||||||
- gochecknoinits
|
|
||||||
- gocognit
|
|
||||||
- gocritic
|
|
||||||
- gocyclo
|
|
||||||
- godot
|
|
||||||
- godox
|
|
||||||
- goerr113
|
|
||||||
- gofumpt
|
|
||||||
- gomnd
|
|
||||||
- gosec
|
|
||||||
- ifshort
|
|
||||||
- lll
|
|
||||||
- makezero
|
|
||||||
- nakedret
|
|
||||||
- nestif
|
|
||||||
- nlreturn
|
|
||||||
- paralleltest
|
|
||||||
- testpackage
|
|
||||||
- thelper
|
|
||||||
- wrapcheck
|
|
||||||
- interfacer
|
|
||||||
- lll
|
|
||||||
- nakedret
|
|
||||||
- nestif
|
|
||||||
- nlreturn
|
|
||||||
- testpackage
|
|
||||||
- wsl
|
|
||||||
- varnamelen
|
|
||||||
- nilnil
|
|
||||||
- ireturn
|
|
||||||
- govet
|
|
||||||
- forcetypeassert
|
|
||||||
- cyclop
|
|
||||||
- containedctx
|
|
||||||
- revive
|
|
||||||
- nosnakecase
|
|
||||||
- exhaustruct
|
|
||||||
- depguard
|
|
||||||
|
|
||||||
issues:
|
|
||||||
exclude-rules:
|
|
||||||
# not needed
|
|
||||||
- path: /*.go
|
|
||||||
text: "ST1003: should not use underscores in package names"
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
- path: /*.go
|
|
||||||
text: "don't use an underscore in package name"
|
|
||||||
linters:
|
|
||||||
- golint
|
|
||||||
- path: rtype.go
|
|
||||||
linters:
|
|
||||||
- golint
|
|
||||||
- stylecheck
|
|
||||||
- path: error.go
|
|
||||||
linters:
|
|
||||||
- staticcheck
|
|
||||||
|
|
||||||
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
|
|
||||||
max-issues-per-linter: 0
|
|
||||||
|
|
||||||
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
|
||||||
max-same-issues: 0
|
|
425
vendor/github.com/goccy/go-json/CHANGELOG.md
generated
vendored
425
vendor/github.com/goccy/go-json/CHANGELOG.md
generated
vendored
@ -1,425 +0,0 @@
|
|||||||
# v0.10.2 - 2023/03/20
|
|
||||||
|
|
||||||
### New features
|
|
||||||
|
|
||||||
* Support DebugDOT option for debugging encoder ( #440 )
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Fix combination of embedding structure and omitempty option ( #442 )
|
|
||||||
|
|
||||||
# v0.10.1 - 2023/03/13
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Fix checkptr error for array decoder ( #415 )
|
|
||||||
* Fix added buffer size check when decoding key ( #430 )
|
|
||||||
* Fix handling of anonymous fields other than struct ( #431 )
|
|
||||||
* Fix to not optimize when lower conversion can't handle byte-by-byte ( #432 )
|
|
||||||
* Fix a problem that MarshalIndent does not work when UnorderedMap is specified ( #435 )
|
|
||||||
* Fix mapDecoder.DecodeStream() for empty objects containing whitespace ( #425 )
|
|
||||||
* Fix an issue that could not set the correct NextField for fields in the embedded structure ( #438 )
|
|
||||||
|
|
||||||
# v0.10.0 - 2022/11/29
|
|
||||||
|
|
||||||
### New features
|
|
||||||
|
|
||||||
* Support JSON Path ( #250 )
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Fix marshaler for map's key ( #409 )
|
|
||||||
|
|
||||||
# v0.9.11 - 2022/08/18
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Fix unexpected behavior when buffer ends with backslash ( #383 )
|
|
||||||
* Fix stream decoding of escaped character ( #387 )
|
|
||||||
|
|
||||||
# v0.9.10 - 2022/07/15
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Fix boundary exception of type caching ( #382 )
|
|
||||||
|
|
||||||
# v0.9.9 - 2022/07/15
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Fix encoding of directed interface with typed nil ( #377 )
|
|
||||||
* Fix embedded primitive type encoding using alias ( #378 )
|
|
||||||
* Fix slice/array type encoding with types implementing MarshalJSON ( #379 )
|
|
||||||
* Fix unicode decoding when the expected buffer state is not met after reading ( #380 )
|
|
||||||
|
|
||||||
# v0.9.8 - 2022/06/30
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Fix decoding of surrogate-pair ( #365 )
|
|
||||||
* Fix handling of embedded primitive type ( #366 )
|
|
||||||
* Add validation of escape sequence for decoder ( #367 )
|
|
||||||
* Fix stream tokenizing respecting UseNumber ( #369 )
|
|
||||||
* Fix encoding when struct pointer type that implements Marshal JSON is embedded ( #375 )
|
|
||||||
|
|
||||||
### Improve performance
|
|
||||||
|
|
||||||
* Improve performance of linkRecursiveCode ( #368 )
|
|
||||||
|
|
||||||
# v0.9.7 - 2022/04/22
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
#### Encoder
|
|
||||||
|
|
||||||
* Add filtering process for encoding on slow path ( #355 )
|
|
||||||
* Fix encoding of interface{} with pointer type ( #363 )
|
|
||||||
|
|
||||||
#### Decoder
|
|
||||||
|
|
||||||
* Fix map key decoder that implements UnmarshalJSON ( #353 )
|
|
||||||
* Fix decoding of []uint8 type ( #361 )
|
|
||||||
|
|
||||||
### New features
|
|
||||||
|
|
||||||
* Add DebugWith option for encoder ( #356 )
|
|
||||||
|
|
||||||
# v0.9.6 - 2022/03/22
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Correct the handling of the minimum value of int type for decoder ( #344 )
|
|
||||||
* Fix bugs of stream decoder's bufferSize ( #349 )
|
|
||||||
* Add a guard to use typeptr more safely ( #351 )
|
|
||||||
|
|
||||||
### Improve decoder performance
|
|
||||||
|
|
||||||
* Improve escapeString's performance ( #345 )
|
|
||||||
|
|
||||||
### Others
|
|
||||||
|
|
||||||
* Update go version for CI ( #347 )
|
|
||||||
|
|
||||||
# v0.9.5 - 2022/03/04
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Fix panic when decoding time.Time with context ( #328 )
|
|
||||||
* Fix reading the next character in buffer to nul consideration ( #338 )
|
|
||||||
* Fix incorrect handling on skipValue ( #341 )
|
|
||||||
|
|
||||||
### Improve decoder performance
|
|
||||||
|
|
||||||
* Improve performance when a payload contains escape sequence ( #334 )
|
|
||||||
|
|
||||||
# v0.9.4 - 2022/01/21
|
|
||||||
|
|
||||||
* Fix IsNilForMarshaler for string type with omitempty ( #323 )
|
|
||||||
* Fix the case where the embedded field is at the end ( #326 )
|
|
||||||
|
|
||||||
# v0.9.3 - 2022/01/14
|
|
||||||
|
|
||||||
* Fix logic of removing struct field for decoder ( #322 )
|
|
||||||
|
|
||||||
# v0.9.2 - 2022/01/14
|
|
||||||
|
|
||||||
* Add invalid decoder to delay type error judgment at decode ( #321 )
|
|
||||||
|
|
||||||
# v0.9.1 - 2022/01/11
|
|
||||||
|
|
||||||
* Fix encoding of MarshalText/MarshalJSON operation with head offset ( #319 )
|
|
||||||
|
|
||||||
# v0.9.0 - 2022/01/05
|
|
||||||
|
|
||||||
### New feature
|
|
||||||
|
|
||||||
* Supports dynamic filtering of struct fields ( #314 )
|
|
||||||
|
|
||||||
### Improve encoding performance
|
|
||||||
|
|
||||||
* Improve map encoding performance ( #310 )
|
|
||||||
* Optimize encoding path for escaped string ( #311 )
|
|
||||||
* Add encoding option for performance ( #312 )
|
|
||||||
|
|
||||||
### Fix bugs
|
|
||||||
|
|
||||||
* Fix panic at encoding map value on 1.18 ( #310 )
|
|
||||||
* Fix MarshalIndent for interface type ( #317 )
|
|
||||||
|
|
||||||
# v0.8.1 - 2021/12/05
|
|
||||||
|
|
||||||
* Fix operation conversion from PtrHead to Head in Recursive type ( #305 )
|
|
||||||
|
|
||||||
# v0.8.0 - 2021/12/02
|
|
||||||
|
|
||||||
* Fix embedded field conflict behavior ( #300 )
|
|
||||||
* Refactor compiler for encoder ( #301 #302 )
|
|
||||||
|
|
||||||
# v0.7.10 - 2021/10/16
|
|
||||||
|
|
||||||
* Fix conversion from pointer to uint64 ( #294 )
|
|
||||||
|
|
||||||
# v0.7.9 - 2021/09/28
|
|
||||||
|
|
||||||
* Fix encoding of nil value about interface type that has method ( #291 )
|
|
||||||
|
|
||||||
# v0.7.8 - 2021/09/01
|
|
||||||
|
|
||||||
* Fix mapassign_faststr for indirect struct type ( #283 )
|
|
||||||
* Fix encoding of not empty interface type ( #284 )
|
|
||||||
* Fix encoding of empty struct interface type ( #286 )
|
|
||||||
|
|
||||||
# v0.7.7 - 2021/08/25
|
|
||||||
|
|
||||||
* Fix invalid utf8 on stream decoder ( #279 )
|
|
||||||
* Fix buffer length bug on string stream decoder ( #280 )
|
|
||||||
|
|
||||||
Thank you @orisano !!
|
|
||||||
|
|
||||||
# v0.7.6 - 2021/08/13
|
|
||||||
|
|
||||||
* Fix nil slice assignment ( #276 )
|
|
||||||
* Improve error message ( #277 )
|
|
||||||
|
|
||||||
# v0.7.5 - 2021/08/12
|
|
||||||
|
|
||||||
* Fix encoding of embedded struct with tags ( #265 )
|
|
||||||
* Fix encoding of embedded struct that isn't first field ( #272 )
|
|
||||||
* Fix decoding of binary type with escaped char ( #273 )
|
|
||||||
|
|
||||||
# v0.7.4 - 2021/07/06
|
|
||||||
|
|
||||||
* Fix encoding of indirect layout structure ( #264 )
|
|
||||||
|
|
||||||
# v0.7.3 - 2021/06/29
|
|
||||||
|
|
||||||
* Fix encoding of pointer type in empty interface ( #262 )
|
|
||||||
|
|
||||||
# v0.7.2 - 2021/06/26
|
|
||||||
|
|
||||||
### Fix decoder
|
|
||||||
|
|
||||||
* Add decoder for func type to fix decoding of nil function value ( #257 )
|
|
||||||
* Fix stream decoding of []byte type ( #258 )
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
|
|
||||||
* Improve decoding performance of map[string]interface{} type ( use `mapassign_faststr` ) ( #256 )
|
|
||||||
* Improve encoding performance of empty interface type ( remove recursive calling of `vm.Run` ) ( #259 )
|
|
||||||
|
|
||||||
### Benchmark
|
|
||||||
|
|
||||||
* Add bytedance/sonic as benchmark target ( #254 )
|
|
||||||
|
|
||||||
# v0.7.1 - 2021/06/18
|
|
||||||
|
|
||||||
### Fix decoder
|
|
||||||
|
|
||||||
* Fix error when unmarshal empty array ( #253 )
|
|
||||||
|
|
||||||
# v0.7.0 - 2021/06/12
|
|
||||||
|
|
||||||
### Support context for MarshalJSON and UnmarshalJSON ( #248 )
|
|
||||||
|
|
||||||
* json.MarshalContext(context.Context, interface{}, ...json.EncodeOption) ([]byte, error)
|
|
||||||
* json.NewEncoder(io.Writer).EncodeContext(context.Context, interface{}, ...json.EncodeOption) error
|
|
||||||
* json.UnmarshalContext(context.Context, []byte, interface{}, ...json.DecodeOption) error
|
|
||||||
* json.NewDecoder(io.Reader).DecodeContext(context.Context, interface{}) error
|
|
||||||
|
|
||||||
```go
|
|
||||||
type MarshalerContext interface {
|
|
||||||
MarshalJSON(context.Context) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type UnmarshalerContext interface {
|
|
||||||
UnmarshalJSON(context.Context, []byte) error
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Add DecodeFieldPriorityFirstWin option ( #242 )
|
|
||||||
|
|
||||||
In the default behavior, go-json, like encoding/json, will reflect the result of the last evaluation when a field with the same name exists. I've added new options to allow you to change this behavior. `json.DecodeFieldPriorityFirstWin` option reflects the result of the first evaluation if a field with the same name exists. This behavior has a performance advantage as it allows the subsequent strings to be skipped if all fields have been evaluated.
|
|
||||||
|
|
||||||
### Fix encoder
|
|
||||||
|
|
||||||
* Fix indent number contains recursive type ( #249 )
|
|
||||||
* Fix encoding of using empty interface as map key ( #244 )
|
|
||||||
|
|
||||||
### Fix decoder
|
|
||||||
|
|
||||||
* Fix decoding fields containing escaped characters ( #237 )
|
|
||||||
|
|
||||||
### Refactor
|
|
||||||
|
|
||||||
* Move some tests to subdirectory ( #243 )
|
|
||||||
* Refactor package layout for decoder ( #238 )
|
|
||||||
|
|
||||||
# v0.6.1 - 2021/06/02
|
|
||||||
|
|
||||||
### Fix encoder
|
|
||||||
|
|
||||||
* Fix value of totalLength for encoding ( #236 )
|
|
||||||
|
|
||||||
# v0.6.0 - 2021/06/01
|
|
||||||
|
|
||||||
### Support Colorize option for encoding (#233)
|
|
||||||
|
|
||||||
```go
|
|
||||||
b, err := json.MarshalWithOption(v, json.Colorize(json.DefaultColorScheme))
|
|
||||||
if err != nil {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
fmt.Println(string(b)) // print colored json
|
|
||||||
```
|
|
||||||
|
|
||||||
### Refactor
|
|
||||||
|
|
||||||
* Fix opcode layout - Adjust memory layout of the opcode to 128 bytes in a 64-bit environment ( #230 )
|
|
||||||
* Refactor encode option ( #231 )
|
|
||||||
* Refactor escape string ( #232 )
|
|
||||||
|
|
||||||
# v0.5.1 - 2021/5/20
|
|
||||||
|
|
||||||
### Optimization
|
|
||||||
|
|
||||||
* Add type addrShift to enable bigger encoder/decoder cache ( #213 )
|
|
||||||
|
|
||||||
### Fix decoder
|
|
||||||
|
|
||||||
* Keep original reference of slice element ( #229 )
|
|
||||||
|
|
||||||
### Refactor
|
|
||||||
|
|
||||||
* Refactor Debug mode for encoding ( #226 )
|
|
||||||
* Generate VM sources for encoding ( #227 )
|
|
||||||
* Refactor validator for null/true/false for decoding ( #221 )
|
|
||||||
|
|
||||||
# v0.5.0 - 2021/5/9
|
|
||||||
|
|
||||||
### Supports using omitempty and string tags at the same time ( #216 )
|
|
||||||
|
|
||||||
### Fix decoder
|
|
||||||
|
|
||||||
* Fix stream decoder for unicode char ( #215 )
|
|
||||||
* Fix decoding of slice element ( #219 )
|
|
||||||
* Fix calculating of buffer length for stream decoder ( #220 )
|
|
||||||
|
|
||||||
### Refactor
|
|
||||||
|
|
||||||
* replace skipWhiteSpace goto by loop ( #212 )
|
|
||||||
|
|
||||||
# v0.4.14 - 2021/5/4
|
|
||||||
|
|
||||||
### Benchmark
|
|
||||||
|
|
||||||
* Add valyala/fastjson to benchmark ( #193 )
|
|
||||||
* Add benchmark task for CI ( #211 )
|
|
||||||
|
|
||||||
### Fix decoder
|
|
||||||
|
|
||||||
* Fix decoding of slice with unmarshal json type ( #198 )
|
|
||||||
* Fix decoding of null value for interface type that does not implement Unmarshaler ( #205 )
|
|
||||||
* Fix decoding of null value to []byte by json.Unmarshal ( #206 )
|
|
||||||
* Fix decoding of backslash char at the end of string ( #207 )
|
|
||||||
* Fix stream decoder for null/true/false value ( #208 )
|
|
||||||
* Fix stream decoder for slow reader ( #211 )
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
|
|
||||||
* If cap of slice is enough, reuse slice data for compatibility with encoding/json ( #200 )
|
|
||||||
|
|
||||||
# v0.4.13 - 2021/4/20
|
|
||||||
|
|
||||||
### Fix json.Compact and json.Indent
|
|
||||||
|
|
||||||
* Support validation the input buffer for json.Compact and json.Indent ( #189 )
|
|
||||||
* Optimize json.Compact and json.Indent ( improve memory footprint ) ( #190 )
|
|
||||||
|
|
||||||
# v0.4.12 - 2021/4/15
|
|
||||||
|
|
||||||
### Fix encoder
|
|
||||||
|
|
||||||
* Fix unnecessary indent for empty slice type ( #181 )
|
|
||||||
* Fix encoding of omitempty feature for the slice or interface type ( #183 )
|
|
||||||
* Fix encoding custom types zero values with omitempty when marshaller exists ( #187 )
|
|
||||||
|
|
||||||
### Fix decoder
|
|
||||||
|
|
||||||
* Fix decoder for invalid top level value ( #184 )
|
|
||||||
* Fix decoder for invalid number value ( #185 )
|
|
||||||
|
|
||||||
# v0.4.11 - 2021/4/3
|
|
||||||
|
|
||||||
* Improve decoder performance for interface type
|
|
||||||
|
|
||||||
# v0.4.10 - 2021/4/2
|
|
||||||
|
|
||||||
### Fix encoder
|
|
||||||
|
|
||||||
* Fixed a bug when encoding slice and map containing recursive structures
|
|
||||||
* Fixed a logic to determine if indirect reference
|
|
||||||
|
|
||||||
# v0.4.9 - 2021/3/29
|
|
||||||
|
|
||||||
### Add debug mode
|
|
||||||
|
|
||||||
If you use `json.MarshalWithOption(v, json.Debug())` and `panic` occurred in `go-json`, produces debug information to console.
|
|
||||||
|
|
||||||
### Support a new feature to compatible with encoding/json
|
|
||||||
|
|
||||||
- invalid UTF-8 is coerced to valid UTF-8 ( without performance down )
|
|
||||||
|
|
||||||
### Fix encoder
|
|
||||||
|
|
||||||
- Fixed handling of MarshalJSON of function type
|
|
||||||
|
|
||||||
### Fix decoding of slice of pointer type
|
|
||||||
|
|
||||||
If there is a pointer value, go-json will use it. (This behavior is necessary to achieve the ability to prioritize pre-filled values). However, since slices are reused internally, there was a bug that referred to the previous pointer value. Therefore, it is not necessary to refer to the pointer value in advance for the slice element, so we explicitly initialize slice element by `nil`.
|
|
||||||
|
|
||||||
# v0.4.8 - 2021/3/21
|
|
||||||
|
|
||||||
### Reduce memory usage at compile time
|
|
||||||
|
|
||||||
* go-json have used about 2GB of memory at compile time, but now it can compile with about less than 550MB.
|
|
||||||
|
|
||||||
### Fix any encoder's bug
|
|
||||||
|
|
||||||
* Add many test cases for encoder
|
|
||||||
* Fix composite type ( slice/array/map )
|
|
||||||
* Fix pointer types
|
|
||||||
* Fix encoding of MarshalJSON or MarshalText or json.Number type
|
|
||||||
|
|
||||||
### Refactor encoder
|
|
||||||
|
|
||||||
* Change package layout for reducing memory usage at compile
|
|
||||||
* Remove anonymous and only operation
|
|
||||||
* Remove root property from encodeCompileContext and opcode
|
|
||||||
|
|
||||||
### Fix CI
|
|
||||||
|
|
||||||
* Add Go 1.16
|
|
||||||
* Remove Go 1.13
|
|
||||||
* Fix `make cover` task
|
|
||||||
|
|
||||||
### Number/Delim/Token/RawMessage use the types defined in encoding/json by type alias
|
|
||||||
|
|
||||||
# v0.4.7 - 2021/02/22
|
|
||||||
|
|
||||||
### Fix decoder
|
|
||||||
|
|
||||||
* Fix decoding of deep recursive structure
|
|
||||||
* Fix decoding of embedded unexported pointer field
|
|
||||||
* Fix invalid test case
|
|
||||||
* Fix decoding of invalid value
|
|
||||||
* Fix decoding of prefilled value
|
|
||||||
* Fix not being able to return UnmarshalTypeError when it should be returned
|
|
||||||
* Fix decoding of null value
|
|
||||||
* Fix decoding of type of null string
|
|
||||||
* Use pre allocated pointer if exists it at decoding
|
|
||||||
|
|
||||||
### Reduce memory usage at compile
|
|
||||||
|
|
||||||
* Integrate int/int8/int16/int32/int64 and uint/uint8/uint16/uint32/uint64 operation to reduce memory usage at compile
|
|
||||||
|
|
||||||
### Remove unnecessary optype
|
|
21
vendor/github.com/goccy/go-json/LICENSE
generated
vendored
21
vendor/github.com/goccy/go-json/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2020 Masaaki Goshima
|
|
||||||
|
|
||||||
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.
|
|
39
vendor/github.com/goccy/go-json/Makefile
generated
vendored
39
vendor/github.com/goccy/go-json/Makefile
generated
vendored
@ -1,39 +0,0 @@
|
|||||||
PKG := github.com/goccy/go-json
|
|
||||||
|
|
||||||
BIN_DIR := $(CURDIR)/bin
|
|
||||||
PKGS := $(shell go list ./... | grep -v internal/cmd|grep -v test)
|
|
||||||
COVER_PKGS := $(foreach pkg,$(PKGS),$(subst $(PKG),.,$(pkg)))
|
|
||||||
|
|
||||||
COMMA := ,
|
|
||||||
EMPTY :=
|
|
||||||
SPACE := $(EMPTY) $(EMPTY)
|
|
||||||
COVERPKG_OPT := $(subst $(SPACE),$(COMMA),$(COVER_PKGS))
|
|
||||||
|
|
||||||
$(BIN_DIR):
|
|
||||||
@mkdir -p $(BIN_DIR)
|
|
||||||
|
|
||||||
.PHONY: cover
|
|
||||||
cover:
|
|
||||||
go test -coverpkg=$(COVERPKG_OPT) -coverprofile=cover.out ./...
|
|
||||||
|
|
||||||
.PHONY: cover-html
|
|
||||||
cover-html: cover
|
|
||||||
go tool cover -html=cover.out
|
|
||||||
|
|
||||||
.PHONY: lint
|
|
||||||
lint: golangci-lint
|
|
||||||
$(BIN_DIR)/golangci-lint run
|
|
||||||
|
|
||||||
golangci-lint: | $(BIN_DIR)
|
|
||||||
@{ \
|
|
||||||
set -e; \
|
|
||||||
GOLANGCI_LINT_TMP_DIR=$$(mktemp -d); \
|
|
||||||
cd $$GOLANGCI_LINT_TMP_DIR; \
|
|
||||||
go mod init tmp; \
|
|
||||||
GOBIN=$(BIN_DIR) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.54.2; \
|
|
||||||
rm -rf $$GOLANGCI_LINT_TMP_DIR; \
|
|
||||||
}
|
|
||||||
|
|
||||||
.PHONY: generate
|
|
||||||
generate:
|
|
||||||
go generate ./internal/...
|
|
529
vendor/github.com/goccy/go-json/README.md
generated
vendored
529
vendor/github.com/goccy/go-json/README.md
generated
vendored
@ -1,529 +0,0 @@
|
|||||||
# go-json
|
|
||||||
|
|
||||||

|
|
||||||
[](https://pkg.go.dev/github.com/goccy/go-json?tab=doc)
|
|
||||||
[](https://codecov.io/gh/goccy/go-json)
|
|
||||||
|
|
||||||
Fast JSON encoder/decoder compatible with encoding/json for Go
|
|
||||||
|
|
||||||
<img width="400px" src="https://user-images.githubusercontent.com/209884/92572337-42b42900-f2bf-11ea-973a-c74a359553a5.png"></img>
|
|
||||||
|
|
||||||
# Roadmap
|
|
||||||
|
|
||||||
```
|
|
||||||
* version ( expected release date )
|
|
||||||
|
|
||||||
* v0.9.0
|
|
||||||
|
|
|
||||||
| while maintaining compatibility with encoding/json, we will add convenient APIs
|
|
||||||
|
|
|
||||||
v
|
|
||||||
* v1.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
We are accepting requests for features that will be implemented between v0.9.0 and v.1.0.0.
|
|
||||||
If you have the API you need, please submit your issue [here](https://github.com/goccy/go-json/issues).
|
|
||||||
|
|
||||||
# Features
|
|
||||||
|
|
||||||
- Drop-in replacement of `encoding/json`
|
|
||||||
- Fast ( See [Benchmark section](https://github.com/goccy/go-json#benchmarks) )
|
|
||||||
- Flexible customization with options
|
|
||||||
- Coloring the encoded string
|
|
||||||
- Can propagate context.Context to `MarshalJSON` or `UnmarshalJSON`
|
|
||||||
- Can dynamically filter the fields of the structure type-safely
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
```
|
|
||||||
go get github.com/goccy/go-json
|
|
||||||
```
|
|
||||||
|
|
||||||
# How to use
|
|
||||||
|
|
||||||
Replace import statement from `encoding/json` to `github.com/goccy/go-json`
|
|
||||||
|
|
||||||
```
|
|
||||||
-import "encoding/json"
|
|
||||||
+import "github.com/goccy/go-json"
|
|
||||||
```
|
|
||||||
|
|
||||||
# JSON library comparison
|
|
||||||
|
|
||||||
| name | encoder | decoder | compatible with `encoding/json` |
|
|
||||||
| :----: | :------: | :-----: | :-----------------------------: |
|
|
||||||
| encoding/json | yes | yes | N/A |
|
|
||||||
| [json-iterator/go](https://github.com/json-iterator/go) | yes | yes | partial |
|
|
||||||
| [easyjson](https://github.com/mailru/easyjson) | yes | yes | no |
|
|
||||||
| [gojay](https://github.com/francoispqt/gojay) | yes | yes | no |
|
|
||||||
| [segmentio/encoding/json](https://github.com/segmentio/encoding/tree/master/json) | yes | yes | partial |
|
|
||||||
| [jettison](https://github.com/wI2L/jettison) | yes | no | no |
|
|
||||||
| [simdjson-go](https://github.com/minio/simdjson-go) | no | yes | no |
|
|
||||||
| goccy/go-json | yes | yes | yes |
|
|
||||||
|
|
||||||
- `json-iterator/go` isn't compatible with `encoding/json` in many ways (e.g. https://github.com/json-iterator/go/issues/229 ), but it hasn't been supported for a long time.
|
|
||||||
- `segmentio/encoding/json` is well supported for encoders, but some are not supported for decoder APIs such as `Token` ( streaming decode )
|
|
||||||
|
|
||||||
## Other libraries
|
|
||||||
|
|
||||||
- [jingo](https://github.com/bet365/jingo)
|
|
||||||
|
|
||||||
I tried the benchmark but it didn't work.
|
|
||||||
Also, it seems to panic when it receives an unexpected value because there is no error handling...
|
|
||||||
|
|
||||||
- [ffjson](https://github.com/pquerna/ffjson)
|
|
||||||
|
|
||||||
Benchmarking gave very slow results.
|
|
||||||
It seems that it is assumed that the user will use the buffer pool properly.
|
|
||||||
Also, development seems to have already stopped
|
|
||||||
|
|
||||||
# Benchmarks
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cd benchmarks
|
|
||||||
$ go test -bench .
|
|
||||||
```
|
|
||||||
|
|
||||||
## Encode
|
|
||||||
|
|
||||||
<img width="700px" src="https://user-images.githubusercontent.com/209884/107126758-0845cb00-68f5-11eb-8db7-086fcf9bcfaa.png"></img>
|
|
||||||
<img width="700px" src="https://user-images.githubusercontent.com/209884/107126757-07ad3480-68f5-11eb-87aa-858cc5eacfcb.png"></img>
|
|
||||||
|
|
||||||
## Decode
|
|
||||||
|
|
||||||
<img width="700" alt="" src="https://user-images.githubusercontent.com/209884/107979944-bd1d6d80-7002-11eb-944b-9d17b6674e3f.png">
|
|
||||||
<img width="700" alt="" src="https://user-images.githubusercontent.com/209884/107979931-b989e680-7002-11eb-87a0-66fc22d90dd4.png">
|
|
||||||
<img width="700" alt="" src="https://user-images.githubusercontent.com/209884/107979940-bc84d700-7002-11eb-9647-869bbc25c9d9.png">
|
|
||||||
|
|
||||||
|
|
||||||
# Fuzzing
|
|
||||||
|
|
||||||
[go-json-fuzz](https://github.com/goccy/go-json-fuzz) is the repository for fuzzing tests.
|
|
||||||
If you run the test in this repository and find a bug, please commit to corpus to go-json-fuzz and report the issue to [go-json](https://github.com/goccy/go-json/issues).
|
|
||||||
|
|
||||||
# How it works
|
|
||||||
|
|
||||||
`go-json` is very fast in both encoding and decoding compared to other libraries.
|
|
||||||
It's easier to implement by using automatic code generation for performance or by using a dedicated interface, but `go-json` dares to stick to compatibility with `encoding/json` and is the simple interface. Despite this, we are developing with the aim of being the fastest library.
|
|
||||||
|
|
||||||
Here, we explain the various speed-up techniques implemented by `go-json`.
|
|
||||||
|
|
||||||
## Basic technique
|
|
||||||
|
|
||||||
The techniques listed here are the ones used by most of the libraries listed above.
|
|
||||||
|
|
||||||
### Buffer reuse
|
|
||||||
|
|
||||||
Since the only value required for the result of `json.Marshal(interface{}) ([]byte, error)` is `[]byte`, the only value that must be allocated during encoding is the return value `[]byte` .
|
|
||||||
|
|
||||||
Also, as the number of allocations increases, the performance will be affected, so the number of allocations should be kept as low as possible when creating `[]byte`.
|
|
||||||
|
|
||||||
Therefore, there is a technique to reduce the number of times a new buffer must be allocated by reusing the buffer used for the previous encoding by using `sync.Pool`.
|
|
||||||
|
|
||||||
Finally, you allocate a buffer that is as long as the resulting buffer and copy the contents into it, you only need to allocate the buffer once in theory.
|
|
||||||
|
|
||||||
```go
|
|
||||||
type buffer struct {
|
|
||||||
data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
var bufPool = sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return &buffer{data: make([]byte, 0, 1024)}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := bufPool.Get().(*buffer)
|
|
||||||
data := encode(buf.data) // reuse buf.data
|
|
||||||
|
|
||||||
newBuf := make([]byte, len(data))
|
|
||||||
copy(newBuf, buf)
|
|
||||||
|
|
||||||
buf.data = data
|
|
||||||
bufPool.Put(buf)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Elimination of reflection
|
|
||||||
|
|
||||||
As you know, the reflection operation is very slow.
|
|
||||||
|
|
||||||
Therefore, using the fact that the address position where the type information is stored is fixed for each binary ( we call this `typeptr` ),
|
|
||||||
we can use the address in the type information to call a pre-built optimized process.
|
|
||||||
|
|
||||||
For example, you can get the address to the type information from `interface{}` as follows and you can use that information to call a process that does not have reflection.
|
|
||||||
|
|
||||||
To process without reflection, pass a pointer (`unsafe.Pointer`) to the value is stored.
|
|
||||||
|
|
||||||
```go
|
|
||||||
|
|
||||||
type emptyInterface struct {
|
|
||||||
typ unsafe.Pointer
|
|
||||||
ptr unsafe.Pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
var typeToEncoder = map[uintptr]func(unsafe.Pointer)([]byte, error){}
|
|
||||||
|
|
||||||
func Marshal(v interface{}) ([]byte, error) {
|
|
||||||
iface := (*emptyInterface)(unsafe.Pointer(&v)
|
|
||||||
typeptr := uintptr(iface.typ)
|
|
||||||
if enc, exists := typeToEncoder[typeptr]; exists {
|
|
||||||
return enc(iface.ptr)
|
|
||||||
}
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
※ In reality, `typeToEncoder` can be referenced by multiple goroutines, so exclusive control is required.
|
|
||||||
|
|
||||||
## Unique speed-up technique
|
|
||||||
|
|
||||||
## Encoder
|
|
||||||
|
|
||||||
### Do not escape arguments of `Marshal`
|
|
||||||
|
|
||||||
`json.Marshal` and `json.Unmarshal` receive `interface{}` value and they perform type determination dynamically to process.
|
|
||||||
In normal case, you need to use the `reflect` library to determine the type dynamically, but since `reflect.Type` is defined as `interface`, when you call the method of `reflect.Type`, The reflect's argument is escaped.
|
|
||||||
|
|
||||||
Therefore, the arguments for `Marshal` and `Unmarshal` are always escaped to the heap.
|
|
||||||
However, `go-json` can use the feature of `reflect.Type` while avoiding escaping.
|
|
||||||
|
|
||||||
`reflect.Type` is defined as `interface`, but in reality `reflect.Type` is implemented only by the structure `rtype` defined in the `reflect` package.
|
|
||||||
For this reason, to date `reflect.Type` is the same as `*reflect.rtype`.
|
|
||||||
|
|
||||||
Therefore, by directly handling `*reflect.rtype`, which is an implementation of `reflect.Type`, it is possible to avoid escaping because it changes from `interface` to using `struct`.
|
|
||||||
|
|
||||||
The technique for working with `*reflect.rtype` directly from `go-json` is implemented at [rtype.go](https://github.com/goccy/go-json/blob/master/internal/runtime/rtype.go)
|
|
||||||
|
|
||||||
Also, the same technique is cut out as a library ( https://github.com/goccy/go-reflect )
|
|
||||||
|
|
||||||
Initially this feature was the default behavior of `go-json`.
|
|
||||||
But after careful testing, I found that I passed a large value to `json.Marshal()` and if the argument could not be assigned to the stack, it could not be properly escaped to the heap (a bug in the Go compiler).
|
|
||||||
|
|
||||||
Therefore, this feature will be provided as an **optional** until this issue is resolved.
|
|
||||||
|
|
||||||
To use it, add `NoEscape` like `MarshalNoEscape()`
|
|
||||||
|
|
||||||
### Encoding using opcode sequence
|
|
||||||
|
|
||||||
I explained that you can use `typeptr` to call a pre-built process from type information.
|
|
||||||
|
|
||||||
In other libraries, this dedicated process is processed by making it an function calling like anonymous function, but function calls are inherently slow processes and should be avoided as much as possible.
|
|
||||||
|
|
||||||
Therefore, `go-json` adopted the Instruction-based execution processing system, which is also used to implement virtual machines for programming language.
|
|
||||||
|
|
||||||
If it is the first type to encode, create the opcode ( instruction ) sequence required for encoding.
|
|
||||||
From the second time onward, use `typeptr` to get the cached pre-built opcode sequence and encode it based on it. An example of the opcode sequence is shown below.
|
|
||||||
|
|
||||||
```go
|
|
||||||
json.Marshal(struct{
|
|
||||||
X int `json:"x"`
|
|
||||||
Y string `json:"y"`
|
|
||||||
}{X: 1, Y: "hello"})
|
|
||||||
```
|
|
||||||
|
|
||||||
When encoding a structure like the one above, create a sequence of opcodes like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
- opStructFieldHead ( `{` )
|
|
||||||
- opStructFieldInt ( `"x": 1,` )
|
|
||||||
- opStructFieldString ( `"y": "hello"` )
|
|
||||||
- opStructEnd ( `}` )
|
|
||||||
- opEnd
|
|
||||||
```
|
|
||||||
|
|
||||||
※ When processing each operation, write the letters on the right.
|
|
||||||
|
|
||||||
In addition, each opcode is managed by the following structure (
|
|
||||||
Pseudo code ).
|
|
||||||
|
|
||||||
```go
|
|
||||||
type opType int
|
|
||||||
const (
|
|
||||||
opStructFieldHead opType = iota
|
|
||||||
opStructFieldInt
|
|
||||||
opStructFieldStirng
|
|
||||||
opStructEnd
|
|
||||||
opEnd
|
|
||||||
)
|
|
||||||
type opcode struct {
|
|
||||||
op opType
|
|
||||||
key []byte
|
|
||||||
next *opcode
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The process of encoding using the opcode sequence is roughly implemented as follows.
|
|
||||||
|
|
||||||
```go
|
|
||||||
func encode(code *opcode, b []byte, p unsafe.Pointer) ([]byte, error) {
|
|
||||||
for {
|
|
||||||
switch code.op {
|
|
||||||
case opStructFieldHead:
|
|
||||||
b = append(b, '{')
|
|
||||||
code = code.next
|
|
||||||
case opStructFieldInt:
|
|
||||||
b = append(b, code.key...)
|
|
||||||
b = appendInt((*int)(unsafe.Pointer(uintptr(p)+code.offset)))
|
|
||||||
code = code.next
|
|
||||||
case opStructFieldString:
|
|
||||||
b = append(b, code.key...)
|
|
||||||
b = appendString((*string)(unsafe.Pointer(uintptr(p)+code.offset)))
|
|
||||||
code = code.next
|
|
||||||
case opStructEnd:
|
|
||||||
b = append(b, '}')
|
|
||||||
code = code.next
|
|
||||||
case opEnd:
|
|
||||||
goto END
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END:
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In this way, the huge `switch-case` is used to encode by manipulating the linked list opcodes to avoid unnecessary function calls.
|
|
||||||
|
|
||||||
### Opcode sequence optimization
|
|
||||||
|
|
||||||
One of the advantages of encoding using the opcode sequence is the ease of optimization.
|
|
||||||
The opcode sequence mentioned above is actually converted into the following optimized operations and used.
|
|
||||||
|
|
||||||
```
|
|
||||||
- opStructFieldHeadInt ( `{"x": 1,` )
|
|
||||||
- opStructEndString ( `"y": "hello"}` )
|
|
||||||
- opEnd
|
|
||||||
```
|
|
||||||
|
|
||||||
It has been reduced from 5 opcodes to 3 opcodes !
|
|
||||||
Reducing the number of opcodees means reducing the number of branches with `switch-case`.
|
|
||||||
In other words, the closer the number of operations is to 1, the faster the processing can be performed.
|
|
||||||
|
|
||||||
In `go-json`, optimization to reduce the number of opcodes itself like the above and it speeds up by preparing opcodes with optimized paths.
|
|
||||||
|
|
||||||
### Change recursive call from CALL to JMP
|
|
||||||
|
|
||||||
Recursive processing is required during encoding if the type is defined recursively as follows:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type T struct {
|
|
||||||
X int
|
|
||||||
U *U
|
|
||||||
}
|
|
||||||
|
|
||||||
type U struct {
|
|
||||||
T *T
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := json.Marshal(&T{
|
|
||||||
X: 1,
|
|
||||||
U: &U{
|
|
||||||
T: &T{
|
|
||||||
X: 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
fmt.Println(string(b)) // {"X":1,"U":{"T":{"X":2,"U":null}}}
|
|
||||||
```
|
|
||||||
|
|
||||||
In `go-json`, recursive processing is processed by the operation type of ` opStructFieldRecursive`.
|
|
||||||
|
|
||||||
In this operation, after acquiring the opcode sequence used for recursive processing, the function is **not** called recursively as it is, but the necessary values are saved by itself and implemented by moving to the next operation.
|
|
||||||
|
|
||||||
The technique of implementing recursive processing with the `JMP` operation while avoiding the `CALL` operation is a famous technique for implementing a high-speed virtual machine.
|
|
||||||
|
|
||||||
For more details, please refer to [the article](https://engineering.mercari.com/blog/entry/1599563768-081104c850) ( but Japanese only ).
|
|
||||||
|
|
||||||
### Dispatch by typeptr from map to slice
|
|
||||||
|
|
||||||
When retrieving the data cached from the type information by `typeptr`, we usually use map.
|
|
||||||
Map requires exclusive control, so use `sync.Map` for a naive implementation.
|
|
||||||
|
|
||||||
However, this is slow, so it's a good idea to use the `atomic` package for exclusive control as implemented by `segmentio/encoding/json` ( https://github.com/segmentio/encoding/blob/master/json/codec.go#L41-L55 ).
|
|
||||||
|
|
||||||
This implementation slows down the set instead of speeding up the get, but it works well because of the nature of the library, it encodes much more for the same type.
|
|
||||||
|
|
||||||
However, as a result of profiling, I noticed that `runtime.mapaccess2` accounts for a significant percentage of the execution time. So I thought if I could change the lookup from map to slice.
|
|
||||||
|
|
||||||
There is an API named `typelinks` defined in the `runtime` package that the `reflect` package uses internally.
|
|
||||||
This allows you to get all the type information defined in the binary at runtime.
|
|
||||||
|
|
||||||
The fact that all type information can be acquired means that by constructing slices in advance with the acquired total number of type information, it is possible to look up with the value of `typeptr` without worrying about out-of-range access.
|
|
||||||
|
|
||||||
However, if there is too much type information, it will use a lot of memory, so by default we will only use this optimization if the slice size fits within **2Mib** .
|
|
||||||
|
|
||||||
If this approach is not available, it will fall back to the `atomic` based process described above.
|
|
||||||
|
|
||||||
If you want to know more, please refer to the implementation [here](https://github.com/goccy/go-json/blob/master/internal/runtime/type.go#L36-L100)
|
|
||||||
|
|
||||||
## Decoder
|
|
||||||
|
|
||||||
### Dispatch by typeptr from map to slice
|
|
||||||
|
|
||||||
Like the encoder, the decoder also uses typeptr to call the dedicated process.
|
|
||||||
|
|
||||||
### Faster termination character inspection using NUL character
|
|
||||||
|
|
||||||
In order to decode, you have to traverse the input buffer character by position.
|
|
||||||
At that time, if you check whether the buffer has reached the end, it will be very slow.
|
|
||||||
|
|
||||||
`buf` : `[]byte` type variable. holds the string passed to the decoder
|
|
||||||
`cursor` : `int64` type variable. holds the current read position
|
|
||||||
|
|
||||||
```go
|
|
||||||
buflen := len(buf)
|
|
||||||
for ; cursor < buflen; cursor++ { // compare cursor and buflen at all times, it is so slow.
|
|
||||||
switch buf[cursor] {
|
|
||||||
case ' ', '\n', '\r', '\t':
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Therefore, by adding the `NUL` (`\000`) character to the end of the read buffer as shown below, it is possible to check the termination character at the same time as other characters.
|
|
||||||
|
|
||||||
```go
|
|
||||||
for {
|
|
||||||
switch buf[cursor] {
|
|
||||||
case ' ', '\n', '\r', '\t':
|
|
||||||
case '\000':
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
cursor++
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Use Boundary Check Elimination
|
|
||||||
|
|
||||||
Due to the `NUL` character optimization, the Go compiler does a boundary check every time, even though `buf[cursor]` does not cause out-of-range access.
|
|
||||||
|
|
||||||
Therefore, `go-json` eliminates boundary check by fetching characters for hotspot by pointer operation. For example, the following code.
|
|
||||||
|
|
||||||
```go
|
|
||||||
func char(ptr unsafe.Pointer, offset int64) byte {
|
|
||||||
return *(*byte)(unsafe.Pointer(uintptr(ptr) + uintptr(offset)))
|
|
||||||
}
|
|
||||||
|
|
||||||
p := (*sliceHeader)(&unsafe.Pointer(buf)).data
|
|
||||||
for {
|
|
||||||
switch char(p, cursor) {
|
|
||||||
case ' ', '\n', '\r', '\t':
|
|
||||||
case '\000':
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
cursor++
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Checking the existence of fields of struct using Bitmaps
|
|
||||||
|
|
||||||
I found by the profiling result, in the struct decode, lookup process for field was taking a long time.
|
|
||||||
|
|
||||||
For example, consider decoding a string like `{"a":1,"b":2,"c":3}` into the following structure:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type T struct {
|
|
||||||
A int `json:"a"`
|
|
||||||
B int `json:"b"`
|
|
||||||
C int `json:"c"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
At this time, it was found that it takes a lot of time to acquire the decoding process corresponding to the field from the field name as shown below during the decoding process.
|
|
||||||
|
|
||||||
```go
|
|
||||||
fieldName := decodeKey(buf, cursor) // "a" or "b" or "c"
|
|
||||||
decoder, exists := fieldToDecoderMap[fieldName] // so slow
|
|
||||||
if exists {
|
|
||||||
decoder(buf, cursor)
|
|
||||||
} else {
|
|
||||||
skipValue(buf, cursor)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To improve this process, `json-iterator/go` is optimized so that it can be branched by switch-case when the number of fields in the structure is 10 or less (switch-case is faster than map). However, there is a risk of hash collision because the value hashed by the FNV algorithm is used for conditional branching. Also, `gojay` processes this part at high speed by letting the library user yourself write `switch-case`.
|
|
||||||
|
|
||||||
|
|
||||||
`go-json` considers and implements a new approach that is different from these. I call this **bitmap field optimization**.
|
|
||||||
|
|
||||||
The range of values per character can be represented by `[256]byte`. Also, if the number of fields in the structure is 8 or less, `int8` type can represent the state of each field.
|
|
||||||
In other words, it has the following structure.
|
|
||||||
|
|
||||||
- Base ( 8bit ): `00000000`
|
|
||||||
- Key "a": `00000001` ( assign key "a" to the first bit )
|
|
||||||
- Key "b": `00000010` ( assign key "b" to the second bit )
|
|
||||||
- Key "c": `00000100` ( assign key "c" to the third bit )
|
|
||||||
|
|
||||||
Bitmap structure is the following
|
|
||||||
|
|
||||||
```
|
|
||||||
| key index(0) |
|
|
||||||
------------------------
|
|
||||||
0 | 00000000 |
|
|
||||||
1 | 00000000 |
|
|
||||||
~~ | |
|
|
||||||
97 (a) | 00000001 |
|
|
||||||
98 (b) | 00000010 |
|
|
||||||
99 (c) | 00000100 |
|
|
||||||
~~ | |
|
|
||||||
255 | 00000000 |
|
|
||||||
```
|
|
||||||
|
|
||||||
You can think of this as a Bitmap with a height of `256` and a width of the maximum string length in the field name.
|
|
||||||
In other words, it can be represented by the following type .
|
|
||||||
|
|
||||||
```go
|
|
||||||
[maxFieldKeyLength][256]int8
|
|
||||||
```
|
|
||||||
|
|
||||||
When decoding a field character, check whether the corresponding character exists by referring to the pre-built bitmap like the following.
|
|
||||||
|
|
||||||
```go
|
|
||||||
var curBit int8 = math.MaxInt8 // 11111111
|
|
||||||
|
|
||||||
c := char(buf, cursor)
|
|
||||||
bit := bitmap[keyIdx][c]
|
|
||||||
curBit &= bit
|
|
||||||
if curBit == 0 {
|
|
||||||
// not found field
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If `curBit` is not `0` until the end of the field string, then the string is
|
|
||||||
You may have hit one of the fields.
|
|
||||||
But the possibility is that if the decoded string is shorter than the field string, you will get a false hit.
|
|
||||||
|
|
||||||
- input: `{"a":1}`
|
|
||||||
```go
|
|
||||||
type T struct {
|
|
||||||
X int `json:"abc"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
※ Since `a` is shorter than `abc`, it can decode to the end of the field character without `curBit` being 0.
|
|
||||||
|
|
||||||
Rest assured. In this case, it doesn't matter because you can tell if you hit by comparing the string length of `a` with the string length of `abc`.
|
|
||||||
|
|
||||||
Finally, calculate the position of the bit where `1` is set and get the corresponding value, and you're done.
|
|
||||||
|
|
||||||
Using this technique, field lookups are possible with only bitwise operations and access to slices.
|
|
||||||
|
|
||||||
`go-json` uses a similar technique for fields with 9 or more and 16 or less fields. At this time, Bitmap is constructed as `[maxKeyLen][256]int16` type.
|
|
||||||
|
|
||||||
Currently, this optimization is not performed when the maximum length of the field name is long (specifically, 64 bytes or more) in addition to the limitation of the number of fields from the viewpoint of saving memory usage.
|
|
||||||
|
|
||||||
### Others
|
|
||||||
|
|
||||||
I have done a lot of other optimizations. I will find time to write about them. If you have any questions about what's written here or other optimizations, please visit the `#go-json` channel on `gophers.slack.com` .
|
|
||||||
|
|
||||||
## Reference
|
|
||||||
|
|
||||||
Regarding the story of go-json, there are the following articles in Japanese only.
|
|
||||||
|
|
||||||
- https://speakerdeck.com/goccy/zui-su-falsejsonraiburariwoqiu-mete
|
|
||||||
- https://engineering.mercari.com/blog/entry/1599563768-081104c850/
|
|
||||||
|
|
||||||
# Looking for Sponsors
|
|
||||||
|
|
||||||
I'm looking for sponsors this library. This library is being developed as a personal project in my spare time. If you want a quick response or problem resolution when using this library in your project, please register as a [sponsor](https://github.com/sponsors/goccy). I will cooperate as much as possible. Of course, this library is developed as an MIT license, so you can use it freely for free.
|
|
||||||
|
|
||||||
# License
|
|
||||||
|
|
||||||
MIT
|
|
68
vendor/github.com/goccy/go-json/color.go
generated
vendored
68
vendor/github.com/goccy/go-json/color.go
generated
vendored
@ -1,68 +0,0 @@
|
|||||||
package json
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/encoder"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
ColorFormat = encoder.ColorFormat
|
|
||||||
ColorScheme = encoder.ColorScheme
|
|
||||||
)
|
|
||||||
|
|
||||||
const escape = "\x1b"
|
|
||||||
|
|
||||||
type colorAttr int
|
|
||||||
|
|
||||||
//nolint:deadcode,varcheck
|
|
||||||
const (
|
|
||||||
fgBlackColor colorAttr = iota + 30
|
|
||||||
fgRedColor
|
|
||||||
fgGreenColor
|
|
||||||
fgYellowColor
|
|
||||||
fgBlueColor
|
|
||||||
fgMagentaColor
|
|
||||||
fgCyanColor
|
|
||||||
fgWhiteColor
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint:deadcode,varcheck
|
|
||||||
const (
|
|
||||||
fgHiBlackColor colorAttr = iota + 90
|
|
||||||
fgHiRedColor
|
|
||||||
fgHiGreenColor
|
|
||||||
fgHiYellowColor
|
|
||||||
fgHiBlueColor
|
|
||||||
fgHiMagentaColor
|
|
||||||
fgHiCyanColor
|
|
||||||
fgHiWhiteColor
|
|
||||||
)
|
|
||||||
|
|
||||||
func createColorFormat(attr colorAttr) ColorFormat {
|
|
||||||
return ColorFormat{
|
|
||||||
Header: wrapColor(attr),
|
|
||||||
Footer: resetColor(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapColor(attr colorAttr) string {
|
|
||||||
return fmt.Sprintf("%s[%dm", escape, attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func resetColor() string {
|
|
||||||
return wrapColor(colorAttr(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultColorScheme = &ColorScheme{
|
|
||||||
Int: createColorFormat(fgHiMagentaColor),
|
|
||||||
Uint: createColorFormat(fgHiMagentaColor),
|
|
||||||
Float: createColorFormat(fgHiMagentaColor),
|
|
||||||
Bool: createColorFormat(fgHiYellowColor),
|
|
||||||
String: createColorFormat(fgHiGreenColor),
|
|
||||||
Binary: createColorFormat(fgHiRedColor),
|
|
||||||
ObjectKey: createColorFormat(fgHiCyanColor),
|
|
||||||
Null: createColorFormat(fgBlueColor),
|
|
||||||
}
|
|
||||||
)
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user