mirror of
https://github.com/yusing/godoxy.git
synced 2026-01-16 08:26:49 +01:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b69589586 | ||
|
|
bca3cd84d1 | ||
|
|
ce4bf2f646 | ||
|
|
c49016f22c | ||
|
|
8da63daf02 | ||
|
|
c5fd21552e | ||
|
|
27409abc24 | ||
|
|
21c9e46274 | ||
|
|
22a12d3116 | ||
|
|
89d93dd878 | ||
|
|
66853dfc52 | ||
|
|
c72f66d64b | ||
|
|
59bc342a40 | ||
|
|
e11579df10 | ||
|
|
6a8f6fb4b5 | ||
|
|
8f20bd3840 | ||
|
|
f1abb745fe | ||
|
|
cb2990f6e8 | ||
|
|
fb2f850311 | ||
|
|
2b9c0f09ee | ||
|
|
efe3eb4ce7 | ||
|
|
a1c1a79976 | ||
|
|
90ba355d16 | ||
|
|
01179adfa8 | ||
|
|
e4be403bef | ||
|
|
e1cdf4da0f | ||
|
|
5148cb3b8b | ||
|
|
56c6a9f8fe | ||
|
|
be257b0532 | ||
|
|
0534bc38b2 |
14
.env.example
14
.env.example
@@ -1,3 +1,6 @@
|
||||
# docker image tag (latest, nightly)
|
||||
TAG=latest
|
||||
|
||||
# set timezone to get correct log timestamp
|
||||
TZ=ETC/UTC
|
||||
|
||||
@@ -16,12 +19,11 @@ GODOXY_API_PASSWORD=password
|
||||
|
||||
# OIDC Configuration (optional)
|
||||
# Uncomment and configure these values to enable OIDC authentication.
|
||||
# For `GODOXY_OIDC_SCOPES` you may also include `offline_access` if your Idp supports it (e.g. Authentik)
|
||||
#
|
||||
# GODOXY_OIDC_ISSUER_URL=https://accounts.google.com
|
||||
# GODOXY_OIDC_CLIENT_ID=your-client-id
|
||||
# GODOXY_OIDC_CLIENT_SECRET=your-client-secret
|
||||
# GODOXY_OIDC_SCOPES=openid, profile, email
|
||||
# GODOXY_OIDC_SCOPES=openid, profile, email, groups # you may also include `offline_access` if your Idp supports it (e.g. Authentik, Pocket ID)
|
||||
#
|
||||
# User definitions: Uncomment and configure these values to restrict access to specific users or groups.
|
||||
# These two fields act as a logical AND operator. For example, given the following membership:
|
||||
@@ -48,8 +50,12 @@ GODOXY_API_ADDR=127.0.0.1:8888
|
||||
# Frontend listening port
|
||||
GODOXY_FRONTEND_PORT=3000
|
||||
|
||||
# Prometheus Metrics
|
||||
GODOXY_PROMETHEUS_ENABLED=true
|
||||
# Frontend aliases (subdomains / FQDNs, e.g. godoxy, godoxy.domain.com)
|
||||
GODOXY_FRONTEND_ALIASES=godoxy
|
||||
|
||||
# Docker socket
|
||||
# /var/run/podman/podman.sock for podman
|
||||
DOCKER_SOCKET=/var/run/docker.sock
|
||||
|
||||
# Debug mode
|
||||
GODOXY_DEBUG=false
|
||||
3
.github/workflows/agent-binary.yml
vendored
3
.github/workflows/agent-binary.yml
vendored
@@ -36,9 +36,6 @@ jobs:
|
||||
- name: Check binary
|
||||
run: |
|
||||
file bin/${{ matrix.binary_name }}
|
||||
- name: Test
|
||||
run: |
|
||||
go test -v ./agent/...
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
14
Dockerfile
14
Dockerfile
@@ -6,14 +6,6 @@ HEALTHCHECK NONE
|
||||
# trunk-ignore(hadolint/DL3018)
|
||||
RUN apk add --no-cache tzdata make libcap-setcap
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
# Only copy go.mod and go.sum initially for better caching
|
||||
COPY go.mod go.sum /src/
|
||||
|
||||
ENV GOPATH=/root/go
|
||||
RUN go mod download -x
|
||||
|
||||
# Stage 2: builder
|
||||
FROM deps AS builder
|
||||
|
||||
@@ -25,6 +17,12 @@ COPY internal ./internal
|
||||
COPY pkg ./pkg
|
||||
COPY agent ./agent
|
||||
|
||||
# Only copy go.mod and go.sum initially for better caching
|
||||
COPY go.mod go.sum /src/
|
||||
|
||||
ENV GOPATH=/root/go
|
||||
RUN go mod download -x
|
||||
|
||||
ARG VERSION
|
||||
ENV VERSION=${VERSION}
|
||||
|
||||
|
||||
11
Makefile
11
Makefile
@@ -7,10 +7,12 @@ LDFLAGS = -X github.com/yusing/go-proxy/pkg.version=${VERSION}
|
||||
|
||||
ifeq ($(agent), 1)
|
||||
NAME = godoxy-agent
|
||||
CMD_PATH = ./agent/cmd
|
||||
CMD_PATH = ./cmd
|
||||
PWD = ${shell pwd}/agent
|
||||
else
|
||||
NAME = godoxy
|
||||
CMD_PATH = ./cmd
|
||||
PWD = ${shell pwd}
|
||||
endif
|
||||
|
||||
ifeq ($(trace), 1)
|
||||
@@ -40,6 +42,7 @@ else
|
||||
endif
|
||||
|
||||
BUILD_FLAGS += -ldflags='$(LDFLAGS)'
|
||||
BIN_PATH := $(shell pwd)/bin/${NAME}
|
||||
|
||||
export NAME
|
||||
export CMD_PATH
|
||||
@@ -62,14 +65,14 @@ test:
|
||||
GODOXY_TEST=1 go test ./internal/...
|
||||
|
||||
get:
|
||||
go get -u ./cmd && go mod tidy
|
||||
for dir in ${PWD} ${PWD}/agent; do cd $$dir && go get -u ./... && go mod tidy; done
|
||||
|
||||
build:
|
||||
mkdir -p bin
|
||||
go build ${BUILD_FLAGS} -o bin/${NAME} ${CMD_PATH}
|
||||
cd ${PWD} && go build ${BUILD_FLAGS} -o ${BIN_PATH} ${CMD_PATH}
|
||||
|
||||
# CAP_NET_BIND_SERVICE: permission for binding to :80 and :443
|
||||
$(SETCAP_CMD) CAP_NET_BIND_SERVICE=+ep bin/${NAME}
|
||||
$(SETCAP_CMD) CAP_NET_BIND_SERVICE=+ep ${BIN_PATH}
|
||||
|
||||
run:
|
||||
[ -f .env ] && godotenv -f .env go run ${BUILD_FLAGS} ${CMD_PATH}
|
||||
|
||||
95
agent/go.mod
Normal file
95
agent/go.mod
Normal file
@@ -0,0 +1,95 @@
|
||||
module github.com/yusing/go-proxy/agent
|
||||
|
||||
go 1.24.2
|
||||
|
||||
replace github.com/yusing/go-proxy => ..
|
||||
|
||||
require (
|
||||
github.com/coder/websocket v1.8.13
|
||||
github.com/docker/docker v28.1.1+incompatible
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/yusing/go-proxy v0.11.5
|
||||
)
|
||||
|
||||
replace github.com/docker/docker => github.com/godoxy-app/docker v0.0.0-20250418000134-7af8fd7b079e
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.10.3 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/buger/goterm v1.0.4 // indirect
|
||||
github.com/bytedance/sonic v1.13.2 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/diskfs/go-diskfs v1.6.0 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/djherbis/times v1.6.0 // indirect
|
||||
github.com/docker/cli v28.1.1+incompatible // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/ebitengine/purego v0.8.2 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/go-acme/lego/v4 v4.23.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/goccy/go-yaml v1.17.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/gotify/server/v2 v2.6.3 // indirect
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lithammer/fuzzysearch v1.1.8 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
|
||||
github.com/luthermonson/go-proxmox v0.2.2 // indirect
|
||||
github.com/magefile/mage v1.15.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/miekg/dns v1.1.65 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.23.4 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.51.0 // indirect
|
||||
github.com/samber/lo v1.50.0 // indirect
|
||||
github.com/samber/slog-common v0.18.1 // indirect
|
||||
github.com/samber/slog-zerolog/v2 v2.7.3 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.3 // indirect
|
||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
|
||||
github.com/spf13/afero v1.14.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/vincent-petithory/dataurl v1.0.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/mock v0.5.1 // indirect
|
||||
golang.org/x/arch v0.16.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.32.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
360
agent/go.sum
Normal file
360
agent/go.sum
Normal file
@@ -0,0 +1,360 @@
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
||||
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
|
||||
github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
|
||||
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
|
||||
github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/diskfs/go-diskfs v1.6.0 h1:YmK5+vLSfkwC6kKKRTRPGaDGNF+Xh8FXeiNHwryDfu4=
|
||||
github.com/diskfs/go-diskfs v1.6.0/go.mod h1:bRFumZeGFCO8C2KNswrQeuj2m1WCVr4Ms5IjWMczMDk=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||
github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k=
|
||||
github.com/docker/cli v28.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
|
||||
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab h1:h1UgjJdAAhj+uPL68n7XASS6bU+07ZX1WJvVS2eyoeY=
|
||||
github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||
github.com/go-acme/lego/v4 v4.23.1 h1:lZ5fGtGESA2L9FB8dNTvrQUq3/X4QOb8ExkKyY7LSV4=
|
||||
github.com/go-acme/lego/v4 v4.23.1/go.mod h1:7UMVR7oQbIYw6V7mTgGwi4Er7B6Ww0c+c8feiBM0EgI=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
|
||||
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godoxy-app/docker v0.0.0-20250418000134-7af8fd7b079e h1:LEbMtJ6loEubxetD+Aw8+1x0rShor5iMoy9WuFQ8hN8=
|
||||
github.com/godoxy-app/docker v0.0.0-20250418000134-7af8fd7b079e/go.mod h1:3tMTnTkH7IN5smn7PX83XdmRnNj4Nw2/Pt8GgReqnKM=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4=
|
||||
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gotify/server/v2 v2.6.3 h1:2sLDRsQ/No1+hcFwFDvjNtwKepfCSIR8L3BkXl/Vz1I=
|
||||
github.com/gotify/server/v2 v2.6.3/go.mod h1:IyeQ/iL3vetcuqUAzkCMVObIMGGJx4zb13/mVatIwE8=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
|
||||
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
|
||||
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
||||
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/luthermonson/go-proxmox v0.2.2 h1:BZ7VEj302wxw2i/EwTcyEiBzQib8teocB2SSkLHyySY=
|
||||
github.com/luthermonson/go-proxmox v0.2.2/go.mod h1:oyFgg2WwTEIF0rP6ppjiixOHa5ebK1p8OaRiFhvICBQ=
|
||||
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
|
||||
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
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/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc=
|
||||
github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
|
||||
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
|
||||
github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
|
||||
github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=
|
||||
github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
|
||||
github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||
github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
|
||||
github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
|
||||
github.com/samber/slog-common v0.18.1 h1:c0EipD/nVY9HG5shgm/XAs67mgpWDMF+MmtptdJNCkQ=
|
||||
github.com/samber/slog-common v0.18.1/go.mod h1:QNZiNGKakvrfbJ2YglQXLCZauzkI9xZBjOhWFKS3IKk=
|
||||
github.com/samber/slog-zerolog/v2 v2.7.3 h1:/MkPDl/tJhijN2GvB1MWwBn2FU8RiL3rQ8gpXkQm2EY=
|
||||
github.com/samber/slog-zerolog/v2 v2.7.3/go.mod h1:oWU7WHof4Xp8VguiNO02r1a4VzkgoOyOZhY5CuRke60=
|
||||
github.com/shirou/gopsutil/v4 v4.25.3 h1:SeA68lsu8gLggyMbmCn8cmp97V1TI9ld9sVzAUcKcKE=
|
||||
github.com/shirou/gopsutil/v4 v4.25.3/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA=
|
||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0=
|
||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
|
||||
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8AbShPRpg2CI=
|
||||
github.com/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
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/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
|
||||
go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
||||
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
||||
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f h1:tjZsroqekhC63+WMqzmWyW5Twj/ZfR5HAlpd5YQ1Vs0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 h1:29cjnHVylHwTzH66WfFZqgSQgnxzvWE+jvBwpZCLRxY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
|
||||
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -16,7 +17,6 @@ import (
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
gphttp "github.com/yusing/go-proxy/internal/net/gphttp"
|
||||
"github.com/yusing/go-proxy/internal/net/types"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/pkg"
|
||||
)
|
||||
@@ -49,9 +49,17 @@ const (
|
||||
FakeDockerHostPrefixLen = len(FakeDockerHostPrefix)
|
||||
)
|
||||
|
||||
func mustParseURL(urlStr string) *url.URL {
|
||||
u, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
var (
|
||||
AgentURL = types.MustParseURL(APIBaseURL)
|
||||
HTTPProxyURL = types.MustParseURL(APIBaseURL + EndpointProxyHTTP)
|
||||
AgentURL = mustParseURL(APIBaseURL)
|
||||
HTTPProxyURL = mustParseURL(APIBaseURL + EndpointProxyHTTP)
|
||||
HTTPProxyURLPrefixLen = len(APIEndpointBase + EndpointProxyHTTP)
|
||||
)
|
||||
|
||||
@@ -72,14 +80,6 @@ func (cfg *AgentConfig) Parse(addr string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func withoutBuildTime(version string) string {
|
||||
return strings.Split(version, "-")[0]
|
||||
}
|
||||
|
||||
func checkVersion(a, b string) bool {
|
||||
return withoutBuildTime(a) == withoutBuildTime(b)
|
||||
}
|
||||
|
||||
func (cfg *AgentConfig) StartWithCerts(parent task.Parent, ca, crt, key []byte) error {
|
||||
clientCert, err := tls.X509KeyPair(crt, key)
|
||||
if err != nil {
|
||||
@@ -105,18 +105,6 @@ func (cfg *AgentConfig) StartWithCerts(parent task.Parent, ca, crt, key []byte)
|
||||
ctx, cancel := context.WithTimeout(parent.Context(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// check agent version
|
||||
version, _, err := cfg.Fetch(ctx, EndpointVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
versionStr := string(version)
|
||||
// skip version check for dev versions
|
||||
if strings.HasPrefix(versionStr, "v") && !checkVersion(versionStr, pkg.GetVersion()) {
|
||||
return gperr.Errorf("agent version mismatch: server: %s, agent: %s", pkg.GetVersion(), versionStr)
|
||||
}
|
||||
|
||||
// get agent name
|
||||
name, _, err := cfg.Fetch(ctx, EndpointName)
|
||||
if err != nil {
|
||||
@@ -124,8 +112,21 @@ func (cfg *AgentConfig) StartWithCerts(parent task.Parent, ca, crt, key []byte)
|
||||
}
|
||||
|
||||
cfg.name = string(name)
|
||||
|
||||
cfg.l = logging.With().Str("agent", cfg.name).Logger()
|
||||
|
||||
// check agent version
|
||||
agentVersionBytes, _, err := cfg.Fetch(ctx, EndpointVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
agentVersion := string(agentVersionBytes)
|
||||
|
||||
if pkg.GetVersion().IsNewerMajorThan(pkg.ParseVersion(agentVersion)) {
|
||||
logging.Warn().Msgf("agent %s major version mismatch: server: %s, agent: %s", cfg.name, pkg.GetVersion(), agentVersion)
|
||||
}
|
||||
|
||||
logging.Info().Msgf("agent %q initialized", cfg.name)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,10 +6,11 @@ import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
)
|
||||
|
||||
const AgentCertsBasePath = "certs"
|
||||
|
||||
func writeFile(zipWriter *zip.Writer, name string, data []byte) error {
|
||||
w, err := zipWriter.CreateHeader(&zip.FileHeader{
|
||||
Name: name,
|
||||
@@ -59,7 +60,7 @@ func AgentCertsFilepath(host string) (filepathOut string, ok bool) {
|
||||
if !isValidAgentHost(host) {
|
||||
return "", false
|
||||
}
|
||||
return filepath.Join(common.AgentCertsBasePath, host+".zip"), true
|
||||
return filepath.Join(AgentCertsBasePath, host+".zip"), true
|
||||
}
|
||||
|
||||
func ExtractCert(data []byte) (ca, crt, key []byte, err error) {
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
package certs
|
||||
package certs_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/yusing/go-proxy/internal/utils/testing"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/yusing/go-proxy/agent/pkg/certs"
|
||||
)
|
||||
|
||||
func TestZipCert(t *testing.T) {
|
||||
ca, crt, key := []byte("test1"), []byte("test2"), []byte("test3")
|
||||
zipData, err := ZipCert(ca, crt, key)
|
||||
ExpectNoError(t, err)
|
||||
zipData, err := certs.ZipCert(ca, crt, key)
|
||||
require.NoError(t, err)
|
||||
|
||||
ca2, crt2, key2, err := ExtractCert(zipData)
|
||||
ExpectNoError(t, err)
|
||||
ExpectEqual(t, ca, ca2)
|
||||
ExpectEqual(t, crt, crt2)
|
||||
ExpectEqual(t, key, key2)
|
||||
ca2, crt2, key2, err := certs.ExtractCert(zipData)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ca, ca2)
|
||||
require.Equal(t, crt, crt2)
|
||||
require.Equal(t, key, key2)
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
|
||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
||||
"github.com/yusing/go-proxy/agent/pkg/env"
|
||||
v1 "github.com/yusing/go-proxy/internal/api/v1"
|
||||
"github.com/yusing/go-proxy/internal/logging/memlogger"
|
||||
"github.com/yusing/go-proxy/internal/metrics/systeminfo"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
"github.com/yusing/go-proxy/pkg"
|
||||
)
|
||||
|
||||
type ServeMux struct{ *http.ServeMux }
|
||||
@@ -37,7 +37,7 @@ func NewAgentHandler() http.Handler {
|
||||
mux := ServeMux{http.NewServeMux()}
|
||||
|
||||
mux.HandleFunc(agent.EndpointProxyHTTP+"/{path...}", ProxyHTTP)
|
||||
mux.HandleMethods("GET", agent.EndpointVersion, v1.GetVersion)
|
||||
mux.HandleMethods("GET", agent.EndpointVersion, pkg.GetVersionHTTPHandler())
|
||||
mux.HandleMethods("GET", agent.EndpointName, func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprint(w, env.AgentName)
|
||||
})
|
||||
|
||||
@@ -6,12 +6,13 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/yusing/go-proxy/internal"
|
||||
"github.com/yusing/go-proxy/internal/api/v1/query"
|
||||
"github.com/yusing/go-proxy/internal/auth"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/config"
|
||||
"github.com/yusing/go-proxy/internal/dnsproviders"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/homepage"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/logging/memlogger"
|
||||
"github.com/yusing/go-proxy/internal/metrics/systeminfo"
|
||||
@@ -38,6 +39,7 @@ func parallel(fns ...func()) {
|
||||
|
||||
func main() {
|
||||
initProfiling()
|
||||
dnsproviders.InitProviders()
|
||||
args := pkg.GetArgs(common.MainServerCommandValidator{})
|
||||
|
||||
switch args.Command {
|
||||
@@ -48,7 +50,7 @@ func main() {
|
||||
rawLogger.Println("ok")
|
||||
return
|
||||
case common.CommandListIcons:
|
||||
icons, err := internal.ListAvailableIcons()
|
||||
icons, err := homepage.ListAvailableIcons()
|
||||
if err != nil {
|
||||
rawLogger.Fatal(err)
|
||||
}
|
||||
@@ -77,7 +79,7 @@ func main() {
|
||||
logging.Info().Msgf("GoDoxy version %s", pkg.GetVersion())
|
||||
logging.Trace().Msg("trace enabled")
|
||||
parallel(
|
||||
internal.InitIconListCache,
|
||||
homepage.InitIconListCache,
|
||||
systeminfo.Poller.Start,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
services:
|
||||
frontend:
|
||||
image: ghcr.io/yusing/godoxy-frontend:latest
|
||||
image: ghcr.io/yusing/godoxy-frontend:${TAG:-latest}
|
||||
container_name: godoxy-frontend
|
||||
restart: unless-stopped
|
||||
network_mode: host # do not change this
|
||||
@@ -13,7 +13,7 @@ services:
|
||||
|
||||
# modify below to fit your needs
|
||||
labels:
|
||||
proxy.aliases: godoxy
|
||||
proxy.aliases: ${GODOXY_FRONTEND_ALIASES:-godoxy}
|
||||
proxy.godoxy.port: ${GODOXY_FRONTEND_PORT:-3000}
|
||||
# proxy.godoxy.middlewares.cidr_whitelist: |
|
||||
# status: 403
|
||||
@@ -24,13 +24,13 @@ services:
|
||||
# - 192.168.0.0/16
|
||||
# - 172.16.0.0/12
|
||||
app:
|
||||
image: ghcr.io/yusing/godoxy:latest
|
||||
image: ghcr.io/yusing/godoxy:${TAG:-latest}
|
||||
container_name: godoxy
|
||||
restart: always
|
||||
network_mode: host # do not change this
|
||||
env_file: .env
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ${DOCKER_SOCKET:-/var/run/docker.sock}:/var/run/docker.sock
|
||||
- ./config:/app/config
|
||||
- ./logs:/app/logs
|
||||
- ./error_pages:/app/error_pages
|
||||
|
||||
27
go.mod
27
go.mod
@@ -2,6 +2,10 @@ module github.com/yusing/go-proxy
|
||||
|
||||
go 1.24.2
|
||||
|
||||
replace github.com/yusing/go-proxy/agent => ./agent
|
||||
|
||||
replace github.com/yusing/go-proxy/internal/dnsproviders => ./internal/dnsproviders
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.10.3 // parsing HTML for extract fav icon
|
||||
github.com/coder/websocket v1.8.13 // websocket for API and agent
|
||||
@@ -11,7 +15,7 @@ require (
|
||||
github.com/go-acme/lego/v4 v4.23.1 // acme client
|
||||
github.com/go-playground/validator/v10 v10.26.0 // validator
|
||||
github.com/gobwas/glob v0.2.3 // glob matcher for route rules
|
||||
github.com/gotify/server/v2 v2.6.1 // reference the Message struct for json response
|
||||
github.com/gotify/server/v2 v2.6.3 // reference the Message struct for json response
|
||||
github.com/lithammer/fuzzysearch v1.1.8 // fuzzy search for searching icons and filtering metrics
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 // lock free map for concurrent operations
|
||||
github.com/rs/zerolog v1.34.0 // logging
|
||||
@@ -37,9 +41,17 @@ require (
|
||||
github.com/samber/slog-zerolog/v2 v2.7.3
|
||||
github.com/spf13/afero v1.14.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/yusing/go-proxy/agent v0.0.0-20250428032249-8da63daf0202
|
||||
github.com/yusing/go-proxy/internal/dnsproviders v0.0.0-20250428032249-8da63daf0202
|
||||
go.uber.org/atomic v1.11.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/docker/docker => github.com/godoxy-app/docker v0.0.0-20250425105916-b2ad800de7a1
|
||||
|
||||
require (
|
||||
@@ -79,7 +91,7 @@ require (
|
||||
github.com/boombuler/barcode v1.0.2 // indirect
|
||||
github.com/buger/goterm v1.0.4 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/civo/civogo v0.3.98 // indirect
|
||||
github.com/civo/civogo v0.3.99 // indirect
|
||||
github.com/cloudflare/cloudflare-go v0.115.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/diskfs/go-diskfs v1.6.0 // indirect
|
||||
@@ -119,9 +131,9 @@ require (
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.146 // indirect
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.147 // indirect
|
||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
|
||||
github.com/infobloxopen/infoblox-go-client/v2 v2.9.0 // indirect
|
||||
github.com/infobloxopen/infoblox-go-client/v2 v2.10.0 // indirect
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
@@ -179,7 +191,7 @@ require (
|
||||
github.com/sacloud/iaas-api-go v1.14.0 // indirect
|
||||
github.com/sacloud/packages-go v0.0.11 // indirect
|
||||
github.com/sagikazarmark/locafero v0.9.0 // indirect
|
||||
github.com/samber/lo v1.49.1 // indirect
|
||||
github.com/samber/lo v1.50.0 // indirect
|
||||
github.com/samber/slog-common v0.18.1 // indirect
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33 // indirect
|
||||
github.com/selectel/domains-go v1.1.0 // indirect
|
||||
@@ -195,7 +207,7 @@ require (
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1151 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1154 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
@@ -212,7 +224,6 @@ require (
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
@@ -225,7 +236,7 @@ require (
|
||||
golang.org/x/tools v0.32.0 // indirect
|
||||
google.golang.org/api v0.230.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 // indirect
|
||||
google.golang.org/grpc v1.72.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
|
||||
30
go.sum
30
go.sum
@@ -749,8 +749,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/civo/civogo v0.3.98 h1:FEbB5oxCcHeHUK3fJODxVoMQzhpLV9Jtb7bezANTY5c=
|
||||
github.com/civo/civogo v0.3.98/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc=
|
||||
github.com/civo/civogo v0.3.99 h1:ijv3ecaz9Ju82J72kbQwQvzlSxn9fLMlklu8C8pXGjI=
|
||||
github.com/civo/civogo v0.3.99/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc=
|
||||
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cloudflare-go v0.115.0 h1:84/dxeeXweCc0PN5Cto44iTA8AkG1fyT11yPO5ZB7sM=
|
||||
@@ -1082,8 +1082,8 @@ github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gotify/server/v2 v2.6.1 h1:Kf7v5fzBxzELzZa/jonWfwJMkqYqh1LBzBpCmt5QIAI=
|
||||
github.com/gotify/server/v2 v2.6.1/go.mod h1:Dk8HLyTVDqmXM8YEg6tjROBen6mxyHZFRggJFHTwZLc=
|
||||
github.com/gotify/server/v2 v2.6.3 h1:2sLDRsQ/No1+hcFwFDvjNtwKepfCSIR8L3BkXl/Vz1I=
|
||||
github.com/gotify/server/v2 v2.6.3/go.mod h1:IyeQ/iL3vetcuqUAzkCMVObIMGGJx4zb13/mVatIwE8=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
@@ -1093,6 +1093,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4Zs
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
|
||||
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
@@ -1148,8 +1150,8 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
|
||||
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.146 h1:ld5s5UeA9zgyFsZskVD2Tr6k6VnJWkvaLm5nqvfOEf4=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.146/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.147 h1:ip9+1n9+THhYgChlQpgDLVDVTv4LVJ7AoyPBJBaX2MY=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.147/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
|
||||
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
@@ -1159,8 +1161,8 @@ github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhK
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/infobloxopen/infoblox-go-client/v2 v2.9.0 h1:wS8kTlQVeVbrepeY83s9X+XdSa6Qah5KO+tdW+zRQXU=
|
||||
github.com/infobloxopen/infoblox-go-client/v2 v2.9.0/go.mod h1:NeNJpz09efw/edzqkVivGv1bWqBXTomqYBRFbP+XBqg=
|
||||
github.com/infobloxopen/infoblox-go-client/v2 v2.10.0 h1:AKsihjFT/t6Y0keEv3p59DACcOuh0inWXdUB0ZOzYH0=
|
||||
github.com/infobloxopen/infoblox-go-client/v2 v2.10.0/go.mod h1:NeNJpz09efw/edzqkVivGv1bWqBXTomqYBRFbP+XBqg=
|
||||
github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
|
||||
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
||||
@@ -1518,8 +1520,8 @@ github.com/sacloud/packages-go v0.0.11/go.mod h1:XNF5MCTWcHo9NiqWnYctVbASSSZR3ZO
|
||||
github.com/sagikazarmark/crypt v0.10.0/go.mod h1:gwTNHQVoOS3xp9Xvz5LLR+1AauC5M6880z5NWzdhOyQ=
|
||||
github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
|
||||
github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
|
||||
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
|
||||
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
||||
github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
|
||||
github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
|
||||
github.com/samber/slog-common v0.18.1 h1:c0EipD/nVY9HG5shgm/XAs67mgpWDMF+MmtptdJNCkQ=
|
||||
github.com/samber/slog-common v0.18.1/go.mod h1:QNZiNGKakvrfbJ2YglQXLCZauzkI9xZBjOhWFKS3IKk=
|
||||
github.com/samber/slog-zerolog/v2 v2.7.3 h1:/MkPDl/tJhijN2GvB1MWwBn2FU8RiL3rQ8gpXkQm2EY=
|
||||
@@ -1616,8 +1618,8 @@ github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNG
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1136/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1151 h1:SBbEaeCwhqmyAEEF5ubpg/2vv3RO6SdBsOSYhpnJaL4=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1151/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1154 h1:tc2GXLGwpjaZdapd7pEpUjoeWU5gl3XUuZzDEyes7fg=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1154/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 h1:kMIdSU5IvpOROh27ToVQ3hlm6ym3lCRs9tnGCOBoZqk=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136/go.mod h1:FpyIz3mymKaExVs6Fz27kxDBS42jqZn7vbACtxdeEH4=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
@@ -2438,8 +2440,8 @@ google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOl
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f h1:tjZsroqekhC63+WMqzmWyW5Twj/ZfR5HAlpd5YQ1Vs0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f h1:N/PrbTw4kdkqNRzVfWPrBekzLuarFREcbFOiOLkXon4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 h1:29cjnHVylHwTzH66WfFZqgSQgnxzvWE+jvBwpZCLRxY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.19.0/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=
|
||||
|
||||
@@ -3,11 +3,9 @@ package acl
|
||||
import (
|
||||
"github.com/puzpuzpuz/xsync/v3"
|
||||
acl "github.com/yusing/go-proxy/internal/acl/types"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
var cityCache = xsync.NewMapOf[string, *acl.City]()
|
||||
var numCachedLookup atomic.Uint64
|
||||
|
||||
func (cfg *MaxMindConfig) lookupCity(ip *acl.IPInfo) (*acl.City, bool) {
|
||||
if ip.City != nil {
|
||||
@@ -20,7 +18,7 @@ func (cfg *MaxMindConfig) lookupCity(ip *acl.IPInfo) (*acl.City, bool) {
|
||||
|
||||
city, ok := cityCache.Load(ip.Str)
|
||||
if ok {
|
||||
numCachedLookup.Inc()
|
||||
ip.City = city
|
||||
return city, true
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/puzpuzpuz/xsync/v3"
|
||||
"github.com/rs/zerolog"
|
||||
acl "github.com/yusing/go-proxy/internal/acl/types"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/logging/accesslog"
|
||||
@@ -63,7 +64,7 @@ type checkCache struct {
|
||||
const cacheTTL = 1 * time.Minute
|
||||
|
||||
func (c *checkCache) Expired() bool {
|
||||
return c.created.Add(cacheTTL).After(utils.TimeNow())
|
||||
return c.created.Add(cacheTTL).Before(utils.TimeNow())
|
||||
}
|
||||
|
||||
//TODO: add stats
|
||||
@@ -153,7 +154,10 @@ func (c *Config) Start(parent *task.Task) gperr.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *config) cacheRecord(info *acl.IPInfo, allow bool) {
|
||||
func (c *Config) cacheRecord(info *acl.IPInfo, allow bool) {
|
||||
if common.ForceResolveCountry && info.City == nil {
|
||||
c.MaxMind.lookupCity(info)
|
||||
}
|
||||
c.ipCache.Store(info.Str, &checkCache{
|
||||
IPInfo: info,
|
||||
allow: allow,
|
||||
@@ -175,7 +179,7 @@ func (c *Config) IPAllowed(ip net.IP) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// always allow private and loopback
|
||||
// always allow loopback
|
||||
// loopback is not logged
|
||||
if ip.IsLoopback() {
|
||||
return true
|
||||
|
||||
@@ -54,7 +54,7 @@ func (cfg *MaxMindConfig) LoadMaxMindDB(parent task.Parent) gperr.Error {
|
||||
|
||||
path := dbPath(cfg.Database)
|
||||
reader, err := maxmindDBOpen(path)
|
||||
exists := true
|
||||
valid := true
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, os.ErrNotExist):
|
||||
@@ -65,20 +65,19 @@ func (cfg *MaxMindConfig) LoadMaxMindDB(parent task.Parent) gperr.Error {
|
||||
return gperr.Wrap(err)
|
||||
}
|
||||
}
|
||||
exists = false
|
||||
valid = false
|
||||
}
|
||||
|
||||
if !exists {
|
||||
if !valid {
|
||||
cfg.logger.Info().Msg("MaxMind DB not found/invalid, downloading...")
|
||||
reader, err = cfg.download()
|
||||
if err != nil {
|
||||
if err = cfg.download(); err != nil {
|
||||
return ErrDownloadFailure.With(err)
|
||||
}
|
||||
} else {
|
||||
cfg.logger.Info().Msg("MaxMind DB loaded")
|
||||
cfg.db.Reader = reader
|
||||
go cfg.scheduleUpdate(parent)
|
||||
}
|
||||
cfg.logger.Info().Msg("MaxMind DB loaded")
|
||||
|
||||
cfg.db.Reader = reader
|
||||
go cfg.scheduleUpdate(parent)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -137,17 +136,10 @@ func (cfg *MaxMindConfig) update() {
|
||||
Time("latest", remoteLastModified.Local()).
|
||||
Time("current", cfg.lastUpdate).
|
||||
Msg("MaxMind DB update available")
|
||||
reader, err := cfg.download()
|
||||
if err != nil {
|
||||
if err = cfg.download(); err != nil {
|
||||
cfg.logger.Err(err).Msg("failed to update MaxMind DB")
|
||||
return
|
||||
}
|
||||
cfg.db.Lock()
|
||||
cfg.db.Close()
|
||||
cfg.db.Reader = reader
|
||||
cfg.setLastUpdate(*remoteLastModified)
|
||||
cfg.db.Unlock()
|
||||
|
||||
cfg.logger.Info().Msg("MaxMind DB updated")
|
||||
}
|
||||
|
||||
@@ -190,57 +182,87 @@ func (cfg *MaxMindConfig) checkLastest() (lastModifiedT *time.Time, err error) {
|
||||
return &lastModifiedTime, nil
|
||||
}
|
||||
|
||||
func (cfg *MaxMindConfig) download() (*maxminddb.Reader, error) {
|
||||
func (cfg *MaxMindConfig) download() error {
|
||||
resp, err := newReq(cfg, http.MethodGet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%w: %d", ErrResponseNotOK, resp.StatusCode)
|
||||
return fmt.Errorf("%w: %d", ErrResponseNotOK, resp.StatusCode)
|
||||
}
|
||||
|
||||
path := dbPath(cfg.Database)
|
||||
tmpPath := path + "-tmp.tar.gz"
|
||||
file, err := os.OpenFile(tmpPath, os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbFile := dbPath(cfg.Database)
|
||||
tmpGZPath := dbFile + "-tmp.tar.gz"
|
||||
tmpDBPath := dbFile + "-tmp"
|
||||
|
||||
cfg.logger.Info().Msg("MaxMind DB downloading...")
|
||||
|
||||
_, err = io.Copy(file, resp.Body)
|
||||
if err != nil {
|
||||
file.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
// extract .tar.gz and move only the dbFilename to path
|
||||
err = extractFileFromTarGz(tmpPath, dbFilename(cfg.Database), path)
|
||||
if err != nil {
|
||||
return nil, gperr.New("failed to extract database from archive").With(err)
|
||||
}
|
||||
// cleanup the tar.gz file
|
||||
_ = os.Remove(tmpPath)
|
||||
|
||||
db, err := maxmindDBOpen(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func extractFileFromTarGz(tarGzPath, targetFilename, destPath string) error {
|
||||
f, err := os.Open(tarGzPath)
|
||||
tmpGZFile, err := os.OpenFile(tmpGZPath, os.O_CREATE|os.O_RDWR, 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
gzr, err := gzip.NewReader(f)
|
||||
// cleanup the tar.gz file
|
||||
defer func() {
|
||||
_ = tmpGZFile.Close()
|
||||
_ = os.Remove(tmpGZPath)
|
||||
}()
|
||||
|
||||
cfg.logger.Info().Msg("MaxMind DB downloading...")
|
||||
|
||||
_, err = io.Copy(tmpGZFile, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tmpGZFile.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// extract .tar.gz and to database
|
||||
err = extractFileFromTarGz(tmpGZFile, dbFilename(cfg.Database), tmpDBPath)
|
||||
|
||||
if err != nil {
|
||||
return gperr.New("failed to extract database from archive").With(err)
|
||||
}
|
||||
|
||||
// test if the downloaded database is valid
|
||||
db, err := maxmindDBOpen(tmpDBPath)
|
||||
if err != nil {
|
||||
_ = os.Remove(tmpDBPath)
|
||||
return err
|
||||
}
|
||||
|
||||
db.Close()
|
||||
err = os.Rename(tmpDBPath, dbFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg.db.Lock()
|
||||
defer cfg.db.Unlock()
|
||||
if cfg.db.Reader != nil {
|
||||
cfg.db.Reader.Close()
|
||||
}
|
||||
cfg.db.Reader, err = maxmindDBOpen(dbFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lastModifiedStr := resp.Header.Get("Last-Modified")
|
||||
lastModifiedTime, err := time.Parse(http.TimeFormat, lastModifiedStr)
|
||||
if err == nil {
|
||||
cfg.setLastUpdate(lastModifiedTime)
|
||||
}
|
||||
|
||||
cfg.logger.Info().Msg("MaxMind DB downloaded")
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractFileFromTarGz(tarGzFile *os.File, targetFilename, destPath string) error {
|
||||
defer tarGzFile.Close()
|
||||
|
||||
gzr, err := gzip.NewReader(tarGzFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package acl
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -144,9 +146,17 @@ func Test_MaxMindConfig_download(t *testing.T) {
|
||||
logger: zerolog.Nop(),
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
io.Copy(w, strings.NewReader("FAKEMMDB"))
|
||||
gz := gzip.NewWriter(w)
|
||||
t := tar.NewWriter(gz)
|
||||
t.WriteHeader(&tar.Header{
|
||||
Name: dbFilename(MaxMindGeoLite),
|
||||
})
|
||||
t.Write([]byte("1234"))
|
||||
t.Close()
|
||||
gz.Close()
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
oldURL := dbURL
|
||||
dbURL = func(MaxMindDatabaseType) string { return server.URL }
|
||||
defer func() { dbURL = oldURL }()
|
||||
@@ -163,26 +173,26 @@ func Test_MaxMindConfig_download(t *testing.T) {
|
||||
}
|
||||
defer func() { maxmindDBOpen = origOpen }()
|
||||
|
||||
rw := &fakeReadCloser{}
|
||||
req, err := http.NewRequest(http.MethodGet, server.URL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("newReq() error = %v", err)
|
||||
}
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
oldNewReq := newReq
|
||||
newReq = func(cfg *MaxMindConfig, method string) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: rw,
|
||||
}, nil
|
||||
server.Config.Handler.ServeHTTP(rw, req)
|
||||
return rw.Result(), nil
|
||||
}
|
||||
defer func() { newReq = oldNewReq }()
|
||||
|
||||
db, err := cfg.download()
|
||||
err = cfg.download()
|
||||
if err != nil {
|
||||
t.Fatalf("download() error = %v", err)
|
||||
}
|
||||
if db == nil {
|
||||
if cfg.db.Reader == nil {
|
||||
t.Error("expected db instance")
|
||||
}
|
||||
if !rw.closed {
|
||||
t.Error("expected rw to be closed")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_MaxMindConfig_loadMaxMindDB(t *testing.T) {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package acl
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TCPListener struct {
|
||||
@@ -9,6 +11,17 @@ type TCPListener struct {
|
||||
lis net.Listener
|
||||
}
|
||||
|
||||
type noConn struct{}
|
||||
|
||||
func (noConn) Read(b []byte) (int, error) { return 0, io.EOF }
|
||||
func (noConn) Write(b []byte) (int, error) { return 0, io.EOF }
|
||||
func (noConn) Close() error { return nil }
|
||||
func (noConn) LocalAddr() net.Addr { return nil }
|
||||
func (noConn) RemoteAddr() net.Addr { return nil }
|
||||
func (noConn) SetDeadline(t time.Time) error { return nil }
|
||||
func (noConn) SetReadDeadline(t time.Time) error { return nil }
|
||||
func (noConn) SetWriteDeadline(t time.Time) error { return nil }
|
||||
|
||||
func (cfg *Config) WrapTCP(lis net.Listener) net.Listener {
|
||||
if cfg == nil {
|
||||
return lis
|
||||
@@ -32,11 +45,11 @@ func (s *TCPListener) Accept() (net.Conn, error) {
|
||||
if !ok {
|
||||
// Not a TCPAddr, drop
|
||||
c.Close()
|
||||
return nil, nil
|
||||
return noConn{}, nil
|
||||
}
|
||||
if !s.acl.IPAllowed(addr.IP) {
|
||||
c.Close()
|
||||
return nil, nil
|
||||
return noConn{}, nil
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/yusing/go-proxy/internal/metrics/uptime"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
"github.com/yusing/go-proxy/pkg"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -65,7 +66,7 @@ func (mux ServeMux) HandleFunc(methods, endpoint string, h any, requireAuth ...b
|
||||
func NewHandler(cfg config.ConfigInstance) http.Handler {
|
||||
mux := ServeMux{http.NewServeMux(), cfg}
|
||||
mux.HandleFunc("GET", "/v1", v1.Index)
|
||||
mux.HandleFunc("GET", "/v1/version", v1.GetVersion)
|
||||
mux.HandleFunc("GET", "/v1/version", pkg.GetVersionHTTPHandler())
|
||||
|
||||
mux.HandleFunc("GET", "/v1/stats", v1.Stats, true)
|
||||
mux.HandleFunc("POST", "/v1/reload", v1.Reload, true)
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/yusing/go-proxy/internal"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
config "github.com/yusing/go-proxy/internal/config/types"
|
||||
"github.com/yusing/go-proxy/internal/homepage"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp/middleware"
|
||||
"github.com/yusing/go-proxy/internal/route/routes"
|
||||
@@ -67,7 +67,7 @@ func List(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
limit = 0
|
||||
}
|
||||
icons, err := internal.SearchIcons(r.FormValue("keyword"), limit)
|
||||
icons, err := homepage.SearchIcons(r.FormValue("keyword"), limit)
|
||||
if err != nil {
|
||||
gphttp.ClientError(w, err)
|
||||
return
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy"
|
||||
"github.com/yusing/go-proxy/internal/net/types"
|
||||
)
|
||||
|
||||
func SystemInfo(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) {
|
||||
@@ -40,7 +41,7 @@ func SystemInfo(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Reques
|
||||
}
|
||||
gphttp.WriteBody(w, respData)
|
||||
} else {
|
||||
rp := reverseproxy.NewReverseProxy("agent", agentPkg.AgentURL, agent.Transport())
|
||||
rp := reverseproxy.NewReverseProxy("agent", types.NewURL(agentPkg.AgentURL), agent.Transport())
|
||||
header := r.Header.Clone()
|
||||
r, err := http.NewRequestWithContext(r.Context(), r.Method, agentPkg.EndpointSystemInfo+"?"+query.Encode(), nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp"
|
||||
"github.com/yusing/go-proxy/pkg"
|
||||
)
|
||||
|
||||
func GetVersion(w http.ResponseWriter, r *http.Request) {
|
||||
gphttp.WriteBody(w, []byte(pkg.GetVersion()))
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
@@ -38,22 +39,40 @@ func IsOIDCEnabled() bool {
|
||||
return common.OIDCIssuerURL != ""
|
||||
}
|
||||
|
||||
type nextHandler struct{}
|
||||
|
||||
var nextHandlerContextKey = nextHandler{}
|
||||
|
||||
func RequireAuth(next http.HandlerFunc) http.HandlerFunc {
|
||||
if IsEnabled() {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := defaultAuth.CheckToken(r); err != nil {
|
||||
gphttp.ClientError(w, err, http.StatusUnauthorized)
|
||||
} else {
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
if !IsEnabled() {
|
||||
return next
|
||||
}
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := defaultAuth.CheckToken(r); err != nil {
|
||||
if IsFrontend(r) {
|
||||
r = r.WithContext(context.WithValue(r.Context(), nextHandlerContextKey, next))
|
||||
defaultAuth.LoginHandler(w, r)
|
||||
} else {
|
||||
gphttp.ClientError(w, err, http.StatusUnauthorized)
|
||||
}
|
||||
return
|
||||
}
|
||||
next(w, r)
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
func AuthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if err := defaultAuth.CheckToken(r); err != nil {
|
||||
http.Redirect(w, r, "/v1/auth/login", http.StatusFound)
|
||||
func ProceedNext(w http.ResponseWriter, r *http.Request) {
|
||||
next, ok := r.Context().Value(nextHandlerContextKey).(http.HandlerFunc)
|
||||
if ok {
|
||||
next(w, r)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func AuthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if err := defaultAuth.CheckToken(r); err != nil {
|
||||
defaultAuth.LoginHandler(w, r)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
@@ -19,6 +21,10 @@ type oauthRefreshToken struct {
|
||||
Username string `json:"username"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
|
||||
result *refreshResult
|
||||
err error
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
@@ -27,6 +33,12 @@ type Session struct {
|
||||
Groups []string `json:"groups"`
|
||||
}
|
||||
|
||||
type refreshResult struct {
|
||||
newSession Session
|
||||
jwt string
|
||||
jwtExpiry time.Time
|
||||
}
|
||||
|
||||
type sessionClaims struct {
|
||||
Session
|
||||
jwt.RegisteredClaims
|
||||
@@ -34,11 +46,12 @@ type sessionClaims struct {
|
||||
|
||||
type sessionID string
|
||||
|
||||
var oauthRefreshTokens jsonstore.MapStore[oauthRefreshToken]
|
||||
var oauthRefreshTokens jsonstore.MapStore[*oauthRefreshToken]
|
||||
|
||||
var (
|
||||
defaultRefreshTokenExpiry = 30 * 24 * time.Hour // 1 month
|
||||
refreshBefore = 30 * time.Second
|
||||
sessionInvalidateDelay = 3 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -50,7 +63,7 @@ const sessionTokenIssuer = "GoDoxy"
|
||||
|
||||
func init() {
|
||||
if IsOIDCEnabled() {
|
||||
oauthRefreshTokens = jsonstore.Store[oauthRefreshToken]("oauth_refresh_tokens")
|
||||
oauthRefreshTokens = jsonstore.Store[*oauthRefreshToken]("oauth_refresh_tokens")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +74,7 @@ func (token *oauthRefreshToken) expired() bool {
|
||||
func newSessionID() sessionID {
|
||||
b := make([]byte, 32)
|
||||
_, _ = rand.Read(b)
|
||||
return sessionID(base64.StdEncoding.EncodeToString(b))
|
||||
return sessionID(hex.EncodeToString(b))
|
||||
}
|
||||
|
||||
func newSession(username string, groups []string) Session {
|
||||
@@ -72,26 +85,28 @@ func newSession(username string, groups []string) Session {
|
||||
}
|
||||
}
|
||||
|
||||
// getOnceOAuthRefreshToken returns the refresh token for the given session.
|
||||
// getOAuthRefreshToken returns the refresh token for the given session.
|
||||
//
|
||||
// The token is removed from the store after retrieval.
|
||||
func getOnceOAuthRefreshToken(claims *Session) (*oauthRefreshToken, bool) {
|
||||
func getOAuthRefreshToken(claims *Session) (*oauthRefreshToken, bool) {
|
||||
token, ok := oauthRefreshTokens.Load(string(claims.SessionID))
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
invalidateOAuthRefreshToken(claims.SessionID)
|
||||
|
||||
if token.expired() {
|
||||
invalidateOAuthRefreshToken(claims.SessionID)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if claims.Username != token.Username {
|
||||
return nil, false
|
||||
}
|
||||
return &token, true
|
||||
return token, true
|
||||
}
|
||||
|
||||
func storeOAuthRefreshToken(sessionID sessionID, username, token string) {
|
||||
oauthRefreshTokens.Store(string(sessionID), oauthRefreshToken{
|
||||
oauthRefreshTokens.Store(string(sessionID), &oauthRefreshToken{
|
||||
Username: username,
|
||||
RefreshToken: token,
|
||||
Expiry: time.Now().Add(defaultRefreshTokenExpiry),
|
||||
@@ -135,51 +150,75 @@ func (auth *OIDCProvider) parseSessionJWT(sessionJWT string) (claims *sessionCla
|
||||
return claims, sessionToken.Valid && claims.Issuer == sessionTokenIssuer, nil
|
||||
}
|
||||
|
||||
func (auth *OIDCProvider) TryRefreshToken(w http.ResponseWriter, r *http.Request, sessionJWT string) error {
|
||||
func (auth *OIDCProvider) TryRefreshToken(ctx context.Context, sessionJWT string) (*refreshResult, error) {
|
||||
// verify the session cookie
|
||||
claims, valid, err := auth.parseSessionJWT(sessionJWT)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %w", ErrInvalidSessionToken, err)
|
||||
return nil, fmt.Errorf("session: %s - %w: %w", claims.SessionID, ErrInvalidSessionToken, err)
|
||||
}
|
||||
if !valid {
|
||||
return ErrInvalidSessionToken
|
||||
return nil, ErrInvalidSessionToken
|
||||
}
|
||||
|
||||
// check if refresh is possible
|
||||
refreshToken, ok := getOnceOAuthRefreshToken(&claims.Session)
|
||||
refreshToken, ok := getOAuthRefreshToken(&claims.Session)
|
||||
if !ok {
|
||||
return errNoRefreshToken
|
||||
return nil, errNoRefreshToken
|
||||
}
|
||||
|
||||
if !auth.checkAllowed(claims.Username, claims.Groups) {
|
||||
return ErrUserNotAllowed
|
||||
return nil, ErrUserNotAllowed
|
||||
}
|
||||
|
||||
return auth.doRefreshToken(ctx, refreshToken, &claims.Session)
|
||||
}
|
||||
|
||||
func (auth *OIDCProvider) doRefreshToken(ctx context.Context, refreshToken *oauthRefreshToken, claims *Session) (*refreshResult, error) {
|
||||
refreshToken.mu.Lock()
|
||||
defer refreshToken.mu.Unlock()
|
||||
|
||||
// already refreshed
|
||||
// this must be called after refresh but before invalidate
|
||||
if refreshToken.result != nil || refreshToken.err != nil {
|
||||
return refreshToken.result, refreshToken.err
|
||||
}
|
||||
|
||||
// this step refreshes the token
|
||||
// see https://cs.opensource.google/go/x/oauth2/+/refs/tags/v0.29.0:oauth2.go;l=313
|
||||
newToken, err := auth.oauthConfig.TokenSource(r.Context(), &oauth2.Token{
|
||||
newToken, err := auth.oauthConfig.TokenSource(ctx, &oauth2.Token{
|
||||
RefreshToken: refreshToken.RefreshToken,
|
||||
}).Token()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %w", ErrRefreshTokenFailure, err)
|
||||
refreshToken.err = fmt.Errorf("session: %s - %w: %w", claims.SessionID, ErrRefreshTokenFailure, err)
|
||||
return nil, refreshToken.err
|
||||
}
|
||||
|
||||
idTokenJWT, idToken, err := auth.getIdToken(r.Context(), newToken)
|
||||
idTokenJWT, idToken, err := auth.getIdToken(ctx, newToken)
|
||||
if err != nil {
|
||||
return err
|
||||
refreshToken.err = fmt.Errorf("session: %s - %w: %w", claims.SessionID, ErrRefreshTokenFailure, err)
|
||||
return nil, refreshToken.err
|
||||
}
|
||||
|
||||
// in case there're multiple requests for the same session to refresh
|
||||
// invalidate the token after a short delay
|
||||
go func() {
|
||||
<-time.After(sessionInvalidateDelay)
|
||||
invalidateOAuthRefreshToken(claims.SessionID)
|
||||
}()
|
||||
|
||||
sessionID := newSessionID()
|
||||
|
||||
logging.Debug().Str("username", claims.Username).Time("expiry", newToken.Expiry).Msg("refreshed token")
|
||||
storeOAuthRefreshToken(sessionID, claims.Username, newToken.RefreshToken)
|
||||
|
||||
// set new idToken and new sessionToken
|
||||
auth.setIDTokenCookie(w, r, idTokenJWT, time.Until(idToken.Expiry))
|
||||
auth.setSessionTokenCookie(w, r, Session{
|
||||
SessionID: sessionID,
|
||||
Username: claims.Username,
|
||||
Groups: claims.Groups,
|
||||
})
|
||||
return nil
|
||||
refreshToken.result = &refreshResult{
|
||||
newSession: Session{
|
||||
SessionID: sessionID,
|
||||
Username: claims.Username,
|
||||
Groups: claims.Groups,
|
||||
},
|
||||
jwt: idTokenJWT,
|
||||
jwtExpiry: idToken.Expiry,
|
||||
}
|
||||
return refreshToken.result, nil
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
@@ -38,7 +38,6 @@ type (
|
||||
|
||||
const (
|
||||
CookieOauthState = "godoxy_oidc_state"
|
||||
CookieOauthSessionID = "godoxy_session_id"
|
||||
CookieOauthToken = "godoxy_oauth_token"
|
||||
CookieOauthSessionToken = "godoxy_session_token"
|
||||
)
|
||||
@@ -49,7 +48,12 @@ const (
|
||||
OIDCLogoutPath = "/auth/logout"
|
||||
)
|
||||
|
||||
var errMissingIDToken = errors.New("missing id_token field from oauth token")
|
||||
var (
|
||||
errMissingIDToken = errors.New("missing id_token field from oauth token")
|
||||
|
||||
ErrMissingOAuthToken = gperr.New("missing oauth token")
|
||||
ErrInvalidOAuthToken = gperr.New("invalid oauth token")
|
||||
)
|
||||
|
||||
// generateState generates a random string for OIDC state.
|
||||
const oidcStateLength = 32
|
||||
@@ -62,7 +66,7 @@ func generateState() string {
|
||||
|
||||
func NewOIDCProvider(issuerURL, clientID, clientSecret string, allowedUsers, allowedGroups []string) (*OIDCProvider, error) {
|
||||
if len(allowedUsers)+len(allowedGroups) == 0 {
|
||||
return nil, errors.New("OIDC users, groups, or both must not be empty")
|
||||
return nil, errors.New("oidc.allowed_users or oidc.allowed_groups are both empty")
|
||||
}
|
||||
provider, err := oidc.NewProvider(context.Background(), issuerURL)
|
||||
if err != nil {
|
||||
@@ -84,7 +88,7 @@ func NewOIDCProvider(issuerURL, clientID, clientSecret string, allowedUsers, all
|
||||
ClientSecret: clientSecret,
|
||||
RedirectURL: "",
|
||||
Endpoint: provider.Endpoint(),
|
||||
Scopes: strutils.CommaSeperatedList(common.OIDCScopes),
|
||||
Scopes: common.OIDCScopes,
|
||||
},
|
||||
oidcProvider: provider,
|
||||
oidcVerifier: provider.Verifier(&oidc.Config{
|
||||
@@ -150,12 +154,19 @@ func (auth *OIDCProvider) HandleAuth(w http.ResponseWriter, r *http.Request) {
|
||||
func (auth *OIDCProvider) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// check for session token
|
||||
sessionToken, err := r.Cookie(CookieOauthSessionToken)
|
||||
if err == nil {
|
||||
err = auth.TryRefreshToken(w, r, sessionToken.Value)
|
||||
if err != nil {
|
||||
logging.Debug().Err(err).Msg("failed to refresh token")
|
||||
auth.clearCookie(w, r)
|
||||
if err == nil { // session token exists
|
||||
result, err := auth.TryRefreshToken(r.Context(), sessionToken.Value)
|
||||
// redirect back to where they requested
|
||||
// when token refresh is ok
|
||||
if err == nil {
|
||||
auth.setIDTokenCookie(w, r, result.jwt, time.Until(result.jwtExpiry))
|
||||
auth.setSessionTokenCookie(w, r, result.newSession)
|
||||
ProceedNext(w, r)
|
||||
return
|
||||
}
|
||||
// clear cookies then redirect to home
|
||||
logging.Err(err).Msg("failed to refresh token")
|
||||
auth.clearCookie(w, r)
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,22 +10,21 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMissingOAuthToken = gperr.New("missing oauth token")
|
||||
ErrMissingSessionToken = gperr.New("missing session token")
|
||||
ErrInvalidOAuthToken = gperr.New("invalid oauth token")
|
||||
ErrInvalidSessionToken = gperr.New("invalid session token")
|
||||
ErrUserNotAllowed = gperr.New("user not allowed")
|
||||
)
|
||||
|
||||
func IsFrontend(r *http.Request) bool {
|
||||
return r.Host == common.APIHTTPAddr
|
||||
}
|
||||
|
||||
func requestHost(r *http.Request) string {
|
||||
// check if it's from backend
|
||||
switch r.Host {
|
||||
case common.APIHTTPAddr:
|
||||
// use XFH
|
||||
if IsFrontend(r) {
|
||||
return r.Header.Get("X-Forwarded-Host")
|
||||
default:
|
||||
return r.Host
|
||||
}
|
||||
return r.Host
|
||||
}
|
||||
|
||||
// cookieDomain returns the fully qualified domain name of the request host
|
||||
|
||||
@@ -16,18 +16,15 @@ import (
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
)
|
||||
|
||||
type (
|
||||
AutocertConfig struct {
|
||||
Email string `json:"email,omitempty"`
|
||||
Domains []string `json:"domains,omitempty"`
|
||||
CertPath string `json:"cert_path,omitempty"`
|
||||
KeyPath string `json:"key_path,omitempty"`
|
||||
ACMEKeyPath string `json:"acme_key_path,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
Options ProviderOpt `json:"options,omitempty"`
|
||||
}
|
||||
ProviderOpt map[string]any
|
||||
)
|
||||
type Config struct {
|
||||
Email string `json:"email,omitempty"`
|
||||
Domains []string `json:"domains,omitempty"`
|
||||
CertPath string `json:"cert_path,omitempty"`
|
||||
KeyPath string `json:"key_path,omitempty"`
|
||||
ACMEKeyPath string `json:"acme_key_path,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
Options map[string]any `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
var (
|
||||
ErrMissingDomain = gperr.New("missing field 'domains'")
|
||||
@@ -37,10 +34,15 @@ var (
|
||||
ErrUnknownProvider = gperr.New("unknown provider")
|
||||
)
|
||||
|
||||
const (
|
||||
ProviderLocal = "local"
|
||||
ProviderPseudo = "pseudo"
|
||||
)
|
||||
|
||||
var domainOrWildcardRE = regexp.MustCompile(`^\*?([^.]+\.)+[^.]+$`)
|
||||
|
||||
// Validate implements the utils.CustomValidator interface.
|
||||
func (cfg *AutocertConfig) Validate() gperr.Error {
|
||||
func (cfg *Config) Validate() gperr.Error {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -64,11 +66,11 @@ func (cfg *AutocertConfig) Validate() gperr.Error {
|
||||
}
|
||||
}
|
||||
// check if provider is implemented
|
||||
providerConstructor, ok := providers[cfg.Provider]
|
||||
providerConstructor, ok := Providers[cfg.Provider]
|
||||
if !ok {
|
||||
b.Add(ErrUnknownProvider.
|
||||
Subject(cfg.Provider).
|
||||
Withf(strutils.DoYouMean(utils.NearestField(cfg.Provider, providers))))
|
||||
Withf(strutils.DoYouMean(utils.NearestField(cfg.Provider, Providers))))
|
||||
} else {
|
||||
_, err := providerConstructor(cfg.Options)
|
||||
if err != nil {
|
||||
@@ -79,13 +81,9 @@ func (cfg *AutocertConfig) Validate() gperr.Error {
|
||||
return b.Error()
|
||||
}
|
||||
|
||||
func (cfg *AutocertConfig) GetProvider() (*Provider, gperr.Error) {
|
||||
if cfg == nil {
|
||||
cfg = new(AutocertConfig)
|
||||
}
|
||||
|
||||
func (cfg *Config) GetLegoConfig() (*User, *lego.Config, gperr.Error) {
|
||||
if err := cfg.Validate(); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if cfg.CertPath == "" {
|
||||
@@ -102,35 +100,31 @@ func (cfg *AutocertConfig) GetProvider() (*Provider, gperr.Error) {
|
||||
var err error
|
||||
|
||||
if cfg.Provider != ProviderLocal && cfg.Provider != ProviderPseudo {
|
||||
if privKey, err = cfg.loadACMEKey(); err != nil {
|
||||
if privKey, err = cfg.LoadACMEKey(); err != nil {
|
||||
logging.Info().Err(err).Msg("load ACME private key failed")
|
||||
logging.Info().Msg("generate new ACME private key")
|
||||
privKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, gperr.New("generate ACME private key").With(err)
|
||||
return nil, nil, gperr.New("generate ACME private key").With(err)
|
||||
}
|
||||
if err = cfg.saveACMEKey(privKey); err != nil {
|
||||
return nil, gperr.New("save ACME private key").With(err)
|
||||
if err = cfg.SaveACMEKey(privKey); err != nil {
|
||||
return nil, nil, gperr.New("save ACME private key").With(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
user := &User{
|
||||
Email: cfg.Email,
|
||||
key: privKey,
|
||||
Key: privKey,
|
||||
}
|
||||
|
||||
legoCfg := lego.NewConfig(user)
|
||||
legoCfg.Certificate.KeyType = certcrypto.RSA2048
|
||||
|
||||
return &Provider{
|
||||
cfg: cfg,
|
||||
user: user,
|
||||
legoCfg: legoCfg,
|
||||
}, nil
|
||||
return user, legoCfg, nil
|
||||
}
|
||||
|
||||
func (cfg *AutocertConfig) loadACMEKey() (*ecdsa.PrivateKey, error) {
|
||||
func (cfg *Config) LoadACMEKey() (*ecdsa.PrivateKey, error) {
|
||||
data, err := os.ReadFile(cfg.ACMEKeyPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -138,7 +132,7 @@ func (cfg *AutocertConfig) loadACMEKey() (*ecdsa.PrivateKey, error) {
|
||||
return x509.ParseECPrivateKey(data)
|
||||
}
|
||||
|
||||
func (cfg *AutocertConfig) saveACMEKey(key *ecdsa.PrivateKey) error {
|
||||
func (cfg *Config) SaveACMEKey(key *ecdsa.PrivateKey) error {
|
||||
data, err := x509.MarshalECPrivateKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -13,19 +13,17 @@ import (
|
||||
"time"
|
||||
|
||||
"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/registration"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
U "github.com/yusing/go-proxy/internal/utils"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider struct {
|
||||
cfg *AutocertConfig
|
||||
cfg *Config
|
||||
user *User
|
||||
legoCfg *lego.Config
|
||||
client *lego.Client
|
||||
@@ -36,13 +34,20 @@ type (
|
||||
|
||||
obtainMu sync.Mutex
|
||||
}
|
||||
ProviderGenerator func(ProviderOpt) (challenge.Provider, gperr.Error)
|
||||
|
||||
CertExpiries map[string]time.Time
|
||||
)
|
||||
|
||||
var ErrGetCertFailure = errors.New("get certificate failed")
|
||||
|
||||
func NewProvider(cfg *Config, user *User, legoCfg *lego.Config) *Provider {
|
||||
return &Provider{
|
||||
cfg: cfg,
|
||||
user: user,
|
||||
legoCfg: legoCfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Provider) GetCert(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
if p.tlsCert == nil {
|
||||
return nil, ErrGetCertFailure
|
||||
@@ -205,7 +210,7 @@ func (p *Provider) initClient() error {
|
||||
return err
|
||||
}
|
||||
|
||||
generator := providers[p.cfg.Provider]
|
||||
generator := Providers[p.cfg.Provider]
|
||||
legoProvider, pErr := generator(p.cfg.Options)
|
||||
if pErr != nil {
|
||||
return pErr
|
||||
@@ -322,18 +327,3 @@ func getCertExpiries(cert *tls.Certificate) (CertExpiries, error) {
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func providerGenerator[CT any, PT challenge.Provider](
|
||||
defaultCfg func() *CT,
|
||||
newProvider func(*CT) (PT, error),
|
||||
) ProviderGenerator {
|
||||
return func(opt ProviderOpt) (challenge.Provider, gperr.Error) {
|
||||
cfg := defaultCfg()
|
||||
err := U.Deserialize(opt, &cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p, pErr := newProvider(cfg)
|
||||
return p, gperr.Wrap(pErr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/ovh"
|
||||
"github.com/goccy/go-yaml"
|
||||
U "github.com/yusing/go-proxy/internal/utils"
|
||||
. "github.com/yusing/go-proxy/internal/utils/testing"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
)
|
||||
|
||||
// type Config struct {
|
||||
@@ -44,7 +44,7 @@ oauth2_config:
|
||||
}
|
||||
testYaml = testYaml[1:] // remove first \n
|
||||
opt := make(map[string]any)
|
||||
ExpectNoError(t, yaml.Unmarshal([]byte(testYaml), &opt))
|
||||
ExpectNoError(t, U.Deserialize(opt, cfg))
|
||||
ExpectEqual(t, cfg, cfgExpected)
|
||||
require.NoError(t, yaml.Unmarshal([]byte(testYaml), &opt))
|
||||
require.NoError(t, utils.Deserialize(opt, cfg))
|
||||
require.Equal(t, cfg, cfgExpected)
|
||||
}
|
||||
|
||||
@@ -1,452 +1,26 @@
|
||||
//go:generate /usr/bin/python3 gen.py
|
||||
|
||||
package autocert
|
||||
|
||||
import "github.com/go-acme/lego/v4/providers/dns/acmedns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/active24"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/alidns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/allinkl"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/arvancloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/auroradns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/autodns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/axelname"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/azuredns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/baiducloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/bindman"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/bluecat"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/bookmyname"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/bunny"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/checkdomain"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/civo"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/clouddns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/cloudflare"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/cloudns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/cloudru"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/conoha"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/constellix"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/corenetworks"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/cpanel"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/derak"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/desec"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/designate"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/digitalocean"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/directadmin"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/dnshomede"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/dnsimple"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/dnsmadeeasy"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/dode"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/domeneshop"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/dreamhost"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/duckdns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/dyn"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/dynu"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/easydns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/edgedns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/efficientip"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/epik"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/exec"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/exoscale"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/f5xc"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/freemyip"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/gandi"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/gandiv5"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/gcloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/gcore"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/glesys"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/godaddy"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/googledomains"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/hetzner"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/hostingde"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/hosttech"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/httpnet"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/httpreq"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/huaweicloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/hurricane"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/hyperone"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/ibmcloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/iij"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/iijdpf"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/infoblox"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/infomaniak"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/internetbs"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/inwx"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/ionos"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/ipv64"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/iwantmyname"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/joker"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/liara"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/lightsail"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/limacity"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/linode"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/liquidweb"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/loopia"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/luadns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/mailinabox"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/manageengine"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/metaname"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/metaregistrar"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/mijnhost"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/mittwald"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/myaddr"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/mydnsjp"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/namecheap"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/namedotcom"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/namesilo"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/nearlyfreespeech"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/netcup"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/netlify"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/nicmanager"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/nifcloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/njalla"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/nodion"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/ns1"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/oraclecloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/otc"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/ovh"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/pdns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/plesk"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/porkbun"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/rackspace"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/rainyun"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/rcodezero"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/regfish"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/regru"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/rfc2136"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/rimuhosting"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/route53"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/safedns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/sakuracloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/scaleway"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/selectel"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/selectelv2"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/selfhostde"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/servercow"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/shellrent"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/simply"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/sonic"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/spaceship"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/stackpath"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/technitium"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/tencentcloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/timewebcloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/transip"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/ultradns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/variomedia"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/vegadns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/vercel"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/versio"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/vinyldns"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/vkcloud"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/volcengine"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/vscale"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/vultr"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/webnames"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/websupport"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/wedos"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/westcn"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/yandex"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/yandex360"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/zoneee"
|
||||
import "github.com/go-acme/lego/v4/providers/dns/zonomi"
|
||||
|
||||
const (
|
||||
ProviderLocal = "local"
|
||||
ProviderPseudo = "pseudo"
|
||||
Provideracmedns = "acmedns"
|
||||
Provideractive24 = "active24"
|
||||
Provideralidns = "alidns"
|
||||
Providerallinkl = "allinkl"
|
||||
Providerarvancloud = "arvancloud"
|
||||
Providerauroradns = "auroradns"
|
||||
Providerautodns = "autodns"
|
||||
Provideraxelname = "axelname"
|
||||
Providerazuredns = "azuredns"
|
||||
Providerbaiducloud = "baiducloud"
|
||||
Providerbindman = "bindman"
|
||||
Providerbluecat = "bluecat"
|
||||
Providerbookmyname = "bookmyname"
|
||||
Providerbunny = "bunny"
|
||||
Providercheckdomain = "checkdomain"
|
||||
Providercivo = "civo"
|
||||
Providerclouddns = "clouddns"
|
||||
Providercloudflare = "cloudflare"
|
||||
Providercloudns = "cloudns"
|
||||
Providercloudru = "cloudru"
|
||||
Providerconoha = "conoha"
|
||||
Providerconstellix = "constellix"
|
||||
Providercorenetworks = "corenetworks"
|
||||
Providercpanel = "cpanel"
|
||||
Providerderak = "derak"
|
||||
Providerdesec = "desec"
|
||||
Providerdesignate = "designate"
|
||||
Providerdigitalocean = "digitalocean"
|
||||
Providerdirectadmin = "directadmin"
|
||||
Providerdnshomede = "dnshomede"
|
||||
Providerdnsimple = "dnsimple"
|
||||
Providerdnsmadeeasy = "dnsmadeeasy"
|
||||
Providerdode = "dode"
|
||||
Providerdomeneshop = "domeneshop"
|
||||
Providerdreamhost = "dreamhost"
|
||||
Providerduckdns = "duckdns"
|
||||
Providerdyn = "dyn"
|
||||
Providerdynu = "dynu"
|
||||
Providereasydns = "easydns"
|
||||
Provideredgedns = "edgedns"
|
||||
Providerefficientip = "efficientip"
|
||||
Providerepik = "epik"
|
||||
Providerexec = "exec"
|
||||
Providerexoscale = "exoscale"
|
||||
Providerf5xc = "f5xc"
|
||||
Providerfreemyip = "freemyip"
|
||||
Providergandi = "gandi"
|
||||
Providergandiv5 = "gandiv5"
|
||||
Providergcloud = "gcloud"
|
||||
Providergcore = "gcore"
|
||||
Providerglesys = "glesys"
|
||||
Providergodaddy = "godaddy"
|
||||
Providergoogledomains = "googledomains"
|
||||
Providerhetzner = "hetzner"
|
||||
Providerhostingde = "hostingde"
|
||||
Providerhosttech = "hosttech"
|
||||
Providerhttpnet = "httpnet"
|
||||
Providerhttpreq = "httpreq"
|
||||
Providerhuaweicloud = "huaweicloud"
|
||||
Providerhurricane = "hurricane"
|
||||
Providerhyperone = "hyperone"
|
||||
Provideribmcloud = "ibmcloud"
|
||||
Provideriij = "iij"
|
||||
Provideriijdpf = "iijdpf"
|
||||
Providerinfoblox = "infoblox"
|
||||
Providerinfomaniak = "infomaniak"
|
||||
Providerinternetbs = "internetbs"
|
||||
Providerinwx = "inwx"
|
||||
Providerionos = "ionos"
|
||||
Provideripv64 = "ipv64"
|
||||
Provideriwantmyname = "iwantmyname"
|
||||
Providerjoker = "joker"
|
||||
Providerliara = "liara"
|
||||
Providerlightsail = "lightsail"
|
||||
Providerlimacity = "limacity"
|
||||
Providerlinode = "linode"
|
||||
Providerliquidweb = "liquidweb"
|
||||
Providerloopia = "loopia"
|
||||
Providerluadns = "luadns"
|
||||
Providermailinabox = "mailinabox"
|
||||
Providermanageengine = "manageengine"
|
||||
Providermetaname = "metaname"
|
||||
Providermetaregistrar = "metaregistrar"
|
||||
Providermijnhost = "mijnhost"
|
||||
Providermittwald = "mittwald"
|
||||
Providermyaddr = "myaddr"
|
||||
Providermydnsjp = "mydnsjp"
|
||||
Providernamecheap = "namecheap"
|
||||
Providernamedotcom = "namedotcom"
|
||||
Providernamesilo = "namesilo"
|
||||
Providernearlyfreespeech = "nearlyfreespeech"
|
||||
Providernetcup = "netcup"
|
||||
Providernetlify = "netlify"
|
||||
Providernicmanager = "nicmanager"
|
||||
Providernifcloud = "nifcloud"
|
||||
Providernjalla = "njalla"
|
||||
Providernodion = "nodion"
|
||||
Providerns1 = "ns1"
|
||||
Provideroraclecloud = "oraclecloud"
|
||||
Providerotc = "otc"
|
||||
Providerovh = "ovh"
|
||||
Providerpdns = "pdns"
|
||||
Providerplesk = "plesk"
|
||||
Providerporkbun = "porkbun"
|
||||
Providerrackspace = "rackspace"
|
||||
Providerrainyun = "rainyun"
|
||||
Providerrcodezero = "rcodezero"
|
||||
Providerregfish = "regfish"
|
||||
Providerregru = "regru"
|
||||
Providerrfc2136 = "rfc2136"
|
||||
Providerrimuhosting = "rimuhosting"
|
||||
Providerroute53 = "route53"
|
||||
Providersafedns = "safedns"
|
||||
Providersakuracloud = "sakuracloud"
|
||||
Providerscaleway = "scaleway"
|
||||
Providerselectel = "selectel"
|
||||
Providerselectelv2 = "selectelv2"
|
||||
Providerselfhostde = "selfhostde"
|
||||
Providerservercow = "servercow"
|
||||
Providershellrent = "shellrent"
|
||||
Providersimply = "simply"
|
||||
Providersonic = "sonic"
|
||||
Providerspaceship = "spaceship"
|
||||
Providerstackpath = "stackpath"
|
||||
Providertechnitium = "technitium"
|
||||
Providertencentcloud = "tencentcloud"
|
||||
Providertimewebcloud = "timewebcloud"
|
||||
Providertransip = "transip"
|
||||
Providerultradns = "ultradns"
|
||||
Providervariomedia = "variomedia"
|
||||
Providervegadns = "vegadns"
|
||||
Providervercel = "vercel"
|
||||
Providerversio = "versio"
|
||||
Providervinyldns = "vinyldns"
|
||||
Providervkcloud = "vkcloud"
|
||||
Providervolcengine = "volcengine"
|
||||
Providervscale = "vscale"
|
||||
Providervultr = "vultr"
|
||||
Providerwebnames = "webnames"
|
||||
Providerwebsupport = "websupport"
|
||||
Providerwedos = "wedos"
|
||||
Providerwestcn = "westcn"
|
||||
Provideryandex = "yandex"
|
||||
Provideryandex360 = "yandex360"
|
||||
Providerzoneee = "zoneee"
|
||||
Providerzonomi = "zonomi"
|
||||
import (
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
)
|
||||
|
||||
var providers = map[string]ProviderGenerator{
|
||||
ProviderLocal: providerGenerator(NewDummyDefaultConfig, NewDummyDNSProviderConfig),
|
||||
ProviderPseudo: providerGenerator(NewDummyDefaultConfig, NewDummyDNSProviderConfig),
|
||||
Provideracmedns: providerGenerator(acmedns.NewDefaultConfig, acmedns.NewDNSProviderConfig),
|
||||
Provideractive24: providerGenerator(active24.NewDefaultConfig, active24.NewDNSProviderConfig),
|
||||
Provideralidns: providerGenerator(alidns.NewDefaultConfig, alidns.NewDNSProviderConfig),
|
||||
Providerallinkl: providerGenerator(allinkl.NewDefaultConfig, allinkl.NewDNSProviderConfig),
|
||||
Providerarvancloud: providerGenerator(arvancloud.NewDefaultConfig, arvancloud.NewDNSProviderConfig),
|
||||
Providerauroradns: providerGenerator(auroradns.NewDefaultConfig, auroradns.NewDNSProviderConfig),
|
||||
Providerautodns: providerGenerator(autodns.NewDefaultConfig, autodns.NewDNSProviderConfig),
|
||||
Provideraxelname: providerGenerator(axelname.NewDefaultConfig, axelname.NewDNSProviderConfig),
|
||||
Providerazuredns: providerGenerator(azuredns.NewDefaultConfig, azuredns.NewDNSProviderConfig),
|
||||
Providerbaiducloud: providerGenerator(baiducloud.NewDefaultConfig, baiducloud.NewDNSProviderConfig),
|
||||
Providerbindman: providerGenerator(bindman.NewDefaultConfig, bindman.NewDNSProviderConfig),
|
||||
Providerbluecat: providerGenerator(bluecat.NewDefaultConfig, bluecat.NewDNSProviderConfig),
|
||||
Providerbookmyname: providerGenerator(bookmyname.NewDefaultConfig, bookmyname.NewDNSProviderConfig),
|
||||
Providerbunny: providerGenerator(bunny.NewDefaultConfig, bunny.NewDNSProviderConfig),
|
||||
Providercheckdomain: providerGenerator(checkdomain.NewDefaultConfig, checkdomain.NewDNSProviderConfig),
|
||||
Providercivo: providerGenerator(civo.NewDefaultConfig, civo.NewDNSProviderConfig),
|
||||
Providerclouddns: providerGenerator(clouddns.NewDefaultConfig, clouddns.NewDNSProviderConfig),
|
||||
Providercloudflare: providerGenerator(cloudflare.NewDefaultConfig, cloudflare.NewDNSProviderConfig),
|
||||
Providercloudns: providerGenerator(cloudns.NewDefaultConfig, cloudns.NewDNSProviderConfig),
|
||||
Providercloudru: providerGenerator(cloudru.NewDefaultConfig, cloudru.NewDNSProviderConfig),
|
||||
Providerconoha: providerGenerator(conoha.NewDefaultConfig, conoha.NewDNSProviderConfig),
|
||||
Providerconstellix: providerGenerator(constellix.NewDefaultConfig, constellix.NewDNSProviderConfig),
|
||||
Providercorenetworks: providerGenerator(corenetworks.NewDefaultConfig, corenetworks.NewDNSProviderConfig),
|
||||
Providercpanel: providerGenerator(cpanel.NewDefaultConfig, cpanel.NewDNSProviderConfig),
|
||||
Providerderak: providerGenerator(derak.NewDefaultConfig, derak.NewDNSProviderConfig),
|
||||
Providerdesec: providerGenerator(desec.NewDefaultConfig, desec.NewDNSProviderConfig),
|
||||
Providerdesignate: providerGenerator(designate.NewDefaultConfig, designate.NewDNSProviderConfig),
|
||||
Providerdigitalocean: providerGenerator(digitalocean.NewDefaultConfig, digitalocean.NewDNSProviderConfig),
|
||||
Providerdirectadmin: providerGenerator(directadmin.NewDefaultConfig, directadmin.NewDNSProviderConfig),
|
||||
Providerdnshomede: providerGenerator(dnshomede.NewDefaultConfig, dnshomede.NewDNSProviderConfig),
|
||||
Providerdnsimple: providerGenerator(dnsimple.NewDefaultConfig, dnsimple.NewDNSProviderConfig),
|
||||
Providerdnsmadeeasy: providerGenerator(dnsmadeeasy.NewDefaultConfig, dnsmadeeasy.NewDNSProviderConfig),
|
||||
Providerdode: providerGenerator(dode.NewDefaultConfig, dode.NewDNSProviderConfig),
|
||||
Providerdomeneshop: providerGenerator(domeneshop.NewDefaultConfig, domeneshop.NewDNSProviderConfig),
|
||||
Providerdreamhost: providerGenerator(dreamhost.NewDefaultConfig, dreamhost.NewDNSProviderConfig),
|
||||
Providerduckdns: providerGenerator(duckdns.NewDefaultConfig, duckdns.NewDNSProviderConfig),
|
||||
Providerdyn: providerGenerator(dyn.NewDefaultConfig, dyn.NewDNSProviderConfig),
|
||||
Providerdynu: providerGenerator(dynu.NewDefaultConfig, dynu.NewDNSProviderConfig),
|
||||
Providereasydns: providerGenerator(easydns.NewDefaultConfig, easydns.NewDNSProviderConfig),
|
||||
Provideredgedns: providerGenerator(edgedns.NewDefaultConfig, edgedns.NewDNSProviderConfig),
|
||||
Providerefficientip: providerGenerator(efficientip.NewDefaultConfig, efficientip.NewDNSProviderConfig),
|
||||
Providerepik: providerGenerator(epik.NewDefaultConfig, epik.NewDNSProviderConfig),
|
||||
Providerexec: providerGenerator(exec.NewDefaultConfig, exec.NewDNSProviderConfig),
|
||||
Providerexoscale: providerGenerator(exoscale.NewDefaultConfig, exoscale.NewDNSProviderConfig),
|
||||
Providerf5xc: providerGenerator(f5xc.NewDefaultConfig, f5xc.NewDNSProviderConfig),
|
||||
Providerfreemyip: providerGenerator(freemyip.NewDefaultConfig, freemyip.NewDNSProviderConfig),
|
||||
Providergandi: providerGenerator(gandi.NewDefaultConfig, gandi.NewDNSProviderConfig),
|
||||
Providergandiv5: providerGenerator(gandiv5.NewDefaultConfig, gandiv5.NewDNSProviderConfig),
|
||||
Providergcloud: providerGenerator(gcloud.NewDefaultConfig, gcloud.NewDNSProviderConfig),
|
||||
Providergcore: providerGenerator(gcore.NewDefaultConfig, gcore.NewDNSProviderConfig),
|
||||
Providerglesys: providerGenerator(glesys.NewDefaultConfig, glesys.NewDNSProviderConfig),
|
||||
Providergodaddy: providerGenerator(godaddy.NewDefaultConfig, godaddy.NewDNSProviderConfig),
|
||||
Providergoogledomains: providerGenerator(googledomains.NewDefaultConfig, googledomains.NewDNSProviderConfig),
|
||||
Providerhetzner: providerGenerator(hetzner.NewDefaultConfig, hetzner.NewDNSProviderConfig),
|
||||
Providerhostingde: providerGenerator(hostingde.NewDefaultConfig, hostingde.NewDNSProviderConfig),
|
||||
Providerhosttech: providerGenerator(hosttech.NewDefaultConfig, hosttech.NewDNSProviderConfig),
|
||||
Providerhttpnet: providerGenerator(httpnet.NewDefaultConfig, httpnet.NewDNSProviderConfig),
|
||||
Providerhttpreq: providerGenerator(httpreq.NewDefaultConfig, httpreq.NewDNSProviderConfig),
|
||||
Providerhuaweicloud: providerGenerator(huaweicloud.NewDefaultConfig, huaweicloud.NewDNSProviderConfig),
|
||||
Providerhurricane: providerGenerator(hurricane.NewDefaultConfig, hurricane.NewDNSProviderConfig),
|
||||
Providerhyperone: providerGenerator(hyperone.NewDefaultConfig, hyperone.NewDNSProviderConfig),
|
||||
Provideribmcloud: providerGenerator(ibmcloud.NewDefaultConfig, ibmcloud.NewDNSProviderConfig),
|
||||
Provideriij: providerGenerator(iij.NewDefaultConfig, iij.NewDNSProviderConfig),
|
||||
Provideriijdpf: providerGenerator(iijdpf.NewDefaultConfig, iijdpf.NewDNSProviderConfig),
|
||||
Providerinfoblox: providerGenerator(infoblox.NewDefaultConfig, infoblox.NewDNSProviderConfig),
|
||||
Providerinfomaniak: providerGenerator(infomaniak.NewDefaultConfig, infomaniak.NewDNSProviderConfig),
|
||||
Providerinternetbs: providerGenerator(internetbs.NewDefaultConfig, internetbs.NewDNSProviderConfig),
|
||||
Providerinwx: providerGenerator(inwx.NewDefaultConfig, inwx.NewDNSProviderConfig),
|
||||
Providerionos: providerGenerator(ionos.NewDefaultConfig, ionos.NewDNSProviderConfig),
|
||||
Provideripv64: providerGenerator(ipv64.NewDefaultConfig, ipv64.NewDNSProviderConfig),
|
||||
Provideriwantmyname: providerGenerator(iwantmyname.NewDefaultConfig, iwantmyname.NewDNSProviderConfig),
|
||||
Providerjoker: providerGenerator(joker.NewDefaultConfig, joker.NewDNSProviderConfig),
|
||||
Providerliara: providerGenerator(liara.NewDefaultConfig, liara.NewDNSProviderConfig),
|
||||
Providerlightsail: providerGenerator(lightsail.NewDefaultConfig, lightsail.NewDNSProviderConfig),
|
||||
Providerlimacity: providerGenerator(limacity.NewDefaultConfig, limacity.NewDNSProviderConfig),
|
||||
Providerlinode: providerGenerator(linode.NewDefaultConfig, linode.NewDNSProviderConfig),
|
||||
Providerliquidweb: providerGenerator(liquidweb.NewDefaultConfig, liquidweb.NewDNSProviderConfig),
|
||||
Providerloopia: providerGenerator(loopia.NewDefaultConfig, loopia.NewDNSProviderConfig),
|
||||
Providerluadns: providerGenerator(luadns.NewDefaultConfig, luadns.NewDNSProviderConfig),
|
||||
Providermailinabox: providerGenerator(mailinabox.NewDefaultConfig, mailinabox.NewDNSProviderConfig),
|
||||
Providermanageengine: providerGenerator(manageengine.NewDefaultConfig, manageengine.NewDNSProviderConfig),
|
||||
Providermetaname: providerGenerator(metaname.NewDefaultConfig, metaname.NewDNSProviderConfig),
|
||||
Providermetaregistrar: providerGenerator(metaregistrar.NewDefaultConfig, metaregistrar.NewDNSProviderConfig),
|
||||
Providermijnhost: providerGenerator(mijnhost.NewDefaultConfig, mijnhost.NewDNSProviderConfig),
|
||||
Providermittwald: providerGenerator(mittwald.NewDefaultConfig, mittwald.NewDNSProviderConfig),
|
||||
Providermyaddr: providerGenerator(myaddr.NewDefaultConfig, myaddr.NewDNSProviderConfig),
|
||||
Providermydnsjp: providerGenerator(mydnsjp.NewDefaultConfig, mydnsjp.NewDNSProviderConfig),
|
||||
Providernamecheap: providerGenerator(namecheap.NewDefaultConfig, namecheap.NewDNSProviderConfig),
|
||||
Providernamedotcom: providerGenerator(namedotcom.NewDefaultConfig, namedotcom.NewDNSProviderConfig),
|
||||
Providernamesilo: providerGenerator(namesilo.NewDefaultConfig, namesilo.NewDNSProviderConfig),
|
||||
Providernearlyfreespeech: providerGenerator(nearlyfreespeech.NewDefaultConfig, nearlyfreespeech.NewDNSProviderConfig),
|
||||
Providernetcup: providerGenerator(netcup.NewDefaultConfig, netcup.NewDNSProviderConfig),
|
||||
Providernetlify: providerGenerator(netlify.NewDefaultConfig, netlify.NewDNSProviderConfig),
|
||||
Providernicmanager: providerGenerator(nicmanager.NewDefaultConfig, nicmanager.NewDNSProviderConfig),
|
||||
Providernifcloud: providerGenerator(nifcloud.NewDefaultConfig, nifcloud.NewDNSProviderConfig),
|
||||
Providernjalla: providerGenerator(njalla.NewDefaultConfig, njalla.NewDNSProviderConfig),
|
||||
Providernodion: providerGenerator(nodion.NewDefaultConfig, nodion.NewDNSProviderConfig),
|
||||
Providerns1: providerGenerator(ns1.NewDefaultConfig, ns1.NewDNSProviderConfig),
|
||||
Provideroraclecloud: providerGenerator(oraclecloud.NewDefaultConfig, oraclecloud.NewDNSProviderConfig),
|
||||
Providerotc: providerGenerator(otc.NewDefaultConfig, otc.NewDNSProviderConfig),
|
||||
Providerovh: providerGenerator(ovh.NewDefaultConfig, ovh.NewDNSProviderConfig),
|
||||
Providerpdns: providerGenerator(pdns.NewDefaultConfig, pdns.NewDNSProviderConfig),
|
||||
Providerplesk: providerGenerator(plesk.NewDefaultConfig, plesk.NewDNSProviderConfig),
|
||||
Providerporkbun: providerGenerator(porkbun.NewDefaultConfig, porkbun.NewDNSProviderConfig),
|
||||
Providerrackspace: providerGenerator(rackspace.NewDefaultConfig, rackspace.NewDNSProviderConfig),
|
||||
Providerrainyun: providerGenerator(rainyun.NewDefaultConfig, rainyun.NewDNSProviderConfig),
|
||||
Providerrcodezero: providerGenerator(rcodezero.NewDefaultConfig, rcodezero.NewDNSProviderConfig),
|
||||
Providerregfish: providerGenerator(regfish.NewDefaultConfig, regfish.NewDNSProviderConfig),
|
||||
Providerregru: providerGenerator(regru.NewDefaultConfig, regru.NewDNSProviderConfig),
|
||||
Providerrfc2136: providerGenerator(rfc2136.NewDefaultConfig, rfc2136.NewDNSProviderConfig),
|
||||
Providerrimuhosting: providerGenerator(rimuhosting.NewDefaultConfig, rimuhosting.NewDNSProviderConfig),
|
||||
Providerroute53: providerGenerator(route53.NewDefaultConfig, route53.NewDNSProviderConfig),
|
||||
Providersafedns: providerGenerator(safedns.NewDefaultConfig, safedns.NewDNSProviderConfig),
|
||||
Providersakuracloud: providerGenerator(sakuracloud.NewDefaultConfig, sakuracloud.NewDNSProviderConfig),
|
||||
Providerscaleway: providerGenerator(scaleway.NewDefaultConfig, scaleway.NewDNSProviderConfig),
|
||||
Providerselectel: providerGenerator(selectel.NewDefaultConfig, selectel.NewDNSProviderConfig),
|
||||
Providerselectelv2: providerGenerator(selectelv2.NewDefaultConfig, selectelv2.NewDNSProviderConfig),
|
||||
Providerselfhostde: providerGenerator(selfhostde.NewDefaultConfig, selfhostde.NewDNSProviderConfig),
|
||||
Providerservercow: providerGenerator(servercow.NewDefaultConfig, servercow.NewDNSProviderConfig),
|
||||
Providershellrent: providerGenerator(shellrent.NewDefaultConfig, shellrent.NewDNSProviderConfig),
|
||||
Providersimply: providerGenerator(simply.NewDefaultConfig, simply.NewDNSProviderConfig),
|
||||
Providersonic: providerGenerator(sonic.NewDefaultConfig, sonic.NewDNSProviderConfig),
|
||||
Providerspaceship: providerGenerator(spaceship.NewDefaultConfig, spaceship.NewDNSProviderConfig),
|
||||
Providerstackpath: providerGenerator(stackpath.NewDefaultConfig, stackpath.NewDNSProviderConfig),
|
||||
Providertechnitium: providerGenerator(technitium.NewDefaultConfig, technitium.NewDNSProviderConfig),
|
||||
Providertencentcloud: providerGenerator(tencentcloud.NewDefaultConfig, tencentcloud.NewDNSProviderConfig),
|
||||
Providertimewebcloud: providerGenerator(timewebcloud.NewDefaultConfig, timewebcloud.NewDNSProviderConfig),
|
||||
Providertransip: providerGenerator(transip.NewDefaultConfig, transip.NewDNSProviderConfig),
|
||||
Providerultradns: providerGenerator(ultradns.NewDefaultConfig, ultradns.NewDNSProviderConfig),
|
||||
Providervariomedia: providerGenerator(variomedia.NewDefaultConfig, variomedia.NewDNSProviderConfig),
|
||||
Providervegadns: providerGenerator(vegadns.NewDefaultConfig, vegadns.NewDNSProviderConfig),
|
||||
Providervercel: providerGenerator(vercel.NewDefaultConfig, vercel.NewDNSProviderConfig),
|
||||
Providerversio: providerGenerator(versio.NewDefaultConfig, versio.NewDNSProviderConfig),
|
||||
Providervinyldns: providerGenerator(vinyldns.NewDefaultConfig, vinyldns.NewDNSProviderConfig),
|
||||
Providervkcloud: providerGenerator(vkcloud.NewDefaultConfig, vkcloud.NewDNSProviderConfig),
|
||||
Providervolcengine: providerGenerator(volcengine.NewDefaultConfig, volcengine.NewDNSProviderConfig),
|
||||
Providervscale: providerGenerator(vscale.NewDefaultConfig, vscale.NewDNSProviderConfig),
|
||||
Providervultr: providerGenerator(vultr.NewDefaultConfig, vultr.NewDNSProviderConfig),
|
||||
Providerwebnames: providerGenerator(webnames.NewDefaultConfig, webnames.NewDNSProviderConfig),
|
||||
Providerwebsupport: providerGenerator(websupport.NewDefaultConfig, websupport.NewDNSProviderConfig),
|
||||
Providerwedos: providerGenerator(wedos.NewDefaultConfig, wedos.NewDNSProviderConfig),
|
||||
Providerwestcn: providerGenerator(westcn.NewDefaultConfig, westcn.NewDNSProviderConfig),
|
||||
Provideryandex: providerGenerator(yandex.NewDefaultConfig, yandex.NewDNSProviderConfig),
|
||||
Provideryandex360: providerGenerator(yandex360.NewDefaultConfig, yandex360.NewDNSProviderConfig),
|
||||
Providerzoneee: providerGenerator(zoneee.NewDefaultConfig, zoneee.NewDNSProviderConfig),
|
||||
Providerzonomi: providerGenerator(zonomi.NewDefaultConfig, zonomi.NewDNSProviderConfig),
|
||||
type Generator func(map[string]any) (challenge.Provider, gperr.Error)
|
||||
|
||||
var Providers = make(map[string]Generator)
|
||||
|
||||
func DNSProvider[CT any, PT challenge.Provider](
|
||||
defaultCfg func() *CT,
|
||||
newProvider func(*CT) (PT, error),
|
||||
) Generator {
|
||||
return func(opt map[string]any) (challenge.Provider, gperr.Error) {
|
||||
cfg := defaultCfg()
|
||||
err := utils.Deserialize(opt, &cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p, pErr := newProvider(cfg)
|
||||
return p, gperr.Wrap(pErr)
|
||||
}
|
||||
}
|
||||
|
||||
14
internal/autocert/types/provider.go
Normal file
14
internal/autocert/types/provider.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package autocert
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
)
|
||||
|
||||
type Provider interface {
|
||||
Setup() error
|
||||
GetCert(*tls.ClientHelloInfo) (*tls.Certificate, error)
|
||||
ScheduleRenewal(task.Parent)
|
||||
ObtainCert() error
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
type User struct {
|
||||
Email string
|
||||
Registration *registration.Resource
|
||||
key crypto.PrivateKey
|
||||
Key crypto.PrivateKey
|
||||
}
|
||||
|
||||
func (u *User) GetEmail() string {
|
||||
@@ -21,5 +21,5 @@ func (u *User) GetRegistration() *registration.Resource {
|
||||
}
|
||||
|
||||
func (u *User) GetPrivateKey() crypto.PrivateKey {
|
||||
return u.key
|
||||
return u.Key
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ const (
|
||||
ConfigPath = ConfigBasePath + "/" + ConfigFileName
|
||||
|
||||
IconListCachePath = ConfigBasePath + "/.icon_list_cache.json"
|
||||
IconCachePath = ConfigBasePath + "/.icon_cache.json"
|
||||
|
||||
NamespaceHomepageOverrides = ".homepage"
|
||||
NamespaceIconCache = ".icon_cache"
|
||||
@@ -29,8 +28,6 @@ const (
|
||||
DataDir = "data"
|
||||
|
||||
ErrorPagesBasePath = "error_pages"
|
||||
|
||||
AgentCertsBasePath = "certs"
|
||||
)
|
||||
|
||||
var RequiredDirectories = []string{
|
||||
|
||||
@@ -48,7 +48,7 @@ var (
|
||||
OIDCIssuerURL = GetEnvString("OIDC_ISSUER_URL", "")
|
||||
OIDCClientID = GetEnvString("OIDC_CLIENT_ID", "")
|
||||
OIDCClientSecret = GetEnvString("OIDC_CLIENT_SECRET", "")
|
||||
OIDCScopes = GetEnvString("OIDC_SCOPES", "openid, profile, email")
|
||||
OIDCScopes = GetCommaSepEnv("OIDC_SCOPES", "openid, profile, email, groups")
|
||||
OIDCAllowedUsers = GetCommaSepEnv("OIDC_ALLOWED_USERS", "")
|
||||
OIDCAllowedGroups = GetCommaSepEnv("OIDC_ALLOWED_GROUPS", "")
|
||||
|
||||
@@ -58,6 +58,8 @@ var (
|
||||
MetricsDisableDisk = GetEnvBool("METRICS_DISABLE_DISK", false)
|
||||
MetricsDisableNetwork = GetEnvBool("METRICS_DISABLE_NETWORK", false)
|
||||
MetricsDisableSensors = GetEnvBool("METRICS_DISABLE_SENSORS", false)
|
||||
|
||||
ForceResolveCountry = GetEnvBool("FORCE_RESOLVE_COUNTRY", false)
|
||||
)
|
||||
|
||||
func GetEnv[T any](key string, defaultValue T, parser func(string) (T, error)) T {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/api"
|
||||
"github.com/yusing/go-proxy/internal/autocert"
|
||||
autocert "github.com/yusing/go-proxy/internal/autocert"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
config "github.com/yusing/go-proxy/internal/config/types"
|
||||
"github.com/yusing/go-proxy/internal/entrypoint"
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp/server"
|
||||
"github.com/yusing/go-proxy/internal/notif"
|
||||
"github.com/yusing/go-proxy/internal/proxmox"
|
||||
proxy "github.com/yusing/go-proxy/internal/route/provider"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
@@ -229,6 +230,7 @@ func (cfg *Config) load() gperr.Error {
|
||||
errs.Add(cfg.entrypoint.SetAccessLogger(cfg.task, model.Entrypoint.AccessLog))
|
||||
cfg.initNotification(model.Providers.Notification)
|
||||
errs.Add(cfg.initAutoCert(model.AutoCert))
|
||||
errs.Add(cfg.initProxmox(model.Providers.Proxmox))
|
||||
errs.Add(cfg.loadRouteProviders(&model.Providers))
|
||||
|
||||
cfg.value = model
|
||||
@@ -260,13 +262,33 @@ func (cfg *Config) initNotification(notifCfg []notif.NotificationConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *Config) initAutoCert(autocertCfg *autocert.AutocertConfig) (err gperr.Error) {
|
||||
func (cfg *Config) initAutoCert(autocertCfg *autocert.Config) gperr.Error {
|
||||
if cfg.autocertProvider != nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
cfg.autocertProvider, err = autocertCfg.GetProvider()
|
||||
return
|
||||
if autocertCfg == nil {
|
||||
autocertCfg = new(autocert.Config)
|
||||
}
|
||||
|
||||
user, legoCfg, err := autocertCfg.GetLegoConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg.autocertProvider = autocert.NewProvider(autocertCfg, user, legoCfg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *Config) initProxmox(proxmoxCfg []proxmox.Config) gperr.Error {
|
||||
proxmox.Clients.Clear()
|
||||
var errs = gperr.NewBuilder()
|
||||
for _, cfg := range proxmoxCfg {
|
||||
if err := cfg.Init(); err != nil {
|
||||
errs.Add(err.Subject(cfg.URL))
|
||||
}
|
||||
}
|
||||
return errs.Error()
|
||||
}
|
||||
|
||||
func (cfg *Config) errIfExists(p *proxy.Provider) gperr.Error {
|
||||
|
||||
@@ -12,24 +12,26 @@ import (
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/logging/accesslog"
|
||||
"github.com/yusing/go-proxy/internal/notif"
|
||||
"github.com/yusing/go-proxy/internal/proxmox"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
)
|
||||
|
||||
type (
|
||||
Config struct {
|
||||
ACL *acl.Config `json:"acl"`
|
||||
AutoCert *autocert.AutocertConfig `json:"autocert"`
|
||||
Entrypoint Entrypoint `json:"entrypoint"`
|
||||
Providers Providers `json:"providers"`
|
||||
MatchDomains []string `json:"match_domains" validate:"domain_name"`
|
||||
Homepage HomepageConfig `json:"homepage"`
|
||||
TimeoutShutdown int `json:"timeout_shutdown" validate:"gte=0"`
|
||||
ACL *acl.Config `json:"acl"`
|
||||
AutoCert *autocert.Config `json:"autocert"`
|
||||
Entrypoint Entrypoint `json:"entrypoint"`
|
||||
Providers Providers `json:"providers"`
|
||||
MatchDomains []string `json:"match_domains" validate:"domain_name"`
|
||||
Homepage HomepageConfig `json:"homepage"`
|
||||
TimeoutShutdown int `json:"timeout_shutdown" validate:"gte=0"`
|
||||
}
|
||||
Providers struct {
|
||||
Files []string `json:"include" yaml:"include,omitempty" validate:"dive,filepath"`
|
||||
Docker map[string]string `json:"docker" yaml:"docker,omitempty" validate:"non_empty_docker_keys,dive,unix_addr|url"`
|
||||
Agents []*agent.AgentConfig `json:"agents" yaml:"agents,omitempty"`
|
||||
Notification []notif.NotificationConfig `json:"notification" yaml:"notification,omitempty"`
|
||||
Proxmox []proxmox.Config `json:"proxmox" yaml:"proxmox,omitempty"`
|
||||
}
|
||||
Entrypoint struct {
|
||||
Middlewares []map[string]any `json:"middlewares"`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package autocert
|
||||
package dnsproviders
|
||||
|
||||
type DummyConfig struct{}
|
||||
type DummyProvider struct{}
|
||||
@@ -10,15 +10,17 @@ url = "https://api.github.com/repos/go-acme/lego/contents/providers/dns"
|
||||
response = requests.get(url)
|
||||
data: list[Entry] = [Entry(**i) for i in response.json()]
|
||||
|
||||
header = "//go:generate /usr/bin/python3 gen.py\n\npackage autocert\n\n"
|
||||
header = "//go:generate /usr/bin/python3 gen.py\n\npackage dnsproviders\n\n"
|
||||
names: list[str] = [
|
||||
"ProviderLocal = \"local\"",
|
||||
"ProviderPseudo = \"pseudo\"",
|
||||
"Local = \"local\"",
|
||||
"Pseudo = \"pseudo\"",
|
||||
]
|
||||
imports: list[str] = [
|
||||
"\"github.com/yusing/go-proxy/internal/autocert\""
|
||||
]
|
||||
imports: list[str] = []
|
||||
genMap: list[str] = [
|
||||
"ProviderLocal: providerGenerator(NewDummyDefaultConfig, NewDummyDNSProviderConfig),",
|
||||
"ProviderPseudo: providerGenerator(NewDummyDefaultConfig, NewDummyDNSProviderConfig),",
|
||||
"autocert.Providers[Local] = autocert.DNSProvider(NewDummyDefaultConfig, NewDummyDNSProviderConfig)",
|
||||
"autocert.Providers[Pseudo] = autocert.DNSProvider(NewDummyDefaultConfig, NewDummyDNSProviderConfig)",
|
||||
]
|
||||
|
||||
blacklists = [
|
||||
@@ -35,18 +37,18 @@ blacklists = [
|
||||
for item in data:
|
||||
if item.type != "dir" or item.name in blacklists:
|
||||
continue
|
||||
imports.append(f"import \"github.com/go-acme/lego/v4/providers/dns/{item.name}\"")
|
||||
names.append(f"Provider{item.name} = \"{item.name}\"")
|
||||
genMap.append(f"Provider{item.name}: providerGenerator({item.name}.NewDefaultConfig, {item.name}.NewDNSProviderConfig),")
|
||||
imports.append(f"\"github.com/go-acme/lego/v4/providers/dns/{item.name}\"")
|
||||
genMap.append(f"autocert.Providers[\"{item.name}\"] = autocert.DNSProvider({item.name}.NewDefaultConfig, {item.name}.NewDNSProviderConfig)")
|
||||
|
||||
with open("providers.go", "w") as f:
|
||||
f.write(header)
|
||||
f.write("import (\n")
|
||||
f.write("\n".join(imports))
|
||||
f.write("\n\n")
|
||||
f.write("\n)\n\n")
|
||||
f.write("const (\n")
|
||||
f.write("\n".join(names))
|
||||
f.write("\n)\n\n")
|
||||
f.write("var providers = map[string]ProviderGenerator{\n")
|
||||
f.write("func InitProviders() {\n")
|
||||
f.write("\n".join(genMap))
|
||||
f.write("\n}\n\n")
|
||||
|
||||
194
internal/dnsproviders/go.mod
Normal file
194
internal/dnsproviders/go.mod
Normal file
@@ -0,0 +1,194 @@
|
||||
module github.com/yusing/go-proxy/internal/dnsproviders
|
||||
|
||||
go 1.24.2
|
||||
|
||||
replace github.com/yusing/go-proxy => ../..
|
||||
|
||||
require (
|
||||
github.com/go-acme/lego/v4 v4.23.1
|
||||
github.com/yusing/go-proxy v0.0.0-00010101000000-000000000000
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/auth v0.16.1 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.63.106 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.43.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.51.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect
|
||||
github.com/aws/smithy-go v1.22.3 // indirect
|
||||
github.com/baidubce/bce-sdk-go v0.9.224 // indirect
|
||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||
github.com/boombuler/barcode v1.0.2 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/civo/civogo v0.3.98 // indirect
|
||||
github.com/cloudflare/cloudflare-go v0.115.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dnsimple/dnsimple-go v1.7.0 // indirect
|
||||
github.com/exoscale/egoscale/v3 v3.1.14 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.16.5 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/goccy/go-yaml v1.17.1 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/gophercloud/gophercloud v1.14.1 // indirect
|
||||
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.146 // indirect
|
||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
|
||||
github.com/infobloxopen/infoblox-go-client/v2 v2.9.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect
|
||||
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect
|
||||
github.com/labbsr0x/goh v1.0.1 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/linode/linodego v1.49.0 // indirect
|
||||
github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
|
||||
github.com/liquidweb/liquidweb-go v1.6.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/miekg/dns v1.1.65 // indirect
|
||||
github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // 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
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
|
||||
github.com/nrdcg/auroradns v1.1.0 // indirect
|
||||
github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea // indirect
|
||||
github.com/nrdcg/desec v0.11.0 // indirect
|
||||
github.com/nrdcg/freemyip v0.3.0 // indirect
|
||||
github.com/nrdcg/goacmedns v0.2.0 // indirect
|
||||
github.com/nrdcg/goinwx v0.11.0 // indirect
|
||||
github.com/nrdcg/mailinabox v0.2.0 // indirect
|
||||
github.com/nrdcg/namesilo v0.2.1 // indirect
|
||||
github.com/nrdcg/nodion v0.1.0 // indirect
|
||||
github.com/nrdcg/porkbun v0.4.0 // indirect
|
||||
github.com/nzdjb/go-metaname v1.0.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||
github.com/oracle/oci-go-sdk/v65 v65.89.2 // indirect
|
||||
github.com/ovh/go-ovh v1.7.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/peterhellberg/link v1.2.0 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/pquerna/otp v1.4.0 // indirect
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
|
||||
github.com/regfish/regfish-dnsapi-go v0.1.1 // indirect
|
||||
github.com/rs/zerolog v1.34.0 // indirect
|
||||
github.com/sacloud/api-client-go v0.2.10 // indirect
|
||||
github.com/sacloud/go-http v0.1.9 // indirect
|
||||
github.com/sacloud/iaas-api-go v1.14.0 // indirect
|
||||
github.com/sacloud/packages-go v0.0.11 // indirect
|
||||
github.com/sagikazarmark/locafero v0.9.0 // indirect
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33 // indirect
|
||||
github.com/selectel/domains-go v1.1.0 // indirect
|
||||
github.com/selectel/go-selvpcclient/v3 v3.2.1 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
|
||||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
|
||||
github.com/softlayer/softlayer-go v1.1.7 // indirect
|
||||
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
|
||||
github.com/sony/gobreaker v1.0.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.14.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/stretchr/testify v1.10.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1150 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/transip/gotransip/v6 v6.26.0 // indirect
|
||||
github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec // indirect
|
||||
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
|
||||
github.com/volcengine/volc-sdk-golang v1.0.205 // indirect
|
||||
github.com/vultr/govultr/v3 v3.19.1 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.3 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/ratelimit v0.3.1 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/oauth2 v0.29.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.32.0 // indirect
|
||||
google.golang.org/api v0.230.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f // indirect
|
||||
google.golang.org/grpc v1.72.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/ns1/ns1-go.v2 v2.14.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.33.0 // indirect
|
||||
k8s.io/apimachinery v0.33.0 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
2485
internal/dnsproviders/go.sum
Normal file
2485
internal/dnsproviders/go.sum
Normal file
File diff suppressed because it is too large
Load Diff
309
internal/dnsproviders/providers.go
Normal file
309
internal/dnsproviders/providers.go
Normal file
@@ -0,0 +1,309 @@
|
||||
//go:generate /usr/bin/python3 gen.py
|
||||
|
||||
package dnsproviders
|
||||
|
||||
import (
|
||||
"github.com/go-acme/lego/v4/providers/dns/acmedns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/active24"
|
||||
"github.com/go-acme/lego/v4/providers/dns/alidns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/allinkl"
|
||||
"github.com/go-acme/lego/v4/providers/dns/arvancloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/auroradns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/autodns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/axelname"
|
||||
"github.com/go-acme/lego/v4/providers/dns/azuredns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/baiducloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/bindman"
|
||||
"github.com/go-acme/lego/v4/providers/dns/bluecat"
|
||||
"github.com/go-acme/lego/v4/providers/dns/bookmyname"
|
||||
"github.com/go-acme/lego/v4/providers/dns/bunny"
|
||||
"github.com/go-acme/lego/v4/providers/dns/checkdomain"
|
||||
"github.com/go-acme/lego/v4/providers/dns/civo"
|
||||
"github.com/go-acme/lego/v4/providers/dns/clouddns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
|
||||
"github.com/go-acme/lego/v4/providers/dns/cloudns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/cloudru"
|
||||
"github.com/go-acme/lego/v4/providers/dns/conoha"
|
||||
"github.com/go-acme/lego/v4/providers/dns/constellix"
|
||||
"github.com/go-acme/lego/v4/providers/dns/corenetworks"
|
||||
"github.com/go-acme/lego/v4/providers/dns/cpanel"
|
||||
"github.com/go-acme/lego/v4/providers/dns/derak"
|
||||
"github.com/go-acme/lego/v4/providers/dns/desec"
|
||||
"github.com/go-acme/lego/v4/providers/dns/designate"
|
||||
"github.com/go-acme/lego/v4/providers/dns/digitalocean"
|
||||
"github.com/go-acme/lego/v4/providers/dns/directadmin"
|
||||
"github.com/go-acme/lego/v4/providers/dns/dnshomede"
|
||||
"github.com/go-acme/lego/v4/providers/dns/dnsimple"
|
||||
"github.com/go-acme/lego/v4/providers/dns/dnsmadeeasy"
|
||||
"github.com/go-acme/lego/v4/providers/dns/dode"
|
||||
"github.com/go-acme/lego/v4/providers/dns/domeneshop"
|
||||
"github.com/go-acme/lego/v4/providers/dns/dreamhost"
|
||||
"github.com/go-acme/lego/v4/providers/dns/duckdns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/dyn"
|
||||
"github.com/go-acme/lego/v4/providers/dns/dynu"
|
||||
"github.com/go-acme/lego/v4/providers/dns/easydns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/edgedns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/efficientip"
|
||||
"github.com/go-acme/lego/v4/providers/dns/epik"
|
||||
"github.com/go-acme/lego/v4/providers/dns/exec"
|
||||
"github.com/go-acme/lego/v4/providers/dns/exoscale"
|
||||
"github.com/go-acme/lego/v4/providers/dns/f5xc"
|
||||
"github.com/go-acme/lego/v4/providers/dns/freemyip"
|
||||
"github.com/go-acme/lego/v4/providers/dns/gandi"
|
||||
"github.com/go-acme/lego/v4/providers/dns/gandiv5"
|
||||
"github.com/go-acme/lego/v4/providers/dns/gcloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/gcore"
|
||||
"github.com/go-acme/lego/v4/providers/dns/glesys"
|
||||
"github.com/go-acme/lego/v4/providers/dns/godaddy"
|
||||
"github.com/go-acme/lego/v4/providers/dns/googledomains"
|
||||
"github.com/go-acme/lego/v4/providers/dns/hetzner"
|
||||
"github.com/go-acme/lego/v4/providers/dns/hostingde"
|
||||
"github.com/go-acme/lego/v4/providers/dns/hosttech"
|
||||
"github.com/go-acme/lego/v4/providers/dns/httpnet"
|
||||
"github.com/go-acme/lego/v4/providers/dns/httpreq"
|
||||
"github.com/go-acme/lego/v4/providers/dns/huaweicloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/hurricane"
|
||||
"github.com/go-acme/lego/v4/providers/dns/hyperone"
|
||||
"github.com/go-acme/lego/v4/providers/dns/ibmcloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/iij"
|
||||
"github.com/go-acme/lego/v4/providers/dns/iijdpf"
|
||||
"github.com/go-acme/lego/v4/providers/dns/infoblox"
|
||||
"github.com/go-acme/lego/v4/providers/dns/infomaniak"
|
||||
"github.com/go-acme/lego/v4/providers/dns/internetbs"
|
||||
"github.com/go-acme/lego/v4/providers/dns/inwx"
|
||||
"github.com/go-acme/lego/v4/providers/dns/ionos"
|
||||
"github.com/go-acme/lego/v4/providers/dns/ipv64"
|
||||
"github.com/go-acme/lego/v4/providers/dns/iwantmyname"
|
||||
"github.com/go-acme/lego/v4/providers/dns/joker"
|
||||
"github.com/go-acme/lego/v4/providers/dns/liara"
|
||||
"github.com/go-acme/lego/v4/providers/dns/lightsail"
|
||||
"github.com/go-acme/lego/v4/providers/dns/limacity"
|
||||
"github.com/go-acme/lego/v4/providers/dns/linode"
|
||||
"github.com/go-acme/lego/v4/providers/dns/liquidweb"
|
||||
"github.com/go-acme/lego/v4/providers/dns/loopia"
|
||||
"github.com/go-acme/lego/v4/providers/dns/luadns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/mailinabox"
|
||||
"github.com/go-acme/lego/v4/providers/dns/manageengine"
|
||||
"github.com/go-acme/lego/v4/providers/dns/metaname"
|
||||
"github.com/go-acme/lego/v4/providers/dns/metaregistrar"
|
||||
"github.com/go-acme/lego/v4/providers/dns/mijnhost"
|
||||
"github.com/go-acme/lego/v4/providers/dns/mittwald"
|
||||
"github.com/go-acme/lego/v4/providers/dns/myaddr"
|
||||
"github.com/go-acme/lego/v4/providers/dns/mydnsjp"
|
||||
"github.com/go-acme/lego/v4/providers/dns/namecheap"
|
||||
"github.com/go-acme/lego/v4/providers/dns/namedotcom"
|
||||
"github.com/go-acme/lego/v4/providers/dns/namesilo"
|
||||
"github.com/go-acme/lego/v4/providers/dns/nearlyfreespeech"
|
||||
"github.com/go-acme/lego/v4/providers/dns/netcup"
|
||||
"github.com/go-acme/lego/v4/providers/dns/netlify"
|
||||
"github.com/go-acme/lego/v4/providers/dns/nicmanager"
|
||||
"github.com/go-acme/lego/v4/providers/dns/nifcloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/njalla"
|
||||
"github.com/go-acme/lego/v4/providers/dns/nodion"
|
||||
"github.com/go-acme/lego/v4/providers/dns/ns1"
|
||||
"github.com/go-acme/lego/v4/providers/dns/oraclecloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/otc"
|
||||
"github.com/go-acme/lego/v4/providers/dns/ovh"
|
||||
"github.com/go-acme/lego/v4/providers/dns/pdns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/plesk"
|
||||
"github.com/go-acme/lego/v4/providers/dns/porkbun"
|
||||
"github.com/go-acme/lego/v4/providers/dns/rackspace"
|
||||
"github.com/go-acme/lego/v4/providers/dns/rainyun"
|
||||
"github.com/go-acme/lego/v4/providers/dns/rcodezero"
|
||||
"github.com/go-acme/lego/v4/providers/dns/regfish"
|
||||
"github.com/go-acme/lego/v4/providers/dns/regru"
|
||||
"github.com/go-acme/lego/v4/providers/dns/rfc2136"
|
||||
"github.com/go-acme/lego/v4/providers/dns/rimuhosting"
|
||||
"github.com/go-acme/lego/v4/providers/dns/route53"
|
||||
"github.com/go-acme/lego/v4/providers/dns/safedns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/sakuracloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/scaleway"
|
||||
"github.com/go-acme/lego/v4/providers/dns/selectel"
|
||||
"github.com/go-acme/lego/v4/providers/dns/selectelv2"
|
||||
"github.com/go-acme/lego/v4/providers/dns/selfhostde"
|
||||
"github.com/go-acme/lego/v4/providers/dns/servercow"
|
||||
"github.com/go-acme/lego/v4/providers/dns/shellrent"
|
||||
"github.com/go-acme/lego/v4/providers/dns/simply"
|
||||
"github.com/go-acme/lego/v4/providers/dns/sonic"
|
||||
"github.com/go-acme/lego/v4/providers/dns/spaceship"
|
||||
"github.com/go-acme/lego/v4/providers/dns/stackpath"
|
||||
"github.com/go-acme/lego/v4/providers/dns/technitium"
|
||||
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/timewebcloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/transip"
|
||||
"github.com/go-acme/lego/v4/providers/dns/ultradns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/variomedia"
|
||||
"github.com/go-acme/lego/v4/providers/dns/vegadns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/vercel"
|
||||
"github.com/go-acme/lego/v4/providers/dns/versio"
|
||||
"github.com/go-acme/lego/v4/providers/dns/vinyldns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/vkcloud"
|
||||
"github.com/go-acme/lego/v4/providers/dns/volcengine"
|
||||
"github.com/go-acme/lego/v4/providers/dns/vscale"
|
||||
"github.com/go-acme/lego/v4/providers/dns/vultr"
|
||||
"github.com/go-acme/lego/v4/providers/dns/webnames"
|
||||
"github.com/go-acme/lego/v4/providers/dns/websupport"
|
||||
"github.com/go-acme/lego/v4/providers/dns/wedos"
|
||||
"github.com/go-acme/lego/v4/providers/dns/westcn"
|
||||
"github.com/go-acme/lego/v4/providers/dns/yandex"
|
||||
"github.com/go-acme/lego/v4/providers/dns/yandex360"
|
||||
"github.com/go-acme/lego/v4/providers/dns/zoneee"
|
||||
"github.com/go-acme/lego/v4/providers/dns/zonomi"
|
||||
"github.com/yusing/go-proxy/internal/autocert"
|
||||
)
|
||||
|
||||
const (
|
||||
Local = "local"
|
||||
Pseudo = "pseudo"
|
||||
)
|
||||
|
||||
func InitProviders() {
|
||||
autocert.Providers[Local] = autocert.DNSProvider(NewDummyDefaultConfig, NewDummyDNSProviderConfig)
|
||||
autocert.Providers[Pseudo] = autocert.DNSProvider(NewDummyDefaultConfig, NewDummyDNSProviderConfig)
|
||||
autocert.Providers["acmedns"] = autocert.DNSProvider(acmedns.NewDefaultConfig, acmedns.NewDNSProviderConfig)
|
||||
autocert.Providers["active24"] = autocert.DNSProvider(active24.NewDefaultConfig, active24.NewDNSProviderConfig)
|
||||
autocert.Providers["alidns"] = autocert.DNSProvider(alidns.NewDefaultConfig, alidns.NewDNSProviderConfig)
|
||||
autocert.Providers["allinkl"] = autocert.DNSProvider(allinkl.NewDefaultConfig, allinkl.NewDNSProviderConfig)
|
||||
autocert.Providers["arvancloud"] = autocert.DNSProvider(arvancloud.NewDefaultConfig, arvancloud.NewDNSProviderConfig)
|
||||
autocert.Providers["auroradns"] = autocert.DNSProvider(auroradns.NewDefaultConfig, auroradns.NewDNSProviderConfig)
|
||||
autocert.Providers["autodns"] = autocert.DNSProvider(autodns.NewDefaultConfig, autodns.NewDNSProviderConfig)
|
||||
autocert.Providers["axelname"] = autocert.DNSProvider(axelname.NewDefaultConfig, axelname.NewDNSProviderConfig)
|
||||
autocert.Providers["azuredns"] = autocert.DNSProvider(azuredns.NewDefaultConfig, azuredns.NewDNSProviderConfig)
|
||||
autocert.Providers["baiducloud"] = autocert.DNSProvider(baiducloud.NewDefaultConfig, baiducloud.NewDNSProviderConfig)
|
||||
autocert.Providers["bindman"] = autocert.DNSProvider(bindman.NewDefaultConfig, bindman.NewDNSProviderConfig)
|
||||
autocert.Providers["bluecat"] = autocert.DNSProvider(bluecat.NewDefaultConfig, bluecat.NewDNSProviderConfig)
|
||||
autocert.Providers["bookmyname"] = autocert.DNSProvider(bookmyname.NewDefaultConfig, bookmyname.NewDNSProviderConfig)
|
||||
autocert.Providers["bunny"] = autocert.DNSProvider(bunny.NewDefaultConfig, bunny.NewDNSProviderConfig)
|
||||
autocert.Providers["checkdomain"] = autocert.DNSProvider(checkdomain.NewDefaultConfig, checkdomain.NewDNSProviderConfig)
|
||||
autocert.Providers["civo"] = autocert.DNSProvider(civo.NewDefaultConfig, civo.NewDNSProviderConfig)
|
||||
autocert.Providers["clouddns"] = autocert.DNSProvider(clouddns.NewDefaultConfig, clouddns.NewDNSProviderConfig)
|
||||
autocert.Providers["cloudflare"] = autocert.DNSProvider(cloudflare.NewDefaultConfig, cloudflare.NewDNSProviderConfig)
|
||||
autocert.Providers["cloudns"] = autocert.DNSProvider(cloudns.NewDefaultConfig, cloudns.NewDNSProviderConfig)
|
||||
autocert.Providers["cloudru"] = autocert.DNSProvider(cloudru.NewDefaultConfig, cloudru.NewDNSProviderConfig)
|
||||
autocert.Providers["conoha"] = autocert.DNSProvider(conoha.NewDefaultConfig, conoha.NewDNSProviderConfig)
|
||||
autocert.Providers["constellix"] = autocert.DNSProvider(constellix.NewDefaultConfig, constellix.NewDNSProviderConfig)
|
||||
autocert.Providers["corenetworks"] = autocert.DNSProvider(corenetworks.NewDefaultConfig, corenetworks.NewDNSProviderConfig)
|
||||
autocert.Providers["cpanel"] = autocert.DNSProvider(cpanel.NewDefaultConfig, cpanel.NewDNSProviderConfig)
|
||||
autocert.Providers["derak"] = autocert.DNSProvider(derak.NewDefaultConfig, derak.NewDNSProviderConfig)
|
||||
autocert.Providers["desec"] = autocert.DNSProvider(desec.NewDefaultConfig, desec.NewDNSProviderConfig)
|
||||
autocert.Providers["designate"] = autocert.DNSProvider(designate.NewDefaultConfig, designate.NewDNSProviderConfig)
|
||||
autocert.Providers["digitalocean"] = autocert.DNSProvider(digitalocean.NewDefaultConfig, digitalocean.NewDNSProviderConfig)
|
||||
autocert.Providers["directadmin"] = autocert.DNSProvider(directadmin.NewDefaultConfig, directadmin.NewDNSProviderConfig)
|
||||
autocert.Providers["dnshomede"] = autocert.DNSProvider(dnshomede.NewDefaultConfig, dnshomede.NewDNSProviderConfig)
|
||||
autocert.Providers["dnsimple"] = autocert.DNSProvider(dnsimple.NewDefaultConfig, dnsimple.NewDNSProviderConfig)
|
||||
autocert.Providers["dnsmadeeasy"] = autocert.DNSProvider(dnsmadeeasy.NewDefaultConfig, dnsmadeeasy.NewDNSProviderConfig)
|
||||
autocert.Providers["dode"] = autocert.DNSProvider(dode.NewDefaultConfig, dode.NewDNSProviderConfig)
|
||||
autocert.Providers["domeneshop"] = autocert.DNSProvider(domeneshop.NewDefaultConfig, domeneshop.NewDNSProviderConfig)
|
||||
autocert.Providers["dreamhost"] = autocert.DNSProvider(dreamhost.NewDefaultConfig, dreamhost.NewDNSProviderConfig)
|
||||
autocert.Providers["duckdns"] = autocert.DNSProvider(duckdns.NewDefaultConfig, duckdns.NewDNSProviderConfig)
|
||||
autocert.Providers["dyn"] = autocert.DNSProvider(dyn.NewDefaultConfig, dyn.NewDNSProviderConfig)
|
||||
autocert.Providers["dynu"] = autocert.DNSProvider(dynu.NewDefaultConfig, dynu.NewDNSProviderConfig)
|
||||
autocert.Providers["easydns"] = autocert.DNSProvider(easydns.NewDefaultConfig, easydns.NewDNSProviderConfig)
|
||||
autocert.Providers["edgedns"] = autocert.DNSProvider(edgedns.NewDefaultConfig, edgedns.NewDNSProviderConfig)
|
||||
autocert.Providers["efficientip"] = autocert.DNSProvider(efficientip.NewDefaultConfig, efficientip.NewDNSProviderConfig)
|
||||
autocert.Providers["epik"] = autocert.DNSProvider(epik.NewDefaultConfig, epik.NewDNSProviderConfig)
|
||||
autocert.Providers["exec"] = autocert.DNSProvider(exec.NewDefaultConfig, exec.NewDNSProviderConfig)
|
||||
autocert.Providers["exoscale"] = autocert.DNSProvider(exoscale.NewDefaultConfig, exoscale.NewDNSProviderConfig)
|
||||
autocert.Providers["f5xc"] = autocert.DNSProvider(f5xc.NewDefaultConfig, f5xc.NewDNSProviderConfig)
|
||||
autocert.Providers["freemyip"] = autocert.DNSProvider(freemyip.NewDefaultConfig, freemyip.NewDNSProviderConfig)
|
||||
autocert.Providers["gandi"] = autocert.DNSProvider(gandi.NewDefaultConfig, gandi.NewDNSProviderConfig)
|
||||
autocert.Providers["gandiv5"] = autocert.DNSProvider(gandiv5.NewDefaultConfig, gandiv5.NewDNSProviderConfig)
|
||||
autocert.Providers["gcloud"] = autocert.DNSProvider(gcloud.NewDefaultConfig, gcloud.NewDNSProviderConfig)
|
||||
autocert.Providers["gcore"] = autocert.DNSProvider(gcore.NewDefaultConfig, gcore.NewDNSProviderConfig)
|
||||
autocert.Providers["glesys"] = autocert.DNSProvider(glesys.NewDefaultConfig, glesys.NewDNSProviderConfig)
|
||||
autocert.Providers["godaddy"] = autocert.DNSProvider(godaddy.NewDefaultConfig, godaddy.NewDNSProviderConfig)
|
||||
autocert.Providers["googledomains"] = autocert.DNSProvider(googledomains.NewDefaultConfig, googledomains.NewDNSProviderConfig)
|
||||
autocert.Providers["hetzner"] = autocert.DNSProvider(hetzner.NewDefaultConfig, hetzner.NewDNSProviderConfig)
|
||||
autocert.Providers["hostingde"] = autocert.DNSProvider(hostingde.NewDefaultConfig, hostingde.NewDNSProviderConfig)
|
||||
autocert.Providers["hosttech"] = autocert.DNSProvider(hosttech.NewDefaultConfig, hosttech.NewDNSProviderConfig)
|
||||
autocert.Providers["httpnet"] = autocert.DNSProvider(httpnet.NewDefaultConfig, httpnet.NewDNSProviderConfig)
|
||||
autocert.Providers["httpreq"] = autocert.DNSProvider(httpreq.NewDefaultConfig, httpreq.NewDNSProviderConfig)
|
||||
autocert.Providers["huaweicloud"] = autocert.DNSProvider(huaweicloud.NewDefaultConfig, huaweicloud.NewDNSProviderConfig)
|
||||
autocert.Providers["hurricane"] = autocert.DNSProvider(hurricane.NewDefaultConfig, hurricane.NewDNSProviderConfig)
|
||||
autocert.Providers["hyperone"] = autocert.DNSProvider(hyperone.NewDefaultConfig, hyperone.NewDNSProviderConfig)
|
||||
autocert.Providers["ibmcloud"] = autocert.DNSProvider(ibmcloud.NewDefaultConfig, ibmcloud.NewDNSProviderConfig)
|
||||
autocert.Providers["iij"] = autocert.DNSProvider(iij.NewDefaultConfig, iij.NewDNSProviderConfig)
|
||||
autocert.Providers["iijdpf"] = autocert.DNSProvider(iijdpf.NewDefaultConfig, iijdpf.NewDNSProviderConfig)
|
||||
autocert.Providers["infoblox"] = autocert.DNSProvider(infoblox.NewDefaultConfig, infoblox.NewDNSProviderConfig)
|
||||
autocert.Providers["infomaniak"] = autocert.DNSProvider(infomaniak.NewDefaultConfig, infomaniak.NewDNSProviderConfig)
|
||||
autocert.Providers["internetbs"] = autocert.DNSProvider(internetbs.NewDefaultConfig, internetbs.NewDNSProviderConfig)
|
||||
autocert.Providers["inwx"] = autocert.DNSProvider(inwx.NewDefaultConfig, inwx.NewDNSProviderConfig)
|
||||
autocert.Providers["ionos"] = autocert.DNSProvider(ionos.NewDefaultConfig, ionos.NewDNSProviderConfig)
|
||||
autocert.Providers["ipv64"] = autocert.DNSProvider(ipv64.NewDefaultConfig, ipv64.NewDNSProviderConfig)
|
||||
autocert.Providers["iwantmyname"] = autocert.DNSProvider(iwantmyname.NewDefaultConfig, iwantmyname.NewDNSProviderConfig)
|
||||
autocert.Providers["joker"] = autocert.DNSProvider(joker.NewDefaultConfig, joker.NewDNSProviderConfig)
|
||||
autocert.Providers["liara"] = autocert.DNSProvider(liara.NewDefaultConfig, liara.NewDNSProviderConfig)
|
||||
autocert.Providers["lightsail"] = autocert.DNSProvider(lightsail.NewDefaultConfig, lightsail.NewDNSProviderConfig)
|
||||
autocert.Providers["limacity"] = autocert.DNSProvider(limacity.NewDefaultConfig, limacity.NewDNSProviderConfig)
|
||||
autocert.Providers["linode"] = autocert.DNSProvider(linode.NewDefaultConfig, linode.NewDNSProviderConfig)
|
||||
autocert.Providers["liquidweb"] = autocert.DNSProvider(liquidweb.NewDefaultConfig, liquidweb.NewDNSProviderConfig)
|
||||
autocert.Providers["loopia"] = autocert.DNSProvider(loopia.NewDefaultConfig, loopia.NewDNSProviderConfig)
|
||||
autocert.Providers["luadns"] = autocert.DNSProvider(luadns.NewDefaultConfig, luadns.NewDNSProviderConfig)
|
||||
autocert.Providers["mailinabox"] = autocert.DNSProvider(mailinabox.NewDefaultConfig, mailinabox.NewDNSProviderConfig)
|
||||
autocert.Providers["manageengine"] = autocert.DNSProvider(manageengine.NewDefaultConfig, manageengine.NewDNSProviderConfig)
|
||||
autocert.Providers["metaname"] = autocert.DNSProvider(metaname.NewDefaultConfig, metaname.NewDNSProviderConfig)
|
||||
autocert.Providers["metaregistrar"] = autocert.DNSProvider(metaregistrar.NewDefaultConfig, metaregistrar.NewDNSProviderConfig)
|
||||
autocert.Providers["mijnhost"] = autocert.DNSProvider(mijnhost.NewDefaultConfig, mijnhost.NewDNSProviderConfig)
|
||||
autocert.Providers["mittwald"] = autocert.DNSProvider(mittwald.NewDefaultConfig, mittwald.NewDNSProviderConfig)
|
||||
autocert.Providers["myaddr"] = autocert.DNSProvider(myaddr.NewDefaultConfig, myaddr.NewDNSProviderConfig)
|
||||
autocert.Providers["mydnsjp"] = autocert.DNSProvider(mydnsjp.NewDefaultConfig, mydnsjp.NewDNSProviderConfig)
|
||||
autocert.Providers["namecheap"] = autocert.DNSProvider(namecheap.NewDefaultConfig, namecheap.NewDNSProviderConfig)
|
||||
autocert.Providers["namedotcom"] = autocert.DNSProvider(namedotcom.NewDefaultConfig, namedotcom.NewDNSProviderConfig)
|
||||
autocert.Providers["namesilo"] = autocert.DNSProvider(namesilo.NewDefaultConfig, namesilo.NewDNSProviderConfig)
|
||||
autocert.Providers["nearlyfreespeech"] = autocert.DNSProvider(nearlyfreespeech.NewDefaultConfig, nearlyfreespeech.NewDNSProviderConfig)
|
||||
autocert.Providers["netcup"] = autocert.DNSProvider(netcup.NewDefaultConfig, netcup.NewDNSProviderConfig)
|
||||
autocert.Providers["netlify"] = autocert.DNSProvider(netlify.NewDefaultConfig, netlify.NewDNSProviderConfig)
|
||||
autocert.Providers["nicmanager"] = autocert.DNSProvider(nicmanager.NewDefaultConfig, nicmanager.NewDNSProviderConfig)
|
||||
autocert.Providers["nifcloud"] = autocert.DNSProvider(nifcloud.NewDefaultConfig, nifcloud.NewDNSProviderConfig)
|
||||
autocert.Providers["njalla"] = autocert.DNSProvider(njalla.NewDefaultConfig, njalla.NewDNSProviderConfig)
|
||||
autocert.Providers["nodion"] = autocert.DNSProvider(nodion.NewDefaultConfig, nodion.NewDNSProviderConfig)
|
||||
autocert.Providers["ns1"] = autocert.DNSProvider(ns1.NewDefaultConfig, ns1.NewDNSProviderConfig)
|
||||
autocert.Providers["oraclecloud"] = autocert.DNSProvider(oraclecloud.NewDefaultConfig, oraclecloud.NewDNSProviderConfig)
|
||||
autocert.Providers["otc"] = autocert.DNSProvider(otc.NewDefaultConfig, otc.NewDNSProviderConfig)
|
||||
autocert.Providers["ovh"] = autocert.DNSProvider(ovh.NewDefaultConfig, ovh.NewDNSProviderConfig)
|
||||
autocert.Providers["pdns"] = autocert.DNSProvider(pdns.NewDefaultConfig, pdns.NewDNSProviderConfig)
|
||||
autocert.Providers["plesk"] = autocert.DNSProvider(plesk.NewDefaultConfig, plesk.NewDNSProviderConfig)
|
||||
autocert.Providers["porkbun"] = autocert.DNSProvider(porkbun.NewDefaultConfig, porkbun.NewDNSProviderConfig)
|
||||
autocert.Providers["rackspace"] = autocert.DNSProvider(rackspace.NewDefaultConfig, rackspace.NewDNSProviderConfig)
|
||||
autocert.Providers["rainyun"] = autocert.DNSProvider(rainyun.NewDefaultConfig, rainyun.NewDNSProviderConfig)
|
||||
autocert.Providers["rcodezero"] = autocert.DNSProvider(rcodezero.NewDefaultConfig, rcodezero.NewDNSProviderConfig)
|
||||
autocert.Providers["regfish"] = autocert.DNSProvider(regfish.NewDefaultConfig, regfish.NewDNSProviderConfig)
|
||||
autocert.Providers["regru"] = autocert.DNSProvider(regru.NewDefaultConfig, regru.NewDNSProviderConfig)
|
||||
autocert.Providers["rfc2136"] = autocert.DNSProvider(rfc2136.NewDefaultConfig, rfc2136.NewDNSProviderConfig)
|
||||
autocert.Providers["rimuhosting"] = autocert.DNSProvider(rimuhosting.NewDefaultConfig, rimuhosting.NewDNSProviderConfig)
|
||||
autocert.Providers["route53"] = autocert.DNSProvider(route53.NewDefaultConfig, route53.NewDNSProviderConfig)
|
||||
autocert.Providers["safedns"] = autocert.DNSProvider(safedns.NewDefaultConfig, safedns.NewDNSProviderConfig)
|
||||
autocert.Providers["sakuracloud"] = autocert.DNSProvider(sakuracloud.NewDefaultConfig, sakuracloud.NewDNSProviderConfig)
|
||||
autocert.Providers["scaleway"] = autocert.DNSProvider(scaleway.NewDefaultConfig, scaleway.NewDNSProviderConfig)
|
||||
autocert.Providers["selectel"] = autocert.DNSProvider(selectel.NewDefaultConfig, selectel.NewDNSProviderConfig)
|
||||
autocert.Providers["selectelv2"] = autocert.DNSProvider(selectelv2.NewDefaultConfig, selectelv2.NewDNSProviderConfig)
|
||||
autocert.Providers["selfhostde"] = autocert.DNSProvider(selfhostde.NewDefaultConfig, selfhostde.NewDNSProviderConfig)
|
||||
autocert.Providers["servercow"] = autocert.DNSProvider(servercow.NewDefaultConfig, servercow.NewDNSProviderConfig)
|
||||
autocert.Providers["shellrent"] = autocert.DNSProvider(shellrent.NewDefaultConfig, shellrent.NewDNSProviderConfig)
|
||||
autocert.Providers["simply"] = autocert.DNSProvider(simply.NewDefaultConfig, simply.NewDNSProviderConfig)
|
||||
autocert.Providers["sonic"] = autocert.DNSProvider(sonic.NewDefaultConfig, sonic.NewDNSProviderConfig)
|
||||
autocert.Providers["spaceship"] = autocert.DNSProvider(spaceship.NewDefaultConfig, spaceship.NewDNSProviderConfig)
|
||||
autocert.Providers["stackpath"] = autocert.DNSProvider(stackpath.NewDefaultConfig, stackpath.NewDNSProviderConfig)
|
||||
autocert.Providers["technitium"] = autocert.DNSProvider(technitium.NewDefaultConfig, technitium.NewDNSProviderConfig)
|
||||
autocert.Providers["tencentcloud"] = autocert.DNSProvider(tencentcloud.NewDefaultConfig, tencentcloud.NewDNSProviderConfig)
|
||||
autocert.Providers["timewebcloud"] = autocert.DNSProvider(timewebcloud.NewDefaultConfig, timewebcloud.NewDNSProviderConfig)
|
||||
autocert.Providers["transip"] = autocert.DNSProvider(transip.NewDefaultConfig, transip.NewDNSProviderConfig)
|
||||
autocert.Providers["ultradns"] = autocert.DNSProvider(ultradns.NewDefaultConfig, ultradns.NewDNSProviderConfig)
|
||||
autocert.Providers["variomedia"] = autocert.DNSProvider(variomedia.NewDefaultConfig, variomedia.NewDNSProviderConfig)
|
||||
autocert.Providers["vegadns"] = autocert.DNSProvider(vegadns.NewDefaultConfig, vegadns.NewDNSProviderConfig)
|
||||
autocert.Providers["vercel"] = autocert.DNSProvider(vercel.NewDefaultConfig, vercel.NewDNSProviderConfig)
|
||||
autocert.Providers["versio"] = autocert.DNSProvider(versio.NewDefaultConfig, versio.NewDNSProviderConfig)
|
||||
autocert.Providers["vinyldns"] = autocert.DNSProvider(vinyldns.NewDefaultConfig, vinyldns.NewDNSProviderConfig)
|
||||
autocert.Providers["vkcloud"] = autocert.DNSProvider(vkcloud.NewDefaultConfig, vkcloud.NewDNSProviderConfig)
|
||||
autocert.Providers["volcengine"] = autocert.DNSProvider(volcengine.NewDefaultConfig, volcengine.NewDNSProviderConfig)
|
||||
autocert.Providers["vscale"] = autocert.DNSProvider(vscale.NewDefaultConfig, vscale.NewDNSProviderConfig)
|
||||
autocert.Providers["vultr"] = autocert.DNSProvider(vultr.NewDefaultConfig, vultr.NewDNSProviderConfig)
|
||||
autocert.Providers["webnames"] = autocert.DNSProvider(webnames.NewDefaultConfig, webnames.NewDNSProviderConfig)
|
||||
autocert.Providers["websupport"] = autocert.DNSProvider(websupport.NewDefaultConfig, websupport.NewDNSProviderConfig)
|
||||
autocert.Providers["wedos"] = autocert.DNSProvider(wedos.NewDefaultConfig, wedos.NewDNSProviderConfig)
|
||||
autocert.Providers["westcn"] = autocert.DNSProvider(westcn.NewDefaultConfig, westcn.NewDNSProviderConfig)
|
||||
autocert.Providers["yandex"] = autocert.DNSProvider(yandex.NewDefaultConfig, yandex.NewDNSProviderConfig)
|
||||
autocert.Providers["yandex360"] = autocert.DNSProvider(yandex360.NewDefaultConfig, yandex360.NewDNSProviderConfig)
|
||||
autocert.Providers["zoneee"] = autocert.DNSProvider(zoneee.NewDefaultConfig, zoneee.NewDNSProviderConfig)
|
||||
autocert.Providers["zonomi"] = autocert.DNSProvider(zonomi.NewDefaultConfig, zonomi.NewDNSProviderConfig)
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/jsonstore"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
@@ -15,34 +16,24 @@ import (
|
||||
|
||||
type cacheEntry struct {
|
||||
Icon []byte `json:"icon"`
|
||||
ContentType string `json:"content_type"`
|
||||
ContentType string `json:"content_type,omitempty"`
|
||||
LastAccess atomic.Value[time.Time] `json:"last_access"`
|
||||
}
|
||||
|
||||
// cache key can be absolute url or route name.
|
||||
var (
|
||||
iconCache = make(map[string]*cacheEntry)
|
||||
iconCacheMu sync.RWMutex
|
||||
iconCache = jsonstore.Store[*cacheEntry](common.NamespaceIconCache)
|
||||
iconMu sync.RWMutex
|
||||
)
|
||||
|
||||
const (
|
||||
iconCacheTTL = 3 * 24 * time.Hour
|
||||
cleanUpInterval = time.Minute
|
||||
maxCacheSize = 1024 * 1024 // 1MB
|
||||
maxIconSize = 1024 * 1024 // 1MB
|
||||
maxCacheEntries = 100
|
||||
)
|
||||
|
||||
func InitIconCache() {
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
|
||||
err := utils.LoadJSONIfExist(common.IconCachePath, &iconCache)
|
||||
if err != nil {
|
||||
logging.Error().Err(err).Msg("failed to load icon cache")
|
||||
} else if len(iconCache) > 0 {
|
||||
logging.Info().Int("count", len(iconCache)).Msg("icon cache loaded")
|
||||
}
|
||||
|
||||
func init() {
|
||||
go func() {
|
||||
cleanupTicker := time.NewTicker(cleanUpInterval)
|
||||
defer cleanupTicker.Stop()
|
||||
@@ -55,36 +46,21 @@ func InitIconCache() {
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
task.OnProgramExit("save_favicon_cache", func() {
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
|
||||
if len(iconCache) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if err := utils.SaveJSON(common.IconCachePath, &iconCache, 0o644); err != nil {
|
||||
logging.Error().Err(err).Msg("failed to save icon cache")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func pruneExpiredIconCache() {
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
|
||||
nPruned := 0
|
||||
for key, icon := range iconCache {
|
||||
for key, icon := range iconCache.Range {
|
||||
if icon.IsExpired() {
|
||||
delete(iconCache, key)
|
||||
iconCache.Delete(key)
|
||||
nPruned++
|
||||
}
|
||||
}
|
||||
if len(iconCache) > maxCacheEntries {
|
||||
if iconCache.Size() > maxCacheEntries {
|
||||
iconCache.Clear()
|
||||
newIconCache := make(map[string]*cacheEntry, maxCacheEntries)
|
||||
i := 0
|
||||
for key, icon := range iconCache {
|
||||
for key, icon := range iconCache.Range {
|
||||
if i == maxCacheEntries {
|
||||
break
|
||||
}
|
||||
@@ -93,7 +69,9 @@ func pruneExpiredIconCache() {
|
||||
i++
|
||||
}
|
||||
}
|
||||
iconCache = newIconCache
|
||||
for key, icon := range newIconCache {
|
||||
iconCache.Store(key, icon)
|
||||
}
|
||||
}
|
||||
if nPruned > 0 {
|
||||
logging.Info().Int("pruned", nPruned).Msg("pruned expired icon cache")
|
||||
@@ -101,21 +79,18 @@ func pruneExpiredIconCache() {
|
||||
}
|
||||
|
||||
func PruneRouteIconCache(route route) {
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
delete(iconCache, route.Key())
|
||||
iconCache.Delete(route.Key())
|
||||
}
|
||||
|
||||
func loadIconCache(key string) *FetchResult {
|
||||
iconCacheMu.RLock()
|
||||
defer iconCacheMu.RUnlock()
|
||||
|
||||
icon, ok := iconCache[key]
|
||||
iconMu.RLock()
|
||||
defer iconMu.RUnlock()
|
||||
icon, ok := iconCache.Load(key)
|
||||
if ok && len(icon.Icon) > 0 {
|
||||
logging.Debug().
|
||||
Str("key", key).
|
||||
Msg("icon found in cache")
|
||||
icon.LastAccess.Store(time.Now())
|
||||
icon.LastAccess.Store(utils.TimeNow())
|
||||
return &FetchResult{Icon: icon.Icon, contentType: icon.ContentType}
|
||||
}
|
||||
return nil
|
||||
@@ -123,15 +98,17 @@ func loadIconCache(key string) *FetchResult {
|
||||
|
||||
func storeIconCache(key string, result *FetchResult) {
|
||||
icon := result.Icon
|
||||
if len(icon) > maxCacheSize {
|
||||
if len(icon) > maxIconSize {
|
||||
logging.Debug().Int("size", len(icon)).Msg("icon cache size exceeds max cache size")
|
||||
return
|
||||
}
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
|
||||
iconMu.Lock()
|
||||
defer iconMu.Unlock()
|
||||
|
||||
entry := &cacheEntry{Icon: icon, ContentType: result.contentType}
|
||||
entry.LastAccess.Store(time.Now())
|
||||
iconCache[key] = entry
|
||||
iconCache.Store(key, entry)
|
||||
logging.Debug().Str("key", key).Int("size", len(icon)).Msg("stored icon cache")
|
||||
}
|
||||
|
||||
@@ -140,12 +117,20 @@ func (e *cacheEntry) IsExpired() bool {
|
||||
}
|
||||
|
||||
func (e *cacheEntry) UnmarshalJSON(data []byte) error {
|
||||
var tmp struct {
|
||||
Icon []byte `json:"icon"`
|
||||
ContentType string `json:"content_type,omitempty"`
|
||||
LastAccess time.Time `json:"last_access"`
|
||||
}
|
||||
// check if data is json
|
||||
if json.Valid(data) {
|
||||
err := json.Unmarshal(data, &e)
|
||||
err := json.Unmarshal(data, &tmp)
|
||||
// return only if unmarshal is successful
|
||||
// otherwise fallback to base64
|
||||
if err == nil {
|
||||
e.Icon = tmp.Icon
|
||||
e.ContentType = tmp.ContentType
|
||||
e.LastAccess.Store(tmp.LastAccess)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/lithammer/fuzzysearch/fuzzy"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
)
|
||||
|
||||
@@ -68,6 +69,10 @@ func InitIconListCache() {
|
||||
Int("display_names", len(iconsCache.DisplayNames)).
|
||||
Msg("icon list cache loaded")
|
||||
}
|
||||
|
||||
task.OnProgramExit("save_icon_list_cache", func() {
|
||||
utils.SaveJSON(common.IconListCachePath, iconsCache, 0o644)
|
||||
})
|
||||
}
|
||||
|
||||
func ListAvailableIcons() (*Cache, error) {
|
||||
|
||||
@@ -38,6 +38,10 @@ func (w *Watcher) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
default:
|
||||
f := &ForceCacheControl{expires: w.expires().Format(http.TimeFormat), ResponseWriter: rw}
|
||||
w, ok := watcherMap[w.Key()] // could've been reloaded
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
w.rp.ServeHTTP(f, r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ func NewWatcher(parent task.Parent, r routes.Route) (*Watcher, error) {
|
||||
case routes.StreamRoute:
|
||||
w.stream = r
|
||||
default:
|
||||
return nil, gperr.New("unexpected route type")
|
||||
return nil, gperr.Errorf("unexpected route type: %T", r)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(parent.Context(), reqTimeout)
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/lithammer/fuzzysearch/fuzzy"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
)
|
||||
|
||||
type GitHubContents struct { //! keep this, may reuse in future
|
||||
Type string `json:"type"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Sha string `json:"sha"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
type (
|
||||
IconsMap map[string]map[string]struct{}
|
||||
IconList []string
|
||||
Cache struct {
|
||||
WalkxCode, Selfhst IconsMap
|
||||
DisplayNames ReferenceDisplayNameMap
|
||||
IconList IconList // combined into a single list
|
||||
}
|
||||
ReferenceDisplayNameMap map[string]string
|
||||
)
|
||||
|
||||
func (icons *Cache) needUpdate() bool {
|
||||
return len(icons.WalkxCode) == 0 || len(icons.Selfhst) == 0 || len(icons.IconList) == 0 || len(icons.DisplayNames) == 0
|
||||
}
|
||||
|
||||
const updateInterval = 2 * time.Hour
|
||||
|
||||
var (
|
||||
iconsCache *Cache
|
||||
iconsCahceMu sync.RWMutex
|
||||
lastUpdate time.Time
|
||||
)
|
||||
|
||||
const (
|
||||
walkxcodeIcons = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/tree.json"
|
||||
selfhstIcons = "https://cdn.selfh.st/directory/icons.json"
|
||||
)
|
||||
|
||||
func InitIconListCache() {
|
||||
iconsCahceMu.Lock()
|
||||
defer iconsCahceMu.Unlock()
|
||||
|
||||
iconsCache = &Cache{
|
||||
WalkxCode: make(IconsMap),
|
||||
Selfhst: make(IconsMap),
|
||||
DisplayNames: make(ReferenceDisplayNameMap),
|
||||
IconList: []string{},
|
||||
}
|
||||
err := utils.LoadJSONIfExist(common.IconListCachePath, iconsCache)
|
||||
if err != nil {
|
||||
logging.Error().Err(err).Msg("failed to load icon list cache config")
|
||||
} else if len(iconsCache.IconList) > 0 {
|
||||
logging.Info().
|
||||
Int("icons", len(iconsCache.IconList)).
|
||||
Int("display_names", len(iconsCache.DisplayNames)).
|
||||
Msg("icon list cache loaded")
|
||||
}
|
||||
}
|
||||
|
||||
func ListAvailableIcons() (*Cache, error) {
|
||||
iconsCahceMu.RLock()
|
||||
if time.Since(lastUpdate) < updateInterval {
|
||||
if !iconsCache.needUpdate() {
|
||||
iconsCahceMu.RUnlock()
|
||||
return iconsCache, nil
|
||||
}
|
||||
}
|
||||
iconsCahceMu.RUnlock()
|
||||
|
||||
iconsCahceMu.Lock()
|
||||
defer iconsCahceMu.Unlock()
|
||||
|
||||
logging.Info().Msg("updating icon data")
|
||||
icons, err := fetchIconData()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logging.Info().
|
||||
Int("icons", len(icons.IconList)).
|
||||
Int("display_names", len(icons.DisplayNames)).
|
||||
Msg("icons list updated")
|
||||
|
||||
iconsCache = icons
|
||||
lastUpdate = time.Now()
|
||||
|
||||
err = utils.SaveJSON(common.IconListCachePath, iconsCache, 0o644)
|
||||
if err != nil {
|
||||
logging.Warn().Err(err).Msg("failed to save icon list cache")
|
||||
}
|
||||
return icons, nil
|
||||
}
|
||||
|
||||
func SearchIcons(keyword string, limit int) ([]string, error) {
|
||||
icons, err := ListAvailableIcons()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if keyword == "" {
|
||||
return utils.Slice(icons.IconList, limit), nil
|
||||
}
|
||||
return utils.Slice(fuzzy.Find(keyword, icons.IconList), limit), nil
|
||||
}
|
||||
|
||||
func HasWalkxCodeIcon(name string, filetype string) bool {
|
||||
icons, err := ListAvailableIcons()
|
||||
if err != nil {
|
||||
logging.Error().Err(err).Msg("failed to list icons")
|
||||
return false
|
||||
}
|
||||
if _, ok := icons.WalkxCode[filetype]; !ok {
|
||||
return false
|
||||
}
|
||||
_, ok := icons.WalkxCode[filetype][name+"."+filetype]
|
||||
return ok
|
||||
}
|
||||
|
||||
func HasSelfhstIcon(name string, filetype string) bool {
|
||||
icons, err := ListAvailableIcons()
|
||||
if err != nil {
|
||||
logging.Error().Err(err).Msg("failed to list icons")
|
||||
return false
|
||||
}
|
||||
if _, ok := icons.Selfhst[filetype]; !ok {
|
||||
return false
|
||||
}
|
||||
_, ok := icons.Selfhst[filetype][name+"."+filetype]
|
||||
return ok
|
||||
}
|
||||
|
||||
func GetDisplayName(reference string) (string, bool) {
|
||||
icons, err := ListAvailableIcons()
|
||||
if err != nil {
|
||||
logging.Error().Err(err).Msg("failed to list icons")
|
||||
return "", false
|
||||
}
|
||||
displayName, ok := icons.DisplayNames[reference]
|
||||
return displayName, ok
|
||||
}
|
||||
|
||||
func fetchIconData() (*Cache, error) {
|
||||
walkxCodeIconMap, walkxCodeIconList, err := fetchWalkxCodeIcons()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n := 0
|
||||
for _, items := range walkxCodeIconMap {
|
||||
n += len(items)
|
||||
}
|
||||
|
||||
selfhstIconMap, selfhstIconList, referenceToNames, err := fetchSelfhstIcons()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Cache{
|
||||
WalkxCode: walkxCodeIconMap,
|
||||
Selfhst: selfhstIconMap,
|
||||
DisplayNames: referenceToNames,
|
||||
IconList: append(walkxCodeIconList, selfhstIconList...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
/*
|
||||
format:
|
||||
|
||||
{
|
||||
"png": [
|
||||
"*.png",
|
||||
],
|
||||
"svg": [
|
||||
"*.svg",
|
||||
],
|
||||
"webp": [
|
||||
"*.webp",
|
||||
]
|
||||
}
|
||||
*/
|
||||
func fetchWalkxCodeIcons() (IconsMap, IconList, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, walkxcodeIcons, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
data := make(map[string][]string)
|
||||
err = json.Unmarshal(body, &data)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
icons := make(IconsMap, len(data))
|
||||
iconList := make(IconList, 0, 2000)
|
||||
for fileType, files := range data {
|
||||
icons[fileType] = make(map[string]struct{}, len(files))
|
||||
for _, icon := range files {
|
||||
icons[fileType][icon] = struct{}{}
|
||||
iconList = append(iconList, "@walkxcode/"+icon)
|
||||
}
|
||||
}
|
||||
return icons, iconList, nil
|
||||
}
|
||||
|
||||
/*
|
||||
format:
|
||||
|
||||
{
|
||||
"Name": "2FAuth",
|
||||
"Reference": "2fauth",
|
||||
"SVG": "Yes",
|
||||
"PNG": "Yes",
|
||||
"WebP": "Yes",
|
||||
"Light": "Yes",
|
||||
"Category": "Self-Hosted",
|
||||
"CreatedAt": "2024-08-16 00:27:23+00:00"
|
||||
}
|
||||
*/
|
||||
func fetchSelfhstIcons() (IconsMap, IconList, ReferenceDisplayNameMap, error) {
|
||||
type SelfhStIcon struct {
|
||||
Name string `json:"Name"`
|
||||
Reference string `json:"Reference"`
|
||||
SVG string `json:"SVG"`
|
||||
PNG string `json:"PNG"`
|
||||
WebP string `json:"WebP"`
|
||||
// Light string
|
||||
// Category string
|
||||
// CreatedAt string
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, selfhstIcons, nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
data := make([]SelfhStIcon, 0, 2000)
|
||||
err = json.Unmarshal(body, &data)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
iconList := make(IconList, 0, len(data)*3)
|
||||
icons := make(IconsMap)
|
||||
icons["svg"] = make(map[string]struct{}, len(data))
|
||||
icons["png"] = make(map[string]struct{}, len(data))
|
||||
icons["webp"] = make(map[string]struct{}, len(data))
|
||||
|
||||
referenceToNames := make(ReferenceDisplayNameMap, len(data))
|
||||
|
||||
for _, item := range data {
|
||||
if item.SVG == "Yes" {
|
||||
icons["svg"][item.Reference+".svg"] = struct{}{}
|
||||
iconList = append(iconList, "@selfhst/"+item.Reference+".svg")
|
||||
}
|
||||
if item.PNG == "Yes" {
|
||||
icons["png"][item.Reference+".png"] = struct{}{}
|
||||
iconList = append(iconList, "@selfhst/"+item.Reference+".png")
|
||||
}
|
||||
if item.WebP == "Yes" {
|
||||
icons["webp"][item.Reference+".webp"] = struct{}{}
|
||||
iconList = append(iconList, "@selfhst/"+item.Reference+".webp")
|
||||
}
|
||||
referenceToNames[item.Reference] = item.Name
|
||||
}
|
||||
|
||||
return icons, iconList, referenceToNames, nil
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -42,6 +43,12 @@ type (
|
||||
Name() string // file name or path
|
||||
}
|
||||
|
||||
SupportRotate interface {
|
||||
io.Writer
|
||||
supportRotate
|
||||
Name() string
|
||||
}
|
||||
|
||||
RequestFormatter interface {
|
||||
// AppendRequestLog appends a log line to line with or without a trailing newline
|
||||
AppendRequestLog(line []byte, req *http.Request, res *http.Response) []byte
|
||||
@@ -53,6 +60,7 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
StdoutbufSize = 64
|
||||
MinBufferSize = 4 * kilobyte
|
||||
MaxBufferSize = 1 * megabyte
|
||||
)
|
||||
@@ -79,6 +87,22 @@ func NewMockAccessLogger(parent task.Parent, cfg *RequestLoggerConfig) *AccessLo
|
||||
return NewAccessLoggerWithIO(parent, NewMockFile(), cfg)
|
||||
}
|
||||
|
||||
func unwrap[Writer any](w io.Writer) []Writer {
|
||||
var result []Writer
|
||||
if unwrapped, ok := w.(MultiWriterInterface); ok {
|
||||
for _, w := range unwrapped.Unwrap() {
|
||||
if unwrapped, ok := w.(Writer); ok {
|
||||
result = append(result, unwrapped)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
if unwrapped, ok := w.(Writer); ok {
|
||||
return []Writer{unwrapped}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewAccessLoggerWithIO(parent task.Parent, writer WriterWithName, anyCfg AnyConfig) *AccessLogger {
|
||||
cfg := anyCfg.ToConfig()
|
||||
if cfg.BufferSize == 0 {
|
||||
@@ -90,6 +114,10 @@ func NewAccessLoggerWithIO(parent task.Parent, writer WriterWithName, anyCfg Any
|
||||
if cfg.BufferSize > MaxBufferSize {
|
||||
cfg.BufferSize = MaxBufferSize
|
||||
}
|
||||
if _, ok := writer.(*os.File); ok {
|
||||
cfg.BufferSize = StdoutbufSize
|
||||
}
|
||||
|
||||
l := &AccessLogger{
|
||||
task: parent.Subtask("accesslog."+writer.Name(), true),
|
||||
cfg: cfg,
|
||||
@@ -99,23 +127,8 @@ func NewAccessLoggerWithIO(parent task.Parent, writer WriterWithName, anyCfg Any
|
||||
logger: logging.With().Str("file", writer.Name()).Logger(),
|
||||
}
|
||||
|
||||
if unwrapped, ok := writer.(MultiWriterInterface); ok {
|
||||
for _, w := range unwrapped.Unwrap() {
|
||||
if sr, ok := w.(supportRotate); ok {
|
||||
l.supportRotate = append(l.supportRotate, sr)
|
||||
}
|
||||
if closer, ok := w.(io.Closer); ok {
|
||||
l.closer = append(l.closer, closer)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if sr, ok := writer.(supportRotate); ok {
|
||||
l.supportRotate = append(l.supportRotate, sr)
|
||||
}
|
||||
if closer, ok := writer.(io.Closer); ok {
|
||||
l.closer = append(l.closer, closer)
|
||||
}
|
||||
}
|
||||
l.supportRotate = unwrap[supportRotate](writer)
|
||||
l.closer = unwrap[io.Closer](writer)
|
||||
|
||||
if cfg.req != nil {
|
||||
fmt := CommonFormatter{cfg: &cfg.req.Fields}
|
||||
|
||||
@@ -2,8 +2,9 @@ package accesslog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
pathPkg "path"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
type File struct {
|
||||
*os.File
|
||||
f *os.File
|
||||
|
||||
// os.File.Name() may not equal to key of `openedFiles`.
|
||||
// Store it for later delete from `openedFiles`.
|
||||
@@ -25,21 +26,25 @@ var (
|
||||
openedFilesMu sync.Mutex
|
||||
)
|
||||
|
||||
func newFileIO(path string) (WriterWithName, error) {
|
||||
func newFileIO(path string) (SupportRotate, error) {
|
||||
openedFilesMu.Lock()
|
||||
defer openedFilesMu.Unlock()
|
||||
|
||||
var file *File
|
||||
path = pathPkg.Clean(path)
|
||||
path = filepath.Clean(path)
|
||||
if opened, ok := openedFiles[path]; ok {
|
||||
opened.refCount.Add()
|
||||
return opened, nil
|
||||
} else {
|
||||
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o644)
|
||||
// cannot open as O_APPEND as we need Seek and WriteAt
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0o644)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("access log open error: %w", err)
|
||||
}
|
||||
file = &File{File: f, path: path, refCount: utils.NewRefCounter()}
|
||||
if _, err := f.Seek(0, io.SeekEnd); err != nil {
|
||||
return nil, fmt.Errorf("access log seek error: %w", err)
|
||||
}
|
||||
file = &File{f: f, path: path, refCount: utils.NewRefCounter()}
|
||||
openedFiles[path] = file
|
||||
go file.closeOnZero()
|
||||
}
|
||||
@@ -47,6 +52,30 @@ func newFileIO(path string) (WriterWithName, error) {
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func (f *File) Name() string {
|
||||
return f.f.Name()
|
||||
}
|
||||
|
||||
func (f *File) Write(p []byte) (n int, err error) {
|
||||
return f.f.Write(p)
|
||||
}
|
||||
|
||||
func (f *File) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
return f.f.ReadAt(p, off)
|
||||
}
|
||||
|
||||
func (f *File) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
return f.f.WriteAt(p, off)
|
||||
}
|
||||
|
||||
func (f *File) Seek(offset int64, whence int) (int64, error) {
|
||||
return f.f.Seek(offset, whence)
|
||||
}
|
||||
|
||||
func (f *File) Truncate(size int64) error {
|
||||
return f.f.Truncate(size)
|
||||
}
|
||||
|
||||
func (f *File) Close() error {
|
||||
f.refCount.Sub()
|
||||
return nil
|
||||
@@ -62,5 +91,5 @@ func (f *File) closeOnZero() {
|
||||
openedFilesMu.Lock()
|
||||
delete(openedFiles, f.path)
|
||||
openedFilesMu.Unlock()
|
||||
f.File.Close()
|
||||
f.f.Close()
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
type supportRotate interface {
|
||||
io.ReadSeeker
|
||||
io.Seeker
|
||||
io.ReaderAt
|
||||
io.WriterAt
|
||||
Truncate(size int64) error
|
||||
@@ -66,9 +66,23 @@ var rotateBytePool = synk.NewBytesPool(0, 16*1024*1024)
|
||||
// If the file does not need to be rotated, it returns nil, nil.
|
||||
func rotateLogFile(file supportRotate, config *Retention) (result *RotateResult, err error) {
|
||||
if config.KeepSize > 0 {
|
||||
return rotateLogFileBySize(file, config)
|
||||
result, err = rotateLogFileBySize(file, config)
|
||||
} else {
|
||||
result, err = rotateLogFileByPolicy(file, config)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := file.Seek(0, io.SeekEnd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func rotateLogFileByPolicy(file supportRotate, config *Retention) (result *RotateResult, err error) {
|
||||
var shouldStop func() bool
|
||||
t := utils.TimeNow()
|
||||
|
||||
@@ -234,7 +248,6 @@ var timeJSON = []byte(`"time":"`)
|
||||
//
|
||||
// The returned time is not validated.
|
||||
func ExtractTime(line []byte) []byte {
|
||||
//TODO: optimize this
|
||||
switch line[0] {
|
||||
case '{': // JSON format
|
||||
if i := bytes.Index(line, timeJSON); i != -1 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package systeminfo
|
||||
package systeminfo // import github.com/yusing/go-proxy/internal/metrics/systeminfo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
@@ -133,11 +133,6 @@ func (lb *LoadBalancer) AddServer(srv Server) {
|
||||
|
||||
lb.rebalance()
|
||||
lb.impl.OnAddServer(srv)
|
||||
|
||||
lb.l.Debug().
|
||||
Str("action", "add").
|
||||
Str("server", srv.Name()).
|
||||
Msgf("%d servers available", lb.pool.Size())
|
||||
}
|
||||
|
||||
func (lb *LoadBalancer) RemoveServer(srv Server) {
|
||||
|
||||
@@ -17,8 +17,7 @@ import (
|
||||
)
|
||||
|
||||
type cloudflareRealIP struct {
|
||||
realIP realIP
|
||||
Recursive bool
|
||||
realIP realIP
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -47,7 +46,7 @@ var CloudflareRealIP = NewMiddleware[cloudflareRealIP]()
|
||||
func (cri *cloudflareRealIP) setup() {
|
||||
cri.realIP.RealIPOpts = RealIPOpts{
|
||||
Header: "CF-Connecting-IP",
|
||||
Recursive: cri.Recursive,
|
||||
Recursive: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ var allMiddlewares = map[string]*Middleware{
|
||||
}
|
||||
|
||||
var (
|
||||
ErrUnknownMiddleware = gperr.New("unknown middleware")
|
||||
ErrDuplicatedMiddleware = gperr.New("duplicated middleware")
|
||||
ErrUnknownMiddleware = gperr.New("unknown middleware")
|
||||
ErrMiddlewareAlreadyExists = gperr.New("middleware with the same name already exists")
|
||||
)
|
||||
|
||||
func Get(name string) (*Middleware, Error) {
|
||||
@@ -69,7 +69,7 @@ func LoadComposeFiles() {
|
||||
for name, m := range mws {
|
||||
name = strutils.ToLowerNoSnake(name)
|
||||
if _, ok := allMiddlewares[name]; ok {
|
||||
errs.Add(ErrDuplicatedMiddleware.Subject(name))
|
||||
errs.Add(ErrMiddlewareAlreadyExists.Subject(name))
|
||||
continue
|
||||
}
|
||||
allMiddlewares[name] = m
|
||||
|
||||
@@ -72,6 +72,11 @@ func (amw *oidcMiddleware) before(w http.ResponseWriter, r *http.Request) (proce
|
||||
return false
|
||||
}
|
||||
|
||||
if r.URL.Path == auth.OIDCLogoutPath {
|
||||
amw.auth.LogoutHandler(w, r)
|
||||
return true
|
||||
}
|
||||
|
||||
err := amw.auth.CheckToken(r)
|
||||
if err == nil {
|
||||
return true
|
||||
|
||||
@@ -10,15 +10,18 @@ import (
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/yusing/go-proxy/internal/acl"
|
||||
"github.com/yusing/go-proxy/internal/autocert"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
)
|
||||
|
||||
type CertProvider interface {
|
||||
GetCert(*tls.ClientHelloInfo) (*tls.Certificate, error)
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
Name string
|
||||
CertProvider *autocert.Provider
|
||||
CertProvider CertProvider
|
||||
http *http.Server
|
||||
https *http.Server
|
||||
startTime time.Time
|
||||
@@ -31,7 +34,7 @@ type Options struct {
|
||||
Name string
|
||||
HTTPAddr string
|
||||
HTTPSAddr string
|
||||
CertProvider *autocert.Provider
|
||||
CertProvider CertProvider
|
||||
Handler http.Handler
|
||||
ACL *acl.Config
|
||||
}
|
||||
|
||||
@@ -83,9 +83,6 @@ func (disp *Dispatcher) start() {
|
||||
}
|
||||
|
||||
func (disp *Dispatcher) dispatch(msg *LogMessage) {
|
||||
if true {
|
||||
return
|
||||
}
|
||||
task := disp.task.Subtask("dispatcher")
|
||||
defer task.Finish("notif dispatched")
|
||||
|
||||
|
||||
@@ -80,8 +80,11 @@ func (p *DockerProvider) loadRoutesImpl() (route.Routes, gperr.Error) {
|
||||
errs.Add(err.Subject(container.ContainerName))
|
||||
}
|
||||
for k, v := range newEntries {
|
||||
if routes.Contains(k) {
|
||||
errs.Addf("duplicated alias %s", k)
|
||||
if conflict, ok := routes[k]; ok {
|
||||
errs.Add(gperr.Multiline().
|
||||
Addf("route with alias %s already exists", k).
|
||||
Addf("container %s", container.ContainerName).
|
||||
Addf("conflicting container %s", conflict.Container.ContainerName))
|
||||
} else {
|
||||
routes[k] = v
|
||||
}
|
||||
|
||||
@@ -12,19 +12,13 @@ import (
|
||||
type EventHandler struct {
|
||||
provider *Provider
|
||||
|
||||
errs *gperr.Builder
|
||||
added *gperr.Builder
|
||||
removed *gperr.Builder
|
||||
updated *gperr.Builder
|
||||
errs *gperr.Builder
|
||||
}
|
||||
|
||||
func (p *Provider) newEventHandler() *EventHandler {
|
||||
return &EventHandler{
|
||||
provider: p,
|
||||
errs: gperr.NewBuilder("event errors"),
|
||||
added: gperr.NewBuilder("added"),
|
||||
removed: gperr.NewBuilder("removed"),
|
||||
updated: gperr.NewBuilder("updated"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,15 +82,12 @@ func (handler *EventHandler) Add(parent task.Parent, route *route.Route) {
|
||||
err := handler.provider.startRoute(parent, route)
|
||||
if err != nil {
|
||||
handler.errs.Add(err.Subject("add"))
|
||||
} else {
|
||||
handler.added.Adds(route.Alias)
|
||||
}
|
||||
}
|
||||
|
||||
func (handler *EventHandler) Remove(route *route.Route) {
|
||||
route.Finish("route removed")
|
||||
delete(handler.provider.routes, route.Alias)
|
||||
handler.removed.Adds(route.Alias)
|
||||
}
|
||||
|
||||
func (handler *EventHandler) Update(parent task.Parent, oldRoute *route.Route, newRoute *route.Route) {
|
||||
@@ -104,18 +95,11 @@ func (handler *EventHandler) Update(parent task.Parent, oldRoute *route.Route, n
|
||||
err := handler.provider.startRoute(parent, newRoute)
|
||||
if err != nil {
|
||||
handler.errs.Add(err.Subject("update"))
|
||||
} else {
|
||||
handler.updated.Adds(newRoute.Alias)
|
||||
}
|
||||
}
|
||||
|
||||
func (handler *EventHandler) Log() {
|
||||
results := gperr.NewBuilder("event occurred")
|
||||
results.AddFrom(handler.added, false)
|
||||
results.AddFrom(handler.removed, false)
|
||||
results.AddFrom(handler.updated, false)
|
||||
results.AddFrom(handler.errs, false)
|
||||
if result := results.String(); result != "" {
|
||||
handler.provider.Logger().Info().Msg(result)
|
||||
if err := handler.errs.Error(); err != nil {
|
||||
handler.provider.Logger().Info().Msg(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,25 +15,26 @@ import (
|
||||
loadbalance "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp/middleware"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy"
|
||||
"github.com/yusing/go-proxy/internal/net/types"
|
||||
"github.com/yusing/go-proxy/internal/route/routes"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/internal/watcher/health"
|
||||
"github.com/yusing/go-proxy/internal/watcher/health/monitor"
|
||||
)
|
||||
|
||||
type (
|
||||
ReveseProxyRoute struct {
|
||||
*Route
|
||||
type ReveseProxyRoute struct {
|
||||
*Route
|
||||
|
||||
HealthMon health.HealthMonitor `json:"health,omitempty"`
|
||||
HealthMon health.HealthMonitor `json:"health,omitempty"`
|
||||
|
||||
loadBalancer *loadbalancer.LoadBalancer
|
||||
handler http.Handler
|
||||
rp *reverseproxy.ReverseProxy
|
||||
loadBalancer *loadbalancer.LoadBalancer
|
||||
handler http.Handler
|
||||
rp *reverseproxy.ReverseProxy
|
||||
|
||||
task *task.Task
|
||||
}
|
||||
)
|
||||
task *task.Task
|
||||
}
|
||||
|
||||
var _ routes.ReverseProxyRoute = (*ReveseProxyRoute)(nil)
|
||||
|
||||
// var globalMux = http.NewServeMux() // TODO: support regex subdomain matching.
|
||||
|
||||
@@ -45,7 +46,7 @@ func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, gperr.Error) {
|
||||
a := base.Agent()
|
||||
if a != nil {
|
||||
trans = a.Transport()
|
||||
proxyURL = agent.HTTPProxyURL
|
||||
proxyURL = types.NewURL(agent.HTTPProxyURL)
|
||||
} else {
|
||||
trans = gphttp.NewTransport()
|
||||
if httpConfig.NoTLSVerify {
|
||||
@@ -87,6 +88,11 @@ func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, gperr.Error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// ReverseProxy implements routes.ReverseProxyRoute.
|
||||
func (r *ReveseProxyRoute) ReverseProxy() *reverseproxy.ReverseProxy {
|
||||
return r.rp
|
||||
}
|
||||
|
||||
// Start implements task.TaskStarter.
|
||||
func (r *ReveseProxyRoute) Start(parent task.Parent) gperr.Error {
|
||||
if existing, ok := routes.HTTP.Get(r.Key()); ok && !r.UseLoadBalance() {
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
||||
"github.com/yusing/go-proxy/internal"
|
||||
"github.com/yusing/go-proxy/internal/docker"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/homepage"
|
||||
@@ -152,6 +151,10 @@ func (r *Route) Validate() gperr.Error {
|
||||
}
|
||||
}
|
||||
|
||||
if r.Container != nil && r.Container.IdlewatcherConfig != nil {
|
||||
r.Idlewatcher = r.Container.IdlewatcherConfig
|
||||
}
|
||||
|
||||
// return error if route is localhost:<godoxy_port>
|
||||
switch r.Host {
|
||||
case "localhost", "127.0.0.1":
|
||||
@@ -484,7 +487,7 @@ func (r *Route) FinalizeHomepageConfig() {
|
||||
} else {
|
||||
key = r.Alias
|
||||
}
|
||||
displayName, ok := internal.GetDisplayName(key)
|
||||
displayName, ok := homepage.GetDisplayName(key)
|
||||
if ok {
|
||||
hp.Name = displayName
|
||||
} else {
|
||||
|
||||
@@ -53,7 +53,7 @@ func (mon *HTTPHealthMonitor) CheckHealth() (result *health.HealthCheckResult, e
|
||||
}
|
||||
req.Close = true
|
||||
req.Header.Set("Connection", "close")
|
||||
req.Header.Set("User-Agent", "GoDoxy/"+pkg.GetVersion())
|
||||
req.Header.Set("User-Agent", "GoDoxy/"+pkg.GetVersion().String())
|
||||
|
||||
start := time.Now()
|
||||
resp, respErr := pinger.Do(req)
|
||||
|
||||
111
pkg/version.go
111
pkg/version.go
@@ -1,7 +1,112 @@
|
||||
package pkg
|
||||
|
||||
var version = "unset"
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetVersion() string {
|
||||
return version
|
||||
func GetVersion() Version {
|
||||
return currentVersion
|
||||
}
|
||||
|
||||
func GetLastVersion() Version {
|
||||
return lastVersion
|
||||
}
|
||||
|
||||
func GetVersionHTTPHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(GetVersion().String()))
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
currentVersion = ParseVersion(version)
|
||||
|
||||
// ignore errors
|
||||
// versionFile := filepath.Join(common.DataDir, "version")
|
||||
// var lastVersionStr string
|
||||
// f, err := os.OpenFile(versionFile, os.O_RDWR|os.O_CREATE, 0o644)
|
||||
// if err == nil {
|
||||
// _, err = fmt.Fscanf(f, "%s", &lastVersionStr)
|
||||
// lastVersion = ParseVersion(lastVersionStr)
|
||||
// }
|
||||
// if err != nil && !os.IsNotExist(err) {
|
||||
// logging.Warn().Err(err).Msg("failed to read version file")
|
||||
// return
|
||||
// }
|
||||
// if err := f.Truncate(0); err != nil {
|
||||
// logging.Warn().Err(err).Msg("failed to truncate version file")
|
||||
// return
|
||||
// }
|
||||
// _, err = f.WriteString(version)
|
||||
// if err != nil {
|
||||
// logging.Warn().Err(err).Msg("failed to save version file")
|
||||
// return
|
||||
// }
|
||||
}
|
||||
|
||||
type Version struct{ Generation, Major, Minor int }
|
||||
|
||||
func Ver(major, minor, patch int) Version {
|
||||
return Version{major, minor, patch}
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
return fmt.Sprintf("v%d.%d.%d", v.Generation, v.Major, v.Minor)
|
||||
}
|
||||
|
||||
func (v Version) MarshalText() ([]byte, error) {
|
||||
return []byte(v.String()), nil
|
||||
}
|
||||
|
||||
func (v Version) IsNewerMajorThan(other Version) bool {
|
||||
if v.Generation != other.Generation {
|
||||
return v.Generation > other.Generation
|
||||
}
|
||||
return v.Major > other.Major
|
||||
}
|
||||
|
||||
func (v Version) IsEqual(other Version) bool {
|
||||
return v.Generation == other.Generation && v.Major == other.Major && v.Minor == other.Minor
|
||||
}
|
||||
|
||||
var (
|
||||
version = "unset"
|
||||
currentVersion Version
|
||||
lastVersion Version
|
||||
)
|
||||
|
||||
var versionRegex = regexp.MustCompile(`^v(\d+)\.(\d+)\.(\d+)(\-\w+)?$`)
|
||||
|
||||
func ParseVersion(v string) (ver Version) {
|
||||
if v == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if !versionRegex.MatchString(v) { // likely feature branch (e.g. feat/some-feature)
|
||||
return
|
||||
}
|
||||
|
||||
v = strings.Split(v, "-")[0]
|
||||
v = strings.TrimPrefix(v, "v")
|
||||
parts := strings.Split(v, ".")
|
||||
if len(parts) != 3 {
|
||||
return
|
||||
}
|
||||
gen, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
major, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
minor, err := strconv.Atoi(parts[2])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return Ver(gen, major, minor)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,33 @@ check_pkg() {
|
||||
fi
|
||||
}
|
||||
|
||||
start-service() {
|
||||
systemctl daemon-reload
|
||||
# if command is empty
|
||||
if [ -z "$1" ]; then
|
||||
echo "Enabling and starting the agent service"
|
||||
else
|
||||
echo "Reloading the agent service"
|
||||
fi
|
||||
if ! systemctl enable --now $name; then
|
||||
echo "Failed to enable and start the service. Check with: systemctl status $name"
|
||||
exit 1
|
||||
fi
|
||||
echo "Checking if the agent service is started successfully"
|
||||
if [ "$(systemctl is-active $name)" != "active" ]; then
|
||||
echo "Agent service failed to start, details below:"
|
||||
systemctl status $name
|
||||
more $log_path
|
||||
exit 1
|
||||
fi
|
||||
# if command is empty
|
||||
if [ -z "$1" ]; then
|
||||
echo "Agent installed successfully"
|
||||
else
|
||||
echo "Agent updated successfully"
|
||||
fi
|
||||
}
|
||||
|
||||
# check if curl and jq are installed
|
||||
check_pkg curl
|
||||
check_pkg jq
|
||||
@@ -27,22 +54,24 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# check variables
|
||||
if [ -z "$AGENT_NAME" ]; then
|
||||
echo "AGENT_NAME is not set"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$AGENT_PORT" ]; then
|
||||
echo "AGENT_PORT is not set"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$AGENT_CA_CERT" ]; then
|
||||
echo "AGENT_CA_CERT is not set"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$AGENT_SSL_CERT" ]; then
|
||||
echo "AGENT_SSL_CERT is not set"
|
||||
exit 1
|
||||
# check variables if command is empty
|
||||
if [ -z "$1" ]; then
|
||||
if [ -z "$AGENT_NAME" ]; then
|
||||
echo "AGENT_NAME is not set"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$AGENT_PORT" ]; then
|
||||
echo "AGENT_PORT is not set"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$AGENT_CA_CERT" ]; then
|
||||
echo "AGENT_CA_CERT is not set"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$AGENT_SSL_CERT" ]; then
|
||||
echo "AGENT_SSL_CERT is not set"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# init variables
|
||||
@@ -104,7 +133,24 @@ if [ -z "$api_response" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bin_url=$(echo "$api_response" | jq -r '.assets[] | select(.name | contains("'$filename'")) | .browser_download_url')
|
||||
asset=$(echo "$api_response" | jq -r '.assets[] | select(.name | contains("'$filename'"))')
|
||||
bin_last_updated=$(date -d "$(echo "$asset" | jq -r '.updated_at')" +%s)
|
||||
# check if last_updated == mod time of bin_path
|
||||
if [ -f "$bin_path" ]; then
|
||||
bin_mod_time=$(stat -c %Y "$bin_path")
|
||||
if [ "$bin_last_updated" -eq "$bin_mod_time" ]; then
|
||||
echo "Binary is up to date"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# check if command is update
|
||||
if [ "$1" = "update" ]; then
|
||||
echo "Stopping the agent"
|
||||
systemctl stop $name || true
|
||||
fi
|
||||
|
||||
bin_url=$(echo "$asset" | jq -r '.browser_download_url')
|
||||
if [ -z "$bin_url" ] || [ "$bin_url" = "null" ]; then
|
||||
echo "Failed to find binary for architecture: $arch"
|
||||
exit 1
|
||||
@@ -116,9 +162,19 @@ if ! curl -L -f "$bin_url" -o $bin_path; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Setting binary modification time"
|
||||
touch -d "@${bin_last_updated}" "$bin_path"
|
||||
|
||||
echo "Making the agent binary executable"
|
||||
chmod +x $bin_path
|
||||
|
||||
# check if command is update
|
||||
if [ "$1" = "update" ]; then
|
||||
echo "Starting the agent"
|
||||
start-service
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Creating the environment file"
|
||||
cat <<EOF >$env_file
|
||||
AGENT_NAME="${AGENT_NAME}"
|
||||
@@ -169,18 +225,4 @@ WantedBy=multi-user.target
|
||||
EOF
|
||||
chmod 644 $service_file
|
||||
|
||||
systemctl daemon-reload
|
||||
echo "Enabling and starting the agent service"
|
||||
if ! systemctl enable --now $name; then
|
||||
echo "Failed to enable and start the service. Check with: systemctl status $name"
|
||||
exit 1
|
||||
fi
|
||||
echo "Checking if the agent service is started successfully"
|
||||
if [ "$(systemctl is-active $name)" != "active" ]; then
|
||||
echo "Agent service failed to start, details below:"
|
||||
systemctl status $name
|
||||
more $log_path
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Agent installed successfully"
|
||||
start-service
|
||||
|
||||
Reference in New Issue
Block a user