Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac5df6826b | ||
|
|
91908859bc | ||
|
|
9c8822f857 | ||
|
|
9709da7fb6 | ||
|
|
1852f10131 | ||
|
|
77d7b43e21 | ||
|
|
7410b539a0 | ||
|
|
0403d71502 | ||
|
|
2af1d93a7d | ||
|
|
76281ad761 | ||
|
|
d1ec9b4916 | ||
|
|
448e7460a9 | ||
|
|
ee0cbabffc | ||
|
|
d6a5af890a | ||
|
|
dc313441e5 | ||
|
|
c75320f4f4 | ||
|
|
c788f78416 | ||
|
|
49cf954d4a | ||
|
|
014e3db54f | ||
|
|
6d9c245c81 | ||
|
|
7fa9b79f31 | ||
|
|
c7f3d13b7f | ||
|
|
46f08a89d2 | ||
|
|
0dcfedb4dc | ||
|
|
918bf85a2d | ||
|
|
99db5f7190 | ||
|
|
18eff791b2 | ||
|
|
624dcacac5 | ||
|
|
878d5fd27c | ||
|
|
4b893ce0e8 | ||
|
|
472524f836 | ||
|
|
dbf8b23b15 | ||
|
|
79a5dd53ae | ||
|
|
8a5b20685c | ||
|
|
5a9c972de0 | ||
|
|
fc0e67122d | ||
|
|
eb642f66ca | ||
|
|
8cac15f7dd | ||
|
|
5011e2b7c1 | ||
|
|
b0008143b1 | ||
|
|
a3c3ab5a72 | ||
|
|
3a16269215 | ||
|
|
151145b0c3 | ||
|
|
9c794e9d4b | ||
|
|
01f697d279 | ||
|
|
6cdc37333b | ||
|
|
ae32915565 | ||
|
|
f49457dc5b | ||
|
|
d9e2e247ea | ||
|
|
c6f2f2f150 | ||
|
|
56b9c66cb8 | ||
|
|
5d8a0d0e1f | ||
|
|
f4cb9beda5 | ||
|
|
b66fc3c06d | ||
|
|
ab2e1a9236 | ||
|
|
ab77b400a1 | ||
|
|
eb7ab63563 | ||
|
|
4cf7d01622 | ||
|
|
a876078a9c | ||
|
|
495f2ae3c6 | ||
|
|
4e6d11baf0 | ||
|
|
a951b982b3 | ||
|
|
a33be66504 | ||
|
|
f41b9d5887 | ||
|
|
3c608463e6 | ||
|
|
eeffbe124a | ||
|
|
d7f2d54faa | ||
|
|
7db4b03634 | ||
|
|
77760a681a | ||
|
|
f9c1447ceb | ||
|
|
fb749c1902 | ||
|
|
240c44aa07 | ||
|
|
92cd8642c8 | ||
|
|
89d90cf919 | ||
|
|
920c6b6d8b | ||
|
|
1dd4df3a1c | ||
|
|
c7d44cc253 | ||
|
|
5082ab1893 | ||
|
|
e8b2425222 | ||
|
|
09d12cefd8 | ||
|
|
5f1166965d | ||
|
|
0dbab182e9 | ||
|
|
512f3f99fd | ||
|
|
6fb4fad705 | ||
|
|
fa92529e9b | ||
|
|
d6c6051a6c | ||
|
|
ce063bd3ac | ||
|
|
4468894dfb | ||
|
|
8b00b919ad | ||
|
|
64f4a6dfac | ||
|
|
6faa5153b6 | ||
|
|
a771b1e9b0 | ||
|
|
7750f9c54d | ||
|
|
b2d24ee67b | ||
|
|
589a2a5123 | ||
|
|
184d3d357d | ||
|
|
50b3d85270 | ||
|
|
09fdd34ba3 | ||
|
|
bba10261c5 | ||
|
|
46bfe54097 | ||
|
|
503e7a307e | ||
|
|
821b0a6faf | ||
|
|
d60fdff179 | ||
|
|
fdd841e82a | ||
|
|
2d6f0a116a | ||
|
|
bd13fe4ef4 | ||
|
|
6e1b208464 | ||
|
|
76433a409e | ||
|
|
9b4fa679c2 | ||
|
|
c2ae95c4cc | ||
|
|
b2b7f60fd5 | ||
|
|
a465888b31 | ||
|
|
d368bdc84c | ||
|
|
cdc1150505 | ||
|
|
32d525c53c | ||
|
|
a89b40c607 | ||
|
|
b6bd9150d9 | ||
|
|
96e3e3bc86 | ||
|
|
41377f41bb | ||
|
|
fb744f81e2 | ||
|
|
750c3bcbcd | ||
|
|
d4015d7284 | ||
|
|
a9bf3fda73 | ||
|
|
7f467a4814 | ||
|
|
9f10b5e983 | ||
|
|
5291270e6a | ||
|
|
56bba381d8 | ||
|
|
2ff276b162 | ||
|
|
d77191ce0f | ||
|
|
f99803aef4 | ||
|
|
e09fa17013 | ||
|
|
c7e69aa8a5 | ||
|
|
9548068283 | ||
|
|
09958c78f3 | ||
|
|
aced098982 | ||
|
|
7862a34760 | ||
|
|
1384d28cac | ||
|
|
24b7338153 | ||
|
|
30d254eaef | ||
|
|
bb8a936ade | ||
|
|
61044fd30b | ||
|
|
22a4546d0f | ||
|
|
07450416ed | ||
|
|
0d6db0d2a1 | ||
|
|
ab30b3407b | ||
|
|
7a4c735803 | ||
|
|
654c764019 | ||
|
|
7101139250 | ||
|
|
793614841a | ||
|
|
94f2ac5b2a | ||
|
|
d4d39eecaa | ||
|
|
8af01c859c | ||
|
|
3af92d03e8 | ||
|
|
f17d891302 | ||
|
|
51623436b0 | ||
|
|
1b7c7eef8f | ||
|
|
15e4c7e522 | ||
|
|
120ab132a9 | ||
|
|
0b52e8faa8 | ||
|
|
60eaaf390a | ||
|
|
9101badb1c | ||
|
|
7082111b34 | ||
|
|
a156f2681e | ||
|
|
7cb823c957 | ||
|
|
817f612224 | ||
|
|
1cbaf9d6bc | ||
|
|
d353f9837f | ||
|
|
14beef72fc | ||
|
|
91a33fe7f6 | ||
|
|
7ad7a0ff41 | ||
|
|
d646469f71 | ||
|
|
4f616ffff1 | ||
|
|
64400fba61 | ||
|
|
fc15e8c63d | ||
|
|
cbba1e5317 | ||
|
|
75b997dcc4 | ||
|
|
853063c59b | ||
|
|
5c65edb8fa | ||
|
|
7707cc116f | ||
|
|
737fe749de | ||
|
|
b9c6f17e3f | ||
|
|
af6a340003 | ||
|
|
8ba3bee944 | ||
|
|
153c3566b6 | ||
|
|
97a4753f4f | ||
|
|
74c3899b55 | ||
|
|
273ac6d1a8 | ||
|
|
5edbb39a63 | ||
|
|
0c974c4113 | ||
|
|
46657a525d | ||
|
|
b36aa6f917 | ||
|
|
cddb0ebef9 | ||
|
|
788c4e3531 | ||
|
|
47f9ad8274 | ||
|
|
855beb7fa9 | ||
|
|
f57816b1b0 | ||
|
|
ff08fefc30 | ||
|
|
f792ab9055 | ||
|
|
63af103a4e | ||
|
|
0a36d44cec | ||
|
|
a1f4e1de84 | ||
|
|
05b20d47db | ||
|
|
6b746f13d1 | ||
|
|
e838d5bcd2 | ||
|
|
0dcc21260e | ||
|
|
3c30ad145c | ||
|
|
06b0a8e873 | ||
|
|
b7de2ccadd | ||
|
|
b52c5cfca1 | ||
|
|
fe910c37cf | ||
|
|
337ef330eb | ||
|
|
ffa47177aa | ||
|
|
46a76853c3 | ||
|
|
2cd7dfb2b3 | ||
|
|
fee2808bca | ||
|
|
49e5eb186a | ||
|
|
dee2865466 | ||
|
|
eb340b2615 | ||
|
|
e714549a95 | ||
|
|
a1367bcd3d | ||
|
|
642351dafd | ||
|
|
90b9b5adba | ||
|
|
5bf4bbe45f | ||
|
|
036f928fa3 | ||
|
|
94e7b31fb6 | ||
|
|
be4742382d | ||
|
|
70d2f1a055 | ||
|
|
877fe50049 | ||
|
|
7d505705ee | ||
|
|
38f81a03b5 | ||
|
|
d549d23819 | ||
|
|
934675e0f0 | ||
|
|
2be397aa38 | ||
|
|
a0a422ed45 | ||
|
|
fcce10c695 | ||
|
|
30eb14702f | ||
|
|
3679fcc874 | ||
|
|
d085b4e3c2 | ||
|
|
dc8fcdf214 | ||
|
|
8bab23b65b | ||
|
|
f64022e411 | ||
|
|
2d37302cf9 | ||
|
|
1a1856257d | ||
|
|
24f570b64f | ||
|
|
6322177b71 | ||
|
|
d2390d1cb3 | ||
|
|
6fe6f6b708 | ||
|
|
a656f4fec3 | ||
|
|
399c32da7d | ||
|
|
62167836dc | ||
|
|
caef3897a0 | ||
|
|
5ef6810e3f | ||
|
|
ae2079f583 | ||
|
|
aa65382a0f | ||
|
|
18c61a2bfc | ||
|
|
7cc1a8a58a | ||
|
|
cf9feac702 | ||
|
|
a963cd0209 | ||
|
|
6a5408f9b8 | ||
|
|
9aad62d1e4 | ||
|
|
867eab40f8 | ||
|
|
eb5c7efc4c | ||
|
|
857abc16e7 | ||
|
|
28b9866c42 | ||
|
|
a27deb0a41 | ||
|
|
8e026de20b | ||
|
|
718ecc2372 | ||
|
|
56d46722f4 | ||
|
|
b6463cd715 | ||
|
|
bd3ae0cbfe | ||
|
|
83c3aa894f | ||
|
|
1b88d26fea | ||
|
|
588287fdb4 | ||
|
|
688e544b07 | ||
|
|
3e3f812e83 | ||
|
|
b551c7abe4 | ||
|
|
6d1e7a4c05 | ||
|
|
3341a4bc8e | ||
|
|
1c84980d36 | ||
|
|
833b25881d | ||
|
|
9dbf58903c | ||
|
|
ad007f0d91 | ||
|
|
4b06973a52 | ||
|
|
159a67f15d | ||
|
|
7c03b9953b | ||
|
|
f90987de8d | ||
|
|
70e4ff7820 | ||
|
|
a99356f54b | ||
|
|
c5bc9534cc | ||
|
|
a40733424f | ||
|
|
a937efc60e | ||
|
|
6adb0e8415 | ||
|
|
ff9ffb2f12 | ||
|
|
9be4f472ae | ||
|
|
8581d74b08 | ||
|
|
dafe9bd6b6 | ||
|
|
3ae5772360 | ||
|
|
4628dbccfb | ||
|
|
572b1d4c14 | ||
|
|
bdb70e9859 | ||
|
|
38bda17271 | ||
|
|
455e1d2e5b | ||
|
|
89cd724bab | ||
|
|
b9109b4d0e | ||
|
|
945958f552 | ||
|
|
78eb0d5c06 | ||
|
|
bc6eae711e | ||
|
|
f0a4bf6164 | ||
|
|
fc3b5e3ac3 | ||
|
|
f7235ac847 | ||
|
|
231f4ddb7f | ||
|
|
3cad3994cb | ||
|
|
8c97cc8686 | ||
|
|
7ae976ee5d | ||
|
|
e91b53eb32 | ||
|
|
90311536a7 | ||
|
|
e951b7f2f9 | ||
|
|
e0f94b62cf | ||
|
|
8cb701ec85 | ||
|
|
9afd11e3b8 | ||
|
|
a1d495f2db | ||
|
|
652fa93910 | ||
|
|
ef414855f0 | ||
|
|
76cf35cdf0 | ||
|
|
9d7aa05032 | ||
|
|
62a22c697d | ||
|
|
be497a5aa7 | ||
|
|
fc3e16bc63 | ||
|
|
df35912461 | ||
|
|
0ddc66a854 | ||
|
|
716d557d66 | ||
|
|
f9edcb9d47 | ||
|
|
d4623c5bc9 | ||
|
|
02ba4a3330 | ||
|
|
a72d4eaf78 | ||
|
|
4d3abb2dc0 | ||
|
|
ad6a8d1f7a | ||
|
|
a5c8c2ac97 | ||
|
|
1237004cb1 | ||
|
|
c2bcd17df7 | ||
|
|
bb49cbdd50 | ||
|
|
6ad770a824 | ||
|
|
593eeb3ac3 | ||
|
|
6a7be3ef84 |
@@ -1,61 +0,0 @@
|
|||||||
name: Build & Push Docker Image
|
|
||||||
|
|
||||||
# Builds the Docker image and publishes it to the Gitea container registry
|
|
||||||
# at git.hackner.dev/thomas/rustdesk-api.
|
|
||||||
#
|
|
||||||
# Requires a running Gitea Actions runner (act_runner) and two repo secrets
|
|
||||||
# (Settings -> Actions -> Secrets):
|
|
||||||
# REGISTRY_USER - Gitea username (e.g. thomas)
|
|
||||||
# REGISTRY_PASSWORD - a Gitea access token with "write:package" scope
|
|
||||||
#
|
|
||||||
# (Alternatively the built-in ${{ secrets.GITHUB_TOKEN }} can be used with
|
|
||||||
# username ${{ gitea.actor }} if your Gitea grants it package write access.)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
tags:
|
|
||||||
- 'v*.*.*'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: git.hackner.dev
|
|
||||||
IMAGE_NAME: ${{ github.repository }} # -> thomas/rustdesk-api
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Log in to the Gitea container registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ secrets.REGISTRY_USER }}
|
|
||||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Extract metadata (tags, labels)
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=raw,value=latest,enable={{is_default_branch}}
|
|
||||||
|
|
||||||
- name: Build and push image
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile.dev
|
|
||||||
push: true
|
|
||||||
build-args: |
|
|
||||||
GO_VERSION=1.23
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
@@ -0,0 +1,443 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
BASE_IMAGE_NAMESPACE:
|
||||||
|
description: 'Base image namespace (Default: Your Github username)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
DOCKERHUB_IMAGE_NAMESPACE:
|
||||||
|
description: 'Docker Hub image namespace (Default: Your Github username)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
GHCR_IMAGE_NAMESPACE:
|
||||||
|
description: 'GitHub Container Registry image namespace (Default: Your Github username)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
SKIP_DOCKER_HUB:
|
||||||
|
description: 'Set to true to skip pushing to Docker Hub (default: false)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
SKIP_GHCR:
|
||||||
|
description: 'Set to true to skip pushing to GHCR (default: false)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
WEBCLIENT_SOURCE_LOCATION:
|
||||||
|
description: 'Web Client API Repository'
|
||||||
|
required: true
|
||||||
|
default: 'https://github.com/lejianwen/rustdesk-api-web'
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*' # 当推送带有版本号的 tag(例如 v1.0.0)时触发工作流
|
||||||
|
- 'test*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
LATEST_TAG: latest
|
||||||
|
WEBCLIENT_SOURCE_LOCATION: ${{ github.event.inputs.WEBCLIENT_SOURCE_LOCATION || 'https://github.com/lejianwen/rustdesk-api-web' }}
|
||||||
|
BASE_IMAGE_NAMESPACE: ${{ github.event.inputs.BASE_IMAGE_NAMESPACE || github.actor }}
|
||||||
|
DOCKERHUB_IMAGE_NAMESPACE: ${{ github.event.inputs.DOCKERHUB_IMAGE_NAMESPACE || github.actor }}
|
||||||
|
GHCR_IMAGE_NAMESPACE: ${{ github.event.inputs.GHCR_IMAGE_NAMESPACE || github.actor }}
|
||||||
|
SKIP_DOCKER_HUB: ${{ github.event.inputs.SKIP_DOCKER_HUB || 'false' }}
|
||||||
|
SKIP_GHCR: ${{ github.event.inputs.SKIP_GHCR || 'false' }}
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job:
|
||||||
|
- { platform: "amd64", goos: "linux", file_ext: "tar.gz" }
|
||||||
|
- { platform: "arm64", goos: "linux", file_ext: "tar.gz" }
|
||||||
|
- { platform: "armv7l", goos: "linux", file_ext: "tar.gz" }
|
||||||
|
- { platform: "amd64", goos: "windows", file_ext: "zip" }
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: lejianwen/rustdesk-api-web
|
||||||
|
path: rustdesk-api-web
|
||||||
|
ref: master
|
||||||
|
|
||||||
|
- name: Set up Go environment
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: '1.22' # 选择 Go 版本
|
||||||
|
|
||||||
|
- name: Set up npm
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: build rustdesk-api-web
|
||||||
|
working-directory: rustdesk-api-web
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
mkdir -p ../resources/admin/
|
||||||
|
cp -ar dist/* ../resources/admin/
|
||||||
|
|
||||||
|
- name: tidy
|
||||||
|
run: go mod tidy
|
||||||
|
|
||||||
|
- name: Get tag version
|
||||||
|
run: |
|
||||||
|
TAG_VERSION="${GITHUB_REF##*/}"
|
||||||
|
VERSION="${TAG_VERSION#v}"
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Write version to resources/version
|
||||||
|
run: echo $VERSION > resources/version
|
||||||
|
|
||||||
|
- name: swag
|
||||||
|
run: |
|
||||||
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
|
swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
|
||||||
|
swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
|
||||||
|
|
||||||
|
- name: Build for ${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||||
|
run: |
|
||||||
|
mkdir release -p
|
||||||
|
cp -ar resources release/
|
||||||
|
cp -ar docs release/
|
||||||
|
cp -ar conf release/
|
||||||
|
mkdir -p release/data
|
||||||
|
mkdir -p release/runtime
|
||||||
|
if [ "${{ matrix.job.goos }}" = "windows" ]; then
|
||||||
|
sudo apt-get install gcc-mingw-w64-x86-64 zip -y
|
||||||
|
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain.exe ./cmd/apimain.go
|
||||||
|
echo @echo off > release/start.bat
|
||||||
|
echo cmd /c \"%~dp0apimain.exe\" >> release/start.bat
|
||||||
|
zip -r ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
||||||
|
else
|
||||||
|
if [ "${{ matrix.job.platform }}" = "arm64" ]; then
|
||||||
|
wget https://musl.cc/aarch64-linux-musl-cross.tgz
|
||||||
|
tar -xf aarch64-linux-musl-cross.tgz
|
||||||
|
export PATH=$PATH:$PWD/aarch64-linux-musl-cross/bin
|
||||||
|
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=aarch64-linux-musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||||
|
elif [ "${{ matrix.job.platform }}" = "armv7l" ]; then
|
||||||
|
wget https://musl.cc/armv7l-linux-musleabihf-cross.tgz
|
||||||
|
tar -xf armv7l-linux-musleabihf-cross.tgz
|
||||||
|
export PATH=$PATH:$PWD/armv7l-linux-musleabihf-cross/bin
|
||||||
|
GOOS=${{ matrix.job.goos }} GOARCH=arm GOARM=7 CC=armv7l-linux-musleabihf-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||||
|
else
|
||||||
|
sudo apt-get install musl musl-dev musl-tools -y
|
||||||
|
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||||
|
fi
|
||||||
|
tar -czf ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||||
|
path: |
|
||||||
|
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
||||||
|
|
||||||
|
- name: Upload to GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Generate Changelog
|
||||||
|
run: npx changelogithub # or changelogithub@0.12 if ensure the stable result
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
|
||||||
|
deb-package:
|
||||||
|
name: debian package - ${{ matrix.job.platform }}
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job:
|
||||||
|
- { platform: "amd64", goos: "linux", debian_platform: "amd64", crossbuild_package: ""}
|
||||||
|
- { platform: "arm64", goos: "linux", debian_platform: "arm64", crossbuild_package: "crossbuild-essential-arm64" }
|
||||||
|
- { platform: "armv7l", goos: "linux", debian_platform: "armhf", crossbuild_package: "crossbuild-essential-armhf" }
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Create packaging env
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
DEBIAN_FRONTEND=noninteractive sudo apt install -y devscripts build-essential debhelper pkg-config ${{ matrix.job.crossbuild_package }}
|
||||||
|
mkdir -p debian-build/${{ matrix.job.platform }}/bin
|
||||||
|
|
||||||
|
- name: Get tag version
|
||||||
|
id: get_tag
|
||||||
|
run: |
|
||||||
|
TAG_VERSION="${GITHUB_REF##*/}"
|
||||||
|
VERSION="${TAG_VERSION#v}"
|
||||||
|
echo "TAG_VERSION=$TAG_VERSION" >> $GITHUB_ENV
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Update changelog
|
||||||
|
run: |
|
||||||
|
DATE=$(date -R)
|
||||||
|
sed -i "1i rustdesk-api-server (${VERSION}) stable; urgency=medium\n\n * Automatically generated release for version ${VERSION}.\n\n -- GitHub Actions <actions@github.com> ${DATE}\n" debian/changelog
|
||||||
|
|
||||||
|
- name: Download binaries
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Unzip binaries
|
||||||
|
run: |
|
||||||
|
mkdir -p ${{ matrix.job.platform }}
|
||||||
|
tar -xzf ${{ matrix.job.goos }}-${{ matrix.job.platform }}.tar.gz -C ${{ matrix.job.platform }}
|
||||||
|
|
||||||
|
- name: Build package for ${{ matrix.job.platform }} arch
|
||||||
|
run: |
|
||||||
|
mv ${{ matrix.job.platform }}/release/apimain debian-build/${{ matrix.job.platform }}/bin/rustdesk-api
|
||||||
|
mv ${{ matrix.job.platform }}/release/resources/admin resources
|
||||||
|
chmod -v a+x debian-build/${{ matrix.job.platform }}/bin/*
|
||||||
|
mkdir -p data
|
||||||
|
cp -vr debian systemd conf data resources runtime debian-build/${{ matrix.job.platform }}/
|
||||||
|
cat debian/control.tpl | sed 's/{{ ARCH }}/${{ matrix.job.debian_platform }}/' > debian-build/${{ matrix.job.platform }}/debian/control
|
||||||
|
cd debian-build/${{ matrix.job.platform }}/
|
||||||
|
debuild -i -us -uc -b -a${{ matrix.job.debian_platform}}
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rustdesk-api-${{ matrix.job.debian_platform }}
|
||||||
|
path: |
|
||||||
|
debian-build/*.deb
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
debian-build/rustdesk-api-server_*_${{ matrix.job.debian_platform }}.deb
|
||||||
|
|
||||||
|
docker:
|
||||||
|
name: Push Docker Image
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job:
|
||||||
|
- { platform: "amd64", goos: "linux", docker_platform: "linux/amd64" }
|
||||||
|
- { platform: "arm64", goos: "linux", docker_platform: "linux/arm64" }
|
||||||
|
- { platform: "armv7l", goos: "linux", docker_platform: "linux/arm/v7" }
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if SKIP_DOCKER_HUB is false
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract version from tag
|
||||||
|
id: vars
|
||||||
|
run: |
|
||||||
|
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
||||||
|
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "TAG=latest" >> $GITHUB_ENV # Default to 'latest' if not a tag
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Extract metadata (tags, labels) for Docker
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api
|
||||||
|
|
||||||
|
- name: Download binaries
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||||
|
path: ./
|
||||||
|
|
||||||
|
- name: Unzip binaries
|
||||||
|
run: |
|
||||||
|
mkdir -p ${{ matrix.job.platform }}
|
||||||
|
tar -xzf ${{ matrix.job.goos }}-${{ matrix.job.platform }}.tar.gz -C ${{ matrix.job.platform }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image to Docker Hub ${{ matrix.job.platform }}
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only run this step if SKIP_DOCKER_HUB is false
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: "."
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: ${{ matrix.job.docker_platform }}
|
||||||
|
push: true
|
||||||
|
provenance: false
|
||||||
|
build-args: |
|
||||||
|
BUILDARCH=${{ matrix.job.platform }}
|
||||||
|
tags: |
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.LATEST_TAG }}-${{ matrix.job.platform }},
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
|
- name: Build and push Docker Full S6 image to Docker Hub ${{ matrix.job.platform }}
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only run this step if SKIP_DOCKER_HUB is false
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: "."
|
||||||
|
file: ./Dockerfile_full_s6
|
||||||
|
platforms: ${{ matrix.job.docker_platform }}
|
||||||
|
push: true
|
||||||
|
provenance: false
|
||||||
|
build-args: |
|
||||||
|
BUILDARCH=${{ matrix.job.platform }}
|
||||||
|
tags: |
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-${{ matrix.job.platform }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image to GHCR ${{ matrix.job.platform }}
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }} # Only run this step if SKIP_GHCR is false
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: "."
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: ${{ matrix.job.docker_platform }}
|
||||||
|
push: true
|
||||||
|
provenance: false
|
||||||
|
build-args: |
|
||||||
|
BUILDARCH=${{ matrix.job.platform }}
|
||||||
|
tags: |
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.LATEST_TAG }}-${{ matrix.job.platform }},
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
|
- name: Build and push Docker Full S6 image to GHCR ${{ matrix.job.platform }}
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }} # Only run this step if SKIP_GHCR is false
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: "."
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: ${{ matrix.job.docker_platform }}
|
||||||
|
push: true
|
||||||
|
provenance: false
|
||||||
|
build-args: |
|
||||||
|
BUILDARCH=${{ matrix.job.platform }}
|
||||||
|
tags: |
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-${{ matrix.job.platform }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
|
#
|
||||||
|
docker-manifest:
|
||||||
|
name: Push Docker Manifest
|
||||||
|
needs: docker
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Extract version from tag
|
||||||
|
id: vars
|
||||||
|
run: |
|
||||||
|
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
||||||
|
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "TAG=latest" >> $GITHUB_ENV # Default to 'latest' if not a tag
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if Docker Hub push is enabled
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Create and push manifest Docker Hub (:version)
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||||
|
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
|
||||||
|
push: true
|
||||||
|
|
||||||
|
- name: Create and push manifest GHCR (:version)
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||||
|
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
|
||||||
|
push: true
|
||||||
|
amend: true
|
||||||
|
|
||||||
|
- name: Create and push manifest Docker Hub (:latest)
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
|
||||||
|
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64,
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-armv7l,
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-arm64
|
||||||
|
push: true
|
||||||
|
|
||||||
|
- name: Create and push manifest GHCR (:latest)
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
|
||||||
|
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64,
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-armv7l,
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-arm64
|
||||||
|
push: true
|
||||||
|
amend: true
|
||||||
|
|
||||||
|
- name: Create and push Full S6 manifest Docker Hub (:version)
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:full-s6
|
||||||
|
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-amd64,
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-armv7l,
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-arm64
|
||||||
|
push: true
|
||||||
|
amend: true
|
||||||
|
|
||||||
|
- name: Create and push Full S6 manifest GHCR (:latest)
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:full-s6
|
||||||
|
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-amd64,
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-armv7l,
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-arm64
|
||||||
|
push: true
|
||||||
|
amend: true
|
||||||
@@ -0,0 +1,337 @@
|
|||||||
|
name: Build Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
BASE_IMAGE_NAMESPACE:
|
||||||
|
description: 'Base image namespace (Default: Your Github username)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
DOCKERHUB_IMAGE_NAMESPACE:
|
||||||
|
description: 'Docker Hub image namespace (Default: Your Github username)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
GHCR_IMAGE_NAMESPACE:
|
||||||
|
description: 'GitHub Container Registry image namespace (Default: Your Github username)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
SKIP_DOCKER_HUB:
|
||||||
|
description: 'Set to true to skip pushing to Docker Hub (default: false)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
SKIP_GHCR:
|
||||||
|
description: 'Set to true to skip pushing to GHCR (default: false)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
WEBCLIENT_SOURCE_LOCATION:
|
||||||
|
description: 'Web Client API Repository'
|
||||||
|
required: true
|
||||||
|
default: 'https://github.com/lejianwen/rustdesk-api-web'
|
||||||
|
|
||||||
|
env:
|
||||||
|
LATEST_TAG: latest
|
||||||
|
WEBCLIENT_SOURCE_LOCATION: ${{ github.event.inputs.WEBCLIENT_SOURCE_LOCATION || 'https://github.com/lejianwen/rustdesk-api-web' }}
|
||||||
|
BASE_IMAGE_NAMESPACE: ${{ github.event.inputs.BASE_IMAGE_NAMESPACE || github.actor }}
|
||||||
|
DOCKERHUB_IMAGE_NAMESPACE: ${{ github.event.inputs.DOCKERHUB_IMAGE_NAMESPACE || github.actor }}
|
||||||
|
GHCR_IMAGE_NAMESPACE: ${{ github.event.inputs.GHCR_IMAGE_NAMESPACE || github.actor }}
|
||||||
|
SKIP_DOCKER_HUB: ${{ github.event.inputs.SKIP_DOCKER_HUB || 'false' }}
|
||||||
|
SKIP_GHCR: ${{ github.event.inputs.SKIP_GHCR || 'false' }}
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job:
|
||||||
|
- { platform: "amd64", goos: "linux", file_ext: "tar.gz" }
|
||||||
|
- { platform: "arm64", goos: "linux", file_ext: "tar.gz" }
|
||||||
|
- { platform: "armv7l", goos: "linux", file_ext: "tar.gz" }
|
||||||
|
- { platform: "amd64", goos: "windows", file_ext: "zip" }
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: lejianwen/rustdesk-api-web
|
||||||
|
path: rustdesk-api-web
|
||||||
|
ref: master
|
||||||
|
|
||||||
|
- name: Set up Go environment
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: '1.22' # 选择 Go 版本
|
||||||
|
|
||||||
|
- name: Set up npm
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: build rustdesk-api-web
|
||||||
|
working-directory: rustdesk-api-web
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
mkdir -p ../resources/admin/
|
||||||
|
cp -ar dist/* ../resources/admin/
|
||||||
|
|
||||||
|
- name: tidy
|
||||||
|
run: go mod tidy
|
||||||
|
|
||||||
|
- name: swag
|
||||||
|
run: |
|
||||||
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
|
swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
|
||||||
|
swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
|
||||||
|
|
||||||
|
- name: Build for ${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||||
|
run: |
|
||||||
|
mkdir release -p
|
||||||
|
cp -ar resources release/
|
||||||
|
cp -ar docs release/
|
||||||
|
cp -ar conf release/
|
||||||
|
mkdir -p release/data
|
||||||
|
mkdir -p release/runtime
|
||||||
|
if [ "${{ matrix.job.goos }}" = "windows" ]; then
|
||||||
|
sudo apt-get install gcc-mingw-w64-x86-64 zip -y
|
||||||
|
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain.exe ./cmd/apimain.go
|
||||||
|
echo @echo off > release/start.bat
|
||||||
|
echo cmd /c \"%~dp0apimain.exe\" >> release/start.bat
|
||||||
|
zip -r ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
||||||
|
else
|
||||||
|
if [ "${{ matrix.job.platform }}" = "arm64" ]; then
|
||||||
|
wget https://musl.cc/aarch64-linux-musl-cross.tgz
|
||||||
|
tar -xf aarch64-linux-musl-cross.tgz
|
||||||
|
export PATH=$PATH:$PWD/aarch64-linux-musl-cross/bin
|
||||||
|
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=aarch64-linux-musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||||
|
elif [ "${{ matrix.job.platform }}" = "armv7l" ]; then
|
||||||
|
wget https://musl.cc/armv7l-linux-musleabihf-cross.tgz
|
||||||
|
tar -xf armv7l-linux-musleabihf-cross.tgz
|
||||||
|
export PATH=$PATH:$PWD/armv7l-linux-musleabihf-cross/bin
|
||||||
|
GOOS=${{ matrix.job.goos }} GOARCH=arm GOARM=7 CC=armv7l-linux-musleabihf-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||||
|
else
|
||||||
|
sudo apt-get install musl musl-dev musl-tools -y
|
||||||
|
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||||
|
fi
|
||||||
|
tar -czf ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||||
|
path: |
|
||||||
|
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
||||||
|
|
||||||
|
- name: Upload to GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
||||||
|
tag_name: test
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
deb-package:
|
||||||
|
name: debian package - ${{ matrix.job.platform }}
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job:
|
||||||
|
- { platform: "amd64", goos: "linux", debian_platform: "amd64", crossbuild_package: ""}
|
||||||
|
- { platform: "arm64", goos: "linux", debian_platform: "arm64", crossbuild_package: "crossbuild-essential-arm64" }
|
||||||
|
- { platform: "armv7l", goos: "linux", debian_platform: "armhf", crossbuild_package: "crossbuild-essential-armhf" }
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Create packaging env
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
DEBIAN_FRONTEND=noninteractive sudo apt install -y devscripts build-essential debhelper pkg-config ${{ matrix.job.crossbuild_package }}
|
||||||
|
mkdir -p debian-build/${{ matrix.job.platform }}/bin
|
||||||
|
|
||||||
|
- name: Download binaries
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Unzip binaries
|
||||||
|
run: |
|
||||||
|
mkdir -p ${{ matrix.job.platform }}
|
||||||
|
tar -xzf ${{ matrix.job.goos }}-${{ matrix.job.platform }}.tar.gz -C ${{ matrix.job.platform }}
|
||||||
|
|
||||||
|
- name: Build package for ${{ matrix.job.platform }} arch
|
||||||
|
run: |
|
||||||
|
mv ${{ matrix.job.platform }}/release/apimain debian-build/${{ matrix.job.platform }}/bin/rustdesk-api
|
||||||
|
chmod -v a+x debian-build/${{ matrix.job.platform }}/bin/*
|
||||||
|
mkdir -p data
|
||||||
|
cp -vr debian systemd conf data resources runtime debian-build/${{ matrix.job.platform }}/
|
||||||
|
cat debian/control.tpl | sed 's/{{ ARCH }}/${{ matrix.job.debian_platform }}/' > debian-build/${{ matrix.job.platform }}/debian/control
|
||||||
|
cd debian-build/${{ matrix.job.platform }}/
|
||||||
|
debuild -i -us -uc -b -a${{ matrix.job.debian_platform}}
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rustdesk-api-${{ matrix.job.debian_platform }}
|
||||||
|
path: |
|
||||||
|
debian-build/*.deb
|
||||||
|
|
||||||
|
- name: Upload to GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: test
|
||||||
|
files: |
|
||||||
|
debian-build/rustdesk-api-server_*_${{ matrix.job.debian_platform }}.deb
|
||||||
|
|
||||||
|
docker:
|
||||||
|
name: Push Docker Image
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
job:
|
||||||
|
- { platform: "amd64", goos: "linux", docker_platform: "linux/amd64" }
|
||||||
|
- { platform: "arm64", goos: "linux", docker_platform: "linux/arm64" }
|
||||||
|
- { platform: "armv7l", goos: "linux", docker_platform: "linux/arm/v7" }
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if SKIP_DOCKER_HUB is false
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract version from tag
|
||||||
|
id: vars
|
||||||
|
run: |
|
||||||
|
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
||||||
|
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "TAG=test" >> $GITHUB_ENV # Default to 'test' if not a tag
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Extract metadata (tags, labels) for Docker
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api
|
||||||
|
|
||||||
|
- name: Download binaries
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||||
|
path: ./
|
||||||
|
|
||||||
|
- name: Unzip binaries
|
||||||
|
run: |
|
||||||
|
mkdir -p ${{ matrix.job.platform }}
|
||||||
|
tar -xzf ${{ matrix.job.goos }}-${{ matrix.job.platform }}.tar.gz -C ${{ matrix.job.platform }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image to Docker Hub ${{ matrix.job.platform }}
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only run this step if SKIP_DOCKER_HUB is false
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: "."
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: ${{ matrix.job.docker_platform }}
|
||||||
|
push: true
|
||||||
|
provenance: false
|
||||||
|
build-args: |
|
||||||
|
BUILDARCH=${{ matrix.job.platform }}
|
||||||
|
tags: |
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image to GHCR ${{ matrix.job.platform }}
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }} # Only run this step if SKIP_GHCR is false
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: "."
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: ${{ matrix.job.docker_platform }}
|
||||||
|
push: true
|
||||||
|
provenance: false
|
||||||
|
build-args: |
|
||||||
|
BUILDARCH=${{ matrix.job.platform }}
|
||||||
|
tags: |
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
|
#
|
||||||
|
docker-manifest:
|
||||||
|
name: Push Docker Manifest
|
||||||
|
needs: docker
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Extract version from tag
|
||||||
|
id: vars
|
||||||
|
run: |
|
||||||
|
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
||||||
|
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "TAG=test" >> $GITHUB_ENV # Default to 'test' if not a tag
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if Docker Hub push is enabled
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Create and push manifest Docker Hub (:version)
|
||||||
|
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||||
|
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
|
||||||
|
push: true
|
||||||
|
|
||||||
|
- name: Create and push manifest GHCR (:version)
|
||||||
|
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||||
|
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
|
||||||
|
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
|
||||||
|
push: true
|
||||||
|
amend: true
|
||||||
+1
-1
@@ -5,4 +5,4 @@ runtime/*
|
|||||||
go.sum
|
go.sum
|
||||||
resources/admin
|
resources/admin
|
||||||
release
|
release
|
||||||
data/rustdeskapi.db
|
data
|
||||||
+4
-3
@@ -42,11 +42,11 @@ RUN if [ "$COUNTRY" = "CN" ] ; then \
|
|||||||
fi && \
|
fi && \
|
||||||
apk update && apk add --no-cache git
|
apk update && apk add --no-cache git
|
||||||
|
|
||||||
ARG FRONTEND_GIT_REPO=https://github.com/lejianwen/rustdesk-api-web.git
|
ARG FREONTEND_GIT_REPO=https://github.com/lejianwen/rustdesk-api-web.git
|
||||||
ARG FRONTEND_GIT_BRANCH=master
|
ARG FRONTEND_GIT_BRANCH=master
|
||||||
# Clone the frontend repository
|
# Clone the frontend repository
|
||||||
|
|
||||||
RUN git clone -b $FRONTEND_GIT_BRANCH $FRONTEND_GIT_REPO .
|
RUN git clone -b $FRONTEND_GIT_BRANCH $FREONTEND_GIT_REPO .
|
||||||
|
|
||||||
# Install required tools without caching index to minimize image size
|
# Install required tools without caching index to minimize image size
|
||||||
RUN if [ "$COUNTRY" = "CN" ] ; then \
|
RUN if [ "$COUNTRY" = "CN" ] ; then \
|
||||||
@@ -76,6 +76,7 @@ COPY --from=builder-backend /app/release /app/
|
|||||||
COPY --from=builder-backend /app/conf /app/conf/
|
COPY --from=builder-backend /app/conf /app/conf/
|
||||||
COPY --from=builder-backend /app/resources /app/resources/
|
COPY --from=builder-backend /app/resources /app/resources/
|
||||||
COPY --from=builder-backend /app/docs /app/docs/
|
COPY --from=builder-backend /app/docs /app/docs/
|
||||||
|
COPY --from=builder-backend /app/http/templates /app/http/templates
|
||||||
# Copy frontend build from builder2 stage
|
# Copy frontend build from builder2 stage
|
||||||
COPY --from=builder-admin-frontend /frontend/dist/ /app/resources/admin/
|
COPY --from=builder-admin-frontend /frontend/dist/ /app/resources/admin/
|
||||||
|
|
||||||
@@ -91,4 +92,4 @@ VOLUME /app/data
|
|||||||
EXPOSE 21114
|
EXPOSE 21114
|
||||||
|
|
||||||
# Define the command to run the application
|
# Define the command to run the application
|
||||||
CMD ["./apimain"]
|
CMD ["./apimain"]
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
# RustDesk API
|
# RustDesk API
|
||||||
|
|
||||||
[中文文档](README_EN.md)
|
[English Doc](README_EN.md)
|
||||||
|
|
||||||
This project implements the RustDesk API using Go, and includes both a web UI and web client. RustDesk is a remote
|
本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web Admin 和 Web 客户端。RustDesk 是一个远程桌面软件,提供了自托管的解决方案。
|
||||||
desktop software that provides self-hosted solutions.
|
|
||||||
|
|
||||||
<div align=center>
|
<div align=center>
|
||||||
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
||||||
@@ -14,237 +13,229 @@ desktop software that provides self-hosted solutions.
|
|||||||
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Better used with [lejianwen/rustdesk-server].
|
# 特性
|
||||||
> [lejianwen/rustdesk-server] is a fork of the official RustDesk Server repository.
|
|
||||||
> 1. Solves the API connection timeout issue.
|
|
||||||
> 2. Can enforce login before initiating a connection.
|
|
||||||
> 3. Supports client websocket.
|
|
||||||
|
|
||||||
|
- PC端API
|
||||||
# Features
|
- 个人版API
|
||||||
|
- 登录
|
||||||
- PC API
|
- 地址簿
|
||||||
- Personal API
|
- 群组
|
||||||
- Login
|
- 授权登录
|
||||||
- Address Book
|
- 支持`github`, `google` 和 `OIDC` 登录,
|
||||||
- Groups
|
- 支持`web后台`授权登录
|
||||||
- Authorized login,
|
- 支持`LDAP`(AD和OpenLDAP已测试), 如果API Server配置了LDAP
|
||||||
- supports `GitHub`, `Google` and `OIDC` login,
|
|
||||||
- supports `web admin` authorized login,
|
|
||||||
- supports LDAP(test AD and openladp) if API Server config
|
|
||||||
- i18n
|
- i18n
|
||||||
- Web Admin
|
- Web Admin
|
||||||
- User Management
|
- 用户管理
|
||||||
- Device Management
|
- 设备管理
|
||||||
- Address Book Management
|
- 地址簿管理
|
||||||
- Tag Management
|
- 标签管理
|
||||||
- Group Management
|
- 群组管理
|
||||||
- OAuth Management
|
- Oauth 管理
|
||||||
- LDAP Config by config file or ENV
|
- 配置LDAP, 配置文件或者环境变量
|
||||||
- Login Logs
|
- 登录日志
|
||||||
- Connection Logs
|
- 链接日志
|
||||||
- File Transfer Logs
|
- 文件传输日志
|
||||||
- Quick access to web client
|
- 快速使用web client
|
||||||
- i18n
|
- i18n
|
||||||
- Share to guest by web client
|
- 通过 web client 分享给游客
|
||||||
- Server control (some simple official commands [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
- server控制(一些官方的简单的指令 [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
||||||
- Web Client
|
- Web Client
|
||||||
- Automatically obtain API server
|
- 自动获取API server
|
||||||
- Automatically obtain ID server and KEY
|
- 自动获取ID服务器和KEY
|
||||||
- Automatically obtain address book
|
- 自动获取地址簿
|
||||||
- Visitors are remotely to the device via a temporary sharing link
|
- 游客通过临时分享链接直接远程到设备
|
||||||
|
- v2 Preview
|
||||||
- CLI
|
- CLI
|
||||||
- Reset admin password
|
- 重置管理员密码
|
||||||
|
|
||||||
## Overview
|
## 功能
|
||||||
|
|
||||||
### API Service
|
|
||||||
Basic implementation of the PC client's primary interfaces.Supports the Personal version api, which can be enabled by configuring the `rustdesk.personal` file or the `RUSTDESK_API_RUSTDESK_PERSONAL` environment variable.
|
### API 服务
|
||||||
|
基本实现了PC端基础的接口。支持Personal版本接口,可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%" align="center" colspan="2"><b>Login</b></td>
|
<td width="50%" align="center" colspan="2"><b>登录</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%" align="center" colspan="2"><img src="docs/en_img/pc_login.png"></td>
|
<td width="50%" align="center" colspan="2"><img src="docs/pc_login.png"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%" align="center"><b>Address Book</b></td>
|
<td width="50%" align="center"><b>地址簿</b></td>
|
||||||
<td width="50%" align="center"><b>Groups</b></td>
|
<td width="50%" align="center"><b>群组</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%" align="center"><img src="docs/en_img/pc_ab.png"></td>
|
<td width="50%" align="center"><img src="docs/pc_ab.png"></td>
|
||||||
<td width="50%" align="center"><img src="docs/en_img/pc_gr.png"></td>
|
<td width="50%" align="center"><img src="docs/pc_gr.png"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
### Web Admin
|
### Web Admin:
|
||||||
|
|
||||||
* The frontend and backend are separated to provide a user-friendly management interface, primarily for managing and
|
* 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
||||||
displaying data.Frontend code is available at [rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
|
||||||
|
|
||||||
* Admin panel URL: `http://<your server[:port]>/_admin/`
|
* 后台访问地址是`http://<your server>[:port]/_admin/`
|
||||||
* For the initial installation, the admin username is `admin`, and the password will be printed in the console. You can change the password via the [command line](#CLI).
|
* 初次安装管理员为用户名为`admin`,密码将在控制台打印,可以通过[命令行](#CLI)更改密码
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
1. 管理员界面
|
||||||
|

|
||||||
|
2. 普通用户界面
|
||||||
|

|
||||||
|
|
||||||
1. Admin interface:
|
3. 每个用户可以多个地址簿,也可以将地址簿共享给其他用户
|
||||||

|
4. 分组可以自定义,方便管理,暂时支持两种类型: `共享组` 和 `普通组`
|
||||||
2. Regular user interface:
|
5. 可以直接打开webclient,方便使用;也可以分享给游客,游客可以直接通过webclient远程到设备
|
||||||

|
6. Oauth,支持了`Github`, `Google` 以及 `OIDC`, 需要创建一个`OAuth App`,然后配置到后台
|
||||||
|
- 对于`Google` 和 `Github`, `Issuer` 和 `Scopes`不需要填写.
|
||||||
|
- 对于`OIDC`, `Issuer`是必须的。`Scopes`是可选的,默认为 `openid,profile,email`. 确保可以获取 `sub`,`email` 和`preferred_username`
|
||||||
|
- `github oauth app`在`Settings`->`Developer settings`->`OAuth Apps`->`New OAuth App`
|
||||||
|
中创建,地址 [https://github.com/settings/developers](https://github.com/settings/developers)
|
||||||
|
- `Authorization callback URL`填写`http://<your server[:port]>/api/oauth/callback`
|
||||||
|
,比如`http://127.0.0.1:21114/api/oauth/callback`
|
||||||
|
7. 登录日志
|
||||||
|
8. 链接日志
|
||||||
|
9. 文件传输日志
|
||||||
|
10. server控制
|
||||||
|
|
||||||
3. Each user can have multiple address books, which can also be shared with other users.
|
- `简易模式`,已经界面化了一些简单的指令,可以直接在后台执行
|
||||||
4. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
|

|
||||||
5. You can directly launch the client or open the web client for convenience; you can also share it with guests, who can remotely access the device via the web client.
|
|
||||||
6. OAuth support: Currently, `GitHub`, `Google` and `OIDC` are supported. You need to create an `OAuth App` and configure it in
|
|
||||||
the admin panel.
|
|
||||||
- For `Google` and `Github`, you don't need to fill the `Issuer` and `Scpoes`
|
|
||||||
- For `OIDC`, you must set the `Issuer`. And `Scopes` is optional which default is `openid,email,profile`, please make sure this `Oauth App` can access `sub`, `email` and `preferred_username`
|
|
||||||
- Create a `GitHub OAuth App`
|
|
||||||
at `Settings` -> `Developer settings` -> `OAuth Apps` -> `New OAuth App` [here](https://github.com/settings/developers).
|
|
||||||
- Set the `Authorization callback URL` to `http://<your server[:port]>/api/oidc/callback`,
|
|
||||||
e.g., `http://127.0.0.1:21114/api/oidc/callback`.
|
|
||||||
|
|
||||||
7. Login logs
|
|
||||||
8. Connection logs
|
|
||||||
9. File transfer logs
|
|
||||||
10. Server control
|
|
||||||
- `Simple mode`, some simple commands have been GUI-ized and can be executed directly in the backend
|
|
||||||

|
|
||||||
|
|
||||||
- `Advanced mode`, commands can be executed directly in the backend
|
- `高级模式`,直接在后台执行指令
|
||||||
* Official commands can be used
|
* 可以官方指令
|
||||||
* Custom commands can be added
|
* 可以添加自定义指令
|
||||||
* Custom commands can be executed
|
* 可以执行自定义指令
|
||||||
|
|
||||||
|
|
||||||
|
11. **LDAP 支持**, 当在API Server上设置了LDAP(已测试AD和LDAP),可以通过LDAP中的用户信息进行登录 https://github.com/lejianwen/rustdesk-api/issues/114 ,如果LDAP验证失败,返回本地用户
|
||||||
|
|
||||||
11. **LDAP Support**, When you setup the LDAP(test for OpenLDAP and AD), you can login with the LDAP's user. https://github.com/lejianwen/rustdesk-api/issues/114 , if LDAP fail fallback local user
|
|
||||||
|
|
||||||
### Web Client:
|
### Web Client:
|
||||||
|
|
||||||
1. If you're already logged into the admin panel, the web client will log in automatically.
|
1. 如果已经登录了后台,web client将自动直接登录
|
||||||
2. If you're not logged in, simply click the login button in the top right corner, and the API server will be
|
2. 如果没登录后台,点击右上角登录即可,api server已经自动配置好了
|
||||||
pre-configured.
|
3. 登录后,会自动同步ID服务器和KEY
|
||||||
3. After logging in, the ID server and key will be automatically synced.
|
4. 登录后,会将地址簿自动保存到web client中,方便使用
|
||||||
4. The address book will also be automatically saved to the web client for convenient use.
|
5. 现已支持`v2 Preview`,访问路径是`/webclient2`
|
||||||
|

|
||||||
|
6. `v2 preview` 部署,参考[WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
|
|
||||||
### Automated Documentation : API documentation is generated using Swag, making it easier for developers to understand and use the API.
|
|
||||||
|
|
||||||
1. Admin panel docs: `<your server[:port]>/admin/swagger/index.html`
|
### 自动化文档: 使用 Swag 生成 API 文档,方便开发者理解和使用 API。
|
||||||
2. PC client docs: `<your server[:port]>/swagger/index.html`
|
|
||||||
|
1. 后台文档 `<youer server[:port]>/admin/swagger/index.html`
|
||||||
|
2. PC端文档 `<youer server[:port]>/swagger/index.html`
|
||||||

|

|
||||||
|
|
||||||
### CLI
|
### CLI
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# help
|
# 查看帮助
|
||||||
./apimain -h
|
./apimain -h
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Reset admin password
|
#### 重置管理员密码
|
||||||
```bash
|
```bash
|
||||||
./apimain reset-admin-pwd <pwd>
|
./apimain reset-admin-pwd <pwd>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation and Setup
|
## 安装与运行
|
||||||
|
|
||||||
### Configuration
|
### 相关配置
|
||||||
|
|
||||||
* [Config File](./conf/config.yaml)
|
* [配置文件](./conf/config.yaml)
|
||||||
* Modify the configuration in `conf/config.yaml`.
|
* 参考`conf/config.yaml`配置文件,修改相关配置。
|
||||||
* If `gorm.type` is set to `sqlite`, MySQL-related configurations are not required.
|
* 如果`gorm.type`是`sqlite`,则不需要配置mysql相关配置。
|
||||||
* Language support: `en` and `zh-CN` are supported. The default is `zh-CN`.
|
* 语言如果不设置默认为`zh-CN`
|
||||||
|
|
||||||
|
### 环境变量
|
||||||
|
环境变量和配置文件`conf/config.yaml`中的配置一一对应,变量名前缀是`RUSTDESK_API`
|
||||||
|
下面表格并未全部列出,可以参考`conf/config.yaml`中的配置。
|
||||||
|
|
||||||
|
| 变量名 | 说明 | 示例 |
|
||||||
|
|--------------------------------------------------------|--------------------------------------------------------------------------------|------------------------------|
|
||||||
|
| TZ | 时区 | Asia/Shanghai |
|
||||||
|
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
|
||||||
|
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
|
||||||
|
| RUSTDESK_API_APP_REGISTER | 是否开启注册; `true`, `false` 默认`false` | `false` |
|
||||||
|
| RUSTDESK_API_APP_SHOW_SWAGGER | 是否可见swagger文档;`1`显示,`0`不显示,默认`0`不显示 | `1` |
|
||||||
|
| RUSTDESK_API_APP_TOKEN_EXPIRE | token有效时长 | `168h` |
|
||||||
|
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | 是否禁用密码登录; `true`, `false` 默认`false` | `false` |
|
||||||
|
| -----ADMIN配置----- | ---------- | ---------- |
|
||||||
|
| RUSTDESK_API_ADMIN_TITLE | 后台标题 | `RustDesk Api Admin` |
|
||||||
|
| RUSTDESK_API_ADMIN_HELLO | 后台欢迎语,可以使用`html` | |
|
||||||
|
| RUSTDESK_API_ADMIN_HELLO_FILE | 后台欢迎语文件,如果内容多,使用文件更方便。<br>会覆盖`RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
||||||
|
| -----GIN配置----- | ---------- | ---------- |
|
||||||
|
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
||||||
|
| -----GORM配置----- | ---------- | --------------------------- |
|
||||||
|
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
||||||
|
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
||||||
|
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
||||||
|
| -----MYSQL配置----- | ---------- | ---------- |
|
||||||
|
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
||||||
|
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
||||||
|
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
||||||
|
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
||||||
|
| -----RUSTDESK配置----- | ---------- | ---------- |
|
||||||
|
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk存放key的文件 | `./conf/data/id_ed25519.pub` |
|
||||||
|
| RUSTDESK_API_RUSTDESK_WEBCLIENT<br/>_MAGIC_QUERYONLINE | Web client v2 中是否启用新的在线状态查询方法; `1`:启用,`0`:不启用,默认不启用 | `0` |
|
||||||
|
| RUSTDESK_API_RUSTDESK_WS_HOST | 自定义Websocket Host | `wss://192.168.1.123:1234` |
|
||||||
|
| ----PROXY配置----- | ---------- | ---------- |
|
||||||
|
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
|
||||||
|
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
|
||||||
|
| ----JWT配置---- | -------- | -------- |
|
||||||
|
| RUSTDESK_API_JWT_KEY | 自定义JWT KEY,为空则不启用JWT<br/>如果没使用`lejianwen/rustdesk-server`中的`MUST_LOGIN`,建议设置为空 | |
|
||||||
|
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT有效时间 | `168h` |
|
||||||
|
|
||||||
|
|
||||||
### Environment Variables
|
### 运行
|
||||||
The environment variables correspond one-to-one with the configurations in the `conf/config.yaml` file. The prefix for variable names is `RUSTDESK_API`.
|
|
||||||
The table below does not list all configurations. Please refer to the configurations in `conf/config.yaml`.
|
|
||||||
|
|
||||||
| Variable Name | Description | Example |
|
#### docker运行
|
||||||
|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|
|
|
||||||
| TZ | timezone | Asia/Shanghai |
|
|
||||||
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
|
||||||
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, default: 1 | 1 |
|
|
||||||
| RUSTDESK_API_APP_REGISTER | register enable; `true`, `false`; default:`false` | `false` |
|
|
||||||
| RUSTDESK_API_APP_SHOW_SWAGGER | swagger visible; 1: yes, 0: no; default: 0 | `0` |
|
|
||||||
| RUSTDESK_API_APP_TOKEN_EXPIRE | token expire duration | `168h` |
|
|
||||||
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | disable password login | `false` |
|
|
||||||
| RUSTDESK_API_APP_REGISTER_STATUS | register user default status ; 1 enabled , 2 disabled ; default 1 | `1` |
|
|
||||||
| RUSTDESK_API_APP_CAPTCHA_THRESHOLD | captcha threshold; -1 disabled, 0 always enable, >0 threshold ;default `3` | `3` |
|
|
||||||
| RUSTDESK_API_APP_BAN_THRESHOLD | ban ip threshold; 0 disabled, >0 threshold ; default `0` | `0` |
|
|
||||||
| ----- ADMIN Configuration----- | ---------- | ---------- |
|
|
||||||
| RUSTDESK_API_ADMIN_TITLE | Admin Title | `RustDesk Api Admin` |
|
|
||||||
| RUSTDESK_API_ADMIN_HELLO | Admin welcome message, you can use `html` | |
|
|
||||||
| RUSTDESK_API_ADMIN_HELLO_FILE | Admin welcome message file,<br>will override `RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
|
||||||
| ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- |
|
|
||||||
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
|
||||||
| ----- GORM Configuration ----- | --------------------------------------- | ----------------------------- |
|
|
||||||
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
|
||||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
|
||||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
|
||||||
| ----- MYSQL Configuration ----- | --------------------------------------- | ----------------------------- |
|
|
||||||
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
|
||||||
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
|
||||||
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
|
||||||
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
|
||||||
| RUSTDESK_API_MYSQL_TLS | Whether to enable TLS, optional values: `true`, `false`, `skip-verify`, `custom` | `false` |
|
|
||||||
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ----------------------------- |
|
|
||||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk key file | `./conf/data/id_ed25519.pub` |
|
|
||||||
| RUSTDESK_API_RUSTDESK<br/>_WEBCLIENT_MAGIC_QUERYONLINE | New online query method is enabled in the web client v2; '1': Enabled, '0': Disabled, not enabled by default | `0` |
|
|
||||||
| RUSTDESK_API_RUSTDESK_WS_HOST | Custom Websocket Host | `wss://192.168.1.123:1234` |
|
|
||||||
| ---- PROXY ----- | --------------- | ---------- |
|
|
||||||
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
|
|
||||||
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
|
|
||||||
| ----JWT---- | -------- | -------- |
|
|
||||||
| RUSTDESK_API_JWT_KEY | Custom JWT KEY, if empty JWT is not enabled.<br/>If `MUST_LOGIN` from `lejianwen/rustdesk-server` is not used, it is recommended to leave it empty. | |
|
|
||||||
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT expire duration | `168h` |
|
|
||||||
|
|
||||||
### Installation Steps
|
1. 直接docker运行,配置可以通过挂载配置文件`/app/conf/config.yaml`来修改,或者通过环境变量覆盖配置文件中的配置
|
||||||
|
|
||||||
#### Running via Docker
|
|
||||||
|
|
||||||
1. Run directly with Docker. Configuration can be modified by mounting the config file `/app/conf/config.yaml`, or by
|
|
||||||
using environment variables to override settings.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d --name rustdesk-api -p 21114:21114 \
|
docker run -d --name rustdesk-api -p 21114:21114 \
|
||||||
-v /data/rustdesk/api:/app/data \
|
-v /data/rustdesk/api:/app/data \
|
||||||
-e RUSTDESK_API_LANG=en \
|
-e TZ=Asia/Shanghai \
|
||||||
|
-e RUSTDESK_API_LANG=zh-CN \
|
||||||
-e RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116 \
|
-e RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116 \
|
||||||
-e RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117 \
|
-e RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117 \
|
||||||
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
||||||
-e RUSTDESK_API_RUSTDESK_KEY=abc123456 \
|
-e RUSTDESK_API_RUSTDESK_KEY=<key> \
|
||||||
lejianwen/rustdesk-api
|
lejianwen/rustdesk-api
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Using `docker-compose`,look [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
2. 使用`docker compose`,参考[WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
|
|
||||||
#### Running from Release
|
#### 下载release直接运行
|
||||||
|
|
||||||
Download the release from [release](https://github.com/lejianwen/rustdesk-api/releases).
|
[下载地址](https://github.com/lejianwen/rustdesk-api/releases)
|
||||||
|
|
||||||
#### Source Installation
|
#### 源码安装
|
||||||
|
|
||||||
1. Clone the repository:
|
1. 克隆仓库
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/lejianwen/rustdesk-api.git
|
git clone https://github.com/lejianwen/rustdesk-api.git
|
||||||
cd rustdesk-api
|
cd rustdesk-api
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Install dependencies:
|
2. 安装依赖
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go mod tidy
|
go mod tidy
|
||||||
# Install Swag if you need to generate documentation; otherwise, you can skip this step
|
#安装swag,如果不需要生成文档,可以不安装
|
||||||
go install github.com/swaggo/swag/cmd/swag@latest
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Build the admin front-end (the front-end code is
|
3. 编译后台前端,前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)中
|
||||||
in [rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)):
|
|
||||||
```bash
|
```bash
|
||||||
cd resources
|
cd resources
|
||||||
mkdir -p admin
|
mkdir -p admin
|
||||||
@@ -254,33 +245,23 @@ Download the release from [release](https://github.com/lejianwen/rustdesk-api/re
|
|||||||
npm run build
|
npm run build
|
||||||
cp -ar dist/* ../admin/
|
cp -ar dist/* ../admin/
|
||||||
```
|
```
|
||||||
|
4. 运行
|
||||||
4. Run:
|
|
||||||
```bash
|
```bash
|
||||||
# Run directly
|
#直接运行
|
||||||
go run cmd/apimain.go
|
go run cmd/apimain.go
|
||||||
# Or generate and run the API using generate_api.go
|
#或者使用generate_api.go生成api并运行
|
||||||
go generate generate_api.go
|
go generate generate_api.go
|
||||||
```
|
```
|
||||||
> **Note:** When using `go run` or the compiled binary, the `conf` and `resources`
|
5. 编译,如果想自己编译,先cd到项目根目录,然后windows下直接运行`build.bat`,linux下运行`build.sh`,编译后会在`release`
|
||||||
> directories must exist relative to the current working directory. If you run
|
目录下生成对应的可执行文件。直接运行编译后的可执行文件即可。
|
||||||
> the program from another location, specify absolute paths with `-c` and the
|
|
||||||
> `RUSTDESK_API_GIN_RESOURCES_PATH` environment variable. Example:
|
|
||||||
> ```bash
|
|
||||||
> RUSTDESK_API_GIN_RESOURCES_PATH=/opt/rustdesk-api/resources ./apimain -c /opt/rustdesk-api/conf/config.yaml
|
|
||||||
> ```
|
|
||||||
|
|
||||||
5. To compile, change to the project root directory. For Windows, run `build.bat`, and for Linux, run `build.sh`. After
|
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
||||||
compiling, the corresponding executables will be generated in the `release` directory. Run the compiled executables
|
|
||||||
directly.
|
|
||||||
|
|
||||||
6. Open your browser and visit `http://<your server[:port]>/_admin/`, with default credentials `admin admin`. Please
|
|
||||||
change the password promptly.
|
|
||||||
|
|
||||||
#### Running with my forked server-s6 image
|
#### 使用`lejianwen/server-s6`镜像运行
|
||||||
|
|
||||||
- Connection timeout issue resolved
|
- 已解决链接超时问题
|
||||||
- Can enforce login before initiating a connection
|
- 可以强制登录后才能发起链接
|
||||||
- github https://github.com/lejianwen/rustdesk-server
|
- github https://github.com/lejianwen/rustdesk-server
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -310,28 +291,28 @@ Download the release from [release](https://github.com/lejianwen/rustdesk-api/re
|
|||||||
- RUSTDESK_API_JWT_KEY=xxxxxx # jwt key
|
- RUSTDESK_API_JWT_KEY=xxxxxx # jwt key
|
||||||
volumes:
|
volumes:
|
||||||
- /data/rustdesk/server:/data
|
- /data/rustdesk/server:/data
|
||||||
- /data/rustdesk/api:/app/data # mount the database
|
- /data/rustdesk/api:/app/data #将数据库挂载
|
||||||
networks:
|
networks:
|
||||||
- rustdesk-net
|
- rustdesk-net
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
```
|
```
|
||||||
## Others
|
|
||||||
|
|
||||||
|
## 其他
|
||||||
|
|
||||||
- [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
- [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
- [Connection Timeout](https://github.com/lejianwen/rustdesk-api/issues/92)
|
- [链接超时问题](https://github.com/lejianwen/rustdesk-api/issues/92)
|
||||||
- [Change client ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
- [修改客户端ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
||||||
- [Web client source](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
- [webclient来源](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
Thanks to everyone who contributed!
|
## 鸣谢
|
||||||
|
|
||||||
|
感谢所有做过贡献的人!
|
||||||
|
|
||||||
<a href="https://github.com/lejianwen/rustdesk-api/graphs/contributors">
|
<a href="https://github.com/lejianwen/rustdesk-api/graphs/contributors">
|
||||||
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
|
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
## Thanks for your support! If you find this project useful, please give it a ⭐️. Thank you!
|
## 感谢你的支持!如果这个项目对你有帮助,请点个⭐️鼓励一下,谢谢!
|
||||||
|
|
||||||
|
|
||||||
[lejianwen/rustdesk-server]: https://github.com/lejianwen/rustdesk-server
|
|
||||||
|
|||||||
+169
-187
@@ -1,9 +1,7 @@
|
|||||||
# RustDesk API
|
# RustDesk API
|
||||||
|
|
||||||
[English Doc](README.md)
|
This project implements the RustDesk API using Go, and includes both a web UI and web client. RustDesk is a remote
|
||||||
|
desktop software that provides self-hosted solutions.
|
||||||
本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web Admin 和 Web 客户端。
|
|
||||||
|
|
||||||
|
|
||||||
<div align=center>
|
<div align=center>
|
||||||
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
||||||
@@ -14,237 +12,229 @@
|
|||||||
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## 搭配[lejianwen/rustdesk-server]使用更佳。
|
# Features
|
||||||
> [lejianwen/rustdesk-server]fork自RustDesk Server官方仓库
|
|
||||||
> 1. 解决了使用API链接超时问题
|
|
||||||
> 2. 可以强制登录后才能发起链接
|
|
||||||
> 3. 支持客户端websocket
|
|
||||||
|
|
||||||
|
- PC API
|
||||||
|
- Personal API
|
||||||
# 特性
|
- Login
|
||||||
|
- Address Book
|
||||||
- PC端API
|
- Groups
|
||||||
- 个人版API
|
- Authorized login,
|
||||||
- 登录
|
- supports `GitHub`, `Google` and `OIDC` login,
|
||||||
- 地址簿
|
- supports `web admin` authorized login,
|
||||||
- 群组
|
- supports LDAP(test AD and openladp) if API Server config
|
||||||
- 授权登录
|
|
||||||
- 支持`github`, `google` 和 `OIDC` 登录,
|
|
||||||
- 支持`web后台`授权登录
|
|
||||||
- 支持`LDAP`(AD和OpenLDAP已测试), 如果API Server配置了LDAP
|
|
||||||
- i18n
|
- i18n
|
||||||
- Web Admin
|
- Web Admin
|
||||||
- 用户管理
|
- User Management
|
||||||
- 设备管理
|
- Device Management
|
||||||
- 地址簿管理
|
- Address Book Management
|
||||||
- 标签管理
|
- Tag Management
|
||||||
- 群组管理
|
- Group Management
|
||||||
- Oauth 管理
|
- OAuth Management
|
||||||
- 配置LDAP, 配置文件或者环境变量
|
- LDAP Config by config file or ENV
|
||||||
- 登录日志
|
- Login Logs
|
||||||
- 链接日志
|
- Connection Logs
|
||||||
- 文件传输日志
|
- File Transfer Logs
|
||||||
- 快速使用web client
|
- Quick access to web client
|
||||||
- i18n
|
- i18n
|
||||||
- 通过 web client 分享给游客
|
- Share to guest by web client
|
||||||
- server控制(一些官方的简单的指令 [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
- Server control (some simple official commands [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
||||||
- Web Client
|
- Web Client
|
||||||
- 自动获取API server
|
- Automatically obtain API server
|
||||||
- 自动获取ID服务器和KEY
|
- Automatically obtain ID server and KEY
|
||||||
- 自动获取地址簿
|
- Automatically obtain address book
|
||||||
- 游客通过临时分享链接直接远程到设备
|
- Visitors are remotely to the device via a temporary sharing link
|
||||||
- CLI
|
- CLI
|
||||||
- 重置管理员密码
|
- Reset admin password
|
||||||
|
|
||||||
## 功能
|
## Overview
|
||||||
|
|
||||||
|
### API Service
|
||||||
### API 服务
|
Basic implementation of the PC client's primary interfaces.Supports the Personal version api, which can be enabled by configuring the `rustdesk.personal` file or the `RUSTDESK_API_RUSTDESK_PERSONAL` environment variable.
|
||||||
基本实现了PC端基础的接口。支持Personal版本接口,可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%" align="center" colspan="2"><b>登录</b></td>
|
<td width="50%" align="center" colspan="2"><b>Login</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%" align="center" colspan="2"><img src="docs/pc_login.png"></td>
|
<td width="50%" align="center" colspan="2"><img src="docs/en_img/pc_login.png"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%" align="center"><b>地址簿</b></td>
|
<td width="50%" align="center"><b>Address Book</b></td>
|
||||||
<td width="50%" align="center"><b>群组</b></td>
|
<td width="50%" align="center"><b>Groups</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%" align="center"><img src="docs/pc_ab.png"></td>
|
<td width="50%" align="center"><img src="docs/en_img/pc_ab.png"></td>
|
||||||
<td width="50%" align="center"><img src="docs/pc_gr.png"></td>
|
<td width="50%" align="center"><img src="docs/en_img/pc_gr.png"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
### Web Admin:
|
### Web Admin
|
||||||
|
|
||||||
* 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
* The frontend and backend are separated to provide a user-friendly management interface, primarily for managing and
|
||||||
|
displaying data.Frontend code is available at [rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
||||||
|
|
||||||
* 后台访问地址是`http://<your server>[:port]/_admin/`
|
* Admin panel URL: `http://<your server[:port]>/_admin/`
|
||||||
* 初次安装管理员为用户名为`admin`,密码将在控制台打印,可以通过[命令行](#CLI)更改密码
|
* For the initial installation, the admin username is `admin`, and the password will be printed in the console. You can change the password via the [command line](#CLI).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
1. 管理员界面
|
|
||||||

|
|
||||||
2. 普通用户界面
|
|
||||||

|
|
||||||
|
|
||||||
3. 每个用户可以多个地址簿,也可以将地址簿共享给其他用户
|
1. Admin interface:
|
||||||
4. 分组可以自定义,方便管理,暂时支持两种类型: `共享组` 和 `普通组`
|

|
||||||
5. 可以直接打开webclient,方便使用;也可以分享给游客,游客可以直接通过webclient远程到设备
|
2. Regular user interface:
|
||||||
6. Oauth,支持了`Github`, `Google` 以及 `OIDC`, 需要创建一个`OAuth App`,然后配置到后台
|

|
||||||
- 对于`Google` 和 `Github`, `Issuer` 和 `Scopes`不需要填写.
|
|
||||||
- 对于`OIDC`, `Issuer`是必须的。`Scopes`是可选的,默认为 `openid,profile,email`. 确保可以获取 `sub`,`email` 和`preferred_username`
|
|
||||||
- `github oauth app`在`Settings`->`Developer settings`->`OAuth Apps`->`New OAuth App`
|
|
||||||
中创建,地址 [https://github.com/settings/developers](https://github.com/settings/developers)
|
|
||||||
- `Authorization callback URL`填写`http://<your server[:port]>/api/oidc/callback`
|
|
||||||
,比如`http://127.0.0.1:21114/api/oidc/callback`
|
|
||||||
7. 登录日志
|
|
||||||
8. 链接日志
|
|
||||||
9. 文件传输日志
|
|
||||||
10. server控制
|
|
||||||
|
|
||||||
- `简易模式`,已经界面化了一些简单的指令,可以直接在后台执行
|
3. Each user can have multiple address books, which can also be shared with other users.
|
||||||

|
4. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
|
||||||
|
5. You can directly launch the client or open the web client for convenience; you can also share it with guests, who can remotely access the device via the web client.
|
||||||
|
6. OAuth support: Currently, `GitHub`, `Google` and `OIDC` are supported. You need to create an `OAuth App` and configure it in
|
||||||
|
the admin panel.
|
||||||
|
- For `Google` and `Github`, you don't need to fill the `Issuer` and `Scpoes`
|
||||||
|
- For `OIDC`, you must set the `Issuer`. And `Scopes` is optional which default is `openid,email,profile`, please make sure this `Oauth App` can access `sub`, `email` and `preferred_username`
|
||||||
|
- Create a `GitHub OAuth App`
|
||||||
|
at `Settings` -> `Developer settings` -> `OAuth Apps` -> `New OAuth App` [here](https://github.com/settings/developers).
|
||||||
|
- Set the `Authorization callback URL` to `http://<your server[:port]>/api/oauth/callback`,
|
||||||
|
e.g., `http://127.0.0.1:21114/api/oauth/callback`.
|
||||||
|
|
||||||
|
7. Login logs
|
||||||
|
8. Connection logs
|
||||||
|
9. File transfer logs
|
||||||
|
10. Server control
|
||||||
|
- `Simple mode`, some simple commands have been GUI-ized and can be executed directly in the backend
|
||||||
|

|
||||||
|
|
||||||
- `高级模式`,直接在后台执行指令
|
- `Advanced mode`, commands can be executed directly in the backend
|
||||||
* 可以官方指令
|
* Official commands can be used
|
||||||
* 可以添加自定义指令
|
* Custom commands can be added
|
||||||
* 可以执行自定义指令
|
* Custom commands can be executed
|
||||||
|
|
||||||
|
|
||||||
11. **LDAP 支持**, 当在API Server上设置了LDAP(已测试AD和LDAP),可以通过LDAP中的用户信息进行登录 https://github.com/lejianwen/rustdesk-api/issues/114 ,如果LDAP验证失败,返回本地用户
|
|
||||||
|
|
||||||
|
11. **LDAP Support**, When you setup the LDAP(test for OpenLDAP and AD), you can login with the LDAP's user. https://github.com/lejianwen/rustdesk-api/issues/114 , if LDAP fail fallback local user
|
||||||
|
|
||||||
### Web Client:
|
### Web Client:
|
||||||
|
|
||||||
1. 如果已经登录了后台,web client将自动直接登录
|
1. If you're already logged into the admin panel, the web client will log in automatically.
|
||||||
2. 如果没登录后台,点击右上角登录即可,api server已经自动配置好了
|
2. If you're not logged in, simply click the login button in the top right corner, and the API server will be
|
||||||
3. 登录后,会自动同步ID服务器和KEY
|
pre-configured.
|
||||||
4. 登录后,会将地址簿自动保存到web client中,方便使用
|
3. After logging in, the ID server and key will be automatically synced.
|
||||||
|
4. The address book will also be automatically saved to the web client for convenient use.
|
||||||
|
5. Now supports `v2 Preview`, accessible at `/webclient2`
|
||||||
|

|
||||||
|
6. `v2 preview` deployment, [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
|
|
||||||
|
### Automated Documentation : API documentation is generated using Swag, making it easier for developers to understand and use the API.
|
||||||
|
|
||||||
### 自动化文档: 使用 Swag 生成 API 文档,方便开发者理解和使用 API。
|
1. Admin panel docs: `<your server[:port]>/admin/swagger/index.html`
|
||||||
|
2. PC client docs: `<your server[:port]>/swagger/index.html`
|
||||||
1. 后台文档 `<youer server[:port]>/admin/swagger/index.html`
|
|
||||||
2. PC端文档 `<youer server[:port]>/swagger/index.html`
|
|
||||||

|

|
||||||
|
|
||||||
### CLI
|
### CLI
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 查看帮助
|
# help
|
||||||
./apimain -h
|
./apimain -h
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 重置管理员密码
|
#### Reset admin password
|
||||||
```bash
|
```bash
|
||||||
./apimain reset-admin-pwd <pwd>
|
./apimain reset-admin-pwd <pwd>
|
||||||
```
|
```
|
||||||
|
|
||||||
## 安装与运行
|
## Installation and Setup
|
||||||
|
|
||||||
### 相关配置
|
### Configuration
|
||||||
|
|
||||||
* [配置文件](./conf/config.yaml)
|
* [Config File](./conf/config.yaml)
|
||||||
* 参考`conf/config.yaml`配置文件,修改相关配置。
|
* Modify the configuration in `conf/config.yaml`.
|
||||||
* 如果`gorm.type`是`sqlite`,则不需要配置mysql相关配置。
|
* If `gorm.type` is set to `sqlite`, MySQL-related configurations are not required.
|
||||||
* 语言如果不设置默认为`zh-CN`
|
* Language support: `en` and `zh-CN` are supported. The default is `zh-CN`.
|
||||||
|
|
||||||
### 环境变量
|
|
||||||
环境变量和配置文件`conf/config.yaml`中的配置一一对应,变量名前缀是`RUSTDESK_API`
|
|
||||||
下面表格并未全部列出,可以参考`conf/config.yaml`中的配置。
|
|
||||||
|
|
||||||
| 变量名 | 说明 | 示例 |
|
|
||||||
|--------------------------------------------------------|--------------------------------------------------------------------------------|------------------------------|
|
|
||||||
| TZ | 时区 | Asia/Shanghai |
|
|
||||||
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
|
|
||||||
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
|
|
||||||
| RUSTDESK_API_APP_REGISTER | 是否开启注册; `true`, `false` 默认`false` | `false` |
|
|
||||||
| RUSTDESK_API_APP_SHOW_SWAGGER | 是否可见swagger文档;`1`显示,`0`不显示,默认`0`不显示 | `1` |
|
|
||||||
| RUSTDESK_API_APP_TOKEN_EXPIRE | token有效时长 | `168h` |
|
|
||||||
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | 是否禁用密码登录; `true`, `false` 默认`false` | `false` |
|
|
||||||
| RUSTDESK_API_APP_REGISTER_STATUS | 注册用户默认状态; 1 启用,2 禁用, 默认 1 | `1` |
|
|
||||||
| RUSTDESK_API_APP_CAPTCHA_THRESHOLD | 验证码触发次数; -1 不启用, 0 一直启用, >0 登录错误次数后启用 ;默认 `3` | `3` |
|
|
||||||
| RUSTDESK_API_APP_BAN_THRESHOLD | 封禁IP触发次数; 0 不启用, >0 登录错误次数后封禁IP; 默认 `0` | `0` |
|
|
||||||
| -----ADMIN配置----- | ---------- | ---------- |
|
|
||||||
| RUSTDESK_API_ADMIN_TITLE | 后台标题 | `RustDesk Api Admin` |
|
|
||||||
| RUSTDESK_API_ADMIN_HELLO | 后台欢迎语,可以使用`html` | |
|
|
||||||
| RUSTDESK_API_ADMIN_HELLO_FILE | 后台欢迎语文件,如果内容多,使用文件更方便。<br>会覆盖`RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
|
||||||
| -----GIN配置----- | ---------- | ---------- |
|
|
||||||
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
|
||||||
| -----GORM配置----- | ---------- | --------------------------- |
|
|
||||||
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
|
||||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
|
||||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
|
||||||
| -----MYSQL配置----- | ---------- | ---------- |
|
|
||||||
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
|
||||||
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
|
||||||
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
|
||||||
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
|
||||||
| RUSTDESK_API_MYSQL_TLS | 是否启用TLS, 可选值: `true`, `false`, `skip-verify`, `custom` | `false` |
|
|
||||||
| -----RUSTDESK配置----- | ---------- | ---------- |
|
|
||||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk存放key的文件 | `./conf/data/id_ed25519.pub` |
|
|
||||||
| RUSTDESK_API_RUSTDESK_WEBCLIENT<br/>_MAGIC_QUERYONLINE | Web client v2 中是否启用新的在线状态查询方法; `1`:启用,`0`:不启用,默认不启用 | `0` |
|
|
||||||
| RUSTDESK_API_RUSTDESK_WS_HOST | 自定义Websocket Host | `wss://192.168.1.123:1234` |
|
|
||||||
| ----PROXY配置----- | ---------- | ---------- |
|
|
||||||
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
|
|
||||||
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
|
|
||||||
| ----JWT配置---- | -------- | -------- |
|
|
||||||
| RUSTDESK_API_JWT_KEY | 自定义JWT KEY,为空则不启用JWT<br/>如果没使用`lejianwen/rustdesk-server`中的`MUST_LOGIN`,建议设置为空 | |
|
|
||||||
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT有效时间 | `168h` |
|
|
||||||
|
|
||||||
|
|
||||||
### 运行
|
### Environment Variables
|
||||||
|
The environment variables correspond one-to-one with the configurations in the `conf/config.yaml` file. The prefix for variable names is `RUSTDESK_API`.
|
||||||
|
The table below does not list all configurations. Please refer to the configurations in `conf/config.yaml`.
|
||||||
|
|
||||||
#### docker运行
|
| Variable Name | Description | Example |
|
||||||
|
|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|
|
||||||
|
| TZ | timezone | Asia/Shanghai |
|
||||||
|
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
||||||
|
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, default: 1 | 1 |
|
||||||
|
| RUSTDESK_API_APP_REGISTER | register enable; `true`, `false`; default:`false` | `false` |
|
||||||
|
| RUSTDESK_API_APP_SHOW_SWAGGER | swagger visible; 1: yes, 0: no; default: 0 | `0` |
|
||||||
|
| RUSTDESK_API_APP_TOKEN_EXPIRE | token expire duration | `168h` |
|
||||||
|
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | disable password login | `false` |
|
||||||
|
| ----- ADMIN Configuration----- | ---------- | ---------- |
|
||||||
|
| RUSTDESK_API_ADMIN_TITLE | Admin Title | `RustDesk Api Admin` |
|
||||||
|
| RUSTDESK_API_ADMIN_HELLO | Admin welcome message, you can use `html` | |
|
||||||
|
| RUSTDESK_API_ADMIN_HELLO_FILE | Admin welcome message file,<br>will override `RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
||||||
|
| ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
|
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
||||||
|
| ----- GORM Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
|
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
||||||
|
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
||||||
|
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
||||||
|
| ----- MYSQL Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
|
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
||||||
|
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
||||||
|
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
||||||
|
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
||||||
|
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
|
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk key file | `./conf/data/id_ed25519.pub` |
|
||||||
|
| RUSTDESK_API_RUSTDESK<br/>_WEBCLIENT_MAGIC_QUERYONLINE | New online query method is enabled in the web client v2; '1': Enabled, '0': Disabled, not enabled by default | `0` |
|
||||||
|
| RUSTDESK_API_RUSTDESK_WS_HOST | Custom Websocket Host | `wss://192.168.1.123:1234` |
|
||||||
|
| ---- PROXY ----- | --------------- | ---------- |
|
||||||
|
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
|
||||||
|
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
|
||||||
|
| ----JWT---- | -------- | -------- |
|
||||||
|
| RUSTDESK_API_JWT_KEY | Custom JWT KEY, if empty JWT is not enabled.<br/>If `MUST_LOGIN` from `lejianwen/rustdesk-server` is not used, it is recommended to leave it empty. | |
|
||||||
|
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT expire duration | `168h` |
|
||||||
|
|
||||||
1. 直接docker运行,配置可以通过挂载配置文件`/app/conf/config.yaml`来修改,或者通过环境变量覆盖配置文件中的配置
|
### Installation Steps
|
||||||
|
|
||||||
|
#### Running via Docker
|
||||||
|
|
||||||
|
1. Run directly with Docker. Configuration can be modified by mounting the config file `/app/conf/config.yaml`, or by
|
||||||
|
using environment variables to override settings.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d --name rustdesk-api -p 21114:21114 \
|
docker run -d --name rustdesk-api -p 21114:21114 \
|
||||||
-v /data/rustdesk/api:/app/data \
|
-v /data/rustdesk/api:/app/data \
|
||||||
-e TZ=Asia/Shanghai \
|
-e RUSTDESK_API_LANG=en \
|
||||||
-e RUSTDESK_API_LANG=zh-CN \
|
|
||||||
-e RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116 \
|
-e RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116 \
|
||||||
-e RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117 \
|
-e RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117 \
|
||||||
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
||||||
-e RUSTDESK_API_RUSTDESK_KEY=<key> \
|
-e RUSTDESK_API_RUSTDESK_KEY=abc123456 \
|
||||||
lejianwen/rustdesk-api
|
lejianwen/rustdesk-api
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 使用`docker compose`,参考[WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
2. Using `docker-compose`,look [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
|
|
||||||
#### 下载release直接运行
|
#### Running from Release
|
||||||
|
|
||||||
[下载地址](https://github.com/lejianwen/rustdesk-api/releases)
|
Download the release from [release](https://github.com/lejianwen/rustdesk-api/releases).
|
||||||
|
|
||||||
#### 源码安装
|
#### Source Installation
|
||||||
|
|
||||||
1. 克隆仓库
|
1. Clone the repository:
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/lejianwen/rustdesk-api.git
|
git clone https://github.com/lejianwen/rustdesk-api.git
|
||||||
cd rustdesk-api
|
cd rustdesk-api
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 安装依赖
|
2. Install dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go mod tidy
|
go mod tidy
|
||||||
#安装swag,如果不需要生成文档,可以不安装
|
# Install Swag if you need to generate documentation; otherwise, you can skip this step
|
||||||
go install github.com/swaggo/swag/cmd/swag@latest
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 编译后台前端,前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)中
|
3. Build the admin front-end (the front-end code is
|
||||||
|
in [rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)):
|
||||||
```bash
|
```bash
|
||||||
cd resources
|
cd resources
|
||||||
mkdir -p admin
|
mkdir -p admin
|
||||||
@@ -254,29 +244,26 @@
|
|||||||
npm run build
|
npm run build
|
||||||
cp -ar dist/* ../admin/
|
cp -ar dist/* ../admin/
|
||||||
```
|
```
|
||||||
4. 运行
|
|
||||||
|
4. Run:
|
||||||
```bash
|
```bash
|
||||||
#直接运行
|
# Run directly
|
||||||
go run cmd/apimain.go
|
go run cmd/apimain.go
|
||||||
#或者使用generate_api.go生成api并运行
|
# Or generate and run the API using generate_api.go
|
||||||
go generate generate_api.go
|
go generate generate_api.go
|
||||||
```
|
```
|
||||||
> 注意:使用 `go run` 或编译后的二进制时,当前目录下必须存在 `conf` 和 `resources`
|
|
||||||
> 目录。如果在其他目录运行,可通过 `-c` 和环境变量
|
|
||||||
> `RUSTDESK_API_GIN_RESOURCES_PATH` 指定绝对路径,例如:
|
|
||||||
> ```bash
|
|
||||||
> RUSTDESK_API_GIN_RESOURCES_PATH=/opt/rustdesk-api/resources ./apimain -c /opt/rustdesk-api/conf/config.yaml
|
|
||||||
> ```
|
|
||||||
5. 编译,如果想自己编译,先cd到项目根目录,然后windows下直接运行`build.bat`,linux下运行`build.sh`,编译后会在`release`
|
|
||||||
目录下生成对应的可执行文件。直接运行编译后的可执行文件即可。
|
|
||||||
|
|
||||||
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
5. To compile, change to the project root directory. For Windows, run `build.bat`, and for Linux, run `build.sh`. After
|
||||||
|
compiling, the corresponding executables will be generated in the `release` directory. Run the compiled executables
|
||||||
|
directly.
|
||||||
|
|
||||||
|
6. Open your browser and visit `http://<your server[:port]>/_admin/`, with default credentials `admin admin`. Please
|
||||||
|
change the password promptly.
|
||||||
|
|
||||||
#### 使用`lejianwen/server-s6`镜像运行
|
#### Running with my forked server-s6 image
|
||||||
|
|
||||||
- 已解决链接超时问题
|
- Connection timeout issue resolved
|
||||||
- 可以强制登录后才能发起链接
|
- Can enforce login before initiating a connection
|
||||||
- github https://github.com/lejianwen/rustdesk-server
|
- github https://github.com/lejianwen/rustdesk-server
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -312,24 +299,19 @@
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
```
|
```
|
||||||
|
## Others
|
||||||
|
|
||||||
## 其他
|
|
||||||
|
|
||||||
- [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
- [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
- [链接超时问题](https://github.com/lejianwen/rustdesk-api/issues/92)
|
- [Connection Timeout](https://github.com/lejianwen/rustdesk-api/issues/92)
|
||||||
- [修改客户端ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
- [Change client ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
||||||
- [webclient来源](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
- [Web client source](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
## 鸣谢
|
Thanks to everyone who contributed!
|
||||||
|
|
||||||
感谢所有做过贡献的人!
|
|
||||||
|
|
||||||
<a href="https://github.com/lejianwen/rustdesk-api/graphs/contributors">
|
<a href="https://github.com/lejianwen/rustdesk-api/graphs/contributors">
|
||||||
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
|
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
## 感谢你的支持!如果这个项目对你有帮助,请点个⭐️鼓励一下,谢谢!
|
## Thanks for your support! If you find this project useful, please give it a ⭐️. Thank you!
|
||||||
|
|
||||||
[lejianwen/rustdesk-server]: https://github.com/lejianwen/rustdesk-server
|
|
||||||
+28
-74
@@ -1,11 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/config"
|
"github.com/lejianwen/rustdesk-api/v2/config"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
@@ -21,13 +16,13 @@ import (
|
|||||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DatabaseVersion = 265
|
// @title 管理系统API
|
||||||
|
|
||||||
// @title Management System API
|
|
||||||
// @version 1.0
|
// @version 1.0
|
||||||
// @description API
|
// @description 接口
|
||||||
// @basePath /api
|
// @basePath /api
|
||||||
// @securityDefinitions.apikey token
|
// @securityDefinitions.apikey token
|
||||||
// @in header
|
// @in header
|
||||||
@@ -111,10 +106,10 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func InitGlobal() {
|
func InitGlobal() {
|
||||||
// config parsing
|
//配置解析
|
||||||
global.Viper = config.Init(&global.Config, global.ConfigPath)
|
global.Viper = config.Init(&global.Config, global.ConfigPath)
|
||||||
|
|
||||||
// logging
|
//日志
|
||||||
global.Logger = logger.New(&logger.Config{
|
global.Logger = logger.New(&logger.Config{
|
||||||
Path: global.Config.Logger.Path,
|
Path: global.Config.Logger.Path,
|
||||||
Level: global.Config.Logger.Level,
|
Level: global.Config.Logger.Level,
|
||||||
@@ -144,41 +139,18 @@ func InitGlobal() {
|
|||||||
}
|
}
|
||||||
//gorm
|
//gorm
|
||||||
if global.Config.Gorm.Type == config.TypeMysql {
|
if global.Config.Gorm.Type == config.TypeMysql {
|
||||||
|
dns := global.Config.Mysql.Username + ":" + global.Config.Mysql.Password + "@(" + global.Config.Mysql.Addr + ")/" + global.Config.Mysql.Dbname + "?charset=utf8mb4&parseTime=True&loc=Local"
|
||||||
dsn := fmt.Sprintf("%s:%s@(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local&tls=%s",
|
|
||||||
global.Config.Mysql.Username,
|
|
||||||
global.Config.Mysql.Password,
|
|
||||||
global.Config.Mysql.Addr,
|
|
||||||
global.Config.Mysql.Dbname,
|
|
||||||
global.Config.Mysql.Tls,
|
|
||||||
)
|
|
||||||
|
|
||||||
global.DB = orm.NewMysql(&orm.MysqlConfig{
|
global.DB = orm.NewMysql(&orm.MysqlConfig{
|
||||||
Dsn: dsn,
|
Dns: dns,
|
||||||
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
||||||
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
||||||
}, global.Logger)
|
})
|
||||||
} else if global.Config.Gorm.Type == config.TypePostgresql {
|
|
||||||
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s TimeZone=%s",
|
|
||||||
global.Config.Postgresql.Host,
|
|
||||||
global.Config.Postgresql.Port,
|
|
||||||
global.Config.Postgresql.User,
|
|
||||||
global.Config.Postgresql.Password,
|
|
||||||
global.Config.Postgresql.Dbname,
|
|
||||||
global.Config.Postgresql.Sslmode,
|
|
||||||
global.Config.Postgresql.TimeZone,
|
|
||||||
)
|
|
||||||
global.DB = orm.NewPostgresql(&orm.PostgresqlConfig{
|
|
||||||
Dsn: dsn,
|
|
||||||
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
|
||||||
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
|
||||||
}, global.Logger)
|
|
||||||
} else {
|
} else {
|
||||||
//sqlite
|
//sqlite
|
||||||
global.DB = orm.NewSqlite(&orm.SqliteConfig{
|
global.DB = orm.NewSqlite(&orm.SqliteConfig{
|
||||||
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
||||||
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
||||||
}, global.Logger)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//validator
|
//validator
|
||||||
@@ -203,47 +175,33 @@ func InitGlobal() {
|
|||||||
//service
|
//service
|
||||||
service.New(&global.Config, global.DB, global.Logger, global.Jwt, global.Lock)
|
service.New(&global.Config, global.DB, global.Logger, global.Jwt, global.Lock)
|
||||||
|
|
||||||
global.LoginLimiter = utils.NewLoginLimiter(utils.SecurityPolicy{
|
|
||||||
CaptchaThreshold: global.Config.App.CaptchaThreshold,
|
|
||||||
BanThreshold: global.Config.App.BanThreshold,
|
|
||||||
AttemptsWindow: 10 * time.Minute,
|
|
||||||
BanDuration: 30 * time.Minute,
|
|
||||||
})
|
|
||||||
global.LoginLimiter.RegisterProvider(utils.B64StringCaptchaProvider{})
|
|
||||||
DatabaseAutoUpdate()
|
DatabaseAutoUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func DatabaseAutoUpdate() {
|
func DatabaseAutoUpdate() {
|
||||||
version := DatabaseVersion
|
version := 262
|
||||||
|
|
||||||
db := global.DB
|
db := global.DB
|
||||||
|
|
||||||
if global.Config.Gorm.Type == config.TypeMysql {
|
if global.Config.Gorm.Type == config.TypeMysql {
|
||||||
// check whether the database exists; create it if not
|
//检查存不存在数据库,不存在则创建
|
||||||
dbName := db.Migrator().CurrentDatabase()
|
dbName := db.Migrator().CurrentDatabase()
|
||||||
if dbName == "" {
|
if dbName == "" {
|
||||||
dbName = global.Config.Mysql.Dbname
|
dbName = global.Config.Mysql.Dbname
|
||||||
// remove the database name from the DSN so the initial connection does not specify a database
|
// 移除 DSN 中的数据库名称,以便初始连接时不指定数据库
|
||||||
dsnWithoutDB := fmt.Sprintf("%s:%s@(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
dsnWithoutDB := global.Config.Mysql.Username + ":" + global.Config.Mysql.Password + "@(" + global.Config.Mysql.Addr + ")/?charset=utf8mb4&parseTime=True&loc=Local"
|
||||||
global.Config.Mysql.Username,
|
//新链接
|
||||||
global.Config.Mysql.Password,
|
|
||||||
global.Config.Mysql.Addr,
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
|
|
||||||
// new connection
|
|
||||||
dbWithoutDB := orm.NewMysql(&orm.MysqlConfig{
|
dbWithoutDB := orm.NewMysql(&orm.MysqlConfig{
|
||||||
Dsn: dsnWithoutDB,
|
Dns: dsnWithoutDB,
|
||||||
}, global.Logger)
|
})
|
||||||
// get the underlying *sql.DB object and ensure the connection is closed when the program exits
|
// 获取底层的 *sql.DB 对象,并确保在程序退出时关闭连接
|
||||||
sqlDBWithoutDB, err := dbWithoutDB.DB()
|
sqlDBWithoutDB, err := dbWithoutDB.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Logger.Errorf("failed to get underlying *sql.DB object: %v", err)
|
global.Logger.Errorf("获取底层 *sql.DB 对象失败: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := sqlDBWithoutDB.Close(); err != nil {
|
if err := sqlDBWithoutDB.Close(); err != nil {
|
||||||
global.Logger.Errorf("failed to close connection: %v", err)
|
global.Logger.Errorf("关闭连接失败: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -258,20 +216,20 @@ func DatabaseAutoUpdate() {
|
|||||||
if !db.Migrator().HasTable(&model.Version{}) {
|
if !db.Migrator().HasTable(&model.Version{}) {
|
||||||
Migrate(uint(version))
|
Migrate(uint(version))
|
||||||
} else {
|
} else {
|
||||||
// find the last version
|
//查找最后一个version
|
||||||
var v model.Version
|
var v model.Version
|
||||||
db.Last(&v)
|
db.Last(&v)
|
||||||
if v.Version < uint(version) {
|
if v.Version < uint(version) {
|
||||||
Migrate(uint(version))
|
Migrate(uint(version))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 245 migration
|
// 245迁移
|
||||||
if v.Version < 245 {
|
if v.Version < 245 {
|
||||||
// set the oauths table's oauth_type field to the same value as op
|
//oauths 表的 oauth_type 字段设置为 op同样的值
|
||||||
db.Exec("update oauths set oauth_type = op")
|
db.Exec("update oauths set oauth_type = op")
|
||||||
db.Exec("update oauths set issuer = 'https://accounts.google.com' where op = 'google'")
|
db.Exec("update oauths set issuer = 'https://accounts.google.com' where op = 'google'")
|
||||||
db.Exec("update user_thirds set oauth_type = third_type, op = third_type")
|
db.Exec("update user_thirds set oauth_type = third_type, op = third_type")
|
||||||
// migrate old google authorizations by email
|
//通过email迁移旧的google授权
|
||||||
uts := make([]model.UserThird, 0)
|
uts := make([]model.UserThird, 0)
|
||||||
db.Where("oauth_type = ?", "google").Find(&uts)
|
db.Where("oauth_type = ?", "google").Find(&uts)
|
||||||
for _, ut := range uts {
|
for _, ut := range uts {
|
||||||
@@ -311,7 +269,7 @@ func Migrate(version uint) {
|
|||||||
global.Logger.Error("migrate err :=>", err)
|
global.Logger.Error("migrate err :=>", err)
|
||||||
}
|
}
|
||||||
global.DB.Create(&model.Version{Version: version})
|
global.DB.Create(&model.Version{Version: version})
|
||||||
// if this is the first run, create a default user
|
//如果是初次则创建一个默认用户
|
||||||
var vc int64
|
var vc int64
|
||||||
global.DB.Model(&model.Version{}).Count(&vc)
|
global.DB.Model(&model.Version{}).Count(&vc)
|
||||||
if vc == 1 {
|
if vc == 1 {
|
||||||
@@ -333,7 +291,7 @@ func Migrate(version uint) {
|
|||||||
Type: model.GroupTypeShare,
|
Type: model.GroupTypeShare,
|
||||||
}
|
}
|
||||||
service.AllService.GroupService.Create(groupShare)
|
service.AllService.GroupService.Create(groupShare)
|
||||||
// is true
|
//是true
|
||||||
is_admin := true
|
is_admin := true
|
||||||
admin := &model.User{
|
admin := &model.User{
|
||||||
Username: "admin",
|
Username: "admin",
|
||||||
@@ -343,14 +301,10 @@ func Migrate(version uint) {
|
|||||||
GroupId: 1,
|
GroupId: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate a random password
|
// 生成随机密码
|
||||||
pwd := utils.RandomString(8)
|
pwd := utils.RandomString(8)
|
||||||
global.Logger.Info("Admin Password Is: ", pwd)
|
global.Logger.Info("Admin Password Is: ", pwd)
|
||||||
var err error
|
admin.Password = service.AllService.UserService.EncryptPassword(pwd)
|
||||||
admin.Password, err = utils.EncryptPassword(pwd)
|
|
||||||
if err != nil {
|
|
||||||
global.Logger.Fatalf("failed to generate admin password: %v", err)
|
|
||||||
}
|
|
||||||
global.DB.Create(admin)
|
global.DB.Create(admin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
### 👏👏👏 你好 ***{{username}}***, 欢迎使用 [RustDesk API](https://github.com/lejianwen/rustdesk-api)
|
||||||
+27
-27
@@ -1,26 +1,19 @@
|
|||||||
lang: "en"
|
lang: "zh-CN"
|
||||||
app:
|
app:
|
||||||
web-client: 1 # 1:enable 0:disable
|
web-client: 1 # 1:启用 0:禁用
|
||||||
register: false #whether registration is enabled
|
register: false #是否开启注册
|
||||||
register-status: 1 # default status for registered users 1:enable 2:disable
|
show-swagger: 0 # 1:启用 0:禁用
|
||||||
captcha-threshold: 3 # <0:disabled, 0 always, >0:enabled
|
|
||||||
ban-threshold: 0 # 0:disabled, >0:enabled
|
|
||||||
show-swagger: 0 # 1:enable 0:disable
|
|
||||||
token-expire: 168h
|
token-expire: 168h
|
||||||
web-sso: true #web auth sso
|
web-sso: true #web auth sso
|
||||||
disable-pwd-login: false #disable password login
|
disable-pwd-login: false #禁用密码登录
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
title: "RustDesk API Admin"
|
title: "RustDesk Api Admin"
|
||||||
hello-file: "./conf/admin/hello.html" #prefer to use a file for the welcome message
|
hello-file: "./conf/admin/hello.html" #优先使用file
|
||||||
hello: ""
|
hello: ""
|
||||||
# ID Server and Relay Server ports https://github.com/lejianwen/rustdesk-api/issues/257
|
|
||||||
id-server-port: 21116 # ID Server port (for server cmd)
|
|
||||||
relay-server-port: 21117 # ID Server port (for server cmd)
|
|
||||||
gin:
|
gin:
|
||||||
api-addr: "0.0.0.0:21114"
|
api-addr: "0.0.0.0:21114"
|
||||||
mode: "release" #release,debug,test
|
mode: "release" #release,debug,test
|
||||||
resources-path: 'resources' #public static file directory
|
resources-path: 'resources' #对外静态文件目录
|
||||||
trust-proxy: ""
|
trust-proxy: ""
|
||||||
gorm:
|
gorm:
|
||||||
type: "sqlite"
|
type: "sqlite"
|
||||||
@@ -31,17 +24,6 @@ mysql:
|
|||||||
password: ""
|
password: ""
|
||||||
addr: ""
|
addr: ""
|
||||||
dbname: ""
|
dbname: ""
|
||||||
tls: "false" # true / false / skip-verify / custom
|
|
||||||
|
|
||||||
postgresql:
|
|
||||||
host: "127.0.0.1"
|
|
||||||
port: "5432"
|
|
||||||
user: ""
|
|
||||||
password: ""
|
|
||||||
dbname: "postgres"
|
|
||||||
sslmode: "disable" # disable, require, verify-ca, verify-full
|
|
||||||
time-zone: "Asia/Shanghai" # Time zone for PostgreSQL connection
|
|
||||||
|
|
||||||
rustdesk:
|
rustdesk:
|
||||||
id-server: "192.168.1.66:21116"
|
id-server: "192.168.1.66:21116"
|
||||||
relay-server: "192.168.1.66:21117"
|
relay-server: "192.168.1.66:21117"
|
||||||
@@ -81,4 +63,22 @@ ldap:
|
|||||||
last-name: "sn"
|
last-name: "sn"
|
||||||
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
|
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
|
||||||
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
|
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
|
||||||
allow-group: "cn=users,dc=example,dc=com" # The group name of the users group, if the user is in this group, the user will be an login.
|
|
||||||
|
redis:
|
||||||
|
addr: "127.0.0.1:6379"
|
||||||
|
password: ""
|
||||||
|
db: 0
|
||||||
|
cache:
|
||||||
|
type: "file"
|
||||||
|
file-dir: "./runtime/cache"
|
||||||
|
redis-addr: "127.0.0.1:6379"
|
||||||
|
redis-pwd: ""
|
||||||
|
redis-db: 0
|
||||||
|
oss:
|
||||||
|
access-key-id: ""
|
||||||
|
access-key-secret: ""
|
||||||
|
host: ""
|
||||||
|
callback-url: ""
|
||||||
|
expire-time: 30
|
||||||
|
max-byte: 10240
|
||||||
|
|
||||||
|
|||||||
+28
-43
@@ -14,51 +14,36 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
WebClient int `mapstructure:"web-client"`
|
WebClient int `mapstructure:"web-client"`
|
||||||
Register bool `mapstructure:"register"`
|
Register bool `mapstructure:"register"`
|
||||||
RegisterStatus int `mapstructure:"register-status"`
|
ShowSwagger int `mapstructure:"show-swagger"`
|
||||||
ShowSwagger int `mapstructure:"show-swagger"`
|
TokenExpire time.Duration `mapstructure:"token-expire"`
|
||||||
TokenExpire time.Duration `mapstructure:"token-expire"`
|
WebSso bool `mapstructure:"web-sso"`
|
||||||
WebSso bool `mapstructure:"web-sso"`
|
DisablePwdLogin bool `mapstructure:"disable-pwd-login"`
|
||||||
DisablePwdLogin bool `mapstructure:"disable-pwd-login"`
|
|
||||||
CaptchaThreshold int `mapstructure:"captcha-threshold"`
|
|
||||||
BanThreshold int `mapstructure:"ban-threshold"`
|
|
||||||
}
|
}
|
||||||
type Admin struct {
|
type Admin struct {
|
||||||
Title string `mapstructure:"title"`
|
Title string `mapstructure:"title"`
|
||||||
Hello string `mapstructure:"hello"`
|
Hello string `mapstructure:"hello"`
|
||||||
HelloFile string `mapstructure:"hello-file"`
|
HelloFile string `mapstructure:"hello-file"`
|
||||||
IdServerPort int `mapstructure:"id-server-port"`
|
|
||||||
RelayServerPort int `mapstructure:"relay-server-port"`
|
|
||||||
}
|
}
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Lang string `mapstructure:"lang"`
|
Lang string `mapstructure:"lang"`
|
||||||
App App
|
App App
|
||||||
Admin Admin
|
Admin Admin
|
||||||
Gorm Gorm
|
Gorm Gorm
|
||||||
Mysql Mysql
|
Mysql Mysql
|
||||||
Postgresql Postgresql
|
Gin Gin
|
||||||
Gin Gin
|
Logger Logger
|
||||||
Logger Logger
|
Redis Redis
|
||||||
Redis Redis
|
Cache Cache
|
||||||
Cache Cache
|
Oss Oss
|
||||||
Oss Oss
|
Jwt Jwt
|
||||||
Jwt Jwt
|
Rustdesk Rustdesk
|
||||||
Rustdesk Rustdesk
|
Proxy Proxy
|
||||||
Proxy Proxy
|
Ldap Ldap
|
||||||
Ldap Ldap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Admin) Init() {
|
// Init 初始化配置
|
||||||
if a.IdServerPort == 0 {
|
|
||||||
a.IdServerPort = DefaultIdServerPort
|
|
||||||
}
|
|
||||||
if a.RelayServerPort == 0 {
|
|
||||||
a.RelayServerPort = DefaultRelayServerPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init initializes the configuration
|
|
||||||
func Init(rowVal *Config, path string) *viper.Viper {
|
func Init(rowVal *Config, path string) *viper.Viper {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
path = DefaultConfig
|
path = DefaultConfig
|
||||||
@@ -77,9 +62,9 @@ func Init(rowVal *Config, path string) *viper.Viper {
|
|||||||
v.WatchConfig()
|
v.WatchConfig()
|
||||||
|
|
||||||
|
|
||||||
// watching for config changes is not really necessary
|
//监听配置修改没什么必要
|
||||||
v.OnConfigChange(func(e fsnotify.Event) {
|
v.OnConfigChange(func(e fsnotify.Event) {
|
||||||
// watch for config file changes
|
//配置文件修改监听
|
||||||
fmt.Println("config file changed:", e.Name)
|
fmt.Println("config file changed:", e.Name)
|
||||||
if err2 := v.Unmarshal(rowVal); err2 != nil {
|
if err2 := v.Unmarshal(rowVal); err2 != nil {
|
||||||
fmt.Println(err2)
|
fmt.Println(err2)
|
||||||
@@ -92,11 +77,11 @@ func Init(rowVal *Config, path string) *viper.Viper {
|
|||||||
panic(fmt.Errorf("Fatal error config: %s \n", err))
|
panic(fmt.Errorf("Fatal error config: %s \n", err))
|
||||||
}
|
}
|
||||||
rowVal.Rustdesk.LoadKeyFile()
|
rowVal.Rustdesk.LoadKeyFile()
|
||||||
rowVal.Admin.Init()
|
rowVal.Rustdesk.ParsePort()
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadEnv reads environment variables
|
// ReadEnv 读取环境变量
|
||||||
func ReadEnv(rowVal interface{}) *viper.Viper {
|
func ReadEnv(rowVal interface{}) *viper.Viper {
|
||||||
v := viper.New()
|
v := viper.New()
|
||||||
v.AutomaticEnv()
|
v.AutomaticEnv()
|
||||||
|
|||||||
+2
-14
@@ -1,9 +1,8 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TypeSqlite = "sqlite"
|
TypeSqlite = "sqlite"
|
||||||
TypeMysql = "mysql"
|
TypeMysql = "mysql"
|
||||||
TypePostgresql = "postgresql"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Gorm struct {
|
type Gorm struct {
|
||||||
@@ -17,15 +16,4 @@ type Mysql struct {
|
|||||||
Username string `mapstructure:"username"`
|
Username string `mapstructure:"username"`
|
||||||
Password string `mapstructure:"password"`
|
Password string `mapstructure:"password"`
|
||||||
Dbname string `mapstructure:"dbname"`
|
Dbname string `mapstructure:"dbname"`
|
||||||
Tls string `mapstructure:"tls"` // true / false / skip-verify / custom
|
|
||||||
}
|
|
||||||
|
|
||||||
type Postgresql struct {
|
|
||||||
Host string `mapstructure:"host"`
|
|
||||||
Port string `mapstructure:"port"`
|
|
||||||
User string `mapstructure:"user"`
|
|
||||||
Password string `mapstructure:"password"`
|
|
||||||
Dbname string `mapstructure:"dbname"`
|
|
||||||
Sslmode string `mapstructure:"sslmode"` // "disable", "require", "verify-ca", "verify-full"
|
|
||||||
TimeZone string `mapstructure:"time-zone"` // e.g., "Asia/Shanghai"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ type LdapUser struct {
|
|||||||
LastName string `mapstructure:"last-name"`
|
LastName string `mapstructure:"last-name"`
|
||||||
Sync bool `mapstructure:"sync"` // Will sync the user's information to the internal database
|
Sync bool `mapstructure:"sync"` // Will sync the user's information to the internal database
|
||||||
AdminGroup string `mapstructure:"admin-group"` // Which group is the admin group
|
AdminGroup string `mapstructure:"admin-group"` // Which group is the admin group
|
||||||
AllowGroup string `mapstructure:"allow-group"` // Which group is allowed to login
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type LdapGroup struct {
|
// type LdapGroup struct {
|
||||||
|
|||||||
+3
-5
@@ -3,20 +3,18 @@ package config
|
|||||||
type GithubOauth struct {
|
type GithubOauth struct {
|
||||||
ClientId string `mapstructure:"client-id"`
|
ClientId string `mapstructure:"client-id"`
|
||||||
ClientSecret string `mapstructure:"client-secret"`
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
|
RedirectUrl string `mapstructure:"redirect-url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GoogleOauth struct {
|
type GoogleOauth struct {
|
||||||
ClientId string `mapstructure:"client-id"`
|
ClientId string `mapstructure:"client-id"`
|
||||||
ClientSecret string `mapstructure:"client-secret"`
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
|
RedirectUrl string `mapstructure:"redirect-url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OidcOauth struct {
|
type OidcOauth struct {
|
||||||
Issuer string `mapstructure:"issuer"`
|
Issuer string `mapstructure:"issuer"`
|
||||||
ClientId string `mapstructure:"client-id"`
|
ClientId string `mapstructure:"client-id"`
|
||||||
ClientSecret string `mapstructure:"client-secret"`
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
}
|
RedirectUrl string `mapstructure:"redirect-url"`
|
||||||
|
|
||||||
type LinuxdoOauth struct {
|
|
||||||
ClientId string `mapstructure:"client-id"`
|
|
||||||
ClientSecret string `mapstructure:"client-secret"`
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -38,3 +40,19 @@ func (rd *Rustdesk) LoadKeyFile() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (rd *Rustdesk) ParsePort() {
|
||||||
|
// Parse port
|
||||||
|
idres := strings.Split(rd.IdServer, ":")
|
||||||
|
if len(idres) == 1 {
|
||||||
|
rd.IdServerPort = DefaultIdServerPort
|
||||||
|
} else if len(idres) == 2 {
|
||||||
|
rd.IdServerPort, _ = strconv.Atoi(idres[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
relayres := strings.Split(rd.RelayServer, ":")
|
||||||
|
if len(relayres) == 1 {
|
||||||
|
rd.RelayServerPort = DefaultRelayServerPort
|
||||||
|
} else if len(relayres) == 2 {
|
||||||
|
rd.RelayServerPort, _ = strconv.Atoi(relayres[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ services:
|
|||||||
dockerfile: Dockerfile.dev
|
dockerfile: Dockerfile.dev
|
||||||
args:
|
args:
|
||||||
COUNTRY: CN
|
COUNTRY: CN
|
||||||
FRONTEND_GIT_REPO: https://github.com/lejianwen/rustdesk-api-web.git
|
FREONTEND_GIT_REPO: https://github.com/lejianwen/rustdesk-api-web.git
|
||||||
FRONTEND_GIT_BRANCH: master
|
FRONTEND_GIT_BRANCH: master
|
||||||
# image: lejianwen/rustdesk-api
|
# image: lejianwen/rustdesk-api
|
||||||
container_name: rustdesk-api
|
container_name: rustdesk-api
|
||||||
@@ -18,7 +18,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 21114:21114
|
- 21114:21114
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/rustdesk/api:/app/data #mount the database out for easy backup
|
- ./data/rustdesk/api:/app/data #将数据库挂载出来方便备份
|
||||||
- ./conf:/app/conf # config
|
- ./conf:/app/conf # config
|
||||||
# - ./resources:/app/resources # static resources
|
# - ./resources:/app/resources # 静态资源
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
+1
-1
@@ -13,5 +13,5 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./data/rustdesk/api:/app/data # database
|
- ./data/rustdesk/api:/app/data # database
|
||||||
# - ./conf:/app/conf # config
|
# - ./conf:/app/conf # config
|
||||||
# - ./resources:/app/resources # static resources
|
# - ./resources:/app/resources # 静态资源
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
# RustDesk full stack (server + relay + API/Web Admin) — self-contained example.
|
|
||||||
#
|
|
||||||
# Copy to docker-compose.yml and adjust the public IP / keys / secrets:
|
|
||||||
# cp docker-compose.yml.example docker-compose.yml
|
|
||||||
#
|
|
||||||
# Everything is inline (no .env). The Ed25519 key below is an EXAMPLE — generate
|
|
||||||
# your own for production. The two keys belong together:
|
|
||||||
# - hbbs/hbbr get the SECRET key via -k
|
|
||||||
# - rustdesk-api gets the matching PUBLIC key via RUSTDESK_API_RUSTDESK_KEY
|
|
||||||
# (the public key is also what clients see as their "Key").
|
|
||||||
|
|
||||||
services:
|
|
||||||
hbbs:
|
|
||||||
container_name: hbbs
|
|
||||||
image: rustdesk/rustdesk-server:latest
|
|
||||||
command: hbbs -r 194.164.204.114:21117 -k 1jqLELJaIjaRtt1Tcj6BhqJ7DhT9WszBH/XUHrqJdhdg4K98HmANQFOpUx/vPZFRWnHPTYYHyIB8uH3Xxr8PTw==
|
|
||||||
environment:
|
|
||||||
- TZ=Europe/Berlin
|
|
||||||
- ENCRYPTED_ONLY=1
|
|
||||||
- MUST_LOGIN=Y
|
|
||||||
volumes:
|
|
||||||
- ./data/server:/root
|
|
||||||
ports:
|
|
||||||
- "21115:21115"
|
|
||||||
- "21116:21116"
|
|
||||||
- "21116:21116/udp"
|
|
||||||
- "21118:21118"
|
|
||||||
depends_on:
|
|
||||||
- hbbr
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
hbbr:
|
|
||||||
container_name: hbbr
|
|
||||||
image: rustdesk/rustdesk-server:latest
|
|
||||||
command: hbbr -k 1jqLELJaIjaRtt1Tcj6BhqJ7DhT9WszBH/XUHrqJdhdg4K98HmANQFOpUx/vPZFRWnHPTYYHyIB8uH3Xxr8PTw==
|
|
||||||
environment:
|
|
||||||
- TZ=Europe/Berlin
|
|
||||||
volumes:
|
|
||||||
- ./data/server:/root
|
|
||||||
ports:
|
|
||||||
- "21117:21117"
|
|
||||||
- "21119:21119"
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
rustdesk-api:
|
|
||||||
container_name: rustdesk-api
|
|
||||||
image: git.hackner.dev/thomas/rustdesk-api:latest
|
|
||||||
command: ["./apimain"]
|
|
||||||
environment:
|
|
||||||
- TZ=Europe/Berlin
|
|
||||||
- RUSTDESK_API_LANG=en
|
|
||||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=194.164.204.114:21116
|
|
||||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=194.164.204.114:21117
|
|
||||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://194.164.204.114:21114
|
|
||||||
- RUSTDESK_API_RUSTDESK_KEY=YOCvfB5gDUBTqVMf7z2RUVpxz02GB8iAfLh918a/D08=
|
|
||||||
- RUSTDESK_API_JWT_KEY=z5rt4z465rtzdh5sudtuzrutd66zz6
|
|
||||||
ports:
|
|
||||||
- "21114:21114"
|
|
||||||
volumes:
|
|
||||||
- ./api:/app/data
|
|
||||||
depends_on:
|
|
||||||
- hbbs
|
|
||||||
- hbbr
|
|
||||||
restart: unless-stopped
|
|
||||||
+436
-432
File diff suppressed because it is too large
Load Diff
+437
-433
File diff suppressed because it is too large
Load Diff
+434
-431
File diff suppressed because it is too large
Load Diff
+137
-166
@@ -17,7 +17,7 @@ const docTemplateapi = `{
|
|||||||
"paths": {
|
"paths": {
|
||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "home",
|
"description": "首页",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -25,9 +25,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"home"
|
"首页"
|
||||||
],
|
],
|
||||||
"summary": "home",
|
"summary": "首页",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -51,7 +51,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "address list",
|
"description": "地址列表",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -59,9 +59,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address"
|
"地址"
|
||||||
],
|
],
|
||||||
"summary": "address list",
|
"summary": "地址列表",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -83,7 +83,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "address update",
|
"description": "地址更新",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -91,12 +91,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address"
|
"地址"
|
||||||
],
|
],
|
||||||
"summary": "address update",
|
"summary": "地址更新",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "address form",
|
"description": "地址表单",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -128,7 +128,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "add address",
|
"description": "添加地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -136,9 +136,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "add address",
|
"summary": "添加地址",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -169,7 +169,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "delete address",
|
"description": "删除地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -177,9 +177,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "delete address",
|
"summary": "删除地址",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -212,7 +212,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "update address",
|
"description": "更新地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -220,9 +220,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "update address",
|
"summary": "更新地址",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -255,7 +255,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "address",
|
"description": "地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -263,19 +263,19 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "address list",
|
"summary": "地址列表",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "current",
|
"name": "current",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -309,7 +309,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "personal address",
|
"description": "个人地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -317,9 +317,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "personal address",
|
"summary": "个人地址",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "string valid",
|
"description": "string valid",
|
||||||
@@ -353,7 +353,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "settings",
|
"description": "设置",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -361,9 +361,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "settings",
|
"summary": "设置",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "string valid",
|
"description": "string valid",
|
||||||
@@ -397,7 +397,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "shared",
|
"description": "共享",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -405,19 +405,19 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "shared address book",
|
"summary": "共享地址簿",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "current",
|
"name": "current",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
}
|
}
|
||||||
@@ -445,7 +445,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -453,9 +453,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "add tag",
|
"summary": "标签添加",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -488,7 +488,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -496,9 +496,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "rename tag",
|
"summary": "标签重命名",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -531,7 +531,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -539,9 +539,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "change tag color",
|
"summary": "标签修改颜色",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -574,7 +574,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -582,9 +582,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "delete tag",
|
"summary": "标签删除",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -617,7 +617,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -625,9 +625,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "tag",
|
"summary": "标签",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -655,7 +655,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/audit/conn": {
|
"/audit/conn": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "audit connection",
|
"description": "审计连接",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -663,12 +663,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"audit"
|
"审计"
|
||||||
],
|
],
|
||||||
"summary": "audit connection",
|
"summary": "审计连接",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "audit connection",
|
"description": "审计连接",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -695,7 +695,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/audit/file": {
|
"/audit/file": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "audit file",
|
"description": "审计文件",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -703,12 +703,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"audit"
|
"审计"
|
||||||
],
|
],
|
||||||
"summary": "audit file",
|
"summary": "审计文件",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "audit file",
|
"description": "审计文件",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -740,7 +740,7 @@ const docTemplateapi = `{
|
|||||||
"token": []
|
"token": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "user info",
|
"description": "用户信息",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -748,9 +748,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"user"
|
"用户"
|
||||||
],
|
],
|
||||||
"summary": "user info",
|
"summary": "用户信息",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -774,7 +774,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "machine",
|
"description": "机器",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -782,25 +782,25 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"group"
|
"群组"
|
||||||
],
|
],
|
||||||
"summary": "device",
|
"summary": "设备",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "status",
|
"description": "状态",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -829,7 +829,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/heartbeat": {
|
"/heartbeat": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "heartbeat",
|
"description": "心跳",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -837,9 +837,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"home"
|
"首页"
|
||||||
],
|
],
|
||||||
"summary": "heartbeat",
|
"summary": "心跳",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK"
|
"description": "OK"
|
||||||
@@ -855,7 +855,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/login": {
|
"/login": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "login",
|
"description": "登录",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -863,12 +863,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"login"
|
"登录"
|
||||||
],
|
],
|
||||||
"summary": "login",
|
"summary": "登录",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "login form",
|
"description": "登录表单",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -895,7 +895,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/login-options": {
|
"/login-options": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "login options",
|
"description": "登录选项",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -903,9 +903,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"login"
|
"登录"
|
||||||
],
|
],
|
||||||
"summary": "login options",
|
"summary": "登录选项",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -927,7 +927,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/logout": {
|
"/logout": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "logout",
|
"description": "登出",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -935,9 +935,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"login"
|
"登录"
|
||||||
],
|
],
|
||||||
"summary": "logout",
|
"summary": "登出",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -954,6 +954,35 @@ const docTemplateapi = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/oauth/callback": {
|
||||||
|
"get": {
|
||||||
|
"description": "OauthCallback",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Oauth"
|
||||||
|
],
|
||||||
|
"summary": "OauthCallback",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.LoginRes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.ErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/oidc/auth": {
|
"/oidc/auth": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "OidcAuth",
|
"description": "OidcAuth",
|
||||||
@@ -1012,35 +1041,6 @@ const docTemplateapi = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/oidc/callback": {
|
|
||||||
"get": {
|
|
||||||
"description": "OauthCallback",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Oauth"
|
|
||||||
],
|
|
||||||
"summary": "OauthCallback",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/api.LoginRes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/response.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/peers": {
|
"/peers": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -1048,7 +1048,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "machine",
|
"description": "机器",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1056,25 +1056,25 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"group"
|
"群组"
|
||||||
],
|
],
|
||||||
"summary": "machine",
|
"summary": "机器",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "status",
|
"description": "状态",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -1108,7 +1108,7 @@ const docTemplateapi = `{
|
|||||||
"token": []
|
"token": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "service config, provides an api-server for the webclient",
|
"description": "服务配置,给webclient提供api-server",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1118,7 +1118,7 @@ const docTemplateapi = `{
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT"
|
"WEBCLIENT"
|
||||||
],
|
],
|
||||||
"summary": "service config",
|
"summary": "服务配置",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1142,7 +1142,7 @@ const docTemplateapi = `{
|
|||||||
"token": []
|
"token": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "service config, provides an api-server for the webclient",
|
"description": "服务配置,给webclient提供api-server",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1152,7 +1152,7 @@ const docTemplateapi = `{
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT_V2"
|
"WEBCLIENT_V2"
|
||||||
],
|
],
|
||||||
"summary": "service config",
|
"summary": "服务配置",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1171,7 +1171,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/shared-peer": {
|
"/shared-peer": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "shared peer",
|
"description": "分享的peer",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1181,7 +1181,7 @@ const docTemplateapi = `{
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT"
|
"WEBCLIENT"
|
||||||
],
|
],
|
||||||
"summary": "shared peer",
|
"summary": "分享的peer",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1200,7 +1200,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/sysinfo": {
|
"/sysinfo": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "submit system info",
|
"description": "提交系统信息",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1208,12 +1208,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"System"
|
"地址"
|
||||||
],
|
],
|
||||||
"summary": "submit system info",
|
"summary": "提交系统信息",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "system info form",
|
"description": "系统信息表单",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -1238,35 +1238,6 @@ const docTemplateapi = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/sysinfo_ver": {
|
|
||||||
"post": {
|
|
||||||
"description": "get system version info",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"System"
|
|
||||||
],
|
|
||||||
"summary": "get system version info",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/response.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/users": {
|
"/users": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -1274,7 +1245,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "user list",
|
"description": "用户列表",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1282,25 +1253,25 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"group"
|
"群组"
|
||||||
],
|
],
|
||||||
"summary": "user list",
|
"summary": "用户列表",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "status",
|
"description": "状态",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -1344,7 +1315,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/version": {
|
"/version": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "version",
|
"description": "版本",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1352,9 +1323,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"home"
|
"首页"
|
||||||
],
|
],
|
||||||
"summary": "version",
|
"summary": "版本",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1593,7 +1564,7 @@ const docTemplateapi = `{
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"color": {
|
"color": {
|
||||||
"description": "color is flutter's color value,from 0x00000000 to 0xFFFFFFFF; the first two digits represent transparency, the following 6 digits represent the color, can be converted to rgba",
|
"description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度,后面6位表示颜色, 可以转成rgba",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
@@ -1683,8 +1654,8 @@ var SwaggerInfoapi = &swag.Spec{
|
|||||||
Host: "",
|
Host: "",
|
||||||
BasePath: "/api",
|
BasePath: "/api",
|
||||||
Schemes: []string{},
|
Schemes: []string{},
|
||||||
Title: "management systemAPI",
|
Title: "管理系统API",
|
||||||
Description: "API",
|
Description: "接口",
|
||||||
InfoInstanceName: "api",
|
InfoInstanceName: "api",
|
||||||
SwaggerTemplate: docTemplateapi,
|
SwaggerTemplate: docTemplateapi,
|
||||||
LeftDelim: "{{",
|
LeftDelim: "{{",
|
||||||
|
|||||||
+137
-166
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"swagger": "2.0",
|
"swagger": "2.0",
|
||||||
"info": {
|
"info": {
|
||||||
"description": "API",
|
"description": "接口",
|
||||||
"title": "management systemAPI",
|
"title": "管理系统API",
|
||||||
"contact": {},
|
"contact": {},
|
||||||
"version": "1.0"
|
"version": "1.0"
|
||||||
},
|
},
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "home",
|
"description": "首页",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -18,9 +18,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"home"
|
"首页"
|
||||||
],
|
],
|
||||||
"summary": "home",
|
"summary": "首页",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "address list",
|
"description": "地址列表",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -52,9 +52,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address"
|
"地址"
|
||||||
],
|
],
|
||||||
"summary": "address list",
|
"summary": "地址列表",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "address update",
|
"description": "地址更新",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -84,12 +84,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address"
|
"地址"
|
||||||
],
|
],
|
||||||
"summary": "address update",
|
"summary": "地址更新",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "address form",
|
"description": "地址表单",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "add address",
|
"description": "添加地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -129,9 +129,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "add address",
|
"summary": "添加地址",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "delete address",
|
"description": "删除地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -170,9 +170,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "delete address",
|
"summary": "删除地址",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -205,7 +205,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "update address",
|
"description": "更新地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -213,9 +213,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "update address",
|
"summary": "更新地址",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -248,7 +248,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "address",
|
"description": "地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -256,19 +256,19 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "address list",
|
"summary": "地址列表",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "current",
|
"name": "current",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "personal address",
|
"description": "个人地址",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -310,9 +310,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "personal address",
|
"summary": "个人地址",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "string valid",
|
"description": "string valid",
|
||||||
@@ -346,7 +346,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "settings",
|
"description": "设置",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -354,9 +354,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "settings",
|
"summary": "设置",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "string valid",
|
"description": "string valid",
|
||||||
@@ -390,7 +390,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "shared",
|
"description": "共享",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -398,19 +398,19 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "shared address book",
|
"summary": "共享地址簿",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "current",
|
"name": "current",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
}
|
}
|
||||||
@@ -438,7 +438,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -446,9 +446,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "add tag",
|
"summary": "标签添加",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -481,7 +481,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -489,9 +489,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "rename tag",
|
"summary": "标签重命名",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -524,7 +524,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -532,9 +532,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "change tag color",
|
"summary": "标签修改颜色",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -567,7 +567,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -575,9 +575,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "delete tag",
|
"summary": "标签删除",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -610,7 +610,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "tag",
|
"description": "标签",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -618,9 +618,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"address[Personal]"
|
"地址[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "tag",
|
"summary": "标签",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -648,7 +648,7 @@
|
|||||||
},
|
},
|
||||||
"/audit/conn": {
|
"/audit/conn": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "audit connection",
|
"description": "审计连接",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -656,12 +656,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"audit"
|
"审计"
|
||||||
],
|
],
|
||||||
"summary": "audit connection",
|
"summary": "审计连接",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "audit connection",
|
"description": "审计连接",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -688,7 +688,7 @@
|
|||||||
},
|
},
|
||||||
"/audit/file": {
|
"/audit/file": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "audit file",
|
"description": "审计文件",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -696,12 +696,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"audit"
|
"审计"
|
||||||
],
|
],
|
||||||
"summary": "audit file",
|
"summary": "审计文件",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "audit file",
|
"description": "审计文件",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -733,7 +733,7 @@
|
|||||||
"token": []
|
"token": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "user info",
|
"description": "用户信息",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -741,9 +741,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"user"
|
"用户"
|
||||||
],
|
],
|
||||||
"summary": "user info",
|
"summary": "用户信息",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -767,7 +767,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "machine",
|
"description": "机器",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -775,25 +775,25 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"group"
|
"群组"
|
||||||
],
|
],
|
||||||
"summary": "device",
|
"summary": "设备",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "status",
|
"description": "状态",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -822,7 +822,7 @@
|
|||||||
},
|
},
|
||||||
"/heartbeat": {
|
"/heartbeat": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "heartbeat",
|
"description": "心跳",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -830,9 +830,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"home"
|
"首页"
|
||||||
],
|
],
|
||||||
"summary": "heartbeat",
|
"summary": "心跳",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK"
|
"description": "OK"
|
||||||
@@ -848,7 +848,7 @@
|
|||||||
},
|
},
|
||||||
"/login": {
|
"/login": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "login",
|
"description": "登录",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -856,12 +856,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"login"
|
"登录"
|
||||||
],
|
],
|
||||||
"summary": "login",
|
"summary": "登录",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "login form",
|
"description": "登录表单",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -888,7 +888,7 @@
|
|||||||
},
|
},
|
||||||
"/login-options": {
|
"/login-options": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "login options",
|
"description": "登录选项",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -896,9 +896,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"login"
|
"登录"
|
||||||
],
|
],
|
||||||
"summary": "login options",
|
"summary": "登录选项",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -920,7 +920,7 @@
|
|||||||
},
|
},
|
||||||
"/logout": {
|
"/logout": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "logout",
|
"description": "登出",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -928,9 +928,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"login"
|
"登录"
|
||||||
],
|
],
|
||||||
"summary": "logout",
|
"summary": "登出",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -947,6 +947,35 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/oauth/callback": {
|
||||||
|
"get": {
|
||||||
|
"description": "OauthCallback",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Oauth"
|
||||||
|
],
|
||||||
|
"summary": "OauthCallback",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.LoginRes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.ErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/oidc/auth": {
|
"/oidc/auth": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "OidcAuth",
|
"description": "OidcAuth",
|
||||||
@@ -1005,35 +1034,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/oidc/callback": {
|
|
||||||
"get": {
|
|
||||||
"description": "OauthCallback",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Oauth"
|
|
||||||
],
|
|
||||||
"summary": "OauthCallback",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/api.LoginRes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/response.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/peers": {
|
"/peers": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -1041,7 +1041,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "machine",
|
"description": "机器",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1049,25 +1049,25 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"group"
|
"群组"
|
||||||
],
|
],
|
||||||
"summary": "machine",
|
"summary": "机器",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "status",
|
"description": "状态",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -1101,7 +1101,7 @@
|
|||||||
"token": []
|
"token": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "service config, provides an api-server for the webclient",
|
"description": "服务配置,给webclient提供api-server",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1111,7 +1111,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT"
|
"WEBCLIENT"
|
||||||
],
|
],
|
||||||
"summary": "service config",
|
"summary": "服务配置",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1135,7 +1135,7 @@
|
|||||||
"token": []
|
"token": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "service config, provides an api-server for the webclient",
|
"description": "服务配置,给webclient提供api-server",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1145,7 +1145,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT_V2"
|
"WEBCLIENT_V2"
|
||||||
],
|
],
|
||||||
"summary": "service config",
|
"summary": "服务配置",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1164,7 +1164,7 @@
|
|||||||
},
|
},
|
||||||
"/shared-peer": {
|
"/shared-peer": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "shared peer",
|
"description": "分享的peer",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1174,7 +1174,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT"
|
"WEBCLIENT"
|
||||||
],
|
],
|
||||||
"summary": "shared peer",
|
"summary": "分享的peer",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1193,7 +1193,7 @@
|
|||||||
},
|
},
|
||||||
"/sysinfo": {
|
"/sysinfo": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "submit system info",
|
"description": "提交系统信息",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1201,12 +1201,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"System"
|
"地址"
|
||||||
],
|
],
|
||||||
"summary": "submit system info",
|
"summary": "提交系统信息",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "system info form",
|
"description": "系统信息表单",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -1231,35 +1231,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/sysinfo_ver": {
|
|
||||||
"post": {
|
|
||||||
"description": "get system version info",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"System"
|
|
||||||
],
|
|
||||||
"summary": "get system version info",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/response.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/users": {
|
"/users": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -1267,7 +1238,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "user list",
|
"description": "用户列表",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1275,25 +1246,25 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"group"
|
"群组"
|
||||||
],
|
],
|
||||||
"summary": "user list",
|
"summary": "用户列表",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number",
|
"description": "页码",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "items per page",
|
"description": "每页数量",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "status",
|
"description": "状态",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -1337,7 +1308,7 @@
|
|||||||
},
|
},
|
||||||
"/version": {
|
"/version": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "version",
|
"description": "版本",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1345,9 +1316,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"home"
|
"首页"
|
||||||
],
|
],
|
||||||
"summary": "version",
|
"summary": "版本",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1586,7 +1557,7 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"color": {
|
"color": {
|
||||||
"description": "color is flutter's color value,from 0x00000000 to 0xFFFFFFFF; the first two digits represent transparency, the following 6 digits represent the color, can be converted to rgba",
|
"description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度,后面6位表示颜色, 可以转成rgba",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
|
|||||||
+128
-147
@@ -146,8 +146,8 @@ definitions:
|
|||||||
collection_id:
|
collection_id:
|
||||||
type: integer
|
type: integer
|
||||||
color:
|
color:
|
||||||
description: color is flutter's color value,from 0x00000000 to 0xFFFFFFFF; the first two digits represent transparency, the following 6 digits represent the color,
|
description: color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度,后面6位表示颜色,
|
||||||
can be converted to rgba
|
可以转成rgba
|
||||||
type: integer
|
type: integer
|
||||||
created_at:
|
created_at:
|
||||||
type: string
|
type: string
|
||||||
@@ -194,15 +194,15 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
info:
|
info:
|
||||||
contact: {}
|
contact: {}
|
||||||
description: API
|
description: 接口
|
||||||
title: management systemAPI
|
title: 管理系统API
|
||||||
version: "1.0"
|
version: "1.0"
|
||||||
paths:
|
paths:
|
||||||
/:
|
/:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: home
|
description: 首页
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -214,14 +214,14 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: home
|
summary: 首页
|
||||||
tags:
|
tags:
|
||||||
- home
|
- 首页
|
||||||
/ab:
|
/ab:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: address list
|
description: 地址列表
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -235,15 +235,15 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: address list
|
summary: 地址列表
|
||||||
tags:
|
tags:
|
||||||
- address
|
- 地址
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: address update
|
description: 地址更新
|
||||||
parameters:
|
parameters:
|
||||||
- description: address form
|
- description: 地址表单
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -262,14 +262,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: address update
|
summary: 地址更新
|
||||||
tags:
|
tags:
|
||||||
- address
|
- 地址
|
||||||
/ab/peer/add/{guid}:
|
/ab/peer/add/{guid}:
|
||||||
delete:
|
delete:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: delete address
|
description: 删除地址
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -289,13 +289,13 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: delete address
|
summary: 删除地址
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: add address
|
description: 添加地址
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -315,14 +315,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: add address
|
summary: 添加地址
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/peer/update/{guid}:
|
/ab/peer/update/{guid}:
|
||||||
put:
|
put:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: update address
|
description: 更新地址
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -342,20 +342,20 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: update address
|
summary: 更新地址
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/peers:
|
/ab/peers:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: address
|
description: 地址
|
||||||
parameters:
|
parameters:
|
||||||
- description: page number
|
- description: 页码
|
||||||
in: query
|
in: query
|
||||||
name: current
|
name: current
|
||||||
type: integer
|
type: integer
|
||||||
- description: items per page
|
- description: 每页数量
|
||||||
in: query
|
in: query
|
||||||
name: pageSize
|
name: pageSize
|
||||||
type: integer
|
type: integer
|
||||||
@@ -376,14 +376,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: address list
|
summary: 地址列表
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/personal:
|
/ab/personal:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: personal address
|
description: 个人地址
|
||||||
parameters:
|
parameters:
|
||||||
- description: string valid
|
- description: string valid
|
||||||
in: body
|
in: body
|
||||||
@@ -403,14 +403,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: personal address
|
summary: 个人地址
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/settings:
|
/ab/settings:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: settings
|
description: 设置
|
||||||
parameters:
|
parameters:
|
||||||
- description: string valid
|
- description: string valid
|
||||||
in: body
|
in: body
|
||||||
@@ -430,20 +430,20 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: settings
|
summary: 设置
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/shared/profiles:
|
/ab/shared/profiles:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: shared
|
description: 共享
|
||||||
parameters:
|
parameters:
|
||||||
- description: page number
|
- description: 页码
|
||||||
in: query
|
in: query
|
||||||
name: current
|
name: current
|
||||||
type: integer
|
type: integer
|
||||||
- description: items per page
|
- description: 每页数量
|
||||||
in: query
|
in: query
|
||||||
name: pageSize
|
name: pageSize
|
||||||
type: integer
|
type: integer
|
||||||
@@ -460,14 +460,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: shared address book
|
summary: 共享地址簿
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/tag/{guid}:
|
/ab/tag/{guid}:
|
||||||
delete:
|
delete:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: tag
|
description: 标签
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -487,14 +487,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: delete tag
|
summary: 标签删除
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/tag/add/{guid}:
|
/ab/tag/add/{guid}:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: tag
|
description: 标签
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -514,14 +514,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: add tag
|
summary: 标签添加
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/tag/rename/{guid}:
|
/ab/tag/rename/{guid}:
|
||||||
put:
|
put:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: tag
|
description: 标签
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -541,14 +541,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: rename tag
|
summary: 标签重命名
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/tag/update/{guid}:
|
/ab/tag/update/{guid}:
|
||||||
put:
|
put:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: tag
|
description: 标签
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -568,14 +568,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: change tag color
|
summary: 标签修改颜色
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/ab/tags/{guid}:
|
/ab/tags/{guid}:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: tag
|
description: 标签
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -595,16 +595,16 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: tag
|
summary: 标签
|
||||||
tags:
|
tags:
|
||||||
- address[Personal]
|
- 地址[Personal]
|
||||||
/audit/conn:
|
/audit/conn:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: audit connection
|
description: 审计连接
|
||||||
parameters:
|
parameters:
|
||||||
- description: audit connection
|
- description: 审计连接
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -621,16 +621,16 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: audit connection
|
summary: 审计连接
|
||||||
tags:
|
tags:
|
||||||
- audit
|
- 审计
|
||||||
/audit/file:
|
/audit/file:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: audit file
|
description: 审计文件
|
||||||
parameters:
|
parameters:
|
||||||
- description: audit file
|
- description: 审计文件
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -647,14 +647,14 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: audit file
|
summary: 审计文件
|
||||||
tags:
|
tags:
|
||||||
- audit
|
- 审计
|
||||||
/currentUser:
|
/currentUser:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: user info
|
description: 用户信息
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -668,24 +668,24 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- token: []
|
- token: []
|
||||||
summary: user info
|
summary: 用户信息
|
||||||
tags:
|
tags:
|
||||||
- user
|
- 用户
|
||||||
/device-group/accessible:
|
/device-group/accessible:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: machine
|
description: 机器
|
||||||
parameters:
|
parameters:
|
||||||
- description: page number
|
- description: 页码
|
||||||
in: query
|
in: query
|
||||||
name: page
|
name: page
|
||||||
type: integer
|
type: integer
|
||||||
- description: items per page
|
- description: 每页数量
|
||||||
in: query
|
in: query
|
||||||
name: pageSize
|
name: pageSize
|
||||||
type: integer
|
type: integer
|
||||||
- description: status
|
- description: 状态
|
||||||
in: query
|
in: query
|
||||||
name: status
|
name: status
|
||||||
type: integer
|
type: integer
|
||||||
@@ -706,14 +706,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: device
|
summary: 设备
|
||||||
tags:
|
tags:
|
||||||
- group
|
- 群组
|
||||||
/heartbeat:
|
/heartbeat:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: heartbeat
|
description: 心跳
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -723,16 +723,16 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: heartbeat
|
summary: 心跳
|
||||||
tags:
|
tags:
|
||||||
- home
|
- 首页
|
||||||
/login:
|
/login:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: login
|
description: 登录
|
||||||
parameters:
|
parameters:
|
||||||
- description: login form
|
- description: 登录表单
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -749,14 +749,14 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
summary: login
|
summary: 登录
|
||||||
tags:
|
tags:
|
||||||
- login
|
- 登录
|
||||||
/login-options:
|
/login-options:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: login options
|
description: 登录选项
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -770,14 +770,14 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
summary: login options
|
summary: 登录选项
|
||||||
tags:
|
tags:
|
||||||
- login
|
- 登录
|
||||||
/logout:
|
/logout:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: logout
|
description: 登出
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -789,9 +789,28 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
summary: logout
|
summary: 登出
|
||||||
tags:
|
tags:
|
||||||
- login
|
- 登录
|
||||||
|
/oauth/callback:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: OauthCallback
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.LoginRes'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
|
summary: OauthCallback
|
||||||
|
tags:
|
||||||
|
- Oauth
|
||||||
/oidc/auth:
|
/oidc/auth:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
@@ -830,40 +849,21 @@ paths:
|
|||||||
summary: OidcAuthQuery
|
summary: OidcAuthQuery
|
||||||
tags:
|
tags:
|
||||||
- Oauth
|
- Oauth
|
||||||
/oidc/callback:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: OauthCallback
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/api.LoginRes'
|
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
|
||||||
summary: OauthCallback
|
|
||||||
tags:
|
|
||||||
- Oauth
|
|
||||||
/peers:
|
/peers:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: machine
|
description: 机器
|
||||||
parameters:
|
parameters:
|
||||||
- description: page number
|
- description: 页码
|
||||||
in: query
|
in: query
|
||||||
name: page
|
name: page
|
||||||
type: integer
|
type: integer
|
||||||
- description: items per page
|
- description: 每页数量
|
||||||
in: query
|
in: query
|
||||||
name: pageSize
|
name: pageSize
|
||||||
type: integer
|
type: integer
|
||||||
- description: status
|
- description: 状态
|
||||||
in: query
|
in: query
|
||||||
name: status
|
name: status
|
||||||
type: integer
|
type: integer
|
||||||
@@ -884,14 +884,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: machine
|
summary: 机器
|
||||||
tags:
|
tags:
|
||||||
- group
|
- 群组
|
||||||
/server-config:
|
/server-config:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: service config, provides an api-server for the webclient
|
description: 服务配置,给webclient提供api-server
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -905,14 +905,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- token: []
|
- token: []
|
||||||
summary: service config
|
summary: 服务配置
|
||||||
tags:
|
tags:
|
||||||
- WEBCLIENT
|
- WEBCLIENT
|
||||||
/server-config-v2:
|
/server-config-v2:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: service config, provides an api-server for the webclient
|
description: 服务配置,给webclient提供api-server
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -926,14 +926,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- token: []
|
- token: []
|
||||||
summary: service config
|
summary: 服务配置
|
||||||
tags:
|
tags:
|
||||||
- WEBCLIENT_V2
|
- WEBCLIENT_V2
|
||||||
/shared-peer:
|
/shared-peer:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: shared peer
|
description: 分享的peer
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -945,16 +945,16 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: shared peer
|
summary: 分享的peer
|
||||||
tags:
|
tags:
|
||||||
- WEBCLIENT
|
- WEBCLIENT
|
||||||
/sysinfo:
|
/sysinfo:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: submit system info
|
description: 提交系统信息
|
||||||
parameters:
|
parameters:
|
||||||
- description: system info form
|
- description: 系统信息表单
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -971,43 +971,24 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
summary: submit system info
|
summary: 提交系统信息
|
||||||
tags:
|
tags:
|
||||||
- System
|
- 地址
|
||||||
/sysinfo_ver:
|
|
||||||
post:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: get system version info
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
|
||||||
summary: get system version info
|
|
||||||
tags:
|
|
||||||
- System
|
|
||||||
/users:
|
/users:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: user list
|
description: 用户列表
|
||||||
parameters:
|
parameters:
|
||||||
- description: page number
|
- description: 页码
|
||||||
in: query
|
in: query
|
||||||
name: page
|
name: page
|
||||||
type: integer
|
type: integer
|
||||||
- description: items per page
|
- description: 每页数量
|
||||||
in: query
|
in: query
|
||||||
name: pageSize
|
name: pageSize
|
||||||
type: integer
|
type: integer
|
||||||
- description: status
|
- description: 状态
|
||||||
in: query
|
in: query
|
||||||
name: status
|
name: status
|
||||||
type: integer
|
type: integer
|
||||||
@@ -1035,14 +1016,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: user list
|
summary: 用户列表
|
||||||
tags:
|
tags:
|
||||||
- group
|
- 群组
|
||||||
/version:
|
/version:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: version
|
description: 版本
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -1054,9 +1035,9 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: version
|
summary: 版本
|
||||||
tags:
|
tags:
|
||||||
- home
|
- 首页
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
BearerAuth:
|
BearerAuth:
|
||||||
in: header
|
in: header
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import (
|
|||||||
en_translations "github.com/go-playground/validator/v10/translations/en"
|
en_translations "github.com/go-playground/validator/v10/translations/en"
|
||||||
es_translations "github.com/go-playground/validator/v10/translations/es"
|
es_translations "github.com/go-playground/validator/v10/translations/es"
|
||||||
fr_translations "github.com/go-playground/validator/v10/translations/fr"
|
fr_translations "github.com/go-playground/validator/v10/translations/fr"
|
||||||
ko_translations "github.com/go-playground/validator/v10/translations/ko"
|
|
||||||
ru_translations "github.com/go-playground/validator/v10/translations/ru"
|
ru_translations "github.com/go-playground/validator/v10/translations/ru"
|
||||||
zh_translations "github.com/go-playground/validator/v10/translations/zh"
|
zh_translations "github.com/go-playground/validator/v10/translations/zh"
|
||||||
zh_tw_translations "github.com/go-playground/validator/v10/translations/zh_tw"
|
zh_tw_translations "github.com/go-playground/validator/v10/translations/zh_tw"
|
||||||
@@ -24,7 +23,7 @@ import (
|
|||||||
func ApiInitValidator() {
|
func ApiInitValidator() {
|
||||||
validate := validator.New()
|
validate := validator.New()
|
||||||
|
|
||||||
// define translations for different languages
|
// 定义不同的语言翻译
|
||||||
enT := en.New()
|
enT := en.New()
|
||||||
cn := zh_Hans_CN.New()
|
cn := zh_Hans_CN.New()
|
||||||
koT := ko.New()
|
koT := ko.New()
|
||||||
@@ -52,7 +51,8 @@ func ApiInitValidator() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ko_translations.RegisterDefaultTranslations(validate, koTrans)
|
//validate没有ko的翻译,使用zh的翻译
|
||||||
|
err = zh_translations.RegisterDefaultTranslations(validate, koTrans)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ func ApiInitValidator() {
|
|||||||
return label
|
return label
|
||||||
})
|
})
|
||||||
Validator.Validate = validate
|
Validator.Validate = validate
|
||||||
Validator.UT = uni // store the Universal Translator
|
Validator.UT = uni // 存储 Universal Translator
|
||||||
Validator.VTrans = zhTrans
|
Validator.VTrans = zhTrans
|
||||||
|
|
||||||
Validator.ValidStruct = func(ctx *gin.Context, i interface{}) []string {
|
Validator.ValidStruct = func(ctx *gin.Context, i interface{}) []string {
|
||||||
|
|||||||
+4
-6
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/lejianwen/rustdesk-api/v2/lib/jwt"
|
"github.com/lejianwen/rustdesk-api/v2/lib/jwt"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/lib/lock"
|
"github.com/lejianwen/rustdesk-api/v2/lib/lock"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/lib/upload"
|
"github.com/lejianwen/rustdesk-api/v2/lib/upload"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@@ -32,9 +31,8 @@ var (
|
|||||||
ValidStruct func(*gin.Context, interface{}) []string
|
ValidStruct func(*gin.Context, interface{}) []string
|
||||||
ValidVar func(ctx *gin.Context, field interface{}, tag string) []string
|
ValidVar func(ctx *gin.Context, field interface{}, tag string) []string
|
||||||
}
|
}
|
||||||
Oss *upload.Oss
|
Oss *upload.Oss
|
||||||
Jwt *jwt.Jwt
|
Jwt *jwt.Jwt
|
||||||
Lock lock.Locker
|
Lock lock.Locker
|
||||||
Localizer func(lang string) *i18n.Localizer
|
Localizer func(lang string) *i18n.Localizer
|
||||||
LoginLimiter *utils.LoginLimiter
|
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-2
@@ -10,14 +10,14 @@ import (
|
|||||||
func InitI18n() {
|
func InitI18n() {
|
||||||
bundle := i18n.NewBundle(language.English)
|
bundle := i18n.NewBundle(language.English)
|
||||||
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
||||||
// read all language files under global.Config.Gin.ResourcesPath
|
//读取global.Config.Gin.ResourcesPath下的所有语言文件
|
||||||
dir := Config.Gin.ResourcesPath + "/i18n"
|
dir := Config.Gin.ResourcesPath + "/i18n"
|
||||||
fileInfos, err := os.ReadDir(dir)
|
fileInfos, err := os.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
for _, fileInfo := range fileInfos {
|
for _, fileInfo := range fileInfos {
|
||||||
// if the file name does not end with .toml
|
//如果文件名不是.toml结尾
|
||||||
if fileInfo.IsDir() || fileInfo.Name()[len(fileInfo.Name())-5:] != ".toml" {
|
if fileInfo.IsDir() || fileInfo.Name()[len(fileInfo.Name())-5:] != ".toml" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,19 @@
|
|||||||
module github.com/lejianwen/rustdesk-api/v2
|
module github.com/lejianwen/rustdesk-api/v2
|
||||||
|
|
||||||
go 1.23
|
go 1.22
|
||||||
|
|
||||||
toolchain go1.23.10
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.3.2
|
github.com/BurntSushi/toml v1.3.2
|
||||||
github.com/antonfisher/nested-logrus-formatter v1.3.1
|
github.com/antonfisher/nested-logrus-formatter v1.3.1
|
||||||
github.com/coreos/go-oidc/v3 v3.12.0
|
github.com/fsnotify/fsnotify v1.5.1
|
||||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
|
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
|
||||||
github.com/gin-gonic/gin v1.9.0
|
github.com/gin-gonic/gin v1.9.0
|
||||||
github.com/go-ldap/ldap/v3 v3.4.10
|
|
||||||
github.com/go-playground/locales v0.14.1
|
github.com/go-playground/locales v0.14.1
|
||||||
github.com/go-playground/universal-translator v0.18.1
|
github.com/go-playground/universal-translator v0.18.1
|
||||||
github.com/go-playground/validator/v10 v10.26.0
|
github.com/go-playground/validator/v10 v10.11.2
|
||||||
github.com/go-redis/redis/v8 v8.11.4
|
github.com/go-redis/redis/v8 v8.11.4
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/mojocn/base64Captcha v1.3.6
|
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
@@ -25,13 +21,11 @@ require (
|
|||||||
github.com/swaggo/files v1.0.1
|
github.com/swaggo/files v1.0.1
|
||||||
github.com/swaggo/gin-swagger v1.6.0
|
github.com/swaggo/gin-swagger v1.6.0
|
||||||
github.com/swaggo/swag v1.16.3
|
github.com/swaggo/swag v1.16.3
|
||||||
golang.org/x/crypto v0.33.0
|
|
||||||
golang.org/x/oauth2 v0.23.0
|
golang.org/x/oauth2 v0.23.0
|
||||||
golang.org/x/text v0.22.0
|
golang.org/x/text v0.21.0
|
||||||
gorm.io/driver/mysql v1.5.7
|
gorm.io/driver/mysql v1.5.7
|
||||||
gorm.io/driver/postgres v1.6.0
|
|
||||||
gorm.io/driver/sqlite v1.5.6
|
gorm.io/driver/sqlite v1.5.6
|
||||||
gorm.io/gorm v1.25.10
|
gorm.io/gorm v1.25.7
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -42,12 +36,12 @@ require (
|
|||||||
github.com/bytedance/sonic v1.8.0 // indirect
|
github.com/bytedance/sonic v1.8.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
github.com/coreos/go-oidc/v3 v3.12.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
||||||
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||||
|
github.com/go-ldap/ldap/v3 v3.4.10 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||||
github.com/go-openapi/spec v0.20.4 // indirect
|
github.com/go-openapi/spec v0.20.4 // indirect
|
||||||
@@ -57,16 +51,12 @@ require (
|
|||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
|
||||||
github.com/jackc/pgx/v5 v5.6.0 // indirect
|
|
||||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.2.1 // indirect
|
||||||
github.com/magiconair/properties v1.8.5 // indirect
|
github.com/magiconair/properties v1.8.5 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
@@ -74,9 +64,9 @@ require (
|
|||||||
github.com/mitchellh/mapstructure v1.4.2 // indirect
|
github.com/mitchellh/mapstructure v1.4.2 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/mojocn/base64Captcha v1.3.6 // indirect
|
||||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
|
||||||
github.com/spf13/afero v1.6.0 // indirect
|
github.com/spf13/afero v1.6.0 // indirect
|
||||||
github.com/spf13/cast v1.4.1 // indirect
|
github.com/spf13/cast v1.4.1 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
@@ -85,11 +75,11 @@ require (
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.9 // indirect
|
github.com/ugorji/go/codec v1.2.9 // indirect
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||||
|
golang.org/x/crypto v0.31.0 // indirect
|
||||||
golang.org/x/image v0.13.0 // indirect
|
golang.org/x/image v0.13.0 // indirect
|
||||||
golang.org/x/net v0.34.0 // indirect
|
golang.org/x/net v0.33.0 // indirect
|
||||||
golang.org/x/sync v0.11.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
golang.org/x/sys v0.30.0 // indirect
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||||
golang.org/x/tools v0.26.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.33.0 // indirect
|
google.golang.org/protobuf v1.33.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ import (
|
|||||||
type AddressBook struct {
|
type AddressBook struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail address book
|
// Detail 地址簿
|
||||||
// @Tags address book
|
// @Tags 地址簿
|
||||||
// @Summary address book details
|
// @Summary 地址簿详情
|
||||||
// @Description address book details
|
// @Description 地址簿详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -38,13 +38,13 @@ func (ct *AddressBook) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create address book
|
// Create 创建地址簿
|
||||||
// @Tags address book
|
// @Tags 地址簿
|
||||||
// @Summary create address book
|
// @Summary 创建地址簿
|
||||||
// @Description create address book
|
// @Description 创建地址簿
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "address book info"
|
// @Param body body admin.AddressBookForm true "地址簿信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBook}
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/create [post]
|
// @Router /admin/address_book/create [post]
|
||||||
@@ -84,13 +84,13 @@ func (ct *AddressBook) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchCreate batch create address books
|
// BatchCreate 批量创建地址簿
|
||||||
// @Tags address book
|
// @Tags 地址簿
|
||||||
// @Summary batch create address books
|
// @Summary 批量创建地址簿
|
||||||
// @Description batch create address books
|
// @Description 批量创建地址簿
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "address book info"
|
// @Param body body admin.AddressBookForm true "地址簿信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBook}
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/batchCreate [post]
|
// @Router /admin/address_book/batchCreate [post]
|
||||||
@@ -113,13 +113,13 @@ func (ct *AddressBook) BatchCreate(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ul > 1 {
|
if ul > 1 {
|
||||||
//clear tags in multi-user mode
|
//多用户置空标签
|
||||||
f.Tags = []string{}
|
f.Tags = []string{}
|
||||||
//in multi-user mode, can only create in the default address book
|
//多用户只能创建到默认地址簿
|
||||||
f.CollectionId = 0
|
f.CollectionId = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//create tag
|
//创建标签
|
||||||
/*for _, fu := range f.UserIds {
|
/*for _, fu := range f.UserIds {
|
||||||
if fu == 0 {
|
if fu == 0 {
|
||||||
continue
|
continue
|
||||||
@@ -148,16 +148,16 @@ func (ct *AddressBook) BatchCreate(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags address book
|
// @Tags 地址簿
|
||||||
// @Summary address book list
|
// @Summary 地址簿列表
|
||||||
// @Description address book list
|
// @Description 地址簿列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param user_id query int false "userid"
|
// @Param user_id query int false "用户id"
|
||||||
// @Param is_my query int false "whether it is mine"
|
// @Param is_my query int false "是否是我的"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookList}
|
// @Success 200 {object} response.Response{data=model.AddressBookList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/list [get]
|
// @Router /admin/address_book/list [get]
|
||||||
@@ -196,13 +196,13 @@ func (ct *AddressBook) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags address book
|
// @Tags 地址簿
|
||||||
// @Summary edit address book
|
// @Summary 地址簿编辑
|
||||||
// @Description edit address book
|
// @Description 地址簿编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "address book info"
|
// @Param body body admin.AddressBookForm true "地址簿信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBook}
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/update [post]
|
// @Router /admin/address_book/update [post]
|
||||||
@@ -240,13 +240,13 @@ func (ct *AddressBook) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags address book
|
// @Tags 地址簿
|
||||||
// @Summary delete address book
|
// @Summary 地址簿删除
|
||||||
// @Description delete address book
|
// @Description 地址簿删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "address book info"
|
// @Param body body admin.AddressBookForm true "地址簿信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/delete [post]
|
// @Router /admin/address_book/delete [post]
|
||||||
@@ -277,12 +277,12 @@ func (ct *AddressBook) Delete(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ShareByWebClient
|
// ShareByWebClient
|
||||||
// @Tags address book
|
// @Tags 地址簿
|
||||||
// @Summary share address book
|
// @Summary 地址簿分享
|
||||||
// @Description share address book
|
// @Description 地址簿分享
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.ShareByWebClientForm true "address book info"
|
// @Param body body admin.ShareByWebClientForm true "地址簿信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/share [post]
|
// @Router /admin/address_book/share [post]
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ import (
|
|||||||
type AddressBookCollection struct {
|
type AddressBookCollection struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail address book name
|
// Detail 地址簿名称
|
||||||
// @Tags address book name
|
// @Tags 地址簿名称
|
||||||
// @Summary address book name details
|
// @Summary 地址簿名称详情
|
||||||
// @Description address book name details
|
// @Description 地址簿名称详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -37,13 +37,13 @@ func (abc *AddressBookCollection) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create address book name
|
// Create 创建地址簿名称
|
||||||
// @Tags address book name
|
// @Tags 地址簿名称
|
||||||
// @Summary create address book name
|
// @Summary 创建地址簿名称
|
||||||
// @Description create address book name
|
// @Description 创建地址簿名称
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollection true "address book name info"
|
// @Param body body model.AddressBookCollection true "地址簿名称信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection/create [post]
|
// @Router /admin/address_book_collection/create [post]
|
||||||
@@ -72,16 +72,16 @@ func (abc *AddressBookCollection) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags address book name
|
// @Tags 地址簿名称
|
||||||
// @Summary address book name list
|
// @Summary 地址簿名称列表
|
||||||
// @Description address book name list
|
// @Description 地址簿名称列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param is_my query int false "whether it is mine"
|
// @Param is_my query int false "是否是我的"
|
||||||
// @Param user_id query int false "userid"
|
// @Param user_id query int false "用户id"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection/list [get]
|
// @Router /admin/address_book_collection/list [get]
|
||||||
@@ -100,13 +100,13 @@ func (abc *AddressBookCollection) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags address book name
|
// @Tags 地址簿名称
|
||||||
// @Summary edit address book name
|
// @Summary 地址簿名称编辑
|
||||||
// @Description edit address book name
|
// @Description 地址簿名称编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollection true "address book name info"
|
// @Param body body model.AddressBookCollection true "地址簿名称信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection/update [post]
|
// @Router /admin/address_book_collection/update [post]
|
||||||
@@ -135,13 +135,13 @@ func (abc *AddressBookCollection) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags address book name
|
// @Tags 地址簿名称
|
||||||
// @Summary delete address book name
|
// @Summary 地址簿名称删除
|
||||||
// @Description delete address book name
|
// @Description 地址簿名称删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollection true "address book name info"
|
// @Param body body model.AddressBookCollection true "地址簿名称信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection/delete [post]
|
// @Router /admin/address_book_collection/delete [post]
|
||||||
|
|||||||
@@ -14,17 +14,17 @@ import (
|
|||||||
type AddressBookCollectionRule struct {
|
type AddressBookCollectionRule struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags address book rules
|
// @Tags 地址簿规则
|
||||||
// @Summary address book rule list
|
// @Summary 地址簿规则列表
|
||||||
// @Description address book rule list
|
// @Description 地址簿规则列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param is_my query int false "whether it is mine"
|
// @Param is_my query int false "是否是我的"
|
||||||
// @Param user_id query int false "userid"
|
// @Param user_id query int false "用户id"
|
||||||
// @Param collection_id query int false "address book collectionid"
|
// @Param collection_id query int false "地址簿集合id"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection_rule/list [get]
|
// @Router /admin/address_book_collection_rule/list [get]
|
||||||
@@ -47,10 +47,10 @@ func (abcr *AddressBookCollectionRule) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail address book rules
|
// Detail 地址簿规则
|
||||||
// @Tags address book rules
|
// @Tags 地址簿规则
|
||||||
// @Summary address book rule details
|
// @Summary 地址簿规则详情
|
||||||
// @Description address book rule details
|
// @Description 地址簿规则详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -69,13 +69,13 @@ func (abcr *AddressBookCollectionRule) Detail(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create address book rule
|
// Create 创建地址簿规则
|
||||||
// @Tags address book rules
|
// @Tags 地址簿规则
|
||||||
// @Summary create address book rule
|
// @Summary 创建地址簿规则
|
||||||
// @Description create address book rule
|
// @Description 创建地址簿规则
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
// @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection_rule/create [post]
|
// @Router /admin/address_book_collection_rule/create [post]
|
||||||
@@ -120,7 +120,7 @@ func (abcr *AddressBookCollectionRule) CheckForm(t *model.AddressBookCollectionR
|
|||||||
//check to_id
|
//check to_id
|
||||||
if t.Type == model.ShareAddressBookRuleTypePersonal {
|
if t.Type == model.ShareAddressBookRuleTypePersonal {
|
||||||
if t.ToId == t.UserId {
|
if t.ToId == t.UserId {
|
||||||
return "CannotShareToSelf", false
|
return "ParamsError", false
|
||||||
}
|
}
|
||||||
tou := service.AllService.UserService.InfoById(t.ToId)
|
tou := service.AllService.UserService.InfoById(t.ToId)
|
||||||
if tou.Id == 0 {
|
if tou.Id == 0 {
|
||||||
@@ -134,8 +134,8 @@ func (abcr *AddressBookCollectionRule) CheckForm(t *model.AddressBookCollectionR
|
|||||||
} else {
|
} else {
|
||||||
return "ParamsError", false
|
return "ParamsError", false
|
||||||
}
|
}
|
||||||
// duplicate check
|
// 重复检查
|
||||||
ex := service.AllService.AddressBookService.RuleInfoByToIdAndCid(t.Type, t.ToId, t.CollectionId)
|
ex := service.AllService.AddressBookService.RulePersonalInfoByToIdAndCid(t.ToId, t.CollectionId)
|
||||||
if t.Id == 0 && ex.Id > 0 {
|
if t.Id == 0 && ex.Id > 0 {
|
||||||
return "ItemExists", false
|
return "ItemExists", false
|
||||||
}
|
}
|
||||||
@@ -145,13 +145,13 @@ func (abcr *AddressBookCollectionRule) CheckForm(t *model.AddressBookCollectionR
|
|||||||
return "", true
|
return "", true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags address book rules
|
// @Tags 地址簿规则
|
||||||
// @Summary edit address book rule
|
// @Summary 地址簿规则编辑
|
||||||
// @Description edit address book rule
|
// @Description 地址簿规则编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
// @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection_rule/update [post]
|
// @Router /admin/address_book_collection_rule/update [post]
|
||||||
@@ -185,13 +185,13 @@ func (abcr *AddressBookCollectionRule) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags address book rules
|
// @Tags 地址簿规则
|
||||||
// @Summary delete address book rule
|
// @Summary 地址簿规则删除
|
||||||
// @Description delete address book rule
|
// @Description 地址簿规则删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
// @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection_rule/delete [post]
|
// @Router /admin/address_book_collection_rule/delete [post]
|
||||||
|
|||||||
@@ -13,16 +13,16 @@ import (
|
|||||||
type Audit struct {
|
type Audit struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnList list
|
// ConnList 列表
|
||||||
// @Tags connection log
|
// @Tags 链接日志
|
||||||
// @Summary connection log list
|
// @Summary 链接日志列表
|
||||||
// @Description connection log list
|
// @Description 链接日志列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param peer_id query int false "target device"
|
// @Param peer_id query int false "目标设备"
|
||||||
// @Param from_peer query int false "source device"
|
// @Param from_peer query int false "来源设备"
|
||||||
// @Success 200 {object} response.Response{data=model.AuditConnList}
|
// @Success 200 {object} response.Response{data=model.AuditConnList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_conn/list [get]
|
// @Router /admin/audit_conn/list [get]
|
||||||
@@ -45,13 +45,13 @@ func (a *Audit) ConnList(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnDelete delete
|
// ConnDelete 删除
|
||||||
// @Tags connection log
|
// @Tags 链接日志
|
||||||
// @Summary delete connection log
|
// @Summary 链接日志删除
|
||||||
// @Description delete connection log
|
// @Description 链接日志删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AuditConn true "connection log info"
|
// @Param body body model.AuditConn true "链接日志信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_conn/delete [post]
|
// @Router /admin/audit_conn/delete [post]
|
||||||
@@ -81,13 +81,13 @@ func (a *Audit) ConnDelete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchConnDelete delete
|
// BatchConnDelete 删除
|
||||||
// @Tags connection log
|
// @Tags 链接日志
|
||||||
// @Summary batch delete connection logs
|
// @Summary 链接日志批量删除
|
||||||
// @Description batch delete connection logs
|
// @Description 链接日志批量删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AuditConnLogIds true "connection log"
|
// @Param body body admin.AuditConnLogIds true "链接日志"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_conn/batchDelete [post]
|
// @Router /admin/audit_conn/batchDelete [post]
|
||||||
@@ -112,16 +112,16 @@ func (a *Audit) BatchConnDelete(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileList list
|
// FileList 列表
|
||||||
// @Tags file log
|
// @Tags 文件日志
|
||||||
// @Summary file log list
|
// @Summary 文件日志列表
|
||||||
// @Description file log list
|
// @Description 文件日志列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param peer_id query int false "target device"
|
// @Param peer_id query int false "目标设备"
|
||||||
// @Param from_peer query int false "source device"
|
// @Param from_peer query int false "来源设备"
|
||||||
// @Success 200 {object} response.Response{data=model.AuditFileList}
|
// @Success 200 {object} response.Response{data=model.AuditFileList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_file/list [get]
|
// @Router /admin/audit_file/list [get]
|
||||||
@@ -144,13 +144,13 @@ func (a *Audit) FileList(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileDelete delete
|
// FileDelete 删除
|
||||||
// @Tags file log
|
// @Tags 文件日志
|
||||||
// @Summary delete file log
|
// @Summary 文件日志删除
|
||||||
// @Description delete file log
|
// @Description 文件日志删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AuditFile true "file log info"
|
// @Param body body model.AuditFile true "文件日志信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_file/delete [post]
|
// @Router /admin/audit_file/delete [post]
|
||||||
@@ -180,13 +180,13 @@ func (a *Audit) FileDelete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchFileDelete delete
|
// BatchFileDelete 删除
|
||||||
// @Tags file log
|
// @Tags 文件日志
|
||||||
// @Summary batch delete file logs
|
// @Summary 文件日志批量删除
|
||||||
// @Description batch delete file logs
|
// @Description 文件日志批量删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AuditFileLogIds true "file log"
|
// @Param body body admin.AuditFileLogIds true "文件日志"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_file/batchDelete [post]
|
// @Router /admin/audit_file/batchDelete [post]
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig RUSTDESKservice config
|
// ServerConfig RUSTDESK服务配置
|
||||||
// @Tags ADMIN
|
// @Tags ADMIN
|
||||||
// @Summary RUSTDESKservice config
|
// @Summary RUSTDESK服务配置
|
||||||
// @Description service config, provides an api-server for the webclient
|
// @Description 服务配置,给webclient提供api-server
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -33,10 +33,10 @@ func (co *Config) ServerConfig(c *gin.Context) {
|
|||||||
response.Success(c, cf)
|
response.Success(c, cf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppConfig APPservice config
|
// AppConfig APP服务配置
|
||||||
// @Tags ADMIN
|
// @Tags ADMIN
|
||||||
// @Summary APPservice config
|
// @Summary APP服务配置
|
||||||
// @Description APPservice config
|
// @Description APP服务配置
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -49,10 +49,10 @@ func (co *Config) AppConfig(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminConfig ADMINservice config
|
// AdminConfig ADMIN服务配置
|
||||||
// @Tags ADMIN
|
// @Tags ADMIN
|
||||||
// @Summary ADMINservice config
|
// @Summary ADMIN服务配置
|
||||||
// @Description ADMINservice config
|
// @Description ADMIN服务配置
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -78,13 +78,11 @@ func (co *Config) AdminConfig(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hello := global.Config.Admin.Hello
|
hello := global.Config.Admin.Hello
|
||||||
if hello == "" {
|
helloFile := global.Config.Admin.HelloFile
|
||||||
helloFile := global.Config.Admin.HelloFile
|
if helloFile != "" {
|
||||||
if helloFile != "" {
|
b, err := os.ReadFile(helloFile)
|
||||||
b, err := os.ReadFile(helloFile)
|
if err == nil && len(b) > 0 {
|
||||||
if err == nil && len(b) > 0 {
|
hello = string(b)
|
||||||
hello = string(b)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import (
|
|||||||
type DeviceGroup struct {
|
type DeviceGroup struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail device group
|
// Detail 设备群组
|
||||||
// @Tags device group
|
// @Tags 设备群组
|
||||||
// @Summary device group details
|
// @Summary 设备群组详情
|
||||||
// @Description device group details
|
// @Description 设备群组详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -35,13 +35,13 @@ func (ct *DeviceGroup) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create device group
|
// Create 创建设备群组
|
||||||
// @Tags device group
|
// @Tags 设备群组
|
||||||
// @Summary create device group
|
// @Summary 创建设备群组
|
||||||
// @Description create device group
|
// @Description 创建设备群组
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.DeviceGroupForm true "device group info"
|
// @Param body body admin.DeviceGroupForm true "设备群组信息"
|
||||||
// @Success 200 {object} response.Response{data=model.DeviceGroup}
|
// @Success 200 {object} response.Response{data=model.DeviceGroup}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/device_group/create [post]
|
// @Router /admin/device_group/create [post]
|
||||||
@@ -66,14 +66,14 @@ func (ct *DeviceGroup) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags group
|
// @Tags 群组
|
||||||
// @Summary group list
|
// @Summary 群组列表
|
||||||
// @Description group list
|
// @Description 群组列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Success 200 {object} response.Response{data=model.GroupList}
|
// @Success 200 {object} response.Response{data=model.GroupList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/device_group/list [get]
|
// @Router /admin/device_group/list [get]
|
||||||
@@ -88,13 +88,13 @@ func (ct *DeviceGroup) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags device group
|
// @Tags 设备群组
|
||||||
// @Summary edit device group
|
// @Summary 设备群组编辑
|
||||||
// @Description edit device group
|
// @Description 设备群组编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.DeviceGroupForm true "group info"
|
// @Param body body admin.DeviceGroupForm true "群组信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Group}
|
// @Success 200 {object} response.Response{data=model.Group}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/device_group/update [post]
|
// @Router /admin/device_group/update [post]
|
||||||
@@ -123,13 +123,13 @@ func (ct *DeviceGroup) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags device group
|
// @Tags 设备群组
|
||||||
// @Summary delete device group
|
// @Summary 设备群组删除
|
||||||
// @Description delete device group
|
// @Description 设备群组删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.DeviceGroupForm true "group info"
|
// @Param body body admin.DeviceGroupForm true "群组信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/device_group/delete [post]
|
// @Router /admin/device_group/delete [post]
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
type File struct {
|
type File struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// OssToken file
|
// OssToken 文件
|
||||||
// @Tags file
|
// @Tags 文件
|
||||||
// @Summary getossToken
|
// @Summary 获取ossToken
|
||||||
// @Description getossToken
|
// @Description 获取ossToken
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -33,12 +33,12 @@ type FileBack struct {
|
|||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify callback after successful upload
|
// Notify 上传成功后回调
|
||||||
func (f *File) Notify(c *gin.Context) {
|
func (f *File) Notify(c *gin.Context) {
|
||||||
|
|
||||||
res := global.Oss.Verify(c.Request)
|
res := global.Oss.Verify(c.Request)
|
||||||
if !res {
|
if !res {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
response.Fail(c, 101, "权限错误")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fm := &FileBack{}
|
fm := &FileBack{}
|
||||||
@@ -50,13 +50,13 @@ func (f *File) Notify(c *gin.Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload upload file to local
|
// Upload 上传文件到本地
|
||||||
// @Tags file
|
// @Tags 文件
|
||||||
// @Summary upload file to local
|
// @Summary 上传文件到本地
|
||||||
// @Description upload file to local
|
// @Description 上传文件到本地
|
||||||
// @Accept multipart/form-data
|
// @Accept multipart/form-data
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param file formData file true "file upload example"
|
// @Param file formData file true "上传文件示例"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/file/upload [post]
|
// @Router /admin/file/upload [post]
|
||||||
@@ -71,12 +71,12 @@ func (f *File) Upload(c *gin.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// upload the file to the specified directory
|
// 上传文件至指定目录
|
||||||
err = c.SaveUploadedFile(file, dst)
|
err = c.SaveUploadedFile(file, dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// return filewebaddress
|
// 返回文件web地址
|
||||||
response.Success(c, gin.H{
|
response.Success(c, gin.H{
|
||||||
"url": webPath + file.Filename,
|
"url": webPath + file.Filename,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import (
|
|||||||
type Group struct {
|
type Group struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail group
|
// Detail 群组
|
||||||
// @Tags group
|
// @Tags 群组
|
||||||
// @Summary group details
|
// @Summary 群组详情
|
||||||
// @Description group details
|
// @Description 群组详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -35,13 +35,13 @@ func (ct *Group) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create group
|
// Create 创建群组
|
||||||
// @Tags group
|
// @Tags 群组
|
||||||
// @Summary create group
|
// @Summary 创建群组
|
||||||
// @Description create group
|
// @Description 创建群组
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.GroupForm true "group info"
|
// @Param body body admin.GroupForm true "群组信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Group}
|
// @Success 200 {object} response.Response{data=model.Group}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/group/create [post]
|
// @Router /admin/group/create [post]
|
||||||
@@ -66,14 +66,14 @@ func (ct *Group) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags group
|
// @Tags 群组
|
||||||
// @Summary group list
|
// @Summary 群组列表
|
||||||
// @Description group list
|
// @Description 群组列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Success 200 {object} response.Response{data=model.GroupList}
|
// @Success 200 {object} response.Response{data=model.GroupList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/group/list [get]
|
// @Router /admin/group/list [get]
|
||||||
@@ -88,13 +88,13 @@ func (ct *Group) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags group
|
// @Tags 群组
|
||||||
// @Summary edit group
|
// @Summary 群组编辑
|
||||||
// @Description edit group
|
// @Description 群组编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.GroupForm true "group info"
|
// @Param body body admin.GroupForm true "群组信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Group}
|
// @Success 200 {object} response.Response{data=model.Group}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/group/update [post]
|
// @Router /admin/group/update [post]
|
||||||
@@ -123,13 +123,13 @@ func (ct *Group) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags group
|
// @Tags 群组
|
||||||
// @Summary delete group
|
// @Summary 群组删除
|
||||||
// @Description delete group
|
// @Description 群组删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.GroupForm true "group info"
|
// @Param body body admin.GroupForm true "群组信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/group/delete [post]
|
// @Router /admin/group/delete [post]
|
||||||
|
|||||||
+157
-65
@@ -2,7 +2,6 @@ package admin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/http/controller/api"
|
"github.com/lejianwen/rustdesk-api/v2/http/controller/api"
|
||||||
@@ -12,18 +11,142 @@ import (
|
|||||||
adResp "github.com/lejianwen/rustdesk-api/v2/http/response/admin"
|
adResp "github.com/lejianwen/rustdesk-api/v2/http/response/admin"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"github.com/mojocn/base64Captcha"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Login struct {
|
type Login struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login login
|
// Captcha 验证码结构
|
||||||
// @Tags login
|
type Captcha struct {
|
||||||
// @Summary login
|
Id string `json:"id"` // 验证码 ID
|
||||||
// @Description login
|
B64 string `json:"b64"` // base64 验证码
|
||||||
|
Code string `json:"-"` // 验证码内容
|
||||||
|
ExpiresAt time.Time `json:"-"` // 过期时间
|
||||||
|
}
|
||||||
|
type LoginLimiter struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
failCount map[string]int // 记录每个 IP 的失败次数
|
||||||
|
timestamp map[string]time.Time // 记录每个 IP 的最后失败时间
|
||||||
|
captchas map[string]Captcha // 每个 IP 的验证码
|
||||||
|
threshold int // 失败阈值
|
||||||
|
expiry time.Duration // 失败记录过期时间
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLoginLimiter(threshold int, expiry time.Duration) *LoginLimiter {
|
||||||
|
return &LoginLimiter{
|
||||||
|
failCount: make(map[string]int),
|
||||||
|
timestamp: make(map[string]time.Time),
|
||||||
|
captchas: make(map[string]Captcha),
|
||||||
|
threshold: threshold,
|
||||||
|
expiry: expiry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordFailure 记录登录失败
|
||||||
|
func (l *LoginLimiter) RecordFailure(ip string) {
|
||||||
|
l.mu.Lock()
|
||||||
|
defer l.mu.Unlock()
|
||||||
|
|
||||||
|
// 如果该 IP 的记录已经过期,重置计数
|
||||||
|
if lastTime, exists := l.timestamp[ip]; exists && time.Since(lastTime) > l.expiry {
|
||||||
|
l.failCount[ip] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新失败次数和时间戳
|
||||||
|
l.failCount[ip]++
|
||||||
|
l.timestamp[ip] = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NeedsCaptcha 检查是否需要验证码
|
||||||
|
func (l *LoginLimiter) NeedsCaptcha(ip string) bool {
|
||||||
|
l.mu.RLock()
|
||||||
|
defer l.mu.RUnlock()
|
||||||
|
|
||||||
|
// 检查记录是否存在且未过期
|
||||||
|
if lastTime, exists := l.timestamp[ip]; exists && time.Since(lastTime) <= l.expiry {
|
||||||
|
return l.failCount[ip] >= l.threshold
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateCaptcha 为指定 IP 生成验证码
|
||||||
|
func (l *LoginLimiter) GenerateCaptcha(ip string) Captcha {
|
||||||
|
l.mu.Lock()
|
||||||
|
defer l.mu.Unlock()
|
||||||
|
|
||||||
|
capd := base64Captcha.NewDriverString(50, 150, 5, 10, 4, "1234567890abcdefghijklmnopqrstuvwxyz", nil, nil, nil)
|
||||||
|
b64cap := base64Captcha.NewCaptcha(capd, base64Captcha.DefaultMemStore)
|
||||||
|
id, b64s, answer, err := b64cap.Generate()
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("Generate captcha failed: " + err.Error())
|
||||||
|
return Captcha{}
|
||||||
|
}
|
||||||
|
// 保存验证码到对应 IP
|
||||||
|
l.captchas[ip] = Captcha{
|
||||||
|
Id: id,
|
||||||
|
B64: b64s,
|
||||||
|
Code: answer,
|
||||||
|
ExpiresAt: time.Now().Add(5 * time.Minute),
|
||||||
|
}
|
||||||
|
return l.captchas[ip]
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyCaptcha 验证指定 IP 的验证码
|
||||||
|
func (l *LoginLimiter) VerifyCaptcha(ip, code string) bool {
|
||||||
|
l.mu.RLock()
|
||||||
|
defer l.mu.RUnlock()
|
||||||
|
|
||||||
|
// 检查验证码是否存在且未过期
|
||||||
|
if captcha, exists := l.captchas[ip]; exists && time.Now().Before(captcha.ExpiresAt) {
|
||||||
|
return captcha.Code == code
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveCaptcha 移除指定 IP 的验证码
|
||||||
|
func (l *LoginLimiter) RemoveCaptcha(ip string) {
|
||||||
|
l.mu.Lock()
|
||||||
|
defer l.mu.Unlock()
|
||||||
|
|
||||||
|
delete(l.captchas, ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanupExpired 清理过期的记录
|
||||||
|
func (l *LoginLimiter) CleanupExpired() {
|
||||||
|
l.mu.Lock()
|
||||||
|
defer l.mu.Unlock()
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
for ip, lastTime := range l.timestamp {
|
||||||
|
if now.Sub(lastTime) > l.expiry {
|
||||||
|
delete(l.failCount, ip)
|
||||||
|
delete(l.timestamp, ip)
|
||||||
|
delete(l.captchas, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LoginLimiter) RemoveRecord(ip string) {
|
||||||
|
l.mu.Lock()
|
||||||
|
defer l.mu.Unlock()
|
||||||
|
|
||||||
|
delete(l.failCount, ip)
|
||||||
|
delete(l.timestamp, ip)
|
||||||
|
delete(l.captchas, ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
var loginLimiter = NewLoginLimiter(3, 5*time.Minute)
|
||||||
|
|
||||||
|
// Login 登录
|
||||||
|
// @Tags 登录
|
||||||
|
// @Summary 登录
|
||||||
|
// @Description 登录
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.Login true "login info"
|
// @Param body body admin.Login true "登录信息"
|
||||||
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/login [post]
|
// @Router /admin/login [post]
|
||||||
@@ -33,16 +156,10 @@ func (ct *Login) Login(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "PwdLoginDisabled"))
|
response.Fail(c, 101, response.TranslateMsg(c, "PwdLoginDisabled"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check login limit
|
|
||||||
loginLimiter := global.LoginLimiter
|
|
||||||
clientIp := c.ClientIP()
|
|
||||||
_, needCaptcha := loginLimiter.CheckSecurityStatus(clientIp)
|
|
||||||
|
|
||||||
f := &admin.Login{}
|
f := &admin.Login{}
|
||||||
err := c.ShouldBindJSON(f)
|
err := c.ShouldBindJSON(f)
|
||||||
|
clientIp := c.ClientIP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loginLimiter.RecordFailedAttempt(clientIp)
|
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), clientIp))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), clientIp))
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
@@ -50,15 +167,14 @@ func (ct *Login) Login(c *gin.Context) {
|
|||||||
|
|
||||||
errList := global.Validator.ValidStruct(c, f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
loginLimiter.RecordFailedAttempt(clientIp)
|
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), clientIp))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), clientIp))
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check whether a captcha is required
|
// 检查是否需要验证码
|
||||||
if needCaptcha {
|
if loginLimiter.NeedsCaptcha(clientIp) {
|
||||||
if f.CaptchaId == "" || f.Captcha == "" || !loginLimiter.VerifyCaptcha(f.CaptchaId, f.Captcha) {
|
if f.Captcha == "" || !loginLimiter.VerifyCaptcha(clientIp, f.Captcha) {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -68,19 +184,17 @@ func (ct *Login) Login(c *gin.Context) {
|
|||||||
|
|
||||||
if u.Id == 0 {
|
if u.Id == 0 {
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), clientIp))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), clientIp))
|
||||||
loginLimiter.RecordFailedAttempt(clientIp)
|
loginLimiter.RecordFailure(clientIp)
|
||||||
if _, needCaptcha = loginLimiter.CheckSecurityStatus(clientIp); needCaptcha {
|
if loginLimiter.NeedsCaptcha(clientIp) {
|
||||||
response.Fail(c, 110, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
loginLimiter.RemoveCaptcha(clientIp)
|
||||||
} else {
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
|
||||||
}
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !service.AllService.UserService.CheckUserEnable(u) {
|
if !service.AllService.UserService.CheckUserEnable(u) {
|
||||||
if needCaptcha {
|
if loginLimiter.NeedsCaptcha(clientIp) {
|
||||||
response.Fail(c, 110, response.TranslateMsg(c, "UserDisabled"))
|
loginLimiter.RemoveCaptcha(clientIp)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "UserDisabled"))
|
response.Fail(c, 101, response.TranslateMsg(c, "UserDisabled"))
|
||||||
return
|
return
|
||||||
@@ -95,44 +209,30 @@ func (ct *Login) Login(c *gin.Context) {
|
|||||||
Platform: f.Platform,
|
Platform: f.Platform,
|
||||||
})
|
})
|
||||||
|
|
||||||
// login successful, clear the login limit
|
// 成功后清除记录
|
||||||
loginLimiter.RemoveAttempts(clientIp)
|
loginLimiter.RemoveRecord(clientIp)
|
||||||
|
|
||||||
|
// 清理过期记录
|
||||||
|
go loginLimiter.CleanupExpired()
|
||||||
|
|
||||||
responseLoginSuccess(c, u, ut.Token)
|
responseLoginSuccess(c, u, ut.Token)
|
||||||
}
|
}
|
||||||
func (ct *Login) Captcha(c *gin.Context) {
|
func (ct *Login) Captcha(c *gin.Context) {
|
||||||
loginLimiter := global.LoginLimiter
|
|
||||||
clientIp := c.ClientIP()
|
clientIp := c.ClientIP()
|
||||||
banned, needCaptcha := loginLimiter.CheckSecurityStatus(clientIp)
|
if !loginLimiter.NeedsCaptcha(clientIp) {
|
||||||
if banned {
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "LoginBanned"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !needCaptcha {
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "NoCaptchaRequired"))
|
response.Fail(c, 101, response.TranslateMsg(c, "NoCaptchaRequired"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err, captcha := loginLimiter.RequireCaptcha()
|
captcha := loginLimiter.GenerateCaptcha(clientIp)
|
||||||
if err != nil {
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError")+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err, b64 := loginLimiter.DrawCaptcha(captcha.Content)
|
|
||||||
if err != nil {
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError")+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
response.Success(c, gin.H{
|
response.Success(c, gin.H{
|
||||||
"captcha": gin.H{
|
"captcha": captcha,
|
||||||
"id": captcha.Id,
|
|
||||||
"b64": b64,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout logout
|
// Logout 登出
|
||||||
// @Tags login
|
// @Tags 登录
|
||||||
// @Summary logout
|
// @Summary 登出
|
||||||
// @Description logout
|
// @Description 登出
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -148,29 +248,21 @@ func (ct *Login) Logout(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoginOptions
|
// LoginOptions
|
||||||
// @Tags login
|
// @Tags 登录
|
||||||
// @Summary login options
|
// @Summary 登录选项
|
||||||
// @Description login options
|
// @Description 登录选项
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} []string
|
// @Success 200 {object} []string
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /admin/login-options [post]
|
// @Router /admin/login-options [post]
|
||||||
func (ct *Login) LoginOptions(c *gin.Context) {
|
func (ct *Login) LoginOptions(c *gin.Context) {
|
||||||
loginLimiter := global.LoginLimiter
|
ip := c.ClientIP()
|
||||||
clientIp := c.ClientIP()
|
|
||||||
banned, needCaptcha := loginLimiter.CheckSecurityStatus(clientIp)
|
|
||||||
if banned {
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "LoginBanned"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ops := service.AllService.OauthService.GetOauthProviders()
|
ops := service.AllService.OauthService.GetOauthProviders()
|
||||||
response.Success(c, gin.H{
|
response.Success(c, gin.H{
|
||||||
"ops": ops,
|
"ops": ops,
|
||||||
"register": global.Config.App.Register,
|
"register": global.Config.App.Register,
|
||||||
"need_captcha": needCaptcha,
|
"need_captcha": loginLimiter.NeedsCaptcha(ip),
|
||||||
"disable_pwd": global.Config.App.DisablePwdLogin,
|
|
||||||
"auto_oidc": global.Config.App.DisablePwdLogin && len(ops) == 1,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ import (
|
|||||||
type LoginLog struct {
|
type LoginLog struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail login log
|
// Detail 登录日志
|
||||||
// @Tags login log
|
// @Tags 登录日志
|
||||||
// @Summary login log details
|
// @Summary 登录日志详情
|
||||||
// @Description login log details
|
// @Description 登录日志详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -37,15 +37,15 @@ func (ct *LoginLog) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags login log
|
// @Tags 登录日志
|
||||||
// @Summary login log list
|
// @Summary 登录日志列表
|
||||||
// @Description login log list
|
// @Description 登录日志列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param user_id query int false "userID"
|
// @Param user_id query int false "用户ID"
|
||||||
// @Success 200 {object} response.Response{data=model.LoginLogList}
|
// @Success 200 {object} response.Response{data=model.LoginLogList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/login_log/list [get]
|
// @Router /admin/login_log/list [get]
|
||||||
@@ -65,13 +65,13 @@ func (ct *LoginLog) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags login log
|
// @Tags 登录日志
|
||||||
// @Summary delete login log
|
// @Summary 登录日志删除
|
||||||
// @Description delete login log
|
// @Description 登录日志删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.LoginLog true "login log info"
|
// @Param body body model.LoginLog true "登录日志信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/login_log/delete [post]
|
// @Router /admin/login_log/delete [post]
|
||||||
@@ -101,13 +101,13 @@ func (ct *LoginLog) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, err.Error())
|
response.Fail(c, 101, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchDelete delete
|
// BatchDelete 删除
|
||||||
// @Tags login log
|
// @Tags 登录日志
|
||||||
// @Summary batch delete login logs
|
// @Summary 登录日志批量删除
|
||||||
// @Description batch delete login logs
|
// @Description 登录日志批量删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.LoginLogIds true "login log"
|
// @Param body body admin.LoginLogIds true "登录日志"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/login_log/batchDelete [post]
|
// @Router /admin/login_log/batchDelete [post]
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ import (
|
|||||||
|
|
||||||
type AddressBook struct{}
|
type AddressBook struct{}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags my address book
|
// @Tags 我的地址簿
|
||||||
// @Summary address book list
|
// @Summary 地址簿列表
|
||||||
// @Description address book list
|
// @Description 地址簿列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param user_id query int false "userid"
|
// @Param user_id query int false "用户id"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookList}
|
// @Success 200 {object} response.Response{data=model.AddressBookList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book/list [get]
|
// @Router /admin/my/address_book/list [get]
|
||||||
@@ -34,7 +34,7 @@ func (ct *AddressBook) List(c *gin.Context) {
|
|||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
query.UserId = int(u.Id)
|
query.UserId = int(u.Id)
|
||||||
res := service.AllService.AddressBookService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
res := service.AllService.AddressBookService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
//preload address book name
|
//预加载地址簿名称
|
||||||
tx.Preload("Collection", func(txc *gorm.DB) *gorm.DB {
|
tx.Preload("Collection", func(txc *gorm.DB) *gorm.DB {
|
||||||
return txc.Select("id,name")
|
return txc.Select("id,name")
|
||||||
})
|
})
|
||||||
@@ -60,13 +60,13 @@ func (ct *AddressBook) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create address book
|
// Create 创建地址簿
|
||||||
// @Tags my address book
|
// @Tags 我的地址簿
|
||||||
// @Summary create address book
|
// @Summary 创建地址簿
|
||||||
// @Description create address book
|
// @Description 创建地址簿
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "address book info"
|
// @Param body body admin.AddressBookForm true "地址簿信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBook}
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book/create [post]
|
// @Router /admin/my/address_book/create [post]
|
||||||
@@ -104,13 +104,13 @@ func (ct *AddressBook) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags my address book
|
// @Tags 我的地址簿
|
||||||
// @Summary edit address book
|
// @Summary 地址簿编辑
|
||||||
// @Description edit address book
|
// @Description 地址簿编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "address book info"
|
// @Param body body admin.AddressBookForm true "地址簿信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBook}
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book/update [post]
|
// @Router /admin/my/address_book/update [post]
|
||||||
@@ -158,13 +158,13 @@ func (ct *AddressBook) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags my address book
|
// @Tags 我的地址簿
|
||||||
// @Summary delete address book
|
// @Summary 地址簿删除
|
||||||
// @Description delete address book
|
// @Description 地址簿删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "address book info"
|
// @Param body body admin.AddressBookForm true "地址簿信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book/delete [post]
|
// @Router /admin/my/address_book/delete [post]
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ import (
|
|||||||
type AddressBookCollection struct {
|
type AddressBookCollection struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create address book name
|
// Create 创建地址簿名称
|
||||||
// @Tags my address book name
|
// @Tags 我的地址簿名称
|
||||||
// @Summary create address book name
|
// @Summary 创建地址簿名称
|
||||||
// @Description create address book name
|
// @Description 创建地址簿名称
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollection true "address book name info"
|
// @Param body body model.AddressBookCollection true "地址簿名称信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book_collection/create [post]
|
// @Router /admin/my/address_book_collection/create [post]
|
||||||
@@ -45,14 +45,14 @@ func (abc *AddressBookCollection) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags my address book name
|
// @Tags 我的地址簿名称
|
||||||
// @Summary address book name list
|
// @Summary 地址簿名称列表
|
||||||
// @Description address book name list
|
// @Description 地址簿名称列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book_collection/list [get]
|
// @Router /admin/my/address_book_collection/list [get]
|
||||||
@@ -71,13 +71,13 @@ func (abc *AddressBookCollection) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags my address book name
|
// @Tags 我的地址簿名称
|
||||||
// @Summary edit address book name
|
// @Summary 地址簿名称编辑
|
||||||
// @Description edit address book name
|
// @Description 地址簿名称编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollection true "address book name info"
|
// @Param body body model.AddressBookCollection true "地址簿名称信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book_collection/update [post]
|
// @Router /admin/my/address_book_collection/update [post]
|
||||||
@@ -98,10 +98,10 @@ func (abc *AddressBookCollection) Update(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
//if f.UserId != u.Id {
|
if f.UserId != u.Id {
|
||||||
// response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
// return
|
return
|
||||||
//}
|
}
|
||||||
ex := service.AllService.AddressBookService.CollectionInfoById(f.Id)
|
ex := service.AllService.AddressBookService.CollectionInfoById(f.Id)
|
||||||
if ex.Id == 0 {
|
if ex.Id == 0 {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
@@ -120,13 +120,13 @@ func (abc *AddressBookCollection) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags my address book name
|
// @Tags 我的地址簿名称
|
||||||
// @Summary delete address book name
|
// @Summary 地址簿名称删除
|
||||||
// @Description delete address book name
|
// @Description 地址簿名称删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollection true "address book name info"
|
// @Param body body model.AddressBookCollection true "地址簿名称信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book_collection/delete [post]
|
// @Router /admin/my/address_book_collection/delete [post]
|
||||||
|
|||||||
@@ -13,17 +13,17 @@ import (
|
|||||||
type AddressBookCollectionRule struct {
|
type AddressBookCollectionRule struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags my address book rules
|
// @Tags 我的地址簿规则
|
||||||
// @Summary address book rule list
|
// @Summary 地址簿规则列表
|
||||||
// @Description address book rule list
|
// @Description 地址簿规则列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param is_my query int false "whether it is mine"
|
// @Param is_my query int false "是否是我的"
|
||||||
// @Param user_id query int false "userid"
|
// @Param user_id query int false "用户id"
|
||||||
// @Param collection_id query int false "address book collectionid"
|
// @Param collection_id query int false "地址簿集合id"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book_collection_rule/list [get]
|
// @Router /admin/my/address_book_collection_rule/list [get]
|
||||||
@@ -46,13 +46,13 @@ func (abcr *AddressBookCollectionRule) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create address book rule
|
// Create 创建地址簿规则
|
||||||
// @Tags my address book rules
|
// @Tags 我的地址簿规则
|
||||||
// @Summary create address book rule
|
// @Summary 创建地址簿规则
|
||||||
// @Description create address book rule
|
// @Description 创建地址簿规则
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
// @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book_collection_rule/create [post]
|
// @Router /admin/my/address_book_collection_rule/create [post]
|
||||||
@@ -100,21 +100,21 @@ func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.Address
|
|||||||
//check to_id
|
//check to_id
|
||||||
if t.Type == model.ShareAddressBookRuleTypePersonal {
|
if t.Type == model.ShareAddressBookRuleTypePersonal {
|
||||||
if t.ToId == t.UserId {
|
if t.ToId == t.UserId {
|
||||||
return "CannotShareToSelf", false
|
return "ParamsError", false
|
||||||
}
|
}
|
||||||
tou := service.AllService.UserService.InfoById(t.ToId)
|
tou := service.AllService.UserService.InfoById(t.ToId)
|
||||||
if tou.Id == 0 {
|
if tou.Id == 0 {
|
||||||
return "ItemNotFound", false
|
return "ItemNotFound", false
|
||||||
}
|
}
|
||||||
//non-admins cannot share with users outside their own organization
|
//非管理员不能分享给非本组织用户
|
||||||
//if tou.GroupId != u.GroupId {
|
if tou.GroupId != u.GroupId {
|
||||||
// return "NoAccess", false
|
return "NoAccess", false
|
||||||
//}
|
}
|
||||||
} else if t.Type == model.ShareAddressBookRuleTypeGroup {
|
} else if t.Type == model.ShareAddressBookRuleTypeGroup {
|
||||||
//non-admins cannot share with other groups
|
//非管理员不能分享给其他组
|
||||||
//if t.ToId != u.GroupId {
|
if t.ToId != u.GroupId {
|
||||||
// return "NoAccess", false
|
return "NoAccess", false
|
||||||
//}
|
}
|
||||||
|
|
||||||
tog := service.AllService.GroupService.InfoById(t.ToId)
|
tog := service.AllService.GroupService.InfoById(t.ToId)
|
||||||
if tog.Id == 0 {
|
if tog.Id == 0 {
|
||||||
@@ -123,8 +123,8 @@ func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.Address
|
|||||||
} else {
|
} else {
|
||||||
return "ParamsError", false
|
return "ParamsError", false
|
||||||
}
|
}
|
||||||
// duplicate check
|
// 重复检查
|
||||||
ex := service.AllService.AddressBookService.RuleInfoByToIdAndCid(t.Type, t.ToId, t.CollectionId)
|
ex := service.AllService.AddressBookService.RulePersonalInfoByToIdAndCid(t.ToId, t.CollectionId)
|
||||||
if t.Id == 0 && ex.Id > 0 {
|
if t.Id == 0 && ex.Id > 0 {
|
||||||
return "ItemExists", false
|
return "ItemExists", false
|
||||||
}
|
}
|
||||||
@@ -134,13 +134,13 @@ func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.Address
|
|||||||
return "", true
|
return "", true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags my address book rules
|
// @Tags 我的地址簿规则
|
||||||
// @Summary edit address book rule
|
// @Summary 地址簿规则编辑
|
||||||
// @Description edit address book rule
|
// @Description 地址簿规则编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
// @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book_collection_rule/update [post]
|
// @Router /admin/my/address_book_collection_rule/update [post]
|
||||||
@@ -185,13 +185,13 @@ func (abcr *AddressBookCollectionRule) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags my address book rules
|
// @Tags 我的地址簿规则
|
||||||
// @Summary delete address book rule
|
// @Summary 地址簿规则删除
|
||||||
// @Description delete address book rule
|
// @Description 地址簿规则删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
// @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/address_book_collection_rule/delete [post]
|
// @Router /admin/my/address_book_collection_rule/delete [post]
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ import (
|
|||||||
type LoginLog struct {
|
type LoginLog struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags my login logs
|
// @Tags 我的登录日志
|
||||||
// @Summary login log list
|
// @Summary 登录日志列表
|
||||||
// @Description login log list
|
// @Description 登录日志列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param user_id query int false "userID"
|
// @Param user_id query int false "用户ID"
|
||||||
// @Success 200 {object} response.Response{data=model.LoginLogList}
|
// @Success 200 {object} response.Response{data=model.LoginLogList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/login_log/list [get]
|
// @Router /admin/my/login_log/list [get]
|
||||||
@@ -40,13 +40,13 @@ func (ct *LoginLog) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags my login logs
|
// @Tags 我的登录日志
|
||||||
// @Summary delete login log
|
// @Summary 登录日志删除
|
||||||
// @Description delete login log
|
// @Description 登录日志删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.LoginLog true "login log info"
|
// @Param body body model.LoginLog true "登录日志信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/login_log/delete [post]
|
// @Router /admin/my/login_log/delete [post]
|
||||||
@@ -81,13 +81,13 @@ func (ct *LoginLog) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, err.Error())
|
response.Fail(c, 101, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchDelete delete
|
// BatchDelete 删除
|
||||||
// @Tags my login logs
|
// @Tags 我的登录日志
|
||||||
// @Summary batch delete login logs
|
// @Summary 登录日志批量删除
|
||||||
// @Description batch delete login logs
|
// @Description 登录日志批量删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.LoginLogIds true "login log"
|
// @Param body body admin.LoginLogIds true "登录日志"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/login_log/batchDelete [post]
|
// @Router /admin/my/login_log/batchDelete [post]
|
||||||
|
|||||||
@@ -12,18 +12,18 @@ import (
|
|||||||
type Peer struct {
|
type Peer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags my devices
|
// @Tags 我的设备
|
||||||
// @Summary device list
|
// @Summary 设备列表
|
||||||
// @Description device list
|
// @Description 设备列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param time_ago query int false "time"
|
// @Param time_ago query int false "时间"
|
||||||
// @Param id query string false "ID"
|
// @Param id query string false "ID"
|
||||||
// @Param hostname query string false "hostname"
|
// @Param hostname query string false "主机名"
|
||||||
// @Param uuids query string false "uuids separated by commas"
|
// @Param uuids query string false "uuids 用逗号分隔"
|
||||||
// @Success 200 {object} response.Response{data=model.PeerList}
|
// @Success 200 {object} response.Response{data=model.PeerList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/peer/list [get]
|
// @Router /admin/my/peer/list [get]
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ import (
|
|||||||
type ShareRecord struct {
|
type ShareRecord struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List share record list
|
// List 分享记录列表
|
||||||
// @Tags my share records
|
// @Tags 我的分享记录
|
||||||
// @Summary share record list
|
// @Summary 分享记录列表
|
||||||
// @Description share record list
|
// @Description 分享记录列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/share_record/list [get]
|
// @Router /admin/my/share_record/list [get]
|
||||||
@@ -37,13 +37,13 @@ func (sr *ShareRecord) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete share record
|
// Delete 分享记录删除
|
||||||
// @Tags my share records
|
// @Tags 我的分享记录
|
||||||
// @Summary delete share record
|
// @Summary 分享记录删除
|
||||||
// @Description delete share record
|
// @Description 分享记录删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.ShareRecordForm true "share record info"
|
// @Param body body admin.ShareRecordForm true "分享记录信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/share_record/delete [post]
|
// @Router /admin/my/share_record/delete [post]
|
||||||
@@ -78,10 +78,10 @@ func (sr *ShareRecord) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchDelete batch delete my share records
|
// BatchDelete 批量删除我的分享记录
|
||||||
// @Tags my
|
// @Tags 我的
|
||||||
// @Summary batch delete my share records
|
// @Summary 批量删除我的分享记录
|
||||||
// @Description batch delete my share records
|
// @Description 批量删除我的分享记录
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerShareRecordBatchDeleteForm true "id"
|
// @Param body body admin.PeerShareRecordBatchDeleteForm true "id"
|
||||||
|
|||||||
@@ -11,16 +11,16 @@ import (
|
|||||||
|
|
||||||
type Tag struct{}
|
type Tag struct{}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags my tags
|
// @Tags 我的标签
|
||||||
// @Summary tag list
|
// @Summary 标签列表
|
||||||
// @Description tag list
|
// @Description 标签列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param is_my query int false "whether it is mine"
|
// @Param is_my query int false "是否是我的"
|
||||||
// @Param user_id query int false "userid"
|
// @Param user_id query int false "用户id"
|
||||||
// @Success 200 {object} response.Response{data=model.TagList}
|
// @Success 200 {object} response.Response{data=model.TagList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/tag/list [get]
|
// @Router /admin/my/tag/list [get]
|
||||||
@@ -45,13 +45,13 @@ func (ct *Tag) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create tag
|
// Create 创建标签
|
||||||
// @Tags my tags
|
// @Tags 我的标签
|
||||||
// @Summary create tag
|
// @Summary 创建标签
|
||||||
// @Description create tag
|
// @Description 创建标签
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.TagForm true "tag info"
|
// @Param body body admin.TagForm true "标签信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Tag}
|
// @Success 200 {object} response.Response{data=model.Tag}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/tag/create [post]
|
// @Router /admin/my/tag/create [post]
|
||||||
@@ -78,13 +78,13 @@ func (ct *Tag) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags my tags
|
// @Tags 我的标签
|
||||||
// @Summary edit tag
|
// @Summary 标签编辑
|
||||||
// @Description edit tag
|
// @Description 标签编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.TagForm true "tag info"
|
// @Param body body admin.TagForm true "标签信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Tag}
|
// @Success 200 {object} response.Response{data=model.Tag}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/tag/update [post]
|
// @Router /admin/my/tag/update [post]
|
||||||
@@ -133,13 +133,13 @@ func (ct *Tag) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags tag
|
// @Tags 标签
|
||||||
// @Summary delete tag
|
// @Summary 标签删除
|
||||||
// @Description delete tag
|
// @Description 标签删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.TagForm true "tag info"
|
// @Param body body admin.TagForm true "标签信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/my/tag/delete [post]
|
// @Router /admin/my/tag/delete [post]
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
adminReq "github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
adminReq "github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Oauth struct {
|
type Oauth struct {
|
||||||
@@ -64,21 +63,21 @@ func (o *Oauth) ToBind(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirm confirm authorized login
|
// Confirm 确认授权登录
|
||||||
func (o *Oauth) Confirm(c *gin.Context) {
|
func (o *Oauth) Confirm(c *gin.Context) {
|
||||||
j := &adminReq.OauthConfirmForm{}
|
j := &adminReq.OauthConfirmForm{}
|
||||||
err := c.ShouldBindJSON(j)
|
err := c.ShouldBindJSON(j)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Fail(c, 101, "参数错误"+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if j.Code == "" {
|
if j.Code == "" {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
response.Fail(c, 101, "参数错误: code 不存在")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v := service.AllService.OauthService.GetOauthCache(j.Code)
|
v := service.AllService.OauthService.GetOauthCache(j.Code)
|
||||||
if v == nil {
|
if v == nil {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "OauthExpired"))
|
response.Fail(c, 101, "授权已过期")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
@@ -140,8 +139,8 @@ func (o *Oauth) Unbind(c *gin.Context) {
|
|||||||
|
|
||||||
// Detail Oauth
|
// Detail Oauth
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary Oauthdetails
|
// @Summary Oauth详情
|
||||||
// @Description Oauthdetails
|
// @Description Oauth详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -161,13 +160,13 @@ func (o *Oauth) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create createOauth
|
// Create 创建Oauth
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary createOauth
|
// @Summary 创建Oauth
|
||||||
// @Description createOauth
|
// @Description 创建Oauth
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.OauthForm true "Oauthinfo"
|
// @Param body body admin.OauthForm true "Oauth信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Oauth}
|
// @Success 200 {object} response.Response{data=model.Oauth}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/oauth/create [post]
|
// @Router /admin/oauth/create [post]
|
||||||
@@ -202,14 +201,14 @@ func (o *Oauth) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary Oauthlist
|
// @Summary Oauth列表
|
||||||
// @Description Oauthlist
|
// @Description Oauth列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Success 200 {object} response.Response{data=model.OauthList}
|
// @Success 200 {object} response.Response{data=model.OauthList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/oauth/list [get]
|
// @Router /admin/oauth/list [get]
|
||||||
@@ -224,13 +223,13 @@ func (o *Oauth) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary Oauthedit
|
// @Summary Oauth编辑
|
||||||
// @Description Oauthedit
|
// @Description Oauth编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.OauthForm true "Oauthinfo"
|
// @Param body body admin.OauthForm true "Oauth信息"
|
||||||
// @Success 200 {object} response.Response{data=model.OauthList}
|
// @Success 200 {object} response.Response{data=model.OauthList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/oauth/update [post]
|
// @Router /admin/oauth/update [post]
|
||||||
@@ -259,13 +258,13 @@ func (o *Oauth) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary Oauthdelete
|
// @Summary Oauth删除
|
||||||
// @Description Oauthdelete
|
// @Description Oauth删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.OauthForm true "Oauthinfo"
|
// @Param body body admin.OauthForm true "Oauth信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/oauth/delete [post]
|
// @Router /admin/oauth/delete [post]
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ import (
|
|||||||
type Peer struct {
|
type Peer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail device
|
// Detail 设备
|
||||||
// @Tags device
|
// @Tags 设备
|
||||||
// @Summary device details
|
// @Summary 设备详情
|
||||||
// @Description device details
|
// @Description 设备详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -37,13 +37,13 @@ func (ct *Peer) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create device
|
// Create 创建设备
|
||||||
// @Tags device
|
// @Tags 设备
|
||||||
// @Summary create device
|
// @Summary 创建设备
|
||||||
// @Description create device
|
// @Description 创建设备
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerForm true "device info"
|
// @Param body body admin.PeerForm true "设备信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Peer}
|
// @Success 200 {object} response.Response{data=model.Peer}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/create [post]
|
// @Router /admin/peer/create [post]
|
||||||
@@ -68,18 +68,18 @@ func (ct *Peer) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags device
|
// @Tags 设备
|
||||||
// @Summary device list
|
// @Summary 设备列表
|
||||||
// @Description device list
|
// @Description 设备列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param time_ago query int false "time"
|
// @Param time_ago query int false "时间"
|
||||||
// @Param id query string false "ID"
|
// @Param id query string false "ID"
|
||||||
// @Param hostname query string false "hostname"
|
// @Param hostname query string false "主机名"
|
||||||
// @Param uuids query string false "uuids separated by commas"
|
// @Param uuids query string false "uuids 用逗号分隔"
|
||||||
// @Success 200 {object} response.Response{data=model.PeerList}
|
// @Success 200 {object} response.Response{data=model.PeerList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/list [get]
|
// @Router /admin/peer/list [get]
|
||||||
@@ -108,26 +108,17 @@ func (ct *Peer) List(c *gin.Context) {
|
|||||||
if query.Uuids != "" {
|
if query.Uuids != "" {
|
||||||
tx.Where("uuid in (?)", query.Uuids)
|
tx.Where("uuid in (?)", query.Uuids)
|
||||||
}
|
}
|
||||||
if query.Username != "" {
|
|
||||||
tx.Where("username like ?", "%"+query.Username+"%")
|
|
||||||
}
|
|
||||||
if query.Ip != "" {
|
|
||||||
tx.Where("last_online_ip like ?", "%"+query.Ip+"%")
|
|
||||||
}
|
|
||||||
if query.Alias != "" {
|
|
||||||
tx.Where("alias like ?", "%"+query.Alias+"%")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags device
|
// @Tags 设备
|
||||||
// @Summary edit device
|
// @Summary 设备编辑
|
||||||
// @Description edit device
|
// @Description 设备编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerForm true "device info"
|
// @Param body body admin.PeerForm true "设备信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Peer}
|
// @Success 200 {object} response.Response{data=model.Peer}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/update [post]
|
// @Router /admin/peer/update [post]
|
||||||
@@ -156,13 +147,13 @@ func (ct *Peer) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags device
|
// @Tags 设备
|
||||||
// @Summary delete device
|
// @Summary 设备删除
|
||||||
// @Description delete device
|
// @Description 设备删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerForm true "device info"
|
// @Param body body admin.PeerForm true "设备信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/delete [post]
|
// @Router /admin/peer/delete [post]
|
||||||
@@ -192,13 +183,13 @@ func (ct *Peer) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchDelete batch delete
|
// BatchDelete 批量删除
|
||||||
// @Tags device
|
// @Tags 设备
|
||||||
// @Summary batch delete devices
|
// @Summary 批量设备删除
|
||||||
// @Description batch delete devices
|
// @Description 批量设备删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerBatchDeleteForm true "deviceid"
|
// @Param body body admin.PeerBatchDeleteForm true "设备id"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/batchDelete [post]
|
// @Router /admin/peer/batchDelete [post]
|
||||||
@@ -232,7 +223,7 @@ func (ct *Peer) SimpleData(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := service.AllService.PeerService.List(1, 99999, func(tx *gorm.DB) {
|
res := service.AllService.PeerService.List(1, 99999, func(tx *gorm.DB) {
|
||||||
//information that can be made public
|
//可以公开的情报
|
||||||
tx.Select("id,version")
|
tx.Select("id,version")
|
||||||
tx.Where("id in (?)", f.Ids)
|
tx.Where("id in (?)", f.Ids)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func (r *Rustdesk) CmdList(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := service.AllService.ServerCmdService.List(q.Page, 9999)
|
res := service.AllService.ServerCmdService.List(q.Page, 9999)
|
||||||
//add system commands before the list
|
//在列表前添加系统命令
|
||||||
list := make([]*model.ServerCmd, 0)
|
list := make([]*model.ServerCmd, 0)
|
||||||
list = append(list, model.SysIdServerCmds...)
|
list = append(list, model.SysIdServerCmds...)
|
||||||
list = append(list, model.SysRelayServerCmds...)
|
list = append(list, model.SysRelayServerCmds...)
|
||||||
@@ -119,16 +119,7 @@ func (r *Rustdesk) SendCmd(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
res, err := service.AllService.ServerCmdService.SendCmd(rc.Target, rc.Cmd, rc.Option)
|
||||||
port := 0
|
|
||||||
switch rc.Target {
|
|
||||||
case model.ServerCmdTargetIdServer:
|
|
||||||
port = global.Config.Admin.IdServerPort - 1
|
|
||||||
case model.ServerCmdTargetRelayServer:
|
|
||||||
port = global.Config.Admin.RelayServerPort
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := service.AllService.ServerCmdService.SendCmd(port, rc.Cmd, rc.Option)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, err.Error())
|
response.Fail(c, 101, err.Error())
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ import (
|
|||||||
type ShareRecord struct {
|
type ShareRecord struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags share record
|
// @Tags 分享记录
|
||||||
// @Summary share record list
|
// @Summary 分享记录列表
|
||||||
// @Description share record list
|
// @Description 分享记录列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param user_id query int false "userID"
|
// @Param user_id query int false "用户ID"
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/share_record/list [get]
|
// @Router /admin/share_record/list [get]
|
||||||
@@ -39,13 +39,13 @@ func (sr *ShareRecord) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags share record
|
// @Tags 分享记录
|
||||||
// @Summary delete share record
|
// @Summary 分享记录删除
|
||||||
// @Description delete share record
|
// @Description 分享记录删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.ShareRecordForm true "share record info"
|
// @Param body body admin.ShareRecordForm true "分享记录信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/share_record/delete [post]
|
// @Router /admin/share_record/delete [post]
|
||||||
@@ -75,10 +75,10 @@ func (sr *ShareRecord) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchDelete batch delete
|
// BatchDelete 批量删除
|
||||||
// @Tags share record
|
// @Tags 分享记录
|
||||||
// @Summary batch share records
|
// @Summary 批量分享记录
|
||||||
// @Description batch share records
|
// @Description 批量分享记录
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerShareRecordBatchDeleteForm true "id"
|
// @Param body body admin.PeerShareRecordBatchDeleteForm true "id"
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
type Tag struct {
|
type Tag struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail tag
|
// Detail 标签
|
||||||
// @Tags tag
|
// @Tags 标签
|
||||||
// @Summary tag details
|
// @Summary 标签详情
|
||||||
// @Description tag details
|
// @Description 标签详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -41,13 +41,13 @@ func (ct *Tag) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create create tag
|
// Create 创建标签
|
||||||
// @Tags tag
|
// @Tags 标签
|
||||||
// @Summary create tag
|
// @Summary 创建标签
|
||||||
// @Description create tag
|
// @Description 创建标签
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.TagForm true "tag info"
|
// @Param body body admin.TagForm true "标签信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Tag}
|
// @Success 200 {object} response.Response{data=model.Tag}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/tag/create [post]
|
// @Router /admin/tag/create [post]
|
||||||
@@ -76,16 +76,16 @@ func (ct *Tag) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags tag
|
// @Tags 标签
|
||||||
// @Summary tag list
|
// @Summary 标签列表
|
||||||
// @Description tag list
|
// @Description 标签列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param is_my query int false "whether it is mine"
|
// @Param is_my query int false "是否是我的"
|
||||||
// @Param user_id query int false "userid"
|
// @Param user_id query int false "用户id"
|
||||||
// @Success 200 {object} response.Response{data=model.TagList}
|
// @Success 200 {object} response.Response{data=model.TagList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/tag/list [get]
|
// @Router /admin/tag/list [get]
|
||||||
@@ -110,13 +110,13 @@ func (ct *Tag) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags tag
|
// @Tags 标签
|
||||||
// @Summary edit tag
|
// @Summary 标签编辑
|
||||||
// @Description edit tag
|
// @Description 标签编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.TagForm true "tag info"
|
// @Param body body admin.TagForm true "标签信息"
|
||||||
// @Success 200 {object} response.Response{data=model.Tag}
|
// @Success 200 {object} response.Response{data=model.Tag}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/tag/update [post]
|
// @Router /admin/tag/update [post]
|
||||||
@@ -150,13 +150,13 @@ func (ct *Tag) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags tag
|
// @Tags 标签
|
||||||
// @Summary delete tag
|
// @Summary 标签删除
|
||||||
// @Description delete tag
|
// @Description 标签删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.TagForm true "tag info"
|
// @Param body body admin.TagForm true "标签信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/tag/delete [post]
|
// @Router /admin/tag/delete [post]
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
adResp "github.com/lejianwen/rustdesk-api/v2/http/response/admin"
|
adResp "github.com/lejianwen/rustdesk-api/v2/http/response/admin"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@@ -16,10 +15,10 @@ import (
|
|||||||
type User struct {
|
type User struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail administrator
|
// Detail 管理员
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary administrator details
|
// @Summary 管理员详情
|
||||||
// @Description administrator details
|
// @Description 管理员详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -39,13 +38,13 @@ func (ct *User) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create administrator
|
// Create 管理员
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary create administrator
|
// @Summary 创建管理员
|
||||||
// @Description create administrator
|
// @Description 创建管理员
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.UserForm true "administrator info"
|
// @Param body body admin.UserForm true "管理员信息"
|
||||||
// @Success 200 {object} response.Response{data=model.User}
|
// @Success 200 {object} response.Response{data=model.User}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/create [post]
|
// @Router /admin/user/create [post]
|
||||||
@@ -70,15 +69,15 @@ func (ct *User) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary administrator list
|
// @Summary 管理员列表
|
||||||
// @Description administrator list
|
// @Description 管理员列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param username query int false "account"
|
// @Param username query int false "账户"
|
||||||
// @Success 200 {object} response.Response{data=model.UserList}
|
// @Success 200 {object} response.Response{data=model.UserList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/list [get]
|
// @Router /admin/user/list [get]
|
||||||
@@ -97,13 +96,13 @@ func (ct *User) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update edit
|
// Update 编辑
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary edit administrator
|
// @Summary 管理员编辑
|
||||||
// @Description edit administrator
|
// @Description 管理员编辑
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.UserForm true "user info"
|
// @Param body body admin.UserForm true "用户信息"
|
||||||
// @Success 200 {object} response.Response{data=model.User}
|
// @Success 200 {object} response.Response{data=model.User}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/update [post]
|
// @Router /admin/user/update [post]
|
||||||
@@ -132,13 +131,13 @@ func (ct *User) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary delete administrator
|
// @Summary 管理员删除
|
||||||
// @Description delete administrator
|
// @Description 管理员编删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.UserForm true "user info"
|
// @Param body body admin.UserForm true "用户信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/delete [post]
|
// @Router /admin/user/delete [post]
|
||||||
@@ -168,13 +167,13 @@ func (ct *User) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePassword change password
|
// UpdatePassword 修改密码
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary change password
|
// @Summary 修改密码
|
||||||
// @Description change password
|
// @Description 修改密码
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.UserPasswordForm true "user info"
|
// @Param body body admin.UserPasswordForm true "用户信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/updatePassword [post]
|
// @Router /admin/user/updatePassword [post]
|
||||||
@@ -203,10 +202,10 @@ func (ct *User) UpdatePassword(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current current user
|
// Current 当前用户
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary current user
|
// @Summary 当前用户
|
||||||
// @Description current user
|
// @Description 当前用户
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
||||||
@@ -220,13 +219,13 @@ func (ct *User) Current(c *gin.Context) {
|
|||||||
responseLoginSuccess(c, u, t)
|
responseLoginSuccess(c, u, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeCurPwd change the current user's password
|
// ChangeCurPwd 修改当前用户密码
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary change the current user's password
|
// @Summary 修改当前用户密码
|
||||||
// @Description change the current user's password
|
// @Description 修改当前用户密码
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.ChangeCurPasswordForm true "user info"
|
// @Param body body admin.ChangeCurPasswordForm true "用户信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/changeCurPwd [post]
|
// @Router /admin/user/changeCurPwd [post]
|
||||||
@@ -244,10 +243,11 @@ func (ct *User) ChangeCurPwd(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
// Verify the old password only when the account already has one set
|
// If the password is not empty, the old password is verified
|
||||||
|
// otherwise, the old password is not verified
|
||||||
if !service.AllService.UserService.IsPasswordEmptyByUser(u) {
|
if !service.AllService.UserService.IsPasswordEmptyByUser(u) {
|
||||||
ok, _, err := utils.VerifyPassword(u.Password, f.OldPassword)
|
oldPwd := service.AllService.UserService.EncryptPassword(f.OldPassword)
|
||||||
if err != nil || !ok {
|
if u.Password != oldPwd {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "OldPasswordError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "OldPasswordError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -261,9 +261,9 @@ func (ct *User) ChangeCurPwd(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MyOauth
|
// MyOauth
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary my authorizations
|
// @Summary 我的授权
|
||||||
// @Description my authorizations
|
// @Description 我的授权
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response{data=[]adResp.UserOauthItem}
|
// @Success 200 {object} response.Response{data=[]adResp.UserOauthItem}
|
||||||
@@ -296,12 +296,32 @@ func (ct *User) MyOauth(c *gin.Context) {
|
|||||||
|
|
||||||
// groupUsers
|
// groupUsers
|
||||||
func (ct *User) GroupUsers(c *gin.Context) {
|
func (ct *User) GroupUsers(c *gin.Context) {
|
||||||
aG := service.AllService.GroupService.List(1, 999, nil)
|
q := &admin.GroupUsersQuery{}
|
||||||
aU := service.AllService.UserService.List(1, 9999, nil)
|
if err := c.ShouldBindJSON(q); err != nil {
|
||||||
response.Success(c, gin.H{
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
"groups": aG.Groups,
|
return
|
||||||
"users": aU.Users,
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
gid := u.GroupId
|
||||||
|
uid := u.Id
|
||||||
|
if service.AllService.UserService.IsAdmin(u) && q.UserId > 0 {
|
||||||
|
nu := service.AllService.UserService.InfoById(q.UserId)
|
||||||
|
gid = nu.GroupId
|
||||||
|
uid = q.UserId
|
||||||
|
}
|
||||||
|
res := service.AllService.UserService.List(1, 999, func(tx *gorm.DB) {
|
||||||
|
tx.Where("group_id = ?", gid)
|
||||||
})
|
})
|
||||||
|
var data []*adResp.GroupUsersPayload
|
||||||
|
for _, _u := range res.Users {
|
||||||
|
gup := &adResp.GroupUsersPayload{}
|
||||||
|
gup.FromUser(_u)
|
||||||
|
if _u.Id == uid {
|
||||||
|
gup.Status = 0
|
||||||
|
}
|
||||||
|
data = append(data, gup)
|
||||||
|
}
|
||||||
|
response.Success(c, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
@@ -320,23 +340,12 @@ func (ct *User) Register(c *gin.Context) {
|
|||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
regStatus := model.StatusCode(global.Config.App.RegisterStatus)
|
u := service.AllService.UserService.Register(f.Username, f.Email, f.Password)
|
||||||
// the registration status may not be configured; enabled by default
|
|
||||||
if regStatus != model.COMMON_STATUS_DISABLED && regStatus != model.COMMON_STATUS_ENABLE {
|
|
||||||
regStatus = model.COMMON_STATUS_ENABLE
|
|
||||||
}
|
|
||||||
|
|
||||||
u := service.AllService.UserService.Register(f.Username, f.Email, f.Password, regStatus)
|
|
||||||
if u == nil || u.Id == 0 {
|
if u == nil || u.Id == 0 {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed"))
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if regStatus == model.COMMON_STATUS_DISABLED {
|
// 注册成功后自动登录
|
||||||
// requires administrator approval
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "RegisterSuccessWaitAdminConfirm"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// automatically log in after successful registration
|
|
||||||
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
Client: model.LoginLogClientWebAdmin,
|
Client: model.LoginLogClientWebAdmin,
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ import (
|
|||||||
type UserToken struct {
|
type UserToken struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List list
|
// List 列表
|
||||||
// @Tags login credential
|
// @Tags 登录凭证
|
||||||
// @Summary login credential list
|
// @Summary 登录凭证列表
|
||||||
// @Description login credential list
|
// @Description 登录凭证列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "page size"
|
// @Param page_size query int false "页大小"
|
||||||
// @Param user_id query int false "userID"
|
// @Param user_id query int false "用户ID"
|
||||||
// @Success 200 {object} response.Response{data=model.UserTokenList}
|
// @Success 200 {object} response.Response{data=model.UserTokenList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user_token/list [get]
|
// @Router /admin/user_token/list [get]
|
||||||
@@ -41,13 +41,13 @@ func (ct *UserToken) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete
|
// Delete 删除
|
||||||
// @Tags login credential
|
// @Tags 登录凭证
|
||||||
// @Summary delete login credential
|
// @Summary 登录凭证删除
|
||||||
// @Description delete login credential
|
// @Description 登录凭证删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.UserToken true "login credential info"
|
// @Param body body model.UserToken true "登录凭证信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user_token/delete [post]
|
// @Router /admin/user_token/delete [post]
|
||||||
@@ -82,13 +82,13 @@ func (ct *UserToken) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchDelete batch delete
|
// BatchDelete 批量删除
|
||||||
// @Tags login credential
|
// @Tags 登录凭证
|
||||||
// @Summary batch delete login credentials
|
// @Summary 登录凭证批量删除
|
||||||
// @Description batch delete login credentials
|
// @Description 登录凭证批量删除
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.UserTokenBatchDeleteForm true "login credential info"
|
// @Param body body admin.UserTokenBatchDeleteForm true "登录凭证信息"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user_token/batchDelete [post]
|
// @Router /admin/user_token/batchDelete [post]
|
||||||
|
|||||||
+58
-58
@@ -20,9 +20,9 @@ type Ab struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ab
|
// Ab
|
||||||
// @Tags address
|
// @Tags 地址
|
||||||
// @Summary address list
|
// @Summary 地址列表
|
||||||
// @Description address list
|
// @Description 地址列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -36,7 +36,7 @@ func (a *Ab) Ab(c *gin.Context) {
|
|||||||
tags := service.AllService.TagService.ListByUserIdAndCollectionId(user.Id, 0)
|
tags := service.AllService.TagService.ListByUserIdAndCollectionId(user.Id, 0)
|
||||||
|
|
||||||
tagColors := map[string]uint{}
|
tagColors := map[string]uint{}
|
||||||
// convert the name in tags into a comma-separated string
|
//将tags中的name转成一个以逗号分割的字符串
|
||||||
var tagNames []string
|
var tagNames []string
|
||||||
for _, tag := range tags.Tags {
|
for _, tag := range tags.Tags {
|
||||||
tagNames = append(tagNames, tag.Name)
|
tagNames = append(tagNames, tag.Name)
|
||||||
@@ -56,12 +56,12 @@ func (a *Ab) Ab(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpAb
|
// UpAb
|
||||||
// @Tags address
|
// @Tags 地址
|
||||||
// @Summary address update
|
// @Summary 地址更新
|
||||||
// @Description address update
|
// @Description 地址更新
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body requstform.AddressBookForm true "address form"
|
// @Param body body requstform.AddressBookForm true "地址表单"
|
||||||
// @Success 200 {string} string "null"
|
// @Success 200 {string} string "null"
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /ab [post]
|
// @Router /ab [post]
|
||||||
@@ -99,9 +99,9 @@ func (a *Ab) UpAb(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PTags
|
// PTags
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary tag
|
// @Summary 标签
|
||||||
// @Description tag
|
// @Description 标签
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -128,9 +128,9 @@ func (a *Ab) PTags(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TagAdd
|
// TagAdd
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary add tag
|
// @Summary 标签添加
|
||||||
// @Description tag
|
// @Description 标签
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -177,9 +177,9 @@ func (a *Ab) TagAdd(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TagRename
|
// TagRename
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary rename tag
|
// @Summary 标签重命名
|
||||||
// @Description tag
|
// @Description 标签
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -229,9 +229,9 @@ func (a *Ab) TagRename(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TagUpdate
|
// TagUpdate
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary change tag color
|
// @Summary 标签修改颜色
|
||||||
// @Description tag
|
// @Description 标签
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -275,9 +275,9 @@ func (a *Ab) TagUpdate(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TagDel
|
// TagDel
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary delete tag
|
// @Summary 标签删除
|
||||||
// @Description tag
|
// @Description 标签
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -324,9 +324,9 @@ func (a *Ab) TagDel(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Personal
|
// Personal
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary personal address
|
// @Summary 个人地址
|
||||||
// @Description personal address
|
// @Description 个人地址
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param string body string false "string valid"
|
// @Param string body string false "string valid"
|
||||||
@@ -345,7 +345,7 @@ func (a *Ab) Personal(c *gin.Context) {
|
|||||||
*/
|
*/
|
||||||
if global.Config.Rustdesk.Personal == 1 {
|
if global.Config.Rustdesk.Personal == 1 {
|
||||||
guid := a.ComposeGuid(user.GroupId, user.Id, 0)
|
guid := a.ComposeGuid(user.GroupId, user.Id, 0)
|
||||||
//if it returns guid, subsequent requests will change
|
//如果返回了guid,后面的请求会有变化
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"guid": guid,
|
"guid": guid,
|
||||||
"name": user.Username,
|
"name": user.Username,
|
||||||
@@ -358,9 +358,9 @@ func (a *Ab) Personal(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary settings
|
// @Summary 设置
|
||||||
// @Description settings
|
// @Description 设置
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param string body string false "string valid"
|
// @Param string body string false "string valid"
|
||||||
@@ -370,18 +370,18 @@ func (a *Ab) Personal(c *gin.Context) {
|
|||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
func (a *Ab) Settings(c *gin.Context) {
|
func (a *Ab) Settings(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"max_peer_one_ab": 0, //max peer count, 0 means no limit
|
"max_peer_one_ab": 0, //最大peer数,0表示不限制
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SharedProfiles
|
// SharedProfiles
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary shared address book
|
// @Summary 共享地址簿
|
||||||
// @Description shared
|
// @Description 共享
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param current query int false "page number"
|
// @Param current query int false "页码"
|
||||||
// @Param pageSize query int false "items per page"
|
// @Param pageSize query int false "每页数量"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /ab/shared/profiles [post]
|
// @Router /ab/shared/profiles [post]
|
||||||
@@ -401,14 +401,14 @@ func (a *Ab) SharedProfiles(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
allAbIds := make(map[uint]int) //use map to deduplicate and keep the maximum Rule
|
allAbIds := make(map[uint]int) //用map去重,并保留最大Rule
|
||||||
allUserIds := make(map[uint]*model.User)
|
allUserIds := make(map[uint]*model.User)
|
||||||
rules := service.AllService.AddressBookService.CollectionReadRules(user)
|
rules := service.AllService.AddressBookService.CollectionReadRules(user)
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
//first check whether it exists
|
//先判断是否存在
|
||||||
r, ok := allAbIds[rule.CollectionId]
|
r, ok := allAbIds[rule.CollectionId]
|
||||||
if ok {
|
if ok {
|
||||||
//then check the permission level
|
//再判断权限大小
|
||||||
if r < rule.Rule {
|
if r < rule.Rule {
|
||||||
allAbIds[rule.CollectionId] = rule.Rule
|
allAbIds[rule.CollectionId] = rule.Rule
|
||||||
}
|
}
|
||||||
@@ -448,7 +448,7 @@ func (a *Ab) SharedProfiles(c *gin.Context) {
|
|||||||
|
|
||||||
// ParseGuid
|
// ParseGuid
|
||||||
func (a *Ab) ParseGuid(guid string) (gid, uid, cid uint) {
|
func (a *Ab) ParseGuid(guid string) (gid, uid, cid uint) {
|
||||||
// split guid by -
|
//用-切割 guid
|
||||||
guids := strings.Split(guid, "-")
|
guids := strings.Split(guid, "-")
|
||||||
if len(guids) < 2 {
|
if len(guids) < 2 {
|
||||||
return 0, 0, 0
|
return 0, 0, 0
|
||||||
@@ -521,13 +521,13 @@ func (a *Ab) CheckGuid(cu *model.User, guid string) (gid, uid, cid uint, err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Peers
|
// Peers
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary address list
|
// @Summary 地址列表
|
||||||
// @Description address
|
// @Description 地址
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param current query int false "page number"
|
// @Param current query int false "页码"
|
||||||
// @Param pageSize query int false "items per page"
|
// @Param pageSize query int false "每页数量"
|
||||||
// @Param ab query string false "guid"
|
// @Param ab query string false "guid"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
@@ -557,9 +557,9 @@ func (a *Ab) Peers(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerAdd
|
// PeerAdd
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary add address
|
// @Summary 添加地址
|
||||||
// @Description add address
|
// @Description 添加地址
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -568,7 +568,7 @@ func (a *Ab) Peers(c *gin.Context) {
|
|||||||
// @Router /ab/peer/add/{guid} [post]
|
// @Router /ab/peer/add/{guid} [post]
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
func (a *Ab) PeerAdd(c *gin.Context) {
|
func (a *Ab) PeerAdd(c *gin.Context) {
|
||||||
// forceAlwaysRelay is always the string "false"
|
// forceAlwaysRelay永远是字符串"false"
|
||||||
//f := &gin.H{}
|
//f := &gin.H{}
|
||||||
f := &requstform.PersonalAddressBookForm{}
|
f := &requstform.PersonalAddressBookForm{}
|
||||||
err := c.ShouldBindJSON(f)
|
err := c.ShouldBindJSON(f)
|
||||||
@@ -613,9 +613,9 @@ func (a *Ab) PeerAdd(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerDel
|
// PeerDel
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary delete address
|
// @Summary 删除地址
|
||||||
// @Description delete address
|
// @Description 删除地址
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -661,9 +661,9 @@ func (a *Ab) PeerDel(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerUpdate
|
// PeerUpdate
|
||||||
// @Tags address[Personal]
|
// @Tags 地址[Personal]
|
||||||
// @Summary update address
|
// @Summary 更新地址
|
||||||
// @Description update address
|
// @Description 更新地址
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -693,7 +693,7 @@ func (a *Ab) PeerUpdate(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
//fmt.Println(f)
|
//fmt.Println(f)
|
||||||
// determine whether f["Id"] exists
|
//判断f["Id"]是否存在
|
||||||
fid, ok := f["id"]
|
fid, ok := f["id"]
|
||||||
if !ok {
|
if !ok {
|
||||||
response.Error(c, response.TranslateMsg(c, "ParamsError"))
|
response.Error(c, response.TranslateMsg(c, "ParamsError"))
|
||||||
@@ -706,9 +706,9 @@ func (a *Ab) PeerUpdate(c *gin.Context) {
|
|||||||
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//allowed fields
|
//允许的字段
|
||||||
allowUp := []string{"password", "hash", "tags", "alias"}
|
allowUp := []string{"password", "hash", "tags", "alias"}
|
||||||
// if a field in f is not in allowUp, delete it
|
//f中的字段如果不在allowUp中,就删除
|
||||||
for k := range f {
|
for k := range f {
|
||||||
if !utils.InArray(k, allowUp) {
|
if !utils.InArray(k, allowUp) {
|
||||||
delete(f, k)
|
delete(f, k)
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ type Audit struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AuditConn
|
// AuditConn
|
||||||
// @Tags audit
|
// @Tags 审计
|
||||||
// @Summary audit connection
|
// @Summary 审计连接
|
||||||
// @Description audit connection
|
// @Description 审计连接
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body request.AuditConnForm true "audit connection"
|
// @Param body body request.AuditConnForm true "审计连接"
|
||||||
// @Success 200 {string} string ""
|
// @Success 200 {string} string ""
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /audit/conn [post]
|
// @Router /audit/conn [post]
|
||||||
@@ -59,12 +59,12 @@ func (a *Audit) AuditConn(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AuditFile
|
// AuditFile
|
||||||
// @Tags audit
|
// @Tags 审计
|
||||||
// @Summary audit file
|
// @Summary 审计文件
|
||||||
// @Description audit file
|
// @Description 审计文件
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body request.AuditFileForm true "audit file"
|
// @Param body body request.AuditFileForm true "审计文件"
|
||||||
// @Success 200 {string} string ""
|
// @Success 200 {string} string ""
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /audit/file [post]
|
// @Router /audit/file [post]
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ import (
|
|||||||
type Group struct {
|
type Group struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Users user list
|
// Users 用户列表
|
||||||
// @Tags group
|
// @Tags 群组
|
||||||
// @Summary user list
|
// @Summary 用户列表
|
||||||
// @Description user list
|
// @Description 用户列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param pageSize query int false "items per page"
|
// @Param pageSize query int false "每页数量"
|
||||||
// @Param status query int false "status"
|
// @Param status query int false "状态"
|
||||||
// @Param accessible query string false "accessible"
|
// @Param accessible query string false "accessible"
|
||||||
// @Success 200 {object} response.DataResponse{data=[]apiResp.UserPayload}
|
// @Success 200 {object} response.DataResponse{data=[]apiResp.UserPayload}
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
@@ -38,7 +38,7 @@ func (g *Group) Users(c *gin.Context) {
|
|||||||
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
||||||
userList := &model.UserList{}
|
userList := &model.UserList{}
|
||||||
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
|
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
|
||||||
//can only retrieve one's own
|
//仅能获取到自己
|
||||||
userList.Users = append(userList.Users, u)
|
userList.Users = append(userList.Users, u)
|
||||||
userList.Total = 1
|
userList.Total = 1
|
||||||
} else {
|
} else {
|
||||||
@@ -58,14 +58,14 @@ func (g *Group) Users(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Peers
|
// Peers
|
||||||
// @Tags group
|
// @Tags 群组
|
||||||
// @Summary machine
|
// @Summary 机器
|
||||||
// @Description machine
|
// @Description 机器
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param pageSize query int false "items per page"
|
// @Param pageSize query int false "每页数量"
|
||||||
// @Param status query int false "status"
|
// @Param status query int false "状态"
|
||||||
// @Param accessible query string false "accessible"
|
// @Param accessible query string false "accessible"
|
||||||
// @Success 200 {object} response.DataResponse
|
// @Success 200 {object} response.DataResponse
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
@@ -82,7 +82,7 @@ func (g *Group) Peers(c *gin.Context) {
|
|||||||
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
||||||
users := make([]*model.User, 0, 1)
|
users := make([]*model.User, 0, 1)
|
||||||
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
|
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
|
||||||
//can only retrieve one's own
|
//仅能获取到自己
|
||||||
users = append(users, u)
|
users = append(users, u)
|
||||||
} else {
|
} else {
|
||||||
users = service.AllService.UserService.ListIdAndNameByGroupId(u.GroupId)
|
users = service.AllService.UserService.ListIdAndNameByGroupId(u.GroupId)
|
||||||
@@ -122,14 +122,14 @@ func (g *Group) Peers(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Device
|
// Device
|
||||||
// @Tags group
|
// @Tags 群组
|
||||||
// @Summary device
|
// @Summary 设备
|
||||||
// @Description machine
|
// @Description 机器
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param page query int false "页码"
|
||||||
// @Param pageSize query int false "items per page"
|
// @Param pageSize query int false "每页数量"
|
||||||
// @Param status query int false "status"
|
// @Param status query int false "状态"
|
||||||
// @Param accessible query string false "accessible"
|
// @Param accessible query string false "accessible"
|
||||||
// @Success 200 {object} response.DataResponse
|
// @Success 200 {object} response.DataResponse
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
|
|||||||
@@ -7,16 +7,17 @@ import (
|
|||||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Index struct {
|
type Index struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index home
|
// Index 首页
|
||||||
// @Tags home
|
// @Tags 首页
|
||||||
// @Summary home
|
// @Summary 首页
|
||||||
// @Description home
|
// @Description 首页
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -29,10 +30,10 @@ func (i *Index) Index(c *gin.Context) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heartbeat heartbeat
|
// Heartbeat 心跳
|
||||||
// @Tags home
|
// @Tags 首页
|
||||||
// @Summary heartbeat
|
// @Summary 心跳
|
||||||
// @Description heartbeat
|
// @Description 心跳
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} nil
|
// @Success 200 {object} nil
|
||||||
@@ -49,33 +50,37 @@ func (i *Index) Heartbeat(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, gin.H{})
|
c.JSON(http.StatusOK, gin.H{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
peer := service.AllService.PeerService.FindById(info.Id)
|
peer := service.AllService.PeerService.FindByUuid(info.Uuid)
|
||||||
if peer == nil || peer.RowId == 0 {
|
if peer == nil || peer.RowId == 0 {
|
||||||
c.JSON(http.StatusOK, gin.H{})
|
c.JSON(http.StatusOK, gin.H{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// do not update if within 40s
|
//如果在40s以内则不更新
|
||||||
if time.Now().Unix()-peer.LastOnlineTime >= 30 {
|
if time.Now().Unix()-peer.LastOnlineTime > 40 {
|
||||||
upp := &model.Peer{RowId: peer.RowId, LastOnlineTime: time.Now().Unix(), LastOnlineIp: c.ClientIP()}
|
upp := &model.Peer{RowId: peer.RowId, LastOnlineTime: time.Now().Unix(), LastOnlineIp: c.ClientIP()}
|
||||||
service.AllService.PeerService.Update(upp)
|
service.AllService.PeerService.Update(upp)
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, gin.H{})
|
c.JSON(http.StatusOK, gin.H{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version version
|
// Version 版本
|
||||||
// @Tags home
|
// @Tags 首页
|
||||||
// @Summary version
|
// @Summary 版本
|
||||||
// @Description version
|
// @Description 版本
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /version [get]
|
// @Router /version [get]
|
||||||
func (i *Index) Version(c *gin.Context) {
|
func (i *Index) Version(c *gin.Context) {
|
||||||
// read the resources/version file
|
//读取resources/version文件
|
||||||
v := service.AllService.AppService.GetAppVersion()
|
v, err := os.ReadFile("resources/version")
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
response.Success(
|
response.Success(
|
||||||
c,
|
c,
|
||||||
v,
|
string(v),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ import (
|
|||||||
type Login struct {
|
type Login struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login login
|
// Login 登录
|
||||||
// @Tags login
|
// @Tags 登录
|
||||||
// @Summary login
|
// @Summary 登录
|
||||||
// @Description login
|
// @Description 登录
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body api.LoginForm true "login form"
|
// @Param body body api.LoginForm true "登录表单"
|
||||||
// @Success 200 {object} apiResp.LoginRes
|
// @Success 200 {object} apiResp.LoginRes
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /login [post]
|
// @Router /login [post]
|
||||||
@@ -31,16 +31,10 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
response.Error(c, response.TranslateMsg(c, "PwdLoginDisabled"))
|
response.Error(c, response.TranslateMsg(c, "PwdLoginDisabled"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check login limit
|
|
||||||
loginLimiter := global.LoginLimiter
|
|
||||||
clientIp := c.ClientIP()
|
|
||||||
|
|
||||||
f := &api.LoginForm{}
|
f := &api.LoginForm{}
|
||||||
err := c.ShouldBindJSON(f)
|
err := c.ShouldBindJSON(f)
|
||||||
//fmt.Println(f)
|
//fmt.Println(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loginLimiter.RecordFailedAttempt(clientIp)
|
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
@@ -48,7 +42,6 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
|
|
||||||
errList := global.Validator.ValidStruct(c, f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
loginLimiter.RecordFailedAttempt(clientIp)
|
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Error(c, errList[0])
|
response.Error(c, errList[0])
|
||||||
return
|
return
|
||||||
@@ -57,7 +50,6 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
||||||
|
|
||||||
if u.Id == 0 {
|
if u.Id == 0 {
|
||||||
loginLimiter.RecordFailedAttempt(clientIp)
|
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Error(c, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
response.Error(c, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||||
return
|
return
|
||||||
@@ -68,7 +60,7 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine whether it is webclient or app based on refer
|
//根据refer判断是webclient还是app
|
||||||
ref := c.GetHeader("referer")
|
ref := c.GetHeader("referer")
|
||||||
if ref != "" {
|
if ref != "" {
|
||||||
f.DeviceInfo.Type = model.LoginLogClientWeb
|
f.DeviceInfo.Type = model.LoginLogClientWeb
|
||||||
@@ -92,9 +84,9 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoginOptions
|
// LoginOptions
|
||||||
// @Tags login
|
// @Tags 登录
|
||||||
// @Summary login options
|
// @Summary 登录选项
|
||||||
// @Description login options
|
// @Description 登录选项
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} []string
|
// @Success 200 {object} []string
|
||||||
@@ -123,9 +115,9 @@ func (l *Login) LoginOptions(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Logout
|
// Logout
|
||||||
// @Tags login
|
// @Tags 登录
|
||||||
// @Summary logout
|
// @Summary 登出
|
||||||
// @Description logout
|
// @Description 登出
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {string} string
|
// @Success 200 {string} string
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
"github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
@@ -10,8 +8,7 @@ import (
|
|||||||
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
"net/http"
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Oauth struct {
|
type Oauth struct {
|
||||||
@@ -65,37 +62,36 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken)
|
|||||||
var ut *model.UserToken
|
var ut *model.UserToken
|
||||||
q := &api.OidcAuthQuery{}
|
q := &api.OidcAuthQuery{}
|
||||||
|
|
||||||
// parse query parameters and handle errors
|
// 解析查询参数并处理错误
|
||||||
if err := c.ShouldBindQuery(q); err != nil {
|
if err := c.ShouldBindQuery(q); err != nil {
|
||||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+": "+err.Error())
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+": "+err.Error())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// get OAuth cache
|
// 获取 OAuth 缓存
|
||||||
v := service.AllService.OauthService.GetOauthCache(q.Code)
|
v := service.AllService.OauthService.GetOauthCache(q.Code)
|
||||||
if v == nil {
|
if v == nil {
|
||||||
response.Error(c, response.TranslateMsg(c, "OauthExpired"))
|
response.Error(c, response.TranslateMsg(c, "OauthExpired"))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// if UserId is 0, authorization is still in progress
|
// 如果 UserId 为 0,说明还在授权中
|
||||||
if v.UserId == 0 {
|
if v.UserId == 0 {
|
||||||
//fix: 1.4.2 webclient oidc
|
c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress, please login and bind"})
|
||||||
c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress, please login and bind", "error": "No authed oidc is found"})
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// get user info
|
// 获取用户信息
|
||||||
u = service.AllService.UserService.InfoById(v.UserId)
|
u = service.AllService.UserService.InfoById(v.UserId)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
response.Error(c, response.TranslateMsg(c, "UserNotFound"))
|
response.Error(c, response.TranslateMsg(c, "UserNotFound"))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete OAuth cache
|
// 删除 OAuth 缓存
|
||||||
service.AllService.OauthService.DeleteOauthCache(q.Code)
|
service.AllService.OauthService.DeleteOauthCache(q.Code)
|
||||||
|
|
||||||
// create a login log and generate a user token
|
// 创建登录日志并生成用户令牌
|
||||||
ut = service.AllService.UserService.Login(u, &model.LoginLog{
|
ut = service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
Client: v.DeviceType,
|
Client: v.DeviceType,
|
||||||
@@ -111,7 +107,7 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken)
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// return user token
|
// 返回用户令牌
|
||||||
return u, ut
|
return u, ut
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +132,7 @@ func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// OauthCallback callback
|
// OauthCallback 回调
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary OauthCallback
|
// @Summary OauthCallback
|
||||||
// @Description OauthCallback
|
// @Description OauthCallback
|
||||||
@@ -144,23 +140,22 @@ func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} apiResp.LoginRes
|
// @Success 200 {object} apiResp.LoginRes
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /oidc/callback [get]
|
// @Router /oauth/callback [get]
|
||||||
func (o *Oauth) OauthCallback(c *gin.Context) {
|
func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||||
state := c.Query("state")
|
state := c.Query("state")
|
||||||
if state == "" {
|
if state == "" {
|
||||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
"message": "ParamIsEmpty",
|
"message": response.TranslateParamMsg(c, "ParamIsEmpty", "state"),
|
||||||
"sub_message": "state",
|
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cacheKey := state
|
cacheKey := state
|
||||||
oauthService := service.AllService.OauthService
|
oauthService := service.AllService.OauthService
|
||||||
//get from cache
|
//从缓存中获取
|
||||||
oauthCache := oauthService.GetOauthCache(cacheKey)
|
oauthCache := oauthService.GetOauthCache(cacheKey)
|
||||||
if oauthCache == nil {
|
if oauthCache == nil {
|
||||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
"message": "OauthExpired",
|
"message": response.TranslateMsg(c, "OauthExpired"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -169,13 +164,12 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
action := oauthCache.Action
|
action := oauthCache.Action
|
||||||
verifier := oauthCache.Verifier
|
verifier := oauthCache.Verifier
|
||||||
var user *model.User
|
var user *model.User
|
||||||
// get user info
|
// 获取用户信息
|
||||||
code := c.Query("code")
|
code := c.Query("code")
|
||||||
err, oauthUser := oauthService.Callback(code, verifier, op, nonce)
|
err, oauthUser := oauthService.Callback(code, verifier, op, nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
"message": "OauthFailed",
|
"message": response.TranslateMsg(c, "OauthFailed") + response.TranslateMsg(c, err.Error()),
|
||||||
"sub_message": err.Error(),
|
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -184,40 +178,40 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
if action == service.OauthActionTypeBind {
|
if action == service.OauthActionTypeBind {
|
||||||
|
|
||||||
//fmt.Println("bind", ty, userData)
|
//fmt.Println("bind", ty, userData)
|
||||||
// check whether this openid has already been bound
|
// 检查此openid是否已经绑定过
|
||||||
utr := oauthService.UserThirdInfo(op, openid)
|
utr := oauthService.UserThirdInfo(op, openid)
|
||||||
if utr.UserId > 0 {
|
if utr.UserId > 0 {
|
||||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
"message": "OauthHasBindOtherUser",
|
"message": response.TranslateMsg(c, "OauthHasBindOtherUser"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//bind
|
//绑定
|
||||||
user = service.AllService.UserService.InfoById(userId)
|
user = service.AllService.UserService.InfoById(userId)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
"message": "ItemNotFound",
|
"message": response.TranslateMsg(c, "ItemNotFound"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//bind
|
//绑定
|
||||||
err := oauthService.BindOauthUser(userId, oauthUser, op)
|
err := oauthService.BindOauthUser(userId, oauthUser, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
"message": "BindFail",
|
"message": response.TranslateMsg(c, "BindFail"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
||||||
"message": "BindSuccess",
|
"message": response.TranslateMsg(c, "BindSuccess"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|
||||||
} else if action == service.OauthActionTypeLogin {
|
} else if action == service.OauthActionTypeLogin {
|
||||||
//login
|
//登录
|
||||||
if userId != 0 {
|
if userId != 0 {
|
||||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
"message": "OauthHasBeenSuccess",
|
"message": response.TranslateMsg(c, "OauthHasBeenSuccess"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -225,24 +219,25 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
if user == nil {
|
if user == nil {
|
||||||
oauthConfig := oauthService.InfoByOp(op)
|
oauthConfig := oauthService.InfoByOp(op)
|
||||||
if !*oauthConfig.AutoRegister {
|
if !*oauthConfig.AutoRegister {
|
||||||
//c.String(http.StatusInternalServerError, "not yet bound to a user, please bind first")
|
//c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定")
|
||||||
oauthCache.UpdateFromOauthUser(oauthUser)
|
oauthCache.UpdateFromOauthUser(oauthUser)
|
||||||
c.Redirect(http.StatusFound, "/_admin/#/oauth/bind/"+cacheKey)
|
url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey
|
||||||
|
c.Redirect(http.StatusFound, url)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//auto register
|
//自动注册
|
||||||
err, user = service.AllService.UserService.RegisterByOauth(oauthUser, op)
|
err, user = service.AllService.UserService.RegisterByOauth(oauthUser, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
"message": err.Error(),
|
"message": response.TranslateMsg(c, err.Error()),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oauthCache.UserId = user.Id
|
oauthCache.UserId = user.Id
|
||||||
oauthService.SetOauthCache(cacheKey, oauthCache, 0)
|
oauthService.SetOauthCache(cacheKey, oauthCache, 0)
|
||||||
// if it is webadmin, after successful login redirect to webadmin
|
// 如果是webadmin,登录成功后跳转到webadmin
|
||||||
if oauthCache.DeviceType == model.LoginLogClientWebAdmin {
|
if oauthCache.DeviceType == model.LoginLogClientWebAdmin {
|
||||||
/*service.AllService.UserService.Login(u, &model.LoginLog{
|
/*service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
@@ -252,54 +247,19 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
Type: model.LoginLogTypeOauth,
|
Type: model.LoginLogTypeOauth,
|
||||||
Platform: oauthService.DeviceOs,
|
Platform: oauthService.DeviceOs,
|
||||||
})*/
|
})*/
|
||||||
c.Redirect(http.StatusFound, "/_admin/#/")
|
url := global.Config.Rustdesk.ApiServer + "/_admin/#/"
|
||||||
|
c.Redirect(http.StatusFound, url)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
||||||
"message": "OauthSuccess",
|
"message": response.TranslateMsg(c, "OauthSuccess"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
"message": "ParamsError",
|
"message": response.TranslateMsg(c, "ParamsError"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessageParams struct {
|
|
||||||
Lang string `json:"lang" form:"lang"`
|
|
||||||
Title string `json:"title" form:"title"`
|
|
||||||
Msg string `json:"msg" form:"msg"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Oauth) Message(c *gin.Context) {
|
|
||||||
mp := &MessageParams{}
|
|
||||||
if err := c.ShouldBindQuery(mp); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
localizer := global.Localizer(mp.Lang)
|
|
||||||
res := ""
|
|
||||||
if mp.Title != "" {
|
|
||||||
title, err := localizer.LocalizeMessage(&i18n.Message{
|
|
||||||
ID: mp.Title,
|
|
||||||
})
|
|
||||||
if err == nil {
|
|
||||||
res = utils.StringConcat(";title='", title, "';")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if mp.Msg != "" {
|
|
||||||
msg, err := localizer.LocalizeMessage(&i18n.Message{
|
|
||||||
ID: mp.Msg,
|
|
||||||
})
|
|
||||||
if err == nil {
|
|
||||||
res = utils.StringConcat(res, "msg = '", msg, "';")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//returnjscontent
|
|
||||||
c.Header("Content-Type", "application/javascript")
|
|
||||||
c.String(http.StatusOK, res)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
requstform "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
requstform "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
@@ -14,12 +13,12 @@ type Peer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SysInfo
|
// SysInfo
|
||||||
// @Tags System
|
// @Tags 地址
|
||||||
// @Summary submit system info
|
// @Summary 提交系统信息
|
||||||
// @Description submit system info
|
// @Description 提交系统信息
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body requstform.PeerForm true "system info form"
|
// @Param body body requstform.PeerForm true "系统信息表单"
|
||||||
// @Success 200 {string} string "SYSINFO_UPDATED,ID_NOT_FOUND"
|
// @Success 200 {string} string "SYSINFO_UPDATED,ID_NOT_FOUND"
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /sysinfo [post]
|
// @Router /sysinfo [post]
|
||||||
@@ -34,7 +33,7 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
|||||||
pe := service.AllService.PeerService.FindById(f.Id)
|
pe := service.AllService.PeerService.FindById(f.Id)
|
||||||
if pe.RowId == 0 {
|
if pe.RowId == 0 {
|
||||||
pe = f.ToPeer()
|
pe = f.ToPeer()
|
||||||
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid, pe.Id)
|
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
|
||||||
err = service.AllService.PeerService.Create(pe)
|
err = service.AllService.PeerService.Create(pe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
@@ -42,7 +41,7 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if pe.UserId == 0 {
|
if pe.UserId == 0 {
|
||||||
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid, pe.Id)
|
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
|
||||||
}
|
}
|
||||||
fpe.RowId = pe.RowId
|
fpe.RowId = pe.RowId
|
||||||
fpe.UserId = pe.UserId
|
fpe.UserId = pe.UserId
|
||||||
@@ -52,25 +51,8 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//SYSINFO_UPDATED upload successful
|
//SYSINFO_UPDATED 上传成功
|
||||||
//ID_NOT_FOUND will be uploaded on the next heartbeat
|
//ID_NOT_FOUND 下次心跳会上传
|
||||||
//respond with text directly
|
//直接响应文本
|
||||||
c.String(http.StatusOK, "SYSINFO_UPDATED")
|
c.String(http.StatusOK, "SYSINFO_UPDATED")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SysInfoVer
|
|
||||||
// @Tags System
|
|
||||||
// @Summary get system version info
|
|
||||||
// @Description get system version info
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Success 200 {string} string ""
|
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
|
||||||
// @Router /sysinfo_ver [post]
|
|
||||||
func (p *Peer) SysInfoVer(c *gin.Context) {
|
|
||||||
// read the resources/version file
|
|
||||||
v := service.AllService.AppService.GetAppVersion()
|
|
||||||
// add the start time so the client can conveniently upload info
|
|
||||||
v = fmt.Sprintf("%s\n%s", v, service.AllService.AppService.GetStartTime())
|
|
||||||
c.String(http.StatusOK, v)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import (
|
|||||||
type User struct {
|
type User struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// currentUser current user
|
// currentUser 当前用户
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary user info
|
// @Summary 用户信息
|
||||||
// @Description user info
|
// @Description 用户信息
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} apiResp.UserPayload
|
// @Success 200 {object} apiResp.UserPayload
|
||||||
@@ -26,10 +26,10 @@ type User struct {
|
|||||||
// c.JSON(http.StatusOK, up)
|
// c.JSON(http.StatusOK, up)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// Info user info
|
// Info 用户信息
|
||||||
// @Tags user
|
// @Tags 用户
|
||||||
// @Summary user info
|
// @Summary 用户信息
|
||||||
// @Description user info
|
// @Description 用户信息
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} apiResp.UserPayload
|
// @Success 200 {object} apiResp.UserPayload
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import (
|
|||||||
type WebClient struct {
|
type WebClient struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig service config
|
// ServerConfig 服务配置
|
||||||
// @Tags WEBCLIENT
|
// @Tags WEBCLIENT
|
||||||
// @Summary service config
|
// @Summary 服务配置
|
||||||
// @Description service config, provides an api-server for the webclient
|
// @Description 服务配置,给webclient提供api-server
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -42,10 +42,10 @@ func (i *WebClient) ServerConfig(c *gin.Context) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SharedPeer shared peer
|
// SharedPeer 分享的peer
|
||||||
// @Tags WEBCLIENT
|
// @Tags WEBCLIENT
|
||||||
// @Summary shared peer
|
// @Summary 分享的peer
|
||||||
// @Description shared peer
|
// @Description 分享的peer
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -65,7 +65,7 @@ func (i *WebClient) SharedPeer(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if sr.Expire != 0 {
|
if sr.Expire != 0 {
|
||||||
//check whether expired,created_at + expire > now
|
//判断是否过期,created_at + expire > now
|
||||||
ca := time.Time(sr.CreatedAt)
|
ca := time.Time(sr.CreatedAt)
|
||||||
if ca.Add(time.Second * time.Duration(sr.Expire)).Before(time.Now()) {
|
if ca.Add(time.Second * time.Duration(sr.Expire)).Before(time.Now()) {
|
||||||
response.Fail(c, 101, "share expired")
|
response.Fail(c, 101, "share expired")
|
||||||
@@ -89,10 +89,10 @@ func (i *WebClient) SharedPeer(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfigV2 service config
|
// ServerConfigV2 服务配置
|
||||||
// @Tags WEBCLIENT_V2
|
// @Tags WEBCLIENT_V2
|
||||||
// @Summary service config
|
// @Summary 服务配置
|
||||||
// @Description service config, provides an api-server for the webclient
|
// @Description 服务配置,给webclient提供api-server
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
|
|||||||
+2
-2
@@ -25,7 +25,7 @@ func ApiInit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if global.Config.Gin.Mode == gin.ReleaseMode {
|
if global.Config.Gin.Mode == gin.ReleaseMode {
|
||||||
// redirect gin's Recovery log output to the logger's output
|
//修改gin Recovery日志 输出为logger的输出点
|
||||||
if global.Logger != nil {
|
if global.Logger != nil {
|
||||||
gin.DefaultErrorWriter = global.Logger.WriterLevel(logrus.ErrorLevel)
|
gin.DefaultErrorWriter = global.Logger.WriterLevel(logrus.ErrorLevel)
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ func ApiInit() {
|
|||||||
g.NoRoute(func(c *gin.Context) {
|
g.NoRoute(func(c *gin.Context) {
|
||||||
c.String(http.StatusNotFound, "404 not found")
|
c.String(http.StatusNotFound, "404 not found")
|
||||||
})
|
})
|
||||||
g.Use(middleware.Logger(), middleware.Limiter(), gin.Recovery())
|
g.Use(middleware.Logger(), gin.Recovery())
|
||||||
router.WebInit(g)
|
router.WebInit(g)
|
||||||
router.Init(g)
|
router.Init(g)
|
||||||
router.ApiInit(g)
|
router.ApiInit(g)
|
||||||
|
|||||||
@@ -6,20 +6,20 @@ import (
|
|||||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BackendUserAuth backend permission verification middleware
|
// BackendUserAuth 后台权限验证中间件
|
||||||
func BackendUserAuth() gin.HandlerFunc {
|
func BackendUserAuth() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
|
||||||
//disabled for testing
|
//测试先关闭
|
||||||
token := c.GetHeader("api-token")
|
token := c.GetHeader("api-token")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
response.Fail(c, 403, "请先登录")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user, ut := service.AllService.UserService.InfoByAccessToken(token)
|
user, ut := service.AllService.UserService.InfoByAccessToken(token)
|
||||||
if user.Id == 0 {
|
if user.Id == 0 {
|
||||||
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
response.Fail(c, 403, "请先登录")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ func BackendUserAuth() gin.HandlerFunc {
|
|||||||
|
|
||||||
c.Set("curUser", user)
|
c.Set("curUser", user)
|
||||||
c.Set("token", token)
|
c.Set("token", token)
|
||||||
// if the remaining time is less than 1 day, the token is auto-renewed
|
//如果时间小于1天,token自动续期
|
||||||
service.AllService.UserService.AutoRefreshAccessToken(ut)
|
service.AllService.UserService.AutoRefreshAccessToken(ut)
|
||||||
|
|
||||||
c.Next()
|
c.Next()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ func AdminPrivilege() gin.HandlerFunc {
|
|||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
|
||||||
if !service.AllService.UserService.IsAdmin(u) {
|
if !service.AllService.UserService.IsAdmin(u) {
|
||||||
response.Fail(c, 403, response.TranslateMsg(c, "NoAccess"))
|
response.Fail(c, 403, "无权限")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cors CORS
|
// Cors 跨域
|
||||||
func Cors() gin.HandlerFunc {
|
func Cors() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
origin := c.GetHeader("Origin")
|
origin := c.GetHeader("Origin")
|
||||||
|
|||||||
@@ -9,21 +9,21 @@ import (
|
|||||||
|
|
||||||
func JwtAuth() gin.HandlerFunc {
|
func JwtAuth() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
//disabled for testing
|
//测试先关闭
|
||||||
token := c.GetHeader("api-token")
|
token := c.GetHeader("api-token")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
response.Fail(c, 403, "请先登录")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uid, err := global.Jwt.ParseToken(token)
|
uid, err := global.Jwt.ParseToken(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
response.Fail(c, 403, "请先登录")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if uid == 0 {
|
if uid == 0 {
|
||||||
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
response.Fail(c, 403, "请先登录")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -31,15 +31,15 @@ func JwtAuth() gin.HandlerFunc {
|
|||||||
user := service.AllService.UserService.InfoById(uid)
|
user := service.AllService.UserService.InfoById(uid)
|
||||||
//user := &model.User{
|
//user := &model.User{
|
||||||
// Id: uid,
|
// Id: uid,
|
||||||
// Username: "test user",
|
// Username: "测试用户",
|
||||||
//}
|
//}
|
||||||
if user.Id == 0 {
|
if user.Id == 0 {
|
||||||
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
response.Fail(c, 403, "请先登录")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !service.AllService.UserService.CheckUserEnable(user) {
|
if !service.AllService.UserService.CheckUserEnable(user) {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "Banned"))
|
response.Fail(c, 101, "你已被禁用")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
|
||||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Limiter() gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
loginLimiter := global.LoginLimiter
|
|
||||||
clientIp := c.ClientIP()
|
|
||||||
banned, _ := loginLimiter.CheckSecurityStatus(clientIp)
|
|
||||||
if banned {
|
|
||||||
response.Fail(c, http.StatusLocked, response.TranslateMsg(c, "Banned"))
|
|
||||||
c.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logger logging middleware
|
// Logger 日志中间件
|
||||||
func Logger() gin.HandlerFunc {
|
func Logger() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
global.Logger.WithFields(
|
global.Logger.WithFields(
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
func RustAuth() gin.HandlerFunc {
|
func RustAuth() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
//fmt.Println(c.Request.URL, c.Request.Header)
|
//fmt.Println(c.Request.URL, c.Request.Header)
|
||||||
//getHTTP_AUTHORIZATION
|
//获取HTTP_AUTHORIZATION
|
||||||
token := c.GetHeader("Authorization")
|
token := c.GetHeader("Authorization")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
c.JSON(401, gin.H{
|
c.JSON(401, gin.H{
|
||||||
@@ -25,13 +25,13 @@ func RustAuth() gin.HandlerFunc {
|
|||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//extracttoken, format is Bearer {token}
|
//提取token,格式是Bearer {token}
|
||||||
//this is just a simple extraction
|
//这里只是简单的提取
|
||||||
token = token[7:]
|
token = token[7:]
|
||||||
|
|
||||||
// verify the token
|
//验证token
|
||||||
|
|
||||||
//check whether it is set jwt key
|
//检查是否设置了jwt key
|
||||||
if len(global.Jwt.Key) > 0 {
|
if len(global.Jwt.Key) > 0 {
|
||||||
uid, _ := service.AllService.UserService.VerifyJWT(token)
|
uid, _ := service.AllService.UserService.VerifyJWT(token)
|
||||||
if uid == 0 {
|
if uid == 0 {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ type AddressBookForm struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a AddressBookForm) ToAddressBook() *model.AddressBook {
|
func (a AddressBookForm) ToAddressBook() *model.AddressBook {
|
||||||
//tagsconvert
|
//tags转换
|
||||||
tags, _ := json.Marshal(a.Tags)
|
tags, _ := json.Marshal(a.Tags)
|
||||||
|
|
||||||
return &model.AddressBook{
|
return &model.AddressBook{
|
||||||
@@ -52,7 +52,7 @@ func (a AddressBookForm) ToAddressBook() *model.AddressBook {
|
|||||||
|
|
||||||
}
|
}
|
||||||
func (a AddressBookForm) ToAddressBooks() []*model.AddressBook {
|
func (a AddressBookForm) ToAddressBooks() []*model.AddressBook {
|
||||||
//tagsconvert
|
//tags转换
|
||||||
tags, _ := json.Marshal(a.Tags)
|
tags, _ := json.Marshal(a.Tags)
|
||||||
|
|
||||||
abs := make([]*model.AddressBook, 0, len(a.UserIds))
|
abs := make([]*model.AddressBook, 0, len(a.UserIds))
|
||||||
@@ -92,7 +92,7 @@ type AddressBookQuery struct {
|
|||||||
|
|
||||||
type ShareByWebClientForm struct {
|
type ShareByWebClientForm struct {
|
||||||
Id string `json:"id" validate:"required"`
|
Id string `json:"id" validate:"required"`
|
||||||
PasswordType string `json:"password_type" validate:"required,oneof=once fixed"` //can only be once,fixed
|
PasswordType string `json:"password_type" validate:"required,oneof=once fixed"` //只能是once,fixed
|
||||||
Password string `json:"password" validate:"required"`
|
Password string `json:"password" validate:"required"`
|
||||||
Expire int64 `json:"expire"`
|
Expire int64 `json:"expire"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
type Login struct {
|
type Login struct {
|
||||||
Username string `json:"username" validate:"required" label:"username"`
|
Username string `json:"username" validate:"required" label:"用户名"`
|
||||||
Password string `json:"password,omitempty" validate:"required" label:"password"`
|
Password string `json:"password,omitempty" validate:"required" label:"密码"`
|
||||||
Platform string `json:"platform" label:"platform"`
|
Platform string `json:"platform" label:"平台"`
|
||||||
Captcha string `json:"captcha,omitempty" label:"captcha"`
|
Captcha string `json:"captcha,omitempty" label:"验证码"`
|
||||||
CaptchaId string `json:"captcha_id,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginLogQuery struct {
|
type LoginLogQuery struct {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type OauthForm struct {
|
|||||||
Scopes string `json:"scopes" validate:"omitempty"`
|
Scopes string `json:"scopes" validate:"omitempty"`
|
||||||
ClientId string `json:"client_id" validate:"required"`
|
ClientId string `json:"client_id" validate:"required"`
|
||||||
ClientSecret string `json:"client_secret" validate:"required"`
|
ClientSecret string `json:"client_secret" validate:"required"`
|
||||||
|
RedirectUrl string `json:"redirect_url" validate:"required"`
|
||||||
AutoRegister *bool `json:"auto_register"`
|
AutoRegister *bool `json:"auto_register"`
|
||||||
PkceEnable *bool `json:"pkce_enable"`
|
PkceEnable *bool `json:"pkce_enable"`
|
||||||
PkceMethod string `json:"pkce_method"`
|
PkceMethod string `json:"pkce_method"`
|
||||||
@@ -33,6 +34,7 @@ func (of *OauthForm) ToOauth() *model.Oauth {
|
|||||||
OauthType: of.OauthType,
|
OauthType: of.OauthType,
|
||||||
ClientId: of.ClientId,
|
ClientId: of.ClientId,
|
||||||
ClientSecret: of.ClientSecret,
|
ClientSecret: of.ClientSecret,
|
||||||
|
RedirectUrl: of.RedirectUrl,
|
||||||
AutoRegister: of.AutoRegister,
|
AutoRegister: of.AutoRegister,
|
||||||
Issuer: of.Issuer,
|
Issuer: of.Issuer,
|
||||||
Scopes: of.Scopes,
|
Scopes: of.Scopes,
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ type PeerForm struct {
|
|||||||
Uuid string `json:"uuid"`
|
Uuid string `json:"uuid"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
GroupId uint `json:"group_id"`
|
GroupId uint `json:"group_id"`
|
||||||
Alias string `json:"alias"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PeerBatchDeleteForm struct {
|
type PeerBatchDeleteForm struct {
|
||||||
@@ -33,7 +32,6 @@ func (f *PeerForm) ToPeer() *model.Peer {
|
|||||||
Uuid: f.Uuid,
|
Uuid: f.Uuid,
|
||||||
Version: f.Version,
|
Version: f.Version,
|
||||||
GroupId: f.GroupId,
|
GroupId: f.GroupId,
|
||||||
Alias: f.Alias,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,9 +41,6 @@ type PeerQuery struct {
|
|||||||
Id string `json:"id" form:"id"`
|
Id string `json:"id" form:"id"`
|
||||||
Hostname string `json:"hostname" form:"hostname"`
|
Hostname string `json:"hostname" form:"hostname"`
|
||||||
Uuids string `json:"uuids" form:"uuids"`
|
Uuids string `json:"uuids" form:"uuids"`
|
||||||
Ip string `json:"ip" form:"ip"`
|
|
||||||
Username string `json:"username" form:"username"`
|
|
||||||
Alias string `json:"alias" form:"alias"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SimpleDataQuery struct {
|
type SimpleDataQuery struct {
|
||||||
|
|||||||
@@ -7,14 +7,13 @@ import (
|
|||||||
type UserForm struct {
|
type UserForm struct {
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Username string `json:"username" validate:"required,gte=2,lte=32"`
|
Username string `json:"username" validate:"required,gte=2,lte=32"`
|
||||||
Email string `json:"email"` //validate:"required,email" emailnot enforced
|
Email string `json:"email"` //validate:"required,email" email不强制
|
||||||
//Password string `json:"password" validate:"required,gte=4,lte=20"`
|
//Password string `json:"password" validate:"required,gte=4,lte=20"`
|
||||||
Nickname string `json:"nickname"`
|
Nickname string `json:"nickname"`
|
||||||
Avatar string `json:"avatar"`
|
Avatar string `json:"avatar"`
|
||||||
GroupId uint `json:"group_id" validate:"required"`
|
GroupId uint `json:"group_id" validate:"required"`
|
||||||
IsAdmin *bool `json:"is_admin" `
|
IsAdmin *bool `json:"is_admin" `
|
||||||
Status model.StatusCode `json:"status" validate:"required,gte=0"`
|
Status model.StatusCode `json:"status" validate:"required,gte=0"`
|
||||||
Remark string `json:"remark"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uf *UserForm) FromUser(user *model.User) *UserForm {
|
func (uf *UserForm) FromUser(user *model.User) *UserForm {
|
||||||
@@ -26,7 +25,6 @@ func (uf *UserForm) FromUser(user *model.User) *UserForm {
|
|||||||
uf.GroupId = user.GroupId
|
uf.GroupId = user.GroupId
|
||||||
uf.IsAdmin = user.IsAdmin
|
uf.IsAdmin = user.IsAdmin
|
||||||
uf.Status = user.Status
|
uf.Status = user.Status
|
||||||
uf.Remark = user.Remark
|
|
||||||
return uf
|
return uf
|
||||||
}
|
}
|
||||||
func (uf *UserForm) ToUser() *model.User {
|
func (uf *UserForm) ToUser() *model.User {
|
||||||
@@ -39,7 +37,6 @@ func (uf *UserForm) ToUser() *model.User {
|
|||||||
user.GroupId = uf.GroupId
|
user.GroupId = uf.GroupId
|
||||||
user.IsAdmin = uf.IsAdmin
|
user.IsAdmin = uf.IsAdmin
|
||||||
user.Status = uf.Status
|
user.Status = uf.Status
|
||||||
user.Remark = uf.Remark
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
type OidcAuthRequest struct {
|
type OidcAuthRequest struct {
|
||||||
DeviceInfo DeviceInfoInLogin `json:"deviceInfo" label:"device info"`
|
DeviceInfo DeviceInfoInLogin `json:"deviceInfo" label:"设备信息"`
|
||||||
Id string `json:"id" label:"id"`
|
Id string `json:"id" label:"id"`
|
||||||
Op string `json:"op" label:"op"`
|
Op string `json:"op" label:"op"`
|
||||||
Uuid string `json:"uuid" label:"uuid"`
|
Uuid string `json:"uuid" label:"uuid"`
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func (pf *PeerForm) ToPeer() *model.Peer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PersonalAddressBookForm personal address book form
|
// PersonalAddressBookForm 个人地址簿表单
|
||||||
type PersonalAddressBookForm struct {
|
type PersonalAddressBookForm struct {
|
||||||
model.AddressBook
|
model.AddressBook
|
||||||
ForceAlwaysRelay string `json:"forceAlwaysRelay"`
|
ForceAlwaysRelay string `json:"forceAlwaysRelay"`
|
||||||
|
|||||||
+10
-10
@@ -29,25 +29,25 @@ type DeviceInfoInLogin struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LoginForm struct {
|
type LoginForm struct {
|
||||||
AutoLogin bool `json:"autoLogin" label:"auto login"`
|
AutoLogin bool `json:"autoLogin" label:"自动登录"`
|
||||||
DeviceInfo DeviceInfoInLogin `json:"deviceInfo" label:"device info"`
|
DeviceInfo DeviceInfoInLogin `json:"deviceInfo" label:"设备信息"`
|
||||||
Id string `json:"id" label:"id"`
|
Id string `json:"id" label:"id"`
|
||||||
Type string `json:"type" label:"type"`
|
Type string `json:"type" label:"type"`
|
||||||
Uuid string `json:"uuid" label:"uuid"`
|
Uuid string `json:"uuid" label:"uuid"`
|
||||||
Username string `json:"username" validate:"required,gte=2,lte=32" label:"username"`
|
Username string `json:"username" validate:"required,gte=2,lte=32" label:"用户名"`
|
||||||
Password string `json:"password,omitempty" validate:"gte=4,lte=32" label:"password"`
|
Password string `json:"password,omitempty" validate:"gte=4,lte=32" label:"密码"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserListQuery struct {
|
type UserListQuery struct {
|
||||||
Page uint `json:"page" form:"page" validate:"required" label:"page number"`
|
Page uint `json:"page" form:"page" validate:"required" label:"页码"`
|
||||||
PageSize uint `json:"pageSize" form:"pageSize" validate:"required" label:"items per page"`
|
PageSize uint `json:"page_size" form:"page_size" validate:"required" label:"每页数量"`
|
||||||
Status int `json:"status" form:"status" label:"status"`
|
Status int `json:"status" form:"status" label:"状态"`
|
||||||
Accessible string `json:"accessible" form:"accessible"`
|
Accessible string `json:"accessible" form:"accessible"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PeerListQuery struct {
|
type PeerListQuery struct {
|
||||||
Page uint `json:"page" form:"page" validate:"required" label:"page number"`
|
Page uint `json:"page" form:"page" validate:"required" label:"页码"`
|
||||||
PageSize uint `json:"pageSize" form:"pageSize" validate:"required" label:"items per page"`
|
PageSize uint `json:"page_size" form:"page_size" validate:"required" label:"每页数量"`
|
||||||
Status int `json:"status" form:"status" label:"status"`
|
Status int `json:"status" form:"status" label:"状态"`
|
||||||
Accessible string `json:"accessible" form:"accessible"`
|
Accessible string `json:"accessible" form:"accessible"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,3 +22,15 @@ type UserOauthItem struct {
|
|||||||
Op string `json:"op"`
|
Op string `json:"op"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GroupUsersPayload struct {
|
||||||
|
Id uint `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupUsersPayload) FromUser(user *model.User) {
|
||||||
|
g.Id = user.Id
|
||||||
|
g.Username = user.Username
|
||||||
|
g.Status = 1
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type WebClientPeerInfoPayload struct {
|
|||||||
|
|
||||||
func (wcpp *WebClientPeerPayload) FromAddressBook(a *model.AddressBook) {
|
func (wcpp *WebClientPeerPayload) FromAddressBook(a *model.AddressBook) {
|
||||||
wcpp.ViewStyle = "shrink"
|
wcpp.ViewStyle = "shrink"
|
||||||
//24 hours ago
|
//24小时前
|
||||||
wcpp.Tm = time.Now().Add(-time.Hour * 24).UnixNano()
|
wcpp.Tm = time.Now().Add(-time.Hour * 24).UnixNano()
|
||||||
wcpp.Info = WebClientPeerInfoPayload{
|
wcpp.Info = WebClientPeerInfoPayload{
|
||||||
Username: a.Username,
|
Username: a.Username,
|
||||||
@@ -34,7 +34,7 @@ func (wcpp *WebClientPeerPayload) FromAddressBook(a *model.AddressBook) {
|
|||||||
|
|
||||||
func (wcpp *WebClientPeerPayload) FromShareRecord(sr *model.ShareRecord) {
|
func (wcpp *WebClientPeerPayload) FromShareRecord(sr *model.ShareRecord) {
|
||||||
wcpp.ViewStyle = "shrink"
|
wcpp.ViewStyle = "shrink"
|
||||||
//24 hours ago
|
//24小时前
|
||||||
wcpp.Tm = time.Now().UnixNano()
|
wcpp.Tm = time.Now().UnixNano()
|
||||||
wcpp.Tmppwd = sr.Password
|
wcpp.Tmppwd = sr.Password
|
||||||
wcpp.Info = WebClientPeerInfoPayload{
|
wcpp.Info = WebClientPeerInfoPayload{
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func Init(g *gin.Engine) {
|
|||||||
|
|
||||||
RustdeskCmdBind(adg)
|
RustdeskCmdBind(adg)
|
||||||
DeviceGroupBind(adg)
|
DeviceGroupBind(adg)
|
||||||
//access static files
|
//访问静态文件
|
||||||
//g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload"))
|
//g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-12
@@ -18,7 +18,7 @@ func ApiInit(g *gin.Engine) {
|
|||||||
if global.Config.App.ShowSwagger == 1 {
|
if global.Config.App.ShowSwagger == 1 {
|
||||||
g.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.InstanceName("api")))
|
g.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.InstanceName("api")))
|
||||||
}
|
}
|
||||||
// load HTML template
|
// 加载 HTML 模板
|
||||||
g.LoadHTMLGlob("resources/templates/*")
|
g.LoadHTMLGlob("resources/templates/*")
|
||||||
|
|
||||||
frg := g.Group("/api")
|
frg := g.Group("/api")
|
||||||
@@ -33,7 +33,7 @@ func ApiInit(g *gin.Engine) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
l := &api.Login{}
|
l := &api.Login{}
|
||||||
// if oidc is returned, login via oidc is possible
|
// 如果返回oidc则可以通过oidc登录
|
||||||
frg.GET("/login-options", l.LoginOptions)
|
frg.GET("/login-options", l.LoginOptions)
|
||||||
frg.POST("/login", l.Login)
|
frg.POST("/login", l.Login)
|
||||||
|
|
||||||
@@ -48,17 +48,11 @@ func ApiInit(g *gin.Engine) {
|
|||||||
//api/oauth/callback
|
//api/oauth/callback
|
||||||
frg.GET("/oauth/callback", o.OauthCallback)
|
frg.GET("/oauth/callback", o.OauthCallback)
|
||||||
frg.GET("/oauth/login", o.OauthCallback)
|
frg.GET("/oauth/login", o.OauthCallback)
|
||||||
frg.GET("/oauth/msg", o.Message)
|
|
||||||
|
|
||||||
frg.GET("/oidc/callback", o.OauthCallback)
|
|
||||||
frg.GET("/oidc/login", o.OauthCallback)
|
|
||||||
frg.GET("/oidc/msg", o.Message)
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
pe := &api.Peer{}
|
pe := &api.Peer{}
|
||||||
//submit system info
|
//提交系统信息
|
||||||
frg.POST("/sysinfo", pe.SysInfo)
|
frg.POST("/sysinfo", pe.SysInfo)
|
||||||
frg.POST("/sysinfo_ver", pe.SysInfoVer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if global.Config.App.WebClient == 1 {
|
if global.Config.App.WebClient == 1 {
|
||||||
@@ -93,14 +87,14 @@ func ApiInit(g *gin.Engine) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
ab := &api.Ab{}
|
ab := &api.Ab{}
|
||||||
//get address
|
//获取地址
|
||||||
frg.GET("/ab", ab.Ab)
|
frg.GET("/ab", ab.Ab)
|
||||||
//update address
|
//更新地址
|
||||||
frg.POST("/ab", ab.UpAb)
|
frg.POST("/ab", ab.UpAb)
|
||||||
}
|
}
|
||||||
|
|
||||||
PersonalRoutes(frg)
|
PersonalRoutes(frg)
|
||||||
//access static files
|
//访问静态文件
|
||||||
g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/public/upload"))
|
g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/public/upload"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -10,7 +10,7 @@ type Handler interface {
|
|||||||
Gc() error
|
Gc() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaxTimeOut maximum timeout
|
// MaxTimeOut 最大超时时间
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TypeMem = "memory"
|
TypeMem = "memory"
|
||||||
@@ -49,7 +49,7 @@ func EncodeValue(value interface{}) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DecodeValue(value string, rtv interface{}) error {
|
func DecodeValue(value string, rtv interface{}) error {
|
||||||
// check whether rtv's type is string; if so, assign directly and return
|
//判断rtv的类型是否是string,如果是string,直接赋值并返回
|
||||||
/*switch rtv.(type) {
|
/*switch rtv.(type) {
|
||||||
case *string:
|
case *string:
|
||||||
*(rtv.(*string)) = value
|
*(rtv.(*string)) = value
|
||||||
|
|||||||
Vendored
+6
-6
@@ -42,7 +42,7 @@ func TestFileCacheSet(t *testing.T) {
|
|||||||
err := fc.Set("123", "ddd", 0)
|
err := fc.Set("123", "ddd", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,12 +50,12 @@ func TestFileCacheGet(t *testing.T) {
|
|||||||
fc := New("file")
|
fc := New("file")
|
||||||
err := fc.Set("123", "45156", 300)
|
err := fc.Set("123", "45156", 300)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
res := ""
|
res := ""
|
||||||
err = fc.Get("123", &res)
|
err = fc.Get("123", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
fmt.Println("res", res)
|
fmt.Println("res", res)
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ func TestRedisCacheSet(t *testing.T) {
|
|||||||
err := rc.Set("123", "ddd", 0)
|
err := rc.Set("123", "ddd", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,12 +81,12 @@ func TestRedisCacheGet(t *testing.T) {
|
|||||||
})
|
})
|
||||||
err := rc.Set("123", "451156", 300)
|
err := rc.Set("123", "451156", 300)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
res := ""
|
res := ""
|
||||||
err = rc.Get("123", &res)
|
err = rc.Get("123", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
fmt.Println("res", res)
|
fmt.Println("res", res)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+4
-4
@@ -32,12 +32,12 @@ func (c *FileCache) Get(key string, value interface{}) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// get value; if the file does not exist or has expired, return empty and ignore errors
|
// 获取值,如果文件不存在或者过期,返回空,过滤掉错误
|
||||||
func (c *FileCache) getValue(key string) (string, error) {
|
func (c *FileCache) getValue(key string) (string, error) {
|
||||||
f := c.fileName(key)
|
f := c.fileName(key)
|
||||||
fileInfo, err := os.Stat(f)
|
fileInfo, err := os.Stat(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// file does not exist
|
//文件不存在
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
difT := time.Now().Sub(fileInfo.ModTime())
|
difT := time.Now().Sub(fileInfo.ModTime())
|
||||||
@@ -52,7 +52,7 @@ func (c *FileCache) getValue(key string) (string, error) {
|
|||||||
return string(data), nil
|
return string(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// save value
|
// 保存值
|
||||||
func (c *FileCache) saveValue(key string, value string, exp int) error {
|
func (c *FileCache) saveValue(key string, value string, exp int) error {
|
||||||
f := c.fileName(key)
|
f := c.fileName(key)
|
||||||
lock := c.getLock(f)
|
lock := c.getLock(f)
|
||||||
@@ -91,7 +91,7 @@ func (c *FileCache) fileName(key string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *FileCache) Gc() error {
|
func (c *FileCache) Gc() error {
|
||||||
// check file expiration time and delete
|
//检查文件过期时间,并删除
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+7
-7
@@ -11,7 +11,7 @@ func TestFileSet(t *testing.T) {
|
|||||||
err := fc.Set("123", "ddd", 0)
|
err := fc.Set("123", "ddd", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ func TestFileGet(t *testing.T) {
|
|||||||
err := fc.Get("123", &res)
|
err := fc.Get("123", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
fmt.Println("res", res)
|
fmt.Println("res", res)
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ func TestFileSetGet(t *testing.T) {
|
|||||||
err = fc.Get("key1", &res)
|
err = fc.Get("key1", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
fmt.Println("res", res)
|
fmt.Println("res", res)
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ func TestFileGetJson(t *testing.T) {
|
|||||||
err2 := fc.Get("123", res)
|
err2 := fc.Get("123", res)
|
||||||
fmt.Println("res", res)
|
fmt.Println("res", res)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
t.Fatalf("read failed" + err2.Error())
|
t.Fatalf("读取失败" + err2.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestFileSetGetJson(t *testing.T) {
|
func TestFileSetGetJson(t *testing.T) {
|
||||||
@@ -59,7 +59,7 @@ func TestFileSetGetJson(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err := fc.Set("123", old, 300)
|
err := fc.Set("123", old, 300)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
//old_rr.AA = "aaa"
|
//old_rr.AA = "aaa"
|
||||||
fmt.Println("old_rr", old)
|
fmt.Println("old_rr", old)
|
||||||
@@ -68,10 +68,10 @@ func TestFileSetGetJson(t *testing.T) {
|
|||||||
err2 := fc.Get("123", res)
|
err2 := fc.Get("123", res)
|
||||||
fmt.Println("res", res)
|
fmt.Println("res", res)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
t.Fatalf("read failed" + err2.Error())
|
t.Fatalf("读取失败" + err2.Error())
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(res, old) {
|
if !reflect.DeepEqual(res, old) {
|
||||||
t.Fatalf("read error")
|
t.Fatalf("读取错误")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+9
-9
@@ -11,8 +11,8 @@ import (
|
|||||||
|
|
||||||
type MemoryCache struct {
|
type MemoryCache struct {
|
||||||
data map[string]*CacheItem
|
data map[string]*CacheItem
|
||||||
ll *list.List // used to implement LRU
|
ll *list.List // 用于实现LRU
|
||||||
pq PriorityQueue // used to implement TTL
|
pq PriorityQueue // 用于实现TTL
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
maxBytes int64
|
maxBytes int64
|
||||||
@@ -58,12 +58,12 @@ func (pq *PriorityQueue) Pop() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MemoryCache) Get(key string, value interface{}) error {
|
func (m *MemoryCache) Get(key string, value interface{}) error {
|
||||||
// use reflection to set the stored value into the passed-in pointer variable
|
// 使用反射将存储的值设置到传入的指针变量中
|
||||||
val := reflect.ValueOf(value)
|
val := reflect.ValueOf(value)
|
||||||
if val.Kind() != reflect.Ptr {
|
if val.Kind() != reflect.Ptr {
|
||||||
return errors.New("value must be a pointer")
|
return errors.New("value must be a pointer")
|
||||||
}
|
}
|
||||||
// set to zero value
|
//设为空值
|
||||||
val.Elem().Set(reflect.Zero(val.Elem().Type()))
|
val.Elem().Set(reflect.Zero(val.Elem().Type()))
|
||||||
|
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
@@ -78,7 +78,7 @@ func (m *MemoryCache) Get(key string, value interface{}) error {
|
|||||||
m.deleteItem(item)
|
m.deleteItem(item)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// move to the tail of the queue
|
//移动到队列尾部
|
||||||
m.ll.MoveToBack(item.ListEle)
|
m.ll.MoveToBack(item.ListEle)
|
||||||
|
|
||||||
err := DecodeValue(item.Value, value)
|
err := DecodeValue(item.Value, value)
|
||||||
@@ -97,11 +97,11 @@ func (m *MemoryCache) Set(key string, value interface{}, exp int) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// memory occupied by the key
|
//key 所占用的内存
|
||||||
keyBytes := int64(len(key))
|
keyBytes := int64(len(key))
|
||||||
// size of memory occupied by the value
|
//value所占用的内存空间大小
|
||||||
valueBytes := int64(len(v))
|
valueBytes := int64(len(v))
|
||||||
// check whether the maximum memory limit is exceeded
|
//判断是否超过最大内存限制
|
||||||
if m.maxBytes != 0 && m.maxBytes < keyBytes+valueBytes {
|
if m.maxBytes != 0 && m.maxBytes < keyBytes+valueBytes {
|
||||||
return errors.New("exceed maxBytes")
|
return errors.New("exceed maxBytes")
|
||||||
}
|
}
|
||||||
@@ -176,7 +176,7 @@ func (m *MemoryCache) startEviction() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// stopEviction stops the scheduled cleanup
|
// stopEviction 停止定时清理
|
||||||
func (m *MemoryCache) stopEviction() {
|
func (m *MemoryCache) stopEviction() {
|
||||||
close(m.quit)
|
close(m.quit)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+14
-14
@@ -11,7 +11,7 @@ func TestMemorySet(t *testing.T) {
|
|||||||
err := mc.Set("123", "44567", 0)
|
err := mc.Set("123", "44567", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,10 +22,10 @@ func TestMemoryGet(t *testing.T) {
|
|||||||
err := mc.Get("123", &res)
|
err := mc.Get("123", &res)
|
||||||
fmt.Println("res", res)
|
fmt.Println("res", res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed " + err.Error())
|
t.Fatalf("读取失败 " + err.Error())
|
||||||
}
|
}
|
||||||
if res != "44567" {
|
if res != "44567" {
|
||||||
t.Fatalf("read error")
|
t.Fatalf("读取错误")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -37,30 +37,30 @@ func TestMemorySetExpGet(t *testing.T) {
|
|||||||
mc.Set("2", "5", 5)
|
mc.Set("2", "5", 5)
|
||||||
err := mc.Set("3", "3", 3)
|
err := mc.Set("3", "3", 3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
res := ""
|
res := ""
|
||||||
err = mc.Get("3", &res)
|
err = mc.Get("3", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed" + err.Error())
|
t.Fatalf("读取失败" + err.Error())
|
||||||
}
|
}
|
||||||
fmt.Println("res 3", res)
|
fmt.Println("res 3", res)
|
||||||
time.Sleep(4 * time.Second)
|
time.Sleep(4 * time.Second)
|
||||||
//res = ""
|
//res = ""
|
||||||
err = mc.Get("3", &res)
|
err = mc.Get("3", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed" + err.Error())
|
t.Fatalf("读取失败" + err.Error())
|
||||||
}
|
}
|
||||||
fmt.Println("res 3", res)
|
fmt.Println("res 3", res)
|
||||||
err = mc.Get("2", &res)
|
err = mc.Get("2", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed" + err.Error())
|
t.Fatalf("读取失败" + err.Error())
|
||||||
}
|
}
|
||||||
fmt.Println("res 2", res)
|
fmt.Println("res 2", res)
|
||||||
err = mc.Get("1", &res)
|
err = mc.Get("1", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed" + err.Error())
|
t.Fatalf("读取失败" + err.Error())
|
||||||
}
|
}
|
||||||
fmt.Println("res 1", res)
|
fmt.Println("res 1", res)
|
||||||
|
|
||||||
@@ -69,29 +69,29 @@ func TestMemoryLru(t *testing.T) {
|
|||||||
mc := NewMemoryCache(18)
|
mc := NewMemoryCache(18)
|
||||||
mc.Set("1", "1111", 10)
|
mc.Set("1", "1111", 10)
|
||||||
mc.Set("2", "2222", 5)
|
mc.Set("2", "2222", 5)
|
||||||
// read once, so 2 will be moved to the end
|
//读取一次,2就会被放到最后
|
||||||
mc.Get("1", nil)
|
mc.Get("1", nil)
|
||||||
err := mc.Set("3", "three", 3)
|
err := mc.Set("3", "三", 3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//t.Fatalf("write failed")
|
//t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
res := ""
|
res := ""
|
||||||
err = mc.Get("3", &res)
|
err = mc.Get("3", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed" + err.Error())
|
t.Fatalf("读取失败" + err.Error())
|
||||||
}
|
}
|
||||||
fmt.Println("res3", res)
|
fmt.Println("res3", res)
|
||||||
res = ""
|
res = ""
|
||||||
err = mc.Get("2", &res)
|
err = mc.Get("2", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed" + err.Error())
|
t.Fatalf("读取失败" + err.Error())
|
||||||
}
|
}
|
||||||
fmt.Println("res2", res)
|
fmt.Println("res2", res)
|
||||||
res = ""
|
res = ""
|
||||||
err = mc.Get("1", &res)
|
err = mc.Get("1", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed" + err.Error())
|
t.Fatalf("读取失败" + err.Error())
|
||||||
}
|
}
|
||||||
fmt.Println("res1", res)
|
fmt.Println("res1", res)
|
||||||
|
|
||||||
|
|||||||
Vendored
+6
-6
@@ -17,7 +17,7 @@ func TestRedisSet(t *testing.T) {
|
|||||||
err := rc.Set("123", "ddd", 0)
|
err := rc.Set("123", "ddd", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,12 +29,12 @@ func TestRedisGet(t *testing.T) {
|
|||||||
})
|
})
|
||||||
err := rc.Set("123", "451156", 300)
|
err := rc.Set("123", "451156", 300)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
res := ""
|
res := ""
|
||||||
err = rc.Get("123", &res)
|
err = rc.Get("123", &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
fmt.Println("res", res)
|
fmt.Println("res", res)
|
||||||
}
|
}
|
||||||
@@ -54,16 +54,16 @@ func TestRedisGetJson(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err := rc.Set("1233", old, 300)
|
err := rc.Set("1233", old, 300)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &r{}
|
res := &r{}
|
||||||
err2 := rc.Get("1233", res)
|
err2 := rc.Get("1233", res)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(res, old) {
|
if !reflect.DeepEqual(res, old) {
|
||||||
t.Fatalf("read error")
|
t.Fatalf("读取错误")
|
||||||
}
|
}
|
||||||
fmt.Println(res, res.Aa)
|
fmt.Println(res, res.Aa)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+5
-5
@@ -6,7 +6,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// implements a simple cache used for testing
|
// 此处实现了一个简单的缓存,用于测试
|
||||||
// SimpleCache is a simple cache implementation
|
// SimpleCache is a simple cache implementation
|
||||||
type SimpleCache struct {
|
type SimpleCache struct {
|
||||||
data map[string]interface{}
|
data map[string]interface{}
|
||||||
@@ -19,21 +19,21 @@ func (s *SimpleCache) Get(key string, value interface{}) error {
|
|||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
// use reflection to set the stored value into the passed-in pointer variable
|
// 使用反射将存储的值设置到传入的指针变量中
|
||||||
val := reflect.ValueOf(value)
|
val := reflect.ValueOf(value)
|
||||||
if val.Kind() != reflect.Ptr {
|
if val.Kind() != reflect.Ptr {
|
||||||
return errors.New("value must be a pointer")
|
return errors.New("value must be a pointer")
|
||||||
}
|
}
|
||||||
v, ok := s.data[key]
|
v, ok := s.data[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
// set to zero value
|
//设为空值
|
||||||
val.Elem().Set(reflect.Zero(val.Elem().Type()))
|
val.Elem().Set(reflect.Zero(val.Elem().Type()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
vval := reflect.ValueOf(v)
|
vval := reflect.ValueOf(v)
|
||||||
if val.Elem().Type() != vval.Type() {
|
if val.Elem().Type() != vval.Type() {
|
||||||
// set to zero value
|
//设为空值
|
||||||
val.Elem().Set(reflect.Zero(val.Elem().Type()))
|
val.Elem().Set(reflect.Zero(val.Elem().Type()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ func (s *SimpleCache) Get(key string, value interface{}) error {
|
|||||||
func (s *SimpleCache) Set(key string, value interface{}, exp int) error {
|
func (s *SimpleCache) Set(key string, value interface{}, exp int) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
// check whether the passed-in value is a pointer; if so, dereference it
|
// 检查传入的值是否是指针,如果是则取其值
|
||||||
val := reflect.ValueOf(value)
|
val := reflect.ValueOf(value)
|
||||||
if val.Kind() == reflect.Ptr {
|
if val.Kind() == reflect.Ptr {
|
||||||
val = val.Elem()
|
val = val.Elem()
|
||||||
|
|||||||
Vendored
+11
-11
@@ -9,11 +9,11 @@ func TestSimpleCache_Set(t *testing.T) {
|
|||||||
s := NewSimpleCache()
|
s := NewSimpleCache()
|
||||||
err := s.Set("key", "value", 0)
|
err := s.Set("key", "value", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
err = s.Set("key", 111, 0)
|
err = s.Set("key", 111, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ func TestSimpleCache_Get(t *testing.T) {
|
|||||||
err = s.Get("key", &value)
|
err = s.Get("key", &value)
|
||||||
fmt.Println("value", value)
|
fmt.Println("value", value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.Set("key1", 11, 0)
|
err = s.Set("key1", 11, 0)
|
||||||
@@ -32,7 +32,7 @@ func TestSimpleCache_Get(t *testing.T) {
|
|||||||
err = s.Get("key1", &value1)
|
err = s.Get("key1", &value1)
|
||||||
fmt.Println("value1", value1)
|
fmt.Println("value1", value1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.Set("key2", []byte{'a', 'b'}, 0)
|
err = s.Set("key2", []byte{'a', 'b'}, 0)
|
||||||
@@ -40,7 +40,7 @@ func TestSimpleCache_Get(t *testing.T) {
|
|||||||
err = s.Get("key2", &value2)
|
err = s.Get("key2", &value2)
|
||||||
fmt.Println("value2", string(value2))
|
fmt.Println("value2", string(value2))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.Set("key3", 33.33, 0)
|
err = s.Set("key3", 33.33, 0)
|
||||||
@@ -48,7 +48,7 @@ func TestSimpleCache_Get(t *testing.T) {
|
|||||||
err = s.Get("key3", &value3)
|
err = s.Get("key3", &value3)
|
||||||
fmt.Println("value3", value3)
|
fmt.Println("value3", value3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("read failed")
|
t.Fatalf("读取失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -80,18 +80,18 @@ func TestSimpleCache_GetStruct(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err := s.Set("key", old, 300)
|
err := s.Set("key", old, 300)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("write failed")
|
t.Fatalf("写入失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &r{}
|
res := &r{}
|
||||||
err2 := s.Get("key", res)
|
err2 := s.Get("key", res)
|
||||||
fmt.Println("res", res)
|
fmt.Println("res", res)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
t.Fatalf("read failed" + err2.Error())
|
t.Fatalf("读取失败" + err2.Error())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// modify the original value to see whether it changes afterward
|
//修改原始值,看后面是否会变化
|
||||||
old.A = "aa"
|
old.A = "aa"
|
||||||
old_rr.AA = "aaa"
|
old_rr.AA = "aaa"
|
||||||
fmt.Println("old", old)
|
fmt.Println("old", old)
|
||||||
@@ -99,10 +99,10 @@ func TestSimpleCache_GetStruct(t *testing.T) {
|
|||||||
err3 := s.Get("key", res2)
|
err3 := s.Get("key", res2)
|
||||||
fmt.Println("res2", res2, res2.R.AA, res2.R.BB)
|
fmt.Println("res2", res2, res2.R.AA, res2.R.BB)
|
||||||
if err3 != nil {
|
if err3 != nil {
|
||||||
t.Fatalf("read failed" + err3.Error())
|
t.Fatalf("读取失败" + err3.Error())
|
||||||
|
|
||||||
}
|
}
|
||||||
//if reflect.DeepEqual(res, old) {
|
//if reflect.DeepEqual(res, old) {
|
||||||
// t.Fatalf("read error")
|
// t.Fatalf("读取错误")
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -34,30 +34,30 @@ Hj4yO4j5LOWDMTgDcLsZTxbGiTzkNc/HghrNIevDAQdgjJQNl84zDjyyCA4r/MA7
|
|||||||
bYJTtYj8q6J0EDbRdT9b6hMclyzjNXdx2loJxR0R8WUeL1lDEPq8
|
bYJTtYj8q6J0EDbRdT9b6hMclyzjNXdx2loJxR0R8WUeL1lDEPq8
|
||||||
-----END RSA PRIVATE KEY-----`
|
-----END RSA PRIVATE KEY-----`
|
||||||
|
|
||||||
// test token generation
|
// 测试token生成
|
||||||
func TestGenerateToken(t *testing.T) {
|
func TestGenerateToken(t *testing.T) {
|
||||||
jwtService := NewJwt(pk, time.Second*1000)
|
jwtService := NewJwt(pk, time.Second*1000)
|
||||||
token := jwtService.GenerateToken(1)
|
token := jwtService.GenerateToken(1)
|
||||||
if token == "" {
|
if token == "" {
|
||||||
t.Fatal("token generation failed")
|
t.Fatal("token生成失败")
|
||||||
}
|
}
|
||||||
fmt.Println(pk, token)
|
fmt.Println(pk, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test token parsing
|
// 测试token解析
|
||||||
func TestParseToken(t *testing.T) {
|
func TestParseToken(t *testing.T) {
|
||||||
jwtService := NewJwt(pk, time.Second*1000)
|
jwtService := NewJwt(pk, time.Second*1000)
|
||||||
token := jwtService.GenerateToken(999)
|
token := jwtService.GenerateToken(999)
|
||||||
if token == "" {
|
if token == "" {
|
||||||
t.Fatal("token generation failed")
|
t.Fatal("token生成失败")
|
||||||
}
|
}
|
||||||
uid, err := jwtService.ParseToken(token)
|
uid, err := jwtService.ParseToken(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
t.Fatal("token parsing failed", err)
|
t.Fatal("token解析失败", err)
|
||||||
}
|
}
|
||||||
if uid != 999 {
|
if uid != 999 {
|
||||||
t.Fatal("token parsing failed")
|
t.Fatal("token解析失败")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func New(c *Config) *log.Logger {
|
|||||||
//FieldsOrder: []string{"name", "age"},
|
//FieldsOrder: []string{"name", "age"},
|
||||||
})
|
})
|
||||||
|
|
||||||
// log file
|
// 日志文件
|
||||||
f := c.Path
|
f := c.Path
|
||||||
var write io.Writer
|
var write io.Writer
|
||||||
if f != "" {
|
if f != "" {
|
||||||
|
|||||||
+12
-11
@@ -2,6 +2,7 @@ package orm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/logger"
|
"gorm.io/gorm/logger"
|
||||||
@@ -9,23 +10,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type MysqlConfig struct {
|
type MysqlConfig struct {
|
||||||
Dsn string
|
Dns string
|
||||||
MaxIdleConns int
|
MaxIdleConns int
|
||||||
MaxOpenConns int
|
MaxOpenConns int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMysql(mysqlConf *MysqlConfig, logwriter logger.Writer) *gorm.DB {
|
func NewMysql(mysqlConf *MysqlConfig) *gorm.DB {
|
||||||
db, err := gorm.Open(mysql.New(mysql.Config{
|
db, err := gorm.Open(mysql.New(mysql.Config{
|
||||||
DSN: mysqlConf.Dsn, // DSN data source name
|
DSN: mysqlConf.Dns, // DSN data source name
|
||||||
DefaultStringSize: 256, // default length for string type fields
|
DefaultStringSize: 256, // string 类型字段的默认长度
|
||||||
//DisableDatetimePrecision: true, // disable datetime precision; not supported by databases before MySQL 5.6
|
//DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
|
||||||
//DontSupportRenameIndex: true, // rename indexes by dropping and recreating them; databases before MySQL 5.7 and MariaDB do not support renaming indexes
|
//DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
|
||||||
//DontSupportRenameColumn: true, // rename columns using `change`; databases before MySQL 8 and MariaDB do not support renaming columns
|
//DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
|
||||||
//SkipInitializeWithVersion: false, // auto-configure based on the current MySQL version
|
//SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
|
||||||
}), &gorm.Config{
|
}), &gorm.Config{
|
||||||
DisableForeignKeyConstraintWhenMigrating: true,
|
DisableForeignKeyConstraintWhenMigrating: true,
|
||||||
Logger: logger.New(
|
Logger: logger.New(
|
||||||
logwriter, // io writer
|
global.Logger, // io writer
|
||||||
logger.Config{
|
logger.Config{
|
||||||
SlowThreshold: time.Second, // Slow SQL threshold
|
SlowThreshold: time.Second, // Slow SQL threshold
|
||||||
LogLevel: logger.Warn, // Log level
|
LogLevel: logger.Warn, // Log level
|
||||||
@@ -42,10 +43,10 @@ func NewMysql(mysqlConf *MysqlConfig, logwriter logger.Writer) *gorm.DB {
|
|||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
fmt.Println(err2)
|
fmt.Println(err2)
|
||||||
}
|
}
|
||||||
// SetMaxIdleConns sets the maximum number of connections in the idle connection pool
|
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
|
||||||
sqlDB.SetMaxIdleConns(mysqlConf.MaxIdleConns)
|
sqlDB.SetMaxIdleConns(mysqlConf.MaxIdleConns)
|
||||||
|
|
||||||
// SetMaxOpenConns sets the maximum number of open database connections.
|
// SetMaxOpenConns 设置打开数据库连接的最大数量。
|
||||||
sqlDB.SetMaxOpenConns(mysqlConf.MaxOpenConns)
|
sqlDB.SetMaxOpenConns(mysqlConf.MaxOpenConns)
|
||||||
|
|
||||||
return db
|
return db
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
package orm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"gorm.io/driver/postgres"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"gorm.io/gorm/logger"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PostgresqlConfig struct {
|
|
||||||
Dsn string
|
|
||||||
MaxIdleConns int
|
|
||||||
MaxOpenConns int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPostgresql(conf *PostgresqlConfig, logwriter logger.Writer) *gorm.DB {
|
|
||||||
db, err := gorm.Open(postgres.Open(conf.Dsn), &gorm.Config{
|
|
||||||
DisableForeignKeyConstraintWhenMigrating: true,
|
|
||||||
Logger: logger.New(
|
|
||||||
logwriter, // io writer
|
|
||||||
logger.Config{
|
|
||||||
SlowThreshold: time.Second, // Slow SQL threshold
|
|
||||||
LogLevel: logger.Warn, // Log level
|
|
||||||
//IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
|
|
||||||
ParameterizedQueries: true, // Don't include params in the SQL log
|
|
||||||
Colorful: true,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
sqlDB, err2 := db.DB()
|
|
||||||
if err2 != nil {
|
|
||||||
fmt.Println(err2)
|
|
||||||
}
|
|
||||||
// SetMaxIdleConns sets the maximum number of connections in the idle connection pool
|
|
||||||
sqlDB.SetMaxIdleConns(conf.MaxIdleConns)
|
|
||||||
|
|
||||||
// SetMaxOpenConns sets the maximum number of open database connections.
|
|
||||||
sqlDB.SetMaxOpenConns(conf.MaxOpenConns)
|
|
||||||
|
|
||||||
return db
|
|
||||||
}
|
|
||||||
+5
-4
@@ -2,6 +2,7 @@ package orm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
"gorm.io/driver/sqlite"
|
"gorm.io/driver/sqlite"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/logger"
|
"gorm.io/gorm/logger"
|
||||||
@@ -13,11 +14,11 @@ type SqliteConfig struct {
|
|||||||
MaxOpenConns int
|
MaxOpenConns int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSqlite(sqliteConf *SqliteConfig, logwriter logger.Writer) *gorm.DB {
|
func NewSqlite(sqliteConf *SqliteConfig) *gorm.DB {
|
||||||
db, err := gorm.Open(sqlite.Open("./data/rustdeskapi.db"), &gorm.Config{
|
db, err := gorm.Open(sqlite.Open("./data/rustdeskapi.db"), &gorm.Config{
|
||||||
DisableForeignKeyConstraintWhenMigrating: true,
|
DisableForeignKeyConstraintWhenMigrating: true,
|
||||||
Logger: logger.New(
|
Logger: logger.New(
|
||||||
logwriter, // io writer
|
global.Logger, // io writer
|
||||||
logger.Config{
|
logger.Config{
|
||||||
SlowThreshold: time.Second, // Slow SQL threshold
|
SlowThreshold: time.Second, // Slow SQL threshold
|
||||||
LogLevel: logger.Warn, // Log level
|
LogLevel: logger.Warn, // Log level
|
||||||
@@ -34,10 +35,10 @@ func NewSqlite(sqliteConf *SqliteConfig, logwriter logger.Writer) *gorm.DB {
|
|||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
fmt.Println(err2)
|
fmt.Println(err2)
|
||||||
}
|
}
|
||||||
// SetMaxIdleConns sets the maximum number of connections in the idle connection pool
|
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
|
||||||
sqlDB.SetMaxIdleConns(sqliteConf.MaxIdleConns)
|
sqlDB.SetMaxIdleConns(sqliteConf.MaxIdleConns)
|
||||||
|
|
||||||
// SetMaxOpenConns sets the maximum number of open database connections.
|
// SetMaxOpenConns 设置打开数据库连接的最大数量。
|
||||||
sqlDB.SetMaxOpenConns(sqliteConf.MaxOpenConns)
|
sqlDB.SetMaxOpenConns(sqliteConf.MaxOpenConns)
|
||||||
|
|
||||||
return db
|
return db
|
||||||
|
|||||||
+5
-5
@@ -240,11 +240,11 @@ func getMD5FromNewAuthString(r *http.Request) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* VerifySignature
|
/* VerifySignature
|
||||||
* VerifySignature needs three pieces of data to perform signature verification: 1> obtain the public key PublicKey; 2> generate a new MD5 authentication string; 3> decode the authentication string carried by the Request;
|
* VerifySignature需要三个重要的数据信息来进行签名验证: 1>获取公钥PublicKey; 2>生成新的MD5鉴权串; 3>解码Request携带的鉴权串;
|
||||||
* 1> obtain the public key PublicKey: get the URL from the "x-oss-pub-key-url" field of the RequestHeader, read the public key content the URL points to, decode and parse it, and use it as the input parameter of rsa.VerifyPKCS1v15.
|
* 1>获取公钥PublicKey : 从RequestHeader的"x-oss-pub-key-url"字段中获取 URL, 读取URL链接的包含的公钥内容, 进行解码解析, 将其作为rsa.VerifyPKCS1v15的入参。
|
||||||
* 2> generate a new MD5 authentication string: urldecode the path part of the url in the Request, append the query part of the url, then append the body, combine them and apply MD5 encoding to obtain the MD5 authentication byte string.
|
* 2>生成新的MD5鉴权串 : 把Request中的url中的path部分进行urldecode, 加上url的query部分, 再加上body, 组合之后进行MD5编码, 得到MD5鉴权字节串。
|
||||||
* 3> decode the authentication string carried by the Request: get the "authorization" field of the RequestHeader and Base64-decode it to use as the comparison authentication string for signature verification.
|
* 3>解码Request携带的鉴权串 : 获取RequestHeader的"authorization"字段, 对其进行Base64解码,作为签名验证的鉴权对比串。
|
||||||
* rsa.VerifyPKCS1v15 performs the signature verification and returns the result.
|
* rsa.VerifyPKCS1v15进行签名验证,返回验证结果。
|
||||||
* */
|
* */
|
||||||
func verifySignature(bytePublicKey []byte, byteMd5 []byte, authorization []byte) bool {
|
func verifySignature(bytePublicKey []byte, byteMd5 []byte, authorization []byte) bool {
|
||||||
pubBlock, _ := pem.Decode(bytePublicKey)
|
pubBlock, _ := pem.Decode(bytePublicKey)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import "github.com/lejianwen/rustdesk-api/v2/model/custom_types"
|
|||||||
// String loginName; //login username
|
// String loginName; //login username
|
||||||
// bool? sameServer;
|
// bool? sameServer;
|
||||||
|
|
||||||
// AddressBook some fields are only uploaded for Personal
|
// AddressBook 有些字段是Personal才会上传的
|
||||||
type AddressBook struct {
|
type AddressBook struct {
|
||||||
RowId uint `gorm:"primaryKey" json:"row_id"`
|
RowId uint `gorm:"primaryKey" json:"row_id"`
|
||||||
Id string `json:"id" gorm:"default:0;not null;index"`
|
Id string `json:"id" gorm:"default:0;not null;index"`
|
||||||
@@ -59,8 +59,8 @@ type AddressBookCollectionRule struct {
|
|||||||
IdModel
|
IdModel
|
||||||
UserId uint `json:"user_id" gorm:"default:0;not null;"`
|
UserId uint `json:"user_id" gorm:"default:0;not null;"`
|
||||||
CollectionId uint `json:"collection_id" gorm:"default:0;not null;index" validate:"required"`
|
CollectionId uint `json:"collection_id" gorm:"default:0;not null;index" validate:"required"`
|
||||||
Rule int `json:"rule" gorm:"default:0;not null;" validate:"required,gte=1,lte=3"` // 0: none 1: read 2: read-write 3: full control
|
Rule int `json:"rule" gorm:"default:0;not null;" validate:"required,gte=1,lte=3"` // 0: 无 1: 读 2: 读写 3: 完全控制
|
||||||
Type int `json:"type" gorm:"default:1;not null;" validate:"required,gte=1,lte=2"` // 1: personal 2: group
|
Type int `json:"type" gorm:"default:1;not null;" validate:"required,gte=1,lte=2"` // 1: 个人 2: 群组
|
||||||
ToId uint `json:"to_id" gorm:"default:0;not null;" validate:"required,gt=0"`
|
ToId uint `json:"to_id" gorm:"default:0;not null;" validate:"required,gt=0"`
|
||||||
TimeModel
|
TimeModel
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AutoJson data type
|
// AutoJson 数据类型
|
||||||
type AutoJson json.RawMessage
|
type AutoJson json.RawMessage
|
||||||
|
|
||||||
func (j *AutoJson) Scan(value interface{}) error {
|
func (j *AutoJson) Scan(value interface{}) error {
|
||||||
@@ -33,7 +33,7 @@ func (j *AutoJson) Scan(value interface{}) error {
|
|||||||
}
|
}
|
||||||
result := &json.RawMessage{}
|
result := &json.RawMessage{}
|
||||||
err := json.Unmarshal(bytes, result)
|
err := json.Unmarshal(bytes, result)
|
||||||
// json parse error, return empty
|
//解析json错误 返回空
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*j = AutoJson(json.RawMessage{'[', ']'})
|
*j = AutoJson(json.RawMessage{'[', ']'})
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AutoTime custom time format
|
// AutoTime 自定义时间格式
|
||||||
type AutoTime time.Time
|
type AutoTime time.Time
|
||||||
|
|
||||||
func (mt AutoTime) Value() (driver.Value, error) {
|
func (mt AutoTime) Value() (driver.Value, error) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user