Compare commits

...

57 Commits
1.3.0 ... 1.5.0

Author SHA1 Message Date
WJQSERVER
b05dd37500 1.5.0 2024-10-12 10:20:43 +08:00
WJQSERVER
7fabd3c3e2 1.5.0 2024-10-12 10:20:20 +08:00
WJQSERVER
6dc20398ae 24w15d 2024-10-12 07:03:23 +08:00
WJQSERVER
03118a24a3 24w15d 2024-10-12 06:32:16 +08:00
WJQSERVER
0cb7c9f948 24w15c 2024-10-12 04:30:09 +08:00
WJQSERVER
824656f9d0 24w15c 2024-10-12 03:50:34 +08:00
WJQSERVER
e3d56ae9b7 24w15b 2024-10-11 12:06:16 +08:00
WJQSERVER
794ba22232 24w15b 2024-10-11 11:59:15 +08:00
WJQSERVER
f71c95e381 24w15b 2024-10-11 11:45:19 +08:00
WJQSERVER
997860f3ef 24w15a 2024-10-11 11:38:17 +08:00
WJQSERVER
81c35030e6 24w15a 2024-10-11 10:57:04 +08:00
WJQSERVER
80d2bc0068 fix1 2024-10-11 10:51:15 +08:00
WJQSERVER
4173617e72 fix 2024-10-11 10:48:33 +08:00
WJQSERVER
6a1a1b3c8b 24w15a 2024-10-11 10:45:15 +08:00
WJQSERVER
a21d5659ac 24w15a 2024-10-11 10:39:03 +08:00
WJQSERVER
a0de2f627d 24w15a 2024-10-11 10:34:42 +08:00
WJQSERVER
b47638d066 24w15a 2024-10-11 10:29:43 +08:00
WJQSERVER
69d4d53a51 24w15a 2024-10-11 10:25:33 +08:00
WJQSERVER
6864925dbe 1.4.3 2024-10-11 08:04:39 +08:00
WJQSERVER
2bdc2d0ace 1.4.3 2024-10-11 08:04:08 +08:00
WJQSERVER
1e496fb09e 24w14a 2024-10-11 02:54:16 +08:00
里見 灯花
23bb463490 Update build-dev.yml 2024-10-11 01:31:14 +08:00
里見 灯花
8eb6c09562 Update build-dev.yml 2024-10-11 01:20:16 +08:00
里見 灯花
1277af445c Update build-dev.yml 2024-10-11 01:17:59 +08:00
里見 灯花
62ee8ede1a 24w14a 2024-10-11 00:23:38 +08:00
里見 灯花
87b62e0342 24w14a 2024-10-11 00:21:34 +08:00
里見 灯花
245040a497 24w14a 2024-10-11 00:21:06 +08:00
WJQSERVER
96fba543a2 1.4.2 2024-10-10 23:00:52 +08:00
WJQSERVER
38430a3a68 1.4.2 2024-10-10 22:55:22 +08:00
WJQSERVER
71c5f25d1d update 2024-10-10 22:38:41 +08:00
WJQSERVER
2a53ac1b72 24w13c 2024-10-10 20:51:54 +08:00
WJQSERVER
57146483ec 1.4.2 2024-10-10 09:58:33 +08:00
WJQSERVER
03c33449db 1.4.2 2024-10-10 07:56:42 +08:00
WJQSERVER
6b9b864a4f update 2024-10-10 07:40:21 +08:00
WJQSERVER
db7f8f4bcb 24w13b 2024-10-10 03:22:10 +08:00
WJQSERVER
bfcb835608 24w13b 2024-10-10 03:14:13 +08:00
WJQSERVER
1eeeb56e9b 24w13b 2024-10-10 03:09:01 +08:00
WJQSERVER
d0b20a8828 24w13b 2024-10-10 03:05:48 +08:00
WJQSERVER
b57aa84bda 24w13b 2024-10-10 03:03:13 +08:00
WJQSERVER
4eb9d1a899 24w13a 2024-10-09 22:29:24 +08:00
WJQSERVER
d3d9f78820 1.4.1 2024-10-09 20:53:50 +08:00
WJQSERVER
f3a49b83f2 24w12c 2024-10-09 20:31:02 +08:00
WJQSERVER
fd7491aaa7 24w12c 2024-10-09 20:26:48 +08:00
WJQSERVER
b11a864495 24w12c 2024-10-09 20:14:44 +08:00
WJQSERVER
564364db74 fix 2024-10-09 01:06:13 +08:00
WJQSERVER
a1f0eaafa6 24w12b 2024-10-09 00:59:58 +08:00
WJQSERVER
2bbb539dda 24w12b 2024-10-09 00:59:14 +08:00
WJQSERVER
7ba2b94a00 24w12a 2024-10-09 00:41:45 +08:00
WJQSERVER
5e764a6cd7 24w12a 2024-10-08 21:15:03 +08:00
鬼鬼
abeb6ee8eb Fixed link format error in README.md (#3) 2024-10-08 20:09:34 +08:00
WJQSERVER
df93a90081 1.4.0 2024-10-08 20:04:07 +08:00
WJQSERVER
05032158d4 24w11b 2024-10-08 06:20:35 +08:00
WJQSERVER
b5bfc809a2 24w11a 2024-10-08 05:33:41 +08:00
WJQSERVER
dc8f4a28e9 24w11a 2024-10-08 05:28:56 +08:00
WJQSERVER
f5d7d0994e 24w10a 2024-10-06 19:38:53 +08:00
WJQSERVER
e3cffe70d9 24w10a 2024-10-06 19:33:20 +08:00
WJQSERVER
822b6c8cea 1.3.1 2024-10-06 19:19:54 +08:00
29 changed files with 951 additions and 223 deletions

View File

@@ -11,9 +11,12 @@ on:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux]
goarch: [amd64, arm64]
env:
OUTPUT_BINARY: ghproxy
OUTPUT_ARCHIVE: ghproxy.tar.gz
GO_VERSION: 1.23.2
steps:
@@ -29,25 +32,32 @@ jobs:
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
- name: Build
- name: Install UPX
run: |
go build -o ${{ env.OUTPUT_BINARY }} ./main.go
sudo apt update
sudo apt install upx -y
- name: Build
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
run: |
CGO_ENABLED=0 go build -o ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}} ./main.go
upx -9 ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}
- name: Package
run: |
tar -czvf ${{ env.OUTPUT_ARCHIVE }} ./${{ env.OUTPUT_BINARY }}
tar -czvf ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}.tar.gz ./${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}
- name: Upload to GitHub Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ env.OUTPUT_BINARY }}
path: |
./${{ env.OUTPUT_ARCHIVE }}
./${{ env.OUTPUT_BINARY }}
./${{ env.OUTPUT_BINARY }}*
- name: 上传至Release
id: create_release
uses: ncipollo/release-action@v1
with:
name: ${{ env.VERSION }}
artifacts: ./${{ env.OUTPUT_ARCHIVE }}, ./${{ env.OUTPUT_BINARY }}
artifacts: ./${{ env.OUTPUT_BINARY }}*
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ env.VERSION }}
allowUpdates: true
@@ -61,6 +71,7 @@ jobs:
env:
IMAGE_NAME: wjqserver/ghproxy
DOCKERFILE: docker/dockerfile/dev/Dockerfile
DOCKERFILE_PATH: docker/dockerfile/dev
steps:
- name: Checkout
@@ -86,10 +97,10 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 构建镜像
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
file: ./${{ env.DOCKERFILE }}
platforms: linux/amd64
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ env.IMAGE_NAME }}:${{ env.VERSION }}

View File

@@ -11,9 +11,12 @@ on:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux]
goarch: [amd64, arm64]
env:
OUTPUT_BINARY: ghproxy
OUTPUT_ARCHIVE: ghproxy.tar.gz
GO_VERSION: 1.23.2
steps:
@@ -29,50 +32,55 @@ jobs:
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
- name: Build
- name: Install UPX
run: |
go build -o ${{ env.OUTPUT_BINARY }} ./main.go
sudo apt-get update
sudo apt-get install -y upx
- name: Build
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
run: |
CGO_ENABLED=0 go build -ldflags="-s -w" -o ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}} ./main.go
upx -9 ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}
- name: Package
run: |
tar -czvf ${{ env.OUTPUT_ARCHIVE }} ./${{ env.OUTPUT_BINARY }}
tar -czvf ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}.tar.gz ./${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}
- name: Upload to GitHub Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ env.OUTPUT_BINARY }}
path: |
./${{ env.OUTPUT_ARCHIVE }}
./${{ env.OUTPUT_BINARY }}
./${{ env.OUTPUT_BINARY }}*
- name: 上传至Release
id: create_release
uses: ncipollo/release-action@v1
with:
name: ${{ env.VERSION }}
artifacts: ./${{ env.OUTPUT_ARCHIVE }}, ./${{ env.OUTPUT_BINARY }}
artifacts: ./${{ env.OUTPUT_BINARY }}*
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ env.VERSION }}
allowUpdates: true
env:
export PATH: $PATH:/usr/local/go/bin
docker:
runs-on: ubuntu-latest
needs: build # 确保这个作业在 build 作业完成后运行
env:
IMAGE_NAME: wjqserver/ghproxy # 定义镜像名称变量
DOCKERFILE: docker/dockerfile/release/Dockerfile
DOCKERFILE: docker/dockerfile/release/Dockerfile # 定义 Dockerfile 路径变量
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Load VERSION
run: |
if [ -f DEV-VERSION ]; then
echo "VERSION=$(cat DEV-VERSION)" >> $GITHUB_ENV
if [ -f VERSION ]; then
echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV
else
echo "DEV-VERSION file not found!" && exit 1
echo "VERSION file not found!" && exit 1
fi
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -86,10 +94,10 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 构建镜像
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
file: ./${{ env.DOCKERFILE }}
platforms: linux/amd64
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ env.IMAGE_NAME }}:${{ env.VERSION }}

View File

@@ -1,10 +1,149 @@
# 更新日志
v1.5.0
---
- CHANGE: 优化代码结构,提升性能
- CHANGE: 改进核心部分,即proxy模块的转发部分,对请求体处理与响应体处理进行优化
- CHANGE: 配置文件格式由yaml切换至toml,使其具备更好的可读性
- ADD: 黑白名单引入通配符支持,支持完全屏蔽或放行某个用户,例如`onwer/*`表示匹配`owner`的所有仓库
- ADD: 新增API模块,新增配置开关状态接口,以在前端指示功能状态
- CHANGE: 由于API变动,对前端进行相应调整
- ADD: 日志模块引入日志级别,排障更加直观
- CHANGE: 改进黑白名单机制,若禁用相关功能,则不对相关模块进行初始化
24w15d
---
- PRE-RELEASE: 此版本是v1.5.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- ADD: 新增API模块,新增配置开关状态接口,以在前端指示功能状态
- CHANGE: 由于API变动,对前端进行相应调整
24w15c
---
- PRE-RELEASE: 此版本是v1.5.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 改进核心部分,即proxy模块的转发部分,对请求体处理与响应体处理进行优化
- CHANGE: 改进黑白名单机制,若禁用相关功能,则不对对应模块进行初始化
- ADD: 黑白名单引入通配符支持,支持完全屏蔽或放行某个用户,例如`onwer/*`表示匹配`owner`的所有仓库
- ADD: 日志模块引入日志级别,排障更加直观
24w15b
---
- PRE-RELEASE: 此版本是v1.5.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- FIX: 修正24w15a版本的部分问题
24w15a
---
- PRE-RELEASE: 此版本是v1.5.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 将配置文件由yaml切换至toml
v1.4.3
---
- CHANGE: 优化代码结构,提升性能
- ADD: 新增命令行参数 `-cfg string` 用于指定配置文件路径
- CHANGE: 对二进制文件大小进行改进
24w14a
---
- PRE-RELEASE: 此版本是v1.4.3的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- ADD: 新增命令行参数 `-cfg string` 用于指定配置文件路径
v1.4.2
---
- CHANGE: 优化代码结构,提升性能
- CHANGE: 初步引入ARM64架构支持
- CHANGE: 对Docker镜像构建进行优化大幅减少镜像体积,从v1.4.0的`111 MB`,到v1.4.1的`58 MB`,再到v1.4.2的`28 MB`
- CHANGE: 切换至wjqserver/caddy:2.9.0-rc-alpine作为基础镜像
24w13c
---
- PRE-RELEASE: 此版本是v1.4.2的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 修正交叉编译问题
24w13b
---
- PRE-RELEASE: 此版本是v1.4.2的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 初步引入ARM64支持但仍处于测试阶段
- CHANGE: 对Dockerfile进行优化大幅减少镜像体积
24w13a
---
- PRE-RELEASE: 此版本是v1.4.2的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 更新相关依赖库
v1.4.1
---
- CHANGE: 优化代码结构,提升性能
- CHANGE: 引入Alpine Linux作为基础镜像,大幅减少Docker镜像体积
- FIX: 修正部分参数错误
- CHANGE: CGO_ENABLED=0
24w12c
---
- PRE-RELEASE: 此版本是v1.4.1的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 尝试在DEV版本引入Alpine Linux作为基础镜像,减少镜像体积
24w12b
---
- PRE-RELEASE: 此版本是v1.4.1的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 尝试引入Alpine Linux作为基础镜像,减少镜像体积
24w12a
---
- PRE-RELEASE: 此版本是v1.4.1的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- FIX: 修正部分参数错误
- CHANGE: CGO_ENABLED=0
v1.4.0
---
- CHANGE: 优化代码结构,提升性能
- ADD: 新增auth子模块whitelist.go,支持白名单功能
- ADD: 新增whitelist.json文件,用于配置白名单
- CHANGE&ADD: 在config.yaml文件中新增白名单配置块
- FIX: 由于临时加入且未在原开发路线上计划的白名单功能,导致函数命名冲突,在此修复blacklist.go的函数命名问题
- FIX: 修复黑/白名单是否生效相关问题
24w11b
---
- PRE-RELEASE: 此版本是v1.4.0的预发布版本,请勿在生产环境中使用
- FIX: 修复黑/白名单是否生效相关问题
24w11a
---
- PRE-RELEASE: 此版本是v1.4.0的预发布版本,请勿在生产环境中使用
- **ANNOUNCE**: 自此版本起,DEV版本号格式进行修改,小版本号不再仅限于a/b,而是采用字母表顺序进行排列,此修改将带来一个重要改变,正式版前的预发布版本的数字版本号将会统一,以便于版本管理与发布管理
- CHANGE: 优化代码结构,提升性能
- ADD: 新增auth子模块whitelist.go,支持白名单功能
- ADD: 新增whitelist.json文件,用于配置白名单
- FIX: 由于临时加入且未在原开发路线上计划的白名单功能,导致函数命名冲突,在此修复blacklist.go的函数命名问题
v1.3.1
---
- CHANGE: 优化代码结构,提升性能
- CHANGE: 剃刀计划,减少多余日志输出
- CHANGE: 调整缓存参数
24w10a
---
- PRE-RELEASE: 此版本是v1.3.1的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 剃刀计划,减少多余日志输出
- CHANGE: 调整缓存参数
v1.3.0
---
- CHANGE: 优化代码结构,提升性能
- CHANGE: 优化黑名单功能,提升稳定性
- CHANGE: 剃刀计划,减少调试用日志输出
- CHANGE: 剃刀计划,减少多余日志输出
- ADD 新增auth子模块blacklist.go,支持黑名单功能
- ADD: 新增blacklist.json文件,用于配置黑名单
- CHANGE: config.yaml文件格式修改,使其具备更好的可读性
@@ -12,12 +151,14 @@ v1.3.0
24w09b
---
- PRE-RELEASE: 此版本是v1.3.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 修正配置,提升稳定性
- WARNING: 此版本配置文件重构,此版本不再向前兼容,请注意备份文件并重新部署
24w09a
---
- PRE-RELEASE: 此版本是v1.3.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 优化黑名单功能,提升稳定性
- CHANGE&ADD: 新增auth子模块blacklist.go
@@ -26,6 +167,7 @@ v1.3.0
24w08b
---
- PRE-RELEASE: 此版本是v1.3.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- ADD & CHANGE: 新增仓库黑名单功能,改进Auth模块
- ADD: 新增blacklist.yaml文件,用于配置仓库黑名单
@@ -42,6 +184,7 @@ v1.2.0
24w08a
---
- PRE-RELEASE: 此版本是v1.2.0的预发布版本,请勿在生产环境中使用
- CHANGE: 同步更新logger模块与golang-temp项目定义的开发规范保持一致
- ADD: 新增日志翻转功能
@@ -53,12 +196,14 @@ v1.1.1
24w07b
---
- PRE-RELEASE: 此版本是v1.1.1的预发布版本,请勿在生产环境中使用
- CHANGE: 修改部分代码与golang-temp项目定义的开发规范保持一致
- CHANGE: 更新Go版本至v1.23.2
- CHANGE: 跟随Caddy更新,修改Caddyfile配置
24w07a
---
- PRE-RELEASE: 此版本是v1.1.1的预发布版本,请勿在生产环境中使用
- CHANGE: 修改部分代码与golang-temp项目定义的开发规范保持一致
- CHANGE: 更新Go版本至v1.23.2
@@ -73,6 +218,7 @@ v1.1.0
24w06b
---
- PRE-RELEASE: 此版本是v1.1.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,对main函数进行模块化,提升可读性
- CHANGE: Docker代理功能移至DEV版本内,保证稳定性
- ADD&CHANGE: 增加Auth(用户鉴权)模块,并改进其的错误处理与日志记录
@@ -82,6 +228,7 @@ v1.1.0
v1.0.0
---
- **ANNOUNCE**: 项目正式发布, 并迁移至[WJQSERVER-STUDIO/ghproxy](https://github.com/WJQSERVER-STUDIO/ghproxy)由Apache License Version 2.0转为WJQserver Studio License 请注意相关条例变更
- CHANGE: 项目正式发布, 并迁移至[WJQSERVER-STUDIO/ghproxy](https://github.com/WJQSERVER-STUDIO/ghproxy)
- CHANGE: 再次重构代码,优化性能,提升稳定性
- CHANGE: 使用golang-temp项目作为底层构建,标准化日志与配置模块
@@ -89,6 +236,7 @@ v1.0.0
24w06a
---
- PRE-RELEASE: 此版本是v1.0.0的预发布版本,请勿在生产环境中使用
- CHANGE: 与v1.0.0版本同步
v0.2.0
@@ -100,21 +248,25 @@ v0.2.0
24w05b
---
- PRE-RELEASE: 此版本是v0.2.0的预发布版本,请勿在生产环境中使用
- CHANGE: 重命名proxychrome函数
- ADD: 增加多处日志记录,便于审计与排障
24w05a
---
- PRE-RELEASE: 此版本是v0.2.0的预发布版本,请勿在生产环境中使用
- FIX 修正上一版本的req请求未继承请求方式的问题
- CHANGE: 优化代码结构,进一步模块化,同时提升性能
24w04b
---
- PRE-RELEASE: 此版本是v0.2.0的预发布版本,请勿在生产环境中使用
- CHANGE: 更换Docker基础镜像为daily版本
- ADD 新增使用req库实现代理请求,使用chrome TLS指纹发起请求
24w04a
---
- PRE-RELEASE: 此版本是v0.2.0的预发布版本,请勿在生产环境中使用
- CHANGE: 调整程序结构,使用init函数初始化配置,并优化代码结构
v0.1.7
@@ -123,6 +275,7 @@ v0.1.7
24w03b
---
- PRE-RELEASE: 此版本是v0.1.7的预发布版本,请勿在生产环境中使用
- CHANGE: 合入上游(wjqserver/caddy:latest)安全更新, 增强镜像安全性
v0.1.6
@@ -132,6 +285,7 @@ v0.1.6
24w03a
---
- PRE-RELEASE: 此版本是v0.1.6的预发布版本,请勿在生产环境中使用
- CHANGE: 改进Docker代理相关Caddy配置
- ADD: 新增跨域配置选项
@@ -142,16 +296,17 @@ v0.1.5
24w02b
---
- PRE-RELEASE: 此版本是v0.1.5的预发布版本,请勿在生产环境中使用
- ADD: 新增Docker代理 (未并入正式版)
24w02a
---
- PRE-RELEASE: 此版本是v0.1.5的预发布版本,请勿在生产环境中使用
- CHANGE: 更新Go版本至v1.23.1
- CHANGE: 优化代码行为
v0.1.4
---
正式版24w01b内容更新
- ADD: 新增外部文件配置功能
- ADD: 新增日志功能
- CHANGE: 优化代码结构,提升性能
@@ -159,7 +314,7 @@ v0.1.4
24w01b
---
标志着项目正式进入自主开发阶段
- PRE-RELEASE: 此版本是v0.1.4的预发布版本,请勿在生产环境中使用
- ADD: 新增外部文件配置功能
- ADD: 新增日志功能
- CHANGE: 优化代码结构,提升性能
@@ -167,12 +322,13 @@ v0.1.4
v0.1.3
---
开始自行维护项目,脱离上游更新
- **ANNOUNCE**: 开始自行维护项目,脱离上游更新
- CHANGE: 改进已有实现,增强程序稳定性
24w01a
---
首个DEV版本
- PRE-RELEASE: 此版本是v0.1.3的预发布版本,请勿在生产环境中使用
- **ANNOUNCE**: 首个DEV版本发布
- CHANGE: 同步更新
v0.1.2

View File

@@ -1 +1 @@
24w09b
24w15d

View File

@@ -5,7 +5,7 @@
使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取,支持速率限制,用户鉴权,支持Docker部署
[DEMO](ghproxy.1888866.xyz)
[DEMO](https://ghproxy.1888866.xyz)
## 项目说明
@@ -16,7 +16,7 @@
- 支持Docker部署
- 支持速率限制
- 支持用户鉴权
- 支持自定义黑名单
- 支持自定义黑名单/白名单
- 符合[RFC 7234](https://httpwg.org/specs/rfc7234.html)的HTTP Cache
- 使用Caddy作为Web Server
- 基于[WJQSERVER-STUDIO/golang-temp](https://github.com/WJQSERVER-STUDIO/golang-temp)模板构建,具有标准化的日志记录与构建流程
@@ -51,7 +51,7 @@ git clone https://ghproxy.1888866.xyz/github.com/WJQSERVER-STUDIO/ghproxy.git
- Docker-cli
```
docker run -p 7210:80 -v ./ghproxy/log/run:/data/ghproxy/log -v ./ghproxy/log/caddy:/data/caddy/log --restart always wjqserver/ghproxy
docker run -p 7210:80 -v ./ghproxy/log/run:/data/ghproxy/log -v ./ghproxy/log/caddy:/data/caddy/log -v ./ghproxy/config:/data/ghproxy/config --restart always wjqserver/ghproxy
```
- Docker-Compose
@@ -60,34 +60,33 @@ docker run -p 7210:80 -v ./ghproxy/log/run:/data/ghproxy/log -v ./ghproxy/log/ca
### 外部配置文件
本项目采用config.yaml作为外部配置,默认配置如下
使用Docker部署时,慎重修改config.yaml,以免造成不必要的麻烦
本项目采用`config.toml`作为外部配置,默认配置如下
使用Docker部署时,慎重修改`config.toml`,以免造成不必要的麻烦
```yaml
# 核心配置
server:
port: 8080 # 监听端口(小白请勿修改)
host: "127.0.0.1" # 监听地址(小白请勿修改)
sizelimit: 131072000 # 125MB
```toml
[server]
host = "127.0.0.1" # 监听地址(小白请勿修改)
port = 8080 #监听端口(小白请勿修改)
sizelimit = 131072000 # 125MB
# 日志配置
logger:
logfilepath: "/data/ghproxy/log/ghproxy.log" # 日志文件路径(小白请勿修改)
maxlogsize: 25 # MB
[log]
logfilepath = "/data/ghproxy/log/ghproxy.log" # 日志文件路径(小白请勿修改)
maxlogsize = 5 # MB
# CORS 配置
cors:
enabled: true # 是否开启CORS
[cors]
enabled = true # 是否开启CORS
# 鉴权配置
auth:
enabled: false # 是否开启鉴权
authtoken: "test" # 鉴权Token
[auth]
authtoken = "test" # 鉴权Token
enabled = false # 是否开启鉴权
# 黑名单配置
blacklist:
enabled: true
blacklistfile: "/data/ghproxy/config/blacklist.json"
[blacklist]
blacklistfile = "/data/ghproxy/config/blacklist.json" # 黑名单文件路径
enabled = false # 是否开启黑名单
[whitelist]
enabled = false # 是否开启白名单
whitelistfile = "/data/ghproxy/config/whitelist.json" # 白名单文件路径
```
@@ -100,7 +99,21 @@ blacklist:
"blacklist": [
"test/test1",
"example/repo2",
"another/repo3"
"another/*"
]
}
```
### 白名单配置
白名单配置位于config/whitelist.json,格式如下:
```json
{
"whitelist": [
"test/test1",
"example/repo2",
"another/*"
]
}
```
@@ -120,6 +133,10 @@ example.com {
}
```
### 前端页面
![ghproxy-demo-v1.5.0.png](https://webp.wjqserver.com/ghproxy/ghproxy-demo-v1.5.0.png)
## TODO & DEV
### TODO
@@ -128,6 +145,7 @@ example.com {
- [x] 改进程序效率
- [x] 用户鉴权
- [x] 仓库黑名单
- [x] 仓库白名单
### DEV

View File

@@ -7,15 +7,9 @@
| 版本 | 是否支持 |
| --- | --- |
| v1.x.x | :white_check_mark: |
| **w**a/b | :warning: 这是测试版本,用于开发测试,可能存在未知的安全隐患 |
| **w**a/b/c... | :warning: 此为PRE-RELEASE版本,用于开发测试,可能存在未知的问题 |
| v0.x.x | :x: 这些版本不再受支持 |
### 版本说明
- **v1.0.0**: 这是正式发布的版本
- **xx W xx A/B***: 这是开发测试版本,可能存在未知的安全隐患。不推荐在生产环境中使用。
- **v0.x.x**: 这些早期版本不再受支持,建议尽快升级到 v1.0.0 或更高版本。
### 用户须知
本项目为开源项目,开发者不对使用本项目造成的任何损失或问题承担责任。用户需自行评估并承担使用本项目的风险。

View File

@@ -1 +1 @@
1.3.0
1.5.0

76
api/api.go Normal file
View File

@@ -0,0 +1,76 @@
package api
import (
"encoding/json"
"ghproxy/config"
"ghproxy/logger"
"github.com/gin-gonic/gin"
)
var (
router *gin.Engine
cfg *config.Config
)
// 日志模块
var (
logw = logger.Logw
logInfo = logger.LogInfo
LogWarning = logger.LogWarning
logError = logger.LogError
)
func InitHandleRouter(cfg *config.Config, router *gin.Engine) {
// 设置路由
apiRouter := router.Group("api")
{
apiRouter.GET("/size_limit", func(c *gin.Context) {
SizeLimitHandler(cfg, c)
})
apiRouter.GET("/whitelist/status", func(c *gin.Context) {
WhiteListStatusHandler(c, cfg)
})
apiRouter.GET("/blacklist/status", func(c *gin.Context) {
BlackListStatusHandler(c, cfg)
})
apiRouter.GET("/healthcheck", func(c *gin.Context) {
HealthcheckHandler(c)
})
}
logInfo("API router Init success")
}
func SizeLimitHandler(cfg *config.Config, c *gin.Context) {
// 转换为MB
sizeLimit := cfg.Server.SizeLimit / 1024 / 1024
// 设置响应头
c.Writer.Header().Set("Content-Type", "application/json")
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
"MaxResponseBodySize": sizeLimit,
})
}
func WhiteListStatusHandler(c *gin.Context, cfg *config.Config) {
// 设置响应头
c.Writer.Header().Set("Content-Type", "application/json")
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
"Whitelist": cfg.Whitelist.Enabled,
})
}
func BlackListStatusHandler(c *gin.Context, cfg *config.Config) {
// 设置响应头
c.Writer.Header().Set("Content-Type", "application/json")
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
"Blacklist": cfg.Blacklist.Enabled,
})
}
func HealthcheckHandler(c *gin.Context) {
// 设置响应头
c.Writer.Header().Set("Content-Type", "application/json")
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
"Status": "OK",
})
}

View File

@@ -7,7 +7,24 @@ import (
"github.com/gin-gonic/gin"
)
var logw = logger.Logw
// 日志模块
var (
logw = logger.Logw
logInfo = logger.LogInfo
LogWarning = logger.LogWarning
logError = logger.LogError
)
// Auth Init
func Init(cfg *config.Config) {
if cfg.Blacklist.Enabled {
LoadBlacklist(cfg)
}
if cfg.Whitelist.Enabled {
LoadWhitelist(cfg)
}
logInfo("Auth Init")
}
func AuthHandler(c *gin.Context, cfg *config.Config) bool {
// 如果身份验证未启用,直接返回 true
@@ -17,19 +34,19 @@ func AuthHandler(c *gin.Context, cfg *config.Config) bool {
// 获取 auth_token 参数
authToken := c.Query("auth_token")
logw("auth_token received: %s", authToken)
logInfo("auth_token received: %s", authToken)
// 验证 token
if authToken == "" {
logw("auth FAILED: no auth_token provided")
LogWarning("auth FAILED: no auth_token provided")
return false
}
isValid := authToken == cfg.Auth.AuthToken
if !isValid {
logw("auth FAILED: invalid auth_token: %s", authToken)
LogWarning("auth FAILED: invalid auth_token: %s", authToken)
}
logw("auth SUCCESS: %t", isValid)
logInfo("auth SUCCESS: %t", isValid)
return isValid
}

View File

@@ -4,43 +4,53 @@ import (
"encoding/json"
"ghproxy/config"
"os"
"strings"
)
type Config struct {
type BlacklistConfig struct {
Blacklist []string `json:"blacklist"`
}
var (
cfg *config.Config
blacklistfile = "/data/ghproxy/config/blacklist.json"
blacklist *Config
blacklist *BlacklistConfig
)
func LoadBlacklist(cfg *config.Config) {
blacklistfile = cfg.Blacklist.BlacklistFile
blacklist = &Config{}
blacklist = &BlacklistConfig{}
data, err := os.ReadFile(blacklistfile)
if err != nil {
logw("Failed to read blacklist file: %v", err)
logError("Failed to read blacklist file: %v", err)
}
err = json.Unmarshal(data, blacklist)
if err != nil {
logw("Failed to unmarshal blacklist JSON: %v", err)
logError("Failed to unmarshal blacklist JSON: %v", err)
}
}
// fullrepo: "owner/repo" or "owner/*"
func CheckBlacklist(fullrepo string) bool {
return forRangeCheck(blacklist.Blacklist, fullrepo)
return forRangeCheckBlacklist(blacklist.Blacklist, fullrepo)
}
func forRangeCheck(blist []string, fullrepo string) bool {
func sliceRepoName_Blacklist(fullrepo string) (string, string) {
s := strings.Split(fullrepo, "/")
if len(s) != 2 {
return "", ""
}
return s[0], s[1]
}
func forRangeCheckBlacklist(blist []string, fullrepo string) bool {
repoUser, _ := sliceRepoName_Blacklist(fullrepo)
for _, blocked := range blist {
if blocked == fullrepo {
if blocked == fullrepo || (strings.HasSuffix(blocked, "/*") && strings.HasPrefix(repoUser, blocked[:len(blocked)-2])) {
return true
}
}
logw("%s not in blacklist", fullrepo)
return false
}

54
auth/whitelist.go Normal file
View File

@@ -0,0 +1,54 @@
package auth
import (
"encoding/json"
"ghproxy/config"
"os"
"strings"
)
type WhitelistConfig struct {
Whitelist []string `json:"whitelist"`
}
var (
whitelistfile = "/data/ghproxy/config/whitelist.json"
whitelist *WhitelistConfig
)
func LoadWhitelist(cfg *config.Config) {
whitelistfile = cfg.Whitelist.WhitelistFile
whitelist = &WhitelistConfig{}
data, err := os.ReadFile(whitelistfile)
if err != nil {
logError("Failed to read whitelist file: %v", err)
}
err = json.Unmarshal(data, whitelist)
if err != nil {
logError("Failed to unmarshal whitelist JSON: %v", err)
}
}
func CheckWhitelist(fullrepo string) bool {
return forRangeCheckWhitelist(whitelist.Whitelist, fullrepo)
}
func sliceRepoName_Whitelist(fullrepo string) (string, string) {
s := strings.Split(fullrepo, "/")
if len(s) != 2 {
return "", ""
}
return s[0], s[1]
}
func forRangeCheckWhitelist(wlist []string, fullrepo string) bool {
repoUser, _ := sliceRepoName_Whitelist(fullrepo)
for _, blocked := range wlist {
if blocked == fullrepo || (strings.HasSuffix(blocked, "/*") && strings.HasPrefix(repoUser, blocked[:len(blocked)-2])) {
return true
}
}
return false
}

View File

@@ -72,10 +72,12 @@
import header_realip
}
import log ghproxy
import cache 0s 600s
import cache 0s 300s
import error_page
import encode
import rate_limit 60
header Age 10
header Cache-Control "max-age=300"
route / {
root /data/www
file_server
@@ -84,7 +86,7 @@
route /favicon.ico {
root /data/www
file_server
import cache 60s 24h
import cache 0s 24h
}
handle_errors {
@redirects `{err.status_code} in [301, 302, 307]`

View File

@@ -60,12 +60,6 @@
header_up X-Forwarded-Proto {http.request.header.CF-Visitor}
}
(buffer) {
flush_interval 2000s
buffer_responses
max_buffer_size 256k
}
(rate_limit) {
route /* {
rate_limit {remote.ip} {args[0]}r/m 10000 429
@@ -78,7 +72,7 @@
import header_realip
}
import log ghproxy
import cache 0s 600s
import cache 0s 300s
import error_page
import encode
route /* {
@@ -92,7 +86,7 @@
route /favicon.ico {
root /data/www
file_server
import cache 60s 24h
import cache 0s 24h
}
}

View File

@@ -1,8 +1,7 @@
{
"blacklist": [
"black/list",
"test/test1",
"example/repo2",
"another/repo3"
"example/repo2"
]
}

View File

@@ -1,12 +1,10 @@
package config
import (
"os"
"gopkg.in/yaml.v3"
"github.com/BurntSushi/toml"
)
type Config struct {
/*type Config struct {
Server struct {
Port int `yaml:"port"`
Host string `yaml:"host"`
@@ -31,6 +29,11 @@ type Config struct {
Enabled bool `yaml:"enabled"`
BlacklistFile string `yaml:"blacklistfile"`
} `yaml:"blacklist"`
Whitelist struct {
Enabled bool `yaml:"enabled"`
WhitelistFile string `yaml:"whitelistfile"`
} `yaml:"whitelist"`
}
// LoadConfig 从 YAML 配置文件加载配置
@@ -49,4 +52,52 @@ func loadYAML(filePath string, out interface{}) error {
return err
}
return yaml.Unmarshal(data, out)
}*/
type Config struct {
Server ServerConfig
Log LogConfig
CORS CORSConfig
Auth AuthConfig
Blacklist BlacklistConfig
Whitelist WhitelistConfig
}
type ServerConfig struct {
Port int `toml:"port"`
Host string `toml:"host"`
SizeLimit int `toml:"sizelimit"`
}
type LogConfig struct {
LogFilePath string `toml:"logfilepath"`
MaxLogSize int `toml:"maxlogsize"`
}
type CORSConfig struct {
Enabled bool `toml:"enabled"`
}
type AuthConfig struct {
Enabled bool `toml:"enabled"`
AuthToken string `toml:"authtoken"`
}
type BlacklistConfig struct {
Enabled bool `toml:"enabled"`
BlacklistFile string `toml:"blacklistfile"`
}
type WhitelistConfig struct {
Enabled bool `toml:"enabled"`
WhitelistFile string `toml:"whitelistfile"`
}
// LoadConfig 从 TOML 配置文件加载配置
func LoadConfig(filePath string) (*Config, error) {
var config Config
if _, err := toml.DecodeFile(filePath, &config); err != nil {
return nil, err
}
return &config, nil
}

23
config/config.toml Normal file
View File

@@ -0,0 +1,23 @@
[server]
host = "127.0.0.1"
port = 8080
sizelimit = 131072000 # 125MB
[log]
logfilepath = "/data/ghproxy/log/ghproxy.log"
maxlogsize = 5 # MB
[cors]
enabled = true
[auth]
authtoken = "test"
enabled = false
[blacklist]
blacklistfile = "/data/ghproxy/config/blacklist.json"
enabled = false
[whitelist]
enabled = false
whitelistfile = "/data/ghproxy/config/whitelist.json"

View File

@@ -7,7 +7,7 @@ server:
# Logging Configuration
logger:
logfilepath: "/data/ghproxy/log/ghproxy.log"
maxlogsize: 25 # MB
maxlogsize: 5 # MB
# CORS Configuration
cors:
@@ -20,5 +20,10 @@ auth:
# Blacklist Configuration
blacklist:
enabled: true
enabled: false
blacklistfile: "/data/ghproxy/config/blacklist.json"
# Whitelist Configuration
whitelist:
enabled: false
whitelistfile: "/data/ghproxy/config/whitelist.json"

7
config/whitelist.json Normal file
View File

@@ -0,0 +1,7 @@
{
"whitelist": [
"white/list",
"white/test1",
"example/white"
]
}

View File

@@ -1,20 +1,47 @@
FROM wjqserver/caddy:daily
FROM wjqserver/caddy:daily-alpine AS builder
ARG USER=WJQSERVER-STUDIO
ARG REPO=ghproxy
ARG APPLICATION=ghproxy
ARG TARGETOS
ARG TARGETARCH
ARG TARGETPLATFORM
# 创建文件夹
RUN mkdir -p /data/www
RUN mkdir -p /data/${APPLICATION}/config
RUN mkdir -p /data/${APPLICATION}/log
# 安装依赖
RUN apk add --no-cache curl wget
# 前端
RUN wget -O /data/www/index.html https://raw.githubusercontent.com/${USER}/${REPO}/main/pages/index.html
RUN wget -O /data/www/favicon.ico https://raw.githubusercontent.com/${USER}/${REPO}/main/pages/favicon.ico
RUN wget -O /data/caddy/Caddyfile https://raw.githubusercontent.com/${USER}/${REPO}/main/caddyfile/release/Caddyfile
# 后端
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}
RUN wget -O /data/${APPLICATION}/config.yaml https://raw.githubusercontent.com/${USER}/${REPO}/main/config/config.yaml
wget -O /data/${APPLICATION}/${APPLICATION} https://github.com/${USER}/${REPO}/releases/download/$VERSION/${APPLICATION}-${TARGETOS}-${TARGETARCH}
RUN wget -O /usr/local/bin/init.sh https://raw.githubusercontent.com/${USER}/${REPO}/main/docker/dockerfile/dev/init.sh
# 拉取配置
RUN wget -O /data/caddy/Caddyfile https://raw.githubusercontent.com/${USER}/${REPO}/main/caddyfile/dev/Caddyfile
RUN wget -O /data/${APPLICATION}/config.toml https://raw.githubusercontent.com/${USER}/${REPO}/main/config/config.toml
RUN wget -O /data/${APPLICATION}/blacklist.json https://raw.githubusercontent.com/${USER}/${REPO}/main/config/blacklist.json
RUN wget -O /usr/local/bin/init.sh https://raw.githubusercontent.com/${USER}/${REPO}/main/init.sh
RUN wget -O /data/${APPLICATION}/whitelist.json https://raw.githubusercontent.com/${USER}/${REPO}/main/config/whitelist.json
# 权限
RUN chmod +x /data/${APPLICATION}/${APPLICATION}
RUN chmod +x /usr/local/bin/init.sh
FROM wjqserver/caddy:daily-alpine
COPY --from=builder /data/www /data/www
COPY --from=builder /data/caddy /data/caddy
COPY --from=builder /data/${APPLICATION} /data/${APPLICATION}
COPY --from=builder /usr/local/bin/init.sh /usr/local/bin/init.sh
# 权限
RUN chmod +x /data/${APPLICATION}/${APPLICATION}
RUN chmod +x /usr/local/bin/init.sh

View File

@@ -0,0 +1,27 @@
#!/bin/sh
APPLICATION=ghproxy
if [ ! -f /data/caddy/config/Caddyfile ]; then
cp /data/caddy/Caddyfile /data/caddy/config/Caddyfile
fi
if [ ! -f /data/${APPLICATION}/config/blacklist.json ]; then
cp /data/${APPLICATION}/blacklist.json /data/${APPLICATION}/config/blacklist.json
fi
if [ ! -f /data/${APPLICATION}/config/whitelist.json ]; then
cp /data/${APPLICATION}/whitelist.json /data/${APPLICATION}/config/whitelist.json
fi
if [ ! -f /data/${APPLICATION}/config/config.toml ]; then
cp /data/${APPLICATION}/config.toml /data/${APPLICATION}/config/config.toml
fi
/data/caddy/caddy run --config /data/caddy/config/Caddyfile > /data/${APPLICATION}/log/caddy.log 2>&1 &
/data/${APPLICATION}/${APPLICATION} -cfg /data/${APPLICATION}/config/config.toml > /data/${APPLICATION}/log/run.log 2>&1 &
while true; do
sleep 1
done

View File

@@ -1,20 +1,47 @@
FROM wjqserver/caddy:latest
FROM wjqserver/caddy:2.9.0-rc-alpine AS builder
ARG USER=WJQSERVER-STUDIO
ARG REPO=ghproxy
ARG APPLICATION=ghproxy
ARG TARGETOS
ARG TARGETARCH
ARG TARGETPLATFORM
# 创建文件夹
RUN mkdir -p /data/www
RUN mkdir -p /data/${APPLICATION}/config
RUN mkdir -p /data/${APPLICATION}/log
# 安装依赖
RUN apk add --no-cache curl wget
# 前端
RUN wget -O /data/www/index.html https://raw.githubusercontent.com/${USER}/${REPO}/main/pages/index.html
RUN wget -O /data/www/favicon.ico https://raw.githubusercontent.com/${USER}/${REPO}/main/pages/favicon.ico
RUN wget -O /data/caddy/Caddyfile https://raw.githubusercontent.com/${USER}/${REPO}/main/caddyfile/release/Caddyfile
# 后端
RUN VERSION=$(curl -s https://raw.githubusercontent.com/${USER}/${REPO}/main/VERSION) && \
wget -O /data/${APPLICATION}/${APPLICATION} https://github.com/${USER}/${REPO}/releases/download/$VERSION/${APPLICATION}
RUN wget -O /data/${APPLICATION}/config.yaml https://raw.githubusercontent.com/${USER}/${REPO}/main/config/config.yaml
wget -O /data/${APPLICATION}/${APPLICATION} https://github.com/${USER}/${REPO}/releases/download/$VERSION/${APPLICATION}-${TARGETOS}-${TARGETARCH}
RUN wget -O /usr/local/bin/init.sh https://raw.githubusercontent.com/${USER}/${REPO}/main/docker/dockerfile/release/init.sh
# 拉取配置
RUN wget -O /data/caddy/Caddyfile https://raw.githubusercontent.com/${USER}/${REPO}/main/caddyfile/release/Caddyfile
RUN wget -O /data/${APPLICATION}/config.toml https://raw.githubusercontent.com/${USER}/${REPO}/main/config/config.toml
RUN wget -O /data/${APPLICATION}/blacklist.json https://raw.githubusercontent.com/${USER}/${REPO}/main/config/blacklist.json
RUN wget -O /usr/local/bin/init.sh https://raw.githubusercontent.com/${USER}/${REPO}/main/init.sh
RUN wget -O /data/${APPLICATION}/whitelist.json https://raw.githubusercontent.com/${USER}/${REPO}/main/config/whitelist.json
# 权限
RUN chmod +x /data/${APPLICATION}/${APPLICATION}
RUN chmod +x /usr/local/bin/init.sh
FROM wjqserver/caddy:2.9.0-rc-alpine
COPY --from=builder /data/www /data/www
COPY --from=builder /data/caddy /data/caddy
COPY --from=builder /data/${APPLICATION} /data/${APPLICATION}
COPY --from=builder /usr/local/bin/init.sh /usr/local/bin/init.sh
# 权限
RUN chmod +x /data/${APPLICATION}/${APPLICATION}
RUN chmod +x /usr/local/bin/init.sh

View File

@@ -0,0 +1,27 @@
#!/bin/sh
APPLICATION=ghproxy
if [ ! -f /data/caddy/config/Caddyfile ]; then
cp /data/caddy/Caddyfile /data/caddy/config/Caddyfile
fi
if [ ! -f /data/${APPLICATION}/config/blacklist.json ]; then
cp /data/${APPLICATION}/blacklist.json /data/${APPLICATION}/config/blacklist.json
fi
if [ ! -f /data/${APPLICATION}/config/whitelist.json ]; then
cp /data/${APPLICATION}/whitelist.json /data/${APPLICATION}/config/whitelist.json
fi
if [ ! -f /data/${APPLICATION}/config/config.toml ]; then
cp /data/${APPLICATION}/config.toml /data/${APPLICATION}/config/config.toml
fi
/data/caddy/caddy run --config /data/caddy/config/Caddyfile > /data/${APPLICATION}/log/caddy.log 2>&1 &
/data/${APPLICATION}/${APPLICATION} -cfg /data/${APPLICATION}/config/config.toml > /data/${APPLICATION}/log/run.log 2>&1 &
while true; do
sleep 1
done

48
go.mod
View File

@@ -3,48 +3,52 @@ module ghproxy
go 1.23.2
require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudflare/circl v1.4.0 // indirect
github.com/BurntSushi/toml v1.4.0
github.com/gin-gonic/gin v1.10.0
github.com/imroc/req/v3 v3.47.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/bytedance/sonic v1.12.3 // indirect
github.com/bytedance/sonic/loader v0.2.0 // indirect
github.com/cloudflare/circl v1.5.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.10.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-playground/validator/v10 v10.22.1 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/google/pprof v0.0.0-20241009165004-a3522334989c // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/imroc/req/v3 v3.46.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.47.0 // indirect
github.com/refraction-networking/utls v1.6.7 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/arch v0.11.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/tools v0.25.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/tools v0.26.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
)

50
go.sum
View File

@@ -1,11 +1,21 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU=
github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudflare/circl v1.4.0 h1:BV7h5MgrktNzytKmWjpOtdYrf0lkkbF8YMlBGPhJQrY=
github.com/cloudflare/circl v1.4.0/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
@@ -14,6 +24,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
@@ -24,13 +36,22 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 h1:c5FlPPgxOn7kJz3VoPLkQYQXGBS3EklQ4Zfi57uOuqQ=
github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20241008150032-332c0e1a4a34 h1:4iExbL0TFWhkSCZx6nfKwjM+CbnBySx18KssYmdL1fc=
github.com/google/pprof v0.0.0-20241008150032-332c0e1a4a34/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20241009165004-a3522334989c h1:NDovD0SMpBYXlE1zJmS1q55vWB/fUQBcPAqAboZSccA=
github.com/google/pprof v0.0.0-20241009165004-a3522334989c/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -38,13 +59,21 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/imroc/req/v3 v3.46.1 h1:oahr2hBTb3AaFI4P6jkN0Elj2ZVKJcdQ/IjWqeIKjvc=
github.com/imroc/req/v3 v3.46.1/go.mod h1:weam9gmyb00QnOtu6HXSnk44dNFkIUQb5QdMx13FeUU=
github.com/imroc/req/v3 v3.47.0 h1:O8D1KtZSEuhHIrWA+YBd4MZeFg3KprfbNSFR49EWdNA=
github.com/imroc/req/v3 v3.47.0/go.mod h1:weam9gmyb00QnOtu6HXSnk44dNFkIUQb5QdMx13FeUU=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0=
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
@@ -59,6 +88,8 @@ 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/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
@@ -81,23 +112,34 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4=
golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw=
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -106,14 +148,22 @@ golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
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=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -10,13 +10,17 @@ if [ ! -f /data/${APPLICATON}/config/blacklist.json ]; then
cp /data/${APPLICATON}/blacklist.json /data/${APPLICATON}/config/blacklist.json
fi
if [ ! -f /data/${APPLICATON}/config/whitelist.json ]; then
cp /data/${APPLICATON}/whitelist.json /data/${APPLICATON}/config/whitelist.json
fi
if [ ! -f /data/${APPLICATON}/config/config.yaml ]; then
cp /data/${APPLICATON}/config.yaml /data/${APPLICATON}/config/config.yaml
fi
/data/caddy/caddy run --config /data/caddy/config/Caddyfile > /data/${APPLICATON}/log/caddy.log 2>&1 &
/data/${APPLICATON}/${APPLICATON} > /data/ghproxy/log/run.log 2>&1 &
/data/${APPLICATON}/${APPLICATON} > /data/${APPLICATON}/log/run.log 2>&1 &
while [[ true ]]; do
sleep 1

View File

@@ -19,14 +19,16 @@ var (
logChannel = make(chan string, 100)
quitChannel = make(chan struct{})
logFileMutex sync.Mutex // 保护 logFile 的互斥锁
logFilePath = "/data/ghproxy/log/ghproxy.log"
)
// Init 初始化日志记录器,接受日志文件路径作为参数
func Init(logFilePath string, maxLogsize int) error {
func Init(logFilePath_input string, maxLogsize int) error {
logFileMutex.Lock()
defer logFileMutex.Unlock()
var err error
logFilePath = logFilePath_input
logFile, err = os.OpenFile(logFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
return err
@@ -62,6 +64,26 @@ func Logw(format string, args ...interface{}) {
Log(message)
}
// 日志等级INFO
func LogInfo(format string, args ...interface{}) {
message := fmt.Sprintf(format, args...)
output := fmt.Sprintf("[INFO] %s", message)
Log(output)
}
// 日志等级WARNING
func LogWarning(format string, args ...interface{}) {
message := fmt.Sprintf(format, args...)
output := fmt.Sprintf("[WARNING] %s", message)
Log(output)
}
// 日志等级ERROR
func LogError(format string, args ...interface{}) {
message := fmt.Sprintf(format, args...)
Log(message)
}
// Close 关闭日志文件
func Close() {
logFileMutex.Lock()

63
main.go
View File

@@ -1,12 +1,12 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"regexp"
"ghproxy/api"
"ghproxy/auth"
"ghproxy/config"
"ghproxy/logger"
@@ -17,21 +17,23 @@ import (
var (
cfg *config.Config
logw = logger.Logw
router *gin.Engine
configfile = "/data/ghproxy/config/config.yaml"
configfile = "/data/ghproxy/config/config.toml"
)
// 日志模块
var (
exps = []*regexp.Regexp{
regexp.MustCompile(`^(?:https?://)?github\.com/([^/]+)/([^/]+)/(?:releases|archive)/.*`),
regexp.MustCompile(`^(?:https?://)?github\.com/([^/]+)/([^/]+)/(?:blob|raw)/.*`),
regexp.MustCompile(`^(?:https?://)?github\.com/([^/]+)/([^/]+)/(?:info|git-).*`),
regexp.MustCompile(`^(?:https?://)?raw\.github(?:usercontent|)\.com/([^/]+)/([^/]+)/.+?/.+`),
regexp.MustCompile(`^(?:https?://)?gist\.github\.com/([^/]+)/.+?/.+`),
}
logw = logger.Logw
logInfo = logger.LogInfo
LogWarning = logger.LogWarning
logError = logger.LogError
)
func ReadFlag() {
cfgfile := flag.String("cfg", configfile, "config file path")
configfile = *cfgfile
}
func loadConfig() {
var err error
// 初始化配置
@@ -42,25 +44,31 @@ func loadConfig() {
fmt.Printf("Loaded config: %v\n", cfg)
}
func setupLogger() {
func setupLogger(cfg *config.Config) {
// 初始化日志模块
var err error
err = logger.Init(cfg.Log.LogFilePath, cfg.Log.MaxLogSize) // 传递日志文件路径
if err != nil {
log.Fatalf("Failed to initialize logger: %v", err)
}
logw("Logger initialized")
logw("Init Completed")
logInfo("Logger initialized")
logInfo("Init Completed")
}
func LoadBlacklist(cfg *config.Config) {
auth.LoadBlacklist(cfg)
func Loadlist(cfg *config.Config) {
auth.Init(cfg)
}
func setupApi(cfg *config.Config, router *gin.Engine) {
// 注册 API 接口
api.InitHandleRouter(cfg, router)
}
func init() {
ReadFlag()
loadConfig()
setupLogger()
LoadBlacklist(cfg)
setupLogger(cfg)
Loadlist(cfg)
// 设置 Gin 模式
gin.SetMode(gin.ReleaseMode)
@@ -68,18 +76,13 @@ func init() {
// 初始化路由
router = gin.Default()
setupApi(cfg, router)
// 定义路由
router.GET("/", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "https://ghproxy0rtt.1888866.xyz/")
})
router.GET("/api", api)
// 健康检查
router.GET("/api/healthcheck", func(c *gin.Context) {
c.String(http.StatusOK, "OK")
})
// 未匹配路由处理
router.NoRoute(func(c *gin.Context) {
proxy.NoRouteHandler(cfg)(c)
@@ -90,16 +93,8 @@ func main() {
// 启动服务器
err := router.Run(fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port))
if err != nil {
log.Fatalf("Error starting server: %v\n", err)
logError("Error starting server: %v\n", err)
}
fmt.Println("Program finished")
}
func api(c *gin.Context) {
// 设置响应头
c.Writer.Header().Set("Content-Type", "application/json")
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
"MaxResponseBodySize": cfg.Server.SizeLimit,
})
}

View File

@@ -91,6 +91,18 @@
}
.status-container {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 5px;
}
.status-container p {
margin: 0px 5px;
}
.code {
position: relative;
padding-right: 0px;
@@ -136,7 +148,11 @@
</div>
<div class="tips">
<p>GitHub链接带不带协议头均可支持release、archive以及文件转换后链接均可使用</a></p>
<div class="status-container">
<p id="sizeLimitDisplay">文件大小限制: ...</p>
<p id="whiteListStatus">白名单状态: ...</p>
<p id="blackListStatus">黑名单状态: ...</p>
</div>
</div>
</div>
@@ -173,19 +189,57 @@
alert('链接已复制到剪贴板');
});
function fetchAPI() {
fetch(window.location.origin + '/api')
function fetchSizeLimit() {
fetch(window.location.origin + '/api/size_limit')
.then(response => response.json())
.then(data => {
const sizeLimitDisplay = document.getElementById('sizeLimitDisplay');
const sizeInMB = (data.MaxResponseBodySize / (1024 * 1024)).toFixed(0);
sizeLimitDisplay.textContent = `文件大小限制: ${sizeInMB} MB`;
sizeLimitDisplay.textContent = `文件大小限制: ${data.MaxResponseBodySize} MB`;
})
.catch(error => {
console.error('Error fetching API:', error);
});
}
function fetchWhiteList() {
fetch(window.location.origin + '/api/whitelist/status')
.then(response => response.json())
.then(data => {
const whiteListStatus = document.getElementById('whiteListStatus');
if (data.Whitelist) {
whiteListStatus.textContent = `白名单状态: 已开启`;
} else if (!data.Whitelist) {
whiteListStatus.textContent = `白名单状态: 已关闭`;
} else {
whiteListStatus.textContent = `白名单状态: 未知`;
}
})
.catch(error => {
console.error('Error fetching API:', error);
});
}
function fetchBlackList() {
fetch(window.location.origin + '/api/blacklist/status')
.then(response => response.json())
.then(data => {
const blackListStatus = document.getElementById('blackListStatus');
if (data.Blacklist) {
blackListStatus.textContent = `黑名单状态: 已开启`;
} else if (!data.Blacklist) {
blackListStatus.textContent = `黑名单状态: 已关闭`;
} else {
blackListStatus.textContent = `黑名单状态: 未知`;
}
})
.catch(error => {
console.error('Error fetching API:', error);
});
}
function fetchAPI() {
fetchSizeLimit();
fetchWhiteList();
fetchBlackList();
}
document.addEventListener('DOMContentLoaded', fetchAPI);
</script>
</body>
@@ -195,8 +249,7 @@
Copyright &copy; 2024 WJQSERVER-STUDIO
</p>
<p>
GitHub仓库地址<a
href="https://github.com/WJQSERVER-STUDIO/ghproxy">https://github.com/WJQSERVER-STUDIO/ghproxy</a>
GitHub仓库地址<a href="https://github.com/WJQSERVER-STUDIO/ghproxy">https://github.com/WJQSERVER-STUDIO/ghproxy</a>
</p>
<div id="visitor-info" style="text-align: center; margin-top: 15px;">
<p>您的IP地址: <span id="visitor-ip"></span></p>

View File

@@ -17,7 +17,13 @@ import (
"github.com/imroc/req/v3"
)
var logw = logger.Logw
// 日志模块
var (
logw = logger.Logw
logInfo = logger.LogInfo
LogWarning = logger.LogWarning
logError = logger.LogError
)
var exps = []*regexp.Regexp{
regexp.MustCompile(`^(?:https?://)?github\.com/([^/]+)/([^/]+)/(?:releases|archive)/.*`),
@@ -34,7 +40,7 @@ func NoRouteHandler(cfg *config.Config) gin.HandlerFunc {
matches := re.FindStringSubmatch(rawPath)
if len(matches) < 3 {
logw("Invalid URL: %s", rawPath)
LogWarning("Invalid URL: %s", rawPath)
c.String(http.StatusForbidden, "Invalid URL.")
return
}
@@ -45,24 +51,37 @@ func NoRouteHandler(cfg *config.Config) gin.HandlerFunc {
pathmatches := regexp.MustCompile(`^([^/]+)/([^/]+)/([^/]+)/.*`)
pathParts := pathmatches.FindStringSubmatch(matches[2])
if len(pathParts) < 4 {
logw("Invalid path: %s", rawPath)
LogWarning("Invalid path: %s", rawPath)
c.String(http.StatusForbidden, "Invalid path; expected username/repo.")
return
}
username := pathParts[2]
repo := pathParts[3]
logw("Blacklist Check > Username: %s, Repo: %s", username, repo)
LogWarning("Blacklist Check > Username: %s, Repo: %s", username, repo)
fullrepo := fmt.Sprintf("%s/%s", username, repo)
// 白名单检查
if cfg.Whitelist.Enabled {
whitelistpass := auth.CheckWhitelist(fullrepo)
if !whitelistpass {
errMsg := fmt.Sprintf("Whitelist Blocked repo: %s", fullrepo)
c.JSON(http.StatusForbidden, gin.H{"error": errMsg})
LogWarning(errMsg)
return
}
}
// 黑名单检查
if cfg.Blacklist.Enabled {
blacklistpass := auth.CheckBlacklist(fullrepo)
if blacklistpass {
errMsg := fmt.Sprintf("Blacklist Blocked repo: %s", fullrepo)
c.JSON(http.StatusForbidden, gin.H{"error": errMsg})
logw(errMsg)
LogWarning(errMsg)
return
}
}
matches = CheckURL(rawPath)
if matches == nil {
@@ -76,18 +95,18 @@ func NoRouteHandler(cfg *config.Config) gin.HandlerFunc {
if !auth.AuthHandler(c, cfg) {
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
logw("Unauthorized request: %s", rawPath)
LogWarning("Unauthorized request: %s", rawPath)
return
}
logw("Matches: %v", matches)
logInfo("Matches: %v", matches)
switch {
case exps[0].MatchString(rawPath), exps[1].MatchString(rawPath), exps[3].MatchString(rawPath), exps[4].MatchString(rawPath):
logw("%s Matched - USE proxy-chrome", rawPath)
logInfo("%s Matched - USE proxy-chrome", rawPath)
ProxyRequest(c, rawPath, cfg, "chrome")
case exps[2].MatchString(rawPath):
logw("%s Matched - USE proxy-git", rawPath)
logInfo("%s Matched - USE proxy-git", rawPath)
ProxyRequest(c, rawPath, cfg, "git")
default:
c.String(http.StatusForbidden, "Invalid input.")
@@ -98,33 +117,18 @@ func NoRouteHandler(cfg *config.Config) gin.HandlerFunc {
func ProxyRequest(c *gin.Context, u string, cfg *config.Config, mode string) {
method := c.Request.Method
logw("%s %s", method, u)
logInfo("%s %s", method, u)
client := req.C()
client := createHTTPClient(mode)
switch mode {
case "chrome":
client.SetUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36").
SetTLSFingerprintChrome().
ImpersonateChrome()
case "git":
client.SetUserAgent("git/2.33.1")
}
body, err := io.ReadAll(c.Request.Body)
body, err := readRequestBody(c)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to read request body: %v", err))
HandleError(c, err.Error())
return
}
defer c.Request.Body.Close()
req := client.R().SetBody(body)
for key, values := range c.Request.Header {
for _, value := range values {
req.SetHeader(key, value)
}
}
setRequestHeaders(c, req)
resp, err := SendRequest(req, method, u)
if err != nil {
@@ -134,17 +138,56 @@ func ProxyRequest(c *gin.Context, u string, cfg *config.Config, mode string) {
defer resp.Body.Close()
if err := HandleResponseSize(resp, cfg, c); err != nil {
logw("Error handling response size: %v", err)
LogWarning("Error handling response size: %v", err)
return
}
CopyResponseHeaders(resp, c, cfg)
c.Status(resp.StatusCode)
if _, err := io.Copy(c.Writer, resp.Body); err != nil {
logw("Failed to copy response body: %v", err)
if err := copyResponseBody(c, resp.Body); err != nil {
logError("Failed to copy response body: %v", err)
}
}
// createHTTPClient 创建并配置 HTTP 客户端
func createHTTPClient(mode string) *req.Client {
client := req.C()
switch mode {
case "chrome":
client.SetUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36").
SetTLSFingerprintChrome().
ImpersonateChrome()
case "git":
client.SetUserAgent("git/2.33.1")
}
return client
}
// readRequestBody 读取请求体
func readRequestBody(c *gin.Context) ([]byte, error) {
body, err := io.ReadAll(c.Request.Body)
if err != nil {
return nil, fmt.Errorf("failed to read request body: %v", err)
}
defer c.Request.Body.Close()
return body, nil
}
// setRequestHeaders 设置请求头
func setRequestHeaders(c *gin.Context, req *req.Request) {
for key, values := range c.Request.Header {
for _, value := range values {
req.SetHeader(key, value)
}
}
}
// copyResponseBody 复制响应体到客户端
func copyResponseBody(c *gin.Context, respBody io.Reader) error {
_, err := io.Copy(c.Writer, respBody)
return err
}
func SendRequest(req *req.Request, method, url string) (*req.Response, error) {
switch method {
case "GET":
@@ -156,7 +199,7 @@ func SendRequest(req *req.Request, method, url string) (*req.Response, error) {
case "DELETE":
return req.Delete(url)
default:
logw("Unsupported method: %s", method)
logInfo("Unsupported method: %s", method)
return nil, fmt.Errorf("unsupported method: %s", method)
}
}
@@ -168,14 +211,25 @@ func HandleResponseSize(resp *req.Response, cfg *config.Config, c *gin.Context)
if err == nil && size > cfg.Server.SizeLimit {
finalURL := resp.Request.URL.String()
c.Redirect(http.StatusMovedPermanently, finalURL)
logw("Redirecting to %s due to size limit (%d bytes)", finalURL, size)
return fmt.Errorf("response size exceeds limit")
LogWarning("Size limit exceeded: %s, Size: %d", finalURL, size)
return fmt.Errorf("size limit exceeded: %d", size)
}
}
return nil
}
func CopyResponseHeaders(resp *req.Response, c *gin.Context, cfg *config.Config) {
removeHeaders(resp)
copyHeaders(resp, c)
setCORSHeaders(c, cfg)
setDefaultHeaders(c)
}
// removeHeaders 移除指定的响应头
func removeHeaders(resp *req.Response) {
headersToRemove := map[string]struct{}{
"Content-Security-Policy": {},
"Referrer-Policy": {},
@@ -185,32 +239,45 @@ func CopyResponseHeaders(resp *req.Response, c *gin.Context, cfg *config.Config)
for header := range headersToRemove {
resp.Header.Del(header)
}
}
// copyHeaders 复制响应头到 Gin 上下文
func copyHeaders(resp *req.Response, c *gin.Context) {
for key, values := range resp.Header {
for _, value := range values {
c.Header(key, value)
}
}
}
c.Header("Access-Control-Allow-Origin", "")
// setCORSHeaders 设置 CORS 相关的响应头
func setCORSHeaders(c *gin.Context, cfg *config.Config) {
if cfg.CORS.Enabled {
c.Header("Access-Control-Allow-Origin", "*")
} else {
c.Header("Access-Control-Allow-Origin", "")
}
}
// setDefaultHeaders 设置默认的响应头
func setDefaultHeaders(c *gin.Context) {
c.Header("Age", "10")
c.Header("Cache-Control", "max-age=300")
}
func HandleError(c *gin.Context, message string) {
c.String(http.StatusInternalServerError, fmt.Sprintf("server error %v", message))
logw(message)
LogWarning(message)
}
func CheckURL(u string) []string {
for _, exp := range exps {
if matches := exp.FindStringSubmatch(u); matches != nil {
logw("URL matched: %s, Matches: %v", u, matches[1:])
logInfo("URL matched: %s, Matches: %v", u, matches[1:])
return matches[1:]
}
}
errMsg := fmt.Sprintf("Invalid URL: %s", u)
logw(errMsg)
LogWarning(errMsg)
return nil
}