Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04242e7d4a | ||
|
|
f6afe0fa12 | ||
|
|
30f9069e45 | ||
|
|
431781c798 | ||
|
|
f1b914fab9 | ||
|
|
c63a498034 | ||
|
|
82a20236e1 | ||
|
|
4e74171dc5 | ||
|
|
dfa5a65ba5 | ||
|
|
913e0f78db | ||
|
|
fc505b0733 | ||
|
|
06ae3d0555 | ||
|
|
58e07fe4aa | ||
|
|
d1f92000db | ||
|
|
6f921f6c97 | ||
|
|
94b46d32e4 | ||
|
|
07eb014d64 | ||
|
|
f9301ef0f4 | ||
|
|
8b30f83075 | ||
|
|
3242a49b27 | ||
|
|
b88bcd9113 | ||
|
|
f298901b17 | ||
|
|
71fc28cf22 | ||
|
|
ce8d76056f | ||
|
|
3ca242d086 | ||
|
|
9d7a5b4598 | ||
|
|
8e96962791 | ||
|
|
a59540d42d | ||
|
|
830dde3cec | ||
|
|
c308bbb6b0 | ||
|
|
c818b2a9db | ||
|
|
ee36205ac1 | ||
|
|
acbdbee26a | ||
|
|
9863821dbc | ||
|
|
206808e83a | ||
|
|
a248c6e39e | ||
|
|
5e2020efff | ||
|
|
c0bda707b7 | ||
|
|
ffc4318725 | ||
|
|
8023a9b021 | ||
|
|
56153510e1 | ||
|
|
be7343191d | ||
|
|
b1773ee5e9 | ||
|
|
18707cec47 | ||
|
|
993d3867ee | ||
|
|
d4d7435265 | ||
|
|
70f17453fd | ||
|
|
ef38cbc790 | ||
|
|
6205772a59 | ||
|
|
807186be61 | ||
|
|
1c625dd881 | ||
|
|
30194479d1 | ||
|
|
ddeced3540 | ||
|
|
dc43b6973a | ||
|
|
d1013c2416 | ||
|
|
f7be2bc2e6 | ||
|
|
42d1e35913 | ||
|
|
74f512d214 | ||
|
|
b945069117 | ||
|
|
efcbff23d8 | ||
|
|
dcabfb1546 | ||
|
|
9e6d758c0f | ||
|
|
1da20feb06 | ||
|
|
3044c9b735 | ||
|
|
b44e4891a6 | ||
|
|
cbbf3ba0ba | ||
|
|
1144f67d37 | ||
|
|
bc6e3962f8 |
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Environments**
|
||||
Your operating system, such as `Mac OS Catalina 10.15.7`.
|
||||
|
||||
**RevSuit Version**
|
||||
Versions of RevSuit with bugs.
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the new feature you expect to add**
|
||||
A clear and concise description.
|
||||
|
||||
**Why do you want to add this feature**
|
||||
A clear and concise description of why you need the feature, such as in what kind of usage scenarios it would be more convenient to have a certain feature.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,11 @@
|
||||
### Describe the pull request
|
||||
|
||||
A clear and concise description of what the pull request is about, i.e. what problem should be fixed?
|
||||
|
||||
Link to the issue: <!-- paste the issue link here, or put "n/a" if not applicable -->
|
||||
|
||||
### Checklist
|
||||
|
||||
- [ ] I agree to follow the [Code of Conduct](https://go.dev/conduct) by submitting this pull request.
|
||||
- [ ] I have reviewed my own code.
|
||||
- [ ] All new and existing tests passed.
|
||||
@@ -21,6 +21,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: create dist directory
|
||||
run: mkdir frontend/dist && touch frontend/dist/revsuit
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/[email protected]
|
||||
with:
|
||||
|
||||
@@ -4,67 +4,40 @@ on:
|
||||
name: Build
|
||||
jobs:
|
||||
release-linux:
|
||||
name: release linux
|
||||
name: release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16.0'
|
||||
- name: compile
|
||||
env:
|
||||
CGO_ENABLE: 1
|
||||
CGO_LDFLAGS: -static
|
||||
run: |
|
||||
GOARCH="amd64" go build -v -ldflags="-s -w -extldflags=-static" -trimpath -o "bin/revsuit_linux_amd64" ./cmd/revsuit/revsuit.go
|
||||
GOARCH="386" go build -v -ldflags="-s -w -extldflags=-static" -trimpath -o "bin/revsuit_linux_i386" ./cmd/revsuit/revsuit.go
|
||||
GOARCH="arm" go build -v -ldflags="-s -w -extldflags=-static" -trimpath -o "bin/revsuit_linux_arm" ./cmd/revsuit/revsuit.go
|
||||
GOARCH="arm64" go build -v -ldflags="-s -w -extldflags=-static" -trimpath -o "bin/revsuit_linux_arm64" ./cmd/revsuit/revsuit.go
|
||||
- name: Upload the artifacts
|
||||
uses: li4n0/upload-release-action@v2
|
||||
|
||||
- name: install nodejs
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: bin/*
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
file_glob: true
|
||||
release-darwin-amd64:
|
||||
name: release darwin/amd64
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16.0'
|
||||
- name: compile
|
||||
env:
|
||||
CGO_ENABLE: 1
|
||||
run: |
|
||||
GOARCH="amd64" go build -v -ldflags="-s -w" -trimpath -o "bin/revsuit_darwin_amd64" ./cmd/revsuit/revsuit.go
|
||||
- name: Upload the artifacts
|
||||
uses: li4n0/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: bin/*
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
file_glob: true
|
||||
release-windows:
|
||||
name: release windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16.0'
|
||||
- name: compile
|
||||
env:
|
||||
CGO_ENABLE: 1
|
||||
CGO_LDFLAGS: -static
|
||||
run: |
|
||||
env GOARCH=amd64 go build -v -ldflags="-s -w -extldflags=-static" -trimpath -o "bin/revsuit_windows_amd64.exe" ./cmd/revsuit/revsuit.go
|
||||
env GOARCH=386 go build -v -ldflags="-s -w -extldflags=-static" -trimpath -o "bin/revsuit_windows_i386.exe" ./cmd/revsuit/revsuit.go
|
||||
env GOARCH=arm go build -v -ldflags="-s -w -extldflags=-static" -trimpath -o "bin/revsuit_windows_arm.exe" ./cmd/revsuit/revsuit.go
|
||||
node-version: '12'
|
||||
|
||||
- name: install yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: build frontend
|
||||
run: cd frontend && yarn install && yarn build
|
||||
|
||||
- name: get the version
|
||||
id: get_version
|
||||
run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3)
|
||||
|
||||
- name: compile linux amd64
|
||||
run: GOARCH="amd64" go build -ldflags="-s -w -X 'github.com/li4n0/revsuit/pkg/server.VERSION=${{ steps.get_version.outputs.VERSION }}'" -tags netgo -trimpath -o "bin/revsuit_linux_amd64" ./cmd/revsuit/revsuit.go
|
||||
- name: compile linux arm64
|
||||
run: GOARCH="arm64" go build -ldflags="-s -w -X 'github.com/li4n0/revsuit/pkg/server.VERSION=${{ steps.get_version.outputs.VERSION }}'" -tags netgo -trimpath -o "bin/revsuit_linux_arm64" ./cmd/revsuit/revsuit.go
|
||||
- name: compile darwin amd64
|
||||
run: GOOS="darwin" GOARCH="amd64" go build -ldflags="-s -w -X 'github.com/li4n0/revsuit/pkg/server.VERSION=${{ steps.get_version.outputs.VERSION }}'" -trimpath -o "bin/revsuit_darwin_amd64" ./cmd/revsuit/revsuit.go
|
||||
- name: compile darwin arm64
|
||||
run: GOOS="darwin" GOARCH="arm64" go build -ldflags="-s -w -X 'github.com/li4n0/revsuit/pkg/server.VERSION=${{ steps.get_version.outputs.VERSION }}'" -trimpath -o "bin/revsuit_darwin_arm64" ./cmd/revsuit/revsuit.go
|
||||
- name: compile windows amd64
|
||||
run: GOOS="windows" GOARCH="amd64" go build -ldflags="-s -w -X 'github.com/li4n0/revsuit/pkg/server.VERSION=${{ steps.get_version.outputs.VERSION }}' " -trimpath -o "bin/revsuit_windows_amd64.exe" ./cmd/revsuit/revsuit.go
|
||||
|
||||
- name: Upload the artifacts
|
||||
uses: li4n0/upload-release-action@v2
|
||||
with:
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
# local files
|
||||
qqwry.dat
|
||||
revsuit.db
|
||||
revsuit.db-shm
|
||||
revsuit.db-wal
|
||||
GeoLite2-City.mmdb
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
|
||||
# local config
|
||||
config.yaml
|
||||
config.yaml*
|
||||
|
||||
# binary
|
||||
revsuit
|
||||
/revsuit
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
@@ -19,4 +20,12 @@ revsuit
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
*.sw?
|
||||
|
||||
## node
|
||||
/package.json
|
||||
package-lock.json
|
||||
node_modules/
|
||||
|
||||
## frontend dist
|
||||
dist/
|
||||
@@ -0,0 +1,119 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [0.5.0](https://github.com/Li4n0/revsuit/compare/v0.4.0...v0.5.0) (2022-01-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **build:** replace sqlite driver with which does not depend cgo ([#52](https://github.com/Li4n0/revsuit/issues/52)) ([82a2023](https://github.com/Li4n0/revsuit/commit/82a20236e1b1a092277b645554a38513e3bb4087))
|
||||
* **dns:** support use multiple root domains ([#51](https://github.com/Li4n0/revsuit/issues/51)) ([913e0f7](https://github.com/Li4n0/revsuit/commit/913e0f78db380cb1beeb88b57dc30f47e7c26c1c))
|
||||
* **ldap:** add ldap protocol support ([#50](https://github.com/Li4n0/revsuit/issues/50)) ([fc505b0](https://github.com/Li4n0/revsuit/commit/fc505b0733a8375d29b910aa897c6e0b642ab34b))
|
||||
* support auto check upgrade ([#53](https://github.com/Li4n0/revsuit/issues/53)) ([f6afe0f](https://github.com/Li4n0/revsuit/commit/f6afe0fa12188f17b74548129035f7b89a149660))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **settings:** fix the bug of update rmi & mysql addr settings not working ([#49](https://github.com/Li4n0/revsuit/issues/49)) ([06ae3d0](https://github.com/Li4n0/revsuit/commit/06ae3d0555eff3bf2d6a53b2c405d1dd50beea87))
|
||||
|
||||
## [0.4.0](https://github.com/Li4n0/revsuit/compare/v0.3.0...v0.4.0) (2021-12-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **database:** support postgres ([#43](https://github.com/Li4n0/revsuit/issues/43)) ([8b30f83](https://github.com/Li4n0/revsuit/commit/8b30f83075bab3f62546793c471b74075745d8d0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **rmi:** fix the problem that rmi has multiple rules matching in one record ([6f921f6](https://github.com/Li4n0/revsuit/commit/6f921f6c97f39638c73de13d87879514485125ef))
|
||||
* **server:** fix auth failure when complex characters in token ([#42](https://github.com/Li4n0/revsuit/issues/42)) ([3242a49](https://github.com/Li4n0/revsuit/commit/3242a49b2731392125e5c22375549586495ee6fc))
|
||||
|
||||
## [0.3.0](https://github.com/Li4n0/revsuit/compare/v0.2.1...v0.3.0) (2021-12-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **database:** add mysql support ([#39](https://github.com/Li4n0/revsuit/issues/39)) ([9d7a5b4](https://github.com/Li4n0/revsuit/commit/9d7a5b45984bb3fee187146b0f27e77d6ec0ea0a))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** fix typos ([#41](https://github.com/Li4n0/revsuit/issues/41)) ([8e96962](https://github.com/Li4n0/revsuit/commit/8e969627917fda9ce220283eb34599b781f03ae3))
|
||||
* **database:** fix the error when load package ([3ca242d](https://github.com/Li4n0/revsuit/commit/3ca242d0866f5f10aade3557d80b8252be7ef938))
|
||||
* **mysql/record:** fix the bug when searching mysql record with username as keyword ([ce8d760](https://github.com/Li4n0/revsuit/commit/ce8d76056faec45d3e68164b3802ceaaec0468b9))
|
||||
* **pkg:** fix the conflict between rank field and built-in function ([#38](https://github.com/Li4n0/revsuit/issues/38)) ([a59540d](https://github.com/Li4n0/revsuit/commit/a59540d42ddf820e445a8395c2995fa89fc14323))
|
||||
|
||||
### [0.2.1](https://github.com/Li4n0/revsuit/compare/v0.2.0...v0.2.1) (2021-07-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **rule:** add `flag` as a built-in template variable ([ee36205](https://github.com/Li4n0/revsuit/commit/ee36205ac160a75d23dbb244c72f3bb2d185ab80))
|
||||
|
||||
## [0.2.0](https://github.com/Li4n0/revsuit/compare/v0.1.7...v0.2.0) (2021-07-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* support deleting logs based on filtering results ([#35](https://github.com/Li4n0/revsuit/issues/35)) ([9863821](https://github.com/Li4n0/revsuit/commit/9863821dbc351734569b7ec1eda2b6712bd02bb0))
|
||||
|
||||
### [0.1.7](https://github.com/Li4n0/revsuit/compare/v0.1.6...v0.1.7) (2021-07-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **http:** fix the bug that http record url search does not work ([ffc4318](https://github.com/Li4n0/revsuit/commit/ffc4318725017c7eda7ec11ca67d5de16ad1e8a8))
|
||||
* **mysql:** fix the bug that crashes when mysql port conflicts ([c0bda70](https://github.com/Li4n0/revsuit/commit/c0bda707b750b7858fdd4efc414b726ee37e71da))
|
||||
|
||||
### [0.1.6](https://github.com/Li4n0/revsuit/compare/v0.1.5...v0.1.6) (2021-06-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** fix the bug that the prompt may not be output when generating config file ([5615351](https://github.com/Li4n0/revsuit/commit/56153510e11783c08843cbb8b0f827d5f8567842))
|
||||
* **ipinfo:** fix a potential panic when downloading ip location database ([#33](https://github.com/Li4n0/revsuit/issues/33)) ([b1773ee](https://github.com/Li4n0/revsuit/commit/b1773ee5e9ebd8c8be72f315981268992c08b3f1))
|
||||
|
||||
### [0.1.5](https://github.com/Li4n0/revsuit/compare/v0.1.5-beta...v0.1.5) (2021-06-22 公开该项目以庆祝毕业,愿工作多年后的我,归来时仍是少年)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **notice:** fix the buf of notice with null record field ([#31](https://github.com/Li4n0/revsuit/issues/31)) ([ef38cbc](https://github.com/Li4n0/revsuit/commit/ef38cbc790f69716a335167321e1c7c8bdee2e41))
|
||||
|
||||
### [0.1.5-beta](https://github.com/Li4n0/revsuit/compare/v0.1.4-beta-fix-1...v0.1.5-beta) (2021-06-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ipinfo:** support GeoIP ([#26](https://github.com/Li4n0/revsuit/issues/26)) ([dc43b69](https://github.com/Li4n0/revsuit/commit/dc43b6973a5ac98e439d1353102ade2029b1d382))
|
||||
* **platform:** support custom admin path prefix ([#25](https://github.com/Li4n0/revsuit/issues/25)) ([f7be2bc](https://github.com/Li4n0/revsuit/commit/f7be2bc2e67841178e9316995999b20f80a49df7))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **frontend:** fix the bug of autoRefresh ([#27](https://github.com/Li4n0/revsuit/issues/27)) ([d1013c2](https://github.com/Li4n0/revsuit/commit/d1013c2416c04bd72b9cbb0c7e6b4b3f2e717837))
|
||||
* **frontend:** fix the frontend display bugs ([#28](https://github.com/Li4n0/revsuit/issues/28)) ([ddeced3](https://github.com/Li4n0/revsuit/commit/ddeced354042e0be6db5dd4feffa13ef22db231f))
|
||||
|
||||
### [0.1.4-beta-fix-1](https://github.com/Li4n0/revsuit/compare/v0.1.4-beta...v0.1.4-beta-fix-1) (2021-05-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **frontend:** fix the problem of autoRefresh failure ([#24](https://github.com/Li4n0/revsuit/issues/24)) ([b945069](https://github.com/Li4n0/revsuit/commit/b945069117fec6eb5de88557da5d4c2c996cfd90))
|
||||
* **http:** fix the problem that ip_header setting does not take effect ([#23](https://github.com/Li4n0/revsuit/issues/23)) ([74f512d](https://github.com/Li4n0/revsuit/commit/74f512d2140fb97128acf56be803d1bd3b888fa3))
|
||||
|
||||
### [0.1.4-beta](https://github.com/Li4n0/revsuit/compare/v0.1.3-beta-fix1...v0.1.4-beta) (2021-05-27)
|
||||
|
||||
### Features
|
||||
|
||||
* **dns:** support custom dns service
|
||||
port ([7fb4c97](https://github.com/Li4n0/revsuit/commit/7fb4c97279e57d120a4e4aef5dda5c8f3c024835))
|
||||
* **frontend:** auto refresh data when switching back to the revsuit
|
||||
console ([9b31406](https://github.com/Li4n0/revsuit/commit/9b314062a39ddc7acf7a7eab3570b24b9bb9d122))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **http:** fix the problem that ip_header configuration does not take
|
||||
effect ([b76c39e](https://github.com/Li4n0/revsuit/commit/b76c39e2fc1ada189feb783fdec76daffa11d1c7))
|
||||
@@ -0,0 +1,46 @@
|
||||
## Configuration file description
|
||||
|
||||
RevSuit will generate a profile template the first time it is run, and you can edit its contents to implement some customization requirements.
|
||||
```yaml
|
||||
version: 1.5
|
||||
addr: :10000 # Address of the HTTP service will listen
|
||||
token: # Authentication Token, both the admin page and the client need to be authenticated by this Token
|
||||
domains: [] # The domain names used by the platform
|
||||
external_ip: # The external IP of the platform, you need to make sure that the target you want to test can access the platform through this IP
|
||||
admin_path_prefix: "/revsuit" # The http path prefix for the admin page, the page will be located at: /admin_path_prefix/admin
|
||||
database: revsuit.db # Database connection information, support using Sqlite3, MySQL, Postgres
|
||||
# database: "mysql://root:password@tcp(127.0.0.1:3306)/revsuit?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
# database: "postgres://host=127.0.0.1 user=root password=password dbname=revsuit port=5432 sslmode=disable TimeZone=Asia/Shanghai"
|
||||
|
||||
log_level: info # Output log levels, divided into: debug, info, warning, error, fatal
|
||||
check_upgrade: true # Whether to automatically check for updates
|
||||
|
||||
ip_location_database: # IP database related configuration
|
||||
database: "qqwry" # qqwry or geoip.
|
||||
geo_license_key: "" # Mandatory field, if you choose to use GeoIP.
|
||||
|
||||
http: # HTTP receive connection related configuration
|
||||
ip_header: # Specify the source IP via the HTTP Header, which is usually required when there is a predecessor reverse proxy
|
||||
dns: # DNS receive connection related configuration
|
||||
enable: true
|
||||
addr: :53 # Address of the DNS service will listen
|
||||
rmi: # RMI receive connection related configuration
|
||||
enable: true
|
||||
addr: :1099 # Address of the RMI service will listen
|
||||
ldap:
|
||||
enable: true
|
||||
addr: :1389 # Address of the Ldap service will listen
|
||||
mysql: # MySQL receive connection related configuration
|
||||
enable: true
|
||||
addr: :3306 # Address of the MySQL service will listen
|
||||
version_string: 10.4.13-MariaDB-log # The version of the MySQL service in disguise
|
||||
ftp: # FTP receive connection related configuration
|
||||
enable: true
|
||||
addr: :21 # Address of the FTP service will listen
|
||||
pasv_port: 2020 # FTP passive mode port listening address
|
||||
notice:
|
||||
dingtalk: https://oapi.dingtalk.com/robot/send?access_token={token} # Webhook of DingTalk Bot
|
||||
lark: https://open.feishu.cn/open-apis/bot/v2/hook/{token} # Webhook of Lark Bot
|
||||
weixin: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={key} # Webhook of Weixin Bot
|
||||
slack: https://hooks.slack.com/services/{id}/{token} # Webhook of Slack Bot
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
## 配置文件说明
|
||||
|
||||
```yaml
|
||||
version: 1.5
|
||||
addr: :10000 # HTTP 服务监听的地址
|
||||
token: # 鉴权Token,管理页面和客户端都需要通过该 Token 进行鉴权
|
||||
domains: [] # 反连平台绑定的域名
|
||||
external_ip: # 反连平台的外部IP,需要确保你想测试的目标能通过该 IP 访问到平台
|
||||
admin_path_prefix: "/revsuit" # 管理页面的 http path 前缀,管理页面将位于:/admin_path_prefix/admin
|
||||
database: revsuit.db # 数据库连接信息 支持Sqlite3、MySQL、Postgres
|
||||
# database: "mysql://root:password@tcp(127.0.0.1:3306)/revsuit?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
# database: "postgres://host=127.0.0.1 user=root password=password dbname=revsuit port=5432 sslmode=disable TimeZone=Asia/Shanghai"
|
||||
|
||||
log_level: info # 输出日志的级别,分为:debug、info、warning、error、fatal
|
||||
check_upgrade: false # 是否自动检查更新
|
||||
|
||||
ip_location_database: # IP 数据库相关配置
|
||||
database: "qqwry" # qqwry 或者 geoip.
|
||||
geo_license_key: "" # 如果你使用 GeoIP 则该字段为必填
|
||||
|
||||
http: # HTTP 反连相关配置
|
||||
ip_header: # 通过 HTTP 请求头获取来源IP,通常在有前置反向代理时需要配置
|
||||
dns: # DNS 反连相关配置
|
||||
enable: true
|
||||
addr: :53 # DNS 服务监听的地址
|
||||
rmi: # RMI 反连相关配置
|
||||
enable: true
|
||||
addr: :1099 # RMI 服务监听的地址
|
||||
ldap:
|
||||
enable: true
|
||||
addr: :1389 # Ldap 服务监听的地址
|
||||
mysql: # MySQL 反连相关配置
|
||||
enable: true
|
||||
addr: :3306 # MySQL 服务监听的地址
|
||||
version_string: 10.4.13-MariaDB-log # 伪装MySQL服务的版本
|
||||
ftp: # FTP 反连相关配置
|
||||
enable: true
|
||||
addr: :21 # FTP 服务监听的地址
|
||||
pasv_port: 2020 # FTP被动模式端口监听的地址
|
||||
notice:
|
||||
dingtalk: https://oapi.dingtalk.com/robot/send?access_token={token} # 钉钉机器人webhook地址
|
||||
lark: https://open.feishu.cn/open-apis/bot/v2/hook/{token} # 飞书机器人webhook地址
|
||||
weixin: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={key} # 企业微信机器人webhook地址
|
||||
slack: https://hooks.slack.com/services/{id}/{token} # slack机器人webhook地址
|
||||
|
||||
```
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2021 Li4n0
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,4 +1,258 @@
|
||||
# RevSuit - A Reverse Platform Developed in Golang
|
||||
# RevSuit - A Flexible and Powerful Reverse Connection Platform
|
||||
|
||||
English |[简体中文](./README.zh-CN.md)
|
||||
|
||||
## Overview
|
||||
RevSuit is an open-sourced Reverse Platform designed for receive connection from target host in bug bounty.
|
||||
|
||||
RevSuit is a flexible and powerful reverse connection platform designed for receiving connection from target host in
|
||||
penetration. It currently supports HTTP, DNS, RMI, LDAP, MySQL and FTP protocols.
|
||||
|
||||
Flexible:
|
||||
|
||||
1. RevSuit can set flexible rules to capture different connections.
|
||||
2. Deploy and run via binaries without worrying about nasty dependency errors.
|
||||
|
||||
Powerful:
|
||||
|
||||
1. Allows to customize the response for different connections through rules and supports dynamic response generation
|
||||
using template variables.
|
||||
2. Support a variety of protocols, and support the in-depth utilization of some protocols, such as DNS rebinding, MySQL
|
||||
Load Local Data, JDBC Deserialize Exploit, FTP Passive Mode SSRF, etc.
|
||||
3. Native support for use with scanners.
|
||||
4. Support push notifications to popular office software.
|
||||
5. Other thoughtful and detailed features.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Installation and Configuration
|
||||
|
||||
Download the latest release directly or build by following steps:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Li4n0/revsuit.git
|
||||
cd revsuit/frontend && yarn install && yarn build
|
||||
cd ../ && go build ./cmd/revsuit/revsuit.go
|
||||
```
|
||||
|
||||
RevSuit will generate default configuration file on first run. Modify the configuration file according to your needs,
|
||||
then re-run. A detailed description of the configuration file can be found at: [Configuration Notes](./CONFIG.md)
|
||||
|
||||
### Run
|
||||
|
||||
In order to confirm the IP location, it needs to use the IP location database. `QQwry` is used as the data source by
|
||||
default, you can also modify the configuration to use `GeoIP`. If the selected database is not available in the current
|
||||
directory or the database is updated for more than a week, RevSuit will automatically download the latest database. If
|
||||
the download fails, the `IpArea` field will always be null.
|
||||
|
||||
```bash
|
||||
$ ./revsuit
|
||||
2021/05/16 22:55:10 [ INFO] Downloading qqwry.dat...
|
||||
|
||||
____ _____ _ __
|
||||
/ __ \___ _ __/ ___/__ __(_) /_
|
||||
/ /_/ / _ \ | / /\__ \/ / / / / __/
|
||||
/ _, _/ __/ |/ /___/ / /_/ / / /_
|
||||
/_/ |_|\___/|___//____/\__,_/_/\__/
|
||||
vBeta0.1
|
||||
https://revsuit.pro
|
||||
2021/05/16 22:55:22 [ INFO] Starting HTTP Server at :80, token:your_token
|
||||
2021/05/16 22:55:22 [ INFO] Start to listen FTP PASV port at :2020, PasvIP is 10.9.8.7
|
||||
2021/05/16 22:55:22 [ INFO] Starting FTP Server at :21
|
||||
2021/05/16 22:55:22 [ INFO] Starting MySQL Server at :3306
|
||||
2021/05/16 22:55:22 [ INFO] Starting RMI Server at :1099
|
||||
2021/05/16 22:55:22 [ INFO] Starting DNS Server at :53
|
||||
```
|
||||
|
||||
After running, you can visit the `/revsuit/admin/` path of HTTP Server and enter the token to access the control panel.
|
||||
|
||||
### Create Rules and Receive Connection
|
||||
|
||||
Take the creation of HTTP rules as an example:
|
||||
|
||||
A few notes are as follows:
|
||||
|
||||
1. The `name` and `flagFormat` of rule are unique.
|
||||
2. `FlagFormat` uses regular expression syntax, and for different protocols, the fields matched by flagFormat are
|
||||
different, you can check the corresponding hints to get details when creating rules.
|
||||
3. Rules with high rank will take effect first.
|
||||
4. For different protocol rules, you can make different custom responses, and for some protocols, template variables can
|
||||
be used.
|
||||
5. You can set the named grouping of regular expressions in `flagFormat`, and the result of the matching grouping will
|
||||
also be used as a template variable.
|
||||
|
||||
As shown below, we create a rule that uses the built-in template variables and custom template variables of the http
|
||||
protocol, and names it `test_create_rule`:
|
||||
|
||||

|
||||
|
||||
Then make a request that satisfies the rule and view the response.
|
||||
|
||||

|
||||
|
||||
The request will be logged on the platform at the same time.
|
||||
|
||||

|
||||
|
||||
### Notice
|
||||
|
||||
If you want to be notified of new connections on your office software, you can configure the webhook address of the
|
||||
relevant software in the configuration file and turn on the `Notice` switch for the corresponding rule. Only support to
|
||||
four software types currently: dingtalk,wechat,lark,slack.(Discord and telegram support is in the plan.)
|
||||
|
||||
### Import/Export Rules
|
||||
|
||||
If you're migrating platforms or purging data, it can be a hassle to recreate rules. That's why the platform supports
|
||||
import and export of rules.
|
||||
|
||||
The entry point for this function is located at `Settings>RULES`.
|
||||
|
||||
The rules are stored in yaml format for import and export, like the following:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
- name: test_create_rule
|
||||
flag_format: (?P<what>\w+)\?
|
||||
rank: 0
|
||||
push_to_client: false
|
||||
notice: false
|
||||
response_status_code: "302"
|
||||
response_headers:
|
||||
Location: ${query.url}
|
||||
response_body: ${header.say} ${what}
|
||||
- name: other_rule
|
||||
flag_format: other
|
||||
rank: 1
|
||||
push_to_client: false
|
||||
notice: true
|
||||
response_status_code: "200"
|
||||
response_headers: { }
|
||||
response_body: Hello Revsuit!
|
||||
dns:
|
||||
... ...
|
||||
```
|
||||
|
||||
## Advance Usage
|
||||
|
||||
### Use with Scanner
|
||||
|
||||
RevSuit was split from my scanner project, so its native support works with scanners.
|
||||
|
||||
From RevSuit's perspective, we call a scanner a client.
|
||||
|
||||
#### Establish connection
|
||||
|
||||
RevSuit
|
||||
uses [HTTP Server-sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
|
||||
(SSE) to establish a one-way communication channel with the client.
|
||||
|
||||
The API for the channel is: `/revsuit/api/events?message` .The client first needs to add the `Token: your token` header
|
||||
to the Header, and then access the API to establish the channel. When the platform receives a new connection, the `flag`
|
||||
captured by the rule will be passed to the client through this channel.
|
||||

|
||||
|
||||
Here is a [simple demo](https://gist.github.com/Li4n0/21aa0bec2d626114a729ca2677efb05a) using Golang's sse library as an
|
||||
example.
|
||||
|
||||
#### Multi-client
|
||||
|
||||
As shown above, RevSuit supports multiple clients, and each client **in the connected state** receives a push of `flag`,
|
||||
so distributed scanning can be supported.
|
||||
|
||||
#### Temporary storage queue
|
||||
|
||||
RevSuit will store `flag` temporarily in the queue when there is no client connection and send it when the client
|
||||
connects, so you don't have to worry about missing the vulnerability because the client disconnects. (This is especially
|
||||
helpful for discovering delay-triggered vulnerabilities.)
|
||||
|
||||
#### Use flagGroup
|
||||
|
||||
In a real-world vulnerability scanning scenario, you may send a large number of different payloads for a single
|
||||
vulnerability point, and they may all be valid, which can result in the backlink platform receiving many requests, yet
|
||||
they are caused by the same vulnerability. If you don't want the client to receive so many `flags` for the same
|
||||
vulnerability, you can take advantage of the `flagGroup` feature of rule's flagFormat.
|
||||
|
||||
`FlagGroup` is the content matched by the anonymous group in the `flagFormat` field of the rule. The platform will check
|
||||
the content matched in the grouping,and the flag is only pushed to the client when then content(`flagGroup`) captured
|
||||
for the first time.
|
||||
|
||||
For example, SSRF scanning.
|
||||
|
||||
Firstly create a rule like the following:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
- name: ssrf
|
||||
flag_format: (ssrf[a-z0-9]{6})[0-9]{1,3}
|
||||
rank: 0
|
||||
push_to_client: false
|
||||
notice: false
|
||||
response_status_code: "200"
|
||||
response_headers: { }
|
||||
response_body: "Here is a SSRF!"
|
||||
```
|
||||
|
||||
Suppose our target is `https://www.testvuln.com?url=api.com&p=useless`, and for SSRF we have 5 payloads. The final
|
||||
request sent by the scanner may
|
||||
be `['https://www.testvuln.com?url=http://revsuit.com/ssrfa98oni1&p=useless','https://www.testvuln.com?url=http://revsuit.com/ssrfa98oni2&p=useless', ... ,'https://www.testvuln.com?url=//revsuit.com/ssrfa98oni5&p=useless`']
|
||||
. They may all attack successfully.
|
||||
|
||||
However, because anonymous grouping is used in the rule's `flagFormat`, The platform will query the
|
||||
connected `flagGroup`, in this case `ssrfa98oni`, and push `flag` to the client only at its first appearance, so the
|
||||
client will only receive one flag:`ssrfa98oni1`. It already proves that the `url` parameter of the target is vulnerable.
|
||||
|
||||
### Multi-module collocation
|
||||
|
||||
In actual penetration testing scenarios, certain tasks can be done easily and quickly by combining and matching various
|
||||
modules of RevSuit. The following is an example of a blind XXE in Java Web, showing how to use RevSuit's HTTP and FTP
|
||||
modules, combined with template variables, to quickly complete a port scan.
|
||||
|
||||
First create an HTTP rule to return evil.dtd, customize the response to the contents of dtd so that it goes to connect
|
||||
to RevSuit's FTP service, and use template variables to pass the Host and Port to be scanned to FTP via FTP's user and
|
||||
password.
|
||||
|
||||

|
||||
|
||||
Then create an FTP rule that receives the Host and port to be scanned from the user and password template variables, set
|
||||
to Pasv Address.
|
||||
|
||||

|
||||
|
||||
Then use BurpSuit to launch the scan, by setting the host and port parameters in the evil.dtd URL to set the target of
|
||||
the port scan.
|
||||
|
||||

|
||||
|
||||
The running effect is as follows:
|
||||
|
||||

|
||||
|
||||
It because the FTP connection will be crashed if `Passive Address` is not accessible, we can determine whether the port
|
||||
is open or not based on whether the connection exits normally.For this example, we successfully detected that port 8005
|
||||
and 8080 are open.
|
||||
|
||||
## More Usage
|
||||
|
||||
A more detailed wiki is being prepared, you can explore by yourself before it.
|
||||
|
||||
## Feedback, Suggestions and Communication
|
||||
|
||||
Submit an issue or contact me through Weixin: `TGk0bjA2Cg==`
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
### Reference
|
||||
|
||||
This project draws on the code of the following outstanding projects:
|
||||
|
||||
* [https://github.com/rmb122/rogue_mysql_server](https://github.com/rmb122/rogue_mysql_server)
|
||||
* [https://github.com/256dpi/newdns](https://github.com/256dpi/newdns)
|
||||
* [https://github.com/EmYiQing/JNDIScan](https://github.com/EmYiQing/JNDIScan)
|
||||
|
||||
### Specifically
|
||||
|
||||
Thanks to my friend [@E99p1ant](https://github.com/wuhan005/) for all the help and advice I received during the
|
||||
development of this project.
|
||||
|
||||
## License
|
||||
|
||||
@Apache License 2.0
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
# RevSuit - A Flexible and Powerful Reverse Connection Platform
|
||||
|
||||
简体中文 |[English](./README.md)
|
||||
|
||||
## 简介
|
||||
|
||||
RevSuit 是一款灵活并且强大的反连平台。目前支持 HTTP、DNS、RMI、LDAP、MySQL 和 FTP 协议。
|
||||
|
||||
灵活:
|
||||
|
||||
1. 通过灵活的规则来捕获连接
|
||||
2. 通过二进制文件部署和运行而无需担心讨厌的依赖错误
|
||||
|
||||
强大:
|
||||
|
||||
1. 可以通过规则,为不同类型的连接自定义响应,并且可以使用模板变量实现动态响应。
|
||||
2. 支持的协议数量相对较多,并且支持其中的部分协议的进一步利用,如 DNS重绑定、MySQL客户端文件读取和 JDBC 反序列化、FTP 被动模式 SSRF 等
|
||||
3. 原生支持扫描器
|
||||
4. 支持发送通知到流行的办公软件
|
||||
5. 其它有趣或贴心的功能
|
||||
|
||||
## 基础使用
|
||||
|
||||
### 安装及配置
|
||||
|
||||
在 Releases 里下载最新版本的 RevSuit,或者通过以下命令自行编译:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Li4n0/revsuit.git
|
||||
cd revsuit/frontend && yarn install && yarn build
|
||||
cd ../ && go build ./cmd/revsuit/revsuit.go
|
||||
```
|
||||
|
||||
RevSuit首次运行将会在当前目录生成配置文件,您可以根据需要自定义其中的某些内容。配置文件的详细说明可见:[配置说明](./CONFIG.zh-CN.md)
|
||||
|
||||
### 运行
|
||||
为了确认连接 IP 的归属地,RevSuit 需要依赖 IP 归属地数据库。默认情况下使用纯真 IP 库,你也可以在配置文件中指定使用 GeoIP。如果当前目录下没有被选中的IP数据库文件,或者IP数据库文件更新的时间大于一周,RevSuit
|
||||
将会自动下载最新版的数据库文件到本地。如果下载失败,连接记录的`IpArea`字段将始终为空。
|
||||
|
||||
```bash
|
||||
$ ./revsuit
|
||||
2021/05/16 22:55:10 [ INFO] Downloading qqwry.dat...
|
||||
|
||||
____ _____ _ __
|
||||
/ __ \___ _ __/ ___/__ __(_) /_
|
||||
/ /_/ / _ \ | / /\__ \/ / / / / __/
|
||||
/ _, _/ __/ |/ /___/ / /_/ / / /_
|
||||
/_/ |_|\___/|___//____/\__,_/_/\__/
|
||||
vBeta0.1
|
||||
https://revsuit.pro
|
||||
2021/05/16 22:55:22 [ INFO] Starting HTTP Server at :80, token:your_token
|
||||
2021/05/16 22:55:22 [ INFO] Start to listen FTP PASV port at :2020, PasvIP is 10.9.8.7
|
||||
2021/05/16 22:55:22 [ INFO] Starting FTP Server at :21
|
||||
2021/05/16 22:55:22 [ INFO] Starting MySQL Server at :3306
|
||||
2021/05/16 22:55:22 [ INFO] Starting RMI Server at :1099
|
||||
2021/05/16 22:55:22 [ INFO] Starting DNS Server at :53
|
||||
```
|
||||
|
||||
在启动之后,你可以通过访问HTTP Server的`/revsuit/admin/`路径,并输入 token 来进入控制面板。
|
||||
|
||||
### 创建规则与接收连接
|
||||
|
||||
这里以创建一个HTTP规则作为例子:
|
||||
|
||||
一些需要注意的内容如下:
|
||||
|
||||
1. 规则的 `name` 和 `flagFormat` 字段是唯一的。
|
||||
2. `flagFormat` 使用正则表达式语法。对于不同的协议,其匹配的字段也是不同的。你可以在创建规则的时候查看对应的帮助信息来获知该协议的哪个字段是会被匹配的。
|
||||
3. `rank` 决定了规则的优先级,如果一个请求同时满足多条规则,只有 `rank` 值最大的那条规则会生效。
|
||||
4. 对于不同的协议,你可以设置不同的响应,部分协议可以使用模板变量来动态生成响应。
|
||||
5. 你可以在 `flagFormat` 中使用正则表达式中的命名分组,命名分组匹配的结果将会成为自定义的模板变量。
|
||||
|
||||
如下图所示,我们创建一个名为 `test_create_rule` 的HTTP协议的规则,其中使用了内置的模板变量和自定义的模板变量:
|
||||
|
||||

|
||||
|
||||
然后发送一个满足这条规则的请求来进行测试,可以看到响应的内容中各个模板变量都获取到了对应的值:
|
||||
|
||||

|
||||
|
||||
这条请求同时会被记录在平台:
|
||||
|
||||

|
||||
|
||||
### 通知
|
||||
|
||||
通过配置 Webhook 地址并打开对应规则的 `Notice` 开关,你可以通过办公软件接收新连接的通知。目前支持 钉钉、企业微信、飞书 和 slack。(计划会后续支持Discord 和 Telegram)
|
||||
|
||||
### 导入/导出规则
|
||||
|
||||
如果你想要迁移平台或者清除数据,重新创建规则可能是一件麻烦事。因此 RevSuit 支持导入和导出规则。
|
||||
|
||||
该功能位于 `Settings>RULES` 选项卡,如下所示,规则将会被以 yaml 的格式进行导入和导出:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
- name: test_create_rule
|
||||
flag_format: (?P<what>\w+)\?
|
||||
rank: 0
|
||||
push_to_client: false
|
||||
notice: false
|
||||
response_status_code: "302"
|
||||
response_headers:
|
||||
Location: ${query.url}
|
||||
response_body: ${header.say} ${what}
|
||||
- name: other_rule
|
||||
flag_format: other
|
||||
rank: 1
|
||||
push_to_client: false
|
||||
notice: true
|
||||
response_status_code: "200"
|
||||
response_headers: { }
|
||||
response_body: Hello Revsuit!
|
||||
dns:
|
||||
... ...
|
||||
```
|
||||
|
||||
## 高级功能
|
||||
|
||||
### 与扫描器适配
|
||||
|
||||
RevSuit 拆分自我的扫描器项目,因此它原生支持搭配扫描器使用。
|
||||
|
||||
从 RevSuit 的视角,我们称扫描器为客户端。
|
||||
|
||||
#### 建立通信管道
|
||||
|
||||
RevSuit
|
||||
使用 [HTTP Server-sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
|
||||
(SSE) 与客户端建立一条单向通信管道。
|
||||
|
||||
通信管道的API为 `/revsuit/api/events?message`。客户端只需携带 `Token: your token` 请求头,然后请求这个 API 来建立通信管道。这样当 RevSuit
|
||||
捕获新连接的时候,匹配到的 `flag` 就会通过这条管道传递给客户端。
|
||||
|
||||

|
||||
|
||||
这里是一个使用 Go 语言的 sse 库编写客户端的[简单例子](https://gist.github.com/Li4n0/21aa0bec2d626114a729ca2677efb05a) 。
|
||||
|
||||
#### 多客户端
|
||||
|
||||
如上一节的图片里所展示的,RevSuit 支持多个客户端,每个在**连接状态**的客户端都会接收到 `flag` 的推送,因此分布式扫描也是支持的。
|
||||
|
||||
#### 暂存队列
|
||||
|
||||
当没有客户端连接的时候,RevSuit 会把 `flag` 暂时存储到队列里,当有客户端连接的时候再进行推送。因此你不必担心因为客户端与 RevSuit 断开连接就错过漏洞。(这对发现延时触发的漏洞尤为有帮助)
|
||||
|
||||
#### 使用flagGroup
|
||||
|
||||
在真实的漏洞扫描情景中,对于一个漏洞点,往往会发送许多不同的 payload,它们可能全部是有效 payload,这会导致 RevSuit
|
||||
收到很多个连接,然而这些连接背后的漏洞其实是同一个。如果你不想客户端收到代表同一个漏洞的 `flag`
|
||||
,你可以使用 `flagGroup`。
|
||||
|
||||
`flagGroup` 是被规则中的 `flagFormat` 中的匿名分组所匹配到的内容。RevSuit 将会检查 `flagGroup` 是否已经在之前的连接中被捕获过,只有当 `flagGroup`
|
||||
是首次出现时,才会推送 `flag`
|
||||
到客户端。
|
||||
|
||||
以针对 SSRF 漏洞扫描为例:
|
||||
|
||||
首先我们创建一个如下的规则:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
- name: ssrf
|
||||
flag_format: (ssrf[a-z0-9]{6})[0-9]{1,3}
|
||||
rank: 0
|
||||
push_to_client: false
|
||||
notice: false
|
||||
response_status_code: "200"
|
||||
response_headers: { }
|
||||
response_body: "Here is a SSRF!"
|
||||
```
|
||||
|
||||
假设我们的目标是 `https://www.testvuln.com?url=api.com&p=useless`,并且针对 SSRF 漏洞,我们有5个
|
||||
payload,最后被扫描器发出的请求是:`['https://www.testvuln.com?url=http://revsuit.com/ssrfa98oni1&p=useless','https://www.testvuln.com?url=http://revsuit.com/ssrfa98oni2&p=useless', ... ,'https://www.testvuln.com?url=//revsuit.com/ssrfa98oni5&p=useless`']
|
||||
,它们可能全部攻击成功.
|
||||
|
||||
然而,因为我们在规则的 `flagFormat` 中使用了匿名分组,RevSuit 将会在数据库中查询连接的 `flagGroup`,在这个例子里也就是 `ssrfa98oni` ,只有当它是第一次出现时,才会向客户端推送 `flag`
|
||||
,所以客户端只会收到 `ssrfa98oni1` 这一个 `flag` ,这足以确认这个请求的 URL 参数存在漏洞了。
|
||||
|
||||
### 多模块联动
|
||||
|
||||
在实际的渗透测试场景中,一些特定的操作可以通过 RevSuit 多个模块配合,快速、简单地完成。下面以一个 Java Web 环境中 盲XXE 漏洞利用场景为例,展示如何使用 RevSuit 的 HTTP 和 FTP
|
||||
模块,配合模板变量,快速完成内网端口扫描。
|
||||
|
||||
首先创建一个 HTTP 规则来返回 evil.dtd, 使被攻击的目标去连接 RevSuit 的 FTP 模块,并且通过设置 FTP 连接的用户名和密码为模板变量来传递我们要扫描的 IP 和端口。
|
||||
|
||||

|
||||
|
||||
然后创建一个 FTP 规则,其中 `Pasv Address` 的 Host 和 Port 通过模板变量从 FTP 连接的用户名和密码动态获取。
|
||||
|
||||

|
||||
|
||||
然后使用 BurpSuit 即可进行扫描,通过设置 evil.dtd 请求中的 host 和 post 参数,来指定要扫描的目标端口:
|
||||
|
||||

|
||||
|
||||
运行效果如下:
|
||||
|
||||

|
||||
|
||||
因为在 FTP被动模式 中如果 `Passive Address` 是不可达的, FTP 的连接会中断,因此我们可以通过检查 FTP 的连接是否正常退出,来判断端口是否开放。对于上面这个例子,我们成功的探测出 8005 端口和 8080
|
||||
端口是开放的。
|
||||
|
||||
## 更多用法
|
||||
|
||||
一个更详细的 wiki 正在准备中,在此之前你可以自己探索...
|
||||
|
||||
## 反馈、建议与交流
|
||||
|
||||
提交 Issue 或者通过微信联系我`TGk0bjA2Cg==`
|
||||
|
||||
## 致谢
|
||||
|
||||
### 引用
|
||||
|
||||
本项目引用了如下优秀项目的代码:
|
||||
|
||||
* [https://github.com/rmb122/rogue_mysql_server](https://github.com/rmb122/rogue_mysql_server)
|
||||
* [https://github.com/256dpi/newdns](https://github.com/256dpi/newdns)
|
||||
* [https://github.com/EmYiQing/JNDIScan](https://github.com/EmYiQing/JNDIScan)
|
||||
|
||||
### 特别感谢
|
||||
|
||||
感谢我的朋友[@E99p1ant](https://github.com/wuhan005/) 在我开发这个项目过程中给予非常多的建议和帮助。
|
||||
|
||||
## 开源许可协议
|
||||
|
||||
@Apache License 2.0
|
||||
@@ -1 +0,0 @@
|
||||
.custom-icons-list[data-v-05a908c2] .anticon{margin-right:6px}body[data-v-6db702b8],html[data-v-6db702b8]{height:100%;margin:0}.fade-transform-enter-active[data-v-6db702b8],.fade-transform-leave-active[data-v-6db702b8]{transition:all .3s;opacity:0}.fade-transform-enter[data-v-6db702b8],.fade-transform-leave[data-v-6db702b8]{opacity:0}.fade-transform-enter-to[data-v-6db702b8]{opacity:0}.ant-menu-item>span>a[data-v-6db702b8]{color:hsla(0,0%,100%,.65)}.ant-menu-item-selected>span>a[data-v-6db702b8]{color:#fff}#nav[data-v-6db702b8]{height:100%}#nav .trigger[data-v-6db702b8]{font-size:18px;line-height:64px;padding:0 24px;cursor:pointer;transition:color .3s}#nav .trigger[data-v-6db702b8]:hover{color:#1890ff}#nav .logo[data-v-6db702b8]{height:32px;background:#0a1d2d;margin:16px;text-align:center;font-size:1.2rem;color:#fff;padding-bottom:5px;border-bottom:2px solid #b6befa}.copyright[data-v-6db702b8]{color:#888;text-align:right;margin-right:1rem}
|
||||
@@ -1 +0,0 @@
|
||||
#add-rule[data-v-e8e0136c]{margin-bottom:10px}
|
||||
@@ -1 +0,0 @@
|
||||
#add-rule[data-v-2586daf9]{margin-bottom:10px}
|
||||
@@ -1 +0,0 @@
|
||||
.gray-table-row{background-color:#f5f5f5}
|
||||
@@ -1 +0,0 @@
|
||||
#add-rule[data-v-487bb706]{margin-bottom:10px}
|
||||
@@ -1 +0,0 @@
|
||||
.gray-table-row{background-color:#f5f5f5}
|
||||
@@ -1 +0,0 @@
|
||||
.gray-table-row{background-color:#f5f5f5}
|
||||
@@ -1 +0,0 @@
|
||||
#add-rule[data-v-169b853c]{margin-bottom:10px}.full-screen-icon[data-v-169b853c]{position:absolute;z-index:5;color:#9e9e9e;right:1px;font-size:1rem;cursor:pointer;transition:font-size .1s}.full-screen-icon[data-v-169b853c]:hover{font-size:1.1rem;transition:font-size .1s}
|
||||
@@ -1 +0,0 @@
|
||||
#add-rule[data-v-98f944a6]{margin-bottom:10px}
|
||||
@@ -1 +0,0 @@
|
||||
.gray-table-row{background-color:#f5f5f5}
|
||||
@@ -1 +0,0 @@
|
||||
.gray-table-row{background-color:#f5f5f5}
|
||||
@@ -1 +0,0 @@
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>RevSuit Control Panel</title><link href="css/chunk-012c9c90.css" rel="prefetch"><link href="css/chunk-0155152b.css" rel="prefetch"><link href="css/chunk-1da7f23b.css" rel="prefetch"><link href="css/chunk-2e835d68.css" rel="prefetch"><link href="css/chunk-330a7e95.css" rel="prefetch"><link href="css/chunk-3d13e56e.css" rel="prefetch"><link href="css/chunk-d4730ae2.css" rel="prefetch"><link href="css/chunk-e00d17cc.css" rel="prefetch"><link href="css/chunk-e039e75a.css" rel="prefetch"><link href="css/chunk-fef965c2.css" rel="prefetch"><link href="js/chunk-012c9c90.js" rel="prefetch"><link href="js/chunk-0155152b.js" rel="prefetch"><link href="js/chunk-08f9fbe8.js" rel="prefetch"><link href="js/chunk-1da7f23b.js" rel="prefetch"><link href="js/chunk-2e835d68.js" rel="prefetch"><link href="js/chunk-330a7e95.js" rel="prefetch"><link href="js/chunk-3d13e56e.js" rel="prefetch"><link href="js/chunk-b241c712.js" rel="prefetch"><link href="js/chunk-d4730ae2.js" rel="prefetch"><link href="js/chunk-e00d17cc.js" rel="prefetch"><link href="js/chunk-e039e75a.js" rel="prefetch"><link href="js/chunk-fef965c2.js" rel="prefetch"><link href="css/app.css" rel="preload" as="style"><link href="css/chunk-vendors.css" rel="preload" as="style"><link href="js/app.js" rel="preload" as="script"><link href="js/chunk-vendors.js" rel="preload" as="script"><link href="css/chunk-vendors.css" rel="stylesheet"><link href="css/app.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but revsuit-frontend doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.js"></script><script src="js/app.js"></script></body></html>
|
||||
@@ -5,19 +5,21 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "revsuit-frontend",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"ant-design-vue": "^1.2.4",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0"
|
||||
"vue-router": "^3.2.0",
|
||||
"vue-visibility-change": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/cli-service": "^4.5.11",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
@@ -13528,6 +13530,11 @@
|
||||
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vue-visibility-change": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npm.taobao.org/vue-visibility-change/download/vue-visibility-change-1.2.1.tgz",
|
||||
"integrity": "sha1-0YAIv08d4slHr+VEHuBEuenGAUE="
|
||||
},
|
||||
"node_modules/warning": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz",
|
||||
@@ -26192,6 +26199,11 @@
|
||||
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=",
|
||||
"dev": true
|
||||
},
|
||||
"vue-visibility-change": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npm.taobao.org/vue-visibility-change/download/vue-visibility-change-1.2.1.tgz",
|
||||
"integrity": "sha1-0YAIv08d4slHr+VEHuBEuenGAUE="
|
||||
},
|
||||
"warning": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz",
|
||||
|
||||
@@ -12,13 +12,14 @@
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0"
|
||||
"vue-router": "^3.2.0",
|
||||
"vue-visibility-change": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/cli-service": "^4.5.11",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<a-layout id="nav">
|
||||
<a-layout id="app" v-visibility-change="()=>{this.$refs.content.fetch?this.$refs.content.fetch():null}">
|
||||
<a-layout-sider v-model="collapsed" :trigger="null" collapsible>
|
||||
<div class="logo"><b>R</b><span v-if="!collapsed"><b>ev</b>Suit</span></div>
|
||||
<a-menu theme="dark" mode="inline" :selectedKeys="[this.$route.path]" :open-keys.sync='openKeys'>
|
||||
<!-- <a-menu-item key="/">-->
|
||||
<a-menu theme="dark" mode="inline" :selectedKeys="[this.$route.path]" :openKeys.sync="openKeys">
|
||||
<!-- <a-menu-item key="
|
||||
/">-->
|
||||
<!-- <router-link to="/">-->
|
||||
<!-- <a-icon type="dashboard"/>-->
|
||||
<!-- <span>Dashboard</span>-->
|
||||
@@ -20,6 +21,9 @@
|
||||
<a-menu-item key="/logs/rmi">
|
||||
<router-link to="/logs/rmi">RMI Logs</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="/logs/ldap">
|
||||
<router-link to="/logs/ldap">LDAP Logs</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="/logs/mysql">
|
||||
<router-link to="/logs/mysql">MySQL Logs</router-link>
|
||||
</a-menu-item>
|
||||
@@ -38,6 +42,9 @@
|
||||
<a-menu-item key="/rules/rmi">
|
||||
<router-link to="/rules/rmi">RMI Rules</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="/rules/ldap">
|
||||
<router-link to="/rules/ldap">LDAP Rules</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="/rules/mysql">
|
||||
<router-link to="/rules/mysql">MySQL Rules</router-link>
|
||||
</a-menu-item>
|
||||
@@ -48,8 +55,7 @@
|
||||
<a-menu-item key="/settings">
|
||||
<router-link to="/settings">
|
||||
<a-icon type="setting"/>
|
||||
Settings
|
||||
</router-link>
|
||||
<span>Settings</span></router-link>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-layout-sider>
|
||||
@@ -60,9 +66,9 @@
|
||||
:type="collapsed ? 'menu-unfold' : 'menu-fold'"
|
||||
@click="() => (collapsed = !collapsed)"
|
||||
/>
|
||||
<div v-if="isLogMode" style="float: right; min-width:50% ;padding: 12px 0;line-height: 24px;">
|
||||
<div v-if="isLogMode" style="float: right; min-width:60% ;padding: 12px 0;line-height: 24px;">
|
||||
<a-row :gutter="24" type="flex">
|
||||
<a-col :span="21">
|
||||
<a-col :span="20">
|
||||
<a-form-model v-show="showSettings" ref="settings" layout="inline">
|
||||
<a-row :gutter="24" type="flex">
|
||||
<a-col :span="9" :offset="2">
|
||||
@@ -80,9 +86,23 @@
|
||||
</a-row>
|
||||
</a-form-model>
|
||||
</a-col>
|
||||
<a-col :span="3">
|
||||
<a-col :span="4">
|
||||
<a-popconfirm
|
||||
:title="showLogNum?`This will delete all logs in the current filtered state, a total of ${this.$refs.content.pagination.total}, are you sure?`:'This will delete all logs in the current filtered state, a total of 0, are you sure?'"
|
||||
ok-text="Yes"
|
||||
cancel-text="No"
|
||||
@visibleChange="showLogNum?delayChangeShowLogNum():showLogNum=!showLogNum"
|
||||
@confirm="deleteLogs"
|
||||
>
|
||||
<a-icon slot="icon" type="question-circle-o" style="color: red"/>
|
||||
<a-icon
|
||||
:style="'font-size: 18px;padding: 12px 0;'"
|
||||
type="delete"
|
||||
@click="()=>{}"
|
||||
/>
|
||||
</a-popconfirm>
|
||||
<a-icon
|
||||
:style="'font-size: 18px;padding: 12px 0;'+(showSettings?'color: #1b90ff;':'')"
|
||||
:style="'font-size: 18px;padding:12px 15px;'+(showSettings?'color: #1b90ff;':'')"
|
||||
type="setting"
|
||||
@click="showSettings = !showSettings"
|
||||
/>
|
||||
@@ -98,10 +118,17 @@
|
||||
</transition>
|
||||
</a-layout-content>
|
||||
<div class="copyright">
|
||||
<p class="">
|
||||
RevSuit Current Version: {{ this.version }} ©2021 <a href="https://github.com/Li4n0">Li4n0</a>. <a
|
||||
<p v-if="!this.upgrade.upgradeable">
|
||||
RevSuit Current Version: {{ this.version }}|© 2021 <a href="https://github.com/Li4n0">Li4n0</a>|<a
|
||||
href="https://github.com/Li4n0/revsuit">GitHub</a>
|
||||
</p>
|
||||
<p v-else>
|
||||
RevSuit {{ this.version }}(Upgrade Available: <a
|
||||
target="_blank"
|
||||
:href="this.upgrade.release">v{{ this.upgrade.version }}</a>)|© 2021 <a
|
||||
href="https://github.com/Li4n0">Li4n0</a>|<a href="https://github.com/Li4n0/revsuit">GitHub</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</a-layout>
|
||||
<Auth></Auth>
|
||||
@@ -110,7 +137,7 @@
|
||||
<script>
|
||||
import Auth from '@/components/Auth'
|
||||
import RuleIcon from "@/components/Icon";
|
||||
import {getVersion} from "@/api/auth";
|
||||
import {getVersion, getUpgrade} from "@/api/version";
|
||||
import {store} from "@/main";
|
||||
|
||||
|
||||
@@ -123,14 +150,16 @@ export default {
|
||||
pageSize: store.pageSize,
|
||||
collapsed: false,
|
||||
showSettings: false,
|
||||
openKeys: ['logs'],
|
||||
showLogNum: false,
|
||||
openKeys: [],
|
||||
version: "",
|
||||
upgrade: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isLogMode() {
|
||||
return this.$route.path.includes('logs')
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
timing() {
|
||||
@@ -141,17 +170,39 @@ export default {
|
||||
this.$refs.content.fetch()
|
||||
}, this.refreshInterval * 1000)
|
||||
},
|
||||
GetVersion() {
|
||||
_getVersion() {
|
||||
getVersion().then(res => {
|
||||
this.version = res.data.result
|
||||
})
|
||||
},
|
||||
_getUpgrade() {
|
||||
getUpgrade().then(res => {
|
||||
this.upgrade = res.data.result
|
||||
})
|
||||
},
|
||||
deleteLogs() {
|
||||
this.$refs.content.delete()
|
||||
},
|
||||
delayChangeShowLogNum() {
|
||||
setTimeout(() => {
|
||||
this.showLogNum = !this.showLogNum
|
||||
}, 1000)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.autoRefresh && this.isLogMode) {
|
||||
this.timing()
|
||||
if (localStorage.getItem("autoRefresh") === null) {
|
||||
this.autoRefresh = true;
|
||||
}
|
||||
this.GetVersion()
|
||||
this._getVersion()
|
||||
this._getUpgrade()
|
||||
},
|
||||
created() {
|
||||
let unwatch = this.$watch('$route', function (to, from) {
|
||||
if (from.path === "/" && this.openKeys.length === 0) {
|
||||
this.openKeys.push(to.path.split("/")[1])
|
||||
unwatch()
|
||||
}
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
clearInterval(this.timer)
|
||||
@@ -166,12 +217,11 @@ export default {
|
||||
localStorage.setItem('autoRefresh', val)
|
||||
},
|
||||
isLogMode(val) {
|
||||
if (!val) {
|
||||
if (!val && this.timer) {
|
||||
clearInterval(this.timer)
|
||||
} else {
|
||||
} else if (this.autoRefresh) {
|
||||
this.timing()
|
||||
}
|
||||
localStorage.setItem('autoRefresh', val)
|
||||
},
|
||||
refreshInterval(val) {
|
||||
clearInterval(this.timer)
|
||||
@@ -185,8 +235,12 @@ export default {
|
||||
store.pageSize = val
|
||||
localStorage.setItem('pageSize', val)
|
||||
},
|
||||
'store.authed'() {
|
||||
this.$refs.content.fetch()
|
||||
'store.authed'(val) {
|
||||
if (val) {
|
||||
this.$refs.content.fetch()
|
||||
this._getVersion()
|
||||
this._getUpgrade()
|
||||
}
|
||||
},
|
||||
'store.pageSize'() {
|
||||
this.$refs.content.pagination.pageSize = store.pageSize
|
||||
@@ -236,11 +290,11 @@ html, body {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#nav {
|
||||
height: 100%;
|
||||
#app {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
#nav .trigger {
|
||||
#app .trigger {
|
||||
font-size: 18px;
|
||||
line-height: 64px;
|
||||
padding: 0 24px;
|
||||
@@ -248,11 +302,11 @@ html, body {
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
#nav .trigger:hover {
|
||||
#app .trigger:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
#nav .logo {
|
||||
#app .logo {
|
||||
height: 32px;
|
||||
background: #0a1d2d;
|
||||
margin: 16px;
|
||||
|
||||
@@ -5,18 +5,5 @@ export function auth(token) {
|
||||
url: '/auth',
|
||||
method: 'get',
|
||||
headers: {"Token": token},
|
||||
validateStatus: function (status) {
|
||||
return status >= 200 && status < 300
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getVersion() {
|
||||
return request({
|
||||
url: '/version',
|
||||
method: 'get',
|
||||
validateStatus: function (status) {
|
||||
return status >= 200 && status < 300
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
import axios from 'axios'
|
||||
import {store} from "@/main";
|
||||
|
||||
const service = axios.create({
|
||||
baseURL: '/revsuit/api/', // api的base_url
|
||||
baseURL: location.pathname.slice(0, -'/admin/'.length) + "/api", // api的base_url
|
||||
timeout: 5000, // request timeout
|
||||
validateStatus: function (status) {
|
||||
if (status === 403) {
|
||||
store.authed = false
|
||||
}
|
||||
return status >= 200 && status < 300 // 默认的
|
||||
}
|
||||
})
|
||||
|
||||
@@ -9,6 +9,15 @@ export function getHttpRecord(params) {
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteHttpRecord(params) {
|
||||
return request({
|
||||
url: '/record/http',
|
||||
params: params,
|
||||
method: 'delete',
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function getDnsRecord(params) {
|
||||
return request({
|
||||
url: '/record/dns',
|
||||
@@ -17,6 +26,14 @@ export function getDnsRecord(params) {
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDnsRecord(params) {
|
||||
return request({
|
||||
url: '/record/dns',
|
||||
params: params,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function getMysqlRecord(params) {
|
||||
return request({
|
||||
url: '/record/mysql',
|
||||
@@ -25,6 +42,14 @@ export function getMysqlRecord(params) {
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteMysqlRecord(params) {
|
||||
return request({
|
||||
url: '/record/mysql',
|
||||
params: params,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function getRmiRecord(params) {
|
||||
return request({
|
||||
url: '/record/rmi',
|
||||
@@ -33,10 +58,42 @@ export function getRmiRecord(params) {
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteRmiRecord(params) {
|
||||
return request({
|
||||
url: '/record/rmi',
|
||||
params: params,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function getLdapRecord(params) {
|
||||
return request({
|
||||
url: '/record/ldap',
|
||||
params: params,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteLdapRecord(params) {
|
||||
return request({
|
||||
url: '/record/ldap',
|
||||
params: params,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function getFtpRecord(params) {
|
||||
return request({
|
||||
url: '/record/ftp',
|
||||
params: params,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteFtpRecord(params) {
|
||||
return request({
|
||||
url: '/record/ftp',
|
||||
params: params,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -97,6 +97,30 @@ export function deleteRmiRule(data) {
|
||||
})
|
||||
}
|
||||
|
||||
export function getLdapRule(params) {
|
||||
return request({
|
||||
url: '/rule/ldap',
|
||||
params: params,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function upsertLdapRule(data) {
|
||||
return request({
|
||||
url: '/rule/ldap',
|
||||
data: data,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteLdapRule(data) {
|
||||
return request({
|
||||
url: '/rule/ldap',
|
||||
data: data,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function getFtpRule(params) {
|
||||
return request({
|
||||
url: '/rule/ftp',
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import request from './index'
|
||||
|
||||
export function getHttpConfig() {
|
||||
export function getPlatformConfig() {
|
||||
return request({
|
||||
url: '/setting/getHttpConfig',
|
||||
url: '/setting/getPlatformConfig',
|
||||
})
|
||||
}
|
||||
|
||||
export function updateHttpConfig(data) {
|
||||
export function updatePlatformConfig(data) {
|
||||
return request({
|
||||
url: '/setting/updateHttpConfig',
|
||||
url: '/setting/updatePlatformConfig',
|
||||
method: "post",
|
||||
data: data
|
||||
})
|
||||
@@ -42,6 +42,20 @@ export function updateRmiConfig(data) {
|
||||
})
|
||||
}
|
||||
|
||||
export function getLdapConfig() {
|
||||
return request({
|
||||
url: '/setting/getLdapConfig',
|
||||
})
|
||||
}
|
||||
|
||||
export function updateLdapConfig(data) {
|
||||
return request({
|
||||
url: '/setting/updateLdapConfig',
|
||||
method: "post",
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export function getMySQLConfig() {
|
||||
return request({
|
||||
url: '/setting/getMySQLConfig',
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import request from "@/api/index";
|
||||
|
||||
export function getVersion() {
|
||||
return request({
|
||||
url: '/version',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
export function getUpgrade() {
|
||||
return request({
|
||||
url: '/getUpgrade',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
@@ -15,20 +15,20 @@
|
||||
<a-form-model-item :rules="rules.flagFormat" prop="flag_format">
|
||||
<span slot="label">
|
||||
Flag Format
|
||||
<a-tooltip title="Basic usage:
|
||||
1. Only when the request contains content that satisfies the flag format, the request will be captured.
|
||||
<a-tooltip :title="`Basic usage:
|
||||
1. Only when the request's ${flagField} contains content that satisfies the flag format, the request will be captured.
|
||||
2. Use regular expression syntax.
|
||||
3. The character '*' means to capture all requests.
|
||||
Advanced usage:
|
||||
1. When the regex uses grouping without group name, the platform will only notify the user or push to the client when the first group appears for the first time.
|
||||
2. When the regex uses grouping with group name, you can get these submatches through template variables and use them in other fields of the rule.">
|
||||
2. When the regex uses grouping with group name, you can get these submatches through template variables and use them in other fields of the rule.`">
|
||||
<a-icon type="question-circle-o"/>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-input
|
||||
v-model="form.flag_format"
|
||||
style="width: 100%"
|
||||
placeholder="please enter flag format"
|
||||
placeholder="Please enter flag format"
|
||||
:readOnly="readOnly"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
@@ -97,7 +97,7 @@ export default {
|
||||
},
|
||||
}
|
||||
},
|
||||
props: ['form', 'readOnly']
|
||||
props: ['form', 'readOnly', 'flagField']
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
<a-select-option value='error'>ERROR</a-select-option>
|
||||
<a-select-option value='fatal'>FATAL</a-select-option>
|
||||
</a-select>
|
||||
<a-input :disabled="key ==='Addr' && parent==='Http'" v-else v-model="form[key]"/>
|
||||
<a-input :disabled="(key ==='Addr'||key==='AdminPathPrefix') && parent==='Http'" v-else
|
||||
v-model="form[key]"/>
|
||||
</a-form-model-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
@@ -4,10 +4,14 @@ import App from './App';
|
||||
import router from "@/router";
|
||||
import 'ant-design-vue/dist/antd.css';
|
||||
import '@/utils/index'
|
||||
import visibility from 'vue-visibility-change';
|
||||
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
Vue.use(Antd);
|
||||
Vue.use(visibility);
|
||||
|
||||
export const store = Vue.observable({
|
||||
authed: true,
|
||||
pageSize: localStorage.getItem("pageSize") ? parseInt(localStorage.getItem("pageSize")) : 10
|
||||
|
||||
@@ -30,6 +30,11 @@ const routes = [
|
||||
name: 'RmiLogs',
|
||||
component: () => import( '../views/logs/Rmi')
|
||||
},
|
||||
{
|
||||
path: '/logs/ldap',
|
||||
name: 'LdapLogs',
|
||||
component: () => import( '../views/logs/Ldap')
|
||||
},
|
||||
{
|
||||
path: '/logs/ftp',
|
||||
name: 'FtpLogs',
|
||||
@@ -56,6 +61,11 @@ const routes = [
|
||||
name: 'RmiRules',
|
||||
component: () => import( '../views/rules/Rmi')
|
||||
},
|
||||
{
|
||||
path: '/rules/ldap',
|
||||
name: 'LdapRules',
|
||||
component: () => import( '../views/rules/Ldap')
|
||||
},
|
||||
{
|
||||
path: '/rules/ftp',
|
||||
name: 'FtpRules',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -36,7 +37,7 @@
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import {getDnsRecord} from '@/api/record'
|
||||
import {deleteDnsRecord, getDnsRecord} from '@/api/record'
|
||||
import {store} from '@/main'
|
||||
import FilterDropdown from '@/components/FilterDropdown'
|
||||
|
||||
@@ -139,11 +140,23 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
console.error(e)
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
delete: function () {
|
||||
let params = {
|
||||
...this.filters,
|
||||
}
|
||||
this.loading = true;
|
||||
deleteDnsRecord(params).then(() => {
|
||||
this.$message.success('Deleted successfully')
|
||||
this.filters = {}
|
||||
this.fetch()
|
||||
}).catch(e => {
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Failed to delete: ' + e.response.data.error)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -71,7 +72,7 @@
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import {getFtpRecord} from '@/api/record'
|
||||
import {deleteFtpRecord, getFtpRecord} from '@/api/record'
|
||||
import {store} from '@/main'
|
||||
import FilterDropdown from '@/components/FilterDropdown'
|
||||
|
||||
@@ -228,11 +229,23 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
console.error(e)
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
delete: function () {
|
||||
let params = {
|
||||
...this.filters,
|
||||
}
|
||||
this.loading = true;
|
||||
deleteFtpRecord(params).then(() => {
|
||||
this.$message.success('Deleted successfully')
|
||||
this.filters = {}
|
||||
this.fetch()
|
||||
}).catch(e => {
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Failed to delete: ' + e.response.data.error)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -48,7 +49,7 @@
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import {getHttpRecord} from '@/api/record'
|
||||
import {getHttpRecord, deleteHttpRecord} from '@/api/record'
|
||||
import {store} from '@/main'
|
||||
import FilterDropdown from '@/components/FilterDropdown'
|
||||
|
||||
@@ -104,9 +105,9 @@ const columns = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'PATH',
|
||||
dataIndex: 'path',
|
||||
key: 'path',
|
||||
title: 'URI',
|
||||
dataIndex: 'uri',
|
||||
key: 'uri',
|
||||
ellipsis: true,
|
||||
scopedSlots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
@@ -173,11 +174,23 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
console.error(e)
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
delete: function () {
|
||||
let params = {
|
||||
...this.filters,
|
||||
}
|
||||
this.loading = true;
|
||||
deleteHttpRecord(params).then(() => {
|
||||
this.$message.success('Deleted successfully')
|
||||
this.filters = {}
|
||||
this.fetch()
|
||||
}).catch(e => {
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Failed to delete: ' + e.response.data.error)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
@change="handleTableChange"
|
||||
:rowClassName="(record, index) => index % 2 === 0 ? '' : 'gray-table-row'"
|
||||
>
|
||||
<filter-dropdown
|
||||
slot="filterDropdown"
|
||||
slot-scope="{ setSelectedKeys, selectedKeys, clearFilters, column }"
|
||||
:set-selected-keys="setSelectedKeys"
|
||||
:selected-keys="selectedKeys"
|
||||
:clear-filters="clearFilters"
|
||||
:column="column"
|
||||
:filters="filters"
|
||||
:fetch="fetch"
|
||||
/>
|
||||
<a-icon
|
||||
slot="filterIcon"
|
||||
slot-scope="filtered"
|
||||
type="search"
|
||||
:style="{ color: filtered ? '#108ee9' : undefined }"
|
||||
/>
|
||||
|
||||
<span slot="time" slot-scope="time">
|
||||
{{ new Date(time).format("yyyy-MM-dd hh:mm:ss") }}
|
||||
</span>
|
||||
</a-table>
|
||||
</template>
|
||||
<style>
|
||||
.gray-table-row {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import {deleteLdapRecord, getLdapRecord} from '@/api/record'
|
||||
import {store} from '@/main'
|
||||
import FilterDropdown from '@/components/FilterDropdown'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
sorter: true,
|
||||
sortDirections: ['descend', 'ascend'],
|
||||
},
|
||||
{
|
||||
title: 'REQUEST TIME',
|
||||
dataIndex: 'request_time',
|
||||
key: 'request_time',
|
||||
scopedSlots: {customRender: 'time'},
|
||||
},
|
||||
{
|
||||
title: 'RULE',
|
||||
dataIndex: 'rule_name',
|
||||
key: 'rule_name',
|
||||
scopedSlots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'FLAG',
|
||||
dataIndex: 'flag',
|
||||
key: 'flag',
|
||||
scopedSlots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'PATH',
|
||||
dataIndex: 'path',
|
||||
key: 'path',
|
||||
ellipsis: true,
|
||||
scopedSlots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'REMOTE IP',
|
||||
key: 'remote_ip',
|
||||
dataIndex: 'remote_ip',
|
||||
scopedSlots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'IP AREA',
|
||||
key: 'ip_area',
|
||||
dataIndex: 'ip_area'
|
||||
}
|
||||
];
|
||||
|
||||
export default {
|
||||
name: 'LdapLogs',
|
||||
data() {
|
||||
return {
|
||||
store,
|
||||
data: [],
|
||||
pagination: {
|
||||
current: 1, showSizeChanger: true, pageSize: store.pageSize,
|
||||
onShowSizeChange: (current, size) => {
|
||||
store.pageSize = size
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
order: "desc",
|
||||
loading: false,
|
||||
columns,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleTableChange(pagination, filters, sorter) {
|
||||
const pager = {...this.pagination};
|
||||
pager.current = pagination.current;
|
||||
this.pagination = pager;
|
||||
this.order = sorter.order === "ascend" ? "asc" : "desc"
|
||||
this.fetch();
|
||||
},
|
||||
fetch: function () {
|
||||
let params = {
|
||||
...this.filters,
|
||||
page: this.pagination.current,
|
||||
pageSize: this.pagination.pageSize,
|
||||
order: this.order
|
||||
}
|
||||
this.loading = true;
|
||||
getLdapRecord(params).then(res => {
|
||||
let result = res.data.result
|
||||
this.data = result.data
|
||||
const pagination = {...this.pagination};
|
||||
|
||||
pagination.total = result.count;
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
delete: function () {
|
||||
let params = {
|
||||
...this.filters,
|
||||
}
|
||||
this.loading = true;
|
||||
deleteLdapRecord(params).then(() => {
|
||||
this.$message.success('Deleted successfully')
|
||||
this.filters = {}
|
||||
this.fetch()
|
||||
}).catch(e => {
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Failed to delete: ' + e.response.data.error)
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetch();
|
||||
},
|
||||
components: {
|
||||
FilterDropdown
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -69,7 +70,7 @@
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import {getMysqlRecord} from '@/api/record'
|
||||
import {deleteMysqlRecord, getMysqlRecord} from '@/api/record'
|
||||
import {store} from '@/main'
|
||||
import FilterDropdown from '@/components/FilterDropdown'
|
||||
|
||||
@@ -120,6 +121,15 @@ const columns = [
|
||||
filterIcon: 'filterIcon',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'SCHEMA',
|
||||
dataIndex: 'schema',
|
||||
key: 'schema',
|
||||
scopedSlots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'LOAD DATA',
|
||||
dataIndex: 'load_local_data',
|
||||
@@ -216,11 +226,23 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
console.error(e)
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
delete: function () {
|
||||
let params = {
|
||||
...this.filters,
|
||||
}
|
||||
this.loading = true;
|
||||
deleteMysqlRecord(params).then(() => {
|
||||
this.$message.success('Deleted successfully')
|
||||
this.filters = {}
|
||||
this.fetch()
|
||||
}).catch(e => {
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Failed to delete: ' + e.response.data.error)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -36,7 +37,7 @@
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import {getRmiRecord} from '@/api/record'
|
||||
import {deleteRmiRecord, getRmiRecord} from '@/api/record'
|
||||
import {store} from '@/main'
|
||||
import FilterDropdown from '@/components/FilterDropdown'
|
||||
|
||||
@@ -109,7 +110,8 @@ export default {
|
||||
onShowSizeChange: (current, size) => {
|
||||
store.pageSize = size
|
||||
}
|
||||
}, filters: {},
|
||||
},
|
||||
filters: {},
|
||||
order: "desc",
|
||||
loading: false,
|
||||
columns,
|
||||
@@ -140,11 +142,23 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
console.error(e)
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
delete: function () {
|
||||
let params = {
|
||||
...this.filters,
|
||||
}
|
||||
this.loading = true;
|
||||
deleteRmiRecord(params).then(() => {
|
||||
this.$message.success('Deleted successfully')
|
||||
this.filters = {}
|
||||
this.fetch()
|
||||
}).catch(e => {
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Failed to delete: ' + e.response.data.error)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
@close="closeDrawer"
|
||||
>
|
||||
<a-form-model :model="form" ref="form" layout="vertical" @submit="handleSubmit">
|
||||
<BasicRule :form="form" :readOnly="formReadOnly"/>
|
||||
<BasicRule :form="form" :readOnly="formReadOnly" flagFormat="domain"/>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="12">
|
||||
<a-form-model-item label="Type" :rules="rules.type">
|
||||
@@ -51,7 +51,7 @@
|
||||
<span slot="label">
|
||||
Value
|
||||
<a-tooltip
|
||||
title="Support template such as ${varname}">
|
||||
title="Support template such as ${flag}/${custom_varname}">
|
||||
<a-icon type="question-circle-o"/>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
@@ -90,6 +90,7 @@
|
||||
</a-drawer>
|
||||
<!-- rule table -->
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -296,7 +297,7 @@ export default {
|
||||
onShowSizeChange: (current, size) => {
|
||||
store.pageSize = size
|
||||
}
|
||||
}, filters: {},
|
||||
}, filters: {},
|
||||
loading: false,
|
||||
columns,
|
||||
colors,
|
||||
@@ -332,18 +333,8 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
this.$notification.error({
|
||||
message: 'Unknown error: ' + e.response.status,
|
||||
style: {
|
||||
width: '100px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
@close="closeDrawer"
|
||||
>
|
||||
<a-form-model :model="form" ref="form" layout="vertical" @submit="handleSubmit">
|
||||
<BasicRule :form="form" :readOnly="formReadOnly"/>
|
||||
<BasicRule :form="form" :readOnly="formReadOnly" flagFormat="user or password"/>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
<a-form-model-item>
|
||||
@@ -28,7 +28,7 @@
|
||||
<a-input
|
||||
v-model="form.pasv_address"
|
||||
style="width: 100%"
|
||||
placeholder="use default value in the config"
|
||||
placeholder="Use `external_ip:pasv_port` by default"
|
||||
:readOnly="formReadOnly"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
@@ -42,7 +42,7 @@
|
||||
<a-tooltip
|
||||
title="1. The data to be returned when the client executes the download request.
|
||||
2. Please use base64 encoding.
|
||||
3. Support template such as ${user}/${password}/${varname}">
|
||||
3. Support template such as ${user}/${password}/${flag}/${custom_varname}">
|
||||
<a-icon type="question-circle-o"/>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
@@ -78,6 +78,7 @@
|
||||
</a-drawer>
|
||||
<!-- rule table -->
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -267,18 +268,8 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
this.$notification.error({
|
||||
message: 'Unknown error: ' + e.response.status,
|
||||
style: {
|
||||
width: '100px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
@close="closeDrawer"
|
||||
>
|
||||
<a-form-model :model="form" ref="form" layout="vertical" @submit="handleSubmit">
|
||||
<BasicRule :form="form" :readOnly="formReadOnly"/>
|
||||
<BasicRule :form="form" :readOnly="formReadOnly" flagFormat="raw message"/>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
<a-form-model-item :rules="rules.response_status_code"
|
||||
@@ -21,7 +21,7 @@
|
||||
<span slot="label">
|
||||
Response Status Code
|
||||
<a-tooltip
|
||||
title="Number between 100-600, or template such as ${query.varname}/${body.varname}/${header.varname}">
|
||||
title="Number between 100-600, or template such as ${query.varname}/${body.varname}/${header.varname}/${flag}/${custom_varname}">
|
||||
<a-icon type="question-circle-o"/>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
@@ -130,6 +130,7 @@
|
||||
</a-drawer>
|
||||
<!-- rule table -->
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -374,18 +375,8 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
this.$notification.error({
|
||||
message: 'Unknown error: ' + e.response.status,
|
||||
style: {
|
||||
width: '100px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
<template xmlns:a-col="http://www.w3.org/1999/html">
|
||||
<div>
|
||||
<a-button id="add-rule" type="primary" @click="addRule">
|
||||
<a-icon type="plus"/>
|
||||
New Rule
|
||||
</a-button>
|
||||
<!-- rule form-->
|
||||
<a-drawer
|
||||
:title="formAction+ ' RMI rule'"
|
||||
:width="490"
|
||||
:visible="formVisible"
|
||||
:body-style="{ paddingBottom: '80px' }"
|
||||
@close="closeDrawer"
|
||||
>
|
||||
<a-form-model :model="form" ref="form" layout="vertical" @submit="handleSubmit">
|
||||
<BasicRule :form="form" :readOnly="formReadOnly" flagFormat="path"/>
|
||||
</a-form-model>
|
||||
<div
|
||||
:style="{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
borderTop: '1px solid #e9e9e9',
|
||||
padding: '10px 16px',
|
||||
background: '#fff',
|
||||
textAlign: 'right',
|
||||
zIndex: 1,
|
||||
}"
|
||||
>
|
||||
<a-button :style="{ marginRight: '8px' }" @click="handleCancel">
|
||||
Cancel
|
||||
</a-button>
|
||||
<a-button type="primary" :disabled="formReadOnly" @click="handleSubmit">
|
||||
Submit
|
||||
</a-button>
|
||||
</div>
|
||||
</a-drawer>
|
||||
<!-- rule table -->
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<div
|
||||
slot="filterDropdown"
|
||||
slot-scope="{ setSelectedKeys, selectedKeys, clearFilters, column }"
|
||||
style="padding: 8px"
|
||||
>
|
||||
<a-input
|
||||
:placeholder="`Search ${column.dataIndex}`"
|
||||
:value="selectedKeys[0]"
|
||||
style="width: 188px; margin-bottom: 8px; display: block;"
|
||||
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
|
||||
@pressEnter="() => {filters[column.dataIndex] = selectedKeys[0];fetch()}"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
icon="search"
|
||||
size="small"
|
||||
style="width: 90px; margin-right: 8px"
|
||||
@click="() => {filters[column.dataIndex] = selectedKeys[0];fetch()}"
|
||||
>
|
||||
Search
|
||||
</a-button>
|
||||
</div>
|
||||
<a-icon
|
||||
slot="filterIcon"
|
||||
slot-scope="filtered"
|
||||
type="search"
|
||||
:style="{ color: filtered ? '#108ee9' : undefined }"
|
||||
/>
|
||||
<span slot="rank" slot-scope="rank">
|
||||
<a-tag
|
||||
:color="'#'+(0x2db7f5+rank*80).toString(16)"
|
||||
>
|
||||
{{ rank }}
|
||||
</a-tag>
|
||||
</span>
|
||||
|
||||
<span slot="switchRender" slot-scope="checked,record,index,dataIndex">
|
||||
<a-switch :checked="checked" @click="clickSwitch(record,dataIndex.dataIndex)"></a-switch>
|
||||
</span>
|
||||
<span slot="valueRender" slot-scope="values">
|
||||
<span v-for="value in values.split(',')" :key="value">{{ value }}<br/></span>
|
||||
</span>
|
||||
<span slot="action" slot-scope="text,record,index">
|
||||
<a-button @click="viewRule(record)" style="
|
||||
color: #67C23A;
|
||||
background-color: transparent;
|
||||
border-color: #67C23A;
|
||||
text-shadow: none;
|
||||
margin:0 10px 3px 0;
|
||||
" size="small" ghost>View</a-button>
|
||||
<a-button @click="editRule(record,index)" style="
|
||||
color: #909399;
|
||||
background-color: transparent;
|
||||
border-color: #909399;
|
||||
text-shadow: none;
|
||||
margin:0 10px 3px 0;
|
||||
" size="small" ghost>Edit</a-button>
|
||||
<a-popconfirm
|
||||
title="Are you sure delete this task?"
|
||||
ok-text="Yes"
|
||||
cancel-text="No"
|
||||
@confirm="deleteRule(record,index)"
|
||||
>
|
||||
<a-button type="danger" size="small" ghost>Delete</a-button>
|
||||
</a-popconfirm>
|
||||
</span>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
#add-rule {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import {getLdapRule, upsertLdapRule, deleteLdapRule} from '@/api/rule'
|
||||
import {store} from '@/main'
|
||||
import BasicRule from "@/components/BasicRule";
|
||||
|
||||
const VIEW = "View"
|
||||
const EDIT = "Edit"
|
||||
const CREATE = "Create"
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
sorter: true,
|
||||
sortDirections: ['descend', 'ascend'],
|
||||
},
|
||||
{
|
||||
title: 'NAME',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
scopedSlots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'FLAG FORMAT',
|
||||
dataIndex: 'flag_format',
|
||||
key: 'flag_format',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'RANK',
|
||||
dataIndex: 'rank',
|
||||
key: 'rank',
|
||||
scopedSlots: {
|
||||
customRender: 'rank',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'PUSH TO CLIENT',
|
||||
dataIndex: 'push_to_client',
|
||||
key: 'push_to_client',
|
||||
scopedSlots: {
|
||||
customRender: 'switchRender',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'NOTICE',
|
||||
dataIndex: 'notice',
|
||||
key: 'notice',
|
||||
scopedSlots: {
|
||||
customRender: 'switchRender',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Action',
|
||||
key: 'action',
|
||||
scopedSlots: {customRender: 'action'},
|
||||
},
|
||||
];
|
||||
export default {
|
||||
name: 'LdapRules',
|
||||
data() {
|
||||
return {
|
||||
store,
|
||||
data: [],
|
||||
formVisible: false,
|
||||
pagination: {
|
||||
current: 1, showSizeChanger: true, pageSize: store.pageSize,
|
||||
onShowSizeChange: (current, size) => {
|
||||
store.pageSize = size
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
loading: false,
|
||||
columns,
|
||||
form: {},
|
||||
formReadOnly: false,
|
||||
formAction: "", // View ,Create or Edit
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleTableChange(pagination, filters, sorter) {
|
||||
const pager = {...this.pagination};
|
||||
pager.current = pagination.current;
|
||||
this.pagination = pager;
|
||||
this.order = sorter.order === "ascend" ? "asc" : "desc"
|
||||
this.fetch();
|
||||
},
|
||||
fetch: function () {
|
||||
let params = {
|
||||
...this.filters,
|
||||
page: this.pagination.current,
|
||||
pageSize: this.pagination.pageSize,
|
||||
order: this.order
|
||||
}
|
||||
this.loading = true;
|
||||
getLdapRule(params).then(res => {
|
||||
let result = res.data.result
|
||||
this.data = result.data
|
||||
const pagination = {...this.pagination};
|
||||
pagination.total = result.count;
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
clickSwitch(record, prop) {
|
||||
record[prop] = !record[prop]
|
||||
upsertLdapRule(record).then().catch(e => {
|
||||
this.$notification.error({
|
||||
message: 'Edit failed',
|
||||
description:
|
||||
e.response.data.error,
|
||||
style: {
|
||||
width: '600px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
})
|
||||
},
|
||||
addRule() {
|
||||
this.form = {}
|
||||
this.showForm(CREATE)
|
||||
},
|
||||
viewRule(record) {
|
||||
this.form = record
|
||||
this.showForm(VIEW)
|
||||
},
|
||||
editRule(record) {
|
||||
this.form = JSON.parse(JSON.stringify(record))
|
||||
this.showForm(EDIT)
|
||||
},
|
||||
deleteRule(record, index) {
|
||||
deleteLdapRule(record).then(() => {
|
||||
this.data.splice(index, 1)
|
||||
}).catch(e => {
|
||||
this.$notification.error({
|
||||
message: 'Error',
|
||||
description:
|
||||
e.response.data.error,
|
||||
style: {
|
||||
width: '600px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
})
|
||||
},
|
||||
showForm(action) {
|
||||
this.formAction = action
|
||||
this.formReadOnly = action === VIEW;
|
||||
this.formVisible = true;
|
||||
},
|
||||
closeDrawer() {
|
||||
this.formVisible = false;
|
||||
},
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
upsertLdapRule(this.form).then(() => {
|
||||
this.closeDrawer()
|
||||
this.fetch({page: this.pagination.current});
|
||||
this.$notification.info({
|
||||
message: 'Success',
|
||||
style: {
|
||||
width: '600px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 2.5
|
||||
});
|
||||
}).catch(e => {
|
||||
this.$notification.error({
|
||||
message: this.formAction + ' failed',
|
||||
description:
|
||||
e.response.data.error,
|
||||
style: {
|
||||
width: '600px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleCancel() {
|
||||
this.form = {}
|
||||
this.closeDrawer()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetch({page: "1"});
|
||||
},
|
||||
components: {
|
||||
BasicRule,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -13,7 +13,7 @@
|
||||
@close="closeDrawer"
|
||||
>
|
||||
<a-form-model :model="form" ref="form" layout="vertical" @submit="handleSubmit">
|
||||
<BasicRule :form="form" :readOnly="formReadOnly"/>
|
||||
<BasicRule :form="form" :readOnly="formReadOnly" :flagField="'user or schema'"/>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
<a-form-model-item label="Files" :rules="rules.files">
|
||||
@@ -31,7 +31,8 @@
|
||||
<a-form-model-item>
|
||||
<div class="ant-form-item-label">
|
||||
<label for="exploit-jdbc-client">Exploit Jdbc Client
|
||||
<a-tooltip placement="topLeft" title="Whether test to exploit jdbc client.">
|
||||
<a-tooltip placement="topLeft"
|
||||
title="Whether test to exploit jdbc client.">
|
||||
<a-icon type="question-circle"/>
|
||||
</a-tooltip>
|
||||
</label>
|
||||
@@ -41,8 +42,13 @@
|
||||
</a-row>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
<a-form-model-item label="Payload">
|
||||
<a-input-group compact v-for="payloadKey in payloadKeys" :key="payloadKey">
|
||||
<a-form-model-item>
|
||||
<label for="payload">Payload
|
||||
<a-tooltip placement="topLeft" title="Need to set ${payload} variable by flag format first. Payload which key is same as ${payload} will be used.">
|
||||
<a-icon type="question-circle"/>
|
||||
</a-tooltip>
|
||||
</label>
|
||||
<a-input-group id="payload" compact v-for="payloadKey in payloadKeys" :key="payloadKey">
|
||||
<a-input v-model="form['Key-'+payloadKey]"
|
||||
style="width: 47%;margin-bottom: 5px"
|
||||
v-decorator="['Key-'+payloadKey,]"
|
||||
@@ -94,6 +100,7 @@
|
||||
</a-drawer>
|
||||
<!-- rule table -->
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -256,7 +263,7 @@ export default {
|
||||
onShowSizeChange: (current, size) => {
|
||||
store.pageSize = size
|
||||
}
|
||||
}, filters: {},
|
||||
}, filters: {},
|
||||
loading: false,
|
||||
columns,
|
||||
form: {},
|
||||
@@ -291,19 +298,14 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
this.$notification.error({
|
||||
this.$notification.error({
|
||||
message: 'Unknown error: ' + e.response.status,
|
||||
style: {
|
||||
width: '100px',
|
||||
width: '400px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
clickSwitch(record, prop) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
@close="closeDrawer"
|
||||
>
|
||||
<a-form-model :model="form" ref="form" layout="vertical" @submit="handleSubmit">
|
||||
<BasicRule :form="form" :readOnly="formReadOnly"/>
|
||||
<BasicRule :form="form" :readOnly="formReadOnly" flagFormat="path"/>
|
||||
</a-form-model>
|
||||
<div
|
||||
:style="{
|
||||
@@ -38,6 +38,7 @@
|
||||
</a-drawer>
|
||||
<!-- rule table -->
|
||||
<a-table
|
||||
style="overflow-x: auto;"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
:loading="loading"
|
||||
@@ -193,7 +194,8 @@ export default {
|
||||
onShowSizeChange: (current, size) => {
|
||||
store.pageSize = size
|
||||
}
|
||||
}, filters: {},
|
||||
},
|
||||
filters: {},
|
||||
loading: false,
|
||||
columns,
|
||||
form: {},
|
||||
@@ -225,18 +227,8 @@ export default {
|
||||
this.pagination = pagination;
|
||||
this.loading = false
|
||||
}).catch(e => {
|
||||
if (e.response.status === 403) {
|
||||
store.authed = false
|
||||
return []
|
||||
} else {
|
||||
this.$notification.error({
|
||||
message: 'Unknown error: ' + e.response.status,
|
||||
style: {
|
||||
width: '100px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
if (e.response.status !== 403) {
|
||||
this.$message.error('Unknown error with status code: ' + e.response.status)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getHttpConfig, updateHttpConfig} from "@/api/settings"
|
||||
import {getPlatformConfig, updatePlatformConfig} from "@/api/settings"
|
||||
import SettingForm from "@/components/SettingForm";
|
||||
|
||||
export default {
|
||||
@@ -37,7 +37,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getConfig() {
|
||||
getHttpConfig().then(res => {
|
||||
getPlatformConfig().then(res => {
|
||||
this.form = res.data
|
||||
}).catch(e => {
|
||||
this.$notification.error({
|
||||
@@ -55,10 +55,10 @@ export default {
|
||||
updateConfig() {
|
||||
this.spinning = true
|
||||
let targetConfig = JSON.stringify(this.form)
|
||||
updateHttpConfig(this.form).then(
|
||||
updatePlatformConfig(this.form).then(
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
getHttpConfig().then((res) => {
|
||||
getPlatformConfig().then((res) => {
|
||||
this.spinning = false
|
||||
let nowConfig = JSON.stringify(res.data)
|
||||
if (nowConfig !== targetConfig) {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div>
|
||||
<SettingForm :form="form" :spinning="spinning"></SettingForm>
|
||||
<a-result v-if="status"
|
||||
:status="status"
|
||||
:title="title"
|
||||
:sub-title="subTitle"
|
||||
>
|
||||
<template #extra>
|
||||
<a-row>
|
||||
<a-col :span="12" :offset="7">
|
||||
<div style="text-align: left">
|
||||
<li v-for="err in errors" :key="err">{{ err }}</li>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
</a-result>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getLdapConfig, updateLdapConfig} from "@/api/settings"
|
||||
import SettingForm from "@/components/SettingForm";
|
||||
|
||||
export default {
|
||||
name: "Ldap",
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
spinning: false,
|
||||
status: "",
|
||||
title: "",
|
||||
subTitle: "",
|
||||
errors: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getConfig() {
|
||||
getLdapConfig().then(res => {
|
||||
this.form = res.data
|
||||
}).catch(e => {
|
||||
this.$notification.error({
|
||||
message: 'Error',
|
||||
description:
|
||||
e.response.data.error,
|
||||
style: {
|
||||
width: '600px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
})
|
||||
},
|
||||
updateConfig() {
|
||||
this.spinning = true
|
||||
let targetConfig = JSON.stringify(this.form)
|
||||
updateLdapConfig(this.form).then(
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
getLdapConfig().then((res) => {
|
||||
this.spinning = false
|
||||
let nowConfig = JSON.stringify(res.data)
|
||||
if (nowConfig !== targetConfig) {
|
||||
this.status = "warning"
|
||||
this.title = "Updating the configuration seems to have failed"
|
||||
this.subTitle = "Please check your config options carefully."
|
||||
}
|
||||
this.form = res.data
|
||||
this.status = ""
|
||||
this.title = ""
|
||||
this.subTitle = ""
|
||||
}
|
||||
)
|
||||
}, 3000)
|
||||
}
|
||||
).catch(e => {
|
||||
this.$notification.error({
|
||||
message: 'Error',
|
||||
description:
|
||||
e.response.data.error,
|
||||
style: {
|
||||
width: '600px',
|
||||
marginLeft: `${335 - 600}px`,
|
||||
},
|
||||
duration: 4
|
||||
});
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getConfig()
|
||||
},
|
||||
components: {
|
||||
SettingForm
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -5,13 +5,14 @@
|
||||
:active-tab-key="tabKey"
|
||||
@tabChange="key => this.tabKey = key"
|
||||
style="width: 100%;">
|
||||
<http v-if="tabKey==='HTTP'"></http>
|
||||
<dns v-else-if="tabKey==='DNS'"></dns>
|
||||
<rmi v-else-if="tabKey==='RMI'"></rmi>
|
||||
<mysql v-else-if="tabKey==='MYSQL'"></mysql>
|
||||
<ftp v-else-if="tabKey==='FTP'"></ftp>
|
||||
<notice v-else-if="tabKey==='NOTICE'"></notice>
|
||||
<rules v-else-if="tabKey==='RULES'"></rules>
|
||||
<http ref="settings" v-if="tabKey==='HTTP'"></http>
|
||||
<dns ref="settings" v-else-if="tabKey==='DNS'"></dns>
|
||||
<rmi ref="settings" v-else-if="tabKey==='RMI'"></rmi>
|
||||
<ldap ref="settings" v-else-if="tabKey==='LDAP'"></ldap>
|
||||
<mysql ref="settings" v-else-if="tabKey==='MYSQL'"></mysql>
|
||||
<ftp ref="settings" v-else-if="tabKey==='FTP'"></ftp>
|
||||
<notice ref="settings" v-else-if="tabKey==='NOTICE'"></notice>
|
||||
<rules ref="settings" v-else-if="tabKey==='RULES'"></rules>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
@@ -20,6 +21,7 @@
|
||||
import Http from "./Http"
|
||||
import Dns from "./Dns"
|
||||
import Rmi from "./Rmi"
|
||||
import Ldap from "./Ldap"
|
||||
import Mysql from "./Mysql"
|
||||
import Ftp from "./Ftp"
|
||||
import Notice from "./Notice"
|
||||
@@ -33,6 +35,7 @@ export default {
|
||||
{key: "HTTP", tab: "PLATFORM|HTTP"},
|
||||
{key: "DNS", tab: "DNS"},
|
||||
{key: "RMI", tab: "RMI"},
|
||||
{key: "LDAP", tab: "LDAP"},
|
||||
{key: "MYSQL", tab: "MYSQL"},
|
||||
{key: "FTP", tab: "FTP"},
|
||||
{key: "NOTICE", tab: "NOTICE"},
|
||||
@@ -42,11 +45,16 @@ export default {
|
||||
}
|
||||
}
|
||||
,
|
||||
methods: {},
|
||||
methods: {
|
||||
fetch() {
|
||||
this.$refs.settings.getConfig();
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Http,
|
||||
Dns,
|
||||
Rmi,
|
||||
Ldap,
|
||||
Mysql,
|
||||
Ftp,
|
||||
Notice,
|
||||
|
||||
@@ -12,13 +12,13 @@ module.exports = {
|
||||
'/api': {
|
||||
target: 'http://localhost:10000',
|
||||
pathRewrite: {
|
||||
'^/revsuit/api': '/revsuit/api'
|
||||
'^/api': '/revsuit/api'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
productionSourceMap:false,
|
||||
productionSourceMap: false,
|
||||
runtimeCompiler: true,
|
||||
filenameHashing: false,
|
||||
publicPath: ''
|
||||
publicPath: '/revsuit/admin/',
|
||||
}
|
||||
|
||||
@@ -4,31 +4,33 @@ go 1.16
|
||||
|
||||
require (
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/fatih/color v1.10.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.2.0
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-playground/validator/v10 v10.4.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/golang/protobuf v1.4.3 // indirect
|
||||
github.com/jinzhu/now v1.1.2 // indirect
|
||||
github.com/json-iterator/go v1.1.10 // indirect
|
||||
github.com/gin-gonic/gin v1.7.2
|
||||
github.com/glebarez/sqlite v1.3.3
|
||||
github.com/go-playground/validator/v10 v10.7.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.6 // indirect
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/miekg/dns v1.1.38
|
||||
github.com/oschwald/geoip2-golang v1.5.0
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rhysd/go-github-selfupdate v1.2.3
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sinlov/qqwry-golang v0.0.0-20191204062238-bea9868bbbf4
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/ugorji/go v1.2.4 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/ugorji/go v1.2.6 // indirect
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341 // indirect
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
gorm.io/driver/sqlite v1.1.4
|
||||
gorm.io/gorm v1.21.4
|
||||
gorm.io/driver/mysql v1.2.1
|
||||
gorm.io/driver/postgres v1.2.3
|
||||
gorm.io/gorm v1.22.4
|
||||
unknwon.dev/clog/v2 v2.2.0
|
||||
vitess.io/vitess v0.9.0
|
||||
)
|
||||
|
||||
@@ -34,7 +34,10 @@ github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3
|
||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||
github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
|
||||
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
@@ -72,6 +75,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/buger/jsonparser v0.0.0-20200322175846-f7e751efca13/go.mod h1:tgcrVJ81GPSF0mz+0nu1Xaz0fazGPrmmJfJtxjbHhUQ=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@@ -80,6 +84,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA=
|
||||
@@ -137,15 +143,21 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
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.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
|
||||
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/glebarez/go-sqlite v1.14.5 h1:kSjlUZFt/Uy4ZzJG/FjzNVfHfFqqUKTHVy+J6EKQKhk=
|
||||
github.com/glebarez/go-sqlite v1.14.5/go.mod h1:uw5Rp1iEmkACQBl+djShb9eBdoLR9nRRqpCpbdt+1pM=
|
||||
github.com/glebarez/sqlite v1.3.3 h1:Sp3DGh6ZbSnv2l8dV5ECRvlLLHZvUhxkq4RXlO4dqbs=
|
||||
github.com/glebarez/sqlite v1.3.3/go.mod h1:18ms2rP2nM4lUdLwNKSL/p/xPkS0Kkwnz02s27ojfNk=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||
@@ -197,12 +209,15 @@ github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8c
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-playground/validator/v10 v10.7.0 h1:gLi5ajTBBheLNt0ctewgq7eolXoDALQd5/y90Hh9ZgM=
|
||||
github.com/go-playground/validator/v10 v10.7.0/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
@@ -226,8 +241,9 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@@ -235,9 +251,13 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github/v27 v27.0.4/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0=
|
||||
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 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -248,6 +268,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
@@ -310,13 +332,64 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
||||
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
|
||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8=
|
||||
github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
|
||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns=
|
||||
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||
github.com/jackc/pgtype v1.9.0 h1:/SH1RxEtltvJgsDqp3TbiTFApD3mey3iygpuEGeuBXk=
|
||||
github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||
github.com/jackc/pgx/v4 v4.14.0 h1:TgdrmgnM7VY72EuSQzBbBd4JA1RLqJolrw9nQVZABVc=
|
||||
github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
|
||||
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI=
|
||||
github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
@@ -324,13 +397,14 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
@@ -345,12 +419,18 @@ github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/krishicks/yaml-patch v0.0.10/go.mod h1:Sm5TchwZS6sm7RJoyg87tzxm2ZcKzdRE4Q7TjNhPrME=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/looplab/fsm v0.2.0/go.mod h1:p+IElwgCnAByqr2DWMuNbPjgMwqcHvTRZZn3dvKEke0=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
@@ -364,6 +444,7 @@ github.com/martini-contrib/auth v0.0.0-20150219114609-fa62c19b7ae8/go.mod h1:ahT
|
||||
github.com/martini-contrib/gzip v0.0.0-20151124214156-6c035326b43f/go.mod h1:jhUB0rZB2TPWqy0yGugKRRictO591eSO7If7O4MfCaA=
|
||||
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
@@ -371,17 +452,18 @@ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
@@ -423,10 +505,16 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
|
||||
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
|
||||
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
|
||||
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
@@ -470,8 +558,15 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag=
|
||||
github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzxazpPAODuqarmPDe2Rg=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@@ -483,10 +578,14 @@ github.com/samuel/go-zookeeper v0.0.0-20200724154423-2164a8ac840e/go.mod h1:gi+0
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sinlov/qqwry-golang v0.0.0-20191204062238-bea9868bbbf4 h1:61LVBhbJS5O8mK3roLwSUDXBSvdQ2MjnOMqnGCgIRko=
|
||||
github.com/sinlov/qqwry-golang v0.0.0-20191204062238-bea9868bbbf4/go.mod h1:ddgkUYVfqz6Adxc3zINDNKi3NHuq84KhoZju4D024LQ=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sjmudd/stopwatch v0.0.0-20170613150411-f380bf8a9be1/go.mod h1:Pgf1sZ2KrHK8vdRTV5UHGp80LT7HMUKuNAiKC402abY=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
@@ -518,10 +617,14 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tchap/go-patricia v0.0.0-20160729071656-dd168db6051b/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
|
||||
github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw=
|
||||
github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE=
|
||||
github.com/tebeka/selenium v0.9.9/go.mod h1:5Fr8+pUvU6B1OiPfkdCKdXZyr5znvVkxuPd0NOdZCQc=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tinylib/msgp v1.1.1/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
@@ -532,12 +635,14 @@ github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex
|
||||
github.com/uber/jaeger-client-go v2.16.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/uber/jaeger-lib v2.0.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.4 h1:cTciPbZ/VSOzCLKclmssnfQ/jyoVyOcJ3aoJyUV1Urc=
|
||||
github.com/ugorji/go v1.2.4/go.mod h1:EuaSCk8iZMdIspsu6HXH7X2UGKw1ezO4wCfGszGmmo4=
|
||||
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
|
||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.4 h1:C5VurWRRCKjuENsbM6GYVw8W++WVW9rSxoACKIvxzz8=
|
||||
github.com/ugorji/go/codec v1.2.4/go.mod h1:bWBu1+kIRWcF8uMklKaJrR6fTWQOwAlrIzX22pHwryA=
|
||||
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||
github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I=
|
||||
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
@@ -549,6 +654,7 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/z-division/go-zookeeper v0.0.0-20190128072838-6d7457066b9b/go.mod h1:JNALoWa+nCXR8SmgLluHcBNVJgyejzpKPZk9pX2yXXE=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
@@ -559,8 +665,15 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -568,6 +681,7 @@ golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b/go.mod h1:6SG95UA2DQfeDnf
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -577,8 +691,12 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -628,10 +746,13 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -656,6 +777,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -663,26 +785,37 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341 h1:2/QtM1mL37YmcsT8HaDNHDgTqqFVw+zr8UzMiBVLzYU=
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201126233918-771906719818/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-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -699,6 +832,7 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
@@ -708,14 +842,21 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw
|
||||
golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201202200335-bef1c476418a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -730,8 +871,10 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -759,10 +902,11 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
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.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/DataDog/dd-trace-go.v1 v1.17.0/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||
@@ -774,6 +918,7 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.41.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
@@ -794,11 +939,13 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM=
|
||||
gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw=
|
||||
gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.21.4 h1:J0xfPJMRfHgpVcYLrEAIqY/apdvTIkrltPQNHQLq9Qc=
|
||||
gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/driver/mysql v1.2.1 h1:h+3f1l9Ng2C072Y2tIiLgPpWN78r1KXL7bHJ0nTjlhU=
|
||||
gorm.io/driver/mysql v1.2.1/go.mod h1:qsiz+XcAyMrS6QY+X3M9R6b/lKM1imKmcuK9kac5LTo=
|
||||
gorm.io/driver/postgres v1.2.3 h1:f4t0TmNMy9gh3TU2PX+EppoA6YsgFnyq8Ojtddb42To=
|
||||
gorm.io/driver/postgres v1.2.3/go.mod h1:pJV6RgYQPG47aM1f0QeOzFH9HxQc8JcmAgjRCgS0wjs=
|
||||
gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||
gorm.io/gorm v1.22.4 h1:8aPcyEJhY0MAt8aY6Dc524Pn+pO29K+ydu+e/cXSpQM=
|
||||
gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -820,11 +967,123 @@ k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
||||
modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.33.11/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.34.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.4/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.5/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.7/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.8/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.10/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
|
||||
modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw=
|
||||
modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI=
|
||||
modernc.org/ccgo/v3 v3.11.1/go.mod h1:lWHxfsn13L3f7hgGsGlU28D9eUOf6y3ZYHKoPaKU0ag=
|
||||
modernc.org/ccgo/v3 v3.11.3/go.mod h1:0oHunRBMBiXOKdaglfMlRPBALQqsfrCKXgw9okQ3GEw=
|
||||
modernc.org/ccgo/v3 v3.12.4/go.mod h1:Bk+m6m2tsooJchP/Yk5ji56cClmN6R1cqc9o/YtbgBQ=
|
||||
modernc.org/ccgo/v3 v3.12.6/go.mod h1:0Ji3ruvpFPpz+yu+1m0wk68pdr/LENABhTrDkMDWH6c=
|
||||
modernc.org/ccgo/v3 v3.12.8/go.mod h1:Hq9keM4ZfjCDuDXxaHptpv9N24JhgBZmUG5q60iLgUo=
|
||||
modernc.org/ccgo/v3 v3.12.11/go.mod h1:0jVcmyDwDKDGWbcrzQ+xwJjbhZruHtouiBEvDfoIsdg=
|
||||
modernc.org/ccgo/v3 v3.12.14/go.mod h1:GhTu1k0YCpJSuWwtRAEHAol5W7g1/RRfS4/9hc9vF5I=
|
||||
modernc.org/ccgo/v3 v3.12.18/go.mod h1:jvg/xVdWWmZACSgOiAhpWpwHWylbJaSzayCqNOJKIhs=
|
||||
modernc.org/ccgo/v3 v3.12.20/go.mod h1:aKEdssiu7gVgSy/jjMastnv/q6wWGRbszbheXgWRHc8=
|
||||
modernc.org/ccgo/v3 v3.12.21/go.mod h1:ydgg2tEprnyMn159ZO/N4pLBqpL7NOkJ88GT5zNU2dE=
|
||||
modernc.org/ccgo/v3 v3.12.22/go.mod h1:nyDVFMmMWhMsgQw+5JH6B6o4MnZ+UQNw1pp52XYFPRk=
|
||||
modernc.org/ccgo/v3 v3.12.25/go.mod h1:UaLyWI26TwyIT4+ZFNjkyTbsPsY3plAEB6E7L/vZV3w=
|
||||
modernc.org/ccgo/v3 v3.12.29/go.mod h1:FXVjG7YLf9FetsS2OOYcwNhcdOLGt8S9bQ48+OP75cE=
|
||||
modernc.org/ccgo/v3 v3.12.36/go.mod h1:uP3/Fiezp/Ga8onfvMLpREq+KUjUmYMxXPO8tETHtA8=
|
||||
modernc.org/ccgo/v3 v3.12.38/go.mod h1:93O0G7baRST1vNj4wnZ49b1kLxt0xCW5Hsa2qRaZPqc=
|
||||
modernc.org/ccgo/v3 v3.12.43/go.mod h1:k+DqGXd3o7W+inNujK15S5ZYuPoWYLpF5PYougCmthU=
|
||||
modernc.org/ccgo/v3 v3.12.46/go.mod h1:UZe6EvMSqOxaJ4sznY7b23/k13R8XNlyWsO5bAmSgOE=
|
||||
modernc.org/ccgo/v3 v3.12.47/go.mod h1:m8d6p0zNps187fhBwzY/ii6gxfjob1VxWb919Nk1HUk=
|
||||
modernc.org/ccgo/v3 v3.12.50/go.mod h1:bu9YIwtg+HXQxBhsRDE+cJjQRuINuT9PUK4orOco/JI=
|
||||
modernc.org/ccgo/v3 v3.12.51/go.mod h1:gaIIlx4YpmGO2bLye04/yeblmvWEmE4BBBls4aJXFiE=
|
||||
modernc.org/ccgo/v3 v3.12.53/go.mod h1:8xWGGTFkdFEWBEsUmi+DBjwu/WLy3SSOrqEmKUjMeEg=
|
||||
modernc.org/ccgo/v3 v3.12.54/go.mod h1:yANKFTm9llTFVX1FqNKHE0aMcQb1fuPJx6p8AcUx+74=
|
||||
modernc.org/ccgo/v3 v3.12.55/go.mod h1:rsXiIyJi9psOwiBkplOaHye5L4MOOaCjHg1Fxkj7IeU=
|
||||
modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU=
|
||||
modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc=
|
||||
modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM=
|
||||
modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ=
|
||||
modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84=
|
||||
modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ=
|
||||
modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
|
||||
modernc.org/ccgo/v3 v3.12.84/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
|
||||
modernc.org/ccgo/v3 v3.12.86/go.mod h1:dN7S26DLTgVSni1PVA3KxxHTcykyDurf3OgUzNqTSrU=
|
||||
modernc.org/ccgo/v3 v3.12.88/go.mod h1:0MFzUHIuSIthpVZyMWiFYMwjiFnhrN5MkvBrUwON+ZM=
|
||||
modernc.org/ccgo/v3 v3.12.90/go.mod h1:obhSc3CdivCRpYZmrvO88TXlW0NvoSVvdh/ccRjJYko=
|
||||
modernc.org/ccgo/v3 v3.12.92/go.mod h1:5yDdN7ti9KWPi5bRVWPl8UNhpEAtCjuEE7ayQnzzqHA=
|
||||
modernc.org/ccgo/v3 v3.12.95/go.mod h1:ZcLyvtocXYi8uF+9Ebm3G8EF8HNY5hGomBqthDp4eC8=
|
||||
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
||||
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
|
||||
modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg=
|
||||
modernc.org/libc v1.11.2/go.mod h1:ioIyrl3ETkugDO3SGZ+6EOKvlP3zSOycUETe4XM4n8M=
|
||||
modernc.org/libc v1.11.5/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU=
|
||||
modernc.org/libc v1.11.6/go.mod h1:ddqmzR6p5i4jIGK1d/EiSw97LBcE3dK24QEwCFvgNgE=
|
||||
modernc.org/libc v1.11.11/go.mod h1:lXEp9QOOk4qAYOtL3BmMve99S5Owz7Qyowzvg6LiZso=
|
||||
modernc.org/libc v1.11.13/go.mod h1:ZYawJWlXIzXy2Pzghaf7YfM8OKacP3eZQI81PDLFdY8=
|
||||
modernc.org/libc v1.11.16/go.mod h1:+DJquzYi+DMRUtWI1YNxrlQO6TcA5+dRRiq8HWBWRC8=
|
||||
modernc.org/libc v1.11.19/go.mod h1:e0dgEame6mkydy19KKaVPBeEnyJB4LGNb0bBH1EtQ3I=
|
||||
modernc.org/libc v1.11.24/go.mod h1:FOSzE0UwookyT1TtCJrRkvsOrX2k38HoInhw+cSCUGk=
|
||||
modernc.org/libc v1.11.26/go.mod h1:SFjnYi9OSd2W7f4ct622o/PAYqk7KHv6GS8NZULIjKY=
|
||||
modernc.org/libc v1.11.27/go.mod h1:zmWm6kcFXt/jpzeCgfvUNswM0qke8qVwxqZrnddlDiE=
|
||||
modernc.org/libc v1.11.28/go.mod h1:Ii4V0fTFcbq3qrv3CNn+OGHAvzqMBvC7dBNyC4vHZlg=
|
||||
modernc.org/libc v1.11.31/go.mod h1:FpBncUkEAtopRNJj8aRo29qUiyx5AvAlAxzlx9GNaVM=
|
||||
modernc.org/libc v1.11.34/go.mod h1:+Tzc4hnb1iaX/SKAutJmfzES6awxfU1BPvrrJO0pYLg=
|
||||
modernc.org/libc v1.11.37/go.mod h1:dCQebOwoO1046yTrfUE5nX1f3YpGZQKNcITUYWlrAWo=
|
||||
modernc.org/libc v1.11.39/go.mod h1:mV8lJMo2S5A31uD0k1cMu7vrJbSA3J3waQJxpV4iqx8=
|
||||
modernc.org/libc v1.11.42/go.mod h1:yzrLDU+sSjLE+D4bIhS7q1L5UwXDOw99PLSX0BlZvSQ=
|
||||
modernc.org/libc v1.11.44/go.mod h1:KFq33jsma7F5WXiYelU8quMJasCCTnHK0mkri4yPHgA=
|
||||
modernc.org/libc v1.11.45/go.mod h1:Y192orvfVQQYFzCNsn+Xt0Hxt4DiO4USpLNXBlXg/tM=
|
||||
modernc.org/libc v1.11.47/go.mod h1:tPkE4PzCTW27E6AIKIR5IwHAQKCAtudEIeAV1/SiyBg=
|
||||
modernc.org/libc v1.11.49/go.mod h1:9JrJuK5WTtoTWIFQ7QjX2Mb/bagYdZdscI3xrvHbXjE=
|
||||
modernc.org/libc v1.11.51/go.mod h1:R9I8u9TS+meaWLdbfQhq2kFknTW0O3aw3kEMqDDxMaM=
|
||||
modernc.org/libc v1.11.53/go.mod h1:5ip5vWYPAoMulkQ5XlSJTy12Sz5U6blOQiYasilVPsU=
|
||||
modernc.org/libc v1.11.54/go.mod h1:S/FVnskbzVUrjfBqlGFIPA5m7UwB3n9fojHhCNfSsnw=
|
||||
modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M=
|
||||
modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18=
|
||||
modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8=
|
||||
modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
|
||||
modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0=
|
||||
modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
|
||||
modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
|
||||
modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY=
|
||||
modernc.org/libc v1.11.88/go.mod h1:h3oIVe8dxmTcchcFuCcJ4nAWaoiwzKCdv82MM0oiIdQ=
|
||||
modernc.org/libc v1.11.90/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c=
|
||||
modernc.org/libc v1.11.98/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c=
|
||||
modernc.org/libc v1.11.99/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI=
|
||||
modernc.org/libc v1.11.101/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI=
|
||||
modernc.org/libc v1.11.104 h1:gxoa5b3HPo7OzD4tKZjgnwXk/w//u1oovvjSMP3Q96Q=
|
||||
modernc.org/libc v1.11.104/go.mod h1:2MH3DaF/gCU8i/UBiVE1VFRos4o523M7zipmwH8SIgQ=
|
||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
|
||||
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
|
||||
modernc.org/memory v1.0.5 h1:XRch8trV7GgvTec2i7jc33YlUI0RKVDBvZ5eZ5m8y14=
|
||||
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
|
||||
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.14.3 h1:psrTwgpEujgWEP3FNdsC9yNh5tSeA77U0GeWhHH4XmQ=
|
||||
modernc.org/sqlite v1.14.3/go.mod h1:xMpicS1i2MJ4C8+Ap0vYBqTwYfpFvdnPE6brbFOtV2Y=
|
||||
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
||||
modernc.org/tcl v1.9.2/go.mod h1:aw7OnlIoiuJgu1gwbTZtrKnGpDqH9wyH++jZcxdqNsg=
|
||||
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
|
||||
modernc.org/z v1.2.20/go.mod h1:zU9FiF4PbHdOTUxw+IF8j7ArBMRPsHgq10uVPt6xTzo=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
|
||||
|
||||
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 206 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 764 KiB |
|
After Width: | Height: | Size: 135 KiB |
@@ -6,5 +6,6 @@ const banner = `
|
||||
/ /_/ / _ \ | / /\__ \/ / / / / __/
|
||||
/ _, _/ __/ |/ /___/ / /_/ / / /_
|
||||
/_/ |_|\___/|___//____/\__,_/_/\__/
|
||||
v%s
|
||||
https://revsuit.pro`
|
||||
%s
|
||||
https://revsuit.pro
|
||||
`
|
||||
|
||||
@@ -16,6 +16,7 @@ func Start() {
|
||||
log.ConsoleConfig{
|
||||
Level: log.LevelInfo,
|
||||
})
|
||||
defer log.Stop()
|
||||
app := &cli.App{
|
||||
Name: "RevSuit",
|
||||
Usage: "An Open-Sourced Reverse Platform Designed for Receive Various Kinds of Connection",
|
||||
@@ -41,16 +42,36 @@ func Start() {
|
||||
Usage: "load configuration from FILE (default: config.yaml)",
|
||||
},
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "upgrade",
|
||||
Action: func(c *cli.Context) error {
|
||||
checkUpdateFromCli()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
var configFile = "config.yaml"
|
||||
if c.Path("config") != "" {
|
||||
configFile = c.Path("config")
|
||||
}
|
||||
conf := &server.Config{}
|
||||
tpl := &server.Config{}
|
||||
_ = yaml.Unmarshal(configTemplate, tpl)
|
||||
if content, err := os.ReadFile(configFile); err == nil {
|
||||
if err := yaml.Unmarshal(content, conf); err != nil {
|
||||
return err
|
||||
}
|
||||
if conf.Version != tpl.Version {
|
||||
backup := fmt.Sprintf("%s_%.1f", configFile, conf.Version)
|
||||
log.Warn("Old version of configuration file detected, new configuration file being generated, old configuration backed up to %s", backup)
|
||||
if err := os.WriteFile(backup, content, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(configFile, configTemplate, 0644)
|
||||
}
|
||||
|
||||
} else if os.IsNotExist(err) && configFile == "config.yaml" {
|
||||
log.Warn("Generate default configurations to config.yaml, please configure and run again.")
|
||||
return os.WriteFile("config.yaml", configTemplate, 0644)
|
||||
@@ -61,21 +82,26 @@ func Start() {
|
||||
conf.Addr = c.String("addr")
|
||||
}
|
||||
if c.String("token") != "" {
|
||||
conf.Addr = c.String("token")
|
||||
conf.Token = c.String("token")
|
||||
}
|
||||
if c.String("db") != "" {
|
||||
conf.Database = c.String("db")
|
||||
}
|
||||
if c.String("log") != "" {
|
||||
conf.Database = c.String("log")
|
||||
conf.LogLevel = c.String("log")
|
||||
}
|
||||
fmt.Printf(banner, server.VERSION)
|
||||
|
||||
if conf.CheckUpgrade {
|
||||
checkUpdateFromCli()
|
||||
}
|
||||
|
||||
server.New(conf).Run()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
sort.Sort(cli.FlagsByName(app.Flags))
|
||||
sort.Sort(cli.CommandsByName(app.Commands))
|
||||
fmt.Printf(banner, server.VERSION)
|
||||
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
version: 4.0
|
||||
version: 1.5
|
||||
addr: :10000
|
||||
token:
|
||||
domains: []
|
||||
external_ip: # You need to make sure that your target can access the server through this ip.
|
||||
admin_path_prefix: "/revsuit"
|
||||
database: revsuit.db
|
||||
log_level: info
|
||||
check_upgrade: true
|
||||
|
||||
ip_location_database:
|
||||
database: "qqwry" # qqwry or geoip.
|
||||
geo_license_key: "" # Mandatory field, if you choose to use GeoIP.
|
||||
|
||||
http:
|
||||
ip_header:
|
||||
dns:
|
||||
enable: true
|
||||
addr: :53
|
||||
rmi:
|
||||
enable: true
|
||||
addr: :1099
|
||||
ldap:
|
||||
enable: true
|
||||
addr: :1389
|
||||
mysql:
|
||||
enable: true
|
||||
addr: :3306
|
||||
@@ -18,7 +30,6 @@ mysql:
|
||||
ftp:
|
||||
enable: true
|
||||
addr: :21
|
||||
pasv_ip: 127.0.0.1 # your public network ip
|
||||
pasv_port: 2020
|
||||
notice:
|
||||
dingtalk: https://oapi.dingtalk.com/robot/send?access_token={token}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/li4n0/revsuit/internal/update"
|
||||
"github.com/li4n0/revsuit/pkg/server"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rhysd/go-github-selfupdate/selfupdate"
|
||||
log "unknwon.dev/clog/v2"
|
||||
)
|
||||
|
||||
func checkUpdateFromCli() {
|
||||
log.Info("Checking for updates...")
|
||||
if upgradeable, release, err := update.CheckUpgrade(server.VERSION); err != nil {
|
||||
log.Warn(err.Error())
|
||||
} else if upgradeable {
|
||||
err := updateFromCli(release)
|
||||
if err != nil {
|
||||
log.Warn(err.Error())
|
||||
}
|
||||
} else {
|
||||
log.Info("The current version is the latest")
|
||||
}
|
||||
}
|
||||
|
||||
func updateFromCli(release *selfupdate.Release) error {
|
||||
releaseNotes := release.ReleaseNotes
|
||||
releaseNotes = strings.Replace(releaseNotes, "\n\n", "\n", -1)
|
||||
releaseNotes = strings.Replace(releaseNotes, "\r\n\r\n", "\n", -1)
|
||||
releaseNotes = strings.Replace(releaseNotes, "**", "", -1)
|
||||
|
||||
log.Info("New version detected: %s\n%s", release.URL, releaseNotes)
|
||||
log.Warn("Do you want to update to v%s?[Y/n]:", release.Version)
|
||||
|
||||
var upgrade string
|
||||
_, _ = fmt.Scanln(&upgrade)
|
||||
if upgrade != "n" {
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
log.Error("error when locate executable path, err: %v", err)
|
||||
}
|
||||
|
||||
assetURL := "https://upgrade.revsuit.pro" + strings.TrimPrefix(release.AssetURL, "https://github.com/Li4n0/revsuit/releases") + "?from=" + server.VERSION
|
||||
|
||||
log.Info("Downloading from %s", assetURL)
|
||||
if err := selfupdate.UpdateTo(assetURL, exe); err != nil {
|
||||
return errors.Wrap(err, "error when download asset")
|
||||
}
|
||||
log.Info("Successfully updated to v%s", release.Version)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,13 +1,49 @@
|
||||
package database
|
||||
|
||||
import "gorm.io/gorm"
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
var DB *gorm.DB
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func InitDB(driver, dsn string) (err error) {
|
||||
switch driver {
|
||||
case "sqlite":
|
||||
DB, err = NewSqlite3(dsn)
|
||||
var (
|
||||
DB *gorm.DB
|
||||
Driver DriverType
|
||||
)
|
||||
|
||||
type DriverType = string
|
||||
|
||||
const Sqlite = "sqlite"
|
||||
const Mysql = "mysql"
|
||||
const Postgres = "postgres"
|
||||
const UnknowDatabase = "unknown database"
|
||||
|
||||
func InitDB(dsn string) (err error) {
|
||||
dbName, dbDsn := dbType(dsn)
|
||||
|
||||
switch dbName {
|
||||
case Sqlite:
|
||||
DB, err = NewSqlite3(dbDsn)
|
||||
case Mysql:
|
||||
DB, err = NewMysql(dbDsn)
|
||||
case Postgres:
|
||||
DB, err = NewPostgres(dbDsn)
|
||||
default:
|
||||
err = errors.New("unsupported database")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func dbType(dsn string) (DriverType, string) {
|
||||
if strings.HasSuffix(dsn, ".db") || strings.HasPrefix(dsn, "sqlite3://") {
|
||||
return Sqlite, strings.TrimPrefix(dsn, "sqlite3://")
|
||||
} else if strings.HasPrefix(dsn, "postgres://") {
|
||||
return Postgres, strings.TrimPrefix(dsn, "postgres://")
|
||||
} else if strings.HasPrefix(dsn, "mysql://") {
|
||||
return Mysql, strings.TrimPrefix(dsn, "mysql://")
|
||||
} else if strings.Contains(dsn, "@tcp") { //兼容上个版本的写法
|
||||
return Mysql, dsn
|
||||
}
|
||||
return UnknowDatabase, dsn
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func NewMysql(dsn string) (*gorm.DB, error) {
|
||||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func NewPostgres(dsn string) (*gorm.DB, error) {
|
||||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package database
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package ipinfo
|
||||
|
||||
type Config struct {
|
||||
Database string
|
||||
GeoLicenseKey string `yaml:"geo_license_key"`
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ipinfo
|
||||
|
||||
type Database interface {
|
||||
Area(string) string
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package geoip
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "unknwon.dev/clog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
Url = "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=%s&suffix=tar.gz"
|
||||
)
|
||||
|
||||
func get(url string) (b []byte, err error) {
|
||||
var resp *http.Response
|
||||
client := http.Client{
|
||||
Timeout: 90 * time.Second,
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // disable verify
|
||||
}}
|
||||
request, _ := http.NewRequest(http.MethodGet, url, nil)
|
||||
request.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36")
|
||||
|
||||
resp, err = client.Do(request)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
log.Warn("%v", err)
|
||||
}
|
||||
}(resp.Body)
|
||||
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func extractTarGz(gzipStream io.Reader) error {
|
||||
uncompressedStream, err := gzip.NewReader(gzipStream)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tarReader := tar.NewReader(uncompressedStream)
|
||||
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeReg:
|
||||
if !strings.HasSuffix(header.Name, "GeoLite2-City.mmdb") {
|
||||
continue
|
||||
}
|
||||
outFile, err := os.Create("GeoLite2-City.mmdb")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||
_ = outFile.Close()
|
||||
return err
|
||||
}
|
||||
err = outFile.Close()
|
||||
if err != nil {
|
||||
log.Warn("%v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func download(licenseKey string) (err error) {
|
||||
var GeoLite2TarGz []byte
|
||||
log.Info("Downloading GeoLite2-City.mmdb...")
|
||||
if GeoLite2TarGz, err = get(fmt.Sprintf(Url, licenseKey)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return extractTarGz(bytes.NewReader(GeoLite2TarGz))
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package geoip
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/oschwald/geoip2-golang"
|
||||
log "unknwon.dev/clog/v2"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
geo *geoip2.Reader
|
||||
}
|
||||
|
||||
var geo *geoip2.Reader
|
||||
var once sync.Once
|
||||
|
||||
// Area returns IpArea according to ip
|
||||
func (db *Database) Area(ip string) string {
|
||||
defer func() {
|
||||
_ = recover()
|
||||
}()
|
||||
record, err := db.geo.City(net.ParseIP(ip))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
country := record.Country.Names["en"]
|
||||
city := record.City.Names["en"]
|
||||
if city == "" {
|
||||
city = record.Location.TimeZone
|
||||
}
|
||||
return fmt.Sprintf("%s %s", country, city)
|
||||
}
|
||||
|
||||
func checkUpdate(licenseKey string) {
|
||||
info, err := os.Stat("GeoLite2-City.mmdb")
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err := download(licenseKey)
|
||||
if err != nil {
|
||||
log.Warn("Download GeoLite2-City.mmdb failed, caused by:%v, recommend to download it by yourself otherwise the `IpArea` will be null", err)
|
||||
}
|
||||
}
|
||||
} else if -time.Until(info.ModTime()) > 7*24*time.Hour {
|
||||
log.Info("Updating GeoLite2-City.mmdb...")
|
||||
err := download(licenseKey)
|
||||
if err != nil {
|
||||
log.Warn("Update GeoLite2-City.mmdb failed, please download GeoLite2-City.mmdb by yourself")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func New(licenseKey string) *Database {
|
||||
once.Do(func() {
|
||||
var err error
|
||||
checkUpdate(licenseKey)
|
||||
geo, err = geoip2.Open("GeoLite2-City.mmdb")
|
||||
if err != nil {
|
||||
log.Error("Load GeoLite2-City.mmdb failed, `IpArea` will be null")
|
||||
}
|
||||
})
|
||||
return &Database{geo: geo}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package ipinfo
|
||||
|
||||
import (
|
||||
"github.com/li4n0/revsuit/internal/ipinfo/geoip"
|
||||
"github.com/li4n0/revsuit/internal/ipinfo/qqwry"
|
||||
log "unknwon.dev/clog/v2"
|
||||
)
|
||||
|
||||
var db Database
|
||||
|
||||
func Area(ip string) string {
|
||||
if db != nil {
|
||||
return db.Area(ip)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func Init(config Config) {
|
||||
switch config.Database {
|
||||
case "qqwry":
|
||||
db = qqwry.New()
|
||||
case "geoip":
|
||||
db = geoip.New(config.GeoLicenseKey)
|
||||
default:
|
||||
log.Fatal("wrong ip location database type: %q", config.Database)
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,9 @@ import (
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -16,10 +17,11 @@ import (
|
||||
|
||||
const (
|
||||
CopyWriteUrl = "https://qqwry.mirror.noc.one/copywrite.rar"
|
||||
QqwryUrl = "https://qqwry.mirror.noc.one/qqwry.rar"
|
||||
Url = "https://qqwry.mirror.noc.one/qqwry.rar"
|
||||
)
|
||||
|
||||
func get(url string) (b []byte, err error) {
|
||||
var resp *http.Response
|
||||
client := http.Client{
|
||||
Timeout: 90 * time.Second,
|
||||
Transport: &http.Transport{
|
||||
@@ -28,14 +30,19 @@ func get(url string) (b []byte, err error) {
|
||||
request, _ := http.NewRequest("GET", url, nil)
|
||||
request.Header.Add("User-Agent", "Nali/2.1.2 (Nali CLI, https://nali.skk.moe)")
|
||||
|
||||
resp, err := client.Do(request)
|
||||
resp, err = client.Do(request)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err = ioutil.ReadAll(resp.Body)
|
||||
return b, err
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
log.Warn("%v", err)
|
||||
}
|
||||
}(resp.Body)
|
||||
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func getKey(b []byte) (key uint32, err error) {
|
||||
@@ -47,26 +54,36 @@ func getKey(b []byte) (key uint32, err error) {
|
||||
}
|
||||
|
||||
func decrypt(b []byte, key uint32) (_ []byte, err error) {
|
||||
var rc io.ReadCloser
|
||||
for i := 0; i < 0x200; i++ {
|
||||
key *= uint32(0x805)
|
||||
key++
|
||||
key &= uint32(0xff)
|
||||
b[i] = b[i] ^ byte(key)
|
||||
}
|
||||
rc, err := zlib.NewReader(bytes.NewBuffer(b))
|
||||
rc, err = zlib.NewReader(bytes.NewBuffer(b))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer rc.Close()
|
||||
return ioutil.ReadAll(rc)
|
||||
|
||||
defer func(rc io.ReadCloser) {
|
||||
err := rc.Close()
|
||||
if err != nil {
|
||||
log.Warn("%v", err)
|
||||
}
|
||||
}(rc)
|
||||
|
||||
return io.ReadAll(rc)
|
||||
}
|
||||
|
||||
func download() (err error) {
|
||||
var (
|
||||
copyWriteData, qqwryData []byte
|
||||
wg sync.WaitGroup
|
||||
key uint32
|
||||
)
|
||||
log.Info("Downloading qqwry.dat...")
|
||||
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
@@ -77,23 +94,21 @@ func download() (err error) {
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if qqwryData, err = get(QqwryUrl); err != nil {
|
||||
if qqwryData, err = get(Url); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var key uint32
|
||||
if key, err = getKey(copyWriteData); err != nil {
|
||||
return
|
||||
}
|
||||
b, err := decrypt(qqwryData, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = ioutil.WriteFile("qqwry.dat", b, 0644)
|
||||
|
||||
return nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if key, err = getKey(copyWriteData); err != nil {
|
||||
return err
|
||||
}
|
||||
if b, err := decrypt(qqwryData, key); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return os.WriteFile("qqwry.dat", b, 0644)
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,29 @@ import (
|
||||
log "unknwon.dev/clog/v2"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
wry *qqwry.QQwry
|
||||
}
|
||||
|
||||
// Area returns IpArea according to ip
|
||||
func (db *Database) Area(ip string) string {
|
||||
defer func() {
|
||||
_ = recover()
|
||||
}()
|
||||
if db.wry == nil {
|
||||
return ""
|
||||
}
|
||||
ipData := db.wry.SearchByIPv4(ip)
|
||||
if ipData.Area == " CZ88.NET" {
|
||||
return ipData.Country
|
||||
}
|
||||
return ipData.Country + " " + ipData.Area
|
||||
}
|
||||
|
||||
var wry *qqwry.QQwry
|
||||
var once sync.Once
|
||||
|
||||
func init() {
|
||||
_ = log.NewConsole(100,
|
||||
log.ConsoleConfig{
|
||||
Level: log.LevelInfo,
|
||||
})
|
||||
func checkUpdate() {
|
||||
info, err := os.Stat("qqwry.dat")
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
@@ -25,7 +40,7 @@ func init() {
|
||||
log.Warn("Download qqwry.dat failed, caused by:%v, recommend to download it by yourself otherwise the `IpArea` will be null", err)
|
||||
}
|
||||
}
|
||||
} else if time.Until(info.ModTime()) > 5*24*time.Hour {
|
||||
} else if -time.Until(info.ModTime()) > 7*24*time.Hour {
|
||||
log.Info("Updating qqwry.dat...")
|
||||
err := download()
|
||||
if err != nil {
|
||||
@@ -34,8 +49,9 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func GetQQWry() *qqwry.QQwry {
|
||||
func New() *Database {
|
||||
once.Do(func() {
|
||||
checkUpdate()
|
||||
qqwry.DatData.FilePath = "qqwry.dat"
|
||||
init := qqwry.DatData.InitDatFile()
|
||||
if v, ok := init.(error); ok {
|
||||
@@ -46,6 +62,5 @@ func GetQQWry() *qqwry.QQwry {
|
||||
}
|
||||
wry = qqwry.NewQQwry()
|
||||
})
|
||||
|
||||
return wry
|
||||
return &Database{wry: wry}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- "1.12"
|
||||
- tip
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
install:
|
||||
- go get -t ./...
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -service=travis-ci
|
||||
@@ -1,10 +0,0 @@
|
||||
all: fmt vet lint
|
||||
|
||||
fmt:
|
||||
go fmt .
|
||||
|
||||
vet:
|
||||
go vet .
|
||||
|
||||
lint:
|
||||
golint .
|
||||
@@ -1,16 +0,0 @@
|
||||
package qqwry
|
||||
|
||||
// Area returns IpArea according to ip
|
||||
func Area(ip string) string {
|
||||
defer func() {
|
||||
_ = recover()
|
||||
}()
|
||||
if GetQQWry() == nil {
|
||||
return ""
|
||||
}
|
||||
ipData := GetQQWry().SearchByIPv4(ip)
|
||||
if ipData.Area == " CZ88.NET" {
|
||||
return ipData.Country
|
||||
}
|
||||
return ipData.Country + " " + ipData.Area
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var recordChan = make(chan BaseRecord, 100)
|
||||
var recordChan = make(chan BaseRecord, 1000)
|
||||
|
||||
type Record interface {
|
||||
GetFlag() string
|
||||
@@ -13,7 +13,7 @@ type Record interface {
|
||||
}
|
||||
|
||||
type BaseRecord struct {
|
||||
Record `gorm:"-" json:"-"`
|
||||
Record `gorm:"-" json:"-" notice:"-"`
|
||||
ID uint `gorm:"primarykey" form:"id" json:"id" notice:"-"`
|
||||
RuleName string `gorm:"index" form:"rule_name" json:"rule_name" notice:"rule"`
|
||||
Flag string `gorm:"index" form:"flag" json:"flag" `
|
||||
|
||||
@@ -14,16 +14,17 @@ type Rule interface {
|
||||
}
|
||||
|
||||
type BaseRule struct {
|
||||
Rule `gorm:"-" json:"-" yaml:"-"`
|
||||
ID uint `gorm:"primarykey" form:"id" json:"id" yaml:"-"`
|
||||
CreatedAt time.Time `json:"created_at" yaml:"-"`
|
||||
UpdatedAt time.Time `json:"updated_at" yaml:"-"`
|
||||
Name string `gorm:"index;unique;not null;" form:"name" json:"name"`
|
||||
FlagFormat string `gorm:"unique;not null;" form:"flag_format" json:"flag_format" yaml:"flag_format"`
|
||||
flagCatcher *regexp.Regexp `gorm:"-" json:"-"`
|
||||
Rank int `gorm:"default:0" json:"rank" form:"rank"`
|
||||
PushToClient bool `gorm:"default:false;not null;" form:"push_to_client" json:"push_to_client" yaml:"push_to_client"`
|
||||
Notice bool `gorm:"default:false;not null;" form:"notice" json:"notice"`
|
||||
Rule `gorm:"-" json:"-" yaml:"-"`
|
||||
ID uint `gorm:"primarykey" form:"id" json:"id" yaml:"-"`
|
||||
CreatedAt time.Time `json:"created_at" yaml:"-"`
|
||||
UpdatedAt time.Time `json:"updated_at" yaml:"-"`
|
||||
Name string `gorm:"index;unique;not null;" form:"name" json:"name"`
|
||||
FlagFormat string `gorm:"unique;not null;" form:"flag_format" json:"flag_format" yaml:"flag_format"`
|
||||
flagCatcher *regexp.Regexp `gorm:"-" json:"-"`
|
||||
// base_bank 解决 mysql 中关键字 rank 冲突和 pg 下不能使用 ``
|
||||
Rank int `gorm:"default:0;column:base_rank" json:"rank" form:"rank"`
|
||||
PushToClient bool `gorm:"default:false;not null;" form:"push_to_client" json:"push_to_client" yaml:"push_to_client"`
|
||||
Notice bool `gorm:"default:false;not null;" form:"notice" json:"notice"`
|
||||
}
|
||||
|
||||
func (br BaseRule) Match(s string) (flag, flagGroup string, vars map[string]string) {
|
||||
@@ -60,6 +61,7 @@ func (br BaseRule) Match(s string) (flag, flagGroup string, vars map[string]stri
|
||||
vars[name] = strings.TrimSpace(matched[j])
|
||||
}
|
||||
}
|
||||
vars["flag"] = flag
|
||||
|
||||
return flag, flagGroup, vars
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package update
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rhysd/go-github-selfupdate/selfupdate"
|
||||
)
|
||||
|
||||
func CheckUpgrade(currentVersion string) (bool, *selfupdate.Release, error) {
|
||||
latest, found, err := selfupdate.DetectLatest("Li4n0/revsuit")
|
||||
if err != nil {
|
||||
return false, nil, errors.Wrap(err, "error when detecting version")
|
||||
}
|
||||
|
||||
v, err := semver.Parse(strings.TrimPrefix(currentVersion, "v"))
|
||||
if err != nil {
|
||||
return false, nil, errors.Wrap(err, "error when parse version")
|
||||
}
|
||||
if !found || latest.Version.LTE(v) {
|
||||
return false, nil, nil
|
||||
}
|
||||
return true, latest, nil
|
||||
}
|
||||
@@ -2,4 +2,5 @@ package dns
|
||||
|
||||
type Config struct {
|
||||
Enable bool
|
||||
Addr string
|
||||
}
|
||||
|
||||