Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbfc7c0d6d | ||
|
|
5af898b3e6 | ||
|
|
3c162bf9d7 | ||
|
|
1eed79463d | ||
|
|
6f67f6f5b4 | ||
|
|
2a5570a447 |
20
.github/workflows/build-dev.yml
vendored
20
.github/workflows/build-dev.yml
vendored
@@ -21,31 +21,35 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Load VERSION
|
- name: 加载版本号
|
||||||
run: |
|
run: |
|
||||||
if [ -f DEV-VERSION ]; then
|
if [ -f DEV-VERSION ]; then
|
||||||
echo "VERSION=$(cat DEV-VERSION)" >> $GITHUB_ENV
|
echo "VERSION=$(cat DEV-VERSION)" >> $GITHUB_ENV
|
||||||
else
|
else
|
||||||
echo "DEV-VERSION file not found!" && exit 1
|
echo "DEV-VERSION file not found!" && exit 1
|
||||||
fi
|
fi
|
||||||
- name: Set up Go
|
- name: 安装 Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
- name: Install UPX
|
- name: 安装UPX
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install upx -y
|
sudo apt install upx -y
|
||||||
- name: Build
|
- name: 编译
|
||||||
env:
|
env:
|
||||||
GOOS: ${{ matrix.goos }}
|
GOOS: ${{ matrix.goos }}
|
||||||
GOARCH: ${{ matrix.goarch }}
|
GOARCH: ${{ matrix.goarch }}
|
||||||
run: |
|
run: |
|
||||||
CGO_ENABLED=0 go build -o ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}} ./main.go
|
CGO_ENABLED=0 go build -ldflags "-X main.version=${{ env.VERSION }}" -o ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}} ./main.go
|
||||||
upx -9 ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}
|
upx -9 ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}
|
||||||
- name: Package
|
- name: 打包
|
||||||
run: |
|
run: |
|
||||||
tar -czvf ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}.tar.gz ./${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}
|
mkdir ghproxyd
|
||||||
|
cp ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}} ./ghproxyd/
|
||||||
|
cp LICENSE ./ghproxyd/
|
||||||
|
tar -czf ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}.tar.gz -C ghproxyd .
|
||||||
|
ls
|
||||||
- name: Upload to GitHub Artifacts
|
- name: Upload to GitHub Artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
@@ -57,7 +61,7 @@ jobs:
|
|||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
name: ${{ env.VERSION }}
|
name: ${{ env.VERSION }}
|
||||||
artifacts: ./${{ env.OUTPUT_BINARY }}*
|
artifacts: ./${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}.tar.gz
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag: ${{ env.VERSION }}
|
tag: ${{ env.VERSION }}
|
||||||
allowUpdates: true
|
allowUpdates: true
|
||||||
|
|||||||
45
.github/workflows/build.yml
vendored
45
.github/workflows/build.yml
vendored
@@ -62,7 +62,8 @@ jobs:
|
|||||||
tag: ${{ env.VERSION }}
|
tag: ${{ env.VERSION }}
|
||||||
allowUpdates: true
|
allowUpdates: true
|
||||||
env:
|
env:
|
||||||
export PATH: $PATH:/usr/local/go/bin
|
export PATH: $PATH:/usr/local/go/bin
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build # 确保这个作业在 build 作业完成后运行
|
needs: build # 确保这个作业在 build 作业完成后运行
|
||||||
@@ -102,3 +103,45 @@ jobs:
|
|||||||
tags: |
|
tags: |
|
||||||
${{ env.IMAGE_NAME }}:${{ env.VERSION }}
|
${{ env.IMAGE_NAME }}:${{ env.VERSION }}
|
||||||
${{ env.IMAGE_NAME }}:latest
|
${{ env.IMAGE_NAME }}:latest
|
||||||
|
|
||||||
|
docker-nocache:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build # 确保这个作业在 build 作业完成后运行
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: wjqserver/ghproxy # 定义镜像名称变量
|
||||||
|
DOCKERFILE: docker/dockerfile/nocache/Dockerfile # 定义 Dockerfile 路径变量
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Load VERSION
|
||||||
|
run: |
|
||||||
|
if [ -f VERSION ]; then
|
||||||
|
echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "VERSION file not found!" && exit 1
|
||||||
|
fi
|
||||||
|
- name: Wait for Compile
|
||||||
|
run: sleep 300s
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: 构建镜像
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
file: ./${{ env.DOCKERFILE }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
${{ env.IMAGE_NAME }}:${{ env.VERSION }}-nocache
|
||||||
|
${{ env.IMAGE_NAME }}:nocache
|
||||||
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,5 +1,25 @@
|
|||||||
# 更新日志
|
# 更新日志
|
||||||
|
|
||||||
|
24w21c
|
||||||
|
---
|
||||||
|
- PRE-RELEASE: 此版本是v1.7.0的预发布版本,请勿在生产环境中使用
|
||||||
|
- CHANGE: 对编译打包进行改进,此后不再提供独立可执行文件,请改为拉取`tar.gz`压缩包
|
||||||
|
- CHANGE: 由于上述原因,对Docker打包进行相应改进
|
||||||
|
|
||||||
|
24w21b
|
||||||
|
---
|
||||||
|
- PRE-RELEASE: 此版本是v1.7.0的预发布版本,请勿在生产环境中使用
|
||||||
|
- ADD: 加入版本号标识与对应API接口
|
||||||
|
- ADD: 加入速率限制API接口
|
||||||
|
- CHANGE: 修改打包部分
|
||||||
|
|
||||||
|
24w21a
|
||||||
|
---
|
||||||
|
- PRE-RELEASE: 此版本是v1.7.0的预发布版本,请勿在生产环境中使用
|
||||||
|
- ADD: 尝试加入程序内置速率限制
|
||||||
|
- CHANGE: 更新相关依赖库
|
||||||
|
- CHANGE: 更换Dev版本底包,于release版本保持一致
|
||||||
|
|
||||||
v1.6.2
|
v1.6.2
|
||||||
---
|
---
|
||||||
- CHANGE: 优化前端界面,优化部分样式
|
- CHANGE: 优化前端界面,优化部分样式
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
24w20b
|
24w21c
|
||||||
26
api/api.go
26
api/api.go
@@ -13,7 +13,6 @@ var (
|
|||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
)
|
)
|
||||||
|
|
||||||
// 日志模块
|
|
||||||
var (
|
var (
|
||||||
logw = logger.Logw
|
logw = logger.Logw
|
||||||
logInfo = logger.LogInfo
|
logInfo = logger.LogInfo
|
||||||
@@ -21,8 +20,7 @@ var (
|
|||||||
logError = logger.LogError
|
logError = logger.LogError
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitHandleRouter(cfg *config.Config, router *gin.Engine) {
|
func InitHandleRouter(cfg *config.Config, router *gin.Engine, version string) {
|
||||||
// 设置路由
|
|
||||||
apiRouter := router.Group("api")
|
apiRouter := router.Group("api")
|
||||||
{
|
{
|
||||||
apiRouter.GET("/size_limit", func(c *gin.Context) {
|
apiRouter.GET("/size_limit", func(c *gin.Context) {
|
||||||
@@ -40,6 +38,12 @@ func InitHandleRouter(cfg *config.Config, router *gin.Engine) {
|
|||||||
apiRouter.GET("/healthcheck", func(c *gin.Context) {
|
apiRouter.GET("/healthcheck", func(c *gin.Context) {
|
||||||
HealthcheckHandler(c)
|
HealthcheckHandler(c)
|
||||||
})
|
})
|
||||||
|
apiRouter.GET("/version", func(c *gin.Context) {
|
||||||
|
VersionHandler(c, version)
|
||||||
|
})
|
||||||
|
apiRouter.GET("/rate_limit/status", func(c *gin.Context) {
|
||||||
|
RateLimitStatusHandler(c, cfg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
logInfo("API router Init success")
|
logInfo("API router Init success")
|
||||||
}
|
}
|
||||||
@@ -84,3 +88,19 @@ func HealthcheckHandler(c *gin.Context) {
|
|||||||
"Status": "OK",
|
"Status": "OK",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func VersionHandler(c *gin.Context, version string) {
|
||||||
|
logInfo("%s %s %s %s %s", c.ClientIP(), c.Request.Method, c.Request.URL.Path, c.Request.UserAgent(), c.Request.Proto)
|
||||||
|
c.Writer.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
|
||||||
|
"Version": version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func RateLimitStatusHandler(c *gin.Context, cfg *config.Config) {
|
||||||
|
logInfo("%s %s %s %s %s", c.ClientIP(), c.Request.Method, c.Request.URL.Path, c.Request.UserAgent(), c.Request.Proto)
|
||||||
|
c.Writer.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
|
||||||
|
"RateLimit": cfg.RateLimit.Enabled,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ type Config struct {
|
|||||||
Auth AuthConfig
|
Auth AuthConfig
|
||||||
Blacklist BlacklistConfig
|
Blacklist BlacklistConfig
|
||||||
Whitelist WhitelistConfig
|
Whitelist WhitelistConfig
|
||||||
|
RateLimit RateLimitConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
@@ -49,6 +50,12 @@ type WhitelistConfig struct {
|
|||||||
WhitelistFile string `toml:"whitelistFile"`
|
WhitelistFile string `toml:"whitelistFile"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RateLimitConfig struct {
|
||||||
|
Enabled bool `toml:"enabled"`
|
||||||
|
RatePerMinute int `toml:"ratePerMinute"`
|
||||||
|
Burst int `toml:"burst"`
|
||||||
|
}
|
||||||
|
|
||||||
// LoadConfig 从 TOML 配置文件加载配置
|
// LoadConfig 从 TOML 配置文件加载配置
|
||||||
func LoadConfig(filePath string) (*Config, error) {
|
func LoadConfig(filePath string) (*Config, error) {
|
||||||
var config Config
|
var config Config
|
||||||
|
|||||||
@@ -25,3 +25,8 @@ enabled = false
|
|||||||
[whitelist]
|
[whitelist]
|
||||||
enabled = false
|
enabled = false
|
||||||
whitelistFile = "/data/ghproxy/config/whitelist.json"
|
whitelistFile = "/data/ghproxy/config/whitelist.json"
|
||||||
|
|
||||||
|
[rateLimit]
|
||||||
|
enabled = false
|
||||||
|
ratePerMinute = 100
|
||||||
|
burst = 10
|
||||||
|
|||||||
@@ -96,7 +96,9 @@ VERSION=$(curl -s https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/mai
|
|||||||
wget -q -O ${ghproxy_dir}/VERSION https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/DEV-VERSION
|
wget -q -O ${ghproxy_dir}/VERSION https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/DEV-VERSION
|
||||||
|
|
||||||
# 下载ghproxy
|
# 下载ghproxy
|
||||||
wget -q -O ${ghproxy_dir}/ghproxy https://github.com/WJQSERVER-STUDIO/ghproxy/releases/download/$VERSION/ghproxy-linux-$ARCH
|
wget -q -O ${ghproxy_dir}/ghproxy https://github.com/WJQSERVER-STUDIO/ghproxy/releases/download/$VERSION/ghproxy-linux-$ARCH.tar.gz
|
||||||
|
install tar
|
||||||
|
tar -zxvf ${ghproxy_dir}/ghproxy-linux-$ARCH.tar.gz -C ${ghproxy_dir}
|
||||||
chmod +x ${ghproxy_dir}/ghproxy
|
chmod +x ${ghproxy_dir}/ghproxy
|
||||||
|
|
||||||
# 下载pages
|
# 下载pages
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM wjqserver/caddy:daily-alpine AS builder
|
FROM wjqserver/caddy:2.9.0-rc-alpine AS builder
|
||||||
|
|
||||||
ARG USER=WJQSERVER-STUDIO
|
ARG USER=WJQSERVER-STUDIO
|
||||||
ARG REPO=ghproxy
|
ARG REPO=ghproxy
|
||||||
@@ -13,7 +13,7 @@ RUN mkdir -p /data/${APPLICATION}/config
|
|||||||
RUN mkdir -p /data/${APPLICATION}/log
|
RUN mkdir -p /data/${APPLICATION}/log
|
||||||
|
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
RUN apk add --no-cache curl wget
|
RUN apk add --no-cache curl wget tar
|
||||||
|
|
||||||
# 前端
|
# 前端
|
||||||
RUN wget -O /data/www/index.html https://raw.githubusercontent.com/${USER}/${REPO}/main/pages/index.html
|
RUN wget -O /data/www/index.html https://raw.githubusercontent.com/${USER}/${REPO}/main/pages/index.html
|
||||||
@@ -21,7 +21,9 @@ RUN wget -O /data/www/favicon.ico https://raw.githubusercontent.com/${USER}/${RE
|
|||||||
|
|
||||||
# 后端
|
# 后端
|
||||||
RUN VERSION=$(curl -s https://raw.githubusercontent.com/${USER}/${REPO}/main/DEV-VERSION) && \
|
RUN VERSION=$(curl -s https://raw.githubusercontent.com/${USER}/${REPO}/main/DEV-VERSION) && \
|
||||||
wget -O /data/${APPLICATION}/${APPLICATION} https://github.com/${USER}/${REPO}/releases/download/$VERSION/${APPLICATION}-${TARGETOS}-${TARGETARCH}
|
wget -O /data/${APPLICATION}/${APPLICATION} https://github.com/${USER}/${REPO}/releases/download/$VERSION/${APPLICATION}-${TARGETOS}-${TARGETARCH}.tar.gz && \
|
||||||
|
tar -zxvf /data/${APPLICATION}/${APPLICATION}-${TARGETOS}-${TARGETARCH}.tar.gz -C /data/${APPLICATION} && \
|
||||||
|
rm -rf /data/${APPLICATION}/${APPLICATION}-${TARGETOS}-${TARGETARCH}.tar.gz
|
||||||
RUN wget -O /usr/local/bin/init.sh https://raw.githubusercontent.com/${USER}/${REPO}/main/docker/dockerfile/dev/init.sh
|
RUN wget -O /usr/local/bin/init.sh https://raw.githubusercontent.com/${USER}/${REPO}/main/docker/dockerfile/dev/init.sh
|
||||||
|
|
||||||
# 拉取配置
|
# 拉取配置
|
||||||
@@ -34,7 +36,7 @@ RUN wget -O /data/${APPLICATION}/whitelist.json https://raw.githubusercontent.co
|
|||||||
RUN chmod +x /data/${APPLICATION}/${APPLICATION}
|
RUN chmod +x /data/${APPLICATION}/${APPLICATION}
|
||||||
RUN chmod +x /usr/local/bin/init.sh
|
RUN chmod +x /usr/local/bin/init.sh
|
||||||
|
|
||||||
FROM wjqserver/caddy:daily-alpine
|
FROM wjqserver/caddy:2.9.0-rc-alpine
|
||||||
|
|
||||||
COPY --from=builder /data/www /data/www
|
COPY --from=builder /data/www /data/www
|
||||||
COPY --from=builder /data/caddy /data/caddy
|
COPY --from=builder /data/caddy /data/caddy
|
||||||
|
|||||||
5
go.mod
5
go.mod
@@ -22,7 +22,7 @@ require (
|
|||||||
github.com/go-playground/validator/v10 v10.22.1 // indirect
|
github.com/go-playground/validator/v10 v10.22.1 // indirect
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.3 // indirect
|
github.com/goccy/go-json v0.10.3 // indirect
|
||||||
github.com/google/pprof v0.0.0-20241023014458-598669927662 // indirect
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
@@ -32,7 +32,7 @@ require (
|
|||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/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/onsi/ginkgo/v2 v2.20.2 // indirect
|
github.com/onsi/ginkgo/v2 v2.21.0 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.3 // 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.48.1 // indirect
|
github.com/quic-go/quic-go v0.48.1 // indirect
|
||||||
@@ -48,6 +48,7 @@ require (
|
|||||||
golang.org/x/sync v0.8.0 // indirect
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.26.0 // indirect
|
golang.org/x/sys v0.26.0 // indirect
|
||||||
golang.org/x/text v0.19.0 // indirect
|
golang.org/x/text v0.19.0 // indirect
|
||||||
|
golang.org/x/time v0.7.0 // indirect
|
||||||
golang.org/x/tools v0.26.0 // indirect
|
golang.org/x/tools v0.26.0 // indirect
|
||||||
google.golang.org/protobuf v1.35.1 // indirect
|
google.golang.org/protobuf v1.35.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|||||||
7
go.sum
7
go.sum
@@ -50,6 +50,8 @@ github.com/google/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jn
|
|||||||
github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
|
github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
|
||||||
github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||||
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
@@ -76,8 +78,11 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
||||||
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||||
|
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@@ -132,6 +137,8 @@ golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
|||||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||||
|
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||||
|
|||||||
20
main.go
20
main.go
@@ -5,12 +5,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"ghproxy/api"
|
"ghproxy/api"
|
||||||
"ghproxy/auth"
|
"ghproxy/auth"
|
||||||
"ghproxy/config"
|
"ghproxy/config"
|
||||||
"ghproxy/logger"
|
"ghproxy/logger"
|
||||||
"ghproxy/proxy"
|
"ghproxy/proxy"
|
||||||
|
"ghproxy/rate"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -20,6 +22,8 @@ var (
|
|||||||
router *gin.Engine
|
router *gin.Engine
|
||||||
configfile = "/data/ghproxy/config/config.toml"
|
configfile = "/data/ghproxy/config/config.toml"
|
||||||
cfgfile string
|
cfgfile string
|
||||||
|
limiter *rate.RateLimiter
|
||||||
|
version string
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -58,8 +62,15 @@ func loadlist(cfg *config.Config) {
|
|||||||
auth.Init(cfg)
|
auth.Init(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupApi(cfg *config.Config, router *gin.Engine) {
|
func setupApi(cfg *config.Config, router *gin.Engine, version string) {
|
||||||
api.InitHandleRouter(cfg, router)
|
api.InitHandleRouter(cfg, router, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupRateLimit(cfg *config.Config) {
|
||||||
|
if cfg.RateLimit.Enabled {
|
||||||
|
limiter = rate.New(cfg.RateLimit.RatePerMinute, cfg.RateLimit.Burst, 1*time.Minute)
|
||||||
|
logInfo("Rate Limit Loaded")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -68,13 +79,14 @@ func init() {
|
|||||||
loadConfig()
|
loadConfig()
|
||||||
setupLogger(cfg)
|
setupLogger(cfg)
|
||||||
loadlist(cfg)
|
loadlist(cfg)
|
||||||
|
setupRateLimit(cfg)
|
||||||
|
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
|
||||||
router = gin.Default()
|
router = gin.Default()
|
||||||
router.UseH2C = true
|
router.UseH2C = true
|
||||||
|
|
||||||
setupApi(cfg, router)
|
setupApi(cfg, router, version)
|
||||||
|
|
||||||
if cfg.Pages.Enabled {
|
if cfg.Pages.Enabled {
|
||||||
indexPagePath := fmt.Sprintf("%s/index.html", cfg.Pages.StaticDir)
|
indexPagePath := fmt.Sprintf("%s/index.html", cfg.Pages.StaticDir)
|
||||||
@@ -92,7 +104,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
router.NoRoute(func(c *gin.Context) {
|
router.NoRoute(func(c *gin.Context) {
|
||||||
proxy.NoRouteHandler(cfg)(c)
|
proxy.NoRouteHandler(cfg, limiter)(c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 80%;
|
max-width: 65%;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"ghproxy/auth"
|
"ghproxy/auth"
|
||||||
"ghproxy/config"
|
"ghproxy/config"
|
||||||
"ghproxy/logger"
|
"ghproxy/logger"
|
||||||
|
"ghproxy/rate"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/imroc/req/v3"
|
"github.com/imroc/req/v3"
|
||||||
@@ -32,8 +33,17 @@ var exps = []*regexp.Regexp{
|
|||||||
regexp.MustCompile(`^(?:https?://)?gist\.github(?:usercontent|)\.com/([^/]+)/.+?/.+`),
|
regexp.MustCompile(`^(?:https?://)?gist\.github(?:usercontent|)\.com/([^/]+)/.+?/.+`),
|
||||||
}
|
}
|
||||||
|
|
||||||
func NoRouteHandler(cfg *config.Config) gin.HandlerFunc {
|
func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
// 限制访问频率
|
||||||
|
if cfg.RateLimit.Enabled {
|
||||||
|
if !limiter.Allow() {
|
||||||
|
c.JSON(http.StatusTooManyRequests, gin.H{"error": "Too Many Requests"})
|
||||||
|
logWarning("%s %s %s %s %s 429-TooManyRequests", c.ClientIP(), c.Request.Method, c.Request.URL.RequestURI(), c.Request.Header.Get("User-Agent"), c.Request.Proto)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rawPath := strings.TrimPrefix(c.Request.URL.RequestURI(), "/")
|
rawPath := strings.TrimPrefix(c.Request.URL.RequestURI(), "/")
|
||||||
re := regexp.MustCompile(`^(http:|https:)?/?/?(.*)`)
|
re := regexp.MustCompile(`^(http:|https:)?/?/?(.*)`)
|
||||||
matches := re.FindStringSubmatch(rawPath)
|
matches := re.FindStringSubmatch(rawPath)
|
||||||
|
|||||||
21
rate/rate.go
Normal file
21
rate/rate.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package rate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/time/rate"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RateLimiter struct {
|
||||||
|
limiter *rate.Limiter
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(limit int, burst int, duration time.Duration) *RateLimiter {
|
||||||
|
return &RateLimiter{
|
||||||
|
limiter: rate.NewLimiter(rate.Limit(float64(limit)/duration.Seconds()), burst),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *RateLimiter) Allow() bool {
|
||||||
|
return rl.limiter.Allow()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user