Compare commits

...

78 Commits

Author SHA1 Message Date
WJQSERVER
52fdaf5f81 24w18b 2024-10-17 10:43:36 +08:00
WJQSERVER
d6b8f2b812 hotfix 2024-10-17 09:57:14 +08:00
WJQSERVER
00d2113904 hotfix 2024-10-17 00:04:29 +08:00
WJQSERVER
670bca31ca 24w18a 2024-10-16 23:52:07 +08:00
WJQSERVER
f77de0d37a 24w18a 2024-10-16 23:32:25 +08:00
WJQSERVER
1c18ccc363 24w18a 2024-10-16 21:51:24 +08:00
WJQSERVER
a386304d42 update 2024-10-16 17:45:51 +08:00
WJQSERVER
a1fdd0f477 1.5.2 2024-10-16 15:19:10 +08:00
WJQSERVER
e94a98668e 24w17b 2024-10-16 13:08:58 +08:00
WJQSERVER
22273f166c 24w17b 2024-10-16 12:54:21 +08:00
WJQSERVER
2187514da7 24w17b 2024-10-16 12:48:02 +08:00
WJQSERVER
ac859c39a6 24w17a 2024-10-16 06:31:36 +08:00
WJQSERVER
518bbf2600 24w17a 2024-10-16 06:27:28 +08:00
WJQSERVER
d383c2d2a6 24w17a 2024-10-16 06:25:59 +08:00
WJQSERVER
6d055e19e3 1.5.1 2024-10-14 16:16:56 +08:00
WJQSERVER
18f78385f3 1.5.1 2024-10-14 16:16:04 +08:00
WJQSERVER
2edb6f6dd7 Merge branch 'main' of https://github.com/WJQSERVER-STUDIO/ghproxy 2024-10-14 13:49:33 +08:00
WJQSERVER
d42ed119d4 24w16a 2024-10-14 13:49:30 +08:00
dependabot[bot]
072f73fdce Bump github.com/imroc/req/v3 from 3.47.0 to 3.48.0 (#6)
Bumps [github.com/imroc/req/v3](https://github.com/imroc/req) from 3.47.0 to 3.48.0. - [Release notes](https://github.com/imroc/req/releases) - [提交](https://github.com/imroc/req/compare/v3.47.0...v3.48.0) --- updated-dependencies: - dependency-name: github.com/imroc/req/v3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-14 13:38:56 +08:00
WJQSERVER
02b4857334 Merge branch 'main' of https://github.com/WJQSERVER-STUDIO/ghproxy 2024-10-13 09:41:20 +08:00
WJQSERVER
a156f1b2e7 update 2024-10-13 09:41:18 +08:00
里見 灯花
1d8c3914d2 Update README.md 2024-10-13 08:50:57 +08:00
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
33 changed files with 1246 additions and 346 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,5 +1,174 @@
# 更新日志
24w18b
---
- PRE-RELEASE: 此版本是预发布版本,请勿在生产环境中使用
- CHANGE: 经团队考量,移除 Docker 代理功能,若造成了不便敬请谅解
- CHANGE: 修改日志检查周期
24w18a
---
- PRE-RELEASE: 此版本是预发布版本,请勿在生产环境中使用
- CHANGE: 改进Docker 代理
- CHANGE: 改进前端页面的copy提示,弃用alert提示
v1.5.2
---
- FIX: 修正flag传入问题
- CHANGE: 去除/路径重定向,改为返回403,并记录对应请求日志
- CHANGE: 优化Proxy模块的日志记录,记录请求详细信息
24w17b
---
- PRE-RELEASE: 此版本是v1.5.2的预发布版本,请勿在生产环境中使用
- FIX: 修正flag传入问题
- CHANGE: 去除/路径重定向,改为返回403,并记录对应请求日志
- CHANGE: 优化Proxy模块的日志记录,记录请求详细信息
24w17a
---
- PRE-RELEASE: 此版本是v1.5.2的预发布版本,请勿在生产环境中使用
- FIX: 初步修正flag传入问题,但仍有可能存在其他问题
v1.5.1
---
- CHANGE: 优化代码结构,提升性能
- CHANGE: Bump github.com/imroc/req/v3 from 3.48.0 to 3.49.0 by @dependabot in https://github.com/WJQSERVER-STUDIO/ghproxy/pull/7
- ADD: 新增一键部署脚本,简化二进制文件部署流程
24w16a
---
- PRE-RELEASE: 此版本是v1.5.1的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: Bump github.com/imroc/req/v3 from 3.47.0 to 3.48.0 by @dependabot in https://github.com/WJQSERVER-STUDIO/ghproxy/pull/6
- ADD: 新增一键部署脚本,简化二进制文件部署流程
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: 优化代码结构,提升性能
@@ -8,6 +177,7 @@ v1.3.1
24w10a
---
- PRE-RELEASE: 此版本是v1.3.1的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- CHANGE: 剃刀计划,减少多余日志输出
- CHANGE: 调整缓存参数
@@ -24,12 +194,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
@@ -38,6 +210,7 @@ v1.3.0
24w08b
---
- PRE-RELEASE: 此版本是v1.3.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,提升性能
- ADD & CHANGE: 新增仓库黑名单功能,改进Auth模块
- ADD: 新增blacklist.yaml文件,用于配置仓库黑名单
@@ -54,6 +227,7 @@ v1.2.0
24w08a
---
- PRE-RELEASE: 此版本是v1.2.0的预发布版本,请勿在生产环境中使用
- CHANGE: 同步更新logger模块与golang-temp项目定义的开发规范保持一致
- ADD: 新增日志翻转功能
@@ -65,12 +239,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
@@ -85,6 +261,7 @@ v1.1.0
24w06b
---
- PRE-RELEASE: 此版本是v1.1.0的预发布版本,请勿在生产环境中使用
- CHANGE: 优化代码结构,对main函数进行模块化,提升可读性
- CHANGE: Docker代理功能移至DEV版本内,保证稳定性
- ADD&CHANGE: 增加Auth(用户鉴权)模块,并改进其的错误处理与日志记录
@@ -94,6 +271,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项目作为底层构建,标准化日志与配置模块
@@ -101,6 +279,7 @@ v1.0.0
24w06a
---
- PRE-RELEASE: 此版本是v1.0.0的预发布版本,请勿在生产环境中使用
- CHANGE: 与v1.0.0版本同步
v0.2.0
@@ -112,21 +291,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
@@ -135,6 +318,7 @@ v0.1.7
24w03b
---
- PRE-RELEASE: 此版本是v0.1.7的预发布版本,请勿在生产环境中使用
- CHANGE: 合入上游(wjqserver/caddy:latest)安全更新, 增强镜像安全性
v0.1.6
@@ -144,6 +328,7 @@ v0.1.6
24w03a
---
- PRE-RELEASE: 此版本是v0.1.6的预发布版本,请勿在生产环境中使用
- CHANGE: 改进Docker代理相关Caddy配置
- ADD: 新增跨域配置选项
@@ -154,16 +339,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: 优化代码结构,提升性能
@@ -171,7 +357,7 @@ v0.1.4
24w01b
---
标志着项目正式进入自主开发阶段
- PRE-RELEASE: 此版本是v0.1.4的预发布版本,请勿在生产环境中使用
- ADD: 新增外部文件配置功能
- ADD: 新增日志功能
- CHANGE: 优化代码结构,提升性能
@@ -179,12 +365,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 @@
24w10a
24w18b

View File

@@ -5,7 +5,9 @@
使用Go实现的GHProxy,用于加速部分地区Github仓库的拉取,支持速率限制,用户鉴权,支持Docker部署
[DEMO](ghproxy.1888866.xyz)
[DEMO](https://ghproxy.1888866.xyz)
[TG讨论群组](https://t.me/ghproxy_go)
## 项目说明
@@ -16,7 +18,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,43 +53,52 @@ 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
参看[docker-compose.yml](https://github.com/WJQSERVER-STUDIO/ghproxy/blob/main/docker/compose/docker-compose.yml)
### 二进制文件部署(不推荐)
一键部署脚本:
```bash
wget -O install.sh https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/deploy/install.sh && chmod +x install.sh &&./install.sh
```
## 配置说明
### 外部配置文件
本项目采用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: 5 # 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 +111,21 @@ blacklist:
"blacklist": [
"test/test1",
"example/repo2",
"another/repo3"
"another/*"
]
}
```
### 白名单配置
白名单配置位于config/whitelist.json,格式如下:
```json
{
"whitelist": [
"test/test1",
"example/repo2",
"another/*"
]
}
```
@@ -120,14 +145,16 @@ example.com {
}
```
### 前端页面
![ghproxy-demo-v1.5.0.png](https://webp.wjqserver.com/ghproxy/ghproxy-demo-v1.5.0.png)
## TODO & DEV
### TODO
- [x] 允许更多参数通过config结构传入
- [x] 改进程序效率
- [x] 用户鉴权
- [x] 仓库黑名单
- [x] 仓库白名单
### DEV

View File

@@ -7,21 +7,16 @@
| 版本 | 是否支持 |
| --- | --- |
| 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 或更高版本。
### 用户须知
本项目为开源项目,开发者不对使用本项目造成的任何损失或问题承担责任。用户需自行评估并承担使用本项目的风险。
使用本项目,请遵循 **[WSL (WJQSERVER-STUDIO LICENSE)](https://wjqserver-studio.github.io/LICENSE/LICENSE.html)** 协议。
本项目所有文件均受到 WSL (WJQSERVER-STUDIO LICENSE) 协议保护,任何人不得在任何情况下以非 WSL (WJQSERVER-STUDIO LICENSE) 协议内规定的方式使用,复制,修改,编译,发布,分发,再许可,或者出售本项目的任何部分。
## 报告漏洞
如果您发现本项目存在安全漏洞,请通过发送ISSUES或尝试联系项目维护者来报告。请在您的报告中包含以下信息:

View File

@@ -1 +1 @@
1.3.1
1.5.2

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,40 +4,51 @@ 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
}
}

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

@@ -76,6 +76,8 @@
import error_page
import encode
import rate_limit 60
header Age 10
header Cache-Control "max-age=300"
route / {
root /data/www
file_server
@@ -86,21 +88,10 @@
file_server
import cache 0s 24h
}
handle_errors {
@redirects `{err.status_code} in [301, 302, 307]`
reverse_proxy @redirects {
header_up Location {http.response.header.Location}
}
}
route /v2* {
reverse_proxy https://registry-1.docker.io {
header_up Host registry-1.docker.io
header_up X-Real-IP {remote}
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
header_up X-Forwarded-Proto {scheme}
header_up Authorization {http.request.header.Authorization}
}
route /api* {
rate_limit 15r/m 10000 429
import cache 0s 6h
}
}

View File

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

View File

@@ -1,52 +1,53 @@
package config
import (
"os"
"gopkg.in/yaml.v3"
"github.com/BurntSushi/toml"
)
type Config struct {
Server struct {
Port int `yaml:"port"`
Host string `yaml:"host"`
SizeLimit int `yaml:"sizelimit"`
} `yaml:"server"`
Log struct {
LogFilePath string `yaml:"logfilepath"`
MaxLogSize int `yaml:"maxlogsize"`
} `yaml:"logger"`
CORS struct {
Enabled bool `yaml:"enabled"`
} `yaml:"cors"`
Auth struct {
Enabled bool `yaml:"enabled"`
AuthToken string `yaml:"authtoken"`
} `yaml:"auth"`
Blacklist struct {
Enabled bool `yaml:"enabled"`
BlacklistFile string `yaml:"blacklistfile"`
} `yaml:"blacklist"`
Server ServerConfig
Log LogConfig
CORS CORSConfig
Auth AuthConfig
Blacklist BlacklistConfig
Whitelist WhitelistConfig
}
// LoadConfig 从 YAML 配置文件加载配置
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 := loadYAML(filePath, &config); err != nil {
if _, err := toml.DecodeFile(filePath, &config); err != nil {
return nil, err
}
return &config, nil
}
// LoadyamlConfig 从 YAML 配置文件加载配置
func loadYAML(filePath string, out interface{}) error {
data, err := os.ReadFile(filePath)
if err != nil {
return err
}
return yaml.Unmarshal(data, out)
}

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

@@ -1,24 +0,0 @@
# Server Configuration
server:
port: 8080
host: "127.0.0.1"
sizelimit: 131072000 # 125MB
# Logging Configuration
logger:
logfilepath: "/data/ghproxy/log/ghproxy.log"
maxlogsize: 5 # MB
# CORS Configuration
cors:
enabled: true
# Authentication Configuration
auth:
enabled: false
authtoken: "test"
# Blacklist Configuration
blacklist:
enabled: true
blacklistfile: "/data/ghproxy/config/blacklist.json"

7
config/whitelist.json Normal file
View File

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

23
deploy/config.toml Normal file
View File

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

13
deploy/ghproxy.service Normal file
View File

@@ -0,0 +1,13 @@
[Unit]
Description=Github Proxy Service
After=network.target
[Service]
ExecStart=/bin/bash -c '/root/data/ghproxy/ghproxy -cfg /root/data/ghproxy/config/config.toml > /root/data/ghproxy/log/run.log 2>&1'
WorkingDirectory=/root/data/ghproxy
Restart=always
User=root
Group=root
[Install]
WantedBy=multi-user.target

83
deploy/install-dev.sh Normal file
View File

@@ -0,0 +1,83 @@
# /bin/bash
# install packages
install() {
if [ $# -eq 0 ]; then
echo "ARGS NOT FOUND"
return 1
fi
for package in "$@"; do
if ! command -v "$package" &>/dev/null; then
if command -v dnf &>/dev/null; then
dnf -y update && dnf install -y "$package"
elif command -v yum &>/dev/null; then
yum -y update && yum -y install "$package"
elif command -v apt &>/dev/null; then
apt update -y && apt install -y "$package"
elif command -v apk &>/dev/null; then
apk update && apk add "$package"
else
echo "UNKNOWN PACKAGE MANAGER"
return 1
fi
fi
done
return 0
}
# 安装依赖包
install curl wget sed
# 查看当前架构是否为linux/amd64或linux/arm64
ARCH=$(uname -m)
if [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "aarch64" ]; then
echo " $ARCH 架构不被支持"
exit 1
fi
# 重写架构值,改为amd64或arm64
if [ "$ARCH" == "x86_64" ]; then
ARCH="amd64"
elif [ "$ARCH" == "aarch64" ]; then
ARCH="arm64"
fi
read -p "请输入程序监听的端口(默认8080): " PORT
if [ -z "$PORT" ]; then
PORT=8080
fi
# 创建目录
mkdir -p /root/data/ghproxy
mkdir -p /root/data/ghproxy/config
mkdir -p /root/data/ghproxy/log
# 获取最新版本号
VERSION=$(curl -s https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/DEV-VERSION)
wget -O /root/data/ghproxy/VERSION https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/DEV-VERSION
# 下载ghproxy
wget -O /root/data/ghproxy/ghproxy https://github.com/WJQSERVER-STUDIO/ghproxy/releases/download/$VERSION/ghproxy-linux-$ARCH
chmod +x /root/data/ghproxy/ghproxy
# 下载配置文件
if [ -f /root/data/ghproxy/config/config.toml ]; then
echo "配置文件已存在, 跳过下载"
else
wget -O /root/data/ghproxy/config/config.toml https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/deploy/config.toml
fi
# 替换 port = 8080
sed -i "s/port = 8080/port = $PORT/g" /root/data/ghproxy/config/config.toml
# 下载systemd服务文件
wget -O /etc/systemd/system/ghproxy.service https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/deploy/ghproxy.service
# 启动ghproxy
systemctl daemon-reload
systemctl enable ghproxy
systemctl start ghproxy
echo "ghproxy 安装成功, 监听端口为 $PORT"

83
deploy/install.sh Normal file
View File

@@ -0,0 +1,83 @@
# /bin/bash
# install packages
install() {
if [ $# -eq 0 ]; then
echo "ARGS NOT FOUND"
return 1
fi
for package in "$@"; do
if ! command -v "$package" &>/dev/null; then
if command -v dnf &>/dev/null; then
dnf -y update && dnf install -y "$package"
elif command -v yum &>/dev/null; then
yum -y update && yum -y install "$package"
elif command -v apt &>/dev/null; then
apt update -y && apt install -y "$package"
elif command -v apk &>/dev/null; then
apk update && apk add "$package"
else
echo "UNKNOWN PACKAGE MANAGER"
return 1
fi
fi
done
return 0
}
# 安装依赖包
install curl wget sed
# 查看当前架构是否为linux/amd64或linux/arm64
ARCH=$(uname -m)
if [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "aarch64" ]; then
echo " $ARCH 架构不被支持"
exit 1
fi
# 重写架构值,改为amd64或arm64
if [ "$ARCH" == "x86_64" ]; then
ARCH="amd64"
elif [ "$ARCH" == "aarch64" ]; then
ARCH="arm64"
fi
read -p "请输入程序监听的端口(默认8080): " PORT
if [ -z "$PORT" ]; then
PORT=8080
fi
# 创建目录
mkdir -p /root/data/ghproxy
mkdir -p /root/data/ghproxy/config
mkdir -p /root/data/ghproxy/log
# 获取最新版本号
VERSION=$(curl -s https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/VERSION)
wget -O /root/data/ghproxy/VERSION https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/VERSION
# 下载ghproxy
wget -O /root/data/ghproxy/ghproxy https://github.com/WJQSERVER-STUDIO/ghproxy/releases/download/$VERSION/ghproxy-linux-$ARCH
chmod +x /root/data/ghproxy/ghproxy
# 下载配置文件
if [ -f /root/data/ghproxy/config/config.toml ]; then
echo "配置文件已存在, 跳过下载"
else
wget -O /root/data/ghproxy/config/config.toml https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/deploy/config.toml
fi
# 替换 port = 8080
sed -i "s/port = 8080/port = $PORT/g" /root/data/ghproxy/config/config.toml
# 下载systemd服务文件
wget -O /etc/systemd/system/ghproxy.service https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/deploy/ghproxy.service
# 启动ghproxy
systemctl daemon-reload
systemctl enable ghproxy
systemctl start ghproxy
echo "ghproxy 安装成功, 监听端口为 $PORT"

13
deploy/uninstall.sh Normal file
View File

@@ -0,0 +1,13 @@
# /bin/bash
# 停止 ghproxy 服务
systemctl stop ghproxy
# 删除 ghproxy 服务
systemctl disable ghproxy
rm /etc/systemd/system/ghproxy.service
# 删除 ghproxy 文件夹
rm -r /root/data/ghproxy
echo "ghproxy 已成功卸载"

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

46
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.48.0
)
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
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
gopkg.in/yaml.v3 v3.0.1 // indirect
)

109
go.sum
View File

@@ -1,50 +1,60 @@
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
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/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
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.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
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/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/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.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=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
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=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.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/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/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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-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=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/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.48.0 h1:IYuMGetuwLzOOTzDCquDqs912WNwpsPK0TBXWPIvoqg=
github.com/imroc/req/v3 v3.48.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.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=
@@ -57,8 +67,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/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/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
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=
@@ -69,54 +82,48 @@ github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5D
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/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 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
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/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/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/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4=
golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
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-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=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/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/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=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
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.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
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/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
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.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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
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=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

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

@@ -18,15 +18,17 @@ var (
logger *log.Logger
logChannel = make(chan string, 100)
quitChannel = make(chan struct{})
logFileMutex sync.Mutex // 保护 logFile 的互斥锁
logFileMutex sync.Mutex
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
@@ -38,7 +40,6 @@ func Init(logFilePath string, maxLogsize int) error {
return nil
}
// logWorker 处理日志记录
func logWorker() {
for {
select {
@@ -51,18 +52,37 @@ func logWorker() {
}
}
// Log 直接记录日志的函数
func Log(customMessage string) {
logChannel <- customMessage
}
// Logw 用于格式化日志记录
// 格式化日志记录
func Logw(format string, args ...interface{}) {
message := fmt.Sprintf(format, args...)
Log(message)
}
// Close 关闭日志文件
// 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)
}
// 关闭日志文件
func Close() {
logFileMutex.Lock()
defer logFileMutex.Unlock()
@@ -78,7 +98,7 @@ func Close() {
func monitorLogSize(logFilePath string, maxLogsize int) {
var maxLogsizeBytes int64 = int64(maxLogsize) * 1024 * 1024 // 最大日志文件大小单位为MB
for {
time.Sleep(600 * time.Second) // 每10分钟检查一次
time.Sleep(120 * time.Minute) // 每120分钟检查一次日志文件大小
logFileMutex.Lock()
info, err := logFile.Stat()
logFileMutex.Unlock()

73
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,50 +17,61 @@ import (
var (
cfg *config.Config
logw = logger.Logw
router *gin.Engine
configfile = "/data/ghproxy/config/config.yaml"
configfile = "/data/ghproxy/config/config.toml"
cfgfile string
)
// 日志模块
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() {
flag.StringVar(&cfgfile, "cfg", configfile, "config file path")
}
func loadConfig() {
var err error
// 初始化配置
cfg, err = config.LoadConfig(configfile)
cfg, err = config.LoadConfig(cfgfile)
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
fmt.Println("Config File Path: ", cfgfile)
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("Config File Path: ", cfgfile)
logInfo("Loaded config: %v\n", cfg)
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()
flag.Parse()
loadConfig()
setupLogger()
LoadBlacklist(cfg)
setupLogger(cfg)
Loadlist(cfg)
// 设置 Gin 模式
gin.SetMode(gin.ReleaseMode)
@@ -68,16 +79,14 @@ 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")
// 返回403错误
c.String(http.StatusForbidden, "403 Forbidden This route is not allowed to access.")
// 记录访问者IP UA METHOD
LogWarning("Forbidden: IP:%s UA:%s METHOD:%s", c.ClientIP(), c.Request.UserAgent(), c.Request.Method)
})
// 未匹配路由处理
@@ -90,16 +99,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;
@@ -119,6 +131,28 @@
text-align: center;
line-height: 0.5;
}
#toast {
position: fixed;
top: 10%;
/* 垂直居中 */
left: 50%;
/* 水平居中 */
transform: translate(-50%, -50%);
/* 调整使其中心对齐 */
background-color: rgba(97, 97, 97, 0.7);
/* 半透明黑色背景 */
color: white;
/* 字体颜色 */
padding: 15px 20px;
/* 内边距 */
border-radius: 10px;
/* 圆角 */
font-size: 16px;
/* 字体大小 */
z-index: 1000;
/* 确保显示在其他元素上面 */
}
</style>
</head>
@@ -131,14 +165,22 @@
<button class="btn rounded-button" id="formatButton">获取文件链接</button>
<div class="code" id="outputBlock">
<button class="copy-button" id="copyButton" onclick="copyCode(this)">Copy</button>
<button class="copy-button" id="copyButton">Copy</button>
<pre id="formattedLinkOutput"></pre>
</div>
<div class="tips">
<p>GitHub链接带不带协议头均可支持release、archive以及文件转换后链接均可使用</a></p>
<p id="sizeLimitDisplay">文件大小限制: ...</p>
<div class="status-container">
<p id="sizeLimitDisplay">文件大小限制: ...</p>
<p id="whiteListStatus">白名单状态: ...</p>
<p id="blackListStatus">黑名单状态: ...</p>
</div>
</div>
</div>
<div id="toast" style="display:none;">
链接已复制到剪贴板
</div>
<script>
function formatGithubLink() {
@@ -170,22 +212,71 @@
window.getSelection().addRange(range);
document.execCommand('copy');
window.getSelection().removeAllRanges();
alert('链接已复制到剪贴板');
//alert('链接已复制到剪贴板');
showToast('链接已复制到剪贴板');
});
function fetchAPI() {
fetch(window.location.origin + '/api')
function showToast(message) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.style.display = 'block';
setTimeout(() => {
toast.style.display = 'none';
}, 3000); // 3秒后隐藏
}
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 +286,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> <br><a href="https://t.me/ghproxy_go">Telegram交流群</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,23 +51,36 @@ 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
}
}
// 黑名单检查
blacklistpass := auth.CheckBlacklist(fullrepo)
if blacklistpass {
errMsg := fmt.Sprintf("Blacklist Blocked repo: %s", fullrepo)
c.JSON(http.StatusForbidden, gin.H{"error": errMsg})
logw(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})
LogWarning(errMsg)
return
}
}
matches = CheckURL(rawPath)
@@ -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,19 @@ 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)
// 记录 IP Method URL UA
logInfo("%s %s %s %s", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"))
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 +139,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/129.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 +200,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 +212,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 +240,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
}