mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-20 07:21:26 +02:00
Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eef994082c | ||
|
|
8c670ab92e | ||
|
|
d11ddb7c91 | ||
|
|
78aea4b4d2 | ||
|
|
80dd142861 | ||
|
|
92aa61e732 | ||
|
|
848f26aa86 | ||
|
|
81e500fcfc | ||
|
|
f417e0fa25 | ||
|
|
cb5a8e7b9d | ||
|
|
16cad11e89 | ||
|
|
2bfbdbf519 | ||
|
|
d5e9a7b3b6 | ||
|
|
7ea415078f | ||
|
|
e67704695b | ||
|
|
804c7eec60 | ||
|
|
ea8be56bf8 | ||
|
|
20c77edce5 | ||
|
|
4f2f0f58e2 | ||
|
|
ac8ad149b8 | ||
|
|
14ec80c883 | ||
|
|
5de5f854ce | ||
|
|
3d8994b42e | ||
|
|
66043e4a26 | ||
|
|
d1e403e16f | ||
|
|
e72e20af69 | ||
|
|
ad6201c27a | ||
|
|
c4c9e9300c | ||
|
|
b23c3f1c3b | ||
|
|
38c0419483 | ||
|
|
357ce38b18 | ||
|
|
ef34c3ffdd | ||
|
|
2e411373a2 | ||
|
|
3dedd66ad1 | ||
|
|
98f047d88a | ||
|
|
973a58e982 | ||
|
|
4b55d1c607 | ||
|
|
63eff4707c | ||
|
|
55a74c36b0 | ||
|
|
fbabb7b7fb | ||
|
|
7a1841e9a5 | ||
|
|
d82bfd0ebd | ||
|
|
1f41c035ea | ||
|
|
c2c9f42fb3 | ||
|
|
60cfff3435 | ||
|
|
c93a460043 | ||
|
|
9bf7a0beef | ||
|
|
c89c737ecd | ||
|
|
382fc61a9c | ||
|
|
b2de33e835 | ||
|
|
86644054e6 | ||
|
|
c2dcabe144 | ||
|
|
c59ddc1df6 | ||
|
|
f4db874fd6 | ||
|
|
f334f5c13c | ||
|
|
5acc4c3894 | ||
|
|
a8aa82f687 | ||
|
|
0f3a1ac6e6 | ||
|
|
9fceda6729 | ||
|
|
becb49e864 | ||
|
|
3aed41e078 | ||
|
|
8047067b2b | ||
|
|
c3fa7c66a7 | ||
|
|
cab68807ee | ||
|
|
d08be872a0 | ||
|
|
bb5f0cdf09 | ||
|
|
a150f1a628 | ||
|
|
584db2efce | ||
|
|
c27bc0e129 | ||
|
|
b46b464e65 | ||
|
|
52ec309f6b | ||
|
|
6051f75145 | ||
|
|
f4f104d206 | ||
|
|
448a2fbd6f | ||
|
|
74224c8e87 | ||
|
|
ae57edfcb0 | ||
|
|
fc23e262d7 | ||
|
|
11a3935e0c | ||
|
|
42e7adbf86 | ||
|
|
1e0c7a15d8 | ||
|
|
ba8edb160f | ||
|
|
4852efcf9c | ||
|
|
ef40793301 | ||
|
|
80862bcd2e | ||
|
|
45b16abd68 | ||
|
|
f411e17d80 | ||
|
|
024100aa8c | ||
|
|
9d508c5950 | ||
|
|
2ff5e5c0b6 | ||
|
|
2a05c6a630 | ||
|
|
6776f20332 | ||
|
|
5043ef778f | ||
|
|
22bcf1201b | ||
|
|
acecd827d6 | ||
|
|
b2713a4b83 | ||
|
|
e2aeef3a86 | ||
|
|
9545482a44 | ||
|
|
d406b940d9 | ||
|
|
dc1175ad69 | ||
|
|
1409a4e8b9 | ||
|
|
8ec9752656 | ||
|
|
a932688ca3 | ||
|
|
55c1c918ba | ||
|
|
14e243d245 | ||
|
|
f7149453d6 | ||
|
|
00d137d05c | ||
|
|
f9affba9fc | ||
|
|
6b3bf84148 | ||
|
|
62a667758d | ||
|
|
ddd27156fc | ||
|
|
af8e2d56b2 | ||
|
|
74a215b894 | ||
|
|
ccdc0046fd | ||
|
|
2f7fdc4c51 | ||
|
|
de1f4da126 | ||
|
|
a48ccb4423 | ||
|
|
193fd9a249 | ||
|
|
0bc4c4af77 | ||
|
|
5fa1417add | ||
|
|
b763c92645 | ||
|
|
09b14a47e9 | ||
|
|
83a69322fa | ||
|
|
3aba5a1911 | ||
|
|
ca805edfe0 | ||
|
|
7205bf47de | ||
|
|
b12999210f | ||
|
|
8b8969f033 | ||
|
|
025ebab1ce | ||
|
|
ea7bd0d19a |
2
.github/workflows/agent-binary.yml
vendored
2
.github/workflows/agent-binary.yml
vendored
@@ -25,6 +25,8 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|||||||
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[submodule "internal/gopsutil"]
|
||||||
|
path = internal/gopsutil
|
||||||
|
url = https://github.com/godoxy-app/gopsutil.git
|
||||||
|
[submodule "internal/go-oidc"]
|
||||||
|
path = internal/go-oidc
|
||||||
|
url = https://github.com/godoxy-app/go-oidc.git
|
||||||
|
[submodule "goutils"]
|
||||||
|
path = goutils
|
||||||
|
url = https://github.com/yusing/goutils.git
|
||||||
@@ -70,7 +70,6 @@ linters:
|
|||||||
govet:
|
govet:
|
||||||
disable:
|
disable:
|
||||||
- shadow
|
- shadow
|
||||||
- fieldalignment
|
|
||||||
enable-all: true
|
enable-all: true
|
||||||
misspell:
|
misspell:
|
||||||
locale: US
|
locale: US
|
||||||
@@ -108,8 +107,7 @@ linters:
|
|||||||
- all
|
- all
|
||||||
- -SA1019
|
- -SA1019
|
||||||
dot-import-whitelist:
|
dot-import-whitelist:
|
||||||
- github.com/yusing/go-proxy/internal/utils/testing
|
- github.com/yusing/godoxy/internal/utils/testing
|
||||||
- github.com/yusing/go-proxy/internal/api/v1/utils
|
|
||||||
tagalign:
|
tagalign:
|
||||||
align: false
|
align: false
|
||||||
sort: true
|
sort: true
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ lint:
|
|||||||
- markdownlint
|
- markdownlint
|
||||||
- yamllint
|
- yamllint
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.467
|
- checkov@3.2.471
|
||||||
- golangci-lint2@2.4.0
|
- golangci-lint2@2.5.0
|
||||||
- hadolint@2.12.1-beta
|
- hadolint@2.14.0
|
||||||
- actionlint@1.7.7
|
- actionlint@1.7.7
|
||||||
- git-diff-check
|
- git-diff-check
|
||||||
- gofmt@1.20.4
|
- gofmt@1.20.4
|
||||||
@@ -32,7 +32,7 @@ lint:
|
|||||||
- prettier@3.6.2
|
- prettier@3.6.2
|
||||||
- shellcheck@0.11.0
|
- shellcheck@0.11.0
|
||||||
- shfmt@3.6.0
|
- shfmt@3.6.0
|
||||||
- trufflehog@3.90.5
|
- trufflehog@3.90.8
|
||||||
actions:
|
actions:
|
||||||
disabled:
|
disabled:
|
||||||
- trunk-announce
|
- trunk-announce
|
||||||
|
|||||||
4
.vscode/settings.example.json
vendored
4
.vscode/settings.example.json
vendored
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"yaml.schemas": {
|
"yaml.schemas": {
|
||||||
"https://github.com/yusing/godoxy-webui/raw/refs/heads/main/src/types/godoxy/config.schema.json": [
|
"https://github.com/yusing/godoxy-webui/raw/refs/heads/main/types/godoxy/config.schema.json": [
|
||||||
"config.example.yml",
|
"config.example.yml",
|
||||||
"config.yml"
|
"config.yml"
|
||||||
],
|
],
|
||||||
"https://github.com/yusing/godoxy-webui/raw/refs/heads/main/src/types/godoxy/routes.schema.json": [
|
"https://github.com/yusing/godoxy-webui/raw/refs/heads/main/types/godoxy/routes.schema.json": [
|
||||||
"providers.example.yml"
|
"providers.example.yml"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
15
Dockerfile
15
Dockerfile
@@ -1,5 +1,5 @@
|
|||||||
# Stage 1: deps
|
# Stage 1: deps
|
||||||
FROM golang:1.25.1-alpine AS deps
|
FROM golang:1.25.2-alpine AS deps
|
||||||
HEALTHCHECK NONE
|
HEALTHCHECK NONE
|
||||||
|
|
||||||
# package version does not matter
|
# package version does not matter
|
||||||
@@ -7,14 +7,19 @@ HEALTHCHECK NONE
|
|||||||
RUN apk add --no-cache tzdata make libcap-setcap
|
RUN apk add --no-cache tzdata make libcap-setcap
|
||||||
|
|
||||||
ENV GOPATH=/root/go
|
ENV GOPATH=/root/go
|
||||||
|
ENV GOCACHE=/root/.cache/go-build
|
||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
|
COPY goutils/go.mod goutils/go.sum ./goutils/
|
||||||
|
COPY internal/go-oidc/go.mod internal/go-oidc/go.sum ./internal/go-oidc/
|
||||||
|
COPY internal/gopsutil/go.mod internal/gopsutil/go.sum ./internal/gopsutil/
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
|
|
||||||
# remove godoxy stuff from go.mod first
|
# remove godoxy stuff from go.mod first
|
||||||
RUN sed -i '/^module github\.com\/yusing\/go-proxy/!{/github\.com\/yusing\/go-proxy/d}' go.mod && \
|
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||||
go mod download -x
|
--mount=type=cache,target=/root/go/pkg/mod \
|
||||||
|
sed -i '/^module github\.com\/yusing\/godoxy/!{/github\.com\/yusing\/godoxy/d}' go.mod && go mod download -x
|
||||||
|
|
||||||
# Stage 2: builder
|
# Stage 2: builder
|
||||||
FROM deps AS builder
|
FROM deps AS builder
|
||||||
@@ -28,6 +33,7 @@ COPY internal ./internal
|
|||||||
COPY pkg ./pkg
|
COPY pkg ./pkg
|
||||||
COPY agent ./agent
|
COPY agent ./agent
|
||||||
COPY socket-proxy ./socket-proxy
|
COPY socket-proxy ./socket-proxy
|
||||||
|
COPY goutils ./goutils
|
||||||
|
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
ENV VERSION=${VERSION}
|
ENV VERSION=${VERSION}
|
||||||
@@ -35,9 +41,6 @@ ENV VERSION=${VERSION}
|
|||||||
ARG MAKE_ARGS
|
ARG MAKE_ARGS
|
||||||
ENV MAKE_ARGS=${MAKE_ARGS}
|
ENV MAKE_ARGS=${MAKE_ARGS}
|
||||||
|
|
||||||
ENV GOCACHE=/root/.cache/go-build
|
|
||||||
ENV GOPATH=/root/go
|
|
||||||
|
|
||||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||||
--mount=type=cache,target=/root/go/pkg/mod \
|
--mount=type=cache,target=/root/go/pkg/mod \
|
||||||
make ${MAKE_ARGS} docker=1 build
|
make ${MAKE_ARGS} docker=1 build
|
||||||
|
|||||||
25
Makefile
25
Makefile
@@ -6,7 +6,7 @@ export GOOS = linux
|
|||||||
WEBUI_DIR ?= ../godoxy-frontend
|
WEBUI_DIR ?= ../godoxy-frontend
|
||||||
DOCS_DIR ?= ../godoxy-wiki
|
DOCS_DIR ?= ../godoxy-wiki
|
||||||
|
|
||||||
LDFLAGS = -X github.com/yusing/go-proxy/pkg.version=${VERSION} -checklinkname=0
|
LDFLAGS = -X github.com/yusing/goutils/version.version=${VERSION} -checklinkname=0
|
||||||
|
|
||||||
ifeq ($(agent), 1)
|
ifeq ($(agent), 1)
|
||||||
NAME = godoxy-agent
|
NAME = godoxy-agent
|
||||||
@@ -26,16 +26,15 @@ ifeq ($(trace), 1)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(race), 1)
|
ifeq ($(race), 1)
|
||||||
debug = 1
|
CGO_ENABLED = 1
|
||||||
BUILD_FLAGS += -race
|
GODOXY_DEBUG = 1
|
||||||
endif
|
BUILD_FLAGS += -tags debug -race
|
||||||
|
else ifeq ($(debug), 1)
|
||||||
ifeq ($(debug), 1)
|
|
||||||
CGO_ENABLED = 1
|
CGO_ENABLED = 1
|
||||||
GODOXY_DEBUG = 1
|
GODOXY_DEBUG = 1
|
||||||
BUILD_FLAGS += -gcflags=all='-N -l' -tags debug -asan
|
BUILD_FLAGS += -gcflags=all='-N -l' -tags debug -asan
|
||||||
else ifeq ($(pprof), 1)
|
else ifeq ($(pprof), 1)
|
||||||
CGO_ENABLED = 1
|
CGO_ENABLED = 0
|
||||||
GORACE = log_path=logs/pprof strip_path_prefix=$(shell pwd)/ halt_on_error=1
|
GORACE = log_path=logs/pprof strip_path_prefix=$(shell pwd)/ halt_on_error=1
|
||||||
BUILD_FLAGS += -tags pprof
|
BUILD_FLAGS += -tags pprof
|
||||||
VERSION := ${VERSION}-pprof
|
VERSION := ${VERSION}-pprof
|
||||||
@@ -72,7 +71,7 @@ endif
|
|||||||
.PHONY: debug
|
.PHONY: debug
|
||||||
|
|
||||||
test:
|
test:
|
||||||
GODOXY_TEST=1 go test ./internal/...
|
go test -v -race ./internal/...
|
||||||
|
|
||||||
docker-build-test:
|
docker-build-test:
|
||||||
docker build -t godoxy .
|
docker build -t godoxy .
|
||||||
@@ -114,13 +113,13 @@ run:
|
|||||||
cd ${PWD} && [ -f .env ] && godotenv -f .env go run ${BUILD_FLAGS} ./cmd
|
cd ${PWD} && [ -f .env ] && godotenv -f .env go run ${BUILD_FLAGS} ./cmd
|
||||||
|
|
||||||
dev:
|
dev:
|
||||||
docker compose -f dev.compose.yml up -t 0 -d
|
docker compose -f dev.compose.yml $(args)
|
||||||
|
|
||||||
dev-build: build
|
dev-build: build
|
||||||
docker compose -f dev.compose.yml up -t 0 -d --build
|
docker compose -f dev.compose.yml up -t 0 -d app --force-recreate
|
||||||
|
|
||||||
dev-logs:
|
dev-run: build
|
||||||
docker compose -f dev.compose.yml logs -f app
|
cd dev-data && ${BIN_PATH}
|
||||||
|
|
||||||
mtrace:
|
mtrace:
|
||||||
${BIN_PATH} debug-ls-mtrace > mtrace.json
|
${BIN_PATH} debug-ls-mtrace > mtrace.json
|
||||||
@@ -155,4 +154,4 @@ gen-swagger-markdown: gen-swagger
|
|||||||
gen-api-types: gen-swagger
|
gen-api-types: gen-swagger
|
||||||
# --disable-throw-on-error
|
# --disable-throw-on-error
|
||||||
pnpx swagger-typescript-api generate --sort-types --generate-union-enums --axios --add-readonly --route-types \
|
pnpx swagger-typescript-api generate --sort-types --generate-union-enums --axios --add-readonly --route-types \
|
||||||
--responses -o ${WEBUI_DIR}/lib -n api.ts -p internal/api/v1/docs/swagger.json
|
--responses -o ${WEBUI_DIR}/lib -n api.ts -p internal/api/v1/docs/swagger.json
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -33,6 +33,7 @@ Have questions? Ask [ChatGPT](https://chatgpt.com/g/g-6825390374b481919ad482f2e4
|
|||||||
- [Prerequisites](#prerequisites)
|
- [Prerequisites](#prerequisites)
|
||||||
- [Setup](#setup)
|
- [Setup](#setup)
|
||||||
- [How does GoDoxy work](#how-does-godoxy-work)
|
- [How does GoDoxy work](#how-does-godoxy-work)
|
||||||
|
- [Update / Uninstall system agent](#update--uninstall-system-agent)
|
||||||
- [Screenshots](#screenshots)
|
- [Screenshots](#screenshots)
|
||||||
- [idlesleeper](#idlesleeper)
|
- [idlesleeper](#idlesleeper)
|
||||||
- [Metrics and Logs](#metrics-and-logs)
|
- [Metrics and Logs](#metrics-and-logs)
|
||||||
@@ -58,6 +59,7 @@ Have questions? Ask [ChatGPT](https://chatgpt.com/g/g-6825390374b481919ad482f2e4
|
|||||||
- Country **(Maxmind account required)**
|
- Country **(Maxmind account required)**
|
||||||
- Timezone **(Maxmind account required)**
|
- Timezone **(Maxmind account required)**
|
||||||
- **Access logging**
|
- **Access logging**
|
||||||
|
- Periodic notification of access summaries for number of allowed and blocked connections
|
||||||
- **Advanced Automation**
|
- **Advanced Automation**
|
||||||
- Automatic SSL certificate management with Let's Encrypt ([using DNS-01 Challenge](https://docs.godoxy.dev/DNS-01-Providers))
|
- Automatic SSL certificate management with Let's Encrypt ([using DNS-01 Challenge](https://docs.godoxy.dev/DNS-01-Providers))
|
||||||
- Auto-configuration for Docker containers
|
- Auto-configuration for Docker containers
|
||||||
@@ -128,6 +130,20 @@ Configure Wildcard DNS Record(s) to point to machine running `GoDoxy`, e.g.
|
|||||||
>
|
>
|
||||||
> For example, with the label `proxy.aliases: qbt` you can access your app via `qbt.domain.com`.
|
> For example, with the label `proxy.aliases: qbt` you can access your app via `qbt.domain.com`.
|
||||||
|
|
||||||
|
## Update / Uninstall system agent
|
||||||
|
|
||||||
|
Update:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash -c "$(curl -fsSL https://github.com/yusing/godoxy/raw/refs/heads/main/scripts/install-agent.sh)" -- update
|
||||||
|
```
|
||||||
|
|
||||||
|
Uninstall:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash -c "$(curl -fsSL https://github.com/yusing/godoxy/raw/refs/heads/main/scripts/install-agent.sh)" -- uninstall
|
||||||
|
```
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
### idlesleeper
|
### idlesleeper
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
- [安裝](#安裝)
|
- [安裝](#安裝)
|
||||||
- [手動安裝](#手動安裝)
|
- [手動安裝](#手動安裝)
|
||||||
- [資料夾結構](#資料夾結構)
|
- [資料夾結構](#資料夾結構)
|
||||||
|
- [更新 / 卸載系統代理 (System Agent)](#更新--卸載系統代理-system-agent)
|
||||||
- [截圖](#截圖)
|
- [截圖](#截圖)
|
||||||
- [閒置休眠](#閒置休眠)
|
- [閒置休眠](#閒置休眠)
|
||||||
- [監控](#監控)
|
- [監控](#監控)
|
||||||
@@ -57,6 +58,7 @@
|
|||||||
- 國家 **(需要 Maxmind 帳戶)**
|
- 國家 **(需要 Maxmind 帳戶)**
|
||||||
- 時區 **(需要 Maxmind 帳戶)**
|
- 時區 **(需要 Maxmind 帳戶)**
|
||||||
- **存取日誌記錄**
|
- **存取日誌記錄**
|
||||||
|
- 定時發送摘要 (允許和拒絕的連線次數)
|
||||||
- **自動化**
|
- **自動化**
|
||||||
- 使用 Let's Encrypt 自動管理 SSL 憑證 ([使用 DNS-01 驗證](https://docs.godoxy.dev/DNS-01-Providers))
|
- 使用 Let's Encrypt 自動管理 SSL 憑證 ([使用 DNS-01 驗證](https://docs.godoxy.dev/DNS-01-Providers))
|
||||||
- Docker 容器自動配置
|
- Docker 容器自動配置
|
||||||
@@ -144,6 +146,20 @@
|
|||||||
└── .env
|
└── .env
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 更新 / 卸載系統代理 (System Agent)
|
||||||
|
|
||||||
|
更新:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo /bin/bash -c "$(curl -fsSL https://github.com/yusing/godoxy/raw/refs/heads/main/scripts/install-agent.sh)" -- update
|
||||||
|
```
|
||||||
|
|
||||||
|
卸載:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo /bin/bash -c "$(curl -fsSL https://github.com/yusing/godoxy/raw/refs/heads/main/scripts/install-agent.sh)" -- uninstall
|
||||||
|
```
|
||||||
|
|
||||||
## 截圖
|
## 截圖
|
||||||
|
|
||||||
### 閒置休眠
|
### 閒置休眠
|
||||||
|
|||||||
@@ -5,16 +5,15 @@ import (
|
|||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/env"
|
"github.com/yusing/godoxy/agent/pkg/env"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/server"
|
"github.com/yusing/godoxy/agent/pkg/server"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/metrics/systeminfo"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/systeminfo"
|
socketproxy "github.com/yusing/godoxy/socketproxy/pkg"
|
||||||
httpServer "github.com/yusing/go-proxy/internal/net/gphttp/server"
|
httpServer "github.com/yusing/goutils/server"
|
||||||
"github.com/yusing/go-proxy/internal/task"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
"github.com/yusing/goutils/task"
|
||||||
"github.com/yusing/go-proxy/pkg"
|
"github.com/yusing/goutils/version"
|
||||||
socketproxy "github.com/yusing/go-proxy/socketproxy/pkg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -27,24 +26,24 @@ func main() {
|
|||||||
ca := &agent.PEMPair{}
|
ca := &agent.PEMPair{}
|
||||||
err := ca.Load(env.AgentCACert)
|
err := ca.Load(env.AgentCACert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gperr.LogFatal("init CA error", err)
|
log.Fatal().Err(err).Msg("init CA error")
|
||||||
}
|
}
|
||||||
caCert, err := ca.ToTLSCert()
|
caCert, err := ca.ToTLSCert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gperr.LogFatal("init CA error", err)
|
log.Fatal().Err(err).Msg("init CA error")
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := &agent.PEMPair{}
|
srv := &agent.PEMPair{}
|
||||||
srv.Load(env.AgentSSLCert)
|
srv.Load(env.AgentSSLCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gperr.LogFatal("init SSL error", err)
|
log.Fatal().Err(err).Msg("init SSL error")
|
||||||
}
|
}
|
||||||
srvCert, err := srv.ToTLSCert()
|
srvCert, err := srv.ToTLSCert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gperr.LogFatal("init SSL error", err)
|
log.Fatal().Err(err).Msg("init SSL error")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Msgf("GoDoxy Agent version %s", pkg.GetVersion())
|
log.Info().Msgf("GoDoxy Agent version %s", version.Get())
|
||||||
log.Info().Msgf("Agent name: %s", env.AgentName)
|
log.Info().Msgf("Agent name: %s", env.AgentName)
|
||||||
log.Info().Msgf("Agent port: %d", env.AgentPort)
|
log.Info().Msgf("Agent port: %d", env.AgentPort)
|
||||||
log.Info().Msgf("Agent runtime: %s", env.Runtime)
|
log.Info().Msgf("Agent runtime: %s", env.Runtime)
|
||||||
|
|||||||
66
agent/go.mod
66
agent/go.mod
@@ -1,26 +1,27 @@
|
|||||||
module github.com/yusing/go-proxy/agent
|
module github.com/yusing/godoxy/agent
|
||||||
|
|
||||||
go 1.25.1
|
go 1.25.2
|
||||||
|
|
||||||
replace github.com/yusing/go-proxy => ..
|
replace github.com/yusing/godoxy => ..
|
||||||
|
|
||||||
replace github.com/yusing/go-proxy/socketproxy => ../socket-proxy
|
replace github.com/yusing/godoxy/socketproxy => ../socket-proxy
|
||||||
|
|
||||||
replace github.com/yusing/go-proxy/internal/utils => ../internal/utils
|
replace github.com/shirou/gopsutil/v4 => ../internal/gopsutil
|
||||||
|
|
||||||
replace github.com/shirou/gopsutil/v4 => github.com/godoxy-app/gopsutil/v4 v4.0.0-20250816043325-ee003f88b84d
|
replace github.com/yusing/goutils => ../goutils
|
||||||
|
|
||||||
exclude github.com/containerd/nerdctl/mod/tigron v0.0.0
|
exclude github.com/containerd/nerdctl/mod/tigron v0.0.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.10.1
|
github.com/bytedance/sonic v1.14.1
|
||||||
|
github.com/gin-gonic/gin v1.11.0
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/puzpuzpuz/xsync/v4 v4.1.0
|
github.com/puzpuzpuz/xsync/v4 v4.2.0
|
||||||
github.com/rs/zerolog v1.34.0
|
github.com/rs/zerolog v1.34.0
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/yusing/go-proxy v0.17.6
|
github.com/yusing/godoxy v0.18.6
|
||||||
github.com/yusing/go-proxy/internal/utils v0.0.0
|
github.com/yusing/godoxy/socketproxy v0.0.0-00010101000000-000000000000
|
||||||
github.com/yusing/go-proxy/socketproxy v0.0.0-00010101000000-000000000000
|
github.com/yusing/goutils v0.6.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -29,7 +30,6 @@ require (
|
|||||||
github.com/PuerkitoBio/goquery v1.10.3 // indirect
|
github.com/PuerkitoBio/goquery v1.10.3 // indirect
|
||||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||||
github.com/bytedance/sonic v1.14.1 // indirect
|
|
||||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
@@ -37,11 +37,11 @@ require (
|
|||||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/cli v28.4.0+incompatible // indirect
|
github.com/docker/cli v28.5.1+incompatible // indirect
|
||||||
github.com/docker/docker v28.4.0+incompatible // indirect
|
github.com/docker/docker v28.5.1+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.6.0 // indirect
|
github.com/docker/go-connections v0.6.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/ebitengine/purego v0.8.4 // indirect
|
github.com/ebitengine/purego v0.9.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
@@ -50,11 +50,11 @@ require (
|
|||||||
github.com/go-ole/go-ole v1.3.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/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
github.com/go-playground/validator/v10 v10.28.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||||
github.com/gorilla/mux v1.8.1 // indirect
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/gotify/server/v2 v2.7.2 // indirect
|
github.com/gotify/server/v2 v2.7.3 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||||
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect
|
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
@@ -69,27 +69,27 @@ require (
|
|||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
|
github.com/pires/go-proxyproto v0.8.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // 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/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/quic-go/qpack v0.5.1 // indirect
|
github.com/quic-go/qpack v0.5.1 // indirect
|
||||||
github.com/quic-go/quic-go v0.54.0 // indirect
|
github.com/quic-go/quic-go v0.55.0 // indirect
|
||||||
github.com/samber/lo v1.51.0 // indirect
|
github.com/samber/lo v1.52.0 // indirect
|
||||||
github.com/samber/slog-common v0.19.0 // indirect
|
github.com/samber/slog-common v0.19.0 // indirect
|
||||||
github.com/samber/slog-zerolog/v2 v2.7.3 // indirect
|
github.com/samber/slog-zerolog/v2 v2.7.3 // indirect
|
||||||
github.com/shirou/gopsutil/v4 v4.25.8 // indirect
|
github.com/shirou/gopsutil/v4 v4.25.9 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
|
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
|
||||||
github.com/spf13/afero v1.15.0 // indirect
|
|
||||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||||
github.com/vincent-petithory/dataurl v1.0.0 // indirect
|
github.com/vincent-petithory/dataurl v1.0.0 // indirect
|
||||||
github.com/yusing/ds v0.1.0 // indirect
|
github.com/yusing/ds v0.2.0 // indirect
|
||||||
|
github.com/yusing/gointernals v0.1.16 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.2.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
|
||||||
@@ -97,17 +97,15 @@ require (
|
|||||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
go.uber.org/mock v0.6.0 // indirect
|
golang.org/x/arch v0.22.0 // indirect
|
||||||
golang.org/x/arch v0.21.0 // indirect
|
golang.org/x/crypto v0.43.0 // indirect
|
||||||
golang.org/x/crypto v0.42.0 // indirect
|
golang.org/x/mod v0.29.0 // indirect
|
||||||
golang.org/x/mod v0.28.0 // indirect
|
golang.org/x/net v0.46.0 // indirect
|
||||||
golang.org/x/net v0.44.0 // indirect
|
|
||||||
golang.org/x/sync v0.17.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.36.0 // indirect
|
golang.org/x/sys v0.37.0 // indirect
|
||||||
golang.org/x/text v0.29.0 // indirect
|
golang.org/x/text v0.30.0 // indirect
|
||||||
golang.org/x/time v0.13.0 // indirect
|
golang.org/x/tools v0.38.0 // indirect
|
||||||
golang.org/x/tools v0.37.0 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
google.golang.org/protobuf v1.36.9 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
gotest.tools/v3 v3.5.2 // indirect
|
gotest.tools/v3 v3.5.2 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
124
agent/go.sum
124
agent/go.sum
@@ -6,12 +6,16 @@ github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiU
|
|||||||
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
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 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
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/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
||||||
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
||||||
github.com/bytedance/sonic v1.14.1 h1:FBMC0zVz5XUmE4z9wF4Jey0An5FueFvOsTKKKtwIl7w=
|
github.com/bytedance/sonic v1.14.1 h1:FBMC0zVz5XUmE4z9wF4Jey0An5FueFvOsTKKKtwIl7w=
|
||||||
github.com/bytedance/sonic v1.14.1/go.mod h1:gi6uhQLMbTdeP0muCnrjHLeCUPyb70ujhnNlhOylAFc=
|
github.com/bytedance/sonic v1.14.1/go.mod h1:gi6uhQLMbTdeP0muCnrjHLeCUPyb70ujhnNlhOylAFc=
|
||||||
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
||||||
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
github.com/bytedance/sonic/loader v0.3.0/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/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||||
@@ -22,31 +26,43 @@ github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151X
|
|||||||
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.16.0 h1:qRQUCFstKpXwmEjDQTIbyY/5jF00+asXzSkmkoa/mow=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.16.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
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.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.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 h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/diskfs/go-diskfs v1.7.0 h1:vonWmt5CMowXwUc79jWyGrf2DIMeoOjkLlMnQYGVOs8=
|
||||||
|
github.com/diskfs/go-diskfs v1.7.0/go.mod h1:LhQyXqOugWFRahYUSw47NyZJPezFzB9UELwhpszLP/k=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
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/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/cli v28.4.0+incompatible h1:RBcf3Kjw2pMtwui5V0DIMdyeab8glEw5QY0UUU4C9kY=
|
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||||
github.com/docker/cli v28.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||||
github.com/docker/docker v28.4.0+incompatible h1:KVC7bz5zJY/4AZe/78BIvCnPsLaC9T/zh72xnlrTTOk=
|
github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
|
||||||
github.com/docker/docker v28.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
|
||||||
|
github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||||
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
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/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k=
|
||||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
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.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||||
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
|
||||||
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
|
||||||
|
github.com/go-acme/lego/v4 v4.26.0 h1:521aEQxNstXvPQcFDDPrJiFfixcCQuvAvm35R4GbyYA=
|
||||||
|
github.com/go-acme/lego/v4 v4.26.0/go.mod h1:BQVAWgcyzW4IT9eIKHY/RxYlVhoyKyOMXOkq7jK1eEQ=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
@@ -61,15 +77,17 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
|||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
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 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
||||||
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
||||||
|
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-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/godoxy-app/gopsutil/v4 v4.0.0-20250816043325-ee003f88b84d h1:bNqtnmyhGDxpBSaFYIo7ferYRIc/QzlaGfIhh/JmMPk=
|
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||||
github.com/godoxy-app/gopsutil/v4 v4.0.0-20250816043325-ee003f88b84d/go.mod h1:7iQ/w4jyGYJCZ56dZLNztwM4atNxj5C2HNTBxhLvV8A=
|
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
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 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
@@ -80,10 +98,12 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
|||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
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/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gotify/server/v2 v2.7.2 h1:YRgYl/kB7Uh4OINd7gK60N3QBTY4YEeKTrBLhd67LC4=
|
github.com/gotify/server/v2 v2.7.3 h1:nro/ZnxdlZFvxFcw9LREGA8zdk6CK744azwhuhX/A4g=
|
||||||
github.com/gotify/server/v2 v2.7.2/go.mod h1:KJH+8yhkAxArygPwaRfp9otHjt6tE0YSzdrsgPX/5EE=
|
github.com/gotify/server/v2 v2.7.3/go.mod h1:VAtE1RIc/2j886PYs9WPQbMjqbFsoyQ0G8IdFtnAxU0=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
||||||
|
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||||
|
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||||
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU=
|
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU=
|
||||||
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0=
|
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
@@ -98,6 +118,10 @@ github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8
|
|||||||
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
||||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
|
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
|
||||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||||
|
github.com/luthermonson/go-proxmox v0.2.3 h1:NAjUJ5Jd1ynIK6UHMGd/VLGgNZWpGXhfL+DBmAVSEaA=
|
||||||
|
github.com/luthermonson/go-proxmox v0.2.3/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.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 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
@@ -105,6 +129,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
|||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
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 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
|
||||||
|
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
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/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 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||||
@@ -128,6 +154,8 @@ github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5
|
|||||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
|
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||||
|
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
@@ -135,19 +163,19 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
|||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/puzpuzpuz/xsync/v4 v4.1.0 h1:x9eHRl4QhZFIPJ17yl4KKW9xLyVWbb3/Yq4SXpjF71U=
|
github.com/puzpuzpuz/xsync/v4 v4.2.0 h1:dlxm77dZj2c3rxq0/XNvvUKISAmovoXF4a4qM6Wvkr0=
|
||||||
github.com/puzpuzpuz/xsync/v4 v4.1.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
|
github.com/puzpuzpuz/xsync/v4 v4.2.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
|
||||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
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/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||||
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
|
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
||||||
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
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 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||||
github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
|
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
|
||||||
github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
|
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
|
||||||
github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI=
|
github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI=
|
||||||
github.com/samber/slog-common v0.19.0/go.mod h1:dTz+YOU76aH007YUU0DffsXNsGFQRQllPQh9XyNoA3M=
|
github.com/samber/slog-common v0.19.0/go.mod h1:dTz+YOU76aH007YUU0DffsXNsGFQRQllPQh9XyNoA3M=
|
||||||
github.com/samber/slog-zerolog/v2 v2.7.3 h1:/MkPDl/tJhijN2GvB1MWwBn2FU8RiL3rQ8gpXkQm2EY=
|
github.com/samber/slog-zerolog/v2 v2.7.3 h1:/MkPDl/tJhijN2GvB1MWwBn2FU8RiL3rQ8gpXkQm2EY=
|
||||||
@@ -176,12 +204,14 @@ github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2W
|
|||||||
github.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8AbShPRpg2CI=
|
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/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yusing/ds v0.1.0 h1:aiZs7jPMN3MEChUsddMYjpZFHhhAmkxrwRyIUnGy5AU=
|
github.com/yusing/ds v0.2.0 h1:lPhDU5eA2uvquVrBrzLCrQXRJJgSXlUYA53TbuK2sQY=
|
||||||
github.com/yusing/ds v0.1.0/go.mod h1:KC785+mtt+Bau0LLR+slExDaUjeiqLT1k9Or6Rpryh4=
|
github.com/yusing/ds v0.2.0/go.mod h1:XhKV4l7cZwBbbl7lRzNC9zX27zvCM0frIwiuD40ULRk=
|
||||||
|
github.com/yusing/gointernals v0.1.16 h1:GrhZZdxzA+jojLEqankctJrOuAYDb7kY1C93S1pVR34=
|
||||||
|
github.com/yusing/gointernals v0.1.16/go.mod h1:B/0FVXt4WPmgzVy3ynzkqKi+BSGaJVmwCJBRXYapo34=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.0 h1:YpRtUFjvhSymycLS2T81lT6IGhcUP+LUPtv0iv1N8bM=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.0/go.mod h1:1deq2zL7rwjwC8mR7XgY2N+tlIl6pjmEUoLDENMEzwk=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
|
||||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||||
@@ -204,23 +234,23 @@ 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/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||||
golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw=
|
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
|
||||||
golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
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.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.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.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.12.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.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.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
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.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
@@ -230,8 +260,10 @@ 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.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
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.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||||
|
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||||
|
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -259,8 +291,8 @@ 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.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.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.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
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-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@@ -279,28 +311,28 @@ 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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.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.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||||
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
|
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||||
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
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.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/genproto v0.0.0-20250908214217-97024824d090 h1:ywCL7vA2n3vVHyf+bx1ZV/knaTPRI8GIeKY0MEhEeOc=
|
google.golang.org/genproto v0.0.0-20250908214217-97024824d090 h1:ywCL7vA2n3vVHyf+bx1ZV/knaTPRI8GIeKY0MEhEeOc=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 h1:APHvLLYBhtZvsbnpkfknDZ7NyH4z5+ub/I0u8L3Oz6g=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 h1:APHvLLYBhtZvsbnpkfknDZ7NyH4z5+ub/I0u8L3Oz6g=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1/go.mod h1:xUjFWUnWDpZ/C0Gu0qloASKFb6f8/QXiiXhSPFsD668=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1/go.mod h1:xUjFWUnWDpZ/C0Gu0qloASKFb6f8/QXiiXhSPFsD668=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251007200510-49b9836ed3ff h1:A90eA31Wq6HOMIQlLfzFwzqGKBTuaVztYu/g8sn+8Zc=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251007200510-49b9836ed3ff/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
||||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
||||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
|||||||
@@ -2,15 +2,16 @@ package agent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"iter"
|
"iter"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/puzpuzpuz/xsync/v4"
|
"github.com/puzpuzpuz/xsync/v4"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var agentPool = xsync.NewMap[string, *AgentConfig](xsync.WithPresize(10))
|
var agentPool = xsync.NewMap[string, *AgentConfig](xsync.WithPresize(10))
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if common.IsTest {
|
if strings.HasSuffix(os.Args[0], ".test") {
|
||||||
agentPool.Store("test-agent", &AgentConfig{
|
agentPool.Store("test-agent", &AgentConfig{
|
||||||
Addr: "test-agent",
|
Addr: "test-agent",
|
||||||
})
|
})
|
||||||
@@ -63,5 +64,5 @@ func NumAgents() int {
|
|||||||
|
|
||||||
func getAgentByAddr(addr string) (agent *AgentConfig, ok bool) {
|
func getAgentByAddr(addr string) (agent *AgentConfig, ok bool) {
|
||||||
agent, ok = agentPool.Load(addr)
|
agent, ok = agentPool.Load(addr)
|
||||||
return
|
return agent, ok
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,20 @@ import (
|
|||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/certs"
|
"github.com/yusing/godoxy/agent/pkg/certs"
|
||||||
"github.com/yusing/go-proxy/pkg"
|
"github.com/yusing/goutils/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AgentConfig struct {
|
type AgentConfig struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version"`
|
Version version.Version `json:"version"`
|
||||||
Runtime ContainerRuntime `json:"runtime"`
|
Runtime ContainerRuntime `json:"runtime"`
|
||||||
|
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
tlsConfig *tls.Config
|
httpClientHealthCheck *http.Client
|
||||||
l zerolog.Logger
|
tlsConfig *tls.Config
|
||||||
|
l zerolog.Logger
|
||||||
} // @name Agent
|
} // @name Agent
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -81,7 +82,7 @@ func (cfg *AgentConfig) Parse(addr string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var serverVersion = pkg.GetVersion()
|
var serverVersion = version.Get()
|
||||||
|
|
||||||
func (cfg *AgentConfig) StartWithCerts(ctx context.Context, ca, crt, key []byte) error {
|
func (cfg *AgentConfig) StartWithCerts(ctx context.Context, ca, crt, key []byte) error {
|
||||||
clientCert, err := tls.X509KeyPair(crt, key)
|
clientCert, err := tls.X509KeyPair(crt, key)
|
||||||
@@ -104,6 +105,8 @@ func (cfg *AgentConfig) StartWithCerts(ctx context.Context, ca, crt, key []byte)
|
|||||||
|
|
||||||
// create transport and http client
|
// create transport and http client
|
||||||
cfg.httpClient = cfg.NewHTTPClient()
|
cfg.httpClient = cfg.NewHTTPClient()
|
||||||
|
cfg.httpClientHealthCheck = cfg.NewHTTPClient()
|
||||||
|
applyHealthCheckTransportConfig(cfg.httpClientHealthCheck.Transport.(*http.Transport))
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -148,11 +151,10 @@ func (cfg *AgentConfig) StartWithCerts(ctx context.Context, ca, crt, key []byte)
|
|||||||
return fmt.Errorf("failed to get agent runtime: HTTP %d %s", status, runtimeBytes)
|
return fmt.Errorf("failed to get agent runtime: HTTP %d %s", status, runtimeBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.Version = string(agentVersionBytes)
|
cfg.Version = version.Parse(string(agentVersionBytes))
|
||||||
agentVersion := pkg.ParseVersion(cfg.Version)
|
|
||||||
|
|
||||||
if serverVersion.IsNewerMajorThan(agentVersion) {
|
if serverVersion.IsNewerThanMajor(cfg.Version) {
|
||||||
log.Warn().Msgf("agent %s major version mismatch: server: %s, agent: %s", cfg.Name, serverVersion, agentVersion)
|
log.Warn().Msgf("agent %s major version mismatch: server: %s, agent: %s", cfg.Name, serverVersion, cfg.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Msgf("agent %q initialized", cfg.Name)
|
log.Info().Msgf("agent %q initialized", cfg.Name)
|
||||||
@@ -208,3 +210,12 @@ func (cfg *AgentConfig) DialContext(ctx context.Context) (net.Conn, error) {
|
|||||||
func (cfg *AgentConfig) String() string {
|
func (cfg *AgentConfig) String() string {
|
||||||
return cfg.Name + "@" + cfg.Addr
|
return cfg.Name + "@" + cfg.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyHealthCheckTransportConfig(transport *http.Transport) {
|
||||||
|
transport.DisableKeepAlives = true
|
||||||
|
transport.DisableCompression = true
|
||||||
|
transport.MaxIdleConns = 1
|
||||||
|
transport.MaxIdleConnsPerHost = 1
|
||||||
|
transport.ReadBufferSize = 1024
|
||||||
|
transport.WriteBufferSize = 1024
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy"
|
"github.com/yusing/goutils/http/reverseproxy"
|
||||||
nettypes "github.com/yusing/go-proxy/internal/net/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cfg *AgentConfig) Do(ctx context.Context, method, endpoint string, body io.Reader) (*http.Response, error) {
|
func (cfg *AgentConfig) Do(ctx context.Context, method, endpoint string, body io.Reader) (*http.Response, error) {
|
||||||
@@ -19,7 +18,6 @@ func (cfg *AgentConfig) Do(ctx context.Context, method, endpoint string, body io
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *AgentConfig) Forward(req *http.Request, endpoint string) (*http.Response, error) {
|
func (cfg *AgentConfig) Forward(req *http.Request, endpoint string) (*http.Response, error) {
|
||||||
req = req.WithContext(req.Context())
|
|
||||||
req.URL.Host = AgentHost
|
req.URL.Host = AgentHost
|
||||||
req.URL.Scheme = "https"
|
req.URL.Scheme = "https"
|
||||||
req.URL.Path = APIEndpointBase + endpoint
|
req.URL.Path = APIEndpointBase + endpoint
|
||||||
@@ -31,6 +29,24 @@ func (cfg *AgentConfig) Forward(req *http.Request, endpoint string) (*http.Respo
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg *AgentConfig) DoHealthCheck(ctx context.Context, endpoint string) ([]byte, int, error) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", APIBaseURL+endpoint, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Accept-Encoding", "identity")
|
||||||
|
req.Header.Set("Connection", "close")
|
||||||
|
|
||||||
|
resp, err := cfg.httpClientHealthCheck.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
data, _ := io.ReadAll(resp.Body)
|
||||||
|
return data, resp.StatusCode, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (cfg *AgentConfig) Fetch(ctx context.Context, endpoint string) ([]byte, int, error) {
|
func (cfg *AgentConfig) Fetch(ctx context.Context, endpoint string) ([]byte, int, error) {
|
||||||
resp, err := cfg.Do(ctx, "GET", endpoint, nil)
|
resp, err := cfg.Do(ctx, "GET", endpoint, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -56,17 +72,11 @@ func (cfg *AgentConfig) Websocket(ctx context.Context, endpoint string) (*websoc
|
|||||||
//
|
//
|
||||||
// It will create a new request with the same context, method, and body, but with the agent host and scheme, and the endpoint
|
// It will create a new request with the same context, method, and body, but with the agent host and scheme, and the endpoint
|
||||||
// If the request has a query, it will be added to the proxy request's URL
|
// If the request has a query, it will be added to the proxy request's URL
|
||||||
func (cfg *AgentConfig) ReverseProxy(w http.ResponseWriter, req *http.Request, endpoint string) error {
|
func (cfg *AgentConfig) ReverseProxy(w http.ResponseWriter, req *http.Request, endpoint string) {
|
||||||
rp := reverseproxy.NewReverseProxy("agent", nettypes.NewURL(AgentURL), cfg.Transport())
|
rp := reverseproxy.NewReverseProxy("agent", AgentURL, cfg.Transport())
|
||||||
uri := APIEndpointBase + endpoint
|
req.URL.Host = AgentHost
|
||||||
if req.URL.RawQuery != "" {
|
req.URL.Scheme = "https"
|
||||||
uri += "?" + req.URL.RawQuery
|
req.URL.Path = endpoint
|
||||||
}
|
req.RequestURI = ""
|
||||||
r, err := http.NewRequestWithContext(req.Context(), req.Method, uri, req.Body)
|
rp.ServeHTTP(w, req)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r.Header = req.Header
|
|
||||||
rp.ServeHTTP(w, r)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package agent
|
|||||||
import (
|
import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
@@ -10,14 +12,11 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -244,5 +243,5 @@ func NewAgent() (ca, srv, client *PEMPair, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client = toPEMPair(clientCertDER, clientKey)
|
client = toPEMPair(clientCertDER, clientKey)
|
||||||
return
|
return ca, srv, client, err
|
||||||
}
|
}
|
||||||
|
|||||||
73
agent/pkg/agentproxy/config.go
Normal file
73
agent/pkg/agentproxy/config.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package agentproxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
route "github.com/yusing/godoxy/internal/route/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Scheme string `json:"scheme,omitempty"`
|
||||||
|
Host string `json:"host,omitempty"` // host or host:port
|
||||||
|
|
||||||
|
route.HTTPConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConfigFromHeaders(h http.Header) (Config, error) {
|
||||||
|
cfg, err := proxyConfigFromHeaders(h)
|
||||||
|
if cfg.Host == "" || err != nil {
|
||||||
|
cfg = proxyConfigFromHeadersLegacy(h)
|
||||||
|
}
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func proxyConfigFromHeadersLegacy(h http.Header) (cfg Config) {
|
||||||
|
cfg.Host = h.Get(HeaderXProxyHost)
|
||||||
|
isHTTPS, _ := strconv.ParseBool(h.Get(HeaderXProxyHTTPS))
|
||||||
|
cfg.NoTLSVerify, _ = strconv.ParseBool(h.Get(HeaderXProxySkipTLSVerify))
|
||||||
|
responseHeaderTimeout, err := strconv.Atoi(h.Get(HeaderXProxyResponseHeaderTimeout))
|
||||||
|
if err != nil {
|
||||||
|
responseHeaderTimeout = 0
|
||||||
|
}
|
||||||
|
cfg.ResponseHeaderTimeout = time.Duration(responseHeaderTimeout) * time.Second
|
||||||
|
|
||||||
|
cfg.Scheme = "http"
|
||||||
|
if isHTTPS {
|
||||||
|
cfg.Scheme = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func proxyConfigFromHeaders(h http.Header) (cfg Config, err error) {
|
||||||
|
cfg.Scheme = h.Get(HeaderXProxyScheme)
|
||||||
|
cfg.Host = h.Get(HeaderXProxyHost)
|
||||||
|
|
||||||
|
cfgBase64 := h.Get(HeaderXProxyConfig)
|
||||||
|
cfgJSON, err := base64.StdEncoding.DecodeString(cfgBase64)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sonic.Unmarshal(cfgJSON, &cfg)
|
||||||
|
return cfg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) SetAgentProxyConfigHeadersLegacy(h http.Header) {
|
||||||
|
h.Set(HeaderXProxyHost, cfg.Host)
|
||||||
|
h.Set(HeaderXProxyHTTPS, strconv.FormatBool(cfg.Scheme == "https"))
|
||||||
|
h.Set(HeaderXProxySkipTLSVerify, strconv.FormatBool(cfg.NoTLSVerify))
|
||||||
|
h.Set(HeaderXProxyResponseHeaderTimeout, strconv.Itoa(int(cfg.ResponseHeaderTimeout.Round(time.Second).Seconds())))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) SetAgentProxyConfigHeaders(h http.Header) {
|
||||||
|
h.Set(HeaderXProxyHost, cfg.Host)
|
||||||
|
h.Set(HeaderXProxyScheme, string(cfg.Scheme))
|
||||||
|
cfgJSON, _ := sonic.Marshal(cfg.HTTPConfig)
|
||||||
|
cfgBase64 := base64.StdEncoding.EncodeToString(cfgJSON)
|
||||||
|
h.Set(HeaderXProxyConfig, cfgBase64)
|
||||||
|
}
|
||||||
@@ -1,27 +1,14 @@
|
|||||||
package agentproxy
|
package agentproxy
|
||||||
|
|
||||||
import (
|
const (
|
||||||
"net/http"
|
HeaderXProxyScheme = "X-Proxy-Scheme"
|
||||||
"strconv"
|
HeaderXProxyHost = "X-Proxy-Host"
|
||||||
|
HeaderXProxyConfig = "X-Proxy-Config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// deprecated
|
||||||
const (
|
const (
|
||||||
HeaderXProxyHost = "X-Proxy-Host"
|
|
||||||
HeaderXProxyHTTPS = "X-Proxy-Https"
|
HeaderXProxyHTTPS = "X-Proxy-Https"
|
||||||
HeaderXProxySkipTLSVerify = "X-Proxy-Skip-Tls-Verify"
|
HeaderXProxySkipTLSVerify = "X-Proxy-Skip-Tls-Verify"
|
||||||
HeaderXProxyResponseHeaderTimeout = "X-Proxy-Response-Header-Timeout"
|
HeaderXProxyResponseHeaderTimeout = "X-Proxy-Response-Header-Timeout"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AgentProxyHeaders struct {
|
|
||||||
Host string
|
|
||||||
IsHTTPS bool
|
|
||||||
SkipTLSVerify bool
|
|
||||||
ResponseHeaderTimeout int
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetAgentProxyHeaders(r *http.Request, headers *AgentProxyHeaders) {
|
|
||||||
r.Header.Set(HeaderXProxyHost, headers.Host)
|
|
||||||
r.Header.Set(HeaderXProxyHTTPS, strconv.FormatBool(headers.IsHTTPS))
|
|
||||||
r.Header.Set(HeaderXProxySkipTLSVerify, strconv.FormatBool(headers.SkipTLSVerify))
|
|
||||||
r.Header.Set(HeaderXProxyResponseHeaderTimeout, strconv.Itoa(headers.ResponseHeaderTimeout))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const AgentCertsBasePath = "certs"
|
const AgentCertsBasePath = "certs"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/certs"
|
"github.com/yusing/godoxy/agent/pkg/certs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestZipCert(t *testing.T) {
|
func TestZipCert(t *testing.T) {
|
||||||
|
|||||||
18
agent/pkg/env/env.go
vendored
18
agent/pkg/env/env.go
vendored
@@ -3,8 +3,8 @@ package env
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/goutils/env"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
@@ -32,14 +32,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Load() {
|
func Load() {
|
||||||
DockerSocket = common.GetEnvString("DOCKER_SOCKET", "/var/run/docker.sock")
|
DockerSocket = env.GetEnvString("DOCKER_SOCKET", "/var/run/docker.sock")
|
||||||
AgentName = common.GetEnvString("AGENT_NAME", DefaultAgentName())
|
AgentName = env.GetEnvString("AGENT_NAME", DefaultAgentName())
|
||||||
AgentPort = common.GetEnvInt("AGENT_PORT", 8890)
|
AgentPort = env.GetEnvInt("AGENT_PORT", 8890)
|
||||||
AgentSkipClientCertCheck = common.GetEnvBool("AGENT_SKIP_CLIENT_CERT_CHECK", false)
|
AgentSkipClientCertCheck = env.GetEnvBool("AGENT_SKIP_CLIENT_CERT_CHECK", false)
|
||||||
|
|
||||||
AgentCACert = common.GetEnvString("AGENT_CA_CERT", "")
|
AgentCACert = env.GetEnvString("AGENT_CA_CERT", "")
|
||||||
AgentSSLCert = common.GetEnvString("AGENT_SSL_CERT", "")
|
AgentSSLCert = env.GetEnvString("AGENT_SSL_CERT", "")
|
||||||
Runtime = agent.ContainerRuntime(common.GetEnvString("RUNTIME", "docker"))
|
Runtime = agent.ContainerRuntime(env.GetEnvString("RUNTIME", "docker"))
|
||||||
|
|
||||||
switch Runtime {
|
switch Runtime {
|
||||||
case agent.ContainerRuntimeDocker, agent.ContainerRuntimePodman: //, agent.ContainerRuntimeNerdctl:
|
case agent.ContainerRuntimeDocker, agent.ContainerRuntimePodman: //, agent.ContainerRuntimeNerdctl:
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/internal/types"
|
"github.com/bytedance/sonic"
|
||||||
"github.com/yusing/go-proxy/internal/watcher/health/monitor"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
|
"github.com/yusing/godoxy/internal/watcher/health/monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultHealthConfig = types.DefaultHealthConfig()
|
var defaultHealthConfig = types.DefaultHealthConfig()
|
||||||
@@ -22,8 +22,10 @@ func CheckHealth(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var result *types.HealthCheckResult
|
var (
|
||||||
var err error
|
result types.HealthCheckResult
|
||||||
|
err error
|
||||||
|
)
|
||||||
switch scheme {
|
switch scheme {
|
||||||
case "fileserver":
|
case "fileserver":
|
||||||
path := query.Get("path")
|
path := query.Get("path")
|
||||||
@@ -32,7 +34,7 @@ func CheckHealth(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
result = &types.HealthCheckResult{Healthy: err == nil}
|
result = types.HealthCheckResult{Healthy: err == nil}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.Detail = err.Error()
|
result.Detail = err.Error()
|
||||||
}
|
}
|
||||||
@@ -76,5 +78,5 @@ func CheckHealth(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(result)
|
sonic.ConfigDefault.NewEncoder(w).Encode(result)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/handler"
|
"github.com/yusing/godoxy/agent/pkg/handler"
|
||||||
"github.com/yusing/go-proxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCheckHealthHTTP(t *testing.T) {
|
func TestCheckHealthHTTP(t *testing.T) {
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/env"
|
"github.com/yusing/godoxy/agent/pkg/env"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/systeminfo"
|
"github.com/yusing/godoxy/internal/metrics/systeminfo"
|
||||||
"github.com/yusing/go-proxy/pkg"
|
socketproxy "github.com/yusing/godoxy/socketproxy/pkg"
|
||||||
socketproxy "github.com/yusing/go-proxy/socketproxy/pkg"
|
"github.com/yusing/goutils/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServeMux struct{ *http.ServeMux }
|
type ServeMux struct{ *http.ServeMux }
|
||||||
@@ -45,7 +45,7 @@ func NewAgentHandler() http.Handler {
|
|||||||
|
|
||||||
mux.HandleFunc(agent.EndpointProxyHTTP+"/{path...}", ProxyHTTP)
|
mux.HandleFunc(agent.EndpointProxyHTTP+"/{path...}", ProxyHTTP)
|
||||||
mux.HandleEndpoint("GET", agent.EndpointVersion, func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleEndpoint("GET", agent.EndpointVersion, func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprint(w, pkg.GetVersion())
|
fmt.Fprint(w, version.Get())
|
||||||
})
|
})
|
||||||
mux.HandleEndpoint("GET", agent.EndpointName, func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleEndpoint("GET", agent.EndpointName, func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprint(w, env.AgentName)
|
fmt.Fprint(w, env.AgentName)
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agentproxy"
|
"github.com/yusing/godoxy/agent/pkg/agentproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTransport() *http.Transport {
|
func NewTransport() *http.Transport {
|
||||||
@@ -24,31 +23,24 @@ func NewTransport() *http.Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ProxyHTTP(w http.ResponseWriter, r *http.Request) {
|
func ProxyHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
host := r.Header.Get(agentproxy.HeaderXProxyHost)
|
cfg, err := agentproxy.ConfigFromHeaders(r.Header)
|
||||||
isHTTPS, _ := strconv.ParseBool(r.Header.Get(agentproxy.HeaderXProxyHTTPS))
|
|
||||||
skipTLSVerify, _ := strconv.ParseBool(r.Header.Get(agentproxy.HeaderXProxySkipTLSVerify))
|
|
||||||
responseHeaderTimeout, err := strconv.Atoi(r.Header.Get(agentproxy.HeaderXProxyResponseHeaderTimeout))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
responseHeaderTimeout = 0
|
http.Error(w, fmt.Sprintf("failed to parse agent proxy config: %s", err.Error()), http.StatusBadRequest)
|
||||||
}
|
|
||||||
|
|
||||||
if host == "" {
|
|
||||||
http.Error(w, "missing required headers", http.StatusBadRequest)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scheme := "http"
|
|
||||||
if isHTTPS {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
|
|
||||||
transport := NewTransport()
|
transport := NewTransport()
|
||||||
if skipTLSVerify {
|
if cfg.ResponseHeaderTimeout > 0 {
|
||||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
transport.ResponseHeaderTimeout = cfg.ResponseHeaderTimeout
|
||||||
|
}
|
||||||
|
if cfg.DisableCompression {
|
||||||
|
transport.DisableCompression = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if responseHeaderTimeout > 0 {
|
transport.TLSClientConfig, err = cfg.BuildTLSConfig(r.URL)
|
||||||
transport.ResponseHeaderTimeout = time.Duration(responseHeaderTimeout) * time.Second
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("failed to build TLS client config: %s", err.Error()), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r.URL.Scheme = ""
|
r.URL.Scheme = ""
|
||||||
@@ -58,8 +50,8 @@ func ProxyHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
rp := &httputil.ReverseProxy{
|
rp := &httputil.ReverseProxy{
|
||||||
Director: func(r *http.Request) {
|
Director: func(r *http.Request) {
|
||||||
r.URL.Scheme = scheme
|
r.URL.Scheme = cfg.Scheme
|
||||||
r.URL.Host = host
|
r.URL.Host = cfg.Host
|
||||||
},
|
},
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/env"
|
"github.com/yusing/godoxy/agent/pkg/env"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/handler"
|
"github.com/yusing/godoxy/agent/pkg/handler"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/server"
|
"github.com/yusing/goutils/server"
|
||||||
"github.com/yusing/go-proxy/internal/task"
|
"github.com/yusing/goutils/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
@@ -39,5 +39,5 @@ func StartAgentServer(parent task.Parent, opt Options) {
|
|||||||
TLSConfig: tlsConfig,
|
TLSConfig: tlsConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
server.Start(parent, agentServer, nil, &log.Logger)
|
server.Start(parent, agentServer, server.WithLogger(&log.Logger))
|
||||||
}
|
}
|
||||||
|
|||||||
44
cmd/main.go
44
cmd/main.go
@@ -5,19 +5,21 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/internal/auth"
|
"github.com/yusing/godoxy/internal/api"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/auth"
|
||||||
"github.com/yusing/go-proxy/internal/config"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/dnsproviders"
|
"github.com/yusing/godoxy/internal/config"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/dnsproviders"
|
||||||
"github.com/yusing/go-proxy/internal/homepage"
|
"github.com/yusing/godoxy/internal/homepage"
|
||||||
"github.com/yusing/go-proxy/internal/logging"
|
"github.com/yusing/godoxy/internal/logging"
|
||||||
"github.com/yusing/go-proxy/internal/logging/memlogger"
|
"github.com/yusing/godoxy/internal/logging/memlogger"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/systeminfo"
|
"github.com/yusing/godoxy/internal/metrics/systeminfo"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/uptime"
|
"github.com/yusing/godoxy/internal/metrics/uptime"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/middleware"
|
"github.com/yusing/godoxy/internal/net/gphttp/middleware"
|
||||||
"github.com/yusing/go-proxy/internal/task"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/go-proxy/pkg"
|
"github.com/yusing/goutils/server"
|
||||||
|
"github.com/yusing/goutils/task"
|
||||||
|
"github.com/yusing/goutils/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parallel(fns ...func()) {
|
func parallel(fns ...func()) {
|
||||||
@@ -32,7 +34,7 @@ func main() {
|
|||||||
initProfiling()
|
initProfiling()
|
||||||
|
|
||||||
logging.InitLogger(os.Stderr, memlogger.GetMemLogger())
|
logging.InitLogger(os.Stderr, memlogger.GetMemLogger())
|
||||||
log.Info().Msgf("GoDoxy version %s", pkg.GetVersion())
|
log.Info().Msgf("GoDoxy version %s", version.Get())
|
||||||
log.Trace().Msg("trace enabled")
|
log.Trace().Msg("trace enabled")
|
||||||
parallel(
|
parallel(
|
||||||
dnsproviders.InitProviders,
|
dnsproviders.InitProviders,
|
||||||
@@ -50,26 +52,26 @@ func main() {
|
|||||||
prepareDirectory(dir)
|
prepareDirectory(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.Load()
|
err := config.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gperr.LogWarn("errors in config", err)
|
gperr.LogWarn("errors in config", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.Start(&config.StartServersOptions{
|
config.StartProxyServers()
|
||||||
Proxy: true,
|
|
||||||
})
|
|
||||||
if err := auth.Initialize(); err != nil {
|
if err := auth.Initialize(); err != nil {
|
||||||
log.Fatal().Err(err).Msg("failed to initialize authentication")
|
log.Fatal().Err(err).Msg("failed to initialize authentication")
|
||||||
}
|
}
|
||||||
// API Handler needs to start after auth is initialized.
|
// API Handler needs to start after auth is initialized.
|
||||||
cfg.StartServers(&config.StartServersOptions{
|
server.StartServer(task.RootTask("api_server", false), server.Options{
|
||||||
API: true,
|
Name: "api",
|
||||||
|
HTTPAddr: common.APIHTTPAddr,
|
||||||
|
Handler: api.NewHandler(),
|
||||||
})
|
})
|
||||||
|
|
||||||
uptime.Poller.Start()
|
uptime.Poller.Start()
|
||||||
config.WatchChanges()
|
config.WatchChanges()
|
||||||
|
|
||||||
task.WaitExit(cfg.Value().TimeoutShutdown)
|
task.WaitExit(config.Value().TimeoutShutdown)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareDirectory(dir string) {
|
func prepareDirectory(dir string) {
|
||||||
|
|||||||
@@ -10,16 +10,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const mb = 1024 * 1024
|
|
||||||
|
|
||||||
func initProfiling() {
|
func initProfiling() {
|
||||||
debug.SetGCPercent(-1)
|
|
||||||
debug.SetMemoryLimit(50 * mb)
|
|
||||||
debug.SetMaxStack(4 * mb)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Info().Msgf("pprof server started at http://localhost:7777/debug/pprof/")
|
log.Info().Msgf("pprof server started at http://localhost:7777/debug/pprof/")
|
||||||
log.Error().Err(http.ListenAndServe(":7777", nil)).Msg("pprof server failed")
|
log.Error().Err(http.ListenAndServe(":7777", nil)).Msg("pprof server failed")
|
||||||
@@ -27,9 +21,14 @@ func initProfiling() {
|
|||||||
go func() {
|
go func() {
|
||||||
ticker := time.NewTicker(time.Second * 10)
|
ticker := time.NewTicker(time.Second * 10)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
var m runtime.MemStats
|
||||||
|
var gcStats debug.GCStats
|
||||||
|
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
var m runtime.MemStats
|
|
||||||
runtime.ReadMemStats(&m)
|
runtime.ReadMemStats(&m)
|
||||||
|
debug.ReadGCStats(&gcStats)
|
||||||
|
|
||||||
log.Info().Msgf("-----------------------------------------------------")
|
log.Info().Msgf("-----------------------------------------------------")
|
||||||
log.Info().Msgf("Timestamp: %s", time.Now().Format(time.RFC3339))
|
log.Info().Msgf("Timestamp: %s", time.Now().Format(time.RFC3339))
|
||||||
log.Info().Msgf(" Go Heap - In Use (Alloc/HeapAlloc): %s", strutils.FormatByteSize(m.Alloc))
|
log.Info().Msgf(" Go Heap - In Use (Alloc/HeapAlloc): %s", strutils.FormatByteSize(m.Alloc))
|
||||||
@@ -37,8 +36,12 @@ func initProfiling() {
|
|||||||
log.Info().Msgf(" Go Stacks - In Use (StackInuse): %s", strutils.FormatByteSize(m.StackInuse))
|
log.Info().Msgf(" Go Stacks - In Use (StackInuse): %s", strutils.FormatByteSize(m.StackInuse))
|
||||||
log.Info().Msgf(" Go Runtime - Other Sys (MSpanInuse, MCacheInuse, BuckHashSys, GCSys, OtherSys): %s", strutils.FormatByteSize(m.MSpanInuse+m.MCacheInuse+m.BuckHashSys+m.GCSys+m.OtherSys))
|
log.Info().Msgf(" Go Runtime - Other Sys (MSpanInuse, MCacheInuse, BuckHashSys, GCSys, OtherSys): %s", strutils.FormatByteSize(m.MSpanInuse+m.MCacheInuse+m.BuckHashSys+m.GCSys+m.OtherSys))
|
||||||
log.Info().Msgf(" Go Runtime - Total from OS (Sys): %s", strutils.FormatByteSize(m.Sys))
|
log.Info().Msgf(" Go Runtime - Total from OS (Sys): %s", strutils.FormatByteSize(m.Sys))
|
||||||
|
log.Info().Msgf(" Go Runtime - Freed from OS (HeapReleased): %s", strutils.FormatByteSize(m.HeapReleased))
|
||||||
log.Info().Msgf(" Number of Goroutines: %d", runtime.NumGoroutine())
|
log.Info().Msgf(" Number of Goroutines: %d", runtime.NumGoroutine())
|
||||||
log.Info().Msgf(" Number of GCs: %d", m.NumGC)
|
log.Info().Msgf(" Number of completed GC cycles: %d", m.NumGC)
|
||||||
|
log.Info().Msgf(" Number of GCs: %d", gcStats.NumGC)
|
||||||
|
log.Info().Msgf(" Total GC time: %s", gcStats.PauseTotal)
|
||||||
|
log.Info().Msgf(" Last GC time: %s", gcStats.LastGC.Format(time.DateTime))
|
||||||
log.Info().Msg("-----------------------------------------------------")
|
log.Info().Msg("-----------------------------------------------------")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ services:
|
|||||||
env_file: .env
|
env_file: .env
|
||||||
user: ${GODOXY_UID:-1000}:${GODOXY_GID:-1000}
|
user: ${GODOXY_UID:-1000}:${GODOXY_GID:-1000}
|
||||||
read_only: true
|
read_only: true
|
||||||
|
tmpfs:
|
||||||
|
- /app/.next/cache # next image caching
|
||||||
security_opt:
|
security_opt:
|
||||||
- no-new-privileges:true
|
- no-new-privileges:true
|
||||||
cap_drop:
|
cap_drop:
|
||||||
|
|||||||
@@ -17,6 +17,10 @@
|
|||||||
|
|
||||||
# 3. other providers, see https://docs.godoxy.dev/DNS-01-Providers
|
# 3. other providers, see https://docs.godoxy.dev/DNS-01-Providers
|
||||||
|
|
||||||
|
# Access Control
|
||||||
|
# When enabled, it will be applied globally at connection level,
|
||||||
|
# all incoming connections (web, tcp and udp) will be checked against the ACL rules.
|
||||||
|
|
||||||
# acl:
|
# acl:
|
||||||
# default: allow # or deny (default: allow)
|
# default: allow # or deny (default: allow)
|
||||||
# allow_local: true # or false (default: true)
|
# allow_local: true # or false (default: true)
|
||||||
@@ -31,12 +35,21 @@
|
|||||||
# - country:US
|
# - country:US
|
||||||
# - timezone:Asia/Shanghai
|
# - timezone:Asia/Shanghai
|
||||||
# log: # warning: logging ACL can be slow based on the number of incoming connections and configured rules
|
# log: # warning: logging ACL can be slow based on the number of incoming connections and configured rules
|
||||||
# buffer_size: 65536 # (default: 64KB)
|
|
||||||
# path: /app/logs/acl.log # (default: none)
|
# path: /app/logs/acl.log # (default: none)
|
||||||
# stdout: false # (default: false)
|
# stdout: false # (default: false)
|
||||||
# keep: last 10 # (default: none)
|
# keep: 30 days # (default: 30 days)
|
||||||
|
# log_allowed: false # (default: false)
|
||||||
|
# notify:
|
||||||
|
# interval: 1m # (default: 1m)
|
||||||
|
# to: [gotify, discord] # names under providers.notification
|
||||||
|
# include_allowed: false # (default: false)
|
||||||
|
|
||||||
entrypoint:
|
entrypoint:
|
||||||
|
# Proxy Protocol: https://www.haproxy.com/blog/use-the-proxy-protocol-to-preserve-a-clients-ip-address
|
||||||
|
# When set to true, web entrypoint and all tcp routes will be wrapped with Proxy Protocol listener in order to preserve the client's IP address.
|
||||||
|
# Note that HTTP/3 with proxy protocol is not supported yet.
|
||||||
|
support_proxy_protocol: false
|
||||||
|
|
||||||
# Below define an example of middleware config
|
# Below define an example of middleware config
|
||||||
# 1. set security headers
|
# 1. set security headers
|
||||||
# 2. block non local IP connections
|
# 2. block non local IP connections
|
||||||
@@ -57,20 +70,14 @@ entrypoint:
|
|||||||
X-Frame-Options: SAMEORIGIN
|
X-Frame-Options: SAMEORIGIN
|
||||||
Referrer-Policy: same-origin
|
Referrer-Policy: same-origin
|
||||||
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
|
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
|
||||||
# - use: CIDRWhitelist
|
|
||||||
# allow:
|
|
||||||
# - "127.0.0.1"
|
|
||||||
# - "10.0.0.0/8"
|
|
||||||
# - "172.16.0.0/12"
|
|
||||||
# - "192.168.0.0/16"
|
|
||||||
# status: 403
|
|
||||||
# message: "Forbidden"
|
|
||||||
# - use: RedirectHTTP
|
# - use: RedirectHTTP
|
||||||
|
|
||||||
# below enables access log
|
# below enables access log
|
||||||
access_log:
|
access_log:
|
||||||
format: combined
|
format: combined
|
||||||
path: /app/logs/entrypoint.log
|
path: /app/logs/entrypoint.log
|
||||||
|
stdout: false # (default: false)
|
||||||
|
keep: 30 days # (default: 30 days)
|
||||||
|
|
||||||
providers:
|
providers:
|
||||||
# include files are standalone yaml files under `config/` directory
|
# include files are standalone yaml files under `config/` directory
|
||||||
@@ -95,9 +102,13 @@ providers:
|
|||||||
# remote-1: tcp://10.0.2.1:2375
|
# remote-1: tcp://10.0.2.1:2375
|
||||||
# remote-2: ssh://root:1234@10.0.2.2
|
# remote-2: ssh://root:1234@10.0.2.2
|
||||||
|
|
||||||
# notification providers (notify when service health changes)
|
# notification providers
|
||||||
#
|
#
|
||||||
# notification:
|
# notification:
|
||||||
|
# - name: ntfy
|
||||||
|
# provider: ntfy
|
||||||
|
# url: https://ntfy.domain.tld
|
||||||
|
# topic: godoxy
|
||||||
# - name: gotify
|
# - name: gotify
|
||||||
# provider: gotify
|
# provider: gotify
|
||||||
# url: https://gotify.domain.tld
|
# url: https://gotify.domain.tld
|
||||||
@@ -106,6 +117,11 @@ providers:
|
|||||||
# provider: webhook
|
# provider: webhook
|
||||||
# url: https://discord.com/api/webhooks/...
|
# url: https://discord.com/api/webhooks/...
|
||||||
# template: discord # this means use payload template from internal/notif/templates/discord.json
|
# template: discord # this means use payload template from internal/notif/templates/discord.json
|
||||||
|
# - name: pushover
|
||||||
|
# provider: webhook
|
||||||
|
# url: https://api.pushover.net/1/messages.json
|
||||||
|
# mime_type: application/x-www-form-urlencoded
|
||||||
|
# payload: '{"token": "your-app-token", "user": "your-user-key", "title": $title, "message": $message}'
|
||||||
|
|
||||||
# Proxmox providers (for idlesleep support for proxmox LXCs)
|
# Proxmox providers (for idlesleep support for proxmox LXCs)
|
||||||
#
|
#
|
||||||
@@ -115,8 +131,8 @@ providers:
|
|||||||
# secret: aaaa-bbbb-cccc-dddd
|
# secret: aaaa-bbbb-cccc-dddd
|
||||||
# no_tls_verify: true
|
# no_tls_verify: true
|
||||||
|
|
||||||
# Check https://docs.godoxy.dev/Certificates-and-domain-matching
|
# Match domains
|
||||||
# for explaination of `match_domains`
|
# See https://docs.godoxy.dev/Certificates-and-domain-matching
|
||||||
#
|
#
|
||||||
# match_domains:
|
# match_domains:
|
||||||
# - my.site
|
# - my.site
|
||||||
|
|||||||
@@ -1,33 +1,7 @@
|
|||||||
# Stage 1: deps
|
|
||||||
FROM golang:1.25.0-alpine AS deps
|
|
||||||
HEALTHCHECK NONE
|
|
||||||
|
|
||||||
# package version does not matter
|
|
||||||
# trunk-ignore(hadolint/DL3018)
|
|
||||||
RUN apk add --no-cache tzdata make libcap-setcap
|
|
||||||
|
|
||||||
# Stage 3: Final image
|
|
||||||
FROM alpine:3.22
|
FROM alpine:3.22
|
||||||
|
|
||||||
LABEL maintainer="yusing@6uo.me"
|
RUN apk add --no-cache ca-certificates
|
||||||
LABEL proxy.exclude=1
|
|
||||||
|
|
||||||
# copy timezone data
|
|
||||||
COPY --from=deps /usr/share/zoneinfo /usr/share/zoneinfo
|
|
||||||
|
|
||||||
# copy certs
|
|
||||||
COPY --from=deps /etc/ssl/certs /etc/ssl/certs
|
|
||||||
|
|
||||||
ARG TARGET
|
|
||||||
ENV TARGET=${TARGET}
|
|
||||||
|
|
||||||
ENV DOCKER_HOST=unix:///var/run/docker.sock
|
|
||||||
|
|
||||||
# copy binary
|
|
||||||
COPY bin/${TARGET} /app/run
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN chown -R 1000:1000 /app
|
CMD ["/app/run"]
|
||||||
|
|
||||||
CMD ["/app/run"]
|
|
||||||
|
|||||||
@@ -4,18 +4,16 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: dev.Dockerfile
|
dockerfile: dev.Dockerfile
|
||||||
args:
|
|
||||||
- TARGET=godoxy
|
|
||||||
container_name: godoxy-proxy-dev
|
container_name: godoxy-proxy-dev
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: dev.env
|
env_file: dev.env
|
||||||
environment:
|
environment:
|
||||||
|
DOCKER_HOST: unix:///var/run/docker.sock
|
||||||
TZ: Asia/Hong_Kong
|
TZ: Asia/Hong_Kong
|
||||||
API_ADDR: :8999
|
API_ADDR: 127.0.0.1:8999
|
||||||
API_USER: dev
|
API_USER: dev
|
||||||
API_PASSWORD: 1234
|
API_PASSWORD: 1234
|
||||||
API_SKIP_ORIGIN_CHECK: true
|
API_SKIP_ORIGIN_CHECK: true
|
||||||
API_JWT_SECURE: false
|
|
||||||
API_JWT_TTL: 24h
|
API_JWT_TTL: 24h
|
||||||
DEBUG: true
|
DEBUG: true
|
||||||
API_SECRET: 1234567891234567
|
API_SECRET: 1234567891234567
|
||||||
@@ -25,6 +23,7 @@ services:
|
|||||||
ipc: host
|
ipc: host
|
||||||
network_mode: host
|
network_mode: host
|
||||||
volumes:
|
volumes:
|
||||||
|
- ./bin/godoxy:/app/run:ro
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- ./dev-data/config:/app/config
|
- ./dev-data/config:/app/config
|
||||||
- ./dev-data/certs:/app/certs
|
- ./dev-data/certs:/app/certs
|
||||||
@@ -32,6 +31,17 @@ services:
|
|||||||
- ./dev-data/data:/app/data
|
- ./dev-data/data:/app/data
|
||||||
- ./dev-data/logs:/app/logs
|
- ./dev-data/logs:/app/logs
|
||||||
- ~/certs/myCA.pem:/etc/ssl/certs/ca.crt:ro
|
- ~/certs/myCA.pem:/etc/ssl/certs/ca.crt:ro
|
||||||
|
parca:
|
||||||
|
image: ghcr.io/parca-dev/parca:v0.24.2
|
||||||
|
container_name: godoxy-parca
|
||||||
|
restart: unless-stopped
|
||||||
|
command: [/parca, --config-path, /parca.yaml]
|
||||||
|
network_mode: host
|
||||||
|
# ports:
|
||||||
|
# - 7070:7070
|
||||||
|
configs:
|
||||||
|
- source: parca
|
||||||
|
target: /parca.yaml
|
||||||
tinyauth:
|
tinyauth:
|
||||||
image: ghcr.io/steveiliop56/tinyauth:v3
|
image: ghcr.io/steveiliop56/tinyauth:v3
|
||||||
container_name: tinyauth
|
container_name: tinyauth
|
||||||
@@ -42,3 +52,16 @@ services:
|
|||||||
- USERS=user:$$2a$$10$$UdLYoJ5lgPsC0RKqYH/jMua7zIn0g9kPqWmhYayJYLaZQ/FTmH2/u # user:password
|
- USERS=user:$$2a$$10$$UdLYoJ5lgPsC0RKqYH/jMua7zIn0g9kPqWmhYayJYLaZQ/FTmH2/u # user:password
|
||||||
labels:
|
labels:
|
||||||
proxy.tinyauth.port: "3000"
|
proxy.tinyauth.port: "3000"
|
||||||
|
configs:
|
||||||
|
parca:
|
||||||
|
content: |
|
||||||
|
object_storage:
|
||||||
|
bucket:
|
||||||
|
type: "FILESYSTEM"
|
||||||
|
config:
|
||||||
|
directory: "./data"
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: "parca"
|
||||||
|
scrape_interval: "1s"
|
||||||
|
static_configs:
|
||||||
|
- targets: [ 'localhost:7777' ]
|
||||||
|
|||||||
192
go.mod
192
go.mod
@@ -1,86 +1,70 @@
|
|||||||
module github.com/yusing/go-proxy
|
module github.com/yusing/godoxy
|
||||||
|
|
||||||
go 1.25.1
|
go 1.25.2
|
||||||
|
|
||||||
replace github.com/yusing/go-proxy/agent => ./agent
|
replace github.com/yusing/godoxy/agent => ./agent
|
||||||
|
|
||||||
replace github.com/yusing/go-proxy/internal/dnsproviders => ./internal/dnsproviders
|
replace github.com/yusing/godoxy/internal/dnsproviders => ./internal/dnsproviders
|
||||||
|
|
||||||
replace github.com/yusing/go-proxy/internal/utils => ./internal/utils
|
replace github.com/coreos/go-oidc/v3 => ./internal/go-oidc
|
||||||
|
|
||||||
replace github.com/coreos/go-oidc/v3 => github.com/godoxy-app/go-oidc/v3 v3.0.0-20250816044348-0630187cb14b
|
replace github.com/shirou/gopsutil/v4 => ./internal/gopsutil
|
||||||
|
|
||||||
replace github.com/shirou/gopsutil/v4 => github.com/godoxy-app/gopsutil/v4 v4.0.0-20250816043325-ee003f88b84d
|
replace github.com/yusing/goutils => ./goutils
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PuerkitoBio/goquery v1.10.3 // parsing HTML for extract fav icon
|
github.com/PuerkitoBio/goquery v1.10.3 // parsing HTML for extract fav icon
|
||||||
github.com/coreos/go-oidc/v3 v3.15.0 // oidc authentication
|
github.com/coreos/go-oidc/v3 v3.16.0 // oidc authentication
|
||||||
github.com/docker/docker v28.4.0+incompatible // docker daemon
|
github.com/docker/docker v28.5.1+incompatible // docker daemon
|
||||||
github.com/fsnotify/fsnotify v1.9.0 // file watcher
|
github.com/fsnotify/fsnotify v1.9.0 // file watcher
|
||||||
|
github.com/gin-gonic/gin v1.11.0 // api server
|
||||||
github.com/go-acme/lego/v4 v4.26.0 // acme client
|
github.com/go-acme/lego/v4 v4.26.0 // acme client
|
||||||
github.com/go-playground/validator/v10 v10.27.0 // validator
|
github.com/go-playground/validator/v10 v10.28.0 // validator
|
||||||
github.com/gobwas/glob v0.2.3 // glob matcher for route rules
|
github.com/gobwas/glob v0.2.3 // glob matcher for route rules
|
||||||
github.com/gorilla/websocket v1.5.3 // websocket for API and agent
|
github.com/gorilla/websocket v1.5.3 // websocket for API and agent
|
||||||
github.com/gotify/server/v2 v2.7.2 // reference the Message struct for json response
|
github.com/gotify/server/v2 v2.7.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/lithammer/fuzzysearch v1.1.8 // fuzzy search for searching icons and filtering metrics
|
||||||
github.com/puzpuzpuz/xsync/v4 v4.1.0 // lock free map for concurrent operations
|
github.com/pires/go-proxyproto v0.8.1 // proxy protocol support
|
||||||
|
github.com/puzpuzpuz/xsync/v4 v4.2.0 // lock free map for concurrent operations
|
||||||
github.com/rs/zerolog v1.34.0 // logging
|
github.com/rs/zerolog v1.34.0 // logging
|
||||||
github.com/shirou/gopsutil/v4 v4.25.8 // system info metrics
|
|
||||||
github.com/vincent-petithory/dataurl v1.0.0 // data url for fav icon
|
github.com/vincent-petithory/dataurl v1.0.0 // data url for fav icon
|
||||||
golang.org/x/crypto v0.42.0 // encrypting password with bcrypt
|
golang.org/x/crypto v0.43.0 // encrypting password with bcrypt
|
||||||
golang.org/x/net v0.44.0 // HTTP header utilities
|
golang.org/x/net v0.46.0 // HTTP header utilities
|
||||||
golang.org/x/oauth2 v0.31.0 // oauth2 authentication
|
golang.org/x/oauth2 v0.32.0 // oauth2 authentication
|
||||||
golang.org/x/sync v0.17.0
|
golang.org/x/sync v0.17.0
|
||||||
golang.org/x/time v0.13.0 // time utilities
|
golang.org/x/time v0.14.0 // time utilities
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/docker/cli v28.4.0+incompatible
|
github.com/docker/cli v28.5.1+incompatible
|
||||||
github.com/goccy/go-yaml v1.18.0 // yaml parsing for different config files
|
github.com/goccy/go-yaml v1.18.0 // yaml parsing for different config files
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||||
github.com/luthermonson/go-proxmox v0.2.3
|
github.com/luthermonson/go-proxmox v0.2.3
|
||||||
github.com/oschwald/maxminddb-golang v1.13.1
|
github.com/oschwald/maxminddb-golang v1.13.1
|
||||||
github.com/quic-go/quic-go v0.54.0
|
github.com/quic-go/quic-go v0.55.0 // indirect; http3 support
|
||||||
github.com/samber/slog-zerolog/v2 v2.7.3
|
github.com/samber/slog-zerolog/v2 v2.7.3 // indirect
|
||||||
github.com/spf13/afero v1.15.0
|
github.com/spf13/afero v1.15.0
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/yusing/go-proxy/agent v0.0.0-20250913143824-493c0afdface
|
github.com/yusing/ds v0.2.0
|
||||||
github.com/yusing/go-proxy/internal/dnsproviders v0.0.0-20250913143824-493c0afdface
|
github.com/yusing/godoxy/agent v0.0.0-20251011032714-d1e403e16f1c
|
||||||
github.com/yusing/go-proxy/internal/utils v0.0.0
|
github.com/yusing/godoxy/internal/dnsproviders v0.0.0-20251011032714-d1e403e16f1c
|
||||||
|
github.com/yusing/goutils v0.6.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/auth v0.16.5 // indirect
|
cloud.google.com/go/auth v0.17.0 // indirect
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.8.0 // indirect
|
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
||||||
github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // 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/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/privatedns/armprivatedns v1.3.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.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.5.0 // indirect
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
|
|
||||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.39.0 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.31.8 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.12 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.7 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.7 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.7 // 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.13.1 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.7 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.48.4 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.58.2 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.29.3 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.4 // indirect
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.38.4 // indirect
|
|
||||||
github.com/aws/smithy-go v1.23.0 // indirect
|
|
||||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||||
github.com/boombuler/barcode v1.1.0 // indirect
|
|
||||||
github.com/buger/goterm v1.0.4 // indirect
|
github.com/buger/goterm v1.0.4 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
@@ -89,166 +73,112 @@ require (
|
|||||||
github.com/djherbis/times v1.6.0 // indirect
|
github.com/djherbis/times v1.6.0 // indirect
|
||||||
github.com/docker/go-connections v0.6.0
|
github.com/docker/go-connections v0.6.0
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/ebitengine/purego v0.8.4 // indirect
|
github.com/ebitengine/purego v0.9.0 // indirect
|
||||||
github.com/exoscale/egoscale/v3 v3.1.26 // indirect
|
|
||||||
github.com/fatih/structs v1.1.0 // indirect
|
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||||
github.com/go-errors/errors v1.5.1 // indirect
|
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
||||||
github.com/go-jose/go-jose/v4 v4.1.2 // indirect
|
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-resty/resty/v2 v2.16.5 // indirect
|
github.com/gofrs/flock v0.13.0 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
|
||||||
github.com/gofrs/flock v0.12.1 // indirect
|
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
|
||||||
github.com/google/s2a-go v0.1.9 // indirect
|
github.com/google/s2a-go v0.1.9 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
github.com/googleapis/gax-go/v2 v2.15.0 // 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-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
|
||||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
|
||||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
|
|
||||||
github.com/infobloxopen/infoblox-go-client/v2 v2.10.0 // indirect
|
|
||||||
github.com/jinzhu/copier v0.4.0 // indirect
|
github.com/jinzhu/copier v0.4.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect
|
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // 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/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/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/linode/linodego v1.57.0 // indirect
|
|
||||||
github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
|
|
||||||
github.com/liquidweb/liquidweb-go v1.6.4 // indirect
|
|
||||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect
|
|
||||||
github.com/magefile/mage v1.15.0 // indirect
|
github.com/magefile/mage v1.15.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/miekg/dns v1.1.68 // indirect
|
github.com/miekg/dns v1.1.68 // indirect
|
||||||
github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // 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/goacmedns v0.2.0 // indirect
|
||||||
github.com/nrdcg/goinwx v0.11.0 // indirect
|
|
||||||
github.com/nrdcg/mailinabox v0.2.0 // indirect
|
|
||||||
github.com/nrdcg/nodion v0.1.0 // indirect
|
|
||||||
github.com/nrdcg/porkbun v0.4.0 // indirect
|
github.com/nrdcg/porkbun v0.4.0 // indirect
|
||||||
github.com/nzdjb/go-metaname v1.0.0 // indirect
|
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/ovh/go-ovh v1.9.0 // indirect
|
github.com/ovh/go-ovh v1.9.0 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // 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/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // 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/pquerna/otp v1.5.0 // indirect
|
|
||||||
github.com/quic-go/qpack v0.5.1 // indirect
|
github.com/quic-go/qpack v0.5.1 // indirect
|
||||||
github.com/regfish/regfish-dnsapi-go v0.1.1 // indirect
|
github.com/samber/lo v1.52.0 // indirect
|
||||||
github.com/sacloud/api-client-go v0.3.3 // indirect
|
|
||||||
github.com/sacloud/go-http v0.1.9 // indirect
|
|
||||||
github.com/sacloud/iaas-api-go v1.17.1 // indirect
|
|
||||||
github.com/sacloud/packages-go v0.0.11 // indirect
|
|
||||||
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
|
||||||
github.com/samber/lo v1.51.0 // indirect
|
|
||||||
github.com/samber/slog-common v0.19.0 // indirect
|
github.com/samber/slog-common v0.19.0 // indirect
|
||||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.34 // indirect
|
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.35 // indirect
|
||||||
github.com/selectel/domains-go v1.1.0 // indirect
|
|
||||||
github.com/shopspring/decimal v1.4.0 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // 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.2.1 // indirect
|
|
||||||
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
|
|
||||||
github.com/sony/gobreaker v1.0.0 // indirect
|
github.com/sony/gobreaker v1.0.0 // indirect
|
||||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
|
||||||
github.com/spf13/cast v1.10.0 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
|
||||||
github.com/spf13/viper v1.21.0 // indirect
|
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
|
||||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
|
||||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
|
||||||
github.com/transip/gotransip/v6 v6.26.0 // indirect
|
|
||||||
github.com/ultradns/ultradns-go-sdk v1.8.1-20250722213956-faef419 // indirect
|
|
||||||
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
|
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.219 // indirect
|
|
||||||
github.com/vultr/govultr/v3 v3.23.0 // indirect
|
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.2.0 // indirect
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||||
go.uber.org/atomic v1.11.0
|
go.uber.org/atomic v1.11.0
|
||||||
go.uber.org/mock v0.6.0 // indirect
|
|
||||||
go.uber.org/ratelimit v0.3.1 // indirect
|
go.uber.org/ratelimit v0.3.1 // indirect
|
||||||
golang.org/x/mod v0.28.0 // indirect
|
golang.org/x/mod v0.29.0 // indirect
|
||||||
golang.org/x/sys v0.36.0 // indirect
|
golang.org/x/sys v0.37.0 // indirect
|
||||||
golang.org/x/text v0.29.0 // indirect
|
golang.org/x/text v0.30.0 // indirect
|
||||||
golang.org/x/tools v0.37.0 // indirect
|
golang.org/x/tools v0.38.0 // indirect
|
||||||
google.golang.org/api v0.249.0 // indirect
|
google.golang.org/api v0.252.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251007200510-49b9836ed3ff // indirect
|
||||||
google.golang.org/grpc v1.75.1 // indirect
|
google.golang.org/grpc v1.76.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.9 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/ns1/ns1-go.v2 v2.15.0 // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.10.1
|
github.com/bytedance/sonic v1.14.1
|
||||||
github.com/yusing/ds v0.1.0
|
github.com/shirou/gopsutil/v4 v4.25.9
|
||||||
|
github.com/yusing/gointernals v0.1.16
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/akamai/AkamaiOPEN-edgegrid-golang/v11 v11.1.0 // indirect
|
github.com/akamai/AkamaiOPEN-edgegrid-golang/v11 v11.1.0 // indirect
|
||||||
github.com/aziontech/azionapi-go-sdk v0.142.0 // indirect
|
|
||||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||||
github.com/bytedance/sonic v1.14.1 // indirect
|
|
||||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
github.com/containerd/errdefs v1.0.0 // indirect
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/dnsimple/dnsimple-go/v4 v4.0.0 // indirect
|
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||||
|
github.com/go-resty/resty/v2 v2.16.5 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
|
github.com/linode/linodego v1.60.0 // indirect
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect
|
||||||
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
||||||
github.com/moby/term v0.5.2 // indirect
|
github.com/moby/term v0.5.2 // indirect
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/namedotcom/go/v4 v4.0.2 // indirect
|
github.com/nrdcg/oci-go-sdk/common/v1065 v1065.102.0 // indirect
|
||||||
github.com/nrdcg/oci-go-sdk/common/v1065 v1065.100.0 // indirect
|
github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.102.0 // indirect
|
||||||
github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.100.0 // indirect
|
|
||||||
github.com/onsi/ginkgo/v2 v2.25.1 // indirect
|
|
||||||
github.com/onsi/gomega v1.38.1 // indirect
|
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||||
github.com/selectel/go-selvpcclient/v4 v4.1.0 // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
github.com/stretchr/objx v0.5.3 // 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/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||||
|
github.com/ulikunitz/xz v0.5.14 // indirect
|
||||||
|
github.com/vultr/govultr/v3 v3.24.0 // indirect
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
golang.org/x/arch v0.22.0 // indirect
|
||||||
golang.org/x/arch v0.21.0 // indirect
|
|
||||||
google.golang.org/genproto v0.0.0-20250908214217-97024824d090 // indirect
|
google.golang.org/genproto v0.0.0-20250908214217-97024824d090 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
1
goutils
Submodule
1
goutils
Submodule
Submodule goutils added at 2fa6b6c3e5
@@ -1,17 +1,23 @@
|
|||||||
package acl
|
package acl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
"net"
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/puzpuzpuz/xsync/v4"
|
"github.com/puzpuzpuz/xsync/v4"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/logging/accesslog"
|
||||||
"github.com/yusing/go-proxy/internal/logging/accesslog"
|
"github.com/yusing/godoxy/internal/maxmind"
|
||||||
"github.com/yusing/go-proxy/internal/maxmind"
|
"github.com/yusing/godoxy/internal/notif"
|
||||||
"github.com/yusing/go-proxy/internal/task"
|
"github.com/yusing/godoxy/internal/utils"
|
||||||
"github.com/yusing/go-proxy/internal/utils"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
|
strutils "github.com/yusing/goutils/strings"
|
||||||
|
"github.com/yusing/goutils/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -21,16 +27,42 @@ type Config struct {
|
|||||||
Deny Matchers `json:"deny"`
|
Deny Matchers `json:"deny"`
|
||||||
Log *accesslog.ACLLoggerConfig `json:"log"`
|
Log *accesslog.ACLLoggerConfig `json:"log"`
|
||||||
|
|
||||||
|
Notify struct {
|
||||||
|
To []string `json:"to"` // list of notification providers
|
||||||
|
Interval time.Duration `json:"interval"` // interval between notifications
|
||||||
|
IncludeAllowed *bool `json:"include_allowed"` // default: false
|
||||||
|
} `json:"notify"`
|
||||||
|
|
||||||
config
|
config
|
||||||
valErr gperr.Error
|
valErr gperr.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultNotifyInterval = 1 * time.Minute
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
defaultAllow bool
|
defaultAllow bool
|
||||||
allowLocal bool
|
allowLocal bool
|
||||||
ipCache *xsync.Map[string, *checkCache]
|
ipCache *xsync.Map[string, *checkCache]
|
||||||
logAllowed bool
|
|
||||||
logger *accesslog.AccessLogger
|
// will be nil if Notify.To is empty
|
||||||
|
// these are per IP, reset every Notify.Interval
|
||||||
|
allowedCount map[string]uint32
|
||||||
|
blockedCount map[string]uint32
|
||||||
|
|
||||||
|
// these are total, never reset
|
||||||
|
totalAllowedCount uint64
|
||||||
|
totalBlockedCount uint64
|
||||||
|
|
||||||
|
logAllowed bool
|
||||||
|
// will be nil if Log is nil
|
||||||
|
logger *accesslog.AccessLogger
|
||||||
|
|
||||||
|
// will never tick if Notify.To is empty
|
||||||
|
notifyTicker *time.Ticker
|
||||||
|
notifyAllowed bool
|
||||||
|
|
||||||
|
// will be nil if both Log and Notify.To are empty
|
||||||
|
logNotifyCh chan ipLog
|
||||||
}
|
}
|
||||||
|
|
||||||
type checkCache struct {
|
type checkCache struct {
|
||||||
@@ -39,6 +71,14 @@ type checkCache struct {
|
|||||||
created time.Time
|
created time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ipLog struct {
|
||||||
|
info *maxmind.IPInfo
|
||||||
|
allowed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// could be nil
|
||||||
|
var ActiveConfig atomic.Pointer[Config]
|
||||||
|
|
||||||
const cacheTTL = 1 * time.Minute
|
const cacheTTL = 1 * time.Minute
|
||||||
|
|
||||||
func (c *checkCache) Expired() bool {
|
func (c *checkCache) Expired() bool {
|
||||||
@@ -69,6 +109,10 @@ func (c *Config) Validate() gperr.Error {
|
|||||||
c.allowLocal = true
|
c.allowLocal = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Notify.Interval < 0 {
|
||||||
|
c.Notify.Interval = defaultNotifyInterval
|
||||||
|
}
|
||||||
|
|
||||||
if c.Log != nil {
|
if c.Log != nil {
|
||||||
c.logAllowed = c.Log.LogAllowed
|
c.logAllowed = c.Log.LogAllowed
|
||||||
}
|
}
|
||||||
@@ -79,6 +123,12 @@ func (c *Config) Validate() gperr.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.ipCache = xsync.NewMap[string, *checkCache]()
|
c.ipCache = xsync.NewMap[string, *checkCache]()
|
||||||
|
|
||||||
|
if c.Notify.IncludeAllowed != nil {
|
||||||
|
c.notifyAllowed = *c.Notify.IncludeAllowed
|
||||||
|
} else {
|
||||||
|
c.notifyAllowed = false
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +136,7 @@ func (c *Config) Valid() bool {
|
|||||||
return c != nil && c.valErr == nil
|
return c != nil && c.valErr == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Start(parent *task.Task) gperr.Error {
|
func (c *Config) Start(parent task.Parent) gperr.Error {
|
||||||
if c.Log != nil {
|
if c.Log != nil {
|
||||||
logger, err := accesslog.NewAccessLogger(parent, c.Log)
|
logger, err := accesslog.NewAccessLogger(parent, c.Log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -97,6 +147,23 @@ func (c *Config) Start(parent *task.Task) gperr.Error {
|
|||||||
if c.valErr != nil {
|
if c.valErr != nil {
|
||||||
return c.valErr
|
return c.valErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.needLogOrNotify() {
|
||||||
|
c.logNotifyCh = make(chan ipLog, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.needNotify() {
|
||||||
|
c.allowedCount = make(map[string]uint32)
|
||||||
|
c.blockedCount = make(map[string]uint32)
|
||||||
|
c.notifyTicker = time.NewTicker(c.Notify.Interval)
|
||||||
|
} else {
|
||||||
|
c.notifyTicker = time.NewTicker(time.Duration(math.MaxInt64)) // never tick
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.needLogOrNotify() {
|
||||||
|
go c.logNotifyLoop(parent)
|
||||||
|
}
|
||||||
|
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("default", c.Default).
|
Str("default", c.Default).
|
||||||
Bool("allow_local", c.allowLocal).
|
Bool("allow_local", c.allowLocal).
|
||||||
@@ -117,12 +184,89 @@ func (c *Config) cacheRecord(info *maxmind.IPInfo, allow bool) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) log(info *maxmind.IPInfo, allowed bool) {
|
func (c *Config) needLogOrNotify() bool {
|
||||||
if c.logger == nil {
|
return c.needLog() || c.needNotify()
|
||||||
return
|
}
|
||||||
|
|
||||||
|
func (c *Config) needLog() bool {
|
||||||
|
return c.logger != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) needNotify() bool {
|
||||||
|
return len(c.Notify.To) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) getCachedCity(ip string) string {
|
||||||
|
record, ok := c.ipCache.Load(ip)
|
||||||
|
if ok {
|
||||||
|
if record.City != nil {
|
||||||
|
if record.City.Country.IsoCode != "" {
|
||||||
|
return record.City.Country.IsoCode
|
||||||
|
}
|
||||||
|
return record.City.Location.TimeZone
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !allowed || c.logAllowed {
|
return "unknown location"
|
||||||
c.logger.LogACL(info, !allowed)
|
}
|
||||||
|
|
||||||
|
func (c *Config) logNotifyLoop(parent task.Parent) {
|
||||||
|
defer c.notifyTicker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-parent.Context().Done():
|
||||||
|
return
|
||||||
|
case log := <-c.logNotifyCh:
|
||||||
|
if c.logger != nil {
|
||||||
|
if !log.allowed || c.logAllowed {
|
||||||
|
c.logger.LogACL(log.info, !log.allowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.needNotify() {
|
||||||
|
if log.allowed {
|
||||||
|
if c.notifyAllowed {
|
||||||
|
c.allowedCount[log.info.Str]++
|
||||||
|
c.totalAllowedCount++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.blockedCount[log.info.Str]++
|
||||||
|
c.totalBlockedCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-c.notifyTicker.C: // will never tick when notify is disabled
|
||||||
|
total := len(c.allowedCount) + len(c.blockedCount)
|
||||||
|
if total == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
total++
|
||||||
|
fieldsBody := make(notif.ListBody, total)
|
||||||
|
i := 0
|
||||||
|
fieldsBody[i] = fmt.Sprintf("Total: allowed %d, blocked %d", c.totalAllowedCount, c.totalBlockedCount)
|
||||||
|
i++
|
||||||
|
for ip, count := range c.allowedCount {
|
||||||
|
fieldsBody[i] = fmt.Sprintf("%s (%s): allowed %d times", ip, c.getCachedCity(ip), count)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for ip, count := range c.blockedCount {
|
||||||
|
fieldsBody[i] = fmt.Sprintf("%s (%s): blocked %d times", ip, c.getCachedCity(ip), count)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
notif.Notify(¬if.LogMessage{
|
||||||
|
Level: zerolog.InfoLevel,
|
||||||
|
Title: "ACL Summary for last " + strutils.FormatDuration(c.Notify.Interval),
|
||||||
|
Body: fieldsBody,
|
||||||
|
To: c.Notify.To,
|
||||||
|
})
|
||||||
|
clear(c.allowedCount)
|
||||||
|
clear(c.blockedCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// log and notify if needed
|
||||||
|
func (c *Config) logAndNotify(info *maxmind.IPInfo, allowed bool) {
|
||||||
|
if c.logNotifyCh != nil {
|
||||||
|
c.logNotifyCh <- ipLog{info: info, allowed: allowed}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,30 +281,30 @@ func (c *Config) IPAllowed(ip net.IP) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.allowLocal && ip.IsPrivate() {
|
if c.allowLocal && ip.IsPrivate() {
|
||||||
c.log(&maxmind.IPInfo{IP: ip, Str: ip.String()}, true)
|
c.logAndNotify(&maxmind.IPInfo{IP: ip, Str: ip.String()}, true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
ipStr := ip.String()
|
ipStr := ip.String()
|
||||||
record, ok := c.ipCache.Load(ipStr)
|
record, ok := c.ipCache.Load(ipStr)
|
||||||
if ok && !record.Expired() {
|
if ok && !record.Expired() {
|
||||||
c.log(record.IPInfo, record.allow)
|
c.logAndNotify(record.IPInfo, record.allow)
|
||||||
return record.allow
|
return record.allow
|
||||||
}
|
}
|
||||||
|
|
||||||
ipAndStr := &maxmind.IPInfo{IP: ip, Str: ipStr}
|
ipAndStr := &maxmind.IPInfo{IP: ip, Str: ipStr}
|
||||||
if c.Allow.Match(ipAndStr) {
|
if c.Allow.Match(ipAndStr) {
|
||||||
c.log(ipAndStr, true)
|
c.logAndNotify(ipAndStr, true)
|
||||||
c.cacheRecord(ipAndStr, true)
|
c.cacheRecord(ipAndStr, true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if c.Deny.Match(ipAndStr) {
|
if c.Deny.Match(ipAndStr) {
|
||||||
c.log(ipAndStr, false)
|
c.logAndNotify(ipAndStr, false)
|
||||||
c.cacheRecord(ipAndStr, false)
|
c.cacheRecord(ipAndStr, false)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
c.log(ipAndStr, c.defaultAllow)
|
c.logAndNotify(ipAndStr, c.defaultAllow)
|
||||||
c.cacheRecord(ipAndStr, c.defaultAllow)
|
c.cacheRecord(ipAndStr, c.defaultAllow)
|
||||||
return c.defaultAllow
|
return c.defaultAllow
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/maxmind"
|
||||||
"github.com/yusing/go-proxy/internal/maxmind"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MatcherFunc func(*maxmind.IPInfo) bool
|
type MatcherFunc func(*maxmind.IPInfo) bool
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
maxmind "github.com/yusing/go-proxy/internal/maxmind/types"
|
maxmind "github.com/yusing/godoxy/internal/maxmind/types"
|
||||||
"github.com/yusing/go-proxy/internal/serialization"
|
"github.com/yusing/godoxy/internal/serialization"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMatchers(t *testing.T) {
|
func TestMatchers(t *testing.T) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package acl
|
package acl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
@@ -54,6 +55,21 @@ func (s *TCPListener) Accept() (net.Conn, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tcpListener interface {
|
||||||
|
SetDeadline(t time.Time) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ tcpListener = (*net.TCPListener)(nil)
|
||||||
|
|
||||||
|
func (s *TCPListener) SetDeadline(t time.Time) error {
|
||||||
|
switch lis := s.lis.(type) {
|
||||||
|
case tcpListener:
|
||||||
|
return lis.SetDeadline(t)
|
||||||
|
default:
|
||||||
|
return errors.New("not a TCPListener")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TCPListener) Close() error {
|
func (s *TCPListener) Close() error {
|
||||||
return s.lis.Close()
|
return s.lis.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package acl
|
package acl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -74,6 +75,31 @@ func (s *UDPListener) SetWriteDeadline(t time.Time) error {
|
|||||||
return s.lis.SetWriteDeadline(t)
|
return s.lis.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type udpListener interface {
|
||||||
|
SetReadBuffer(bytes int) error
|
||||||
|
SetWriteBuffer(bytes int) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ udpListener = (*net.UDPConn)(nil)
|
||||||
|
|
||||||
|
func (s *UDPListener) SetReadBuffer(bytes int) error {
|
||||||
|
switch lis := s.lis.(type) {
|
||||||
|
case udpListener:
|
||||||
|
return lis.SetReadBuffer(bytes)
|
||||||
|
default:
|
||||||
|
return errors.New("not a UDPConn")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UDPListener) SetWriteBuffer(bytes int) error {
|
||||||
|
switch lis := s.lis.(type) {
|
||||||
|
case udpListener:
|
||||||
|
return lis.SetWriteBuffer(bytes)
|
||||||
|
default:
|
||||||
|
return errors.New("not a UDPConn")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *UDPListener) Close() error {
|
func (s *UDPListener) Close() error {
|
||||||
return s.lis.Close()
|
return s.lis.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,19 +8,19 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
apiV1 "github.com/yusing/go-proxy/internal/api/v1"
|
apiV1 "github.com/yusing/godoxy/internal/api/v1"
|
||||||
agentApi "github.com/yusing/go-proxy/internal/api/v1/agent"
|
agentApi "github.com/yusing/godoxy/internal/api/v1/agent"
|
||||||
authApi "github.com/yusing/go-proxy/internal/api/v1/auth"
|
authApi "github.com/yusing/godoxy/internal/api/v1/auth"
|
||||||
certApi "github.com/yusing/go-proxy/internal/api/v1/cert"
|
certApi "github.com/yusing/godoxy/internal/api/v1/cert"
|
||||||
dockerApi "github.com/yusing/go-proxy/internal/api/v1/docker"
|
dockerApi "github.com/yusing/godoxy/internal/api/v1/docker"
|
||||||
fileApi "github.com/yusing/go-proxy/internal/api/v1/file"
|
fileApi "github.com/yusing/godoxy/internal/api/v1/file"
|
||||||
homepageApi "github.com/yusing/go-proxy/internal/api/v1/homepage"
|
homepageApi "github.com/yusing/godoxy/internal/api/v1/homepage"
|
||||||
metricsApi "github.com/yusing/go-proxy/internal/api/v1/metrics"
|
metricsApi "github.com/yusing/godoxy/internal/api/v1/metrics"
|
||||||
routeApi "github.com/yusing/go-proxy/internal/api/v1/route"
|
routeApi "github.com/yusing/godoxy/internal/api/v1/route"
|
||||||
"github.com/yusing/go-proxy/internal/auth"
|
"github.com/yusing/godoxy/internal/auth"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @title GoDoxy API
|
// @title GoDoxy API
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package apitypes
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ErrorResponse struct {
|
type ErrorResponse struct {
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package apitypes
|
|
||||||
|
|
||||||
type ErrorCode int
|
|
||||||
|
|
||||||
const (
|
|
||||||
ErrorCodeUnauthorized ErrorCode = iota + 1
|
|
||||||
ErrorCodeNotFound
|
|
||||||
ErrorCodeInternalServerError
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e ErrorCode) String() string {
|
|
||||||
return []string{
|
|
||||||
"Unauthorized",
|
|
||||||
"Not Found",
|
|
||||||
"Internal Server Error",
|
|
||||||
}[e]
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PEMPairResponse struct {
|
type PEMPairResponse struct {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/goutils/apitypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NewAgentRequest struct {
|
type NewAgentRequest struct {
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
"github.com/yusing/goutils/http/httpheaders"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "list"
|
// @x-id "list"
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/certs"
|
"github.com/yusing/godoxy/agent/pkg/certs"
|
||||||
. "github.com/yusing/go-proxy/internal/api/types"
|
config "github.com/yusing/godoxy/internal/config/types"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
"github.com/yusing/godoxy/internal/route/provider"
|
||||||
|
apitypes "github.com/yusing/goutils/apitypes"
|
||||||
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VerifyNewAgentRequest struct {
|
type VerifyNewAgentRequest struct {
|
||||||
@@ -35,44 +37,78 @@ type VerifyNewAgentRequest struct {
|
|||||||
func Verify(c *gin.Context) {
|
func Verify(c *gin.Context) {
|
||||||
var request VerifyNewAgentRequest
|
var request VerifyNewAgentRequest
|
||||||
if err := c.ShouldBindJSON(&request); err != nil {
|
if err := c.ShouldBindJSON(&request); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, Error("invalid request", err))
|
c.JSON(http.StatusBadRequest, apitypes.Error("invalid request", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
filename, ok := certs.AgentCertsFilepath(request.Host)
|
filename, ok := certs.AgentCertsFilepath(request.Host)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.JSON(http.StatusBadRequest, Error("invalid host", nil))
|
c.JSON(http.StatusBadRequest, apitypes.Error("invalid host", nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ca, err := fromEncryptedPEMPairResponse(request.CA)
|
ca, err := fromEncryptedPEMPairResponse(request.CA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusBadRequest, Error("invalid CA", err))
|
c.JSON(http.StatusBadRequest, apitypes.Error("invalid CA", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := fromEncryptedPEMPairResponse(request.Client)
|
client, err := fromEncryptedPEMPairResponse(request.Client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusBadRequest, Error("invalid client", err))
|
c.JSON(http.StatusBadRequest, apitypes.Error("invalid client", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nRoutesAdded, err := config.GetInstance().VerifyNewAgent(request.Host, ca, client, request.ContainerRuntime)
|
nRoutesAdded, err := verifyNewAgent(request.Host, ca, client, request.ContainerRuntime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusBadRequest, Error("invalid request", err))
|
c.JSON(http.StatusBadRequest, apitypes.Error("invalid request", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
zip, err := certs.ZipCert(ca.Cert, client.Cert, client.Key)
|
zip, err := certs.ZipCert(ca.Cert, client.Cert, client.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(InternalServerError(err, "failed to zip certs"))
|
c.Error(apitypes.InternalServerError(err, "failed to zip certs"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(filename, zip, 0o600); err != nil {
|
if err := os.WriteFile(filename, zip, 0o600); err != nil {
|
||||||
c.Error(InternalServerError(err, "failed to write certs"))
|
c.Error(apitypes.InternalServerError(err, "failed to write certs"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, Success(fmt.Sprintf("Added %d routes", nRoutesAdded)))
|
c.JSON(http.StatusOK, apitypes.Success(fmt.Sprintf("Added %d routes", nRoutesAdded)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyNewAgent(host string, ca agent.PEMPair, client agent.PEMPair, containerRuntime agent.ContainerRuntime) (int, gperr.Error) {
|
||||||
|
cfgState := config.ActiveState.Load()
|
||||||
|
for _, a := range cfgState.Value().Providers.Agents {
|
||||||
|
if a.Addr == host {
|
||||||
|
return 0, gperr.New("agent already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var agentCfg agent.AgentConfig
|
||||||
|
agentCfg.Addr = host
|
||||||
|
agentCfg.Runtime = containerRuntime
|
||||||
|
|
||||||
|
err := agentCfg.StartWithCerts(cfgState.Context(), ca.Cert, client.Cert, client.Key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, gperr.Wrap(err, "failed to start agent")
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := provider.NewAgentProvider(&agentCfg)
|
||||||
|
if _, loaded := cfgState.LoadOrStoreProvider(provider.String(), provider); loaded {
|
||||||
|
return 0, gperr.Errorf("provider %s already exists", provider.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// agent must be added before loading routes
|
||||||
|
agent.AddAgent(&agentCfg)
|
||||||
|
err = provider.LoadRoutes()
|
||||||
|
if err != nil {
|
||||||
|
cfgState.DeleteProvider(provider.String())
|
||||||
|
agent.RemoveAgent(&agentCfg)
|
||||||
|
return 0, gperr.Wrap(err, "failed to load routes")
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.NumRoutes(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/auth"
|
"github.com/yusing/godoxy/internal/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "callback"
|
// @x-id "callback"
|
||||||
|
|||||||
@@ -2,17 +2,17 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/auth"
|
"github.com/yusing/godoxy/internal/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "check"
|
// @x-id "check"
|
||||||
// @Base /api/v1
|
// @Base /api/v1
|
||||||
// @Summary Check authentication status
|
// @Summary Check authentication status
|
||||||
// @Description Checks if the user is authenticated by validating their token
|
// @Description Checks if the user is authenticated by validating their token
|
||||||
// @Tags auth
|
// @Tags auth
|
||||||
// @Produce plain
|
// @Produce plain
|
||||||
// @Success 200 {string} string "OK"
|
// @Success 200 {string} string "OK"
|
||||||
// @Failure 403 {string} string "Forbidden: use X-Redirect-To header to redirect to login page"
|
// @Failure 302 {string} string "Redirects to login page or IdP"
|
||||||
// @Router /auth/check [head]
|
// @Router /auth/check [head]
|
||||||
func Check(c *gin.Context) {
|
func Check(c *gin.Context) {
|
||||||
auth.AuthCheckHandler(c.Writer, c.Request)
|
auth.AuthCheckHandler(c.Writer, c.Request)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/auth"
|
"github.com/yusing/godoxy/internal/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "login"
|
// @x-id "login"
|
||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
// @Tags auth
|
// @Tags auth
|
||||||
// @Produce plain
|
// @Produce plain
|
||||||
// @Success 302 {string} string "Redirects to login page or IdP"
|
// @Success 302 {string} string "Redirects to login page or IdP"
|
||||||
// @Failure 403 {string} string "Forbidden(webui): follow X-Redirect-To header"
|
|
||||||
// @Failure 429 {string} string "Too Many Requests"
|
// @Failure 429 {string} string "Too Many Requests"
|
||||||
// @Router /auth/login [post]
|
// @Router /auth/login [post]
|
||||||
func Login(c *gin.Context) {
|
func Login(c *gin.Context) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/auth"
|
"github.com/yusing/godoxy/internal/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "logout"
|
// @x-id "logout"
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
"github.com/yusing/godoxy/internal/autocert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CertInfo struct {
|
type CertInfo struct {
|
||||||
@@ -29,7 +29,7 @@ type CertInfo struct {
|
|||||||
// @Failure 500 {object} apitypes.ErrorResponse
|
// @Failure 500 {object} apitypes.ErrorResponse
|
||||||
// @Router /cert/info [get]
|
// @Router /cert/info [get]
|
||||||
func Info(c *gin.Context) {
|
func Info(c *gin.Context) {
|
||||||
autocert := config.GetInstance().AutoCertProvider()
|
autocert := autocert.ActiveProvider.Load()
|
||||||
if autocert == nil {
|
if autocert == nil {
|
||||||
c.JSON(http.StatusNotFound, apitypes.Error("autocert is not enabled"))
|
c.JSON(http.StatusNotFound, apitypes.Error("autocert is not enabled"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
"github.com/yusing/godoxy/internal/autocert"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/logging/memlogger"
|
||||||
"github.com/yusing/go-proxy/internal/logging/memlogger"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "renew"
|
// @x-id "renew"
|
||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
// @Failure 500 {object} apitypes.ErrorResponse
|
// @Failure 500 {object} apitypes.ErrorResponse
|
||||||
// @Router /cert/renew [get]
|
// @Router /cert/renew [get]
|
||||||
func Renew(c *gin.Context) {
|
func Renew(c *gin.Context) {
|
||||||
autocert := config.GetInstance().AutoCertProvider()
|
autocert := autocert.ActiveProvider.Load()
|
||||||
if autocert == nil {
|
if autocert == nil {
|
||||||
c.JSON(http.StatusNotFound, apitypes.Error("autocert is not enabled"))
|
c.JSON(http.StatusNotFound, apitypes.Error("autocert is not enabled"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "container"
|
// @x-id "container"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContainerState = container.ContainerState // @name ContainerState
|
type ContainerState = container.ContainerState // @name ContainerState
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
|
|
||||||
dockerSystem "github.com/docker/docker/api/types/system"
|
dockerSystem "github.com/docker/docker/api/types/system"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type containerStats struct {
|
type containerStats struct {
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import (
|
|||||||
"github.com/docker/docker/pkg/stdcopy"
|
"github.com/docker/docker/pkg/stdcopy"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
"github.com/yusing/go-proxy/internal/task"
|
"github.com/yusing/goutils/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LogsQueryParams struct {
|
type LogsQueryParams struct {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "restart"
|
// @x-id "restart"
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StartRequest struct {
|
type StartRequest struct {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StopRequest struct {
|
type StopRequest struct {
|
||||||
|
|||||||
@@ -6,13 +6,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/go-proxy/internal/docker"
|
"github.com/yusing/goutils/http/httpheaders"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -22,67 +20,6 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// getDockerClients returns a map of docker clients for the current config.
|
|
||||||
//
|
|
||||||
// Returns a map of docker clients by server name and an error if any.
|
|
||||||
//
|
|
||||||
// Even if there are errors, the map of docker clients might not be empty.
|
|
||||||
func getDockerClients() (DockerClients, gperr.Error) {
|
|
||||||
cfg := config.GetInstance()
|
|
||||||
|
|
||||||
dockerHosts := cfg.Value().Providers.Docker
|
|
||||||
dockerClients := make(DockerClients)
|
|
||||||
|
|
||||||
connErrs := gperr.NewBuilder("failed to connect to docker")
|
|
||||||
|
|
||||||
for name, host := range dockerHosts {
|
|
||||||
dockerClient, err := docker.NewClient(host)
|
|
||||||
if err != nil {
|
|
||||||
connErrs.Add(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
dockerClients[name] = dockerClient
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, agent := range agent.ListAgents() {
|
|
||||||
dockerClient, err := docker.NewClient(agent.FakeDockerHost())
|
|
||||||
if err != nil {
|
|
||||||
connErrs.Add(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
dockerClients[agent.Name] = dockerClient
|
|
||||||
}
|
|
||||||
|
|
||||||
return dockerClients, connErrs.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDockerClient(server string) (*docker.SharedClient, bool, error) {
|
|
||||||
cfg := config.GetInstance()
|
|
||||||
var host string
|
|
||||||
for name, h := range cfg.Value().Providers.Docker {
|
|
||||||
if name == server {
|
|
||||||
host = h
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if host == "" {
|
|
||||||
for _, agent := range agent.ListAgents() {
|
|
||||||
if agent.Name == server {
|
|
||||||
host = agent.FakeDockerHost()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if host == "" {
|
|
||||||
return nil, false, nil
|
|
||||||
}
|
|
||||||
dockerClient, err := docker.NewClient(host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
return dockerClient, true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// closeAllClients closes all docker clients after a delay.
|
// closeAllClients closes all docker clients after a delay.
|
||||||
//
|
//
|
||||||
// This is used to ensure that all docker clients are closed after the http handler returns.
|
// This is used to ensure that all docker clients are closed after the http handler returns.
|
||||||
@@ -103,11 +40,7 @@ func handleResult[V any, T ResultType[V]](c *gin.Context, errs error, result T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func serveHTTP[V any, T ResultType[V]](c *gin.Context, getResult func(ctx context.Context, dockerClients DockerClients) (T, gperr.Error)) {
|
func serveHTTP[V any, T ResultType[V]](c *gin.Context, getResult func(ctx context.Context, dockerClients DockerClients) (T, gperr.Error)) {
|
||||||
dockerClients, err := getDockerClients()
|
dockerClients := docker.Clients()
|
||||||
if err != nil {
|
|
||||||
handleResult[V, T](c, err, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer closeAllClients(dockerClients)
|
defer closeAllClients(dockerClients)
|
||||||
|
|
||||||
if httpheaders.IsWebsocket(c.Request.Header) {
|
if httpheaders.IsWebsocket(c.Request.Header) {
|
||||||
|
|||||||
@@ -239,8 +239,8 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"403": {
|
"302": {
|
||||||
"description": "Forbidden: use X-Redirect-To header to redirect to login page",
|
"description": "Redirects to login page or IdP",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
@@ -267,12 +267,6 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"403": {
|
|
||||||
"description": "Forbidden(webui): follow X-Redirect-To header",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"429": {
|
"429": {
|
||||||
"description": "Too Many Requests",
|
"description": "Too Many Requests",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|||||||
@@ -1581,8 +1581,8 @@ paths:
|
|||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
"403":
|
"302":
|
||||||
description: 'Forbidden: use X-Redirect-To header to redirect to login page'
|
description: Redirects to login page or IdP
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
summary: Check authentication status
|
summary: Check authentication status
|
||||||
@@ -1600,10 +1600,6 @@ paths:
|
|||||||
description: Redirects to login page or IdP
|
description: Redirects to login page or IdP
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
"403":
|
|
||||||
description: 'Forbidden(webui): follow X-Redirect-To header'
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"429":
|
"429":
|
||||||
description: Too Many Requests
|
description: Too Many Requests
|
||||||
schema:
|
schema:
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/homepage"
|
"github.com/yusing/godoxy/internal/homepage"
|
||||||
"github.com/yusing/go-proxy/internal/route/routes"
|
"github.com/yusing/godoxy/internal/route/routes"
|
||||||
|
|
||||||
|
_ "unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GetFavIconRequest struct {
|
type GetFavIconRequest struct {
|
||||||
@@ -44,9 +46,9 @@ func FavIcon(c *gin.Context) {
|
|||||||
c.JSON(http.StatusBadRequest, apitypes.Error("invalid url", err))
|
c.JSON(http.StatusBadRequest, apitypes.Error("invalid url", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fetchResult := homepage.FetchFavIconFromURL(c.Request.Context(), &iconURL)
|
fetchResult, err := homepage.FetchFavIconFromURL(c.Request.Context(), &iconURL)
|
||||||
if !fetchResult.OK() {
|
if err != nil {
|
||||||
c.JSON(fetchResult.StatusCode, apitypes.Error(fetchResult.ErrMsg))
|
homepage.GinFetchError(c, fetchResult.StatusCode, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Data(fetchResult.StatusCode, fetchResult.ContentType(), fetchResult.Icon)
|
c.Data(fetchResult.StatusCode, fetchResult.ContentType(), fetchResult.Icon)
|
||||||
@@ -54,38 +56,39 @@ func FavIcon(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try with alias
|
// try with alias
|
||||||
result := GetFavIconFromAlias(c.Request.Context(), request.Alias)
|
result, err := GetFavIconFromAlias(c.Request.Context(), request.Alias)
|
||||||
if !result.OK() {
|
if err != nil {
|
||||||
c.JSON(result.StatusCode, apitypes.Error(result.ErrMsg))
|
homepage.GinFetchError(c, result.StatusCode, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Data(result.StatusCode, result.ContentType(), result.Icon)
|
c.Data(result.StatusCode, result.ContentType(), result.Icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFavIconFromAlias(ctx context.Context, alias string) *homepage.FetchResult {
|
//go:linkname GetFavIconFromAlias v1.GetFavIconFromAlias
|
||||||
|
func GetFavIconFromAlias(ctx context.Context, alias string) (homepage.FetchResult, error) {
|
||||||
// try with route.Icon
|
// try with route.Icon
|
||||||
r, ok := routes.HTTP.Get(alias)
|
r, ok := routes.HTTP.Get(alias)
|
||||||
if !ok {
|
if !ok {
|
||||||
return &homepage.FetchResult{
|
return homepage.FetchResultWithErrorf(http.StatusNotFound, "route not found")
|
||||||
StatusCode: http.StatusNotFound,
|
|
||||||
ErrMsg: "route not found",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var result *homepage.FetchResult
|
var (
|
||||||
|
result homepage.FetchResult
|
||||||
|
err error
|
||||||
|
)
|
||||||
hp := r.HomepageItem()
|
hp := r.HomepageItem()
|
||||||
if hp.Icon != nil {
|
if hp.Icon != nil {
|
||||||
if hp.Icon.IconSource == homepage.IconSourceRelative {
|
if hp.Icon.IconSource == homepage.IconSourceRelative {
|
||||||
result = homepage.FindIcon(ctx, r, *hp.Icon.FullURL)
|
result, err = homepage.FindIcon(ctx, r, *hp.Icon.FullURL)
|
||||||
} else {
|
} else {
|
||||||
result = homepage.FetchFavIconFromURL(ctx, hp.Icon)
|
result, err = homepage.FetchFavIconFromURL(ctx, hp.Icon)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// try extract from "link[rel=icon]"
|
// try extract from "link[rel=icon]"
|
||||||
result = homepage.FindIcon(ctx, r, "/")
|
result, err = homepage.FindIcon(ctx, r, "/")
|
||||||
}
|
}
|
||||||
if result.StatusCode == 0 {
|
if result.StatusCode == 0 {
|
||||||
result.StatusCode = http.StatusOK
|
result.StatusCode = http.StatusOK
|
||||||
}
|
}
|
||||||
return result
|
return result, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileType string // @name FileType
|
type FileType string // @name FileType
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/utils"
|
"github.com/yusing/godoxy/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListFilesResponse struct {
|
type ListFilesResponse struct {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SetFileContentRequest GetFileContentRequest
|
type SetFileContentRequest GetFileContentRequest
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
config "github.com/yusing/godoxy/internal/config/types"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/net/gphttp/middleware"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/middleware"
|
"github.com/yusing/godoxy/internal/route/provider"
|
||||||
"github.com/yusing/go-proxy/internal/route/provider"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ValidateFileRequest struct {
|
type ValidateFileRequest struct {
|
||||||
@@ -57,7 +57,7 @@ func validateFile(fileType FileType, content []byte) gperr.Error {
|
|||||||
return config.Validate(content)
|
return config.Validate(content)
|
||||||
case FileTypeMiddleware:
|
case FileTypeMiddleware:
|
||||||
errs := gperr.NewBuilder("middleware errors")
|
errs := gperr.NewBuilder("middleware errors")
|
||||||
middleware.BuildMiddlewaresFromYAML("", content, errs)
|
middleware.BuildMiddlewaresFromYAML("", content, &errs)
|
||||||
return errs.Error()
|
return errs.Error()
|
||||||
}
|
}
|
||||||
return provider.Validate(content)
|
return provider.Validate(content)
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
"github.com/yusing/godoxy/internal/route/routes"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
"github.com/yusing/goutils/http/httpheaders"
|
||||||
"github.com/yusing/go-proxy/internal/route/routes"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HealthMap = map[string]routes.HealthInfo // @name HealthMap
|
type HealthMap = map[string]routes.HealthInfo // @name HealthMap
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/homepage"
|
"github.com/yusing/godoxy/internal/homepage"
|
||||||
"github.com/yusing/go-proxy/internal/route/routes"
|
"github.com/yusing/godoxy/internal/route/routes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "categories"
|
// @x-id "categories"
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/homepage"
|
"github.com/yusing/godoxy/internal/homepage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HomepageOverrideItemClickParams struct {
|
type HomepageOverrideItemClickParams struct {
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/lithammer/fuzzysearch/fuzzy"
|
"github.com/lithammer/fuzzysearch/fuzzy"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/homepage"
|
"github.com/yusing/godoxy/internal/homepage"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
"github.com/yusing/godoxy/internal/route/routes"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
"github.com/yusing/goutils/http/httpheaders"
|
||||||
"github.com/yusing/go-proxy/internal/route/routes"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HomepageItemsRequest struct {
|
type HomepageItemsRequest struct {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/homepage"
|
"github.com/yusing/godoxy/internal/homepage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/homepage"
|
"github.com/yusing/godoxy/internal/homepage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListIconsRequest struct {
|
type ListIconsRequest struct {
|
||||||
|
|||||||
@@ -10,16 +10,17 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/metrics/period"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/period"
|
"github.com/yusing/godoxy/internal/metrics/systeminfo"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/systeminfo"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
"github.com/yusing/goutils/http/httpheaders"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
"github.com/yusing/go-proxy/internal/utils/synk"
|
"github.com/yusing/goutils/synk"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -256,7 +257,7 @@ func marshalSystemInfo(ws *websocket.Manager, agentName string, systemInfo any)
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf := bytes.NewBuffer(bytesBuf)
|
buf := bytes.NewBuffer(bytesBuf)
|
||||||
err := json.NewEncoder(buf).Encode(map[string]any{
|
err := sonic.ConfigDefault.NewEncoder(buf).Encode(map[string]any{
|
||||||
agentName: systemInfo,
|
agentName: systemInfo,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
agentPkg "github.com/yusing/go-proxy/agent/pkg/agent"
|
agentPkg "github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/period"
|
"github.com/yusing/godoxy/internal/metrics/period"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/systeminfo"
|
"github.com/yusing/godoxy/internal/metrics/systeminfo"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
"github.com/yusing/goutils/http/httpheaders"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SystemInfoRequest struct {
|
type SystemInfoRequest struct {
|
||||||
@@ -46,6 +46,7 @@ func SystemInfo(c *gin.Context) {
|
|||||||
systeminfo.Poller.ServeHTTP(c)
|
systeminfo.Poller.ServeHTTP(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
c.Request.URL.RawQuery = query.Encode()
|
||||||
|
|
||||||
agent, ok := agentPkg.GetAgent(agentAddr)
|
agent, ok := agentPkg.GetAgent(agentAddr)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -69,10 +70,6 @@ func SystemInfo(c *gin.Context) {
|
|||||||
c.Status(resp.StatusCode)
|
c.Status(resp.StatusCode)
|
||||||
io.Copy(c.Writer, resp.Body)
|
io.Copy(c.Writer, resp.Body)
|
||||||
} else {
|
} else {
|
||||||
err := agent.ReverseProxy(c.Writer, c.Request, agentPkg.EndpointSystemInfo+"?"+query.Encode())
|
agent.ReverseProxy(c.Writer, c.Request, agentPkg.EndpointSystemInfo)
|
||||||
if err != nil {
|
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to reverse proxy"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package metrics
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/period"
|
"github.com/yusing/godoxy/internal/metrics/period"
|
||||||
"github.com/yusing/go-proxy/internal/metrics/uptime"
|
"github.com/yusing/godoxy/internal/metrics/uptime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UptimeRequest struct {
|
type UptimeRequest struct {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
"github.com/yusing/godoxy/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "reload"
|
// @x-id "reload"
|
||||||
@@ -20,7 +20,7 @@ import (
|
|||||||
// @Failure 500 {object} apitypes.ErrorResponse
|
// @Failure 500 {object} apitypes.ErrorResponse
|
||||||
// @Router /reload [post]
|
// @Router /reload [post]
|
||||||
func Reload(c *gin.Context) {
|
func Reload(c *gin.Context) {
|
||||||
if err := config.GetInstance().Reload(); err != nil {
|
if err := config.Reload(); err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to reload config"))
|
c.Error(apitypes.InternalServerError(err, "failed to reload config"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/route"
|
"github.com/yusing/godoxy/internal/route"
|
||||||
"github.com/yusing/go-proxy/internal/route/routes"
|
"github.com/yusing/godoxy/internal/route/routes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RoutesByProvider map[string][]route.Route
|
type RoutesByProvider map[string][]route.Route
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
statequery "github.com/yusing/godoxy/internal/config/query"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
"github.com/yusing/goutils/http/httpheaders"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "providers"
|
// @x-id "providers"
|
||||||
@@ -22,12 +22,11 @@ import (
|
|||||||
// @Failure 500 {object} apitypes.ErrorResponse
|
// @Failure 500 {object} apitypes.ErrorResponse
|
||||||
// @Router /route/providers [get]
|
// @Router /route/providers [get]
|
||||||
func Providers(c *gin.Context) {
|
func Providers(c *gin.Context) {
|
||||||
cfg := config.GetInstance()
|
|
||||||
if httpheaders.IsWebsocket(c.Request.Header) {
|
if httpheaders.IsWebsocket(c.Request.Header) {
|
||||||
websocket.PeriodicWrite(c, 5*time.Second, func() (any, error) {
|
websocket.PeriodicWrite(c, 5*time.Second, func() (any, error) {
|
||||||
return config.GetInstance().RouteProviderList(), nil
|
return statequery.RouteProviderList(), nil
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
c.JSON(http.StatusOK, cfg.RouteProviderList())
|
c.JSON(http.StatusOK, statequery.RouteProviderList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apitypes "github.com/yusing/go-proxy/internal/api/types"
|
apitypes "github.com/yusing/godoxy/internal/api/types"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
statequery "github.com/yusing/godoxy/internal/config/query"
|
||||||
"github.com/yusing/go-proxy/internal/route/routes"
|
"github.com/yusing/godoxy/internal/route/routes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListRouteRequest struct {
|
type ListRouteRequest struct {
|
||||||
@@ -40,7 +40,7 @@ func Route(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// also search for excluded routes
|
// also search for excluded routes
|
||||||
route = config.GetInstance().SearchRoute(request.Which)
|
route = statequery.SearchRoute(request.Which)
|
||||||
if route != nil {
|
if route != nil {
|
||||||
c.JSON(http.StatusOK, route)
|
c.JSON(http.StatusOK, route)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
"github.com/yusing/godoxy/internal/route"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
"github.com/yusing/godoxy/internal/route/routes"
|
||||||
"github.com/yusing/go-proxy/internal/route"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
"github.com/yusing/go-proxy/internal/route/routes"
|
"github.com/yusing/goutils/http/httpheaders"
|
||||||
"github.com/yusing/go-proxy/internal/types"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RouteType route.Route // @name Route
|
type RouteType route.Route // @name Route
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
statequery "github.com/yusing/godoxy/internal/config/query"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp/websocket"
|
"github.com/yusing/goutils/http/httpheaders"
|
||||||
"github.com/yusing/go-proxy/internal/types"
|
"github.com/yusing/goutils/http/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StatsResponse struct {
|
type StatsResponse struct {
|
||||||
@@ -35,10 +35,9 @@ type ProxyStats struct {
|
|||||||
// @Failure 500 {object} apitypes.ErrorResponse
|
// @Failure 500 {object} apitypes.ErrorResponse
|
||||||
// @Router /stats [get]
|
// @Router /stats [get]
|
||||||
func Stats(c *gin.Context) {
|
func Stats(c *gin.Context) {
|
||||||
cfg := config.GetInstance()
|
|
||||||
getStats := func() (any, error) {
|
getStats := func() (any, error) {
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"proxies": cfg.Statistics(),
|
"proxies": statequery.GetStatistics(),
|
||||||
"uptime": int64(time.Since(startTime).Round(time.Second).Seconds()),
|
"uptime": int64(time.Since(startTime).Round(time.Second).Seconds()),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yusing/go-proxy/pkg"
|
"github.com/yusing/goutils/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @x-id "version"
|
// @x-id "version"
|
||||||
@@ -17,5 +17,5 @@ import (
|
|||||||
// @Success 200 {string} string "version"
|
// @Success 200 {string} string "version"
|
||||||
// @Router /version [get]
|
// @Router /version [get]
|
||||||
func Version(c *gin.Context) {
|
func Version(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, pkg.GetVersion().String())
|
c.JSON(http.StatusOK, version.Get().String())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package auth
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultAuth Provider
|
var defaultAuth Provider
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import (
|
|||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/jsonstore"
|
"github.com/yusing/godoxy/internal/jsonstore"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ import (
|
|||||||
|
|
||||||
"github.com/coreos/go-oidc/v3/oidc"
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/utils"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/go-proxy/internal/utils"
|
httputils "github.com/yusing/goutils/http"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
)
|
)
|
||||||
@@ -317,20 +317,23 @@ func (auth *OIDCProvider) PostAuthCallbackHandler(w http.ResponseWriter, r *http
|
|||||||
code := r.URL.Query().Get("code")
|
code := r.URL.Query().Get("code")
|
||||||
oauth2Token, err := auth.oauthConfig.Exchange(r.Context(), code, optRedirectPostAuth(r))
|
oauth2Token, err := auth.oauthConfig.Exchange(r.Context(), code, optRedirectPostAuth(r))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gphttp.ServerError(w, r, fmt.Errorf("failed to exchange token: %w", err))
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||||
|
httputils.LogError(r).Msg(fmt.Sprintf("failed to exchange token: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
idTokenJWT, idToken, err := auth.getIDToken(r.Context(), oauth2Token)
|
idTokenJWT, idToken, err := auth.getIDToken(r.Context(), oauth2Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gphttp.ServerError(w, r, err)
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||||
|
httputils.LogError(r).Msg(fmt.Sprintf("failed to get ID token: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if oauth2Token.RefreshToken != "" {
|
if oauth2Token.RefreshToken != "" {
|
||||||
claims, err := parseClaims(idToken)
|
claims, err := parseClaims(idToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gphttp.ServerError(w, r, err)
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||||
|
httputils.LogError(r).Msg(fmt.Sprintf("failed to parse claims: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session := newSession(claims.Username, claims.Groups)
|
session := newSession(claims.Username, claims.Groups)
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
|
|
||||||
"github.com/coreos/go-oidc/v3/oidc"
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
. "github.com/yusing/go-proxy/internal/utils/testing"
|
expect "github.com/yusing/goutils/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// setupMockOIDC configures mock OIDC provider for testing.
|
// setupMockOIDC configures mock OIDC provider for testing.
|
||||||
@@ -35,7 +35,7 @@ func setupMockOIDC(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
|
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
|
||||||
},
|
},
|
||||||
endSessionURL: Must(url.Parse("http://mock-provider/logout")),
|
endSessionURL: expect.Must(url.Parse("http://mock-provider/logout")),
|
||||||
oidcProvider: provider,
|
oidcProvider: provider,
|
||||||
oidcVerifier: provider.Verifier(&oidc.Config{
|
oidcVerifier: provider.Verifier(&oidc.Config{
|
||||||
ClientID: "test-client",
|
ClientID: "test-client",
|
||||||
@@ -75,7 +75,7 @@ func (j *provider) SignClaims(t *testing.T, claims jwt.Claims) string {
|
|||||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||||
token.Header["kid"] = keyID
|
token.Header["kid"] = keyID
|
||||||
signed, err := token.SignedString(j.key)
|
signed, err := token.SignedString(j.key)
|
||||||
ExpectNoError(t, err)
|
expect.NoError(t, err)
|
||||||
return signed
|
return signed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ func setupProvider(t *testing.T) *provider {
|
|||||||
|
|
||||||
// Generate an RSA key pair for the test.
|
// Generate an RSA key pair for the test.
|
||||||
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
ExpectNoError(t, err)
|
expect.NoError(t, err)
|
||||||
|
|
||||||
// Build the matching public JWK that will be served by the endpoint.
|
// Build the matching public JWK that will be served by the endpoint.
|
||||||
jwk := buildRSAJWK(t, &privKey.PublicKey, keyID)
|
jwk := buildRSAJWK(t, &privKey.PublicKey, keyID)
|
||||||
@@ -227,12 +227,12 @@ func TestOIDCCallbackHandler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if tt.wantStatus == http.StatusTemporaryRedirect {
|
if tt.wantStatus == http.StatusTemporaryRedirect {
|
||||||
setCookie := Must(http.ParseSetCookie(w.Header().Get("Set-Cookie")))
|
setCookie := expect.Must(http.ParseSetCookie(w.Header().Get("Set-Cookie")))
|
||||||
ExpectEqual(t, setCookie.Name, CookieOauthToken)
|
expect.Equal(t, setCookie.Name, CookieOauthToken)
|
||||||
ExpectTrue(t, setCookie.Value != "")
|
expect.True(t, setCookie.Value != "")
|
||||||
ExpectEqual(t, setCookie.Path, "/")
|
expect.Equal(t, setCookie.Path, "/")
|
||||||
ExpectEqual(t, setCookie.SameSite, http.SameSiteLaxMode)
|
expect.Equal(t, setCookie.SameSite, http.SameSiteLaxMode)
|
||||||
ExpectEqual(t, setCookie.HttpOnly, true)
|
expect.Equal(t, setCookie.HttpOnly, true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -245,7 +245,7 @@ func TestInitOIDC(t *testing.T) {
|
|||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
ExpectNoError(t, json.NewEncoder(w).Encode(discoveryDocument(t, server)))
|
expect.NoError(t, json.NewEncoder(w).Encode(discoveryDocument(t, server)))
|
||||||
})
|
})
|
||||||
server = httptest.NewServer(mux)
|
server = httptest.NewServer(mux)
|
||||||
t.Cleanup(server.Close)
|
t.Cleanup(server.Close)
|
||||||
@@ -445,9 +445,9 @@ func TestCheckToken(t *testing.T) {
|
|||||||
// Call CheckToken and verify the result.
|
// Call CheckToken and verify the result.
|
||||||
err := auth.CheckToken(req)
|
err := auth.CheckToken(req)
|
||||||
if tc.wantErr == nil {
|
if tc.wantErr == nil {
|
||||||
ExpectNoError(t, err)
|
expect.NoError(t, err)
|
||||||
} else {
|
} else {
|
||||||
ExpectError(t, tc.wantErr, err)
|
expect.ErrorIs(t, tc.wantErr, err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp"
|
httputils "github.com/yusing/goutils/http"
|
||||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ type UserPassAuthCallbackRequest struct {
|
|||||||
|
|
||||||
func (auth *UserPassAuth) PostAuthCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
func (auth *UserPassAuth) PostAuthCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var creds UserPassAuthCallbackRequest
|
var creds UserPassAuthCallbackRequest
|
||||||
err := json.NewDecoder(r.Body).Decode(&creds)
|
err := sonic.ConfigDefault.NewDecoder(r.Body).Decode(&creds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "invalid request", http.StatusBadRequest)
|
http.Error(w, "invalid request", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -121,7 +121,8 @@ func (auth *UserPassAuth) PostAuthCallbackHandler(w http.ResponseWriter, r *http
|
|||||||
}
|
}
|
||||||
token, err := auth.NewToken()
|
token, err := auth.NewToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gphttp.ServerError(w, r, err)
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||||
|
httputils.LogError(r).Msg(fmt.Sprintf("failed to generate token: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
SetTokenCookie(w, r, auth.TokenCookieName(), token, auth.tokenTTL)
|
SetTokenCookie(w, r, auth.TokenCookieName(), token, auth.tokenTTL)
|
||||||
@@ -129,8 +130,7 @@ func (auth *UserPassAuth) PostAuthCallbackHandler(w http.ResponseWriter, r *http
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (auth *UserPassAuth) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
func (auth *UserPassAuth) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("X-Redirect-To", "/login")
|
http.Redirect(w, r, "/login", http.StatusFound)
|
||||||
w.WriteHeader(http.StatusForbidden)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (auth *UserPassAuth) LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
func (auth *UserPassAuth) LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "github.com/yusing/go-proxy/internal/utils/testing"
|
expect "github.com/yusing/goutils/testing"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newMockUserPassAuth() *UserPassAuth {
|
func newMockUserPassAuth() *UserPassAuth {
|
||||||
return &UserPassAuth{
|
return &UserPassAuth{
|
||||||
username: "username",
|
username: "username",
|
||||||
pwdHash: Must(bcrypt.GenerateFromPassword([]byte("password"), bcrypt.DefaultCost)),
|
pwdHash: expect.Must(bcrypt.GenerateFromPassword([]byte("password"), bcrypt.DefaultCost)),
|
||||||
secret: []byte("abcdefghijklmnopqrstuvwxyz"),
|
secret: []byte("abcdefghijklmnopqrstuvwxyz"),
|
||||||
tokenTTL: time.Hour,
|
tokenTTL: time.Hour,
|
||||||
}
|
}
|
||||||
@@ -25,17 +25,17 @@ func newMockUserPassAuth() *UserPassAuth {
|
|||||||
func TestUserPassValidateCredentials(t *testing.T) {
|
func TestUserPassValidateCredentials(t *testing.T) {
|
||||||
auth := newMockUserPassAuth()
|
auth := newMockUserPassAuth()
|
||||||
err := auth.validatePassword("username", "password")
|
err := auth.validatePassword("username", "password")
|
||||||
ExpectNoError(t, err)
|
expect.NoError(t, err)
|
||||||
err = auth.validatePassword("username", "wrong-password")
|
err = auth.validatePassword("username", "wrong-password")
|
||||||
ExpectError(t, ErrInvalidPassword, err)
|
expect.ErrorIs(t, ErrInvalidPassword, err)
|
||||||
err = auth.validatePassword("wrong-username", "password")
|
err = auth.validatePassword("wrong-username", "password")
|
||||||
ExpectError(t, ErrInvalidUsername, err)
|
expect.ErrorIs(t, ErrInvalidUsername, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserPassCheckToken(t *testing.T) {
|
func TestUserPassCheckToken(t *testing.T) {
|
||||||
auth := newMockUserPassAuth()
|
auth := newMockUserPassAuth()
|
||||||
token, err := auth.NewToken()
|
token, err := auth.NewToken()
|
||||||
ExpectNoError(t, err)
|
expect.NoError(t, err)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
token string
|
token string
|
||||||
wantErr bool
|
wantErr bool
|
||||||
@@ -60,9 +60,9 @@ func TestUserPassCheckToken(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err = auth.CheckToken(req)
|
err = auth.CheckToken(req)
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
ExpectTrue(t, err != nil)
|
expect.True(t, err != nil)
|
||||||
} else {
|
} else {
|
||||||
ExpectNoError(t, err)
|
expect.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,20 +96,20 @@ func TestUserPassLoginCallbackHandler(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req := &http.Request{
|
req := &http.Request{
|
||||||
Host: "app.example.com",
|
Host: "app.example.com",
|
||||||
Body: io.NopCloser(bytes.NewReader(Must(json.Marshal(tt.creds)))),
|
Body: io.NopCloser(bytes.NewReader(expect.Must(json.Marshal(tt.creds)))),
|
||||||
}
|
}
|
||||||
auth.PostAuthCallbackHandler(w, req)
|
auth.PostAuthCallbackHandler(w, req)
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
ExpectEqual(t, w.Code, http.StatusUnauthorized)
|
expect.Equal(t, w.Code, http.StatusUnauthorized)
|
||||||
} else {
|
} else {
|
||||||
setCookie := Must(http.ParseSetCookie(w.Header().Get("Set-Cookie")))
|
setCookie := expect.Must(http.ParseSetCookie(w.Header().Get("Set-Cookie")))
|
||||||
ExpectTrue(t, setCookie.Name == auth.TokenCookieName())
|
expect.True(t, setCookie.Name == auth.TokenCookieName())
|
||||||
ExpectTrue(t, setCookie.Value != "")
|
expect.True(t, setCookie.Value != "")
|
||||||
ExpectEqual(t, setCookie.Domain, "example.com")
|
expect.Equal(t, setCookie.Domain, "example.com")
|
||||||
ExpectEqual(t, setCookie.Path, "/")
|
expect.Equal(t, setCookie.Path, "/")
|
||||||
ExpectEqual(t, setCookie.SameSite, http.SameSiteLaxMode)
|
expect.Equal(t, setCookie.SameSite, http.SameSiteLaxMode)
|
||||||
ExpectEqual(t, setCookie.HttpOnly, true)
|
expect.Equal(t, setCookie.HttpOnly, true)
|
||||||
ExpectEqual(t, w.Code, http.StatusOK)
|
expect.Equal(t, w.Code, http.StatusOK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ import (
|
|||||||
|
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||||
"github.com/go-acme/lego/v4/lego"
|
"github.com/go-acme/lego/v4/lego"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/utils"
|
||||||
"github.com/yusing/go-proxy/internal/utils"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -27,6 +28,8 @@ type Config struct {
|
|||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
Options map[string]any `json:"options,omitempty"`
|
Options map[string]any `json:"options,omitempty"`
|
||||||
|
|
||||||
|
Resolvers []string `json:"resolvers,omitempty"`
|
||||||
|
|
||||||
// Custom ACME CA
|
// Custom ACME CA
|
||||||
CADirURL string `json:"ca_dir_url,omitempty"`
|
CADirURL string `json:"ca_dir_url,omitempty"`
|
||||||
CACerts []string `json:"ca_certs,omitempty"`
|
CACerts []string `json:"ca_certs,omitempty"`
|
||||||
@@ -111,6 +114,12 @@ func (cfg *Config) Validate() gperr.Error {
|
|||||||
return b.Error()
|
return b.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) dns01Options() []dns01.ChallengeOption {
|
||||||
|
return []dns01.ChallengeOption{
|
||||||
|
dns01.CondOption(len(cfg.Resolvers) > 0, dns01.AddRecursiveNameservers(cfg.Resolvers)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (cfg *Config) GetLegoConfig() (*User, *lego.Config, gperr.Error) {
|
func (cfg *Config) GetLegoConfig() (*User, *lego.Config, gperr.Error) {
|
||||||
if err := cfg.Validate(); err != nil {
|
if err := cfg.Validate(); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/internal/serialization"
|
"github.com/yusing/godoxy/internal/serialization"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEABConfigRequired(t *testing.T) {
|
func TestEABConfigRequired(t *testing.T) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/certificate"
|
"github.com/go-acme/lego/v4/certificate"
|
||||||
@@ -17,11 +18,11 @@ import (
|
|||||||
"github.com/go-acme/lego/v4/registration"
|
"github.com/go-acme/lego/v4/registration"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/notif"
|
||||||
"github.com/yusing/go-proxy/internal/notif"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/go-proxy/internal/task"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
"github.com/yusing/goutils/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -49,6 +50,9 @@ const (
|
|||||||
requestCooldownDuration = 15 * time.Second
|
requestCooldownDuration = 15 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// could be nil
|
||||||
|
var ActiveProvider atomic.Pointer[Provider]
|
||||||
|
|
||||||
func NewProvider(cfg *Config, user *User, legoCfg *lego.Config) *Provider {
|
func NewProvider(cfg *Config, user *User, legoCfg *lego.Config) *Provider {
|
||||||
return &Provider{
|
return &Provider{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
@@ -286,7 +290,7 @@ func (p *Provider) initClient() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = legoClient.Challenge.SetDNS01Provider(p.cfg.challengeProvider)
|
err = legoClient.Challenge.SetDNS01Provider(p.cfg.challengeProvider, p.cfg.dns01Options()...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/yusing/go-proxy/internal/autocert"
|
"github.com/yusing/godoxy/internal/autocert"
|
||||||
"github.com/yusing/go-proxy/internal/dnsproviders"
|
"github.com/yusing/godoxy/internal/dnsproviders"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"github.com/go-acme/lego/v4/providers/dns/ovh"
|
"github.com/go-acme/lego/v4/providers/dns/ovh"
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/yusing/go-proxy/internal/serialization"
|
"github.com/yusing/godoxy/internal/serialization"
|
||||||
)
|
)
|
||||||
|
|
||||||
// type Config struct {
|
// type Config struct {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package autocert
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
"github.com/yusing/godoxy/internal/serialization"
|
||||||
"github.com/yusing/go-proxy/internal/serialization"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Generator func(map[string]any) (challenge.Provider, gperr.Error)
|
type Generator func(map[string]any) (challenge.Provider, gperr.Error)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Provider) Setup() (err error) {
|
func (p *Provider) Setup() (err error) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package autocert
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/internal/task"
|
"github.com/yusing/goutils/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
const (
|
|
||||||
CommandStart = ""
|
|
||||||
CommandValidate = "validate"
|
|
||||||
CommandListConfigs = "ls-config"
|
|
||||||
CommandListRoutes = "ls-routes"
|
|
||||||
CommandListIcons = "ls-icons"
|
|
||||||
CommandReload = "reload"
|
|
||||||
CommandDebugListEntries = "debug-ls-entries"
|
|
||||||
CommandDebugListProviders = "debug-ls-providers"
|
|
||||||
CommandDebugListMTrace = "debug-ls-mtrace"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MainServerCommandValidator struct{}
|
|
||||||
|
|
||||||
func (v MainServerCommandValidator) IsCommandValid(cmd string) bool {
|
|
||||||
switch cmd {
|
|
||||||
case CommandStart,
|
|
||||||
CommandValidate,
|
|
||||||
CommandListConfigs,
|
|
||||||
CommandListRoutes,
|
|
||||||
CommandListIcons,
|
|
||||||
CommandReload,
|
|
||||||
CommandDebugListEntries,
|
|
||||||
CommandDebugListProviders,
|
|
||||||
CommandDebugListMTrace:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user