mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 07:57:21 +08:00
refactor: 移除 lego
This commit is contained in:
@@ -650,7 +650,7 @@ func (r *CertController) Renew(ctx http.Context) http.Response {
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Param data body requests.Obtain true "request"
|
||||
// @Success 200 {object} SuccessResponse{data=map[string]acme.Resolve}
|
||||
// @Success 200 {object} SuccessResponse{data=[]acme.DNSRecord}
|
||||
// @Router /panel/cert/manualDNS [post]
|
||||
func (r *CertController) ManualDNS(ctx http.Context) http.Response {
|
||||
var obtainRequest requests.Obtain
|
||||
|
||||
@@ -26,7 +26,6 @@ func (r *DNSStore) Rules(ctx http.Context) map[string]string {
|
||||
"data.token": "required_if:type,dnspod",
|
||||
"data.access_key": "required_if:type,aliyun",
|
||||
"data.secret_key": "required_if:type,aliyun",
|
||||
"data.email": "required_if:type,cloudflare",
|
||||
"data.api_key": "required_if:type,cloudflare",
|
||||
}
|
||||
}
|
||||
|
||||
14
docs/docs.go
14
docs/docs.go
@@ -535,9 +535,9 @@ const docTemplate = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/acme.Resolve"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/acme.DNSRecord"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3696,9 +3696,6 @@ const docTemplate = `{
|
||||
"api_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3710,12 +3707,9 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"acme.Resolve": {
|
||||
"acme.DNSRecord": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"err": {
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -528,9 +528,9 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/acme.Resolve"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/acme.DNSRecord"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3689,9 +3689,6 @@
|
||||
"api_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3703,12 +3700,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"acme.Resolve": {
|
||||
"acme.DNSRecord": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"err": {
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -6,8 +6,6 @@ definitions:
|
||||
type: string
|
||||
api_key:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
secret_key:
|
||||
@@ -15,10 +13,8 @@ definitions:
|
||||
token:
|
||||
type: string
|
||||
type: object
|
||||
acme.Resolve:
|
||||
acme.DNSRecord:
|
||||
properties:
|
||||
err:
|
||||
type: string
|
||||
key:
|
||||
type: string
|
||||
value:
|
||||
@@ -955,9 +951,9 @@ paths:
|
||||
- $ref: '#/definitions/controllers.SuccessResponse'
|
||||
- properties:
|
||||
data:
|
||||
additionalProperties:
|
||||
$ref: '#/definitions/acme.Resolve'
|
||||
type: object
|
||||
items:
|
||||
$ref: '#/definitions/acme.DNSRecord'
|
||||
type: array
|
||||
type: object
|
||||
security:
|
||||
- BearerToken: []
|
||||
|
||||
22
go.mod
22
go.mod
@@ -6,7 +6,6 @@ require (
|
||||
github.com/docker/docker v25.0.5+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/gertd/go-pluralize v0.2.1
|
||||
github.com/go-acme/lego/v4 v4.16.1
|
||||
github.com/gookit/color v1.5.4
|
||||
github.com/gookit/validate v1.5.2
|
||||
github.com/goravel/framework v1.13.1-0.20240215091018-1a9f352e523c
|
||||
@@ -14,6 +13,11 @@ require (
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/iancoleman/strcase v0.3.0
|
||||
github.com/imroc/req/v3 v3.43.1
|
||||
github.com/libdns/alidns v1.0.3
|
||||
github.com/libdns/cloudflare v0.1.1
|
||||
github.com/libdns/dnspod v0.0.3
|
||||
github.com/libdns/libdns v0.2.2
|
||||
github.com/mholt/acmez v1.2.0
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/mojocn/base64Captcha v1.3.6
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
@@ -21,6 +25,7 @@ require (
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/swaggo/http-swagger/v2 v2.0.2
|
||||
github.com/swaggo/swag v1.16.3
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.21.0
|
||||
)
|
||||
|
||||
@@ -41,7 +46,6 @@ require (
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect
|
||||
github.com/RichardKnop/machinery/v2 v2.0.12-0.20231012204029-bdb94a90ca41 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.49.6 // indirect
|
||||
github.com/bytedance/sonic v1.11.0 // indirect
|
||||
@@ -50,7 +54,6 @@ require (
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cloudflare/cloudflare-go v0.86.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
@@ -59,7 +62,6 @@ require (
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
@@ -67,7 +69,6 @@ require (
|
||||
github.com/gin-gonic/gin v1.9.1 // indirect
|
||||
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||
github.com/glebarez/sqlite v1.10.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
@@ -94,7 +95,6 @@ require (
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
@@ -106,13 +106,12 @@ require (
|
||||
github.com/goravel/file-rotatelogs/v2 v2.4.2 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
|
||||
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
@@ -128,7 +127,6 @@ require (
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.6.0 // indirect
|
||||
github.com/miekg/dns v1.1.58 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
@@ -209,7 +207,7 @@ require (
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect
|
||||
google.golang.org/grpc v1.61.1 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
61
go.sum
61
go.sum
@@ -47,7 +47,6 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
@@ -71,7 +70,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.22 h1:/GblQdIudfEM3AWWZ0mrYJQSd7JS4S/Mbzh6F0ov0Xc=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
|
||||
@@ -96,8 +94,6 @@ github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae h1:DcFpTQBYQ9C
|
||||
github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae/go.mod h1:rJJ84PyA/Wlmw1hO+xTzV2wsSUon6J5ktg0g8BF2PuU=
|
||||
github.com/RichardKnop/machinery/v2 v2.0.12-0.20231012204029-bdb94a90ca41 h1:7fLtRodG39Hn6AKqKE+ejO0Jj9B8O9RQOto13lkoDac=
|
||||
github.com/RichardKnop/machinery/v2 v2.0.12-0.20231012204029-bdb94a90ca41/go.mod h1:92dLVxckr2Lv7oKxoS3Uci0Of8Cuy+lmPi2dd6Euwkw=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 h1:J45/QHgrzUdqe/Vco/Vxk0wRvdS2nKUxmf/zLgvfass=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
@@ -106,6 +102,7 @@ github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/
|
||||
github.com/aws/aws-sdk-go v1.37.16/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.49.6 h1:yNldzF5kzLBRvKlKz1S0bkvc2+04R1kt13KfBWQBfFA=
|
||||
github.com/aws/aws-sdk-go v1.49.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4=
|
||||
@@ -143,8 +140,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cloudflare/cloudflare-go v0.86.0 h1:jEKN5VHNYNYtfDL2lUFLTRo+nOVNPFxpXTstVx0rqHI=
|
||||
github.com/cloudflare/cloudflare-go v0.86.0/go.mod h1:wYW/5UP02TUfBToa/yKbQHV+r6h1NnJ1Je7XjuGM4Jw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@@ -187,8 +182,6 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
@@ -210,13 +203,9 @@ github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec
|
||||
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
|
||||
github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc=
|
||||
github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA=
|
||||
github.com/go-acme/lego/v4 v4.16.1 h1:JxZ93s4KG0jL27rZ30UsIgxap6VGzKuREsSkkyzeoCQ=
|
||||
github.com/go-acme/lego/v4 v4.16.1/go.mod h1:AVvwdPned/IWpD/ihHhMsKnveF7HHYAz/CmtXi7OZoE=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
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 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
|
||||
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
@@ -291,7 +280,6 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
@@ -363,8 +351,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@@ -423,15 +409,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
||||
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@@ -448,10 +427,12 @@ github.com/imroc/req/v3 v3.43.1/go.mod h1:SQIz5iYop16MJxbo8ib+4LnostGCok8NQf8Toy
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
||||
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
|
||||
@@ -463,7 +444,6 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
@@ -471,7 +451,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
@@ -513,22 +492,30 @@ github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2t
|
||||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ=
|
||||
github.com/libdns/alidns v1.0.3/go.mod h1:e18uAG6GanfRhcJj6/tps2rCMzQJaYVcGKT+ELjdjGE=
|
||||
github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn054=
|
||||
github.com/libdns/cloudflare v0.1.1/go.mod h1:9VK91idpOjg6v7/WbjkEW49bSCxj00ALesIFDhJ8PBU=
|
||||
github.com/libdns/dnspod v0.0.3 h1:xJHDIujgLjvZnpB8/rMoCHUqA/KxSGBqRUXxSIzNzAA=
|
||||
github.com/libdns/dnspod v0.0.3/go.mod h1:XLnqMmK7QlLPEbHwcOxbRvlzRvDgaaUlthRNFOPjXPI=
|
||||
github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
|
||||
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
|
||||
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
|
||||
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
@@ -536,7 +523,6 @@ github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3
|
||||
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/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||
@@ -756,12 +742,16 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
@@ -1168,8 +1158,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -1177,7 +1167,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
|
||||
requests "panel/app/http/requests/cert"
|
||||
"panel/app/models"
|
||||
"panel/pkg/acme"
|
||||
@@ -21,8 +19,8 @@ type Cert interface {
|
||||
CertUpdate(request requests.CertUpdate) error
|
||||
CertShow(ID uint) (models.Cert, error)
|
||||
CertDestroy(ID uint) error
|
||||
ObtainAuto(ID uint) (certificate.Resource, error)
|
||||
ObtainManual(ID uint) (certificate.Resource, error)
|
||||
ManualDNS(ID uint) (map[string]acme.Resolve, error)
|
||||
Renew(ID uint) (certificate.Resource, error)
|
||||
ObtainAuto(ID uint) (acme.Certificate, error)
|
||||
ObtainManual(ID uint) (acme.Certificate, error)
|
||||
ManualDNS(ID uint) ([]acme.DNSRecord, error)
|
||||
Renew(ID uint) (acme.Certificate, error)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/goravel/framework/facades"
|
||||
|
||||
requests "panel/app/http/requests/cert"
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
)
|
||||
|
||||
type CertImpl struct {
|
||||
client *acme.Client
|
||||
}
|
||||
|
||||
func NewCertImpl() *CertImpl {
|
||||
@@ -34,15 +35,15 @@ func (s *CertImpl) UserStore(request requests.UserStore) error {
|
||||
var client *acme.Client
|
||||
switch user.CA {
|
||||
case "letsencrypt":
|
||||
client, err = acme.NewRegisterClient(user.Email, acme.CALetEncrypt, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CALetsEncrypt, nil, acme.KeyType(user.KeyType))
|
||||
case "buypass":
|
||||
client, err = acme.NewRegisterClient(user.Email, acme.CABuypass, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CABuypass, nil, acme.KeyType(user.KeyType))
|
||||
case "zerossl":
|
||||
client, err = acme.NewRegisterWithExternalAccountBindingClient(user.Email, *user.Kid, *user.HmacEncoded, acme.CAZeroSSL, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CAZeroSSL, &acme.EAB{KeyID: *user.Kid, MACKey: *user.HmacEncoded}, acme.KeyType(user.KeyType))
|
||||
case "sslcom":
|
||||
client, err = acme.NewRegisterWithExternalAccountBindingClient(user.Email, *user.Kid, *user.HmacEncoded, acme.CASSLcom, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CASSLcom, &acme.EAB{KeyID: *user.Kid, MACKey: *user.HmacEncoded}, acme.KeyType(user.KeyType))
|
||||
case "google":
|
||||
client, err = acme.NewRegisterWithExternalAccountBindingClient(user.Email, *user.Kid, *user.HmacEncoded, acme.CAGoogle, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CAGoogle, &acme.EAB{KeyID: *user.Kid, MACKey: *user.HmacEncoded}, acme.KeyType(user.KeyType))
|
||||
default:
|
||||
return errors.New("CA 提供商不支持")
|
||||
}
|
||||
@@ -51,7 +52,7 @@ func (s *CertImpl) UserStore(request requests.UserStore) error {
|
||||
return errors.New("向 CA 注册账号失败,请检查参数是否正确")
|
||||
}
|
||||
|
||||
privateKey, err := acme.GetPrivateKey(client.User.GetPrivateKey(), acme.KeyType(user.KeyType))
|
||||
privateKey, err := acme.EncodePrivateKey(client.Account.PrivateKey)
|
||||
if err != nil {
|
||||
return errors.New("获取私钥失败")
|
||||
}
|
||||
@@ -77,15 +78,15 @@ func (s *CertImpl) UserUpdate(request requests.UserUpdate) error {
|
||||
var client *acme.Client
|
||||
switch user.CA {
|
||||
case "letsencrypt":
|
||||
client, err = acme.NewRegisterClient(user.Email, acme.CALetEncrypt, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CALetsEncrypt, nil, acme.KeyType(user.KeyType))
|
||||
case "buypass":
|
||||
client, err = acme.NewRegisterClient(user.Email, acme.CABuypass, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CABuypass, nil, acme.KeyType(user.KeyType))
|
||||
case "zerossl":
|
||||
client, err = acme.NewRegisterWithExternalAccountBindingClient(user.Email, *user.Kid, *user.HmacEncoded, acme.CAZeroSSL, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CAZeroSSL, &acme.EAB{KeyID: *user.Kid, MACKey: *user.HmacEncoded}, acme.KeyType(user.KeyType))
|
||||
case "sslcom":
|
||||
client, err = acme.NewRegisterWithExternalAccountBindingClient(user.Email, *user.Kid, *user.HmacEncoded, acme.CASSLcom, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CASSLcom, &acme.EAB{KeyID: *user.Kid, MACKey: *user.HmacEncoded}, acme.KeyType(user.KeyType))
|
||||
case "google":
|
||||
client, err = acme.NewRegisterWithExternalAccountBindingClient(user.Email, *user.Kid, *user.HmacEncoded, acme.CAGoogle, certcrypto.KeyType(user.KeyType))
|
||||
client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CAGoogle, &acme.EAB{KeyID: *user.Kid, MACKey: *user.HmacEncoded}, acme.KeyType(user.KeyType))
|
||||
default:
|
||||
return errors.New("CA 提供商不支持")
|
||||
}
|
||||
@@ -94,7 +95,7 @@ func (s *CertImpl) UserUpdate(request requests.UserUpdate) error {
|
||||
return errors.New("向 CA 注册账号失败,请检查参数是否正确")
|
||||
}
|
||||
|
||||
privateKey, err := acme.GetPrivateKey(client.User.GetPrivateKey(), acme.KeyType(user.KeyType))
|
||||
privateKey, err := acme.EncodePrivateKey(client.Account.PrivateKey)
|
||||
if err != nil {
|
||||
return errors.New("获取私钥失败")
|
||||
}
|
||||
@@ -238,67 +239,50 @@ func (s *CertImpl) CertDestroy(ID uint) error {
|
||||
}
|
||||
|
||||
// ObtainAuto 自动签发证书
|
||||
func (s *CertImpl) ObtainAuto(ID uint) (certificate.Resource, error) {
|
||||
func (s *CertImpl) ObtainAuto(ID uint) (acme.Certificate, error) {
|
||||
var cert models.Cert
|
||||
err := facades.Orm().Query().With("Website").With("User").With("DNS").Where("id = ?", ID).First(&cert)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
var ca string
|
||||
switch cert.User.CA {
|
||||
case "letsencrypt":
|
||||
ca = acme.CALetEncrypt
|
||||
case "buypass":
|
||||
ca = acme.CABuypass
|
||||
case "zerossl":
|
||||
ca = acme.CAZeroSSL
|
||||
case "sslcom":
|
||||
ca = acme.CASSLcom
|
||||
case "google":
|
||||
ca = acme.CAGoogle
|
||||
}
|
||||
|
||||
client, err := acme.NewPrivateKeyClient(cert.User.Email, cert.User.PrivateKey, ca, certcrypto.KeyType(cert.User.KeyType))
|
||||
client, err := s.getClient(cert)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
if cert.DNS != nil {
|
||||
err = client.UseDns(acme.DnsType(cert.DNS.Type), cert.DNS.Data)
|
||||
client.UseDns(acme.DnsType(cert.DNS.Type), cert.DNS.Data)
|
||||
} else {
|
||||
if cert.Website == nil {
|
||||
return certificate.Resource{}, errors.New("该证书没有关联网站,无法自动签发")
|
||||
return acme.Certificate{}, errors.New("该证书没有关联网站,无法自动签发")
|
||||
} else {
|
||||
err = client.UseHTTP(cert.Website.Path)
|
||||
client.UseHTTP(cert.Website.Path)
|
||||
}
|
||||
}
|
||||
|
||||
ssl, err := client.ObtainSSL(context.Background(), cert.Domains, acme.KeyType(cert.Type))
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
ssl, err := client.ObtainSSL(cert.Domains)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
}
|
||||
|
||||
cert.CertURL = &ssl.CertURL
|
||||
cert.Cert = string(ssl.Certificate)
|
||||
cert.CertURL = &ssl.URL
|
||||
cert.Cert = string(ssl.ChainPEM)
|
||||
cert.Key = string(ssl.PrivateKey)
|
||||
err = facades.Orm().Query().Save(&cert)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
if cert.Website != nil {
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".pem", string(ssl.Certificate), 0644); err != nil {
|
||||
return certificate.Resource{}, err
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".pem", cert.Cert, 0644); err != nil {
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".key", string(ssl.PrivateKey), 0644); err != nil {
|
||||
return certificate.Resource{}, err
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".key", cert.Key, 0644); err != nil {
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
if _, err := tools.Exec("systemctl reload openresty"); err != nil {
|
||||
return certificate.Resource{}, err
|
||||
if err = tools.ServiceReload("openresty"); err != nil {
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,59 +290,39 @@ func (s *CertImpl) ObtainAuto(ID uint) (certificate.Resource, error) {
|
||||
}
|
||||
|
||||
// ObtainManual 手动签发证书
|
||||
func (s *CertImpl) ObtainManual(ID uint) (certificate.Resource, error) {
|
||||
func (s *CertImpl) ObtainManual(ID uint) (acme.Certificate, error) {
|
||||
var cert models.Cert
|
||||
err := facades.Orm().Query().With("User").Where("id = ?", ID).First(&cert)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
var ca string
|
||||
switch cert.User.CA {
|
||||
case "letsencrypt":
|
||||
ca = acme.CALetEncrypt
|
||||
case "buypass":
|
||||
ca = acme.CABuypass
|
||||
case "zerossl":
|
||||
ca = acme.CAZeroSSL
|
||||
case "sslcom":
|
||||
ca = acme.CASSLcom
|
||||
case "google":
|
||||
ca = acme.CAGoogle
|
||||
if s.client == nil {
|
||||
return acme.Certificate{}, errors.New("请重新获取 DNS 解析记录")
|
||||
}
|
||||
|
||||
client, err := acme.NewPrivateKeyClient(cert.User.Email, cert.User.PrivateKey, ca, certcrypto.KeyType(cert.User.KeyType))
|
||||
ssl, err := s.client.ObtainSSLManual()
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
err = client.UseManualDns()
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
}
|
||||
|
||||
ssl, err := client.ObtainSSL(cert.Domains)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
}
|
||||
|
||||
cert.CertURL = &ssl.CertURL
|
||||
cert.Cert = string(ssl.Certificate)
|
||||
cert.CertURL = &ssl.URL
|
||||
cert.Cert = string(ssl.ChainPEM)
|
||||
cert.Key = string(ssl.PrivateKey)
|
||||
err = facades.Orm().Query().Save(&cert)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
if cert.Website != nil {
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".pem", string(ssl.Certificate), 0644); err != nil {
|
||||
return certificate.Resource{}, err
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".pem", cert.Cert, 0644); err != nil {
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".key", string(ssl.PrivateKey), 0644); err != nil {
|
||||
return certificate.Resource{}, err
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".key", cert.Key, 0644); err != nil {
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
if _, err := tools.Exec("systemctl reload openresty"); err != nil {
|
||||
return certificate.Resource{}, err
|
||||
if err = tools.ServiceReload("openresty"); err != nil {
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,108 +330,106 @@ func (s *CertImpl) ObtainManual(ID uint) (certificate.Resource, error) {
|
||||
}
|
||||
|
||||
// ManualDNS 获取手动 DNS 解析信息
|
||||
func (s *CertImpl) ManualDNS(ID uint) (map[string]acme.Resolve, error) {
|
||||
func (s *CertImpl) ManualDNS(ID uint) ([]acme.DNSRecord, error) {
|
||||
var cert models.Cert
|
||||
err := facades.Orm().Query().With("User").Where("id = ?", ID).First(&cert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ca string
|
||||
switch cert.User.CA {
|
||||
case "letsencrypt":
|
||||
ca = acme.CALetEncrypt
|
||||
case "buypass":
|
||||
ca = acme.CABuypass
|
||||
case "zerossl":
|
||||
ca = acme.CAZeroSSL
|
||||
case "sslcom":
|
||||
ca = acme.CASSLcom
|
||||
case "google":
|
||||
ca = acme.CAGoogle
|
||||
}
|
||||
|
||||
client, err := acme.NewPrivateKeyClient(cert.User.Email, cert.User.PrivateKey, ca, certcrypto.KeyType(cert.User.KeyType))
|
||||
client, err := s.getClient(cert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = client.UseManualDns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.UseManualDns(len(cert.Domains))
|
||||
records, err := client.GetDNSRecords(context.Background(), cert.Domains, acme.KeyType(cert.Type))
|
||||
|
||||
return client.GetDNSResolve(cert.Domains)
|
||||
// 15 分钟后清理客户端
|
||||
s.client = client
|
||||
time.AfterFunc(15*time.Minute, func() {
|
||||
s.client = nil
|
||||
})
|
||||
|
||||
return records, err
|
||||
}
|
||||
|
||||
// Renew 续签证书
|
||||
func (s *CertImpl) Renew(ID uint) (certificate.Resource, error) {
|
||||
func (s *CertImpl) Renew(ID uint) (acme.Certificate, error) {
|
||||
var cert models.Cert
|
||||
err := facades.Orm().Query().With("Website").With("User").With("DNS").Where("id = ?", ID).First(&cert)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
var ca string
|
||||
switch cert.User.CA {
|
||||
case "letsencrypt":
|
||||
ca = acme.CALetEncrypt
|
||||
case "buypass":
|
||||
ca = acme.CABuypass
|
||||
case "zerossl":
|
||||
ca = acme.CAZeroSSL
|
||||
case "sslcom":
|
||||
ca = acme.CASSLcom
|
||||
case "google":
|
||||
ca = acme.CAGoogle
|
||||
}
|
||||
|
||||
client, err := acme.NewPrivateKeyClient(cert.User.Email, cert.User.PrivateKey, ca, certcrypto.KeyType(cert.User.KeyType))
|
||||
client, err := s.getClient(cert)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
if cert.CertURL == nil {
|
||||
return certificate.Resource{}, errors.New("该证书没有签发成功,无法续签")
|
||||
return acme.Certificate{}, errors.New("该证书没有签发成功,无法续签")
|
||||
}
|
||||
|
||||
if cert.DNS != nil {
|
||||
err = client.UseDns(acme.DnsType(cert.DNS.Type), cert.DNS.Data)
|
||||
client.UseDns(acme.DnsType(cert.DNS.Type), cert.DNS.Data)
|
||||
} else {
|
||||
if cert.Website == nil {
|
||||
return certificate.Resource{}, errors.New("该证书没有关联网站,无法续签,可以尝试手动签发")
|
||||
return acme.Certificate{}, errors.New("该证书没有关联网站,无法续签,可以尝试手动签发")
|
||||
} else {
|
||||
err = client.UseHTTP(cert.Website.Path)
|
||||
client.UseHTTP(cert.Website.Path)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
ssl, err := client.RenewSSL(*cert.CertURL)
|
||||
ssl, err := client.RenewSSL(context.Background(), *cert.CertURL, cert.Domains, acme.KeyType(cert.Type))
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
cert.CertURL = &ssl.CertURL
|
||||
cert.Cert = string(ssl.Certificate)
|
||||
cert.CertURL = &ssl.URL
|
||||
cert.Cert = string(ssl.ChainPEM)
|
||||
cert.Key = string(ssl.PrivateKey)
|
||||
err = facades.Orm().Query().Save(&cert)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
|
||||
if cert.Website != nil {
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".pem", string(ssl.Certificate), 0644); err != nil {
|
||||
return certificate.Resource{}, err
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".pem", cert.Cert, 0644); err != nil {
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".key", string(ssl.PrivateKey), 0644); err != nil {
|
||||
return certificate.Resource{}, err
|
||||
if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".key", cert.Key, 0644); err != nil {
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
if _, err := tools.Exec("systemctl reload openresty"); err != nil {
|
||||
return certificate.Resource{}, err
|
||||
if err = tools.ServiceReload("openresty"); err != nil {
|
||||
return acme.Certificate{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return ssl, nil
|
||||
}
|
||||
|
||||
func (s *CertImpl) getClient(cert models.Cert) (*acme.Client, error) {
|
||||
var ca string
|
||||
var eab *acme.EAB
|
||||
switch cert.User.CA {
|
||||
case "letsencrypt":
|
||||
ca = acme.CALetsEncrypt
|
||||
case "buypass":
|
||||
ca = acme.CABuypass
|
||||
case "zerossl":
|
||||
ca = acme.CAZeroSSL
|
||||
eab = &acme.EAB{KeyID: *cert.User.Kid, MACKey: *cert.User.HmacEncoded}
|
||||
case "sslcom":
|
||||
ca = acme.CASSLcom
|
||||
eab = &acme.EAB{KeyID: *cert.User.Kid, MACKey: *cert.User.HmacEncoded}
|
||||
case "google":
|
||||
ca = acme.CAGoogle
|
||||
eab = &acme.EAB{KeyID: *cert.User.Kid, MACKey: *cert.User.HmacEncoded}
|
||||
}
|
||||
|
||||
return acme.NewPrivateKeyAccount(cert.User.Email, cert.User.PrivateKey, ca, eab)
|
||||
}
|
||||
|
||||
292
pkg/acme/acme.go
292
pkg/acme/acme.go
@@ -1,177 +1,195 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
"github.com/mholt/acmez"
|
||||
"github.com/mholt/acmez/acme"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
CALetEncrypt = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
CAZeroSSL = "https://acme.zerossl.com/v2/DV90"
|
||||
CAGoogle = "https://dv.acme-v02.api.pki.goog/directory"
|
||||
CABuypass = "https://api.buypass.com/acme/directory"
|
||||
CASSLcom = "https://acme.ssl.com/sslcom-dv-rsa"
|
||||
CALetsEncryptStaging = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
CALetsEncrypt = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
CAZeroSSL = "https://acme.zerossl.com/v2/DV90"
|
||||
CAGoogle = "https://dv.acme-v02.api.pki.goog/directory"
|
||||
CABuypass = "https://api.buypass.com/acme/directory"
|
||||
CASSLcom = "https://acme.ssl.com/sslcom-dv-rsa"
|
||||
)
|
||||
|
||||
type KeyType = certcrypto.KeyType
|
||||
type KeyType string
|
||||
|
||||
const (
|
||||
KeyEC256 = certcrypto.EC256
|
||||
KeyEC384 = certcrypto.EC384
|
||||
KeyRSA2048 = certcrypto.RSA2048
|
||||
KeyRSA3072 = certcrypto.RSA3072
|
||||
KeyRSA4096 = certcrypto.RSA4096
|
||||
KeyEC256 = KeyType("P256")
|
||||
KeyEC384 = KeyType("P384")
|
||||
KeyRSA2048 = KeyType("2048")
|
||||
KeyRSA3072 = KeyType("3072")
|
||||
KeyRSA4096 = KeyType("4096")
|
||||
)
|
||||
|
||||
type domainError struct {
|
||||
Domain string
|
||||
Error error
|
||||
}
|
||||
type EAB = acme.EAB
|
||||
|
||||
type User struct {
|
||||
Email string
|
||||
Registration *registration.Resource
|
||||
Key crypto.PrivateKey
|
||||
}
|
||||
func NewRegisterAccount(ctx context.Context, email, CA string, eab *EAB, keyType KeyType) (*Client, error) {
|
||||
client, err := getClient(CA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (u *User) GetEmail() string {
|
||||
return u.Email
|
||||
}
|
||||
|
||||
func (u *User) GetRegistration() *registration.Resource {
|
||||
return u.Registration
|
||||
}
|
||||
func (u *User) GetPrivateKey() crypto.PrivateKey {
|
||||
return u.Key
|
||||
}
|
||||
|
||||
func GetPrivateKey(priKey crypto.PrivateKey, keyType KeyType) ([]byte, error) {
|
||||
var marshal []byte
|
||||
var block *pem.Block
|
||||
var err error
|
||||
|
||||
switch keyType {
|
||||
case KeyEC256, KeyEC384:
|
||||
key := priKey.(*ecdsa.PrivateKey)
|
||||
marshal, err = x509.MarshalECPrivateKey(key)
|
||||
accountPrivateKey, err := generatePrivateKey(keyType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account := acme.Account{
|
||||
Contact: []string{"mailto:" + email},
|
||||
TermsOfServiceAgreed: true,
|
||||
PrivateKey: accountPrivateKey,
|
||||
}
|
||||
if eab != nil {
|
||||
err = account.SetExternalAccountBinding(ctx, client.Client, *eab)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block = &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: marshal,
|
||||
}
|
||||
case KeyRSA2048, KeyRSA3072, KeyRSA4096:
|
||||
key := priKey.(*rsa.PrivateKey)
|
||||
marshal = x509.MarshalPKCS1PrivateKey(key)
|
||||
block = &pem.Block{
|
||||
Type: "privateKey",
|
||||
Bytes: marshal,
|
||||
}
|
||||
|
||||
account, err = client.NewAccount(ctx, account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{Account: account, zClient: client}, nil
|
||||
}
|
||||
|
||||
func NewPrivateKeyAccount(email string, privateKey string, CA string, eab *EAB) (*Client, error) {
|
||||
client, err := getClient(CA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := parsePrivateKey([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
account := acme.Account{
|
||||
Contact: []string{"mailto:" + email},
|
||||
TermsOfServiceAgreed: true,
|
||||
PrivateKey: key,
|
||||
}
|
||||
if eab != nil {
|
||||
err = account.SetExternalAccountBinding(context.Background(), client.Client, *eab)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return pem.EncodeToMemory(block), nil
|
||||
account, err = client.GetAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{Account: account, zClient: client}, nil
|
||||
}
|
||||
|
||||
func NewRegisterClient(email string, CA string, keyType certcrypto.KeyType) (*Client, error) {
|
||||
privateKey, err := certcrypto.GeneratePrivateKey(keyType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func parsePrivateKey(key []byte) (crypto.Signer, error) {
|
||||
keyBlockDER, _ := pem.Decode(key)
|
||||
if keyBlockDER == nil {
|
||||
return nil, errors.New("invalid PEM block")
|
||||
}
|
||||
|
||||
user := &User{
|
||||
Email: email,
|
||||
Key: privateKey,
|
||||
}
|
||||
config := lego.NewConfig(user)
|
||||
config.CADirURL = CA
|
||||
config.Certificate.KeyType = keyType
|
||||
client, err := lego.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Registration = reg
|
||||
|
||||
acmeClient := &Client{
|
||||
User: user,
|
||||
Client: client,
|
||||
Config: config,
|
||||
if keyBlockDER.Type != "PRIVATE KEY" && !strings.HasSuffix(keyBlockDER.Type, " PRIVATE KEY") {
|
||||
return nil, fmt.Errorf("unknown PEM header %q", keyBlockDER.Type)
|
||||
}
|
||||
|
||||
return acmeClient, nil
|
||||
if parse, err := x509.ParsePKCS1PrivateKey(keyBlockDER.Bytes); err == nil {
|
||||
return parse, nil
|
||||
}
|
||||
|
||||
if parse, err := x509.ParsePKCS8PrivateKey(keyBlockDER.Bytes); err == nil {
|
||||
switch parse.(type) {
|
||||
case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
|
||||
return parse.(crypto.Signer), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("found unknown private key type in PKCS#8 wrapping: %T", key)
|
||||
}
|
||||
}
|
||||
|
||||
if parse, err := x509.ParseECPrivateKey(keyBlockDER.Bytes); err == nil {
|
||||
return parse, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("解析私钥失败")
|
||||
}
|
||||
|
||||
func NewRegisterWithExternalAccountBindingClient(email, kid, hmac, CA string, keyType certcrypto.KeyType) (*Client, error) {
|
||||
privateKey, err := certcrypto.GeneratePrivateKey(keyType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func generatePrivateKey(keyType KeyType) (crypto.Signer, error) {
|
||||
switch keyType {
|
||||
case KeyEC256:
|
||||
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
case KeyEC384:
|
||||
return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
case KeyRSA2048:
|
||||
return rsa.GenerateKey(rand.Reader, 2048)
|
||||
case KeyRSA3072:
|
||||
return rsa.GenerateKey(rand.Reader, 3072)
|
||||
case KeyRSA4096:
|
||||
return rsa.GenerateKey(rand.Reader, 4096)
|
||||
}
|
||||
|
||||
user := &User{
|
||||
Email: email,
|
||||
Key: privateKey,
|
||||
}
|
||||
config := lego.NewConfig(user)
|
||||
config.CADirURL = CA
|
||||
config.Certificate.KeyType = keyType
|
||||
client, err := lego.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reg, err := client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{TermsOfServiceAgreed: true, Kid: kid, HmacEncoded: hmac})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Registration = reg
|
||||
|
||||
acmeClient := &Client{
|
||||
User: user,
|
||||
Client: client,
|
||||
Config: config,
|
||||
}
|
||||
|
||||
return acmeClient, nil
|
||||
return nil, errors.New("未知的密钥类型")
|
||||
}
|
||||
|
||||
func NewPrivateKeyClient(email string, privateKey string, CA string, keyType certcrypto.KeyType) (*Client, error) {
|
||||
key, err := certcrypto.ParsePEMPrivateKey([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func EncodePrivateKey(key crypto.Signer) ([]byte, error) {
|
||||
var pemType string
|
||||
var keyBytes []byte
|
||||
switch key := key.(type) {
|
||||
case *ecdsa.PrivateKey:
|
||||
var err error
|
||||
pemType = "EC"
|
||||
keyBytes, err = x509.MarshalECPrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case *rsa.PrivateKey:
|
||||
pemType = "RSA"
|
||||
keyBytes = x509.MarshalPKCS1PrivateKey(key)
|
||||
case ed25519.PrivateKey:
|
||||
var err error
|
||||
pemType = "ED25519"
|
||||
keyBytes, err = x509.MarshalPKCS8PrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("未知的密钥类型 %T", key)
|
||||
}
|
||||
|
||||
user := &User{
|
||||
Email: email,
|
||||
Key: key,
|
||||
}
|
||||
config := lego.NewConfig(user)
|
||||
config.CADirURL = CA
|
||||
config.Certificate.KeyType = keyType
|
||||
client, err := lego.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reg, err := client.Registration.ResolveAccountByKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Registration = reg
|
||||
|
||||
acmeClient := &Client{
|
||||
User: user,
|
||||
Client: client,
|
||||
Config: config,
|
||||
}
|
||||
|
||||
return acmeClient, nil
|
||||
pemKey := pem.Block{Type: pemType + " PRIVATE KEY", Bytes: keyBytes}
|
||||
return pem.EncodeToMemory(&pemKey), nil
|
||||
}
|
||||
|
||||
func getClient(CA string) (acmez.Client, error) {
|
||||
logger, err := zap.NewProduction()
|
||||
if err != nil {
|
||||
return acmez.Client{}, err
|
||||
}
|
||||
|
||||
client := acmez.Client{
|
||||
Client: &acme.Client{
|
||||
Directory: CA,
|
||||
HTTPClient: http.DefaultClient,
|
||||
Logger: logger,
|
||||
},
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
@@ -1,192 +1,139 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"time"
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"github.com/go-acme/lego/v4/acme"
|
||||
"github.com/go-acme/lego/v4/acme/api"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
"github.com/go-acme/lego/v4/providers/dns/alidns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
|
||||
"github.com/go-acme/lego/v4/providers/dns/dnspod"
|
||||
"github.com/go-acme/lego/v4/providers/http/webroot"
|
||||
"github.com/libdns/libdns"
|
||||
"github.com/mholt/acmez"
|
||||
"github.com/mholt/acmez/acme"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
Config *lego.Config
|
||||
Client *lego.Client
|
||||
User *User
|
||||
type Certificate struct {
|
||||
PrivateKey []byte
|
||||
acme.Certificate
|
||||
}
|
||||
|
||||
type DnsType string
|
||||
|
||||
const (
|
||||
DnsPod DnsType = "dnspod"
|
||||
AliYun DnsType = "aliyun"
|
||||
CloudFlare DnsType = "cloudflare"
|
||||
)
|
||||
|
||||
type DNSParam struct {
|
||||
ID string `form:"id" json:"id"`
|
||||
Token string `form:"token" json:"token"`
|
||||
AccessKey string `form:"access_key" json:"access_key"`
|
||||
SecretKey string `form:"secret_key" json:"secret_key"`
|
||||
Email string `form:"email" json:"email"`
|
||||
APIkey string `form:"api_key" json:"api_key"`
|
||||
type Client struct {
|
||||
Account acme.Account
|
||||
zClient acmez.Client
|
||||
// 手动 DNS 所需的信号通道
|
||||
manualDNSSolver
|
||||
}
|
||||
|
||||
// UseDns 使用 DNS 接口验证
|
||||
func (c *Client) UseDns(dnsType DnsType, param DNSParam) error {
|
||||
var p challenge.Provider
|
||||
var err error
|
||||
if dnsType == DnsPod {
|
||||
dnsPodConfig := dnspod.NewDefaultConfig()
|
||||
dnsPodConfig.LoginToken = param.ID + "," + param.Token
|
||||
p, err = dnspod.NewDNSProviderConfig(dnsPodConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (c *Client) UseDns(dnsType DnsType, param DNSParam) {
|
||||
c.zClient.ChallengeSolvers = map[string]acmez.Solver{
|
||||
acme.ChallengeTypeDNS01: dnsSolver{
|
||||
dns: dnsType,
|
||||
param: param,
|
||||
records: &[]libdns.Record{},
|
||||
},
|
||||
}
|
||||
if dnsType == AliYun {
|
||||
aliyunConfig := alidns.NewDefaultConfig()
|
||||
aliyunConfig.SecretKey = param.SecretKey
|
||||
aliyunConfig.APIKey = param.AccessKey
|
||||
p, err = alidns.NewDNSProviderConfig(aliyunConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if dnsType == CloudFlare {
|
||||
cloudflareConfig := cloudflare.NewDefaultConfig()
|
||||
cloudflareConfig.AuthEmail = param.Email
|
||||
cloudflareConfig.AuthToken = param.APIkey
|
||||
p, err = cloudflare.NewDNSProviderConfig(cloudflareConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(3*time.Minute))
|
||||
}
|
||||
|
||||
// UseManualDns 使用手动 DNS 验证
|
||||
func (c *Client) UseManualDns(checkDns ...bool) error {
|
||||
p := &manualDnsProvider{}
|
||||
var err error
|
||||
|
||||
if len(checkDns) > 0 && !checkDns[0] {
|
||||
err = c.Client.Challenge.SetDNS01Provider(p, dns01.DisableCompletePropagationRequirement())
|
||||
} else {
|
||||
err = c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(3*time.Minute))
|
||||
func (c *Client) UseManualDns(total int, check ...bool) {
|
||||
c.controlChan = make(chan struct{})
|
||||
c.dataChan = make(chan any)
|
||||
c.zClient.ChallengeSolvers = map[string]acmez.Solver{
|
||||
acme.ChallengeTypeDNS01: manualDNSSolver{
|
||||
check: len(check) > 0 && check[0],
|
||||
controlChan: c.controlChan,
|
||||
dataChan: c.dataChan,
|
||||
records: &[]DNSRecord{},
|
||||
},
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// UseHTTP 使用 HTTP 验证
|
||||
func (c *Client) UseHTTP(path string) error {
|
||||
httpProvider, err := webroot.NewHTTPProvider(path)
|
||||
if err != nil {
|
||||
return err
|
||||
func (c *Client) UseHTTP(path string) {
|
||||
c.zClient.ChallengeSolvers = map[string]acmez.Solver{
|
||||
acme.ChallengeTypeHTTP01: httpSolver{
|
||||
path: path,
|
||||
},
|
||||
}
|
||||
|
||||
err = c.Client.Challenge.SetHTTP01Provider(httpProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ObtainSSL 签发 SSL 证书
|
||||
func (c *Client) ObtainSSL(domains []string) (certificate.Resource, error) {
|
||||
request := certificate.ObtainRequest{
|
||||
Domains: domains,
|
||||
Bundle: true,
|
||||
MustStaple: false,
|
||||
}
|
||||
|
||||
certificates, err := c.Client.Certificate.Obtain(request)
|
||||
func (c *Client) ObtainSSL(ctx context.Context, domains []string, keyType KeyType) (Certificate, error) {
|
||||
certPrivateKey, err := generatePrivateKey(keyType)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return Certificate{}, err
|
||||
}
|
||||
pemPrivateKey, err := EncodePrivateKey(certPrivateKey)
|
||||
if err != nil {
|
||||
return Certificate{}, err
|
||||
}
|
||||
|
||||
return *certificates, nil
|
||||
certs, err := c.zClient.ObtainCertificate(ctx, c.Account, certPrivateKey, domains)
|
||||
if err != nil {
|
||||
return Certificate{}, err
|
||||
}
|
||||
|
||||
cert := c.selectPreferredChain(certs)
|
||||
return Certificate{PrivateKey: pemPrivateKey, Certificate: cert}, nil
|
||||
}
|
||||
|
||||
// ObtainSSLManual 手动验证 SSL 证书
|
||||
func (c *Client) ObtainSSLManual() (Certificate, error) {
|
||||
// 发送信号,开始验证
|
||||
c.controlChan <- struct{}{}
|
||||
// 等待验证完成
|
||||
data := <-c.dataChan
|
||||
|
||||
if err, ok := data.(error); ok {
|
||||
return Certificate{}, err
|
||||
}
|
||||
|
||||
return data.(Certificate), nil
|
||||
}
|
||||
|
||||
// RenewSSL 续签 SSL 证书
|
||||
func (c *Client) RenewSSL(certUrl string) (certificate.Resource, error) {
|
||||
certificates, err := c.Client.Certificate.Get(certUrl, true)
|
||||
func (c *Client) RenewSSL(ctx context.Context, certUrl string, domains []string, keyType KeyType) (Certificate, error) {
|
||||
_, err := c.zClient.GetCertificateChain(ctx, c.Account, certUrl)
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
return Certificate{}, err
|
||||
}
|
||||
|
||||
certificates, err = c.Client.Certificate.RenewWithOptions(*certificates, &certificate.RenewOptions{
|
||||
Bundle: true,
|
||||
MustStaple: false,
|
||||
return c.ObtainSSL(ctx, domains, keyType)
|
||||
}
|
||||
|
||||
// GetDNSRecords 获取 DNS 解析(手动设置)
|
||||
func (c *Client) GetDNSRecords(ctx context.Context, domains []string, keyType KeyType) ([]DNSRecord, error) {
|
||||
go func(ctx context.Context, domains []string, keyType KeyType) {
|
||||
certs, err := c.ObtainSSL(ctx, domains, keyType)
|
||||
// 将证书和错误信息发送到 dataChan
|
||||
if err != nil {
|
||||
c.dataChan <- err
|
||||
return
|
||||
}
|
||||
c.dataChan <- certs
|
||||
}(ctx, domains, keyType)
|
||||
|
||||
// 这里要少一次循环,因为需要卡住最后一次的 dataChan,等待手动 DNS 验证完成
|
||||
for i := 1; i < len(domains); i++ {
|
||||
<-c.dataChan
|
||||
c.controlChan <- struct{}{}
|
||||
}
|
||||
|
||||
// 因为上面少了一次循环,所以这里接收到的即为完整的 DNS 记录切片
|
||||
data := <-c.dataChan
|
||||
if err, ok := data.(error); ok {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data.([]DNSRecord), nil
|
||||
}
|
||||
|
||||
func (c *Client) selectPreferredChain(certChains []acme.Certificate) acme.Certificate {
|
||||
if len(certChains) == 1 {
|
||||
return certChains[0]
|
||||
}
|
||||
|
||||
sort.Slice(certChains, func(i, j int) bool {
|
||||
return len(certChains[i].ChainPEM) < len(certChains[j].ChainPEM)
|
||||
})
|
||||
if err != nil {
|
||||
return certificate.Resource{}, err
|
||||
}
|
||||
|
||||
return *certificates, nil
|
||||
}
|
||||
|
||||
// GetDNSResolve 获取 DNS 解析(手动设置)
|
||||
func (c *Client) GetDNSResolve(domains []string) (map[string]Resolve, error) {
|
||||
core, err := api.New(c.Config.HTTPClient, c.Config.UserAgent, c.Config.CADirURL, c.User.Registration.URI, c.User.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
order, err := core.Orders.New(domains)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resolves := make(map[string]Resolve)
|
||||
resChan, errChan := make(chan acme.Authorization), make(chan domainError)
|
||||
for _, authzURL := range order.Authorizations {
|
||||
go func(authzURL string) {
|
||||
authz, err := core.Authorizations.Get(authzURL)
|
||||
if err != nil {
|
||||
errChan <- domainError{Domain: authz.Identifier.Value, Error: err}
|
||||
return
|
||||
}
|
||||
resChan <- authz
|
||||
}(authzURL)
|
||||
}
|
||||
|
||||
var responses []acme.Authorization
|
||||
for i := 0; i < len(order.Authorizations); i++ {
|
||||
select {
|
||||
case res := <-resChan:
|
||||
responses = append(responses, res)
|
||||
case err := <-errChan:
|
||||
resolves[err.Domain] = Resolve{Err: err.Error.Error()}
|
||||
}
|
||||
}
|
||||
close(resChan)
|
||||
close(errChan)
|
||||
|
||||
for _, auth := range responses {
|
||||
domain := challenge.GetTargetedDomain(auth)
|
||||
acmeChallenge, err := challenge.FindChallenge(challenge.DNS01, auth)
|
||||
if err != nil {
|
||||
resolves[domain] = Resolve{Err: err.Error()}
|
||||
continue
|
||||
}
|
||||
keyAuth, err := core.GetKeyAuthorization(acmeChallenge.Token)
|
||||
if err != nil {
|
||||
resolves[domain] = Resolve{Err: err.Error()}
|
||||
continue
|
||||
}
|
||||
challengeInfo := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
resolves[domain] = Resolve{
|
||||
Key: challengeInfo.FQDN,
|
||||
Value: challengeInfo.Value,
|
||||
}
|
||||
}
|
||||
|
||||
return resolves, nil
|
||||
return certChains[0]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
@@ -16,24 +16,26 @@ func TestClientTestSuite(t *testing.T) {
|
||||
}
|
||||
|
||||
func (s *ClientTestSuite) TestObtainSSL() {
|
||||
client, err := NewRegisterClient("ci@haozi.net", "https://acme-staging-v02.api.letsencrypt.org/directory", KeyEC256)
|
||||
ctx := context.Background()
|
||||
client, err := NewRegisterAccount(ctx, "ci@haozi.net", CALetsEncryptStaging, nil, KeyEC256)
|
||||
s.Nil(err)
|
||||
|
||||
err = client.UseDns(DnsPod, DNSParam{
|
||||
ID: "xxx",
|
||||
Token: "xxx",
|
||||
client.UseDns(DnsPod, DNSParam{
|
||||
ID: "123456",
|
||||
Token: "654321",
|
||||
})
|
||||
s.Nil(err)
|
||||
|
||||
err = client.UseManualDns(false)
|
||||
s.Nil(err)
|
||||
/*client.UseManualDns(2)
|
||||
|
||||
resolves, err := client.GetDNSResolve([]string{"haozi.dev"})
|
||||
resolves, err := client.GetDNSRecords(ctx, []string{"*.haozi.net", "haozi.net"}, KeyEC256)
|
||||
debug.Dump(resolves)
|
||||
s.Nil(err)
|
||||
s.NotNil(resolves)
|
||||
|
||||
ssl, err := client.ObtainSSL([]string{"haozi.dev"})
|
||||
fmt.Println(err.Error())
|
||||
time.Sleep(2 * time.Minute)
|
||||
|
||||
ssl, err := client.ObtainSSLManual()*/
|
||||
ssl, err := client.ObtainSSL(ctx, []string{"*.haozi.net", "haozi.net"}, KeyEC256)
|
||||
s.Error(err)
|
||||
s.NotNil(ssl)
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package acme
|
||||
|
||||
type Resolve struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
Err string `json:"err"`
|
||||
}
|
||||
|
||||
type manualDnsProvider struct {
|
||||
Resolve *Resolve
|
||||
}
|
||||
|
||||
func (p *manualDnsProvider) Present(domain, token, keyAuth string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *manualDnsProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
return nil
|
||||
}
|
||||
189
pkg/acme/solvers.go
Normal file
189
pkg/acme/solvers.go
Normal file
@@ -0,0 +1,189 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/libdns/alidns"
|
||||
"github.com/libdns/cloudflare"
|
||||
"github.com/libdns/dnspod"
|
||||
"github.com/libdns/libdns"
|
||||
"github.com/mholt/acmez/acme"
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
type httpSolver struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func (s httpSolver) Present(ctx context.Context, challenge acme.Challenge) error {
|
||||
var err error
|
||||
if s.path == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
challengeFilePath := filepath.Join(s.path, challenge.HTTP01ResourcePath())
|
||||
err = os.MkdirAll(filepath.Dir(challengeFilePath), 0o755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法在网站目录创建 HTTP 挑战所需的目录: %w", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile(challengeFilePath, []byte(challenge.KeyAuthorization), 0o644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法在网站目录创建 HTTP 挑战所需的文件: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanUp cleans up the HTTP server if it is the last one to finish.
|
||||
func (s httpSolver) CleanUp(_ context.Context, challenge acme.Challenge) error {
|
||||
if s.path == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := os.Remove(filepath.Join(s.path, challenge.HTTP01ResourcePath()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法删除 HTTP 挑战文件: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type dnsSolver struct {
|
||||
dns DnsType
|
||||
param DNSParam
|
||||
records *[]libdns.Record
|
||||
}
|
||||
|
||||
func (s dnsSolver) Present(ctx context.Context, challenge acme.Challenge) error {
|
||||
dnsName := challenge.DNS01TXTRecordName()
|
||||
keyAuth := challenge.DNS01KeyAuthorization()
|
||||
provider, err := s.getDNSProvider()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取 DNS 提供商失败: %w", err)
|
||||
}
|
||||
zone, err := publicsuffix.EffectiveTLDPlusOne(dnsName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取域名 %q 的顶级域失败: %w", dnsName, err)
|
||||
}
|
||||
|
||||
rec := libdns.Record{
|
||||
Type: "TXT",
|
||||
Name: libdns.RelativeName(dnsName+".", zone+"."),
|
||||
Value: keyAuth,
|
||||
}
|
||||
|
||||
results, err := provider.AppendRecords(ctx, zone+".", []libdns.Record{rec})
|
||||
if err != nil {
|
||||
return fmt.Errorf("域名 %q 添加临时记录 %q 失败: %w", zone, dnsName, err)
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return fmt.Errorf("预期添加 1 条记录,但实际添加了 %d 条记录", len(results))
|
||||
}
|
||||
|
||||
s.records = &results
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s dnsSolver) CleanUp(ctx context.Context, challenge acme.Challenge) error {
|
||||
dnsName := challenge.DNS01TXTRecordName()
|
||||
provider, err := s.getDNSProvider()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取 DNS 提供商失败: %w", err)
|
||||
}
|
||||
zone, err := publicsuffix.EffectiveTLDPlusOne(dnsName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取域名 %q 的顶级域失败: %w", dnsName, err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
_, err = provider.DeleteRecords(ctx, zone+".", *s.records)
|
||||
if err != nil {
|
||||
return fmt.Errorf("域名 %q 删除临时记录 %q 失败: %w", zone, dnsName, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s dnsSolver) getDNSProvider() (DNSProvider, error) {
|
||||
var dns DNSProvider
|
||||
|
||||
switch s.dns {
|
||||
case DnsPod:
|
||||
dns = &dnspod.Provider{
|
||||
APIToken: s.param.ID + "," + s.param.Token,
|
||||
}
|
||||
case AliYun:
|
||||
dns = &alidns.Provider{
|
||||
AccKeyID: s.param.AccessKey,
|
||||
AccKeySecret: s.param.SecretKey,
|
||||
}
|
||||
case CloudFlare:
|
||||
dns = &cloudflare.Provider{
|
||||
APIToken: s.param.APIkey,
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("未知的 DNS 提供商 %q", s.dns)
|
||||
}
|
||||
|
||||
return dns, nil
|
||||
}
|
||||
|
||||
type DnsType string
|
||||
|
||||
const (
|
||||
DnsPod DnsType = "dnspod"
|
||||
AliYun DnsType = "aliyun"
|
||||
CloudFlare DnsType = "cloudflare"
|
||||
)
|
||||
|
||||
type DNSParam struct {
|
||||
ID string `form:"id" json:"id"`
|
||||
Token string `form:"token" json:"token"`
|
||||
AccessKey string `form:"access_key" json:"access_key"`
|
||||
SecretKey string `form:"secret_key" json:"secret_key"`
|
||||
APIkey string `form:"api_key" json:"api_key"`
|
||||
}
|
||||
|
||||
type DNSProvider interface {
|
||||
libdns.RecordAppender
|
||||
libdns.RecordDeleter
|
||||
}
|
||||
|
||||
type manualDNSSolver struct {
|
||||
check bool
|
||||
controlChan chan struct{}
|
||||
dataChan chan any
|
||||
records *[]DNSRecord
|
||||
}
|
||||
|
||||
func (s manualDNSSolver) Present(ctx context.Context, challenge acme.Challenge) error {
|
||||
dnsName := challenge.DNS01TXTRecordName()
|
||||
keyAuth := challenge.DNS01KeyAuthorization()
|
||||
|
||||
// 追加记录到 records 中
|
||||
*s.records = append(*s.records, DNSRecord{
|
||||
Key: dnsName,
|
||||
Value: keyAuth,
|
||||
})
|
||||
s.dataChan <- *s.records
|
||||
|
||||
// 等待信号以继续
|
||||
<-s.controlChan
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s manualDNSSolver) CleanUp(ctx context.Context, challenge acme.Challenge) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type DNSRecord struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
Reference in New Issue
Block a user