diff --git a/.github/workflows/release-binary.yml b/.github/workflows/release-binary.yml new file mode 100644 index 0000000..e507504 --- /dev/null +++ b/.github/workflows/release-binary.yml @@ -0,0 +1,24 @@ +name: 🎉 Release Binary + +on: + push: + tags: + - '*' + workflow_dispatch: + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: projectdiscovery/actions/setup/go@v1 + + - uses: projectdiscovery/actions/goreleaser@v1 + with: + release: true + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" \ No newline at end of file diff --git a/.github/workflows/release-test.yml b/.github/workflows/release-test.yml new file mode 100644 index 0000000..1fee128 --- /dev/null +++ b/.github/workflows/release-test.yml @@ -0,0 +1,23 @@ +name: 🔨 Release Test + +on: + pull_request: + paths: + - '**.go' + - '**.mod' + workflow_dispatch: + +jobs: + release-test: + runs-on: ubuntu-latest-16-cores + steps: + - name: "Check out code" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: projectdiscovery/actions/setup/go@v1 + + - name: Release snapshot + uses: projectdiscovery/actions/goreleaser@v1 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ad0c4a --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.idea +dist +text +*.exe +*.pprof +*.csv +*.txt \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..d297832 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,42 @@ +before: + hooks: + - go mod tidy + +builds: + - main: cmd/riverPass/riverPass.go + binary: riverPass + env: + - CGO_ENABLED=0 + + goos: [windows,linux,darwin] + goarch: [amd64,386,arm,arm64] + ignore: + - goos: darwin + goarch: 386 + - goos: windows + goarch: arm + - goos: windows + goarch: arm64 + ldflags: + - "-s" + - "-w" + flags: + - -trimpath + +#- main: cmd/tmc/main.go +# binary: tmc +# id: annotate +# +# env: +# - CGO_ENABLED=0 +# +# goos: [linux] +# goarch: [amd64] + +archives: + - format: zip + name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}' + +checksum: + name_template: "{{ .ProjectName }}-linux-checksums.txt" + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dea3200 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +# Build +FROM golang:1.23.0-alpine AS builder +RUN apk add build-base +WORKDIR /app +COPY . /app +RUN go mod download +RUN go build cmd/riverPass/riverPass.go + +FROM alpine:3.18.3 +RUN apk add bind-tools ca-certificates +COPY --from=builder /app/riverPass /usr/local/bin/riverPass +RUN riverPass + +ENTRYPOINT ["riverPass"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e2e36d9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 wjlin0 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..061bc4d --- /dev/null +++ b/README.md @@ -0,0 +1,118 @@ +

riverPass 是一个用Go编写的瑞数WAF绕过工具。它利用了WebSocket协议,将请求发送的自身浏览器中,从而绕过了瑞数WAF的检测。

+ +

+ + +GitHub Repo stars + + + +

+ +# 特征 + +- 无需安装任意其他工具,只需导入`mitmproxy`证书即可使用 +- 可自定义设置下游代理 +- 支持联动Burp进行重放 + + +# 安装riverPass +## 自行编译 +riverPass自行编译,则需要**go1.23**才能安装成功。执行一下命令 + +```sh +go install -v github.com/wjlin0/riverPass/cmd/riverPass@latest +``` +## 二进制 +下载准备运行的[二进制文件](https://github.com/wjlin0/riverPass/releases/latest) + +- [macOS-arm64](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_macOS_arm64.zip) + +- [macOS-amd64](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_macOS_amd64.zip) + +- [linux-amd64](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_linux_amd64.zip) + +- [windows-amd64](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_windows_amd64.zip) + +- [windows-386](https://github.com/wjlin0/riverPass/releases/download/v1.0.0/riverPass_1.0.0_windows_386.zip) + + +# 用法 + +```shell +riverPass -h +``` +```yaml +riverPass 1.0.0 数瑞WAF绕过工具 + +Usage: + ./riverPass [flags] + +Flags: +输入: + -pp, -proxy-port int 代理监听端口 (default 8001) + -wp, -websocket-port int websocket监听端口 (default 10001) + -wt, -websocket-token string websocket通信密钥 (default "123456") + +代理: + -p, -proxy string[] 下游代理 + +版本: + -v, -version 输出版本 + -update 更新版本 + -duc, -disable-update-check 跳过自动检查更新 + + +EXAMPLES: + +运行 riverPass 并监听 8081端口: + $ riverPass -pp 8081 +运行 riverPass 设置下游代理: + $ riverPass -proxy http://127.0.0.1:7890 + + + +``` + +**注意**:在此之前你必须导入`mitmproxy`的证书(若没有 可随意运行一次 `riverPass`,它位于你主机的 `$HOME/.mitmproxy` 目录下) + +![img.png](./img/README/img.png) + +首先 运行 `riverPass` +```shell +$ riverPass -pp 8081 +``` +![img2.png](./img/README/img2.png) + +使用浏览器设置`Burp`代理 + +![image-20241017202645518](./img/README/image-20241017202645518.png) + +同时在`Burp` 设置目标 + +![image-20241017202734525](./img/README/image-20241017202734525.png) + +完成后,访问目标一次`https://www.189.cn/sc/` + +![image-20241017202921338](./img/README/image-20241017202921338.png) + +其中你会在请求记录中,得到以下结果,则表明此时已经完成代理 + +![image-20241017203033463](./img/README/image-20241017203033463.png) + +对某一个包进行重复攻击,加入以下请求头 + +```text +Req-Flag: 1 +``` + + + +![image-20241017204535406](./img/README/image-20241017204535406.png) + +其中,你可以在`Burp` 日志中,发现你刚刚重复的请求包 + +![image-20241017204644634](./img/README/image-20241017204644634.png) + +# 借鉴 +- https://github.com/R0A1NG/Botgate_bypass diff --git a/cmd/riverPass/riverPass.go b/cmd/riverPass/riverPass.go new file mode 100644 index 0000000..0284017 --- /dev/null +++ b/cmd/riverPass/riverPass.go @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "github.com/projectdiscovery/gologger" + "github.com/wjlin0/riverPass/pkg/runner" + "os" + "os/signal" +) + +func main() { + run, err := runner.NewRunner(runner.ParserOptions()) + if err != nil || run == nil { + if err != nil { + gologger.Print().Msg(fmt.Sprintf("unable to create Runner:%s", err.Error())) + os.Exit(-1) + } + return + } + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + go func() { + for range c { + gologger.Info().Msg("ctrl+c press: exiting") + os.Exit(-1) + } + }() + if err := run.RunEnumeration(); err != nil { + gologger.Fatal().Msgf("unable to run enumeration: %s", err.Error()) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2dd9ef2 --- /dev/null +++ b/go.mod @@ -0,0 +1,88 @@ +module github.com/wjlin0/riverPass + +go 1.23 + +require ( + github.com/google/uuid v1.6.0 + github.com/gorilla/websocket v1.5.3 + github.com/lqqyt2423/go-mitmproxy v1.8.5 + github.com/projectdiscovery/goflags v0.1.64 + github.com/projectdiscovery/gologger v1.1.27 + github.com/projectdiscovery/utils v0.2.14 + github.com/wjlin0/utils v0.0.36 +) + +require ( + aead.dev/minisign v0.2.0 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/VividCortex/ewma v1.2.0 // indirect + github.com/alecthomas/chroma/v2 v2.14.0 // indirect + github.com/andybalholm/brotli v1.0.6 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/charmbracelet/glamour v0.8.0 // indirect + github.com/charmbracelet/lipgloss v0.13.0 // indirect + github.com/charmbracelet/x/ansi v0.3.2 // indirect + github.com/cheggaaa/pb/v3 v3.1.4 // indirect + github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect + github.com/denisbrodbeck/machineid v1.0.1 // indirect + github.com/dlclark/regexp2 v1.11.4 // indirect + github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/go-github/v30 v30.1.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/gorilla/css v1.0.1 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/pgzip v1.2.5 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/logrusorgru/aurora v2.0.3+incompatible // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mholt/archiver/v3 v3.5.1 // indirect + github.com/microcosm-cc/bluemonday v1.0.27 // indirect + github.com/miekg/dns v1.1.56 // indirect + github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect + github.com/nwaples/rardecode v1.1.3 // indirect + github.com/pierrec/lz4/v4 v4.1.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/projectdiscovery/blackrock v0.0.1 // indirect + github.com/remeh/sizedwaitgroup v1.0.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect + github.com/satori/go.uuid v1.2.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/ulikunitz/xz v0.5.11 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + github.com/yuin/goldmark v1.7.4 // indirect + github.com/yuin/goldmark-emoji v1.0.3 // indirect + go.uber.org/atomic v1.11.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.11.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/djherbis/times.v1 v1.3.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a79e012 --- /dev/null +++ b/go.sum @@ -0,0 +1,241 @@ +aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk= +aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= +github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= +github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= +github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= +github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= +github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= +github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= +github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= +github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= +github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30= +github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo= +github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +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/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ= +github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= +github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= +github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= +github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +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.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lqqyt2423/go-mitmproxy v1.8.5 h1:F/Jt+Z5+LkJVMvjbRNtovCt6EuPArnumSOcRK9ImU7Q= +github.com/lqqyt2423/go-mitmproxy v1.8.5/go.mod h1:dSGnI17tVZ8dtYu9vnaIz7kxVwJNFH0CoNQwEQlTpxE= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= +github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= +github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= +github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= +github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= +github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 h1:yRZGarbxsRytL6EGgbqK2mCY+Lk5MWKQYKJT2gEglhc= +github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM= +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/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg= +github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= +github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= +github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM= +github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ= +github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss= +github.com/projectdiscovery/goflags v0.1.64 h1:FDfwdt9N97Hi8OuhbkDlKtVttpc/CRMIWQVa08VsHsI= +github.com/projectdiscovery/goflags v0.1.64/go.mod h1:3FyHIVQtnycNOc1LE3O1jj/XR5XuMdF9QfHd0ujhnX4= +github.com/projectdiscovery/gologger v1.1.27 h1:et/adsKS0jAkPZNUuZTJ+J4U/Ofadxu6Bj3NlUYs1e8= +github.com/projectdiscovery/gologger v1.1.27/go.mod h1:TXLvCbofuDyQlweDkSBanN083w51QKT4EmyKAVMQ+Ts= +github.com/projectdiscovery/utils v0.2.14 h1:n4zc6n1Z9EPZWu1T2CbhBwib81pShvTcCXtcBrmSny0= +github.com/projectdiscovery/utils v0.2.14/go.mod h1:V8t4qhy4MBOvNwZv7WNWT8P3WaU+ahprtGCMnHboLtI= +github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= +github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= +github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/wjlin0/utils v0.0.36 h1:LjPPSbAr/q/ptOyBTtKNBex/3Ac7WpE4kBYrPuOlD+E= +github.com/wjlin0/utils v0.0.36/go.mod h1:q5UFofjWzM8RrKpejgF83mor0YAttpOO12XZYp86X7Q= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= +github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4= +github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +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-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= +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.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +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.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o= +gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= +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= diff --git a/img/README/image-20241017202645518.png b/img/README/image-20241017202645518.png new file mode 100644 index 0000000..eda139b Binary files /dev/null and b/img/README/image-20241017202645518.png differ diff --git a/img/README/image-20241017202734525.png b/img/README/image-20241017202734525.png new file mode 100644 index 0000000..b18461b Binary files /dev/null and b/img/README/image-20241017202734525.png differ diff --git a/img/README/image-20241017202921338.png b/img/README/image-20241017202921338.png new file mode 100644 index 0000000..8b504de Binary files /dev/null and b/img/README/image-20241017202921338.png differ diff --git a/img/README/image-20241017203033463.png b/img/README/image-20241017203033463.png new file mode 100644 index 0000000..d9bf47a Binary files /dev/null and b/img/README/image-20241017203033463.png differ diff --git a/img/README/image-20241017204535406.png b/img/README/image-20241017204535406.png new file mode 100644 index 0000000..4ee2cc5 Binary files /dev/null and b/img/README/image-20241017204535406.png differ diff --git a/img/README/image-20241017204644634.png b/img/README/image-20241017204644634.png new file mode 100644 index 0000000..48cebef Binary files /dev/null and b/img/README/image-20241017204644634.png differ diff --git a/img/README/img.png b/img/README/img.png new file mode 100644 index 0000000..a72803b Binary files /dev/null and b/img/README/img.png differ diff --git a/img/README/img2.png b/img/README/img2.png new file mode 100644 index 0000000..7122d3e Binary files /dev/null and b/img/README/img2.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..96c472f --- /dev/null +++ b/index.html @@ -0,0 +1,82 @@ + \ No newline at end of file diff --git a/pkg/runner/banner.go b/pkg/runner/banner.go new file mode 100644 index 0000000..ff97890 --- /dev/null +++ b/pkg/runner/banner.go @@ -0,0 +1,42 @@ +package runner + +import ( + "github.com/projectdiscovery/gologger" + folderutil "github.com/projectdiscovery/utils/folder" + "os" + "path/filepath" +) + +const ( + banner = ` + _ + _____(_) _____ _____ ____ ____ ___________ + / ___/ / | / / _ \/ ___/_____/ __ \/ __ / ___/ ___/ + / / / /| |/ / __/ / /_____/ /_/ / /_/ (__ |__ ) +/_/ /_/ |___/\___/_/ / .___/\__,_/____/____/ +/_/ +` + Version = "1.0.0" + repoName = "riverByPass" + user = "wjlin0" +) + +var ( + DefaultRiverPassDir = filepath.Join(folderutil.HomeDirOrDefault("."), ".config", "riverPass") + DefaultConfig = filepath.Join(DefaultRiverPassDir, "config.yaml") +) + +func showBanner() { + gologger.Print().Msgf("%s\n", banner) + gologger.Print().Msgf("\t\t\twjlin0.com\n\n") + gologger.Print().Msgf("慎用。你要为自己的行为负责\n") + gologger.Print().Msgf("开发者不承担任何责任,也不对任何误用或损坏负责.\n") +} +func getVersionFromCallback() func() { + return func() { + showBanner() + gologger.Info().Msgf("RiverPass Engine Version: v%s", Version) + gologger.Info().Msgf("RiverPass Config Directory: %s", DefaultConfig) + os.Exit(0) + } +} diff --git a/pkg/runner/options.go b/pkg/runner/options.go new file mode 100644 index 0000000..92c2448 --- /dev/null +++ b/pkg/runner/options.go @@ -0,0 +1,108 @@ +package runner + +import ( + "bufio" + "fmt" + "github.com/projectdiscovery/goflags" + "github.com/projectdiscovery/gologger" + errorutil "github.com/projectdiscovery/utils/errors" + fileutil "github.com/projectdiscovery/utils/file" + proxyutils "github.com/projectdiscovery/utils/proxy" + "github.com/wjlin0/riverPass/pkg/types" + updateutils "github.com/wjlin0/utils/update" + "net/url" + "os" + "path/filepath" + "strings" +) + +func ParserOptions() *types.Options { + options := &types.Options{} + set := goflags.NewFlagSet() + set.SetDescription(fmt.Sprintf("riverPass %s 数瑞WAF绕过工具 ", Version)) + set.CreateGroup("Input", "输入", + set.IntVarP(&options.ProxyPort, "proxy-port", "pp", 8001, "代理监听端口"), + set.IntVarP(&options.WebSocketPort, "websocket-port", "wp", 10001, "websocket监听端口"), + set.StringVarP(&options.WebSocketToken, "websocket-token", "wt", "123456", "websocket通信密钥"), + ) + set.CreateGroup("Proxy", "代理", + set.StringSliceVarP(&options.Proxy, "proxy", "p", nil, "下游代理", goflags.FileCommaSeparatedStringSliceOptions), + ) + set.CreateGroup("Version", "版本", + set.CallbackVarP(getVersionFromCallback(), "version", "v", "输出版本"), + set.CallbackVar(updateutils.GetUpdateToolCallback(repoName, Version), "update", "更新版本"), + set.BoolVarP(&options.DisableUpdateCheck, "disable-update-check", "duc", false, "跳过自动检查更新"), + ) + set.SetCustomHelpText(`EXAMPLES: + +运行 riverPass 并监听 8081端口: + $ riverPass -pp 8081 +运行 riverPass 设置下游代理: + $ riverPass -proxy http://127.0.0.1:7890 +`) + set.SetConfigFilePath(filepath.Join(DefaultConfig)) + + _ = set.Parse() + // show banner + showBanner() + + err := ValidateRunEnumeration(options) + if err != nil { + gologger.Fatal().Msgf("options validation error: %s", err.Error()) + } + + return options +} +func ValidateRunEnumeration(options *types.Options) error { + var ( + err error + ) + + // loading the proxy server list from file or cli and test the connectivity + if err = loadProxyServers(options); err != nil { + return err + } + return nil +} +func loadProxyServers(options *types.Options) error { + var ( + file *os.File + err error + aliveProxy string + proxyURL *url.URL + ) + + if len(options.Proxy) == 0 { + return nil + } + proxyList := []string{} + for _, p := range options.Proxy { + if fileutil.FileExists(p) { + if file, err = os.Open(p); err != nil { + return fmt.Errorf("could not open proxy file: %w", err) + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + if proxy := scanner.Text(); strings.TrimSpace(proxy) == "" { + continue + } else { + proxyList = append(proxyList, proxy) + } + + } + } else { + proxyList = append(proxyList, p) + } + } + aliveProxy, err = proxyutils.GetAnyAliveProxy(30, proxyList...) + if err != nil { + return err + } + proxyURL, err = url.Parse(aliveProxy) + if err != nil { + return errorutil.WrapfWithNil(err, "failed to parse proxy got %v", err) + } + types.ProxyURL = proxyURL.String() + return nil +} diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go new file mode 100644 index 0000000..8cc86f6 --- /dev/null +++ b/pkg/runner/runner.go @@ -0,0 +1,177 @@ +package runner + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "github.com/lqqyt2423/go-mitmproxy/proxy" + "github.com/projectdiscovery/gologger" + "github.com/wjlin0/riverPass/pkg/types" + "github.com/wjlin0/riverPass/pkg/websocketbody" + "github.com/wjlin0/riverPass/pkg/websocketserver" + "net/http" + "strconv" + "strings" +) + +var jstext = " function socket_start() {\n // 避免重复连接\n if (typeof window.globalSocket121 !== 'undefined' && window.globalSocket121.readyState !== WebSocket.CLOSED) {\n return;\n }\n window.globalSocket121 = new WebSocket(\"ws://127.0.0.1:{{websocketPort}}\"),\n window.globalSocket121.onopen = function (t) {\n window.globalSocket121.send(\"{{websocketToken}}\");\n },\n window.globalSocket121.onmessage = function (t) {\n // 解析接收到的数据\n const data = JSON.parse(t.data); // 假设这里接收的是 JSON 格式的数据\n // 从 data 中提取 uuid\n const uuid = data.uuid; // 从数据中提取 UUID\n var method = data.method;\n var url = data.url;\n var body = atob(data.body);\n var headers = JSON.parse(atob(data.headers)) || {};\n // alert(headers);\n // 将 headers 设置为请求头\n const fetchOptions = {\n method: method,\n headers: new Headers(headers),\n };\n\n if (body !== \"\") {\n fetchOptions.body = body;\n }\n\n fetch(url, fetchOptions)\n .then(response => {\n const statusCode = response.status;\n\n // 将 Headers 对象转换为字典格式\n const responseHeaders = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value; // 将 headers 转换为键值对的形式存储在对象中\n });\n\n return response.text().then(body => ({\n statusCode: statusCode,\n headers: responseHeaders, // 使用字典格式的 headers\n body: body,\n }));\n })\n .then(({ statusCode, headers, body }) => {\n const textEncoder = new TextEncoder();\n const bodyAsBytes = textEncoder.encode(body);\n const bodyAsBase64 = btoa(String.fromCharCode(...bodyAsBytes));\n\n\n // 发送响应回去,包括 uuid\n const responseMessage = JSON.stringify({\n uuid: uuid, // 传递回去的 UUID\n statusCode: statusCode,\n headers: btoa(JSON.stringify(headers)), // 保持 headers 为字典格式\n body:bodyAsBase64,\n });\n console.log(btoa(JSON.stringify(headers)))\n window.globalSocket121.send(responseMessage);\n })\n .catch((e) => {\n // 处理错误,发送失败信息\n const errorMessage = JSON.stringify({\n uuid: uuid,\n statusCode: 500,\n headers: \"\",\n body: e.toString(),\n });\n window.globalSocket121.send(errorMessage);\n });\n };\n }\n\n // 确保只有在 WebSocket 没有连接的情况下启动\n if (typeof window.globalSocket121 === 'undefined' || window.globalSocket121.readyState === WebSocket.CLOSED) {\n socket_start();\n }" + +type Runner struct { + Websocket *websocketserver.WebSocketServer + Proxy *proxy.Proxy + Options *types.Options + proxy.BaseAddon +} + +func (r *Runner) Request(flow *proxy.Flow) { + // 得到所有的请求头 + headers := flow.Request.Header + flag := headers.Get("Req-Flag") + if flag == "1" { + //gologger.Info().Msgf("Request: %s", flow.Request.URL.String()) + // 修改请求头 + r.HandleDelayedRequest(flow) + } +} +func (r *Runner) HandleDelayedRequest(flow *proxy.Flow) { + w := websocketbody.NewWebsocketBody() + headers := make(map[string]string) + for k, _ := range flow.Request.Header { + if k == "Req-Flag" { + headers["Res-Flag"] = "1" + continue + } + headers[k] = flow.Request.Header.Get(k) + } + marshal, _ := json.Marshal(headers) + + w.Headers = base64.StdEncoding.EncodeToString(marshal) + + w.Method = flow.Request.Method + w.URL = flow.Request.URL.String() + w.Body = base64.StdEncoding.EncodeToString(flow.Request.Body) + + // TODO: 传递 WebsocketReflectorBody 给 服务器 + body, _ := w.Marshal() + //gologger.Info().Msgf("发送数据: %s", string(body)) + + c2, err := r.Websocket.SendMessageToClient(w.GetURL(), string(body)) + headers = make(map[string]string) + + if err != nil { + flow.Response = &proxy.Response{ + StatusCode: 500, + Body: []byte(err.Error()), + Header: make(http.Header), + } + + } else { + // 获取 c2 通道数据 + msg := <-c2 + err = w.UnMarshal([]byte(msg)) + if err != nil { + flow.Response = &proxy.Response{ + StatusCode: 500, + Body: []byte(err.Error()), + Header: make(http.Header), + } + return + } + code := w.StatusCode + if code == 500 { + gologger.Error().Msgf("Error: %s", string(w.Body)) + flow.Response = &proxy.Response{ + StatusCode: 500, + Body: []byte(fmt.Sprintf("Error: %s", string(w.Body))), + Header: make(http.Header), + } + return + } + + hs := make(map[string]string) + + h, _ := base64.StdEncoding.DecodeString(w.Headers) + + err := json.Unmarshal(h, &hs) + if err != nil { + flow.Response = &proxy.Response{ + StatusCode: 500, + Body: []byte(err.Error()), + Header: make(http.Header), + } + return + } + //gologger.Info().Msgf("接收到数据: %s", string(w.Body)) + bs, _ := base64.StdEncoding.DecodeString(w.Body) + + flow.Response = &proxy.Response{ + StatusCode: code, + Body: bs, + Header: make(http.Header), + } + for k, _ := range hs { + flow.Response.Header.Set(k, hs[k]) + } + return + } + +} + +func (r *Runner) Response(flow *proxy.Flow) { + flow.Response.ReplaceToDecodedBody() + // 得到所有的响应头 + headers := flow.Request.Header + flag := headers.Get("Req-Flag") + ResFlag := headers.Get("Res-Flag") + if flag == "" && ResFlag == "" { + // 修改响应头 + contentType := flow.Response.Header.Get("Content-Type") + switch { + // 判断是否是 text/html 开头 + case strings.HasPrefix(contentType, "text/html"): + flow.Response.Body = append(flow.Response.Body, []byte("")...) + case strings.HasPrefix(contentType, "application/javascript"): + flow.Response.Body = append(flow.Response.Body, []byte(jstext)...) + } + + if flow.Response.Header.Get("Content-Security-Policy") != "" { + // 删除 Content-Security-Policy + flow.Response.Header.Del("Content-Security-Policy") + } + + flow.Response.Header.Set("Content-Length", strconv.Itoa(len(flow.Response.Body))) + } + if ResFlag == "1" { + gologger.Info().Msgf("%s Method: %s Content-Length: %d Status: %d", flow.Request.URL.String(), flow.Request.Method, len(flow.Response.Body), flow.Response.StatusCode) + } +} + +func NewRunner(opts *types.Options) (*Runner, error) { + ws := websocketserver.NewWebSocketServer(opts.WebSocketToken) + jstext = strings.ReplaceAll(jstext, "{{websocketPort}}", fmt.Sprintf("%d", opts.WebSocketPort)) + jstext = strings.ReplaceAll(jstext, "{{websocketToken}}", opts.WebSocketToken) + proxyOpts := &proxy.Options{ + Addr: fmt.Sprintf(":%d", opts.ProxyPort), + StreamLargeBodies: 1024 * 1024 * 5, + Upstream: types.ProxyURL, + SslInsecure: true, + } + ps, err := proxy.NewProxy(proxyOpts) + if err != nil { + return nil, err + } + run := &Runner{ + Websocket: ws, + Proxy: ps, + Options: opts, + } + ps.AddAddon(run) + return run, nil + +} + +func (r *Runner) RunEnumeration() error { + go r.Websocket.Start(fmt.Sprintf(":%d", r.Options.WebSocketPort)) + panic(r.Proxy.Start()) + return nil +} diff --git a/pkg/types/Proxy.go b/pkg/types/Proxy.go new file mode 100644 index 0000000..562804a --- /dev/null +++ b/pkg/types/Proxy.go @@ -0,0 +1,4 @@ +package types + +// ProxyURL is the proxy url +var ProxyURL string diff --git a/pkg/types/options.go b/pkg/types/options.go new file mode 100644 index 0000000..14e9a2a --- /dev/null +++ b/pkg/types/options.go @@ -0,0 +1,11 @@ +package types + +import "github.com/projectdiscovery/goflags" + +type Options struct { + WebSocketPort int `json:"webSocketPort"` + WebSocketToken string `json:"webSocketToken"` + ProxyPort int `json:"proxyPort"` + Proxy goflags.StringSlice `json:"proxy"` + DisableUpdateCheck bool `json:"disableUpdateCheck"` +} diff --git a/pkg/websocketbody/websocketbody.go b/pkg/websocketbody/websocketbody.go new file mode 100644 index 0000000..f686388 --- /dev/null +++ b/pkg/websocketbody/websocketbody.go @@ -0,0 +1,36 @@ +package websocketbody + +import ( + "encoding/json" + "fmt" + "github.com/google/uuid" + "net/url" +) + +type WebsocketBody struct { + Headers string `json:"headers"` + Method string `json:"method"` + URL string `json:"url"` + Body string `json:"body"` + StatusCode int `json:"statusCode"` + UUID string `json:"uuid"` +} + +func NewWebsocketBody() *WebsocketBody { + return &WebsocketBody{ + UUID: uuid.New().String(), + } +} + +func (w *WebsocketBody) GetURL() string { + parse, _ := url.Parse(w.URL) + return fmt.Sprintf("%s://%s", parse.Scheme, parse.Host) +} + +func (w *WebsocketBody) Marshal() ([]byte, error) { + return json.Marshal(w) +} +func (w *WebsocketBody) UnMarshal(data []byte) error { + + return json.Unmarshal(data, w) +} diff --git a/pkg/websocketserver/websocketserver.go b/pkg/websocketserver/websocketserver.go new file mode 100644 index 0000000..154cec8 --- /dev/null +++ b/pkg/websocketserver/websocketserver.go @@ -0,0 +1,132 @@ +package websocketserver + +import ( + "fmt" + "github.com/gorilla/websocket" + "github.com/projectdiscovery/gologger" + "net/http" + "sync" +) + +type Client struct { + Conn *websocket.Conn + Messages chan string // 为每个客户端设置独立的消息通道 +} + +// WebSocketServer 处理结构体 +type WebSocketServer struct { + allClients map[string]*Client + mutex sync.Mutex + token string // 每次初始化时传入的 token +} + +// NewWebSocketServer 创建一个新的 WebSocket 服务器实例 +func NewWebSocketServer(token string) *WebSocketServer { + return &WebSocketServer{ + allClients: make(map[string]*Client), + token: token, + } +} + +// HandleClient 处理 WebSocket 客户端连接 +func (wsServer *WebSocketServer) HandleClient(conn *websocket.Conn, r *http.Request) { + defer conn.Close() + + // 接收 token + _, receivedToken, err := conn.ReadMessage() + if err != nil { + fmt.Println("Error reading token:", err) + return + } + + // 校验 token + if string(receivedToken) != wsServer.token { + fmt.Println("Invalid token, closing connection") + conn.Close() + return + } + + //clientAddress := conn.RemoteAddr().String() + var origin string + // 从 http 头中 获取origin + //gologger.Info().Msg(r.Header.Get("Origin")) + origin = r.Header.Get("Origin") + // gologger.Info().Msgf("get websocket: {%s}") + + client := &Client{ + Conn: conn, + Messages: make(chan string), // 初始化消息通道 + } + // 将连接加入到 clients map + wsServer.mutex.Lock() + wsServer.allClients[origin] = client + wsServer.mutex.Unlock() + + //gologger.Info().Msgf("WebSocket client connected: IP=%s, Origin=%s\n", clientAddress, origin) + // 发送欢迎消息 + //successMessage := base64.StdEncoding.EncodeToString([]byte("success!")) + //if err := conn.WriteMessage(websocket.TextMessage, []byte(successMessage)); err != nil { + // gologger.Error().Msgf("Error sending welcome message: %s", err) + // return + //} + + // 处理消息 + for { + _, msg, err := conn.ReadMessage() + if err != nil { + //fmt.Printf("WebSocket client disconnected: Origin=%s\n", origin) + wsServer.mutex.Lock() + // 关闭通道 + close(client.Messages) + // 删除 + delete(wsServer.allClients, origin) + wsServer.mutex.Unlock() + break + } + + decodedMessage := string(msg) + //gologger.Info().Msgf("Received message from client: %s", decodedMessage) + client.Messages <- decodedMessage + + } +} + +func (wsServer *WebSocketServer) SendMessageToClient(origin string, msg string) (chan string, error) { + wsServer.mutex.Lock() + defer wsServer.mutex.Unlock() + + client, exists := wsServer.allClients[origin] + if !exists { + return nil, fmt.Errorf("client not found: %s", origin) + } + + err := client.Conn.WriteMessage(websocket.TextMessage, []byte(msg)) + if err != nil { + fmt.Println("Error sending message:", err) + client.Conn.Close() + close(client.Messages) + delete(wsServer.allClients, origin) // 移除失效的客户端 + return nil, err + } + return client.Messages, nil +} + +// ServeHTTP WebSocket 路由处理函数 +func (wsServer *WebSocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + upgrader := websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { return true }, + } + + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + gologger.Error().Msgf("WebSocket upgrade failed: %s", err) + return + } + wsServer.HandleClient(conn, r) +} +func (ws *WebSocketServer) Start(addr string) { + http.HandleFunc("/", ws.ServeHTTP) + + gologger.Info().Msgf("WebSocket server started at %s", addr) + http.ListenAndServe(addr, nil) +}