From 749093c8d551aaecdad006dfe2eb93e56e0ad129 Mon Sep 17 00:00:00 2001 From: WJQSERVER Date: Tue, 24 Sep 2024 17:16:21 +0800 Subject: [PATCH] update --- .github/workflows/build-dev.yml | 77 ++++++++ .github/workflows/build.yml | 77 ++++++++ DEV-VERSION | 1 + LICENSE | 107 +++++++++++ README.md | 2 +- VERSION | 1 + caddyfile/dev/Caddyfile | 99 ++++++++++ caddyfile/release/Caddyfile | 99 ++++++++++ config/config.go | 31 ++++ config/config.yaml | 7 + docker/compose/docker-compose.yml | 11 ++ docker/dockerfile/dev/Dockerfile | 21 +++ docker/dockerfile/release/Dockerfile | 21 +++ go.mod | 50 +++++ go.sum | 122 ++++++++++++ init.sh | 20 ++ logger/logger.go | 44 +++++ main.go | 267 +++++++++++++++++++++++++++ pages/favicon.ico | Bin 0 -> 3262 bytes pages/index.html | 226 +++++++++++++++++++++++ 20 files changed, 1282 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build-dev.yml create mode 100644 .github/workflows/build.yml create mode 100644 DEV-VERSION create mode 100644 LICENSE create mode 100644 VERSION create mode 100644 caddyfile/dev/Caddyfile create mode 100644 caddyfile/release/Caddyfile create mode 100644 config/config.go create mode 100644 config/config.yaml create mode 100644 docker/compose/docker-compose.yml create mode 100644 docker/dockerfile/dev/Dockerfile create mode 100644 docker/dockerfile/release/Dockerfile create mode 100644 go.mod create mode 100644 go.sum create mode 100644 init.sh create mode 100644 logger/logger.go create mode 100644 main.go create mode 100644 pages/favicon.ico create mode 100644 pages/index.html diff --git a/.github/workflows/build-dev.yml b/.github/workflows/build-dev.yml new file mode 100644 index 0000000..f189391 --- /dev/null +++ b/.github/workflows/build-dev.yml @@ -0,0 +1,77 @@ +name: Build Dev + +on: + workflow_dispatch: + push: + branches: + - 'main' + paths: + - 'DEV-VERSION' + +jobs: + build: + runs-on: ubuntu-latest + env: + OUTPUT_BINARY: ghproxy + OUTPUT_ARCHIVE: ghproxy.tar.gz + GO_VERSION: 1.23.1 + + steps: + - uses: actions/checkout@v3 + - name: Load VERSION + run: | + if [ -f DEV-VERSION ]; then + echo "VERSION=$(cat DEV-VERSION)" >> $GITHUB_ENV + else + echo "DEV-VERSION file not found!" && exit 1 + fi + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + - name: Build + run: | + go build -o ${{ env.OUTPUT_BINARY }} ./main.go + - name: Package + run: | + tar -czvf ${{ env.OUTPUT_ARCHIVE }} ./${{ env.OUTPUT_BINARY }} + - name: Upload to GitHub Artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{ env.OUTPUT_BINARY }} + path: | + ./${{ env.OUTPUT_ARCHIVE }} + ./${{ env.OUTPUT_BINARY }} + + docker: + runs-on: ubuntu-latest + needs: build + env: + IMAGE_NAME: wjqserver/ghproxy-test + DOCKERFILE: docker/dockerfile/dev/Dockerfile + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: 构建镜像 + uses: docker/build-push-action@v5 + with: + file: ./${{ env.DOCKERFILE }} + platforms: linux/amd64 + push: true + tags: | + ${{ env.IMAGE_NAME }}:${{ env.VERSION }} + ${{ env.IMAGE_NAME }}:dev diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..851b16c --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,77 @@ +name: Build + +on: + workflow_dispatch: + push: + branches: + - 'main' + paths: + - 'VERSION' + +jobs: + build: + runs-on: ubuntu-latest + env: + OUTPUT_BINARY: ghproxy + OUTPUT_ARCHIVE: ghproxy.tar.gz + GO_VERSION: 1.23.1 + + steps: + - uses: actions/checkout@v3 + - name: Load VERSION + run: | + if [ -f VERSION ]; then + echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + else + echo "VERSION file not found!" && exit 1 + fi + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GO_VERSION }} + - name: Build + run: | + go build -o ${{ env.OUTPUT_BINARY }} ./main.go + - name: Package + run: | + tar -czvf ${{ env.OUTPUT_ARCHIVE }} ./${{ env.OUTPUT_BINARY }} + - name: Upload to GitHub Artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{ env.OUTPUT_BINARY }} + path: | + ./${{ env.OUTPUT_ARCHIVE }} + ./${{ env.OUTPUT_BINARY }} + + docker: + runs-on: ubuntu-latest + needs: build # 确保这个作业在 build 作业完成后运行 + env: + IMAGE_NAME: wjqserver/ghproxy-test # 定义镜像名称变量 + DOCKERFILE: docker/dockerfile/release/Dockerfile + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: 构建镜像 + uses: docker/build-push-action@v5 + with: + file: ./Dockerfile + platforms: linux/amd64 + push: true + tags: | + ${{ env.IMAGE_NAME }}:${{ env.VERSION }} + ${{ env.IMAGE_NAME }}:latest diff --git a/DEV-VERSION b/DEV-VERSION new file mode 100644 index 0000000..c853cd0 --- /dev/null +++ b/DEV-VERSION @@ -0,0 +1 @@ +24w01a \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..477d35a --- /dev/null +++ b/LICENSE @@ -0,0 +1,107 @@ +WJQserver Studio 开源许可证 +版本 1.2 + +版权所有 © WJQserver Studio 2024 + +定义 +许可:指在本许可证内定义的使用、复制、分发与修改的条款与要求。 +授权方:指拥有版权的个人或组织,亦或是拥有版权的个人或组织所指派的实体。 +您:指行使本许可授予的权限的个人或法律实体。 +开源与自由软件 +本项目为开源软件,允许用户在遵循本许可证的前提下访问和使用源代码。 +本项目不等同于自由软件,使用权限受到本许可证条款的限制。 +强调版权所有,所有权利均由 WJQserver Studio 保留。 +许可证条款 +1. 使用权限 +1.1 您被授予在私人环境中自由使用本软件的权限。 + +1.2 您可以在不修改关键声明的前提下进行商用。 + +2. 复制与分发 +2.1 您可以复制和分发本软件的原始版本,前提是必须保留所有版权声明和本许可证。 + +3. 修改权限 +3.1 您可以在非商业用途下修改本软件,前提是继承本许可证并保留原版权声明。 + +3.2 禁止在修改后进行商业用途。 + +4. 专利引用 +4.1 若项目被专利相关引用,必须保留来源声明。 + +4.2 若为商业场景,需按照商用处理。 + +5. 免责声明 +5.1 本软件按“现状”提供,不提供任何明示或暗示的保证,包括但不限于适销性、特定用途适用性及非侵权性。 + +5.2 在任何情况下,授权方均不对因使用或无法使用本软件而产生的任何直接、间接、偶然、特殊、惩罚性或后果性损害负责,即使已被告知可能发生此类损害。 + +5.3 用户需根据当地法律对待本项目,确保遵守所有适用法规。 + +6. 许可证期限 +6.1 本许可证自2024年开始生效,有效期暂为无限。 + +6.2 项目所有方有权修改许可证相关条例而不另行通知。 + +条款修订 +7.1 授权方保留随时修改本许可证条款的权利,以便更好地适应法律和技术的发展。 + +7.2 修订后的条款将在发布时生效,继续使用本软件即表示接受修订后的条款。 + +其他 +8.1 本许可证不影响您作为最终用户的法定权利。 + +8.2 若本许可证的某些条款被认定为不可执行,其余条款仍然有效。 + +WJQserver Studio Open Source License +Version 1.2 + +Copyright © WJQserver Studio 2024 + +Definitions +License: The terms and conditions defined within this license for use, copying, distribution, and modification. +Licensor: The individual or organization holding the copyright, or the entity designated by them. +You: The individual or legal entity exercising the permissions granted by this license. +Open Source vs. Free Software +This project is open source, allowing users to access and use the source code under the terms of this license. +This project is not equivalent to free software; usage rights are restricted by this license. +Copyright is emphasized, with all rights reserved by WJQserver Studio. +License Terms +1. Usage Rights +1.1 You are granted the right to use this software freely in a private environment. + +1.2 You may use it commercially without modifying key statements. + +2. Copying and Distribution +2.1 You may copy and distribute the original version of this software, provided all copyright notices and this license are retained. + +3. Modification Rights +3.1 You may modify this software for non-commercial purposes, provided you inherit this license and retain the original copyright notice. + +3.2 Modifications cannot be used commercially. + +4. Patent References +4.1 If the project is cited in patent-related contexts, the source statement must be retained. + +4.2 For commercial scenarios, it must be treated as a commercial use. + +5. Disclaimer +5.1 This software is provided "as is", without any express or implied warranties, including but not limited to merchantability, fitness for a particular purpose, and non-infringement. + +5.2 In no event shall the licensor be liable for any direct, indirect, incidental, special, punitive, or consequential damages arising out of the use or inability to use this software, even if advised of the possibility of such damages. + +5.3 Users must comply with all applicable laws regarding this project. + +6. License Duration +6.1 This license is effective from 2024, with an indefinite duration. + +6.2 The project owner reserves the right to modify the license terms without prior notice. + +Amendments +7.1 The licensor reserves the right to amend this license at any time to better adapt to legal and technological developments. + +7.2 Revised terms become effective upon publication, and continued use of the software indicates acceptance of the revised terms. + +Miscellaneous +8.1 This license does not affect your statutory rights as an end user. + +8.2 If any provision of this license is held to be unenforceable, the remaining provisions shall remain in effect. diff --git a/README.md b/README.md index dac08a6..fcff2c4 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# ghproxy +# golang-temp \ No newline at end of file diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..8a9ecc2 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.0.1 \ No newline at end of file diff --git a/caddyfile/dev/Caddyfile b/caddyfile/dev/Caddyfile new file mode 100644 index 0000000..fddd047 --- /dev/null +++ b/caddyfile/dev/Caddyfile @@ -0,0 +1,99 @@ +{ + debug + http_port 80 + https_port 443 + order cache before rewrite + cache { + cache_name W-Cache + } + log { + level INFO + output file /data/caddy/log/caddy.log { + roll_size 5MB + roll_keep 10 + } + } +} + +(log) { + log { + format transform `{request>headers>X-Forwarded-For>[0]:request>remote_ip} - {user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"` { + time_format "02/Jan/2006:15:04:05 -0700" + } + output file /data/caddy/log/{args.0}/access.log { + roll_size 5MB + roll_keep 10 + roll_keep_for 24h + } + } +} + +(error_page) { + handle_errors { + rewrite * /{err.status_code}.html + root * /data/caddy/pages/errors + file_server + } +} + +(encode) { + encode { + zstd best + br 5 v2 + gzip 5 + minimum_length 512 + } +} + +(cache) { + cache { + allowed_http_verbs GET + stale {args.0} + ttl {args.1} + } +} + +(header_realip) { + header_up X-Real-IP {remote_host} + header_up X-Real-IP {http.request.header.CF-Connecting-IP} + header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} + 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 + } +} + +:80 { + reverse_proxy { + to 127.0.0.1:8080 + import header_realip + } + import log go + import cache 0s 600s + import error_page + import encode + route /* { + rate_limit {remote.ip} 60r/m 10000 429 + } + route / { + root /data/www + file_server + import cache 0s 24h + } + route /favicon.ico { + root /data/www + file_server + import cache 60s 24h + } +} + +import /data/caddy/config.d/* diff --git a/caddyfile/release/Caddyfile b/caddyfile/release/Caddyfile new file mode 100644 index 0000000..fddd047 --- /dev/null +++ b/caddyfile/release/Caddyfile @@ -0,0 +1,99 @@ +{ + debug + http_port 80 + https_port 443 + order cache before rewrite + cache { + cache_name W-Cache + } + log { + level INFO + output file /data/caddy/log/caddy.log { + roll_size 5MB + roll_keep 10 + } + } +} + +(log) { + log { + format transform `{request>headers>X-Forwarded-For>[0]:request>remote_ip} - {user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"` { + time_format "02/Jan/2006:15:04:05 -0700" + } + output file /data/caddy/log/{args.0}/access.log { + roll_size 5MB + roll_keep 10 + roll_keep_for 24h + } + } +} + +(error_page) { + handle_errors { + rewrite * /{err.status_code}.html + root * /data/caddy/pages/errors + file_server + } +} + +(encode) { + encode { + zstd best + br 5 v2 + gzip 5 + minimum_length 512 + } +} + +(cache) { + cache { + allowed_http_verbs GET + stale {args.0} + ttl {args.1} + } +} + +(header_realip) { + header_up X-Real-IP {remote_host} + header_up X-Real-IP {http.request.header.CF-Connecting-IP} + header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} + 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 + } +} + +:80 { + reverse_proxy { + to 127.0.0.1:8080 + import header_realip + } + import log go + import cache 0s 600s + import error_page + import encode + route /* { + rate_limit {remote.ip} 60r/m 10000 429 + } + route / { + root /data/www + file_server + import cache 0s 24h + } + route /favicon.ico { + root /data/www + file_server + import cache 60s 24h + } +} + +import /data/caddy/config.d/* diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..ae3089a --- /dev/null +++ b/config/config.go @@ -0,0 +1,31 @@ +package config + +import ( + "os" + + "gopkg.in/yaml.v3" +) + +type Config struct { + Port int `yaml:"port"` + Host string `yaml:"host"` + SizeLimit int `yaml:"sizelimit"` + LogFilePath string `yaml:"logfilepath"` + CORSOrigin bool `yaml:"CorsAllowOrigins"` + Auth bool `yaml:"auth"` + AuthToken string `yaml:"authtoken"` +} + +// LoadConfig 从 YAML 配置文件加载配置 +func LoadConfig(filePath string) (*Config, error) { + var config Config + data, err := os.ReadFile(filePath) + if err != nil { + return nil, err + } + err = yaml.Unmarshal(data, &config) + if err != nil { + return nil, err + } + return &config, nil +} diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000..7c0b891 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,7 @@ +port: 8080 +host: "127.0.0.1" +sizelimit: 131072000 # 125MB +logfilepath: "/data/ghproxy/log/ghproxy-0rtt.log" +CorsAllowOrigins: true +auth: true +authtoken: "test" \ No newline at end of file diff --git a/docker/compose/docker-compose.yml b/docker/compose/docker-compose.yml new file mode 100644 index 0000000..2c3c2f9 --- /dev/null +++ b/docker/compose/docker-compose.yml @@ -0,0 +1,11 @@ +version: '3.9' +services: + ghproxy: + image: 'wjqserver/ghproxy:latest' + restart: always + volumes: + - './ghproxy/log/run:/data/ghproxy/log' + - './ghproxy/log/caddy:/data/caddy/log' + - './ghproxy/config:/data/ghproxy/config' + ports: + - '7210:80' diff --git a/docker/dockerfile/dev/Dockerfile b/docker/dockerfile/dev/Dockerfile new file mode 100644 index 0000000..89c2d18 --- /dev/null +++ b/docker/dockerfile/dev/Dockerfile @@ -0,0 +1,21 @@ +FROM wjqserver/caddy:daily + +ARG USER=WJQSERVER-STUDIO +ARG REPO=ghproxy +ARG APPLICATION=ghproxy + +RUN mkdir -p /data/www +RUN mkdir -p /data/${APPLICATION}/config +RUN mkdir -p /data/${APPLICATION}/log +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 +RUN wget -O /usr/local/bin/init.sh https://raw.githubusercontent.com/${USER}/${REPO}/main/init.sh +RUN chmod +x /data/${APPLICATION}/${APPLICATION} +RUN chmod +x /usr/local/bin/init.sh + +CMD ["/usr/local/bin/init.sh"] + diff --git a/docker/dockerfile/release/Dockerfile b/docker/dockerfile/release/Dockerfile new file mode 100644 index 0000000..a705995 --- /dev/null +++ b/docker/dockerfile/release/Dockerfile @@ -0,0 +1,21 @@ +FROM wjqserver/caddy:latest + +ARG USER=WJQSERVER-STUDIO +ARG REPO=ghproxy +ARG APPLICATION=ghproxy + +RUN mkdir -p /data/www +RUN mkdir -p /data/${APPLICATION}/config +RUN mkdir -p /data/${APPLICATION}/log +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 +RUN wget -O /usr/local/bin/init.sh https://raw.githubusercontent.com/${USER}/${REPO}/main/init.sh +RUN chmod +x /data/${APPLICATION}/${APPLICATION} +RUN chmod +x /usr/local/bin/init.sh + +CMD ["/usr/local/bin/init.sh"] + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..311935d --- /dev/null +++ b/go.mod @@ -0,0 +1,50 @@ +module ghproxy + +go 1.23.1 + +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/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/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-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/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/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/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/mod v0.21.0 // indirect + golang.org/x/net v0.29.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 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..027815e --- /dev/null +++ b/go.sum @@ -0,0 +1,122 @@ +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/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/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/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/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-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-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/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/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/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/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/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= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +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/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= +github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y= +github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E= +github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM= +github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= +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/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= +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/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/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= +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= diff --git a/init.sh b/init.sh new file mode 100644 index 0000000..0561c76 --- /dev/null +++ b/init.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +APPLICATON=ghproxy + +if [ ! -f /data/caddy/config/Caddyfile ]; then + cp /data/caddy/Caddyfile /data/caddy/config/Caddyfile +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 & + +while [[ true ]]; do + sleep 1 +done + diff --git a/logger/logger.go b/logger/logger.go new file mode 100644 index 0000000..2fb4449 --- /dev/null +++ b/logger/logger.go @@ -0,0 +1,44 @@ +// logger/logger.go +package logger + +import ( + "fmt" + "log" + "os" + "time" +) + +var logFile *os.File +var logger *log.Logger + +// Init 初始化日志记录器,接受日志文件路径作为参数 +func Init(logFilePath string) error { + var err error + logFile, err = os.OpenFile(logFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + return err + } + logger = log.New(logFile, "", 0) // 不使用默认前缀 + return nil +} + +// Log 直接记录日志的函数,带有时间戳 +func Log(customMessage string) { + if logger != nil { + timestamp := time.Now().Format("02/Jan/2006:15:04:05 -0700") // 使用自定义时间格式 + logger.Println(timestamp + " - " + customMessage) + } +} + +// Logw 用于格式化日志记录 +func Logw(format string, args ...interface{}) { + message := fmt.Sprintf(format, args...) // 格式化消息 + Log(message) // 记录日志 +} + +// Close 关闭日志文件 +func Close() { + if logFile != nil { + logFile.Close() + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..a554df0 --- /dev/null +++ b/main.go @@ -0,0 +1,267 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "regexp" + "strconv" + "strings" + + "ghproxy/config" + "ghproxy/logger" + + "github.com/gin-gonic/gin" + "github.com/imroc/req/v3" +) + +var cfg *config.Config +var logw = logger.Logw +var router *gin.Engine + +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/([^/]+)/.+?/.+`), + } +) + +func loadConfig() { + var err error + // 初始化配置 + cfg, err = config.LoadConfig("/data/go/config/config.yaml") + if err != nil { + log.Fatalf("Failed to load config: %v", err) + } + fmt.Printf("Loaded config: %v\n", cfg) +} + +func setupLogger() { + // 初始化日志模块 + var err error + err = logger.Init(cfg.LogFilePath) // 传递日志文件路径 + if err != nil { + log.Fatalf("Failed to initialize logger: %v", err) + } + logw("Logger initialized") + logw("Init Completed") +} + +func init() { + loadConfig() + setupLogger() + + // 设置 Gin 模式 + gin.SetMode(gin.ReleaseMode) + + // 初始化路由 + router = gin.Default() + + // 定义路由 + 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(noRouteHandler(cfg)) +} + +func main() { + // 启动服务器 + err := router.Run(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)) + if err != nil { + log.Fatalf("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.SizeLimit, + }) +} + +func authHandler(c *gin.Context) bool { + if cfg.Auth { + authToken := c.Query("auth_token") + return authToken == cfg.AuthToken + } + return true +} + +func noRouteHandler(config *config.Config) gin.HandlerFunc { + return func(c *gin.Context) { + rawPath := strings.TrimPrefix(c.Request.URL.RequestURI(), "/") + re := regexp.MustCompile(`^(http:|https:)?/?/?(.*)`) + matches := re.FindStringSubmatch(rawPath) + + rawPath = "https://" + matches[2] + + matches = checkURL(rawPath) + if matches == nil { + c.String(http.StatusForbidden, "Invalid input.") + return + } + + if exps[1].MatchString(rawPath) { + rawPath = strings.Replace(rawPath, "/blob/", "/raw/", 1) + } + + if !authHandler(c) { + c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"}) + logw("Unauthorized request: %s", rawPath) + return + } + + // 日志记录 + logw("Request: %s %s", c.Request.Method, rawPath) + logw("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) + proxyRequest(c, rawPath, config, "chrome") + case exps[2].MatchString(rawPath): + logw("%s Matched - USE proxy-git", rawPath) + proxyRequest(c, rawPath, config, "git") + default: + c.String(http.StatusForbidden, "Invalid input.") + return + } + } +} + +func proxyRequest(c *gin.Context, u string, config *config.Config, mode string) { + method := c.Request.Method + logw("%s Method: %s", u, method) + + 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") + } + + // 读取请求体 + body, err := io.ReadAll(c.Request.Body) + if err != nil { + handleError(c, fmt.Sprintf("Failed to read request body: %v", err)) + 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) + } + } + + // 发送请求并处理响应 + resp, err := sendRequest(req, method, u) + if err != nil { + handleError(c, fmt.Sprintf("Failed to send request: %v", err)) + return + } + defer resp.Body.Close() + + // 检查响应内容长度并处理重定向 + if err := handleResponseSize(resp, config, c); err != nil { + logw("Error handling response size: %v", err) + return + } + + copyResponseHeaders(resp, c, config) + c.Status(resp.StatusCode) + if _, err := io.Copy(c.Writer, resp.Body); err != nil { + logw("Failed to copy response body: %v", err) + } +} + +func sendRequest(req *req.Request, method, url string) (*req.Response, error) { + switch method { + case "GET": + return req.Get(url) + case "POST": + return req.Post(url) + case "PUT": + return req.Put(url) + case "DELETE": + return req.Delete(url) + default: + return nil, fmt.Errorf("unsupported method: %s", method) + } +} + +func handleResponseSize(resp *req.Response, config *config.Config, c *gin.Context) error { + contentLength := resp.Header.Get("Content-Length") + if contentLength != "" { + size, err := strconv.Atoi(contentLength) + if err == nil && size > config.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") + } + } + return nil +} + +func copyResponseHeaders(resp *req.Response, c *gin.Context, config *config.Config) { + headersToRemove := []string{"Content-Security-Policy", "Referrer-Policy", "Strict-Transport-Security"} + + for _, header := range headersToRemove { + resp.Header.Del(header) + } + + for key, values := range resp.Header { + for _, value := range values { + c.Header(key, value) + } + } + + if config.CORSOrigin { + c.Header("Access-Control-Allow-Origin", "*") + } else { + c.Header("Access-Control-Allow-Origin", "") + } +} + +func handleError(c *gin.Context, message string) { + c.String(http.StatusInternalServerError, fmt.Sprintf("server error %v", message)) + logw(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:]) + return matches[1:] + } + } + logw("Invalid URL: %s", u) + return nil +} diff --git a/pages/favicon.ico b/pages/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..9c04d31ade74151073f9c5d87d6dc75f72d58111 GIT binary patch literal 3262 zcmc(g%PaO<6vux!?)QX)(#zx+G4Yz1oB=`xk4_k~2{*$u+lPAVnFQnV84` zu2mwhy4uW$JqDx_t)3gx3@R6g~s8NNtS-h{~Q4w9s4>n zn0*F-6UM&!nXe3$@bU5S=;&xgMaB2;-+yyhYHDg}Y3cCr@ZsU16bNB<_nD@dmpGrh zySwG(<$ivCoSBD*hx5r4U{3GDiKCcPfz)pG~&Pj=jZ1?KR>e(6ig|c9A#czT@9W*jRK#= z#l=HILn9+2EiEm*y}cwHA0N*=7z{8zwQ{4cYtYx%Cvip$uBud3RdsQ3v9+~DwO3bH zcXoDygM$Td06+45R&auXK3*#T z>EmETVTlkDH1$!$`ucjnl-Cf!Pfbmc`Qzi`{{BAsZ)|Lk|MvEFNJxl*DTFd9Dk^f) z*NL2;pNEBo8H&K2ot@-UR#rARI0)FMF&0f+hk;KVVB8zT3aOza_){Os&37|Dv2 zmX^jX_4V~-J|Q9D^70ZEZGmxaZcg)#2p{(fGjy(jK^mvAu@QiZgM-Dz#lcEXPhVbM zzQ4bJd3gc+af2QG=l1q?U|_)MltpL1Ak8W3EHX1Q(Nz9XQBjeRk$jevlz_z0lw(G* zmX?+R0s=Ve*w|Qqe}C?ORA5` zSW{EuUSFXX78VRqbS?%&lf2U4;RBPhU{nd1qT{%lh+JJm6rINo*lb+R{QSI0L&p>z z9?qixX)dA&D!QRxU0p>)M1YjIkj>4_LIQR*mKGNm4Mjvc%+b*i zOZJUx3r$T;fVIbe-6ivnf@ zT^&}ni;0N|^9!Qn83}}$PgRVU+uz@>%-xGCoC$Gqa>7PJLqk;rlezgMfx5c7gM$Nz zWc3wsvm=AQzP_g06DTVyiylQA%*e=~_07!8@Vf@y + + + + + + + Github文件加速 + + + + + + +
+

Github文件加速

+
+ +
+ + +
+ +

+        
+
+

GitHub链接带不带协议头均可,支持release、archive以及文件,转换后链接均可使用。

+

文件大小限制: ...

+
+
+ + + + + + + \ No newline at end of file