Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
290
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
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 }}
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- { platform: "amd64", goos: "linux" }
|
||||
- { platform: "arm64", goos: "linux" }
|
||||
- { platform: "amd64", goos: "windows" }
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- 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
|
||||
run: |
|
||||
git clone ${{ env.WEBCLIENT_SOURCE_LOCATION }}
|
||||
cd rustdesk-api-web
|
||||
npm install
|
||||
npm run build
|
||||
mkdir ../resources/admin/ -p
|
||||
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
|
||||
zip -r ${{ matrix.job.goos}}-${{ matrix.job.platform }}.zip ./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
|
||||
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 }}.tar.gz ./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 }}.tar.gz
|
||||
${{ matrix.job.goos}}-${{ matrix.job.platform }}.zip
|
||||
- name: Upload to GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
${{ matrix.job.goos}}-${{ matrix.job.platform }}.tar.gz
|
||||
${{ matrix.job.goos}}-${{ matrix.job.platform }}.zip
|
||||
# tag_name: ${{ env.LATEST_TAG }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
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" }
|
||||
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 }}
|
||||
file ${{ matrix.job.platform }}/apimain
|
||||
|
||||
- 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 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 }}
|
||||
|
||||
#
|
||||
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 }}-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 }}-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-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-arm64
|
||||
push: true
|
||||
amend: true
|
||||
95
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# tags:
|
||||
# - 'v*.*.*' # 当推送带有版本号的 tag(例如 v1.0.0)时触发工作流
|
||||
#on:
|
||||
# push:
|
||||
# branches: [ "master" ]
|
||||
# pull_request:
|
||||
# branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
goos: [ linux, windows ] # 指定要构建的操作系统
|
||||
goarch: [ amd64 ] # 指定架构
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- 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: install gcc zip musl
|
||||
run: |
|
||||
if [ "${{ matrix.goos }}" = "windows" ]; then
|
||||
sudo apt-get install gcc-mingw-w64-x86-64 zip -y
|
||||
else
|
||||
sudo apt-get install musl musl-dev musl-tools -y
|
||||
fi
|
||||
|
||||
|
||||
- name: build rustdesk-api-web
|
||||
run: |
|
||||
git clone https://github.com/lejianwen/rustdesk-api-web
|
||||
cd rustdesk-api-web
|
||||
npm install
|
||||
npm run build
|
||||
mkdir ../resources/admin/ -p
|
||||
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.goos }}-${{ matrix.goarch }}
|
||||
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.goos }}" = "windows" ]; then
|
||||
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain.exe ./cmd/apimain.go
|
||||
zip -r ${{ matrix.goos}}-${{ matrix.goarch }}.zip ./release
|
||||
else
|
||||
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} CC=musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||
tar -czf ${{ matrix.goos}}-${{ matrix.goarch }}.tar.gz ./release
|
||||
fi
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: myapp-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
path: |
|
||||
${{ matrix.goos}}-${{ matrix.goarch }}.tar.gz
|
||||
${{ matrix.goos}}-${{ matrix.goarch }}.zip
|
||||
|
||||
- name: Upload to GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
${{ matrix.goos}}-${{ matrix.goarch }}.tar.gz
|
||||
${{ matrix.goos}}-${{ matrix.goarch }}.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
1
.gitignore
vendored
@@ -5,5 +5,6 @@ go.sum
|
||||
resources/*
|
||||
!resources/public/upload/.gitignore
|
||||
!resources/web
|
||||
!resources/i18n
|
||||
release
|
||||
data
|
||||
40
Dockerfile
@@ -1,39 +1,11 @@
|
||||
FROM golang:1.22-alpine as builder
|
||||
|
||||
RUN set -eux; \
|
||||
apk add --no-cache git gcc build-base sqlite-dev npm nodejs; \
|
||||
git clone https://github.com/lejianwen/rustdesk-api-web; \
|
||||
git clone https://github.com/lejianwen/rustdesk-api; \
|
||||
#先编译后台
|
||||
cd rustdesk-api-web; \
|
||||
npm install; \
|
||||
npm run build; \
|
||||
cd ..; \
|
||||
mkdir -p rustdesk-api/resources/admin; \
|
||||
cp -ar rustdesk-api-web/dist/* rustdesk-api/resources/admin; \
|
||||
cd rustdesk-api; \
|
||||
go mod tidy; \
|
||||
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; \
|
||||
go env -w GO111MODULE=on;\
|
||||
go env -w CGO_ENABLED=1;\
|
||||
go env -w GOOS=linux;\
|
||||
go env -w GOARCH=amd64;\
|
||||
go env -w CGO_LDFLAGS="-static"; \
|
||||
go build -o release/apimain cmd/apimain.go; \
|
||||
cp -ar resources release/; \
|
||||
mkdir -p release/resources/public; \
|
||||
cp -ar docs release/; \
|
||||
cp -ar conf release/; \
|
||||
mkdir -p release/data; \
|
||||
mkdir -p release/runtime;
|
||||
|
||||
VOLUME /app/data
|
||||
FROM alpine
|
||||
|
||||
ARG BUILDARCH
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache tzdata
|
||||
COPY --from=builder /go/rustdesk-api/release /app/
|
||||
RUN apk add --no-cache tzdata file
|
||||
COPY ./${BUILDARCH}/release /app/
|
||||
RUN file /app/apimain
|
||||
VOLUME /app/data
|
||||
|
||||
EXPOSE 21114
|
||||
CMD ["./apimain"]
|
||||
|
||||
267
README.md
@@ -2,37 +2,90 @@
|
||||
|
||||
[English Doc](README_EN.md)
|
||||
|
||||
本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web UI 和 Web 客户端。RustDesk 是一个远程桌面软件,提供了自托管的解决方案。
|
||||
本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web Admin 和 Web 客户端。RustDesk 是一个远程桌面软件,提供了自托管的解决方案。
|
||||
|
||||
<div align=center>
|
||||
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
||||
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
|
||||
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
|
||||
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
|
||||
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
||||
</div>
|
||||
|
||||
# 特性
|
||||
|
||||
- PC端API
|
||||
- 个人版API
|
||||
- 登录
|
||||
- 地址簿
|
||||
- 群组
|
||||
- 授权登录,支持`github`和`google`登录,支持`web后台`授权登录
|
||||
- i18n
|
||||
- Web Admin
|
||||
- 用户管理
|
||||
- 设备管理
|
||||
- 地址簿管理
|
||||
- 标签管理
|
||||
- 群组管理
|
||||
- Oauth 管理
|
||||
- 快速使用web client
|
||||
- i18n
|
||||
- 通过 web client 分享给游客
|
||||
- Web Client
|
||||
- 自动获取API server
|
||||
- 自动获取ID服务器和KEY
|
||||
- 自动获取地址簿
|
||||
- 游客通过临时分享链接直接远程到设备
|
||||
|
||||
## 使用前准备
|
||||
|
||||
### [Rustdesk](https://github.com/rustdesk/rustdesk)
|
||||
|
||||
1. PC客户端使用的是 ***1.3.0***,经测试 ***1.2.6+*** 都可以
|
||||
2. server端必须指定key,不能用自带的生成的key,否则可能链接不上或者超时
|
||||
#### PC客户端使用的是 ***1.3.0***,经测试 ***1.2.6+*** 都可以
|
||||
|
||||
#### 关于PC端链接超时或者链接不上的问题以及解决方案
|
||||
##### 链接不上是或者超时
|
||||
因为server端相对于客户端落后版本,server不会响应客户端的`secure_tcp`请求,所以客户端超时。
|
||||
相关代码代码位置在`https://github.com/rustdesk/rustdesk/blob/master/src/client.rs#L322`
|
||||
```rust
|
||||
if !key.is_empty() && !token.is_empty() {
|
||||
// mainly for the security of token
|
||||
allow_err!(secure_tcp(&mut socket, key).await);
|
||||
}
|
||||
```
|
||||
可看到当`key`和`token`都不为空时,会调用`secure_tcp`,但是server端不会响应,所以客户端超时
|
||||
`secure_tcp` 代码位置在 `https://github.com/rustdesk/rustdesk/blob/master/src/common.rs#L1203`
|
||||
|
||||
##### 4种解决方案
|
||||
1. server端指定key。
|
||||
- 优点:简单
|
||||
- 缺点:链接不是加密的
|
||||
```bash
|
||||
hbbs -r <relay-server-ip[:port]> -k <key>
|
||||
hbbr -k <key>
|
||||
```
|
||||
|
||||
比如
|
||||
|
||||
```bash
|
||||
hbbs -r <relay-server-ip[:port]> -k abc1234567
|
||||
hbbr -k abc1234567
|
||||
```
|
||||
2. server端使用系统生成的key,或者自定义的密钥对,但如果client已登录,链接时容易超时或者链接不上,可以退出登录后再链接就可以了,webclient可以不用退出登录
|
||||
- 优点:链接加密
|
||||
- 缺点:操作麻烦
|
||||
3. server端使用系统生成的key,或者自定义的密钥对,fork官方客户端的代码将`secure_tcp`修改成直接返回,然后通过`Github Actions`编译,下载编译后的客户端。
|
||||
参考[官方文档](https://rustdesk.com/docs/en/dev/build/all/)
|
||||
- 优点:链接加密,可以自定义客户端一些功能,编译后直接可用
|
||||
- 缺点:需要自己fork代码,编译,有点难度
|
||||
4. 使用[我fork的代码](https://github.com/lejianwen/rustdesk),已经修改了`secure_tcp`,可以直接下载使用,[下载地址](https://github.com/lejianwen/rustdesk/releases)
|
||||
- 优点:代码改动可查看,`Github Actions`编译,链接加密,直接下载使用
|
||||
- 缺点:可能跟不上官方版本更新
|
||||
|
||||
***对链接加密要求不高的可以使用`1`,对链接加密要求高的可以使用`3`或`4`***
|
||||
|
||||
## 功能
|
||||
|
||||
### API 服务: 基本实现了PC端基础的接口。
|
||||
### API 服务
|
||||
基本实现了PC端基础的接口。支持Personal版本接口,可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
|
||||
|
||||
#### 登录
|
||||
|
||||
@@ -45,35 +98,36 @@
|
||||
|
||||

|
||||
|
||||
#### 群组,群组分为`共享组`和`普通组`,共享组中所有人都能看到小组成员的地址,普通组只有管理员能看到所有小组成员的地址
|
||||
#### 群组
|
||||
群组分为`共享组`和`普通组`,共享组中所有人都能看到小组成员的设备,普通组只有管理员能看到所有小组成员的设备
|
||||
|
||||

|
||||
|
||||
### **Web UI**: 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。
|
||||
### Web Admin:
|
||||
|
||||
***前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)***
|
||||
* 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
||||
|
||||
***后台访问地址是`http://<your server>[:port]/_admin/`初次安装管理员为用户名密码为`admin` `admin`,请即时更改密码***
|
||||
* 后台访问地址是`http://<your server>[:port]/_admin/`初次安装管理员为用户名密码为`admin` `admin`,请即时更改密码
|
||||
|
||||
1. 管理员界面
|
||||

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

|
||||
3. 右上角也可以更改密码
|
||||
右上角可以更改密码,也可以切换语言
|
||||

|
||||
|
||||
4. 分组可以自定义,方便管理,暂时支持两种类型: `共享组` 和 `普通组`
|
||||
3. 分组可以自定义,方便管理,暂时支持两种类型: `共享组` 和 `普通组`
|
||||

|
||||
5. 可以直接打开webclient,方便使用
|
||||
4. 可以直接打开webclient,方便使用;也可以分享给游客,游客可以直接通过webclient远程到设备
|
||||

|
||||
6. Oauth,暂时只支持了`Github`和`Google`, 需要创建一个`OAuth App`,然后配置到后台
|
||||
5. Oauth,暂时只支持了`Github`和`Google`, 需要创建一个`OAuth App`,然后配置到后台
|
||||

|
||||
- `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`
|
||||
|
||||
### **Web Client**:
|
||||
### Web Client:
|
||||
|
||||
1. 如果已经登录了后台,web client将自动直接登录
|
||||
2. 如果没登录后台,点击右上角登录即可,api server已经自动配置好了
|
||||
@@ -81,19 +135,24 @@
|
||||
3. 登录后,会自动同步ID服务器和KEY
|
||||
4. 登录后,会将地址簿自动保存到web client中,方便使用
|
||||
|
||||
### **自动化文档**: 使用 Swag 生成 API 文档,方便开发者理解和使用 API。
|
||||
### 自动化文档: 使用 Swag 生成 API 文档,方便开发者理解和使用 API。
|
||||
|
||||
1. 后台文档 `<youer server>/admin/swagger/index.html`
|
||||
2. PC端文档 `<youer server>/swagger/index.html`
|
||||
1. 后台文档 `<youer server[:port]>/admin/swagger/index.html`
|
||||
2. PC端文档 `<youer server[:port]>/swagger/index.html`
|
||||

|
||||
|
||||
## 安装与运行
|
||||
|
||||
### 相关配置
|
||||
|
||||
* 参考`conf/config.yaml`配置文件,修改相关配置。如果`gorm.type`是`sqlite`,则不需要配置mysql相关配置。
|
||||
* 参考`conf/config.yaml`配置文件,修改相关配置。
|
||||
* 如果`gorm.type`是`sqlite`,则不需要配置mysql相关配置。
|
||||
* 语言如果不设置默认为`zh-CN`
|
||||
|
||||
```yaml
|
||||
lang: "en"
|
||||
app:
|
||||
web-client: 1 # 1:启用 0:禁用
|
||||
gin:
|
||||
api-addr: "0.0.0.0:21114"
|
||||
mode: "release"
|
||||
@@ -113,20 +172,29 @@ rustdesk:
|
||||
relay-server: "192.168.1.66:21117"
|
||||
api-server: "http://192.168.1.66:21114"
|
||||
key: "123456789"
|
||||
personal: 1
|
||||
logger:
|
||||
path: "./runtime/log.txt"
|
||||
level: "warn" #trace,debug,info,warn,error,fatal
|
||||
report-caller: true
|
||||
```
|
||||
|
||||
* 环境变量,变量名前缀是RUSTDESK_API,环境变量如果存在将覆盖配置文件中的配置
|
||||
### 环境变量
|
||||
变量名前缀是`RUSTDESK_API`,环境变量如果存在将覆盖配置文件中的配置
|
||||
|
||||
| 变量名 | 说明 | 示例 |
|
||||
|:------------------------------------|:-------------------------------------|-----------------------------|
|
||||
|------------------------------------|--------------------------------------|-----------------------------|
|
||||
| TZ | 时区 | Asia/Shanghai |
|
||||
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
|
||||
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
|
||||
| -----GIN配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
||||
| -----------GORM配置------------------ | ------------------------------------ | --------------------------- |
|
||||
| -----------GORM配置---------------- | ------------------------------------ | --------------------------- |
|
||||
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
||||
| -----MYSQL配置----- | -----数据库类型为sqlite时不用填----- | ---------- |
|
||||
| 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 |
|
||||
@@ -137,7 +205,7 @@ rustdesk:
|
||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
||||
|
||||
### 安装步骤
|
||||
### 运行
|
||||
|
||||
#### docker运行
|
||||
|
||||
@@ -147,18 +215,17 @@ rustdesk:
|
||||
docker run -d --name rustdesk-api -p 21114:21114 \
|
||||
-v /data/rustdesk/api:/app/data \
|
||||
-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_RELAY_SERVER=192.168.1.66:21117 \
|
||||
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
||||
-e RUSTDESK_API_RUSTDESK_KEY=123456789 \
|
||||
-e RUSTDESK_API_RUSTDESK_KEY=<key> \
|
||||
lejianwen/rustdesk-api
|
||||
```
|
||||
|
||||
2. 使用`docker compose`
|
||||
|
||||
- 简单示例
|
||||
|
||||
```docker-compose
|
||||
```yaml
|
||||
services:
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
@@ -167,7 +234,7 @@ lejianwen/rustdesk-api
|
||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
||||
- RUSTDESK_API_RUSTDESK_KEY=123456789
|
||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
@@ -178,9 +245,9 @@ lejianwen/rustdesk-api
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
- 根据rustdesk提供的示例加上自己的rustdesk-api
|
||||
|
||||
```docker-compose
|
||||
- 根据rustdesk官方提供的示例,加上自己的rustdesk-api
|
||||
- 如果是使用的系统生成的KEY,去掉`-k <key>`参数,在启动后运行`docker-compose logs hbbs`或者`cat ./data/id_ed25519.pub`查看KEY,然后再修改`RUSTDESK_API_RUSTDESK_KEY=<key>`再执行`docker-compose up -d`
|
||||
```yaml
|
||||
networks:
|
||||
rustdesk-net:
|
||||
external: false
|
||||
@@ -191,11 +258,11 @@ lejianwen/rustdesk-api
|
||||
- 21115:21115
|
||||
- 21116:21116 # 自定义 hbbs 映射端口
|
||||
- 21116:21116/udp # 自定义 hbbs 映射端口
|
||||
- 21118:21118 # web client 需要
|
||||
- 21118:21118 # web client
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbs -r <relay-server-ip[:port]> -k 123456789 # 填入个人域名或 IP + hbbr 暴露端口
|
||||
command: hbbs -r <relay-server-ip[:port]> -k <key> # 填入个人域名或 IP + hbbr 暴露端口
|
||||
volumes:
|
||||
- /data/rustdesk/hbbs:/root # 自定义挂载目录
|
||||
- ./data:/root # 自定义挂载目录
|
||||
networks:
|
||||
- rustdesk-net
|
||||
depends_on:
|
||||
@@ -209,11 +276,11 @@ lejianwen/rustdesk-api
|
||||
container_name: hbbr
|
||||
ports:
|
||||
- 21117:21117 # 自定义 hbbr 映射端口
|
||||
- 21119:21119 # web client
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbr -k 123456789
|
||||
#command: hbbr
|
||||
command: hbbr -k <key>
|
||||
volumes:
|
||||
- /data/rustdesk/hbbr:/root # 自定义挂载目录
|
||||
- ./data:/root
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
@@ -228,7 +295,7 @@ lejianwen/rustdesk-api
|
||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
||||
- RUSTDESK_API_RUSTDESK_KEY=123456789
|
||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
@@ -237,12 +304,111 @@ lejianwen/rustdesk-api
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
|
||||
```
|
||||
|
||||
- S6的镜像
|
||||
- 如果使用***自定义KEY***,会需要修改启动脚本,覆盖镜像中的`/etc/s6-overlay/s6-rc.d/hbbr/run`和`/etc/s6-overlay/s6-rc.d/hbbr/run`
|
||||
1. 创建`hbbr/run`,自定义KEY才需要
|
||||
```bash
|
||||
#!/command/with-contenv sh
|
||||
cd /data
|
||||
PARAMS=
|
||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
||||
/usr/bin/hbbr $PARAMS
|
||||
```
|
||||
2. 创建`hbbs/run`,自定义KEY才需要
|
||||
```bash
|
||||
#!/command/with-contenv sh
|
||||
sleep 2
|
||||
cd /data
|
||||
PARAMS=
|
||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
||||
/usr/bin/hbbs -r $RELAY $PARAMS
|
||||
```
|
||||
3. 修改`docker-compose.yml`中的`s6`部分
|
||||
```yaml
|
||||
networks:
|
||||
rustdesk-net:
|
||||
external: false
|
||||
services:
|
||||
rustdesk-server:
|
||||
container_name: rustdesk-server
|
||||
ports:
|
||||
- 21115:21115
|
||||
- 21116:21116
|
||||
- 21116:21116/udp
|
||||
- 21117:21117
|
||||
- 21118:21118
|
||||
- 21119:21119
|
||||
image: rustdesk/rustdesk-server-s6:latest
|
||||
environment:
|
||||
- RELAY=192.168.1.66:21117
|
||||
- ENCRYPTED_ONLY=1
|
||||
- KEY=<key> #自定义KEY
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./hbbr/run:/etc/s6-overlay/s6-rc.d/hbbr/run
|
||||
- ./hbbs/run:/etc/s6-overlay/s6-rc.d/hbbs/run
|
||||
restart: unless-stopped
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data #将数据库挂载
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
- 如果使用***系统生成的KEY***或者***自定义KEY_PUB,KEY_PRIV***,不需要修改启动脚本,但要在生成KEY后获取到KEY再`docker-compose up -d`
|
||||
```yaml
|
||||
networks:
|
||||
rustdesk-net:
|
||||
external: false
|
||||
services:
|
||||
rustdesk-server:
|
||||
container_name: rustdesk-server
|
||||
ports:
|
||||
- 21115:21115
|
||||
- 21116:21116
|
||||
- 21116:21116/udp
|
||||
- 21117:21117
|
||||
- 21118:21118
|
||||
- 21119:21119
|
||||
image: rustdesk/rustdesk-server-s6:latest
|
||||
environment:
|
||||
- RELAY=192.168.1.66:21117
|
||||
- ENCRYPTED_ONLY=1
|
||||
volumes:
|
||||
- ./data:/data
|
||||
restart: unless-stopped
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
||||
- RUSTDESK_API_RUSTDESK_KEY=<key> #系统生成的KEY
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data #将数据库挂载
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
#### 下载release直接运行
|
||||
|
||||
下载地址[release](https://github.com/lejianwen/rustdesk-api/releases)
|
||||
[下载地址](https://github.com/lejianwen/rustdesk-api/releases)
|
||||
|
||||
#### 源码安装
|
||||
|
||||
@@ -280,9 +446,24 @@ lejianwen/rustdesk-api
|
||||
5. 编译,如果想自己编译,先cd到项目根目录,然后windows下直接运行`build.bat`,linux下运行`build.sh`,编译后会在`release`
|
||||
目录下生成对应的可执行文件。直接运行编译后的可执行文件即可。
|
||||
|
||||
6. 打开浏览器访问`http://<your server>:21114/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
||||
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
||||
|
||||
#### nginx反代
|
||||
在`nginx`中配置反代
|
||||
```
|
||||
server {
|
||||
listen <your port>;
|
||||
server_name <your server>;
|
||||
location / {
|
||||
proxy_pass http://<api-server[:port]>;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
## 其他
|
||||
|
||||
- [修改客户端ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
||||
- [webclient](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
||||
- [webclient来源](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
||||
302
README_EN.md
@@ -8,74 +8,131 @@ desktop software that provides self-hosted solutions.
|
||||
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
|
||||
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
|
||||
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
|
||||
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
||||
</div>
|
||||
|
||||
# Features
|
||||
|
||||
- PC API
|
||||
- Personal API
|
||||
- Login
|
||||
- Address Book
|
||||
- Groups
|
||||
- Authorized login, supports `GitHub` and `Google` login, supports `web admin` authorized login
|
||||
- i18n
|
||||
- Web Admin
|
||||
- User Management
|
||||
- Device Management
|
||||
- Address Book Management
|
||||
- Tag Management
|
||||
- Group Management
|
||||
- OAuth Management
|
||||
- Quick access to web client
|
||||
- i18n
|
||||
- Share to guest by web client
|
||||
- Web Client
|
||||
- Automatically obtain API server
|
||||
- Automatically obtain ID server and KEY
|
||||
- Automatically obtain address book
|
||||
- Visitors are remotely to the device via a temporary sharing link
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### [Rustdesk](https://github.com/rustdesk/rustdesk)
|
||||
|
||||
1. The PC client version used is ***1.3.0***, and versions ***1.2.6+*** have been tested to work.
|
||||
2. The server must specify a key, and not use the auto-generated key, otherwise there may be connection failures or
|
||||
timeouts.
|
||||
|
||||
#### The PC client uses version ***1.3.0***, and versions ***1.2.6+*** have been tested to work.
|
||||
|
||||
#### Solutions for PC client connection timeout or connection issues
|
||||
##### Connection issues or timeouts
|
||||
Because the server version lags behind the client version, the server does not respond to the client's `secure_tcp` request, causing the client to timeout.
|
||||
Relevant code can be found at `https://github.com/rustdesk/rustdesk/blob/master/src/client.rs#L322`
|
||||
```rust
|
||||
if !key.is_empty() && !token.is_empty() {
|
||||
// mainly for the security of token
|
||||
allow_err!(secure_tcp(&mut socket, key).await);
|
||||
}
|
||||
```
|
||||
|
||||
As seen, when both `key` and `token` are not empty, `secure_tcp` is called, but the server does not respond, causing the client to timeout.
|
||||
The `secure_tcp` code is located at `https://github.com/rustdesk/rustdesk/blob/master/src/common.rs#L1203`
|
||||
|
||||
##### Four Solutions
|
||||
1. Specify the key on the server.
|
||||
- Advantage: Simple
|
||||
- Disadvantage: The connection is not encrypted
|
||||
```bash
|
||||
hbbs -r <relay-server-ip[:port]> -k <key>
|
||||
hbbr -k <key>
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
For example
|
||||
```bash
|
||||
hbbs -r <relay-server-ip[:port]> -k abc1234567
|
||||
hbbr -k abc1234567
|
||||
```
|
||||
2. Use a system-generated key or a custom key pair on the server. If the client is already logged in, it may timeout or fail to connect. Logging out and reconnecting usually resolves the issue, and the web client does not need to log out.
|
||||
- Advantage: Encrypted connection
|
||||
- Disadvantage: Complicated operation
|
||||
3. Use a system-generated key or a custom key pair on the server, fork the official client code to modify `secure_tcp` to return directly, then compile using `Github Actions` and download the compiled client.
|
||||
Refer to [official documentation](https://rustdesk.com/docs/en/dev/build/all/)
|
||||
- Advantage: Encrypted connection, customizable client features, ready to use after compilation
|
||||
- Disadvantage: Requires forking code and compiling, which can be challenging
|
||||
4. Use [my forked code](https://github.com/lejianwen/rustdesk), which has already modified `secure_tcp`. You can download and use it directly from [here](https://github.com/lejianwen/rustdesk/releases)
|
||||
- Advantage: Code changes are viewable, compiled with `Github Actions`, encrypted connection, ready to use
|
||||
- Disadvantage: May not keep up with official version updates
|
||||
|
||||
## Features
|
||||
***If encryption is not a high priority, use `1`. If encryption is important, use `3` or `4`.***
|
||||
|
||||
### API Service: Basic implementation of the PC client's primary interfaces.
|
||||
## 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.
|
||||
|
||||
#### Login
|
||||
|
||||
- Added `GitHub` and `Google` login, which can be used after configuration in the admin panel. See the OAuth configuration section
|
||||
for details.
|
||||
- Added `GitHub` and `Google` login, which can be used after configuration in the admin panel. See the OAuth
|
||||
configuration section for details.
|
||||
- Added authorization login for the web admin panel.
|
||||
|
||||

|
||||

|
||||
|
||||
#### Address Book
|
||||
|
||||

|
||||

|
||||
|
||||
#### Groups: Groups are divided into `shared groups` and `regular groups`. In shared groups, everyone can see the addresses of all group members, while in regular groups, only administrators can see all members' addresses.
|
||||
#### Groups
|
||||
Groups are divided into `shared groups` and `regular groups`. In shared groups, everyone can see the peers of all group members, while in regular groups, only administrators can see all members' peers.
|
||||
|
||||

|
||||

|
||||
|
||||
### **Web UI**: The frontend and backend are separated to provide a user-friendly management interface, primarily for managing and displaying data.
|
||||
### Web Admin
|
||||
|
||||
***Frontend code is available at [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)
|
||||
|
||||
***Admin panel URL: `http://<your server>[:port]/_admin/`. The default username and password for the initial
|
||||
installation are `admin` `admin`, please change the password immediately.***
|
||||
* Admin panel URL: `http://<your server[:port]>/_admin/`. The default username and password for the initial
|
||||
installation are `admin` `admin`, please change the password immediately.
|
||||
|
||||
1. Admin interface:
|
||||

|
||||

|
||||
2. Regular user interface:
|
||||

|
||||
3. You can change your password from the top right corner:
|
||||

|
||||
4. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
|
||||

|
||||
5. You can open the web client directly for convenience:
|
||||

|
||||
6. OAuth support: Currently, `GitHub` and `Google` is supported. You need to create an `OAuth App` and configure it in the admin
|
||||

|
||||
You can change your password from the top right corner:
|
||||

|
||||
3. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
|
||||

|
||||
4. You can directly open the web client for convenient use; it can also be shared with guests, allowing them to remotely access the device via the web client.
|
||||

|
||||
5. OAuth support: Currently, `GitHub` and `Google` is supported. You need to create an `OAuth App` and configure it in
|
||||
the admin
|
||||
panel.
|
||||

|
||||

|
||||
- 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`.
|
||||
|
||||
### **Web Client**:
|
||||
### Web Client:
|
||||
|
||||
1. If you're already logged into the admin panel, the web client will log in automatically.
|
||||
2. If you're not logged in, simply click the login button at the top right corner, and the API server will be
|
||||
@@ -84,20 +141,24 @@ installation are `admin` `admin`, please change the password immediately.***
|
||||
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.
|
||||
|
||||
### **Automated Documentation** : API documentation is generated using Swag, making it easier for developers to understand and use the API.
|
||||
### 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>/admin/swagger/index.html`
|
||||
2. PC client docs: `<your server>/swagger/index.html`
|
||||
1. Admin panel docs: `<your server[:port]>/admin/swagger/index.html`
|
||||
2. PC client docs: `<your server[:port]>/swagger/index.html`
|
||||

|
||||
|
||||
## Installation and Setup
|
||||
|
||||
### Configuration
|
||||
|
||||
* Modify the configuration in `conf/config.yaml`. If `gorm.type` is set to `sqlite`, MySQL-related configurations are
|
||||
not required.
|
||||
* Modify the configuration in `conf/config.yaml`.
|
||||
* If `gorm.type` is set to `sqlite`, MySQL-related configurations are not required.
|
||||
* Language support: `en` and `zh-CN` are supported. The default is `zh-CN`.
|
||||
|
||||
```yaml
|
||||
lang: "en"
|
||||
app:
|
||||
web-client: 1 # web client route 1:open 0:close
|
||||
gin:
|
||||
api-addr: "0.0.0.0:21114"
|
||||
mode: "release"
|
||||
@@ -117,25 +178,34 @@ rustdesk:
|
||||
relay-server: "192.168.1.66:21117"
|
||||
api-server: "http://192.168.1.66:21114"
|
||||
key: "123456789"
|
||||
personal: 1
|
||||
logger:
|
||||
path: "./runtime/log.txt"
|
||||
level: "warn" #trace,debug,info,warn,error,fatal
|
||||
report-caller: true
|
||||
```
|
||||
|
||||
* Environment variables, with the prefix `RUSTDESK_API`, will override the settings in the configuration file if
|
||||
present.
|
||||
### Environment Variables
|
||||
The prefix for variable names is `RUSTDESK_API`. If environment variables exist, they will override the configurations in the configuration file.
|
||||
|
||||
| Variable Name | Description | Example |
|
||||
|------------------------------------|-----------------------------------------------------------|--------------------------------|
|
||||
| ----- GIN Configuration ----- | --------------------------------------- | ------------------------------ |
|
||||
|------------------------------------|-----------------------------------------------------------|-------------------------------|
|
||||
| TZ | timezone | Asia/Shanghai |
|
||||
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
||||
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, deault 1 | 1 |
|
||||
| ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
||||
| ----- GORM Configuration ----- | --------------------------------------- | ------------------------------ |
|
||||
| ----- 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 |
|
||||
| ----- MYSQL Configuration ----- | --------------------------------------- | ------------------------------ |
|
||||
| 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 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 |
|
||||
@@ -151,26 +221,26 @@ rustdesk:
|
||||
```bash
|
||||
docker run -d --name rustdesk-api -p 21114:21114 \
|
||||
-v /data/rustdesk/api:/app/data \
|
||||
-e RUSTDESK_API_LANG=en \
|
||||
-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_API_SERVER=http://192.168.1.66:21114 \
|
||||
-e RUSTDESK_API_RUSTDESK_KEY=123456789 \
|
||||
-e RUSTDESK_API_RUSTDESK_KEY=abc123456 \
|
||||
lejianwen/rustdesk-api
|
||||
```
|
||||
|
||||
2. Using `docker-compose`
|
||||
|
||||
- Simple example:
|
||||
|
||||
```docker-compose
|
||||
```yaml
|
||||
services:
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
environment:
|
||||
- RUSTDESK_API_LANG=en
|
||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
||||
- RUSTDESK_API_RUSTDESK_KEY=123456789
|
||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
@@ -182,8 +252,8 @@ lejianwen/rustdesk-api
|
||||
```
|
||||
|
||||
- Example with RustDesk's official Docker Compose file, adding your `rustdesk-api` service:
|
||||
|
||||
```docker-compose
|
||||
- If you are using a system-generated KEY, remove the `-k <key>` parameter. However, after the first startup, run `docker-compose logs hbbs` or `cat ./data/id_ed25519.pub` to view the KEY, then modify `RUSTDESK_API_RUSTDESK_KEY=<key>` and execute `docker-compose up -d` again.
|
||||
```yaml
|
||||
networks:
|
||||
rustdesk-net:
|
||||
external: false
|
||||
@@ -194,11 +264,11 @@ lejianwen/rustdesk-api
|
||||
- 21115:21115
|
||||
- 21116:21116 # 自定义 hbbs 映射端口
|
||||
- 21116:21116/udp # 自定义 hbbs 映射端口
|
||||
- 21118:21118 # web client 需要
|
||||
- 21118:21118 # web client
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbs -r <relay-server-ip[:port]> -k 123456789 # 填入个人域名或 IP + hbbr 暴露端口
|
||||
command: hbbs -r <relay-server-ip[:port]> -k <key> # 填入个人域名或 IP + hbbr 暴露端口
|
||||
volumes:
|
||||
- /data/rustdesk/hbbs:/root # 自定义挂载目录
|
||||
- ./data:/root # 自定义挂载目录
|
||||
networks:
|
||||
- rustdesk-net
|
||||
depends_on:
|
||||
@@ -212,11 +282,11 @@ lejianwen/rustdesk-api
|
||||
container_name: hbbr
|
||||
ports:
|
||||
- 21117:21117 # 自定义 hbbr 映射端口
|
||||
- 21119:21119 # web client
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbr -k 123456789
|
||||
#command: hbbr
|
||||
command: hbbr -k <key>
|
||||
volumes:
|
||||
- /data/rustdesk/hbbr:/root # 自定义挂载目录
|
||||
- ./data:/root
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
@@ -227,10 +297,11 @@ lejianwen/rustdesk-api
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
||||
- RUSTDESK_API_RUSTDESK_KEY=123456789
|
||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
@@ -239,7 +310,107 @@ lejianwen/rustdesk-api
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
- S6 image
|
||||
- - If using ***custom KEY***, you will need to modify the startup script to override the `/etc/s6-overlay/s6-rc.d/hbbr/run` and `/etc/s6-overlay/s6-rc.d/hbbr/run` in the image.
|
||||
1. Create `hbbr/run`, only needed for custom KEY
|
||||
```bash
|
||||
#!/command/with-contenv sh
|
||||
cd /data
|
||||
PARAMS=
|
||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
||||
/usr/bin/hbbr $PARAMS
|
||||
```
|
||||
2. Create `hbbs/run`, only needed for custom KEY
|
||||
```bash
|
||||
#!/command/with-contenv sh
|
||||
sleep 2
|
||||
cd /data
|
||||
PARAMS=
|
||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
||||
/usr/bin/hbbs -r $RELAY $PARAMS
|
||||
```
|
||||
3. Modify the `s6` section in `docker-compose.yml`
|
||||
```yaml
|
||||
networks:
|
||||
rustdesk-net:
|
||||
external: false
|
||||
services:
|
||||
rustdesk-server:
|
||||
container_name: rustdesk-server
|
||||
ports:
|
||||
- 21115:21115
|
||||
- 21116:21116
|
||||
- 21116:21116/udp
|
||||
- 21117:21117
|
||||
- 21118:21118
|
||||
- 21119:21119
|
||||
image: rustdesk/rustdesk-server-s6:latest
|
||||
environment:
|
||||
- RELAY=192.168.1.66:21117
|
||||
- ENCRYPTED_ONLY=1
|
||||
- KEY=<key> #KEY
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./hbbr/run:/etc/s6-overlay/s6-rc.d/hbbr/run
|
||||
- ./hbbs/run:/etc/s6-overlay/s6-rc.d/hbbs/run
|
||||
restart: unless-stopped
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
- If using ***system-generated KEY*** or ***custom KEY_PUB, KEY_PRIV***, you do not need to modify the startup script, but you need to obtain the KEY after it is generated and then run `docker-compose up -d`
|
||||
```yaml
|
||||
networks:
|
||||
rustdesk-net:
|
||||
external: false
|
||||
services:
|
||||
rustdesk-server:
|
||||
container_name: rustdesk-server
|
||||
ports:
|
||||
- 21115:21115
|
||||
- 21116:21116
|
||||
- 21116:21116/udp
|
||||
- 21117:21117
|
||||
- 21118:21118
|
||||
- 21119:21119
|
||||
image: rustdesk/rustdesk-server-s6:latest
|
||||
environment:
|
||||
- RELAY=192.168.1.66:21117
|
||||
- ENCRYPTED_ONLY=1
|
||||
volumes:
|
||||
- ./data:/data
|
||||
restart: unless-stopped
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
#### Running from Release
|
||||
@@ -286,10 +457,25 @@ Download the release from [release](https://github.com/lejianwen/rustdesk-api/re
|
||||
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>:21114/_admin/`, with default credentials `admin admin`. Please
|
||||
6. Open your browser and visit `http://<your server[:port]>/_admin/`, with default credentials `admin admin`. Please
|
||||
change the password promptly.
|
||||
|
||||
## Miscellaneous
|
||||
#### nginx reverse proxy
|
||||
Configure reverse proxy in `nginx`
|
||||
```
|
||||
server {
|
||||
listen <your port>;
|
||||
server_name <your server>;
|
||||
location / {
|
||||
proxy_pass http://<api-server[:port]>;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
## Others
|
||||
|
||||
- [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)
|
||||
116
cmd/apimain.go
@@ -12,12 +12,18 @@ import (
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"fmt"
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/locales/en"
|
||||
"github.com/go-playground/locales/zh_Hans_CN"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
en_translations "github.com/go-playground/validator/v10/translations/en"
|
||||
zh_translations "github.com/go-playground/validator/v10/translations/zh"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"golang.org/x/text/language"
|
||||
nethttp "net/http"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
@@ -42,6 +48,8 @@ func main() {
|
||||
ReportCaller: global.Config.Logger.ReportCaller,
|
||||
})
|
||||
|
||||
InitI18n()
|
||||
|
||||
//redis
|
||||
global.Redis = redis.NewClient(&redis.Options{
|
||||
Addr: global.Config.Redis.Addr,
|
||||
@@ -105,15 +113,25 @@ func main() {
|
||||
|
||||
func ApiInitValidator() {
|
||||
validate := validator.New()
|
||||
|
||||
// 定义不同的语言翻译
|
||||
enT := en.New()
|
||||
cn := zh_Hans_CN.New()
|
||||
|
||||
uni := ut.New(enT, cn)
|
||||
trans, _ := uni.GetTranslator("cn")
|
||||
err := zh_translations.RegisterDefaultTranslations(validate, trans)
|
||||
|
||||
enTrans, _ := uni.GetTranslator("en")
|
||||
zhTrans, _ := uni.GetTranslator("zh_Hans_CN")
|
||||
|
||||
err := zh_translations.RegisterDefaultTranslations(validate, zhTrans)
|
||||
if err != nil {
|
||||
//退出
|
||||
panic(err)
|
||||
}
|
||||
err = en_translations.RegisterDefaultTranslations(validate, enTrans)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
|
||||
label := field.Tag.Get("label")
|
||||
if label == "" {
|
||||
@@ -122,10 +140,16 @@ func ApiInitValidator() {
|
||||
return label
|
||||
})
|
||||
global.Validator.Validate = validate
|
||||
global.Validator.VTrans = trans
|
||||
global.Validator.UT = uni // 存储 Universal Translator
|
||||
global.Validator.VTrans = zhTrans
|
||||
|
||||
global.Validator.ValidStruct = func(i interface{}) []string {
|
||||
global.Validator.ValidStruct = func(ctx *gin.Context, i interface{}) []string {
|
||||
err := global.Validator.Validate.Struct(i)
|
||||
lang := ctx.GetHeader("Accept-Language")
|
||||
if lang == "" {
|
||||
lang = global.Config.Lang
|
||||
}
|
||||
trans := getTranslatorForLang(lang)
|
||||
errList := make([]string, 0, 10)
|
||||
if err != nil {
|
||||
if _, ok := err.(*validator.InvalidValidationError); ok {
|
||||
@@ -133,14 +157,18 @@ func ApiInitValidator() {
|
||||
return errList
|
||||
}
|
||||
for _, err2 := range err.(validator.ValidationErrors) {
|
||||
errList = append(errList, err2.Translate(global.Validator.VTrans))
|
||||
errList = append(errList, err2.Translate(trans))
|
||||
}
|
||||
}
|
||||
return errList
|
||||
}
|
||||
global.Validator.ValidVar = func(field interface{}, tag string) []string {
|
||||
global.Validator.ValidVar = func(ctx *gin.Context, field interface{}, tag string) []string {
|
||||
err := global.Validator.Validate.Var(field, tag)
|
||||
fmt.Println(err)
|
||||
lang := ctx.GetHeader("Accept-Language")
|
||||
if lang == "" {
|
||||
lang = global.Config.Lang
|
||||
}
|
||||
trans := getTranslatorForLang(lang)
|
||||
errList := make([]string, 0, 10)
|
||||
if err != nil {
|
||||
if _, ok := err.(*validator.InvalidValidationError); ok {
|
||||
@@ -148,16 +176,31 @@ func ApiInitValidator() {
|
||||
return errList
|
||||
}
|
||||
for _, err2 := range err.(validator.ValidationErrors) {
|
||||
errList = append(errList, err2.Translate(global.Validator.VTrans))
|
||||
errList = append(errList, err2.Translate(trans))
|
||||
}
|
||||
}
|
||||
return errList
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getTranslatorForLang(lang string) ut.Translator {
|
||||
switch lang {
|
||||
case "zh_CN":
|
||||
fallthrough
|
||||
case "zh-CN":
|
||||
fallthrough
|
||||
case "zh":
|
||||
trans, _ := global.Validator.UT.GetTranslator("zh_Hans_CN")
|
||||
return trans
|
||||
case "en":
|
||||
fallthrough
|
||||
default:
|
||||
trans, _ := global.Validator.UT.GetTranslator("en")
|
||||
return trans
|
||||
}
|
||||
}
|
||||
func DatabaseAutoUpdate() {
|
||||
version := 103
|
||||
version := 220
|
||||
|
||||
db := global.DB
|
||||
|
||||
@@ -218,6 +261,7 @@ func Migrate(version uint) {
|
||||
&model.UserThird{},
|
||||
&model.Oauth{},
|
||||
&model.LoginLog{},
|
||||
&model.ShareRecord{},
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println("migrate err :=>", err)
|
||||
@@ -227,13 +271,23 @@ func Migrate(version uint) {
|
||||
var vc int64
|
||||
global.DB.Model(&model.Version{}).Count(&vc)
|
||||
if vc == 1 {
|
||||
localizer := global.Localizer(&gin.Context{
|
||||
Request: &nethttp.Request{},
|
||||
})
|
||||
defaultGroup, _ := localizer.LocalizeMessage(&i18n.Message{
|
||||
ID: "DefaultGroup",
|
||||
})
|
||||
group := &model.Group{
|
||||
Name: "默认组",
|
||||
Name: defaultGroup,
|
||||
Type: model.GroupTypeDefault,
|
||||
}
|
||||
service.AllService.GroupService.Create(group)
|
||||
|
||||
shareGroup, _ := localizer.LocalizeMessage(&i18n.Message{
|
||||
ID: "ShareGroup",
|
||||
})
|
||||
groupShare := &model.Group{
|
||||
Name: "共享组",
|
||||
Name: shareGroup,
|
||||
Type: model.GroupTypeShare,
|
||||
}
|
||||
service.AllService.GroupService.Create(groupShare)
|
||||
@@ -241,7 +295,7 @@ func Migrate(version uint) {
|
||||
is_admin := true
|
||||
admin := &model.User{
|
||||
Username: "admin",
|
||||
Nickname: "管理员",
|
||||
Nickname: "Admin",
|
||||
Status: model.COMMON_STATUS_ENABLE,
|
||||
IsAdmin: &is_admin,
|
||||
GroupId: 1,
|
||||
@@ -251,3 +305,37 @@ func Migrate(version uint) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func InitI18n() {
|
||||
bundle := i18n.NewBundle(language.English)
|
||||
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
||||
bundle.LoadMessageFile(global.Config.Gin.ResourcesPath + "/i18n/en.toml")
|
||||
bundle.LoadMessageFile(global.Config.Gin.ResourcesPath + "/i18n/zh_CN.toml")
|
||||
global.Localizer = func(ctx *gin.Context) *i18n.Localizer {
|
||||
lang := ctx.GetHeader("Accept-Language")
|
||||
if lang == "" {
|
||||
lang = global.Config.Lang
|
||||
}
|
||||
if lang == "en" {
|
||||
return i18n.NewLocalizer(bundle, "en")
|
||||
} else {
|
||||
return i18n.NewLocalizer(bundle, lang, "en")
|
||||
}
|
||||
}
|
||||
|
||||
//personUnreadEmails := localizer.MustLocalize(&i18n.LocalizeConfig{
|
||||
// DefaultMessage: &i18n.Message{
|
||||
// ID: "PersonUnreadEmails",
|
||||
// },
|
||||
// PluralCount: 6,
|
||||
// TemplateData: map[string]interface{}{
|
||||
// "Name": "LE",
|
||||
// "PluralCount": 6,
|
||||
// },
|
||||
//})
|
||||
//personUnreadEmails, err := global.Localizer.LocalizeMessage(&i18n.Message{
|
||||
// ID: "ParamsError",
|
||||
//})
|
||||
//fmt.Println(err, personUnreadEmails)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
lang: "zh-CN"
|
||||
app:
|
||||
web-client: 1 # 1:启用 0:禁用
|
||||
gin:
|
||||
api-addr: "0.0.0.0:21114"
|
||||
mode: "release" #release,debug,test
|
||||
@@ -15,8 +18,9 @@ mysql:
|
||||
rustdesk:
|
||||
id-server: "192.168.1.66:21116"
|
||||
relay-server: "192.168.1.66:21117"
|
||||
api-server: "http://192.168.1.66:21114"
|
||||
api-server: "http://127.0.0.1:21114"
|
||||
key: "123456789"
|
||||
personal: 1
|
||||
logger:
|
||||
path: "./runtime/log.txt"
|
||||
level: "warn" #trace,debug,info,warn,error,fatal
|
||||
|
||||
@@ -14,7 +14,13 @@ const (
|
||||
DefaultConfig = "conf/config.yaml"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
WebClient int `mapstructure:"web-client"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Lang string `mapstructure:"lang"`
|
||||
App App
|
||||
Gorm Gorm
|
||||
Mysql Mysql
|
||||
Gin Gin
|
||||
|
||||
@@ -5,4 +5,5 @@ type Rustdesk struct {
|
||||
RelayServer string `mapstructure:"relay-server"`
|
||||
ApiServer string `mapstructure:"api-server"`
|
||||
Key string `mapstructure:"key"`
|
||||
Personal int `mapstructure:"personal"`
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const docTemplateadmin = `{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "创建地址簿",
|
||||
"description": "批量创建地址簿",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -32,7 +32,7 @@ const docTemplateadmin = `{
|
||||
"tags": [
|
||||
"地址簿"
|
||||
],
|
||||
"summary": "创建地址簿",
|
||||
"summary": "批量创建地址簿",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "地址簿信息",
|
||||
@@ -244,6 +244,51 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/address_book/share": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "地址簿分享",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址簿"
|
||||
],
|
||||
"summary": "地址簿分享",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "地址簿信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.ShareByWebClientForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/address_book/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -301,6 +346,40 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/app-config": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "APP服务配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"ADMIN"
|
||||
],
|
||||
"summary": "APP服务配置",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/file/oss_token": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -1185,7 +1264,7 @@ const docTemplateadmin = `{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "创建机器",
|
||||
"description": "创建设备",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1193,12 +1272,12 @@ const docTemplateadmin = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "创建机器",
|
||||
"summary": "创建设备",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "机器信息",
|
||||
"description": "设备信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
@@ -1242,7 +1321,7 @@ const docTemplateadmin = `{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "机器删除",
|
||||
"description": "批量设备删除",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1250,17 +1329,17 @@ const docTemplateadmin = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "机器删除",
|
||||
"summary": "批量设备删除",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "机器信息",
|
||||
"description": "设备id",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.PeerForm"
|
||||
"$ref": "#/definitions/admin.PeerBatchDeleteForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1287,7 +1366,7 @@ const docTemplateadmin = `{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "机器详情",
|
||||
"description": "设备详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1295,9 +1374,9 @@ const docTemplateadmin = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "机器详情",
|
||||
"summary": "设备详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
@@ -1342,7 +1421,7 @@ const docTemplateadmin = `{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "机器列表",
|
||||
"description": "设备列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1350,9 +1429,9 @@ const docTemplateadmin = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "机器列表",
|
||||
"summary": "设备列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
@@ -1365,6 +1444,24 @@ const docTemplateadmin = `{
|
||||
"description": "页大小",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "时间",
|
||||
"name": "time_ago",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID",
|
||||
"name": "id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "主机名",
|
||||
"name": "hostname",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1402,7 +1499,7 @@ const docTemplateadmin = `{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "机器编辑",
|
||||
"description": "设备编辑",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1410,12 +1507,12 @@ const docTemplateadmin = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "机器编辑",
|
||||
"summary": "设备编辑",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "机器信息",
|
||||
"description": "设备信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
@@ -1469,7 +1566,7 @@ const docTemplateadmin = `{
|
||||
"tags": [
|
||||
"ADMIN"
|
||||
],
|
||||
"summary": "服务配置",
|
||||
"summary": "RUSTDESK服务配置",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -2266,7 +2363,7 @@ const docTemplateadmin = `{
|
||||
"alias": {
|
||||
"type": "string"
|
||||
},
|
||||
"force_always_relay": {
|
||||
"forceAlwaysRelay": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hash": {
|
||||
@@ -2278,7 +2375,7 @@ const docTemplateadmin = `{
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"login_name": {
|
||||
"loginName": {
|
||||
"type": "string"
|
||||
},
|
||||
"online": {
|
||||
@@ -2290,16 +2387,16 @@ const docTemplateadmin = `{
|
||||
"platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"rdp_port": {
|
||||
"rdpPort": {
|
||||
"type": "string"
|
||||
},
|
||||
"rdp_username": {
|
||||
"rdpUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"row_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"same_server": {
|
||||
"sameServer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tags": {
|
||||
@@ -2311,6 +2408,12 @@ const docTemplateadmin = `{
|
||||
"user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -2398,6 +2501,20 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.PeerBatchDeleteForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"row_ids"
|
||||
],
|
||||
"properties": {
|
||||
"row_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.PeerForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2430,12 +2547,38 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.ShareByWebClientForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"password",
|
||||
"password_type"
|
||||
],
|
||||
"properties": {
|
||||
"expire": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"password_type": {
|
||||
"description": "只能是once,fixed",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"once",
|
||||
"fixed"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.TagForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"color",
|
||||
"name",
|
||||
"user_id"
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"color": {
|
||||
@@ -2456,7 +2599,6 @@ const docTemplateadmin = `{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group_id",
|
||||
"nickname",
|
||||
"status",
|
||||
"username"
|
||||
],
|
||||
@@ -2761,6 +2903,9 @@ const docTemplateadmin = `{
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"last_online_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"memory": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "创建地址簿",
|
||||
"description": "批量创建地址簿",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -25,7 +25,7 @@
|
||||
"tags": [
|
||||
"地址簿"
|
||||
],
|
||||
"summary": "创建地址簿",
|
||||
"summary": "批量创建地址簿",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "地址簿信息",
|
||||
@@ -237,6 +237,51 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/address_book/share": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "地址簿分享",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址簿"
|
||||
],
|
||||
"summary": "地址簿分享",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "地址簿信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.ShareByWebClientForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/address_book/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -294,6 +339,40 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/app-config": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "APP服务配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"ADMIN"
|
||||
],
|
||||
"summary": "APP服务配置",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/file/oss_token": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -1178,7 +1257,7 @@
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "创建机器",
|
||||
"description": "创建设备",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1186,12 +1265,12 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "创建机器",
|
||||
"summary": "创建设备",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "机器信息",
|
||||
"description": "设备信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
@@ -1235,7 +1314,7 @@
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "机器删除",
|
||||
"description": "批量设备删除",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1243,17 +1322,17 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "机器删除",
|
||||
"summary": "批量设备删除",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "机器信息",
|
||||
"description": "设备id",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.PeerForm"
|
||||
"$ref": "#/definitions/admin.PeerBatchDeleteForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1280,7 +1359,7 @@
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "机器详情",
|
||||
"description": "设备详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1288,9 +1367,9 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "机器详情",
|
||||
"summary": "设备详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
@@ -1335,7 +1414,7 @@
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "机器列表",
|
||||
"description": "设备列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1343,9 +1422,9 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "机器列表",
|
||||
"summary": "设备列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
@@ -1358,6 +1437,24 @@
|
||||
"description": "页大小",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "时间",
|
||||
"name": "time_ago",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID",
|
||||
"name": "id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "主机名",
|
||||
"name": "hostname",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1395,7 +1492,7 @@
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "机器编辑",
|
||||
"description": "设备编辑",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1403,12 +1500,12 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"机器"
|
||||
"设备"
|
||||
],
|
||||
"summary": "机器编辑",
|
||||
"summary": "设备编辑",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "机器信息",
|
||||
"description": "设备信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
@@ -1462,7 +1559,7 @@
|
||||
"tags": [
|
||||
"ADMIN"
|
||||
],
|
||||
"summary": "服务配置",
|
||||
"summary": "RUSTDESK服务配置",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -2259,7 +2356,7 @@
|
||||
"alias": {
|
||||
"type": "string"
|
||||
},
|
||||
"force_always_relay": {
|
||||
"forceAlwaysRelay": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hash": {
|
||||
@@ -2271,7 +2368,7 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"login_name": {
|
||||
"loginName": {
|
||||
"type": "string"
|
||||
},
|
||||
"online": {
|
||||
@@ -2283,16 +2380,16 @@
|
||||
"platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"rdp_port": {
|
||||
"rdpPort": {
|
||||
"type": "string"
|
||||
},
|
||||
"rdp_username": {
|
||||
"rdpUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"row_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"same_server": {
|
||||
"sameServer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tags": {
|
||||
@@ -2304,6 +2401,12 @@
|
||||
"user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -2391,6 +2494,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.PeerBatchDeleteForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"row_ids"
|
||||
],
|
||||
"properties": {
|
||||
"row_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.PeerForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2423,12 +2540,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.ShareByWebClientForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"password",
|
||||
"password_type"
|
||||
],
|
||||
"properties": {
|
||||
"expire": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"password_type": {
|
||||
"description": "只能是once,fixed",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"once",
|
||||
"fixed"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.TagForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"color",
|
||||
"name",
|
||||
"user_id"
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"color": {
|
||||
@@ -2449,7 +2592,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group_id",
|
||||
"nickname",
|
||||
"status",
|
||||
"username"
|
||||
],
|
||||
@@ -2754,6 +2896,9 @@
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"last_online_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"memory": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@ definitions:
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
force_always_relay:
|
||||
forceAlwaysRelay:
|
||||
type: boolean
|
||||
hash:
|
||||
type: string
|
||||
@@ -24,7 +24,7 @@ definitions:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
login_name:
|
||||
loginName:
|
||||
type: string
|
||||
online:
|
||||
type: boolean
|
||||
@@ -32,13 +32,13 @@ definitions:
|
||||
type: string
|
||||
platform:
|
||||
type: string
|
||||
rdp_port:
|
||||
rdpPort:
|
||||
type: string
|
||||
rdp_username:
|
||||
rdpUsername:
|
||||
type: string
|
||||
row_id:
|
||||
type: integer
|
||||
same_server:
|
||||
sameServer:
|
||||
type: boolean
|
||||
tags:
|
||||
items:
|
||||
@@ -46,6 +46,10 @@ definitions:
|
||||
type: array
|
||||
user_id:
|
||||
type: integer
|
||||
user_ids:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
username:
|
||||
type: string
|
||||
required:
|
||||
@@ -107,6 +111,15 @@ definitions:
|
||||
- op
|
||||
- redirect_url
|
||||
type: object
|
||||
admin.PeerBatchDeleteForm:
|
||||
properties:
|
||||
row_ids:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
required:
|
||||
- row_ids
|
||||
type: object
|
||||
admin.PeerForm:
|
||||
properties:
|
||||
cpu:
|
||||
@@ -128,6 +141,25 @@ definitions:
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
admin.ShareByWebClientForm:
|
||||
properties:
|
||||
expire:
|
||||
type: integer
|
||||
id:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
password_type:
|
||||
description: 只能是once,fixed
|
||||
enum:
|
||||
- once
|
||||
- fixed
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
- password
|
||||
- password_type
|
||||
type: object
|
||||
admin.TagForm:
|
||||
properties:
|
||||
color:
|
||||
@@ -141,7 +173,6 @@ definitions:
|
||||
required:
|
||||
- color
|
||||
- name
|
||||
- user_id
|
||||
type: object
|
||||
admin.UserForm:
|
||||
properties:
|
||||
@@ -166,7 +197,6 @@ definitions:
|
||||
type: string
|
||||
required:
|
||||
- group_id
|
||||
- nickname
|
||||
- status
|
||||
- username
|
||||
type: object
|
||||
@@ -348,6 +378,8 @@ definitions:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
last_online_time:
|
||||
type: integer
|
||||
memory:
|
||||
type: string
|
||||
os:
|
||||
@@ -473,7 +505,7 @@ paths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建地址簿
|
||||
description: 批量创建地址簿
|
||||
parameters:
|
||||
- description: 地址簿信息
|
||||
in: body
|
||||
@@ -499,7 +531,7 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 创建地址簿
|
||||
summary: 批量创建地址簿
|
||||
tags:
|
||||
- 地址簿
|
||||
/admin/address_book/delete:
|
||||
@@ -605,6 +637,34 @@ paths:
|
||||
summary: 地址簿列表
|
||||
tags:
|
||||
- 地址簿
|
||||
/admin/address_book/share:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 地址簿分享
|
||||
parameters:
|
||||
- description: 地址簿信息
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/admin.ShareByWebClientForm'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 地址簿分享
|
||||
tags:
|
||||
- 地址簿
|
||||
/admin/address_book/update:
|
||||
post:
|
||||
consumes:
|
||||
@@ -638,6 +698,27 @@ paths:
|
||||
summary: 地址簿编辑
|
||||
tags:
|
||||
- 地址簿
|
||||
/admin/app-config:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: APP服务配置
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: APP服务配置
|
||||
tags:
|
||||
- ADMIN
|
||||
/admin/file/oss_token:
|
||||
get:
|
||||
consumes:
|
||||
@@ -1163,9 +1244,9 @@ paths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建机器
|
||||
description: 创建设备
|
||||
parameters:
|
||||
- description: 机器信息
|
||||
- description: 设备信息
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
@@ -1189,21 +1270,21 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 创建机器
|
||||
summary: 创建设备
|
||||
tags:
|
||||
- 机器
|
||||
- 设备
|
||||
/admin/peer/delete:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 机器删除
|
||||
description: 批量设备删除
|
||||
parameters:
|
||||
- description: 机器信息
|
||||
- description: 设备id
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/admin.PeerForm'
|
||||
$ref: '#/definitions/admin.PeerBatchDeleteForm'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -1217,14 +1298,14 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 机器删除
|
||||
summary: 批量设备删除
|
||||
tags:
|
||||
- 机器
|
||||
- 设备
|
||||
/admin/peer/detail/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 机器详情
|
||||
description: 设备详情
|
||||
parameters:
|
||||
- description: ID
|
||||
in: path
|
||||
@@ -1249,14 +1330,14 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 机器详情
|
||||
summary: 设备详情
|
||||
tags:
|
||||
- 机器
|
||||
- 设备
|
||||
/admin/peer/list:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 机器列表
|
||||
description: 设备列表
|
||||
parameters:
|
||||
- description: 页码
|
||||
in: query
|
||||
@@ -1266,6 +1347,18 @@ paths:
|
||||
in: query
|
||||
name: page_size
|
||||
type: integer
|
||||
- description: 时间
|
||||
in: query
|
||||
name: time_ago
|
||||
type: integer
|
||||
- description: ID
|
||||
in: query
|
||||
name: id
|
||||
type: string
|
||||
- description: 主机名
|
||||
in: query
|
||||
name: hostname
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -1284,16 +1377,16 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 机器列表
|
||||
summary: 设备列表
|
||||
tags:
|
||||
- 机器
|
||||
- 设备
|
||||
/admin/peer/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 机器编辑
|
||||
description: 设备编辑
|
||||
parameters:
|
||||
- description: 机器信息
|
||||
- description: 设备信息
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
@@ -1317,9 +1410,9 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 机器编辑
|
||||
summary: 设备编辑
|
||||
tags:
|
||||
- 机器
|
||||
- 设备
|
||||
/admin/server-config:
|
||||
get:
|
||||
consumes:
|
||||
@@ -1338,7 +1431,7 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 服务配置
|
||||
summary: RUSTDESK服务配置
|
||||
tags:
|
||||
- ADMIN
|
||||
/admin/tag/create:
|
||||
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 46 KiB |
@@ -136,7 +136,7 @@ const docTemplateapi = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址"
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签添加",
|
||||
"responses": {
|
||||
@@ -155,14 +155,14 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/personal": {
|
||||
"/ab/peer/add/{guid}": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "个人信息",
|
||||
"description": "添加地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -170,9 +170,136 @@ const docTemplateapi = `{
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"用户"
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "个人信息",
|
||||
"summary": "添加地址",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "删除地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "删除地址",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/peer/update/{guid}": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "更新地址",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/peers": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "地址列表",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
@@ -199,6 +326,283 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/personal": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "个人地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "个人地址",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/settings": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "设置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "设置",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/shared/profiles": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "共享",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "共享地址簿",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/rename/{guid}": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签重命名",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/update/{guid}": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签修改颜色",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/{guid}": {
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签删除",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tags/{guid}": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.TagList"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -389,35 +793,6 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/oauth/login": {
|
||||
"get": {
|
||||
"description": "WebOauthLogin",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Oauth"
|
||||
],
|
||||
"summary": "WebOauthLogin",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/oidc/auth": {
|
||||
"post": {
|
||||
"description": "OidcAuth",
|
||||
@@ -570,13 +945,37 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/shared-peer": {
|
||||
"post": {
|
||||
"description": "分享的peer",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"WEBCLIENT"
|
||||
],
|
||||
"summary": "分享的peer",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/sysinfo": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "提交系统信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
@@ -882,6 +1281,26 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.TagList": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"list": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/model.Tag"
|
||||
}
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"page_size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"response.DataResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址"
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签添加",
|
||||
"responses": {
|
||||
@@ -148,14 +148,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/personal": {
|
||||
"/ab/peer/add/{guid}": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "个人信息",
|
||||
"description": "添加地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -163,9 +163,136 @@
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"用户"
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "个人信息",
|
||||
"summary": "添加地址",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "删除地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "删除地址",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/peer/update/{guid}": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "更新地址",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/peers": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "地址列表",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
@@ -192,6 +319,283 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/personal": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "个人地址",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "个人地址",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/settings": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "设置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "设置",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/shared/profiles": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "共享",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "共享地址簿",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/rename/{guid}": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签重命名",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/update/{guid}": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签修改颜色",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/{guid}": {
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签删除",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tags/{guid}": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.TagList"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -382,35 +786,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/oauth/login": {
|
||||
"get": {
|
||||
"description": "WebOauthLogin",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Oauth"
|
||||
],
|
||||
"summary": "WebOauthLogin",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/oidc/auth": {
|
||||
"post": {
|
||||
"description": "OidcAuth",
|
||||
@@ -563,13 +938,37 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/shared-peer": {
|
||||
"post": {
|
||||
"description": "分享的peer",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"WEBCLIENT"
|
||||
],
|
||||
"summary": "分享的peer",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/sysinfo": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "提交系统信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
@@ -875,6 +1274,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.TagList": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"list": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/model.Tag"
|
||||
}
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"page_size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"response.DataResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -103,6 +103,19 @@ definitions:
|
||||
user_id:
|
||||
type: integer
|
||||
type: object
|
||||
model.TagList:
|
||||
properties:
|
||||
list:
|
||||
items:
|
||||
$ref: '#/definitions/model.Tag'
|
||||
type: array
|
||||
page:
|
||||
type: integer
|
||||
page_size:
|
||||
type: integer
|
||||
total:
|
||||
type: integer
|
||||
type: object
|
||||
response.DataResponse:
|
||||
properties:
|
||||
data: {}
|
||||
@@ -215,12 +228,92 @@ paths:
|
||||
- BearerAuth: []
|
||||
summary: 标签添加
|
||||
tags:
|
||||
- 地址
|
||||
/ab/personal:
|
||||
- 地址[Personal]
|
||||
/ab/peer/add/{guid}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 删除地址
|
||||
parameters:
|
||||
- description: id
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 删除地址
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 个人信息
|
||||
description: 添加地址
|
||||
parameters:
|
||||
- description: id
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 添加地址
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/ab/peer/update/{guid}:
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新地址
|
||||
parameters:
|
||||
- description: id
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 更新地址
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/ab/peers:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 地址
|
||||
parameters:
|
||||
- description: string valid
|
||||
in: body
|
||||
@@ -240,9 +333,180 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 个人信息
|
||||
summary: 地址列表
|
||||
tags:
|
||||
- 用户
|
||||
- 地址[Personal]
|
||||
/ab/personal:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 个人地址
|
||||
parameters:
|
||||
- description: string valid
|
||||
in: body
|
||||
name: string
|
||||
schema:
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 个人地址
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/ab/settings:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 设置
|
||||
parameters:
|
||||
- description: string valid
|
||||
in: body
|
||||
name: string
|
||||
schema:
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 设置
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/ab/shared/profiles:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 共享
|
||||
parameters:
|
||||
- description: string valid
|
||||
in: body
|
||||
name: string
|
||||
schema:
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 共享地址簿
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/ab/tag/{guid}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 标签
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 标签删除
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/ab/tag/rename/{guid}:
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 标签
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 标签重命名
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/ab/tag/update/{guid}:
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 标签
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 标签修改颜色
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/ab/tags/{guid}:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 标签
|
||||
parameters:
|
||||
- description: id
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/model.TagList'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 标签
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/api:
|
||||
get:
|
||||
consumes:
|
||||
@@ -366,25 +630,6 @@ paths:
|
||||
summary: OauthCallback
|
||||
tags:
|
||||
- Oauth
|
||||
/oauth/login:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: WebOauthLogin
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
type: string
|
||||
summary: WebOauthLogin
|
||||
tags:
|
||||
- Oauth
|
||||
/oidc/auth:
|
||||
post:
|
||||
consumes:
|
||||
@@ -482,6 +727,25 @@ paths:
|
||||
summary: 服务配置
|
||||
tags:
|
||||
- WEBCLIENT
|
||||
/shared-peer:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 分享的peer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
summary: 分享的peer
|
||||
tags:
|
||||
- WEBCLIENT
|
||||
/sysinfo:
|
||||
post:
|
||||
consumes:
|
||||
@@ -505,8 +769,6 @@ paths:
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 提交系统信息
|
||||
tags:
|
||||
- 地址
|
||||
|
||||
BIN
docs/en_img/admin_webclient.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
docs/en_img/pc_ab.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
docs/en_img/pc_gr.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
docs/en_img/pc_login.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
docs/en_img/web_admin.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/en_img/web_admin_gr.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
docs/en_img/web_admin_oauth.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/en_img/web_admin_user.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
docs/en_img/web_resetpwd.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 4.3 KiB |
@@ -6,9 +6,11 @@ import (
|
||||
"Gwen/lib/jwt"
|
||||
"Gwen/lib/lock"
|
||||
"Gwen/lib/upload"
|
||||
"github.com/gin-gonic/gin"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
"gorm.io/gorm"
|
||||
@@ -23,11 +25,13 @@ var (
|
||||
Cache cache.Handler
|
||||
Validator struct {
|
||||
Validate *validator.Validate
|
||||
UT *ut.UniversalTranslator
|
||||
VTrans ut.Translator
|
||||
ValidStruct func(interface{}) []string
|
||||
ValidVar func(field interface{}, tag string) []string
|
||||
ValidStruct func(*gin.Context, interface{}) []string
|
||||
ValidVar func(ctx *gin.Context, field interface{}, tag string) []string
|
||||
}
|
||||
Oss *upload.Oss
|
||||
Jwt *jwt.Jwt
|
||||
Lock lock.Locker
|
||||
Localizer func(ctx *gin.Context) *i18n.Localizer
|
||||
)
|
||||
|
||||
9
go.mod
@@ -3,6 +3,7 @@ module Gwen
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.3.2
|
||||
github.com/antonfisher/nested-logrus-formatter v1.3.1
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
|
||||
@@ -12,12 +13,15 @@ require (
|
||||
github.com/go-playground/validator/v10 v10.11.2
|
||||
github.com/go-redis/redis/v8 v8.11.4
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/viper v1.9.0
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.0
|
||||
github.com/swaggo/swag v1.16.3
|
||||
golang.org/x/oauth2 v0.23.0
|
||||
golang.org/x/text v0.18.0
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/driver/sqlite v1.5.6
|
||||
gorm.io/gorm v1.25.7
|
||||
@@ -64,10 +68,9 @@ require (
|
||||
github.com/ugorji/go/codec v1.2.9 // indirect
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
_ "encoding/json"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -31,14 +32,14 @@ func (ct *AddressBook) Detail(c *gin.Context) {
|
||||
t := service.AllService.AddressBookService.InfoByRowId(uint(iid))
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
||||
response.Fail(c, 101, "无权限")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||
return
|
||||
}
|
||||
if t.RowId > 0 {
|
||||
response.Success(c, t)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -56,10 +57,10 @@ func (ct *AddressBook) Detail(c *gin.Context) {
|
||||
func (ct *AddressBook) Create(c *gin.Context) {
|
||||
f := &admin.AddressBookForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -69,14 +70,72 @@ func (ct *AddressBook) Create(c *gin.Context) {
|
||||
if !service.AllService.UserService.IsAdmin(u) || t.UserId == 0 {
|
||||
t.UserId = u.Id
|
||||
}
|
||||
ex := service.AllService.AddressBookService.InfoByUserIdAndId(t.UserId, t.Id)
|
||||
if ex.RowId > 0 {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemExist"))
|
||||
return
|
||||
}
|
||||
|
||||
err := service.AllService.AddressBookService.Create(t)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "创建失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, u)
|
||||
}
|
||||
|
||||
// BatchCreate 批量创建地址簿
|
||||
// @Tags 地址簿
|
||||
// @Summary 批量创建地址簿
|
||||
// @Description 批量创建地址簿
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body admin.AddressBookForm true "地址簿信息"
|
||||
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/address_book/create [post]
|
||||
// @Security token
|
||||
func (ct *AddressBook) BatchCreate(c *gin.Context) {
|
||||
f := &admin.AddressBookForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
|
||||
//创建标签
|
||||
for _, fu := range f.UserIds {
|
||||
if fu == 0 {
|
||||
continue
|
||||
}
|
||||
for _, ft := range f.Tags {
|
||||
exTag := service.AllService.TagService.InfoByUserIdAndName(fu, ft)
|
||||
if exTag.Id == 0 {
|
||||
service.AllService.TagService.Create(&model.Tag{
|
||||
UserId: fu,
|
||||
Name: ft,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
ts := f.ToAddressBooks()
|
||||
for _, t := range ts {
|
||||
if t.UserId == 0 {
|
||||
continue
|
||||
}
|
||||
ex := service.AllService.AddressBookService.InfoByUserIdAndId(t.UserId, t.Id)
|
||||
if ex.RowId == 0 {
|
||||
service.AllService.AddressBookService.Create(t)
|
||||
}
|
||||
}
|
||||
|
||||
response.Success(c, nil)
|
||||
}
|
||||
|
||||
// List 列表
|
||||
// @Tags 地址簿
|
||||
// @Summary 地址簿列表
|
||||
@@ -94,7 +153,7 @@ func (ct *AddressBook) Create(c *gin.Context) {
|
||||
func (ct *AddressBook) List(c *gin.Context) {
|
||||
query := &admin.AddressBookQuery{}
|
||||
if err := c.ShouldBindQuery(query); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
@@ -102,9 +161,18 @@ func (ct *AddressBook) List(c *gin.Context) {
|
||||
query.UserId = int(u.Id)
|
||||
}
|
||||
res := service.AllService.AddressBookService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||
if query.Id != "" {
|
||||
tx.Where("id like ?", "%"+query.Id+"%")
|
||||
}
|
||||
if query.UserId > 0 {
|
||||
tx.Where("user_id = ?", query.UserId)
|
||||
}
|
||||
if query.Username != "" {
|
||||
tx.Where("username like ?", "%"+query.Username+"%")
|
||||
}
|
||||
if query.Hostname != "" {
|
||||
tx.Where("hostname like ?", "%"+query.Hostname+"%")
|
||||
}
|
||||
})
|
||||
response.Success(c, res)
|
||||
}
|
||||
@@ -123,27 +191,27 @@ func (ct *AddressBook) List(c *gin.Context) {
|
||||
func (ct *AddressBook) Update(c *gin.Context) {
|
||||
f := &admin.AddressBookForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
if f.RowId == 0 {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
t := f.ToAddressBook()
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
||||
response.Fail(c, 101, "无权限")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||
return
|
||||
}
|
||||
err := service.AllService.AddressBookService.Update(t)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "更新失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
@@ -163,11 +231,11 @@ func (ct *AddressBook) Update(c *gin.Context) {
|
||||
func (ct *AddressBook) Delete(c *gin.Context) {
|
||||
f := &admin.AddressBookForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "系统错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
id := f.RowId
|
||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
||||
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -175,7 +243,7 @@ func (ct *AddressBook) Delete(c *gin.Context) {
|
||||
t := service.AllService.AddressBookService.InfoByRowId(f.RowId)
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
||||
response.Fail(c, 101, "无权限")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||
return
|
||||
}
|
||||
if u.Id > 0 {
|
||||
@@ -184,8 +252,49 @@ func (ct *AddressBook) Delete(c *gin.Context) {
|
||||
response.Success(c, nil)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, err.Error())
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
}
|
||||
|
||||
// ShareByWebClient
|
||||
// @Tags 地址簿
|
||||
// @Summary 地址簿分享
|
||||
// @Description 地址簿分享
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body admin.ShareByWebClientForm true "地址簿信息"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/address_book/share [post]
|
||||
// @Security token
|
||||
func (ct *AddressBook) ShareByWebClient(c *gin.Context) {
|
||||
f := &admin.ShareByWebClientForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
ab := service.AllService.AddressBookService.InfoByUserIdAndId(u.Id, f.Id)
|
||||
if ab.RowId == 0 {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
m := f.ToShareRecord()
|
||||
m.UserId = u.Id
|
||||
err := service.AllService.AddressBookService.ShareByWebClient(m)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, &gin.H{
|
||||
"share_token": m.ShareToken,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func (ct *Group) Detail(c *gin.Context) {
|
||||
response.Success(c, u)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ func (ct *Group) Detail(c *gin.Context) {
|
||||
func (ct *Group) Create(c *gin.Context) {
|
||||
f := &admin.GroupForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -60,7 +60,7 @@ func (ct *Group) Create(c *gin.Context) {
|
||||
u := f.ToGroup()
|
||||
err := service.AllService.GroupService.Create(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "创建失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, u)
|
||||
@@ -81,7 +81,7 @@ func (ct *Group) Create(c *gin.Context) {
|
||||
func (ct *Group) List(c *gin.Context) {
|
||||
query := &admin.PageQuery{}
|
||||
if err := c.ShouldBindQuery(query); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
res := service.AllService.GroupService.List(query.Page, query.PageSize, nil)
|
||||
@@ -102,14 +102,14 @@ func (ct *Group) List(c *gin.Context) {
|
||||
func (ct *Group) Update(c *gin.Context) {
|
||||
f := &admin.GroupForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
if f.Id == 0 {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -117,7 +117,7 @@ func (ct *Group) Update(c *gin.Context) {
|
||||
u := f.ToGroup()
|
||||
err := service.AllService.GroupService.Update(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "更新失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
@@ -137,11 +137,11 @@ func (ct *Group) Update(c *gin.Context) {
|
||||
func (ct *Group) Delete(c *gin.Context) {
|
||||
f := &admin.GroupForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "系统错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
id := f.Id
|
||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
||||
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -153,8 +153,8 @@ func (ct *Group) Delete(c *gin.Context) {
|
||||
response.Success(c, nil)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, err.Error())
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
adResp "Gwen/http/response/admin"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -28,19 +29,22 @@ func (ct *Login) Login(c *gin.Context) {
|
||||
f := &admin.Login{}
|
||||
err := c.ShouldBindJSON(f)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
||||
|
||||
if u.Id == 0 {
|
||||
response.Fail(c, 101, "用户名或密码错误")
|
||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ func (ct *LoginLog) Detail(c *gin.Context) {
|
||||
response.Success(c, u)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func (ct *LoginLog) Detail(c *gin.Context) {
|
||||
func (ct *LoginLog) List(c *gin.Context) {
|
||||
query := &admin.LoginLogQuery{}
|
||||
if err := c.ShouldBindQuery(query); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
@@ -82,11 +82,11 @@ func (ct *LoginLog) List(c *gin.Context) {
|
||||
func (ct *LoginLog) Delete(c *gin.Context) {
|
||||
f := &model.LoginLog{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "系统错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
id := f.Id
|
||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
||||
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -94,7 +94,7 @@ func (ct *LoginLog) Delete(c *gin.Context) {
|
||||
l := service.AllService.LoginLogService.InfoById(f.Id)
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
if !service.AllService.UserService.IsAdmin(u) && l.UserId != u.Id {
|
||||
response.Fail(c, 101, "无权限")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||
return
|
||||
}
|
||||
if l.Id > 0 {
|
||||
@@ -106,5 +106,5 @@ func (ct *LoginLog) Delete(c *gin.Context) {
|
||||
response.Fail(c, 101, err.Error())
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ type Oauth struct {
|
||||
func (o *Oauth) Info(c *gin.Context) {
|
||||
code := c.Query("code")
|
||||
if code == "" {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
v := service.AllService.OauthService.GetOauthCache(code)
|
||||
if v == nil {
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
response.Success(c, v)
|
||||
@@ -33,20 +33,20 @@ func (o *Oauth) ToBind(c *gin.Context) {
|
||||
f := &adminReq.BindOauthForm{}
|
||||
err := c.ShouldBindJSON(f)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
|
||||
utr := service.AllService.UserService.UserThirdInfo(u.Id, f.Op)
|
||||
if utr.Id > 0 {
|
||||
response.Fail(c, 101, "已绑定过了")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OauthHasBindOtherUser"))
|
||||
return
|
||||
}
|
||||
|
||||
err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||
if err != nil {
|
||||
response.Error(c, err.Error())
|
||||
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -89,22 +89,22 @@ func (o *Oauth) BindConfirm(c *gin.Context) {
|
||||
j := &adminReq.OauthConfirmForm{}
|
||||
err := c.ShouldBindJSON(j)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "参数错误"+err.Error())
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
if j.Code == "" {
|
||||
response.Fail(c, 101, "参数错误: code 不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
v := service.AllService.OauthService.GetOauthCache(j.Code)
|
||||
if v == nil {
|
||||
response.Fail(c, 101, "授权已过期")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OauthExpired"))
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
err = service.AllService.OauthService.BindGithubUser(v.ThirdOpenId, v.ThirdOpenId, u.Id)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "绑定失败,请重试")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "BindFail"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -117,22 +117,30 @@ func (o *Oauth) Unbind(c *gin.Context) {
|
||||
f := &adminReq.UnBindOauthForm{}
|
||||
err := c.ShouldBindJSON(f)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
utr := service.AllService.UserService.UserThirdInfo(u.Id, f.Op)
|
||||
if utr.Id == 0 {
|
||||
response.Fail(c, 101, "未绑定")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
if f.Op == model.OauthTypeGithub {
|
||||
err = service.AllService.OauthService.UnBindGithubUser(u.Id)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "解绑失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
if f.Op == model.OauthTypeGoogle {
|
||||
err = service.AllService.OauthService.UnBindGoogleUser(u.Id)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
response.Success(c, nil)
|
||||
}
|
||||
|
||||
@@ -155,7 +163,7 @@ func (o *Oauth) Detail(c *gin.Context) {
|
||||
response.Success(c, u)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -173,10 +181,10 @@ func (o *Oauth) Detail(c *gin.Context) {
|
||||
func (o *Oauth) Create(c *gin.Context) {
|
||||
f := &admin.OauthForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误"+err.Error())
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -184,14 +192,14 @@ func (o *Oauth) Create(c *gin.Context) {
|
||||
|
||||
ex := service.AllService.OauthService.InfoByOp(f.Op)
|
||||
if ex.Id > 0 {
|
||||
response.Fail(c, 101, "已存在"+f.Op)
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemExists"))
|
||||
return
|
||||
}
|
||||
|
||||
u := f.ToOauth()
|
||||
err := service.AllService.OauthService.Create(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "创建失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, u)
|
||||
@@ -212,7 +220,7 @@ func (o *Oauth) Create(c *gin.Context) {
|
||||
func (o *Oauth) List(c *gin.Context) {
|
||||
query := &admin.PageQuery{}
|
||||
if err := c.ShouldBindQuery(query); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
res := service.AllService.OauthService.List(query.Page, query.PageSize, nil)
|
||||
@@ -233,14 +241,14 @@ func (o *Oauth) List(c *gin.Context) {
|
||||
func (o *Oauth) Update(c *gin.Context) {
|
||||
f := &admin.OauthForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
if f.Id == 0 {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -248,7 +256,7 @@ func (o *Oauth) Update(c *gin.Context) {
|
||||
u := f.ToOauth()
|
||||
err := service.AllService.OauthService.Update(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "更新失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
@@ -268,11 +276,11 @@ func (o *Oauth) Update(c *gin.Context) {
|
||||
func (o *Oauth) Delete(c *gin.Context) {
|
||||
f := &admin.OauthForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "系统错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
id := f.Id
|
||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
||||
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -287,5 +295,5 @@ func (o *Oauth) Delete(c *gin.Context) {
|
||||
response.Fail(c, 101, err.Error())
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
}
|
||||
|
||||
@@ -6,16 +6,18 @@ import (
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Peer struct {
|
||||
}
|
||||
|
||||
// Detail 机器
|
||||
// @Tags 机器
|
||||
// @Summary 机器详情
|
||||
// @Description 机器详情
|
||||
// Detail 设备
|
||||
// @Tags 设备
|
||||
// @Summary 设备详情
|
||||
// @Description 设备详情
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "ID"
|
||||
@@ -31,17 +33,17 @@ func (ct *Peer) Detail(c *gin.Context) {
|
||||
response.Success(c, u)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
|
||||
// Create 创建机器
|
||||
// @Tags 机器
|
||||
// @Summary 创建机器
|
||||
// @Description 创建机器
|
||||
// Create 创建设备
|
||||
// @Tags 设备
|
||||
// @Summary 创建设备
|
||||
// @Description 创建设备
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body admin.PeerForm true "机器信息"
|
||||
// @Param body body admin.PeerForm true "设备信息"
|
||||
// @Success 200 {object} response.Response{data=model.Peer}
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/peer/create [post]
|
||||
@@ -49,10 +51,10 @@ func (ct *Peer) Detail(c *gin.Context) {
|
||||
func (ct *Peer) Create(c *gin.Context) {
|
||||
f := &admin.PeerForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -60,41 +62,59 @@ func (ct *Peer) Create(c *gin.Context) {
|
||||
u := f.ToPeer()
|
||||
err := service.AllService.PeerService.Create(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "创建失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, u)
|
||||
}
|
||||
|
||||
// List 列表
|
||||
// @Tags 机器
|
||||
// @Summary 机器列表
|
||||
// @Description 机器列表
|
||||
// @Tags 设备
|
||||
// @Summary 设备列表
|
||||
// @Description 设备列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "页码"
|
||||
// @Param page_size query int false "页大小"
|
||||
// @Param time_ago query int false "时间"
|
||||
// @Param id query string false "ID"
|
||||
// @Param hostname query string false "主机名"
|
||||
// @Success 200 {object} response.Response{data=model.PeerList}
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/peer/list [get]
|
||||
// @Security token
|
||||
func (ct *Peer) List(c *gin.Context) {
|
||||
query := &admin.PageQuery{}
|
||||
query := &admin.PeerQuery{}
|
||||
if err := c.ShouldBindQuery(query); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
res := service.AllService.PeerService.List(query.Page, query.PageSize, nil)
|
||||
res := service.AllService.PeerService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||
if query.TimeAgo > 0 {
|
||||
lt := time.Now().Unix() - int64(query.TimeAgo)
|
||||
tx.Where("last_online_time < ?", lt)
|
||||
}
|
||||
if query.TimeAgo < 0 {
|
||||
lt := time.Now().Unix() + int64(query.TimeAgo)
|
||||
tx.Where("last_online_time > ?", lt)
|
||||
}
|
||||
if query.Id != "" {
|
||||
tx.Where("id like ?", "%"+query.Id+"%")
|
||||
}
|
||||
if query.Hostname != "" {
|
||||
tx.Where("hostname like ?", "%"+query.Hostname+"%")
|
||||
}
|
||||
})
|
||||
response.Success(c, res)
|
||||
}
|
||||
|
||||
// Update 编辑
|
||||
// @Tags 机器
|
||||
// @Summary 机器编辑
|
||||
// @Description 机器编辑
|
||||
// @Tags 设备
|
||||
// @Summary 设备编辑
|
||||
// @Description 设备编辑
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body admin.PeerForm true "机器信息"
|
||||
// @Param body body admin.PeerForm true "设备信息"
|
||||
// @Success 200 {object} response.Response{data=model.Peer}
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/peer/update [post]
|
||||
@@ -102,14 +122,14 @@ func (ct *Peer) List(c *gin.Context) {
|
||||
func (ct *Peer) Update(c *gin.Context) {
|
||||
f := &admin.PeerForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
if f.RowId == 0 {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -117,19 +137,19 @@ func (ct *Peer) Update(c *gin.Context) {
|
||||
u := f.ToPeer()
|
||||
err := service.AllService.PeerService.Update(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "更新失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
}
|
||||
|
||||
// Delete 删除
|
||||
// @Tags 机器
|
||||
// @Summary 机器删除
|
||||
// @Description 机器删除
|
||||
// @Tags 设备
|
||||
// @Summary 设备删除
|
||||
// @Description 设备删除
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body admin.PeerForm true "机器信息"
|
||||
// @Param body body admin.PeerForm true "设备信息"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/peer/delete [post]
|
||||
@@ -137,11 +157,11 @@ func (ct *Peer) Update(c *gin.Context) {
|
||||
func (ct *Peer) Delete(c *gin.Context) {
|
||||
f := &admin.PeerForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "系统错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
id := f.RowId
|
||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
||||
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -153,8 +173,37 @@ func (ct *Peer) Delete(c *gin.Context) {
|
||||
response.Success(c, nil)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, err.Error())
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
}
|
||||
|
||||
// BatchDelete 批量删除
|
||||
// @Tags 设备
|
||||
// @Summary 批量设备删除
|
||||
// @Description 批量设备删除
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body admin.PeerBatchDeleteForm true "设备id"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/peer/delete [post]
|
||||
// @Security token
|
||||
func (ct *Peer) BatchDelete(c *gin.Context) {
|
||||
f := &admin.PeerBatchDeleteForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
if len(f.RowIds) == 0 {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
err := service.AllService.PeerService.BatchDelete(f.RowIds)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
type Rustdesk struct {
|
||||
}
|
||||
|
||||
// ServerConfig 服务配置
|
||||
// ServerConfig RUSTDESK服务配置
|
||||
// @Tags ADMIN
|
||||
// @Summary 服务配置
|
||||
// @Summary RUSTDESK服务配置
|
||||
// @Description 服务配置,给webclient提供api-server
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
@@ -28,3 +28,19 @@ func (r *Rustdesk) ServerConfig(c *gin.Context) {
|
||||
}
|
||||
response.Success(c, cf)
|
||||
}
|
||||
|
||||
// AppConfig APP服务配置
|
||||
// @Tags ADMIN
|
||||
// @Summary APP服务配置
|
||||
// @Description APP服务配置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/app-config [get]
|
||||
// @Security token
|
||||
func (r *Rustdesk) AppConfig(c *gin.Context) {
|
||||
response.Success(c, &gin.H{
|
||||
"web_client": global.Config.App.WebClient,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -30,14 +30,14 @@ func (ct *Tag) Detail(c *gin.Context) {
|
||||
t := service.AllService.TagService.InfoById(uint(iid))
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
||||
response.Fail(c, 101, "无权限")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||
return
|
||||
}
|
||||
if t.Id > 0 {
|
||||
response.Success(c, t)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -55,10 +55,10 @@ func (ct *Tag) Detail(c *gin.Context) {
|
||||
func (ct *Tag) Create(c *gin.Context) {
|
||||
f := &admin.TagForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -70,7 +70,7 @@ func (ct *Tag) Create(c *gin.Context) {
|
||||
}
|
||||
err := service.AllService.TagService.Create(t)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "创建失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, u)
|
||||
@@ -93,7 +93,7 @@ func (ct *Tag) Create(c *gin.Context) {
|
||||
func (ct *Tag) List(c *gin.Context) {
|
||||
query := &admin.TagQuery{}
|
||||
if err := c.ShouldBindQuery(query); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
@@ -122,27 +122,27 @@ func (ct *Tag) List(c *gin.Context) {
|
||||
func (ct *Tag) Update(c *gin.Context) {
|
||||
f := &admin.TagForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
if f.Id == 0 {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
t := f.ToTag()
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
||||
response.Fail(c, 101, "无权限")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||
return
|
||||
}
|
||||
err := service.AllService.TagService.Update(t)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "更新失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
@@ -162,11 +162,11 @@ func (ct *Tag) Update(c *gin.Context) {
|
||||
func (ct *Tag) Delete(c *gin.Context) {
|
||||
f := &admin.TagForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "系统错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
id := f.Id
|
||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
||||
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -174,7 +174,7 @@ func (ct *Tag) Delete(c *gin.Context) {
|
||||
t := service.AllService.TagService.InfoById(f.Id)
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
||||
response.Fail(c, 101, "无权限")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||
return
|
||||
}
|
||||
if u.Id > 0 {
|
||||
@@ -186,5 +186,5 @@ func (ct *Tag) Delete(c *gin.Context) {
|
||||
response.Fail(c, 101, err.Error())
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (ct *User) Detail(c *gin.Context) {
|
||||
response.Success(c, u)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -51,10 +51,10 @@ func (ct *User) Detail(c *gin.Context) {
|
||||
func (ct *User) Create(c *gin.Context) {
|
||||
f := &admin.UserForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -62,7 +62,7 @@ func (ct *User) Create(c *gin.Context) {
|
||||
u := f.ToUser()
|
||||
err := service.AllService.UserService.Create(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "创建失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, u)
|
||||
@@ -84,7 +84,7 @@ func (ct *User) Create(c *gin.Context) {
|
||||
func (ct *User) List(c *gin.Context) {
|
||||
query := &admin.UserQuery{}
|
||||
if err := c.ShouldBindQuery(query); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
res := service.AllService.UserService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||
@@ -109,14 +109,14 @@ func (ct *User) List(c *gin.Context) {
|
||||
func (ct *User) Update(c *gin.Context) {
|
||||
f := &admin.UserForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误:"+err.Error())
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
if f.Id == 0 {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -124,7 +124,7 @@ func (ct *User) Update(c *gin.Context) {
|
||||
u := f.ToUser()
|
||||
err := service.AllService.UserService.Update(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "更新失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
@@ -144,11 +144,11 @@ func (ct *User) Update(c *gin.Context) {
|
||||
func (ct *User) Delete(c *gin.Context) {
|
||||
f := &admin.UserForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "系统错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
id := f.Id
|
||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
||||
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -163,7 +163,7 @@ func (ct *User) Delete(c *gin.Context) {
|
||||
response.Fail(c, 101, err.Error())
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
}
|
||||
|
||||
// UpdatePassword 修改密码
|
||||
@@ -180,22 +180,22 @@ func (ct *User) Delete(c *gin.Context) {
|
||||
func (ct *User) UpdatePassword(c *gin.Context) {
|
||||
f := &admin.UserPasswordForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.InfoById(f.Id)
|
||||
if u.Id == 0 {
|
||||
response.Fail(c, 101, "信息不存在")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
err := service.AllService.UserService.UpdatePassword(u, f.Password)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "更新失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
@@ -237,11 +237,11 @@ func (ct *User) Current(c *gin.Context) {
|
||||
func (ct *User) ChangeCurPwd(c *gin.Context) {
|
||||
f := &admin.ChangeCurPasswordForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, "参数错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
@@ -249,12 +249,12 @@ func (ct *User) ChangeCurPwd(c *gin.Context) {
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
oldPwd := service.AllService.UserService.EncryptPassword(f.OldPassword)
|
||||
if u.Password != oldPwd {
|
||||
response.Fail(c, 101, "旧密码错误")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OldPasswordError"))
|
||||
return
|
||||
}
|
||||
err := service.AllService.UserService.UpdatePassword(u, f.NewPassword)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, "更新失败")
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
requstform "Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
"Gwen/http/response/api"
|
||||
@@ -9,6 +10,7 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Ab struct {
|
||||
@@ -65,37 +67,30 @@ func (a *Ab) UpAb(c *gin.Context) {
|
||||
abf := &requstform.AddressBookForm{}
|
||||
err := c.ShouldBindJSON(&abf)
|
||||
if err != nil {
|
||||
response.Error(c, "参数错误")
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
abd := &requstform.AddressBookFormData{}
|
||||
err = json.Unmarshal([]byte(abf.Data), abd)
|
||||
if err != nil {
|
||||
response.Error(c, "系统错误")
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
tc := map[string]uint{}
|
||||
err = json.Unmarshal([]byte(abd.TagColors), &tc)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
//fmt.Println(abd)
|
||||
//for _, peer := range abd.Peers {
|
||||
// fmt.Println(peer)
|
||||
//}
|
||||
|
||||
user := service.AllService.UserService.CurUser(c)
|
||||
|
||||
err = service.AllService.AddressBookService.UpdateAddressBook(abd.Peers, user.Id)
|
||||
if err != nil {
|
||||
c.Abort()
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tc := map[string]uint{}
|
||||
err = json.Unmarshal([]byte(abd.TagColors), &tc)
|
||||
if err != nil {
|
||||
response.Error(c, "系统错误")
|
||||
return
|
||||
} else {
|
||||
service.AllService.TagService.UpdateTags(user.Id, tc)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, nil)
|
||||
}
|
||||
@@ -118,7 +113,7 @@ func (a *Ab) Tags(c *gin.Context) {
|
||||
}
|
||||
|
||||
// TagAdd
|
||||
// @Tags 地址
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 标签添加
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
@@ -131,16 +126,371 @@ func (a *Ab) TagAdd(c *gin.Context) {
|
||||
t := &model.Tag{}
|
||||
err := c.ShouldBindJSON(t)
|
||||
if err != nil {
|
||||
response.Error(c, "参数错误")
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
tag := service.AllService.TagService.InfoByUserIdAndName(u.Id, t.Name)
|
||||
if tag != nil && tag.Id != 0 {
|
||||
response.Error(c, response.TranslateMsg(c, "ItemExists"))
|
||||
return
|
||||
}
|
||||
t.UserId = u.Id
|
||||
err = service.AllService.TagService.Create(t)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
// TagRename
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 标签重命名
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/tag/rename/{guid} [put]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) TagRename(c *gin.Context) {
|
||||
t := &requstform.TagRenameForm{}
|
||||
err := c.ShouldBindJSON(t)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
tag := service.AllService.TagService.InfoByUserIdAndName(u.Id, t.Old)
|
||||
if tag == nil || tag.Id == 0 {
|
||||
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
ntag := service.AllService.TagService.InfoByUserIdAndName(u.Id, t.New)
|
||||
if ntag != nil && ntag.Id != 0 {
|
||||
response.Error(c, response.TranslateMsg(c, "ItemExists"))
|
||||
return
|
||||
}
|
||||
tag.Name = t.New
|
||||
err = service.AllService.TagService.Update(tag)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
// TagUpdate
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 标签修改颜色
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/tag/update/{guid} [put]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) TagUpdate(c *gin.Context) {
|
||||
t := &requstform.TagColorForm{}
|
||||
err := c.ShouldBindJSON(t)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
tag := service.AllService.TagService.InfoByUserIdAndName(u.Id, t.Name)
|
||||
if tag == nil || tag.Id == 0 {
|
||||
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
tag.Color = t.Color
|
||||
err = service.AllService.TagService.Update(tag)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
// TagDel
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 标签删除
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/tag/{guid} [delete]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) TagDel(c *gin.Context) {
|
||||
t := &[]string{}
|
||||
err := c.ShouldBind(t)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
//fmt.Println(t)
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
for _, name := range *t {
|
||||
tag := service.AllService.TagService.InfoByUserIdAndName(u.Id, name)
|
||||
if tag == nil || tag.Id == 0 {
|
||||
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
err = service.AllService.TagService.Delete(tag)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
// Personal
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 个人地址
|
||||
// @Description 个人地址
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param string body string false "string valid"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /ab/personal [post]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) Personal(c *gin.Context) {
|
||||
user := service.AllService.UserService.CurUser(c)
|
||||
/**
|
||||
guid = json['guid'] ?? '',
|
||||
name = json['name'] ?? '',
|
||||
owner = json['owner'] ?? '',
|
||||
note = json['note'] ?? '',
|
||||
rule = json['rule'] ?? 0;
|
||||
*/
|
||||
if global.Config.Rustdesk.Personal == 1 {
|
||||
guid := strconv.Itoa(int(user.GroupId)) + "-" + strconv.Itoa(int(user.Id))
|
||||
//如果返回了guid,后面的请求会有变化
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"guid": guid,
|
||||
"name": user.Username,
|
||||
"rule": 0,
|
||||
})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, nil)
|
||||
}
|
||||
|
||||
}
|
||||
//u := service.AllService.UserService.CurUser(c)
|
||||
|
||||
//err = service.AllService.TagService.UpdateTags(t.Name, t.Color, user.Id)
|
||||
//if err != nil {
|
||||
// response.Error(c, "操作失败")
|
||||
// Settings
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 设置
|
||||
// @Description 设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param string body string false "string valid"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /ab/settings [post]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) Settings(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"max_peer_one_ab": 0, //最大peer数,0表示不限制
|
||||
})
|
||||
}
|
||||
|
||||
// SharedProfiles
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 共享地址簿
|
||||
// @Description 共享
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param string body string false "string valid"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /ab/shared/profiles [post]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) SharedProfiles(c *gin.Context) {
|
||||
//AbProfile.fromJson(Map<String, dynamic> json)
|
||||
//: guid = json['guid'] ?? '',
|
||||
// name = json['name'] ?? '',
|
||||
// owner = json['owner'] ?? '',
|
||||
// note = json['note'] ?? '',
|
||||
// rule = json['rule'] ?? 0;
|
||||
//暂时没必要返回数据,可能是为了共享地址簿
|
||||
/*item := map[string]interface{}{
|
||||
"guid": "1",
|
||||
"name": "admin",
|
||||
"owner": "admin",
|
||||
"note": "admin11",
|
||||
"rule": 0,
|
||||
}
|
||||
item2 := map[string]interface{}{
|
||||
"guid": "2",
|
||||
"name": "admin2",
|
||||
"owner": "admin2",
|
||||
"note": "admin22",
|
||||
"rule": 0,
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"total": 2,
|
||||
"data": []interface{}{item, item2},
|
||||
})*/
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"total": 0,
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
|
||||
// Peers
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 地址列表
|
||||
// @Description 地址
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param string body string false "string valid"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /ab/peers [post]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) Peers(c *gin.Context) {
|
||||
user := service.AllService.UserService.CurUser(c)
|
||||
al := service.AllService.AddressBookService.ListByUserId(user.Id, 1, 1000)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"total": al.Total,
|
||||
"data": al.AddressBooks,
|
||||
"licensed_devices": 99999,
|
||||
})
|
||||
}
|
||||
|
||||
// PTags
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 标签
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Success 200 {object} model.TagList
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/tags/{guid} [post]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) PTags(c *gin.Context) {
|
||||
user := service.AllService.UserService.CurUser(c)
|
||||
|
||||
tags := service.AllService.TagService.ListByUserId(user.Id)
|
||||
c.JSON(http.StatusOK, tags.Tags)
|
||||
}
|
||||
|
||||
// PeerAdd
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 添加地址
|
||||
// @Description 添加地址
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/peer/add/{guid} [post]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) PeerAdd(c *gin.Context) {
|
||||
// forceAlwaysRelay永远是字符串"false"
|
||||
//f := &gin.H{}
|
||||
f := &requstform.PersonalAddressBookForm{}
|
||||
err := c.ShouldBindJSON(f)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
//fmt.Println(f)
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
f.UserId = u.Id
|
||||
ab := f.ToAddressBook()
|
||||
|
||||
if ab.Platform == "" || ab.Username == "" || ab.Hostname == "" {
|
||||
peer := service.AllService.PeerService.FindById(ab.Id)
|
||||
if peer.RowId != 0 {
|
||||
ab.Platform = service.AllService.AddressBookService.PlatformFromOs(peer.Os)
|
||||
ab.Username = peer.Username
|
||||
ab.Hostname = peer.Hostname
|
||||
}
|
||||
}
|
||||
|
||||
err = service.AllService.AddressBookService.AddAddressBook(ab)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
// PeerDel
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 删除地址
|
||||
// @Description 删除地址
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/peer/add/{guid} [delete]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) PeerDel(c *gin.Context) {
|
||||
f := &[]string{}
|
||||
err := c.ShouldBind(f)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
for _, id := range *f {
|
||||
ab := service.AllService.AddressBookService.InfoByUserIdAndId(u.Id, id)
|
||||
if ab == nil || ab.RowId == 0 {
|
||||
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
err = service.AllService.AddressBookService.Delete(ab)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
// PeerUpdate
|
||||
// @Tags 地址[Personal]
|
||||
// @Summary 更新地址
|
||||
// @Description 更新地址
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/peer/update/{guid} [put]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) PeerUpdate(c *gin.Context) {
|
||||
//f := &gin.H{}
|
||||
f := &requstform.PersonalAddressBookForm{}
|
||||
err := c.ShouldBindJSON(f)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
//fmt.Println(f)
|
||||
//return
|
||||
//}
|
||||
c.JSON(http.StatusOK, "")
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
ab := service.AllService.AddressBookService.InfoByUserIdAndId(u.Id, f.Id)
|
||||
if ab == nil || ab.RowId == 0 {
|
||||
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
nab := f.ToAddressBook()
|
||||
nab.RowId = ab.RowId
|
||||
err = service.AllService.AddressBookService.Update(nab)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (g *Group) Users(c *gin.Context) {
|
||||
if !*u.IsAdmin {
|
||||
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
||||
if gr.Type != model.GroupTypeShare {
|
||||
response.Error(c, "不是管理员也不在分享组")
|
||||
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ func (g *Group) Peers(c *gin.Context) {
|
||||
if !*u.IsAdmin {
|
||||
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
||||
if gr.Type != model.GroupTypeShare {
|
||||
response.Error(c, "不是管理员也不在分享组")
|
||||
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -96,15 +96,15 @@ func (g *Group) Peers(c *gin.Context) {
|
||||
namesById[user.Id] = user.Username
|
||||
userIds = append(userIds, user.Id)
|
||||
}
|
||||
peerList := service.AllService.AddressBookService.ListByUserIds(userIds, q.Page, q.PageSize)
|
||||
peerList := service.AllService.PeerService.ListByUserIds(userIds, q.Page, q.PageSize)
|
||||
var data []*apiResp.GroupPeerPayload
|
||||
for _, ab := range peerList.AddressBooks {
|
||||
uname, ok := namesById[ab.UserId]
|
||||
for _, peer := range peerList.Peers {
|
||||
uname, ok := namesById[peer.UserId]
|
||||
if !ok {
|
||||
uname = ""
|
||||
}
|
||||
pp := &apiResp.GroupPeerPayload{}
|
||||
pp.FromAddressBook(ab, uname)
|
||||
pp.FromPeer(peer, uname)
|
||||
data = append(data, pp)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
requstform "Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Index struct {
|
||||
@@ -35,5 +38,22 @@ func (i *Index) Index(c *gin.Context) {
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /heartbeat [post]
|
||||
func (i *Index) Heartbeat(c *gin.Context) {
|
||||
info := &requstform.PeerInfoInHeartbeat{}
|
||||
err := c.ShouldBindJSON(info)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
return
|
||||
}
|
||||
if info.Uuid == "" {
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
return
|
||||
}
|
||||
peer := service.AllService.PeerService.FindByUuid(info.Uuid)
|
||||
if peer == nil {
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
return
|
||||
}
|
||||
peer.LastOnlineTime = time.Now().Unix()
|
||||
service.AllService.PeerService.Update(peer)
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
@@ -30,12 +31,14 @@ func (l *Login) Login(c *gin.Context) {
|
||||
err := c.ShouldBindJSON(f)
|
||||
//fmt.Println(f)
|
||||
if err != nil {
|
||||
response.Error(c, "参数错误")
|
||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
errList := global.Validator.ValidStruct(f)
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||
response.Error(c, errList[0])
|
||||
return
|
||||
}
|
||||
@@ -43,7 +46,8 @@ func (l *Login) Login(c *gin.Context) {
|
||||
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
||||
|
||||
if u.Id == 0 {
|
||||
response.Error(c, "用户名或密码错误")
|
||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
||||
response.Error(c, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -95,7 +99,7 @@ func (l *Login) LoginOptions(c *gin.Context) {
|
||||
}
|
||||
common, err := json.Marshal(oidcItems)
|
||||
if err != nil {
|
||||
response.Error(c, "参数错误")
|
||||
response.Error(c, response.TranslateMsg(c, "SystemError")+err.Error())
|
||||
return
|
||||
}
|
||||
var res []string
|
||||
|
||||
@@ -29,17 +29,17 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
|
||||
f := &api.OidcAuthRequest{}
|
||||
err := c.ShouldBindJSON(&f)
|
||||
if err != nil {
|
||||
response.Error(c, "参数错误")
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
if f.Op != model.OauthTypeWebauth && f.Op != model.OauthTypeGoogle && f.Op != model.OauthTypeGithub {
|
||||
response.Error(c, "参数错误")
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
|
||||
err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||
if err != nil {
|
||||
response.Error(c, err.Error())
|
||||
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -72,12 +72,12 @@ func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
||||
q := &api.OidcAuthQuery{}
|
||||
err := c.ShouldBindQuery(q)
|
||||
if err != nil {
|
||||
response.Error(c, "参数错误")
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
v := service.AllService.OauthService.GetOauthCache(q.Code)
|
||||
if v == nil {
|
||||
response.Error(c, "授权已过期,请重新授权")
|
||||
response.Error(c, response.TranslateMsg(c, "OauthExpired"))
|
||||
return
|
||||
}
|
||||
if v.UserId == 0 {
|
||||
@@ -87,7 +87,6 @@ func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
||||
}
|
||||
u := service.AllService.UserService.InfoById(v.UserId)
|
||||
//fmt.Println("auth success u", u)
|
||||
if u.Id > 0 {
|
||||
service.AllService.OauthService.DeleteOauthCache(q.Code)
|
||||
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
||||
UserId: u.Id,
|
||||
@@ -102,9 +101,6 @@ func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
||||
Type: "access_token",
|
||||
User: *(&apiResp.UserPayload{}).FromUser(u),
|
||||
})
|
||||
return
|
||||
}
|
||||
response.Error(c, "用户不存在")
|
||||
}
|
||||
|
||||
// OauthCallback 回调
|
||||
@@ -119,7 +115,7 @@ func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
||||
func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
state := c.Query("state")
|
||||
if state == "" {
|
||||
c.String(http.StatusInternalServerError, "state为空")
|
||||
c.String(http.StatusInternalServerError, response.TranslateParamMsg(c, "ParamIsEmpty", "state"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -127,7 +123,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
//从缓存中获取
|
||||
v := service.AllService.OauthService.GetOauthCache(cacheKey)
|
||||
if v == nil {
|
||||
c.String(http.StatusInternalServerError, "授权已过期,请重新授权")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthExpired"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -138,34 +134,34 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
code := c.Query("code")
|
||||
err, userData := service.AllService.OauthService.GithubCallback(code)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "授权失败:"+err.Error())
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
|
||||
return
|
||||
}
|
||||
if ac == service.OauthActionTypeBind {
|
||||
//fmt.Println("bind", ty, userData)
|
||||
utr := service.AllService.OauthService.UserThirdInfo(ty, strconv.Itoa(userData.Id))
|
||||
if utr.UserId > 0 {
|
||||
c.String(http.StatusInternalServerError, "已经绑定其他账号")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
|
||||
return
|
||||
}
|
||||
//绑定
|
||||
u := service.AllService.UserService.InfoById(v.UserId)
|
||||
if u == nil {
|
||||
c.String(http.StatusInternalServerError, "用户不存在")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
//绑定github
|
||||
err = service.AllService.OauthService.BindGithubUser(strconv.Itoa(userData.Id), userData.Login, v.UserId)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "绑定失败")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, "绑定成功")
|
||||
c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
|
||||
return
|
||||
} else if ac == service.OauthActionTypeLogin {
|
||||
//登录
|
||||
if v.UserId != 0 {
|
||||
c.String(http.StatusInternalServerError, "授权已经成功")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.InfoByGithubId(strconv.Itoa(userData.Id))
|
||||
@@ -183,19 +179,16 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
//自动注册
|
||||
u = service.AllService.UserService.RegisterByGithub(userData.Login, strconv.Itoa(userData.Id))
|
||||
if u.Id == 0 {
|
||||
c.String(http.StatusInternalServerError, "注册失败")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
v.UserId = u.Id
|
||||
service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
||||
c.String(http.StatusOK, "授权成功")
|
||||
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
||||
return
|
||||
}
|
||||
//返回js
|
||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||
c.String(http.StatusOK, "授权错误")
|
||||
|
||||
}
|
||||
|
||||
@@ -203,7 +196,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
code := c.Query("code")
|
||||
err, userData := service.AllService.OauthService.GoogleCallback(code)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "授权失败:"+err.Error())
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
|
||||
return
|
||||
}
|
||||
//将空格替换成_
|
||||
@@ -212,26 +205,26 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
//fmt.Println("bind", ty, userData)
|
||||
utr := service.AllService.OauthService.UserThirdInfo(ty, userData.Email)
|
||||
if utr.UserId > 0 {
|
||||
c.String(http.StatusInternalServerError, "已经绑定其他账号")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
|
||||
return
|
||||
}
|
||||
//绑定
|
||||
u := service.AllService.UserService.InfoById(v.UserId)
|
||||
if u == nil {
|
||||
c.String(http.StatusInternalServerError, "用户不存在")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
//绑定
|
||||
err = service.AllService.OauthService.BindGoogleUser(userData.Email, googleName, v.UserId)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "绑定失败")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, "绑定成功")
|
||||
c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
|
||||
return
|
||||
} else if ac == service.OauthActionTypeLogin {
|
||||
if v.UserId != 0 {
|
||||
c.String(http.StatusInternalServerError, "授权已经成功")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.InfoByGoogleEmail(userData.Email)
|
||||
@@ -250,30 +243,17 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
//自动注册
|
||||
u = service.AllService.UserService.RegisterByGoogle(googleName, userData.Email)
|
||||
if u.Id == 0 {
|
||||
c.String(http.StatusInternalServerError, "注册失败")
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
v.UserId = u.Id
|
||||
service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
||||
c.String(http.StatusOK, "授权成功")
|
||||
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
||||
return
|
||||
}
|
||||
}
|
||||
c.String(http.StatusInternalServerError, "授权配置错误,请联系管理员")
|
||||
|
||||
}
|
||||
|
||||
// WebOauthLogin
|
||||
// @Tags Oauth
|
||||
// @Summary WebOauthLogin
|
||||
// @Description WebOauthLogin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {string} string
|
||||
// @Router /oauth/login [get]
|
||||
func (o *Oauth) WebOauthLogin(c *gin.Context) {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "SystemError"))
|
||||
|
||||
}
|
||||
|
||||
@@ -22,25 +22,35 @@ type Peer struct {
|
||||
// @Success 200 {string} string "SYSINFO_UPDATED,ID_NOT_FOUND"
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /sysinfo [post]
|
||||
// @Security BearerAuth
|
||||
func (p *Peer) SysInfo(c *gin.Context) {
|
||||
f := &requstform.PeerForm{}
|
||||
err := c.ShouldBindBodyWith(f, binding.JSON)
|
||||
if err != nil {
|
||||
response.Error(c, err.Error())
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fpe := f.ToPeer()
|
||||
pe := service.AllService.PeerService.FindById(f.Id)
|
||||
if pe == nil || pe.RowId == 0 {
|
||||
if pe.RowId == 0 {
|
||||
pe = f.ToPeer()
|
||||
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
|
||||
err = service.AllService.PeerService.Create(pe)
|
||||
if err != nil {
|
||||
response.Error(c, err.Error())
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if pe.UserId == 0 {
|
||||
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
|
||||
}
|
||||
fpe.RowId = pe.RowId
|
||||
fpe.UserId = pe.UserId
|
||||
err = service.AllService.PeerService.Update(fpe)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//SYSINFO_UPDATED 上传成功
|
||||
//ID_NOT_FOUND 下次心跳会上传
|
||||
//直接响应文本
|
||||
|
||||
@@ -3,7 +3,6 @@ package api
|
||||
import (
|
||||
apiResp "Gwen/http/response/api"
|
||||
"Gwen/service"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
@@ -42,33 +41,3 @@ func (u *User) Info(c *gin.Context) {
|
||||
up := (&apiResp.UserPayload{}).FromUser(user)
|
||||
c.JSON(http.StatusOK, up)
|
||||
}
|
||||
|
||||
// Personal
|
||||
// @Tags 用户
|
||||
// @Summary 个人信息
|
||||
// @Description 个人信息
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param string body string false "string valid"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /ab/personal [post]
|
||||
// @Security BearerAuth
|
||||
func (u *User) Personal(c *gin.Context) {
|
||||
//打印全部body
|
||||
fmt.Println(c.Request.Body)
|
||||
|
||||
/**
|
||||
guid = json['guid'] ?? '',
|
||||
name = json['name'] ?? '',
|
||||
owner = json['owner'] ?? '',
|
||||
note = json['note'] ?? '',
|
||||
rule = json['rule'] ?? 0;
|
||||
*/
|
||||
//如果返回了guid,后面的请求会有变化
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
//"guid": "123456",
|
||||
//"name": "admindddd",
|
||||
//"rule": 1,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"Gwen/http/response/api"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WebClient struct {
|
||||
@@ -40,3 +41,47 @@ func (i *WebClient) ServerConfig(c *gin.Context) {
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// SharedPeer 分享的peer
|
||||
// @Tags WEBCLIENT
|
||||
// @Summary 分享的peer
|
||||
// @Description 分享的peer
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /shared-peer [post]
|
||||
func (i *WebClient) SharedPeer(c *gin.Context) {
|
||||
j := &gin.H{}
|
||||
c.ShouldBindJSON(j)
|
||||
t := (*j)["share_token"].(string)
|
||||
if t == "" {
|
||||
response.Fail(c, 101, "share_token is required")
|
||||
return
|
||||
}
|
||||
sr := service.AllService.AddressBookService.SharedPeer(t)
|
||||
if sr == nil || sr.Id == 0 {
|
||||
response.Fail(c, 101, "share not found")
|
||||
return
|
||||
}
|
||||
//判断是否过期,created_at + expire > now
|
||||
ca := time.Time(sr.CreatedAt)
|
||||
if ca.Add(time.Second * time.Duration(sr.Expire)).Before(time.Now()) {
|
||||
response.Fail(c, 101, "share expired")
|
||||
return
|
||||
}
|
||||
ab := service.AllService.AddressBookService.InfoByUserIdAndId(sr.UserId, sr.PeerId)
|
||||
if ab.RowId == 0 {
|
||||
response.Fail(c, 101, "peer not found")
|
||||
return
|
||||
}
|
||||
pp := &api.WebClientPeerPayload{}
|
||||
pp.FromShareRecord(sr)
|
||||
pp.Info.Username = ab.Username
|
||||
pp.Info.Hostname = ab.Hostname
|
||||
response.Success(c, gin.H{
|
||||
"id_server": global.Config.Rustdesk.IdServer,
|
||||
"key": global.Config.Rustdesk.Key,
|
||||
"peer": pp,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,67 +8,15 @@ import (
|
||||
type Index struct {
|
||||
}
|
||||
|
||||
func (i *Index) Index(c *gin.Context) {
|
||||
c.Redirect(302, "/_admin/")
|
||||
}
|
||||
|
||||
func (i *Index) ConfigJs(c *gin.Context) {
|
||||
apiServer := global.Config.Rustdesk.ApiServer
|
||||
|
||||
tmp := `
|
||||
window._gwen = {}
|
||||
window._gwen.kv = {}
|
||||
function getQueryVariable() {
|
||||
const query = window.location.hash.substring(3);
|
||||
const vars = query.split("&");
|
||||
for (var i = 0; i < vars.length; i++) {
|
||||
var pair = vars[i].split("=");
|
||||
window._gwen.kv[pair[0]] = pair[1]
|
||||
}
|
||||
}
|
||||
getQueryVariable()
|
||||
const id = window._gwen.kv.id || ''
|
||||
if (id) {
|
||||
localStorage.setItem('remote-id', id)
|
||||
}
|
||||
window._gwen.hosts = [
|
||||
"rs-sg.rustdesk.com",
|
||||
"rs-cn.rustdesk.com",
|
||||
"rs-us.rustdesk.com",
|
||||
]
|
||||
localStorage.setItem('api-server', "` + apiServer + `")
|
||||
const autoWriteServer = () => {
|
||||
return setTimeout(() => {
|
||||
const token = localStorage.getItem('access_token')
|
||||
const apiserver = localStorage.getItem('api-server')
|
||||
if (token && apiserver) {
|
||||
fetch(apiserver + "/api/server-config", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token
|
||||
}
|
||||
}
|
||||
).then(res => res.json()).then(res => {
|
||||
if (res.code === 0) {
|
||||
if(!localStorage.getItem('custom-rendezvous-server') || !localStorage.getItem('key') ) {
|
||||
localStorage.setItem('custom-rendezvous-server', res.data.id_server)
|
||||
localStorage.setItem('key', res.data.key)
|
||||
}
|
||||
|
||||
if (res.data.peers) {
|
||||
oldPeers = JSON.parse(localStorage.getItem('peers')) || {}
|
||||
Object.keys(res.data.peers).forEach(k => {
|
||||
if(!oldPeers[k]) {
|
||||
oldPeers[k] = res.data.peers[k]
|
||||
}
|
||||
})
|
||||
localStorage.setItem('peers', JSON.stringify(oldPeers))
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
autoWriteServer()
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
autoWriteServer()
|
||||
`
|
||||
c.String(200, tmp)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
func RustAuth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
//fmt.Println(c.Request.URL, c.Request.Header)
|
||||
//获取HTTP_AUTHORIZATION
|
||||
token := c.GetHeader("Authorization")
|
||||
if token == "" {
|
||||
|
||||
@@ -16,12 +16,13 @@ type AddressBookForm struct {
|
||||
Tags []string `json:"tags"`
|
||||
Hash string `json:"hash"`
|
||||
UserId uint `json:"user_id"`
|
||||
ForceAlwaysRelay bool `json:"force_always_relay"`
|
||||
RdpPort string `json:"rdp_port"`
|
||||
RdpUsername string `json:"rdp_username"`
|
||||
UserIds []uint `json:"user_ids"`
|
||||
ForceAlwaysRelay bool `json:"forceAlwaysRelay"`
|
||||
RdpPort string `json:"rdpPort"`
|
||||
RdpUsername string `json:"rdpUsername"`
|
||||
Online bool `json:"online"`
|
||||
LoginName string `json:"login_name" `
|
||||
SameServer bool `json:"same_server"`
|
||||
LoginName string `json:"loginName" `
|
||||
SameServer bool `json:"sameServer"`
|
||||
}
|
||||
|
||||
func (a AddressBookForm) ToAddressBook() *model.AddressBook {
|
||||
@@ -48,9 +49,56 @@ func (a AddressBookForm) ToAddressBook() *model.AddressBook {
|
||||
}
|
||||
|
||||
}
|
||||
func (a AddressBookForm) ToAddressBooks() []*model.AddressBook {
|
||||
//tags转换
|
||||
tags, _ := json.Marshal(a.Tags)
|
||||
|
||||
abs := make([]*model.AddressBook, 0, len(a.UserIds))
|
||||
for _, userId := range a.UserIds {
|
||||
abs = append(abs, &model.AddressBook{
|
||||
RowId: a.RowId,
|
||||
Id: a.Id,
|
||||
Username: a.Username,
|
||||
Password: a.Password,
|
||||
Hostname: a.Hostname,
|
||||
Alias: a.Alias,
|
||||
Platform: a.Platform,
|
||||
Tags: tags,
|
||||
Hash: a.Hash,
|
||||
UserId: userId,
|
||||
ForceAlwaysRelay: a.ForceAlwaysRelay,
|
||||
RdpPort: a.RdpPort,
|
||||
RdpUsername: a.RdpUsername,
|
||||
Online: a.Online,
|
||||
LoginName: a.LoginName,
|
||||
SameServer: a.SameServer,
|
||||
})
|
||||
}
|
||||
return abs
|
||||
}
|
||||
|
||||
type AddressBookQuery struct {
|
||||
UserId int `form:"user_id"`
|
||||
IsMy int `form:"is_my"`
|
||||
Username string `form:"username"`
|
||||
Hostname string `form:"hostname"`
|
||||
Id string `form:"id"`
|
||||
PageQuery
|
||||
}
|
||||
|
||||
type ShareByWebClientForm struct {
|
||||
Id string `json:"id" validate:"required"`
|
||||
PasswordType string `json:"password_type" validate:"required,oneof=once fixed"` //只能是once,fixed
|
||||
Password string `json:"password" validate:"required"`
|
||||
Expire int64 `json:"expire"`
|
||||
}
|
||||
|
||||
func (sbwcf ShareByWebClientForm) ToShareRecord() *model.ShareRecord {
|
||||
return &model.ShareRecord{
|
||||
UserId: 0,
|
||||
PeerId: sbwcf.Id,
|
||||
PasswordType: sbwcf.PasswordType,
|
||||
Password: sbwcf.Password,
|
||||
Expire: sbwcf.Expire,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ type PeerForm struct {
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type PeerBatchDeleteForm struct {
|
||||
RowIds []uint `json:"row_ids" validate:"required"`
|
||||
}
|
||||
|
||||
// ToPeer
|
||||
func (f *PeerForm) ToPeer() *model.Peer {
|
||||
return &model.Peer{
|
||||
@@ -28,3 +32,10 @@ func (f *PeerForm) ToPeer() *model.Peer {
|
||||
Version: f.Version,
|
||||
}
|
||||
}
|
||||
|
||||
type PeerQuery struct {
|
||||
PageQuery
|
||||
TimeAgo int `json:"time_ago" form:"time_ago"`
|
||||
Id string `json:"id" form:"id"`
|
||||
Hostname string `json:"hostname" form:"hostname"`
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ type UserForm struct {
|
||||
Id uint `json:"id"`
|
||||
Username string `json:"username" validate:"required,gte=4,lte=10"`
|
||||
//Password string `json:"password" validate:"required,gte=4,lte=20"`
|
||||
Nickname string `json:"nickname" validate:"required"`
|
||||
Nickname string `json:"nickname"`
|
||||
Avatar string `json:"avatar"`
|
||||
GroupId uint `json:"group_id" validate:"required"`
|
||||
IsAdmin *bool `json:"is_admin" `
|
||||
|
||||
@@ -35,3 +35,45 @@ func (pf *PeerForm) ToPeer() *model.Peer {
|
||||
Version: pf.Version,
|
||||
}
|
||||
}
|
||||
|
||||
// PersonalAddressBookForm 个人地址簿表单
|
||||
type PersonalAddressBookForm struct {
|
||||
model.AddressBook
|
||||
ForceAlwaysRelay string `json:"forceAlwaysRelay"`
|
||||
}
|
||||
|
||||
func (pabf *PersonalAddressBookForm) ToAddressBook() *model.AddressBook {
|
||||
return &model.AddressBook{
|
||||
RowId: pabf.RowId,
|
||||
Id: pabf.Id,
|
||||
Username: pabf.Username,
|
||||
Password: pabf.Password,
|
||||
Hostname: pabf.Hostname,
|
||||
Alias: pabf.Alias,
|
||||
Platform: pabf.Platform,
|
||||
Tags: pabf.Tags,
|
||||
Hash: pabf.Hash,
|
||||
UserId: pabf.UserId,
|
||||
ForceAlwaysRelay: pabf.ForceAlwaysRelay == "true",
|
||||
RdpPort: pabf.RdpPort,
|
||||
RdpUsername: pabf.RdpUsername,
|
||||
Online: pabf.Online,
|
||||
LoginName: pabf.LoginName,
|
||||
SameServer: pabf.SameServer,
|
||||
}
|
||||
}
|
||||
|
||||
type TagRenameForm struct {
|
||||
Old string `json:"old"`
|
||||
New string `json:"new"`
|
||||
}
|
||||
type TagColorForm struct {
|
||||
Name string `json:"name"`
|
||||
Color uint `json:"color"`
|
||||
}
|
||||
|
||||
type PeerInfoInHeartbeat struct {
|
||||
Id string `json:"id"`
|
||||
Uuid string `json:"uuid"`
|
||||
Ver int `json:"ver"`
|
||||
}
|
||||
|
||||
@@ -59,16 +59,13 @@ func (gpp *GroupPeerPayload) FromAddressBook(a *model.AddressBook, username stri
|
||||
gpp.UserName = username
|
||||
}
|
||||
|
||||
//func (gpp *GroupPeerPayload) FromPeer(p *model.Peer) {
|
||||
// gpp.Id = p.Id
|
||||
// gpp.Info = &PeerPayloadInfo{
|
||||
// DeviceName: p.Hostname,
|
||||
// Os: p.Os,
|
||||
// Username: p.Username,
|
||||
// }
|
||||
// gpp.Note = ""
|
||||
// if p.User.Id != 0 {
|
||||
// //gpp.User = p.User.Username
|
||||
// gpp.UserName = p.User.Username
|
||||
// }
|
||||
//}
|
||||
func (gpp *GroupPeerPayload) FromPeer(p *model.Peer, username string) {
|
||||
gpp.Id = p.Id
|
||||
gpp.Info = &PeerPayloadInfo{
|
||||
DeviceName: p.Hostname,
|
||||
Os: p.Os,
|
||||
Username: p.Username,
|
||||
}
|
||||
gpp.Note = ""
|
||||
gpp.UserName = username
|
||||
}
|
||||
|
||||
@@ -9,12 +9,15 @@ type WebClientPeerPayload struct {
|
||||
ViewStyle string `json:"view-style"`
|
||||
Tm int64 `json:"tm"`
|
||||
Info WebClientPeerInfoPayload `json:"info"`
|
||||
Tmppwd string `json:"tmppwd"`
|
||||
}
|
||||
|
||||
type WebClientPeerInfoPayload struct {
|
||||
Username string `json:"username"`
|
||||
Hostname string `json:"hostname"`
|
||||
Platform string `json:"platform"`
|
||||
Hash string `json:"hash"`
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
func (wcpp *WebClientPeerPayload) FromAddressBook(a *model.AddressBook) {
|
||||
@@ -25,5 +28,19 @@ func (wcpp *WebClientPeerPayload) FromAddressBook(a *model.AddressBook) {
|
||||
Username: a.Username,
|
||||
Hostname: a.Hostname,
|
||||
Platform: a.Platform,
|
||||
Hash: a.Hash,
|
||||
}
|
||||
}
|
||||
|
||||
func (wcpp *WebClientPeerPayload) FromShareRecord(sr *model.ShareRecord) {
|
||||
wcpp.ViewStyle = "shrink"
|
||||
//24小时前
|
||||
wcpp.Tm = time.Now().UnixNano()
|
||||
wcpp.Tmppwd = sr.Password
|
||||
wcpp.Info = WebClientPeerInfoPayload{
|
||||
Username: "",
|
||||
Hostname: "",
|
||||
Platform: "",
|
||||
Id: sr.PeerId,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -51,3 +54,48 @@ type ServerConfigResponse struct {
|
||||
RelayServer string `json:"relay_server"`
|
||||
ApiServer string `json:"api_server"`
|
||||
}
|
||||
|
||||
func TranslateMsg(c *gin.Context, messageId string) string {
|
||||
localizer := global.Localizer(c)
|
||||
errMsg, err := localizer.LocalizeMessage(&i18n.Message{
|
||||
ID: messageId,
|
||||
})
|
||||
if err != nil {
|
||||
global.Logger.Warn("LocalizeMessage Error: " + err.Error())
|
||||
errMsg = messageId
|
||||
}
|
||||
return errMsg
|
||||
}
|
||||
func TranslateTempMsg(c *gin.Context, messageId string, templateData map[string]interface{}) string {
|
||||
localizer := global.Localizer(c)
|
||||
errMsg, err := localizer.Localize(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: messageId,
|
||||
},
|
||||
TemplateData: templateData,
|
||||
})
|
||||
if err != nil {
|
||||
global.Logger.Warn("LocalizeMessage Error: " + err.Error())
|
||||
errMsg = messageId
|
||||
}
|
||||
return errMsg
|
||||
}
|
||||
func TranslateParamMsg(c *gin.Context, messageId string, params ...string) string {
|
||||
localizer := global.Localizer(c)
|
||||
templateData := make(map[string]interface{})
|
||||
for i, v := range params {
|
||||
k := fmt.Sprintf("P%d", i)
|
||||
templateData[k] = v
|
||||
}
|
||||
errMsg, err := localizer.Localize(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: messageId,
|
||||
},
|
||||
TemplateData: templateData,
|
||||
})
|
||||
if err != nil {
|
||||
global.Logger.Warn("LocalizeMessage Error: " + err.Error())
|
||||
errMsg = messageId
|
||||
}
|
||||
return errMsg
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ func Init(g *gin.Engine) {
|
||||
|
||||
rs := &admin.Rustdesk{}
|
||||
adg.GET("/server-config", rs.ServerConfig)
|
||||
adg.GET("/app-config", rs.AppConfig)
|
||||
|
||||
//访问静态文件
|
||||
//g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload"))
|
||||
@@ -93,6 +94,10 @@ func AddressBookBind(rg *gin.RouterGroup) {
|
||||
aR.POST("/create", cont.Create)
|
||||
aR.POST("/update", cont.Update)
|
||||
aR.POST("/delete", cont.Delete)
|
||||
aR.POST("/shareByWebClient", cont.ShareByWebClient)
|
||||
|
||||
arp := aR.Use(middleware.AdminPrivilege())
|
||||
arp.POST("/batchCreate", cont.BatchCreate)
|
||||
}
|
||||
}
|
||||
func PeerBind(rg *gin.RouterGroup) {
|
||||
@@ -104,6 +109,9 @@ func PeerBind(rg *gin.RouterGroup) {
|
||||
aR.POST("/create", cont.Create)
|
||||
aR.POST("/update", cont.Update)
|
||||
aR.POST("/delete", cont.Delete)
|
||||
|
||||
arp := aR.Use(middleware.AdminPrivilege())
|
||||
arp.POST("/batchDelete", cont.BatchDelete)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,12 +46,12 @@ func ApiInit(g *gin.Engine) {
|
||||
//提交系统信息
|
||||
frg.POST("/sysinfo", pe.SysInfo)
|
||||
}
|
||||
frg.Use(middleware.RustAuth())
|
||||
{
|
||||
w := &api.WebClient{}
|
||||
frg.POST("/server-config", w.ServerConfig)
|
||||
|
||||
if global.Config.App.WebClient == 1 {
|
||||
WebClientRoutes(frg)
|
||||
}
|
||||
|
||||
frg.Use(middleware.RustAuth())
|
||||
{
|
||||
u := &api.User{}
|
||||
frg.GET("/user/info", u.Info)
|
||||
@@ -74,7 +74,49 @@ func ApiInit(g *gin.Engine) {
|
||||
//更新地址
|
||||
frg.POST("/ab", ab.UpAb)
|
||||
}
|
||||
|
||||
PersonalRoutes(frg)
|
||||
//访问静态文件
|
||||
g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/public/upload"))
|
||||
}
|
||||
|
||||
func PersonalRoutes(frg *gin.RouterGroup) {
|
||||
{
|
||||
ab := &api.Ab{}
|
||||
frg.POST("/ab/personal", ab.Personal)
|
||||
//[method:POST] [uri:/api/ab/settings] Request
|
||||
frg.POST("/ab/settings", ab.Settings)
|
||||
// [method:POST] [uri:/api/ab/shared/profiles?current=1&pageSize=100]
|
||||
frg.POST("/ab/shared/profiles", ab.SharedProfiles)
|
||||
//[method:POST] [uri:/api/ab/peers?current=1&pageSize=100&ab=1]
|
||||
frg.POST("/ab/peers", ab.Peers)
|
||||
// [method:POST] [uri:/api/ab/tags/1]
|
||||
frg.POST("/ab/tags/:guid", ab.PTags)
|
||||
//[method:POST] api/ab/peer/add/1
|
||||
frg.POST("/ab/peer/add/:guid", ab.PeerAdd)
|
||||
//[method:DELETE] [uri:/api/ab/peer/1]
|
||||
frg.DELETE("/ab/peer/:guid", ab.PeerDel)
|
||||
//[method:PUT] [uri:/api/ab/peer/update/1]
|
||||
frg.PUT("/ab/peer/update/:guid", ab.PeerUpdate)
|
||||
//[method:POST] [uri:/api/ab/tag/add/1]
|
||||
frg.POST("/ab/tag/add/:guid", ab.TagAdd)
|
||||
//[method:PUT] [uri:/api/ab/tag/rename/1]
|
||||
frg.PUT("/ab/tag/rename/:guid", ab.TagRename)
|
||||
//[method:PUT] [uri:/api/ab/tag/update/1]
|
||||
frg.PUT("/ab/tag/update/:guid", ab.TagUpdate)
|
||||
//[method:DELETE] [uri:/api/ab/tag/1]
|
||||
frg.DELETE("/ab/tag/:guid", ab.TagDel)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func WebClientRoutes(frg *gin.RouterGroup) {
|
||||
w := &api.WebClient{}
|
||||
{
|
||||
frg.POST("/shared-peer", w.SharedPeer)
|
||||
}
|
||||
{
|
||||
frg.POST("/server-config", middleware.RustAuth(), w.ServerConfig)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,14 @@ import (
|
||||
|
||||
func WebInit(g *gin.Engine) {
|
||||
i := &web.Index{}
|
||||
g.GET("/", i.Index)
|
||||
|
||||
if global.Config.App.WebClient == 1 {
|
||||
g.GET("/webclient-config/index.js", i.ConfigJs)
|
||||
}
|
||||
|
||||
if global.Config.App.WebClient == 1 {
|
||||
g.StaticFS("/webclient", http.Dir(global.Config.Gin.ResourcesPath+"/web"))
|
||||
}
|
||||
g.StaticFS("/_admin", http.Dir(global.Config.Gin.ResourcesPath+"/admin"))
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package orm
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"fmt"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MysqlConfig struct {
|
||||
@@ -22,6 +25,16 @@ func NewMysql(mysqlConf *MysqlConfig) *gorm.DB {
|
||||
//SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
|
||||
}), &gorm.Config{
|
||||
DisableForeignKeyConstraintWhenMigrating: true,
|
||||
Logger: logger.New(
|
||||
global.Logger, // 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)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package orm
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"fmt"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SqliteConfig struct {
|
||||
@@ -12,7 +15,19 @@ type SqliteConfig struct {
|
||||
}
|
||||
|
||||
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,
|
||||
Logger: logger.New(
|
||||
global.Logger, // 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)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ type Peer struct {
|
||||
Version string `json:"version" gorm:"default:'';not null;"`
|
||||
UserId uint `json:"user_id" gorm:"default:0;not null;index"`
|
||||
User User `json:"user,omitempty" gorm:""`
|
||||
LastOnlineTime int64 `json:"last_online_time" gorm:"default:0;not null;"`
|
||||
TimeModel
|
||||
}
|
||||
|
||||
|
||||
12
model/shareRecord.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package model
|
||||
|
||||
type ShareRecord struct {
|
||||
IdModel
|
||||
UserId uint `json:"user_id" gorm:"default:0;not null;index"`
|
||||
PeerId string `json:"peer_id" gorm:"default:'';not null;index"`
|
||||
ShareToken string `json:"share_token" gorm:"default:'';not null;index"`
|
||||
PasswordType string `json:"password_type" gorm:"default:'';not null;"`
|
||||
Password string `json:"password" gorm:"default:'';not null;"`
|
||||
Expire int64 `json:"expire" gorm:"default:0;not null;"`
|
||||
TimeModel
|
||||
}
|
||||
121
resources/i18n/en.toml
Normal file
@@ -0,0 +1,121 @@
|
||||
[Test]
|
||||
description = "test"
|
||||
one = "test1 "
|
||||
other = "Test2 {{.P0}}"
|
||||
|
||||
[ParamsError]
|
||||
description = "Params validation failed."
|
||||
one = "Params validation failed."
|
||||
other = "Params validation failed."
|
||||
|
||||
[OperationFailed]
|
||||
description = "OperationFailed."
|
||||
one = "the operation failed."
|
||||
other = "the operation failed."
|
||||
|
||||
[OperationSuccess]
|
||||
description = "OperationSuccess."
|
||||
one = "the operation success."
|
||||
other = "the operation success."
|
||||
|
||||
[ItemExists]
|
||||
description = "Item already exists."
|
||||
one = "Item already exists."
|
||||
other = "Item already exists."
|
||||
|
||||
[ItemNotFound]
|
||||
description = "Item not found."
|
||||
one = "Item not found."
|
||||
other = "Item not found."
|
||||
|
||||
[NoAccess]
|
||||
description = "No access."
|
||||
one = "No access."
|
||||
other = "No access."
|
||||
|
||||
[UsernameOrPasswordError]
|
||||
description = "Username or password error."
|
||||
one = "Username or password error."
|
||||
other = "Username or password error."
|
||||
|
||||
[SystemError]
|
||||
description = "System error."
|
||||
one = "System error."
|
||||
other = "System error."
|
||||
|
||||
[ConfigNotFound]
|
||||
description = "Config not found."
|
||||
one = "Config not found."
|
||||
other = "Config not found."
|
||||
|
||||
[OauthExpired]
|
||||
description = "Oauth expired."
|
||||
one = "Oauth expired, please try again."
|
||||
other = "Oauth expired,please try again."
|
||||
|
||||
[OauthFailed]
|
||||
description = "Oauth failed."
|
||||
one = "Oauth failed."
|
||||
other = "Oauth failed."
|
||||
|
||||
[OauthHasBindOtherUser]
|
||||
description = "Oauth has bind other user."
|
||||
one = "Oauth has bind other user."
|
||||
other = "Oauth has bind other user."
|
||||
|
||||
[ParamIsEmpty]
|
||||
description = "Param is empty."
|
||||
one = "{{.P0}} is empty."
|
||||
other = "{{.P0}} is empty."
|
||||
|
||||
[BindFail]
|
||||
description = "Bind fail."
|
||||
one = "Bind fail."
|
||||
other = "Bind fail."
|
||||
[BindSuccess]
|
||||
description = "Bind success."
|
||||
one = "Bind success."
|
||||
other = "Bind success."
|
||||
[OauthHasBeenSuccess]
|
||||
description = "Oauth has been success."
|
||||
one = "Oauth has been success."
|
||||
other = "Oauth has been success."
|
||||
[OauthSuccess]
|
||||
description = "Oauth success."
|
||||
one = "Oauth success."
|
||||
other = "Oauth success."
|
||||
[OauthRegisterSuccess]
|
||||
description = "Oauth register success."
|
||||
one = "Oauth register success."
|
||||
other = "Oauth register success."
|
||||
[OauthRegisterFailed]
|
||||
description = "Oauth register failed."
|
||||
one = "Oauth register failed."
|
||||
other = "Oauth register failed."
|
||||
[GetOauthTokenError]
|
||||
description = "Get oauth token error."
|
||||
one = "Get oauth token error."
|
||||
other = "Get oauth token error."
|
||||
[GetOauthUserInfoError]
|
||||
description = "Get oauth user info error."
|
||||
one = "Get oauth user info error."
|
||||
other = "Get oauth user info error."
|
||||
[DecodeOauthUserInfoError]
|
||||
description = "Decode oauth user info error."
|
||||
one = "Decode oauth user info error."
|
||||
other = "Decode oauth user info error."
|
||||
|
||||
[OldPasswordError]
|
||||
description = "Old password error."
|
||||
one = "Old password error."
|
||||
other = "Old password error."
|
||||
|
||||
[DefaultGroup]
|
||||
description = "Default group"
|
||||
one = "Default Group"
|
||||
other = "Default Group"
|
||||
|
||||
[ShareGroup]
|
||||
description = "Share group"
|
||||
one = "Share Group"
|
||||
other = "Share Group"
|
||||
123
resources/i18n/zh_CN.toml
Normal file
@@ -0,0 +1,123 @@
|
||||
[Test]
|
||||
description = "test"
|
||||
one = "测试1 {{.P0}}"
|
||||
other = "测试2 {{.P0}}"
|
||||
|
||||
[ParamsError]
|
||||
description = "Params validation failed."
|
||||
one = "参数错误。"
|
||||
other = "参数错误。"
|
||||
|
||||
[OperationFailed]
|
||||
description = "OperationFailed."
|
||||
one = "操作失败。"
|
||||
other = "操作失败。"
|
||||
|
||||
[OperationSuccess]
|
||||
description = "OperationSuccess."
|
||||
one = "操作成功。"
|
||||
other = "操作成功。"
|
||||
|
||||
[ItemExists]
|
||||
description = "Item already exists."
|
||||
one = "数据已存在。"
|
||||
other = "数据已存在。"
|
||||
|
||||
[ItemNotFound]
|
||||
description = "Item not found."
|
||||
one = "数据不存在。"
|
||||
other = "数据不存在。"
|
||||
|
||||
[NoAccess]
|
||||
description = "No access."
|
||||
one = "无权限。"
|
||||
other = "无权限。"
|
||||
|
||||
[UsernameOrPasswordError]
|
||||
description = "Username or password error."
|
||||
one = "用户名或密码错误。"
|
||||
other = "用户名或密码错误。"
|
||||
|
||||
[SystemError]
|
||||
description = "System error."
|
||||
one = "系统错误。"
|
||||
other = "系统错误。"
|
||||
|
||||
[ConfigNotFound]
|
||||
description = "Config not found."
|
||||
one = "配置不存在。"
|
||||
other = "配置不存在。"
|
||||
|
||||
#授权过期
|
||||
[OauthExpired]
|
||||
description = "Oauth expired."
|
||||
one = "授权过期,请重新授权。"
|
||||
other = "授权过期,请重新授权。"
|
||||
|
||||
[OauthFailed]
|
||||
description = "Oauth failed."
|
||||
one = "授权失败。"
|
||||
other = "授权失败。"
|
||||
|
||||
[OauthHasBindOtherUser]
|
||||
description = "Oauth has bind other user."
|
||||
one = "授权已绑定其他用户。"
|
||||
other = "授权已绑定其他用户。"
|
||||
|
||||
[ParamIsEmpty]
|
||||
description = "Param is empty."
|
||||
one = "{{.P0}} 为空。"
|
||||
other = "{{.P0}} 为空。"
|
||||
|
||||
[BindFail]
|
||||
description = "Bind fail."
|
||||
one = "绑定失败。"
|
||||
other = "绑定失败。"
|
||||
[BindSuccess]
|
||||
description = "Bind success."
|
||||
one = "绑定成功。"
|
||||
other = "绑定成功。"
|
||||
[OauthHasBeenSuccess]
|
||||
description = "Oauth has been success."
|
||||
one = "授权已成功。"
|
||||
other = "授权已成功。"
|
||||
[OauthSuccess]
|
||||
description = "Oauth success."
|
||||
one = "授权成功。"
|
||||
other = "授权成功。"
|
||||
[OauthRegisterSuccess]
|
||||
description = "Oauth register success."
|
||||
one = "授权注册成功。"
|
||||
other = "授权注册成功。"
|
||||
[OauthRegisterFailed]
|
||||
description = "Oauth register failed."
|
||||
one = "授权注册失败。"
|
||||
other = "授权注册失败。"
|
||||
[GetOauthTokenError]
|
||||
description = "Get oauth token error."
|
||||
one = "获取授权token失败。"
|
||||
other = "获取授权token失败。"
|
||||
[GetOauthUserInfoError]
|
||||
description = "Get oauth user info error."
|
||||
one = "获取授权用户信息失败。"
|
||||
other = "获取授权用户信息失败。"
|
||||
[DecodeOauthUserInfoError]
|
||||
description = "Decode oauth user info error."
|
||||
one = "解析授权用户信息失败。"
|
||||
other = "解析授权用户信息失败。"
|
||||
|
||||
[OldPasswordError]
|
||||
description = "Old password error."
|
||||
one = "旧密码错误。"
|
||||
other = "旧密码错误。"
|
||||
|
||||
|
||||
[DefaultGroup]
|
||||
description = "Default group."
|
||||
one = "默认组"
|
||||
other = "默认组"
|
||||
|
||||
[ShareGroup]
|
||||
description = "Share group."
|
||||
one = "共享组"
|
||||
other = "共享组"
|
||||
8
resources/web/index.html
vendored
@@ -33,12 +33,10 @@
|
||||
<title>RustDesk</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<script src="/webclient-config/index.js"></script>
|
||||
<script>
|
||||
|
||||
|
||||
</script>
|
||||
<script src="ogvjs-1.8.6/ogv.js"></script>
|
||||
<script type="module" crossorigin src="js/dist/index.js"></script>
|
||||
<script>
|
||||
</script>
|
||||
<link rel="modulepreload" href="js/dist/vendor.js">
|
||||
<script src="yuv-canvas-1.2.6.js"></script>
|
||||
|
||||
@@ -102,6 +100,7 @@
|
||||
<script>
|
||||
var serviceWorkerVersion = '1200232272';
|
||||
var scriptLoaded = false;
|
||||
|
||||
function loadMainDartJs() {
|
||||
if (scriptLoaded) {
|
||||
return;
|
||||
@@ -130,6 +129,7 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!reg.active && (reg.installing || reg.waiting)) {
|
||||
// No active web worker and we have installed or are installing
|
||||
// one for the first time. Simply wait for it to activate.
|
||||
|
||||
3
resources/web/js/dist/index.html
vendored
@@ -7,6 +7,9 @@
|
||||
<script src="ogvjs-1.8.6/ogv.js"></script>
|
||||
<script src="./yuv-canvas-1.2.6.js"></script>
|
||||
<title>Vite App</title>
|
||||
<script type="module" crossorigin src="/index.js"></script>
|
||||
<link rel="modulepreload" href="/vendor.js">
|
||||
<link rel="stylesheet" href="/index.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
4
resources/web/js/dist/index.js
vendored
797
resources/web/js/package-lock.json
generated
vendored
@@ -1,803 +1,8 @@
|
||||
{
|
||||
"name": "web_hbb",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "web_hbb",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"fast-sha256": "^1.3.0",
|
||||
"libsodium": "^0.7.9",
|
||||
"libsodium-wrappers": "^0.7.9",
|
||||
"pcm-player": "^0.0.11",
|
||||
"ts-proto": "^1.141.1",
|
||||
"wasm-feature-detect": "^1.2.11",
|
||||
"zstddec": "^0.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "4.4.4",
|
||||
"vite": "2.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz",
|
||||
"integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
|
||||
},
|
||||
"node_modules/@protobufjs/base64": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
||||
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
|
||||
},
|
||||
"node_modules/@protobufjs/codegen": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
|
||||
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
|
||||
},
|
||||
"node_modules/@protobufjs/eventemitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
|
||||
},
|
||||
"node_modules/@protobufjs/fetch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.1",
|
||||
"@protobufjs/inquire": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@protobufjs/float": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
|
||||
},
|
||||
"node_modules/@protobufjs/inquire": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
|
||||
},
|
||||
"node_modules/@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
|
||||
},
|
||||
"node_modules/@protobufjs/pool": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
|
||||
},
|
||||
"node_modules/@protobufjs/utf8": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
||||
},
|
||||
"node_modules/@types/long": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
|
||||
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz",
|
||||
"integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A=="
|
||||
},
|
||||
"node_modules/@types/object-hash": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-1.3.4.tgz",
|
||||
"integrity": "sha512-xFdpkAkikBgqBdG9vIlsqffDV8GpvnPEzs0IUtr1v3BEB97ijsFQ4RXVbUZwjFThhB4MDSTUfvmxUD5PGx0wXA=="
|
||||
},
|
||||
"node_modules/case-anything": {
|
||||
"version": "2.1.10",
|
||||
"resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz",
|
||||
"integrity": "sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ==",
|
||||
"engines": {
|
||||
"node": ">=12.13"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mesqueeb"
|
||||
}
|
||||
},
|
||||
"node_modules/dataloader": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz",
|
||||
"integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw=="
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
||||
"bin": {
|
||||
"detect-libc": "bin/detect-libc.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/dprint-node": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.7.tgz",
|
||||
"integrity": "sha512-NTZOW9A7ipb0n7z7nC3wftvsbceircwVHSgzobJsEQa+7RnOMbhrfX5IflA6CtC4GA63DSAiHYXa4JKEy9F7cA==",
|
||||
"dependencies": {
|
||||
"detect-libc": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz",
|
||||
"integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/linux-loong64": "0.14.54",
|
||||
"esbuild-android-64": "0.14.54",
|
||||
"esbuild-android-arm64": "0.14.54",
|
||||
"esbuild-darwin-64": "0.14.54",
|
||||
"esbuild-darwin-arm64": "0.14.54",
|
||||
"esbuild-freebsd-64": "0.14.54",
|
||||
"esbuild-freebsd-arm64": "0.14.54",
|
||||
"esbuild-linux-32": "0.14.54",
|
||||
"esbuild-linux-64": "0.14.54",
|
||||
"esbuild-linux-arm": "0.14.54",
|
||||
"esbuild-linux-arm64": "0.14.54",
|
||||
"esbuild-linux-mips64le": "0.14.54",
|
||||
"esbuild-linux-ppc64le": "0.14.54",
|
||||
"esbuild-linux-riscv64": "0.14.54",
|
||||
"esbuild-linux-s390x": "0.14.54",
|
||||
"esbuild-netbsd-64": "0.14.54",
|
||||
"esbuild-openbsd-64": "0.14.54",
|
||||
"esbuild-sunos-64": "0.14.54",
|
||||
"esbuild-windows-32": "0.14.54",
|
||||
"esbuild-windows-64": "0.14.54",
|
||||
"esbuild-windows-arm64": "0.14.54"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz",
|
||||
"integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-32": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz",
|
||||
"integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz",
|
||||
"integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz",
|
||||
"integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-mips64le": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz",
|
||||
"integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-ppc64le": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz",
|
||||
"integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-riscv64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz",
|
||||
"integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-s390x": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz",
|
||||
"integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-netbsd-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-openbsd-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz",
|
||||
"integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-sunos-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz",
|
||||
"integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-32": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz",
|
||||
"integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz",
|
||||
"integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-arm64": {
|
||||
"version": "0.14.54",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz",
|
||||
"integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-sha256": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz",
|
||||
"integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
|
||||
"integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has": "^1.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/libsodium": {
|
||||
"version": "0.7.10",
|
||||
"resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz",
|
||||
"integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ=="
|
||||
},
|
||||
"node_modules/libsodium-wrappers": {
|
||||
"version": "0.7.10",
|
||||
"resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz",
|
||||
"integrity": "sha512-pO3F1Q9NPLB/MWIhehim42b/Fwb30JNScCNh8TcQ/kIc+qGLQch8ag8wb0keK3EP5kbGakk1H8Wwo7v+36rNQg==",
|
||||
"dependencies": {
|
||||
"libsodium": "^0.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/object-hash": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz",
|
||||
"integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==",
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/pcm-player": {
|
||||
"version": "0.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pcm-player/-/pcm-player-0.0.11.tgz",
|
||||
"integrity": "sha512-+FmX62jiqZa7wDCqSRQ1g3DuU6JNgpymgOLCWhmiE/Lj/M+rOUNqgNwVQX509LdA9dtBtVD3EQQUSp9JqU6upw=="
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
|
||||
"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.4",
|
||||
"picocolors": "^1.0.0",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "6.11.3",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz",
|
||||
"integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
"@protobufjs/base64": "^1.1.2",
|
||||
"@protobufjs/codegen": "^2.0.4",
|
||||
"@protobufjs/eventemitter": "^1.1.0",
|
||||
"@protobufjs/fetch": "^1.1.0",
|
||||
"@protobufjs/float": "^1.0.2",
|
||||
"@protobufjs/inquire": "^1.1.0",
|
||||
"@protobufjs/path": "^1.1.2",
|
||||
"@protobufjs/pool": "^1.1.0",
|
||||
"@protobufjs/utf8": "^1.1.0",
|
||||
"@types/long": "^4.0.1",
|
||||
"@types/node": ">=13.7.0",
|
||||
"long": "^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"pbjs": "bin/pbjs",
|
||||
"pbts": "bin/pbts"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.9.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.77.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz",
|
||||
"integrity": "sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-poet": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.4.1.tgz",
|
||||
"integrity": "sha512-AjZEs4h2w4sDfwpHMxQKHrTlNh2wRbM5NRXmLz0RiH+yPGtSQFbe9hBpNocU8vqVNgfh0BIOiXR80xDz3kKxUQ==",
|
||||
"dependencies": {
|
||||
"dprint-node": "^1.0.7"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-proto": {
|
||||
"version": "1.141.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-1.141.1.tgz",
|
||||
"integrity": "sha512-1b7Ka6R96FvFZldHnYPTFy4rzwOo+OTpIP1mBFW0dDwq4WWtSkIVlZ+SokOQSC1TiccNshOJwQC9soVyWfQ7Zg==",
|
||||
"dependencies": {
|
||||
"@types/object-hash": "^1.3.0",
|
||||
"case-anything": "^2.1.10",
|
||||
"dataloader": "^1.4.0",
|
||||
"object-hash": "^1.3.1",
|
||||
"protobufjs": "^6.11.3",
|
||||
"ts-poet": "^6.2.0",
|
||||
"ts-proto-descriptors": "1.7.1"
|
||||
},
|
||||
"bin": {
|
||||
"protoc-gen-ts_proto": "protoc-gen-ts_proto"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-proto-descriptors": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-1.7.1.tgz",
|
||||
"integrity": "sha512-oIKUh3K4Xts4v29USGLfUG+2mEk32MsqpgZAOUyUlkrcIdv34yE+k2oZ2Nzngm6cV/JgFdOxRCqeyvmWHuYAyw==",
|
||||
"dependencies": {
|
||||
"long": "^4.0.0",
|
||||
"protobufjs": "^6.8.8"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
|
||||
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "2.8.6",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-2.8.6.tgz",
|
||||
"integrity": "sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.14.14",
|
||||
"postcss": "^8.4.6",
|
||||
"resolve": "^1.22.0",
|
||||
"rollup": "^2.59.0"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.2.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"less": "*",
|
||||
"sass": "*",
|
||||
"stylus": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/wasm-feature-detect": {
|
||||
"version": "1.2.11",
|
||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
||||
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
||||
},
|
||||
"node_modules/zstddec": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.0.2.tgz",
|
||||
"integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@esbuild/linux-loong64": {
|
||||
"version": "0.14.54",
|
||||
|
||||
2
resources/web/js/package.json
vendored
@@ -3,7 +3,7 @@
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "python ./gen_js_from_hbb.py > src/gen_js_from_hbb.ts && python ./ts_proto.py && tsc && yarn vite build",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
11
resources/web/js/src/connection.ts
vendored
@@ -14,7 +14,8 @@ const HOSTS = [
|
||||
"rs-us.rustdesk.com",
|
||||
];
|
||||
let HOST = localStorage.getItem("rendezvous-server") || HOSTS[0];
|
||||
const SCHEMA = "ws://";
|
||||
//根据协议设置为ws或wss
|
||||
const SCHEMA=location.protocol=="https:"?"wss://":"ws://";
|
||||
|
||||
type MsgboxCallback = (type: string, title: string, text: string) => void;
|
||||
type DrawCallback = (data: Uint8Array) => void;
|
||||
@@ -99,7 +100,7 @@ export default class Connection {
|
||||
ws.sendRendezvous({ punch_hole_request });
|
||||
const msg = (await ws.next()) as rendezvous.RendezvousMessage;
|
||||
ws.close();
|
||||
console.log(new Date() + ": Got relay response");
|
||||
console.log(new Date() + ": Got relay response", msg);
|
||||
const phr = msg.punch_hole_response;
|
||||
const rr = msg.relay_response;
|
||||
if (phr) {
|
||||
@@ -236,8 +237,14 @@ export default class Connection {
|
||||
async msgLoop() {
|
||||
while (true) {
|
||||
const msg = (await this._ws?.next()) as message.Message;
|
||||
// console.log("msg", msg);
|
||||
if (msg?.hash) {
|
||||
this._hash = msg?.hash;
|
||||
const tmp = this.getOption('tmppwd')
|
||||
if(!this._password && tmp){
|
||||
this._password = Uint8Array.from(JSON.parse("[" + tmp + "]"));
|
||||
this.setOption('tmppwd', '')
|
||||
}
|
||||
if (!this._password)
|
||||
this.msgbox("input-password", "Password Required", "");
|
||||
this.login();
|
||||
|
||||
29
resources/web/js/src/globals.js
vendored
@@ -1,11 +1,14 @@
|
||||
import Connection from "./connection";
|
||||
import _sodium from "libsodium-wrappers";
|
||||
import { CursorData } from "./message";
|
||||
import {loadVp9} from "./codec";
|
||||
import {checkIfRetry, version} from "./gen_js_from_hbb";
|
||||
import {initZstd, translate} from "./common";
|
||||
import PCMPlayer from "pcm-player";
|
||||
import {getServerConf} from "./ljw";
|
||||
|
||||
window.myconsole = (...args) => {
|
||||
console.log(args);
|
||||
}
|
||||
window.curConn = undefined;
|
||||
window.isMobile = () => {
|
||||
return /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
|
||||
@@ -126,6 +129,7 @@ export function newConn() {
|
||||
}
|
||||
|
||||
let sodium;
|
||||
|
||||
export async function verify(signed, pk) {
|
||||
if (!sodium) {
|
||||
await _sodium.ready;
|
||||
@@ -178,6 +182,7 @@ export function decrypt(signed, nonce, key) {
|
||||
}
|
||||
|
||||
window.setByName = (name, value) => {
|
||||
myconsole('setByName', name, value);
|
||||
switch (name) {
|
||||
case 'remote_id':
|
||||
localStorage.setItem('remote-id', value);
|
||||
@@ -256,6 +261,9 @@ window.setByName = (name, value) => {
|
||||
case 'option':
|
||||
value = JSON.parse(value);
|
||||
localStorage.setItem(value.name, value.value);
|
||||
if (value.name === 'access_token' && value.value) {
|
||||
getServerConf(value.value);
|
||||
}
|
||||
break;
|
||||
case 'peer_option':
|
||||
value = JSON.parse(value);
|
||||
@@ -271,6 +279,7 @@ window.setByName = (name, value) => {
|
||||
|
||||
window.getByName = (name, arg) => {
|
||||
let v = _getByName(name, arg);
|
||||
myconsole('getByName', name, arg, v);
|
||||
if (typeof v == 'string' || v instanceof String) return v;
|
||||
if (v == undefined || v == null) return '';
|
||||
return JSON.stringify(v);
|
||||
@@ -299,7 +308,11 @@ function _getByName(name, arg) {
|
||||
case 'toggle_option':
|
||||
return curConn.getOption(arg) || false;
|
||||
case 'option':
|
||||
return localStorage.getItem(arg);
|
||||
const v = localStorage.getItem(arg);
|
||||
if (arg === 'access_token' && v) {
|
||||
getServerConf(v);
|
||||
}
|
||||
return v;
|
||||
case 'image_quality':
|
||||
return curConn.getImageQuality();
|
||||
case 'translate':
|
||||
@@ -336,7 +349,8 @@ window.init = async () => {
|
||||
opusWorker.onmessage = (e) => {
|
||||
pcmPlayer.feed(e.data);
|
||||
}
|
||||
loadVp9(() => { });
|
||||
loadVp9(() => {
|
||||
});
|
||||
await initZstd();
|
||||
console.log('init done');
|
||||
}
|
||||
@@ -362,8 +376,7 @@ export function copyToClipboard(text) {
|
||||
// Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
|
||||
return window.clipboardData.setData("Text", text);
|
||||
|
||||
}
|
||||
else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
|
||||
} else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
|
||||
var textarea = document.createElement("textarea");
|
||||
textarea.textContent = text;
|
||||
textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in Microsoft Edge.
|
||||
@@ -371,12 +384,10 @@ export function copyToClipboard(text) {
|
||||
textarea.select();
|
||||
try {
|
||||
return document.execCommand("copy"); // Security exception may be thrown by some browsers.
|
||||
}
|
||||
catch (ex) {
|
||||
} catch (ex) {
|
||||
console.warn("Copy to clipboard failed.", ex);
|
||||
// return prompt("Copy to clipboard: Ctrl+C, Enter", text);
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
}
|
||||
|
||||
99
resources/web/js/src/ljw.js
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
window._gwen = {}
|
||||
window._gwen.kv = {}
|
||||
const apiserver = localStorage.getItem('api-server')
|
||||
|
||||
function stringToUint8Array(str) {
|
||||
var arr = [];
|
||||
for (var i = 0, j = str.length; i < j; ++i) {
|
||||
arr.push(str.charCodeAt(i));
|
||||
}
|
||||
|
||||
var tmpUint8Array = new Uint8Array(arr);
|
||||
return tmpUint8Array
|
||||
}
|
||||
|
||||
function getQueryVariable() {
|
||||
const query = window.location.hash.substring(3);
|
||||
const vars = query.split("&");
|
||||
for (var i = 0; i < vars.length; i++) {
|
||||
var pair = vars[i].split("=");
|
||||
window._gwen.kv[pair[0]] = pair[1]
|
||||
}
|
||||
}
|
||||
|
||||
getQueryVariable()
|
||||
|
||||
const id = window._gwen.kv.id || ''
|
||||
if (id) {
|
||||
localStorage.setItem('remote-id', id)
|
||||
}
|
||||
const share_token = window._gwen.kv.share_token || ''
|
||||
if (share_token) {
|
||||
fetch(apiserver + "/api/shared-peer", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({share_token})
|
||||
}).then(res => res.json()).then(res => {
|
||||
if (res.code === 0) {
|
||||
localStorage.setItem('custom-rendezvous-server', res.data.id_server)
|
||||
localStorage.setItem('key', res.data.key)
|
||||
const peer = res.data.peer
|
||||
localStorage.setItem('remote-id', peer.info.id)
|
||||
peer.tmppwd = stringToUint8Array(window.atob(peer.tmppwd)).toString()
|
||||
const oldPeers = JSON.parse(localStorage.getItem('peers')) || {}
|
||||
oldPeers[peer.info.id] = peer
|
||||
localStorage.setItem('peers', JSON.stringify(oldPeers))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let fetching = false
|
||||
export function getServerConf(token){
|
||||
console.log('getServerConf', token)
|
||||
if(fetching){
|
||||
return
|
||||
}
|
||||
fetching = true
|
||||
fetch(apiserver + "/api/server-config", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token
|
||||
}
|
||||
}
|
||||
).then(res => res.json()).then(res => {
|
||||
fetching = false
|
||||
if (res.code === 0) {
|
||||
if (!localStorage.getItem('custom-rendezvous-server') || !localStorage.getItem('key')) {
|
||||
localStorage.setItem('custom-rendezvous-server', res.data.id_server)
|
||||
localStorage.setItem('key', res.data.key)
|
||||
}
|
||||
if (res.data.peers) {
|
||||
const oldPeers = JSON.parse(localStorage.getItem('peers')) || {}
|
||||
let needUpdate = false
|
||||
Object.keys(res.data.peers).forEach(k => {
|
||||
if (!oldPeers[k]) {
|
||||
oldPeers[k] = res.data.peers[k]
|
||||
needUpdate = true
|
||||
} else {
|
||||
oldPeers[k].info = res.data.peers[k].info
|
||||
}
|
||||
if (oldPeers[k].info && oldPeers[k].info.hash && !oldPeers[k].password) {
|
||||
let p1 = window.atob(oldPeers[k].info.hash)
|
||||
const pwd = stringToUint8Array(p1)
|
||||
oldPeers[k].password = pwd.toString()
|
||||
oldPeers[k].remember = true
|
||||
}
|
||||
})
|
||||
localStorage.setItem('peers', JSON.stringify(oldPeers))
|
||||
if (needUpdate) {
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
}).catch(_ => {
|
||||
fetching = false
|
||||
})
|
||||
}
|
||||
1
resources/web/js/src/main.ts
vendored
@@ -1,2 +1,3 @@
|
||||
import "./ljw";
|
||||
import "./globals";
|
||||
import "./ui";
|
||||
@@ -3,17 +3,25 @@ package service
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AddressBookService struct {
|
||||
}
|
||||
|
||||
func (s *AddressBookService) Info(id uint) *model.AddressBook {
|
||||
func (s *AddressBookService) Info(id string) *model.AddressBook {
|
||||
p := &model.AddressBook{}
|
||||
global.DB.Where("id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (s *AddressBookService) InfoByUserIdAndId(userid uint, id string) *model.AddressBook {
|
||||
p := &model.AddressBook{}
|
||||
global.DB.Where("user_id = ? and id = ?", userid, id).First(p)
|
||||
return p
|
||||
}
|
||||
func (s *AddressBookService) InfoByRowId(id uint) *model.AddressBook {
|
||||
p := &model.AddressBook{}
|
||||
global.DB.Where("row_id = ?", id).First(p)
|
||||
@@ -62,6 +70,14 @@ func (s *AddressBookService) UpdateAddressBook(abs []*model.AddressBook, userId
|
||||
ab.UserId = userId
|
||||
if !ok {
|
||||
//添加
|
||||
if ab.Platform == "" || ab.Username == "" || ab.Hostname == "" {
|
||||
peer := AllService.PeerService.FindById(ab.Id)
|
||||
if peer.RowId != 0 {
|
||||
ab.Platform = AllService.AddressBookService.PlatformFromOs(peer.Os)
|
||||
ab.Username = peer.Username
|
||||
ab.Hostname = peer.Hostname
|
||||
}
|
||||
}
|
||||
tx.Create(ab)
|
||||
} else {
|
||||
//更新
|
||||
@@ -107,3 +123,33 @@ func (t *AddressBookService) Delete(u *model.AddressBook) error {
|
||||
func (t *AddressBookService) Update(u *model.AddressBook) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
// ShareByWebClient 分享
|
||||
func (t *AddressBookService) ShareByWebClient(m *model.ShareRecord) error {
|
||||
m.ShareToken = uuid.New().String()
|
||||
return global.DB.Create(m).Error
|
||||
}
|
||||
|
||||
// SharedPeer
|
||||
func (t *AddressBookService) SharedPeer(shareToken string) *model.ShareRecord {
|
||||
m := &model.ShareRecord{}
|
||||
global.DB.Where("share_token = ?", shareToken).First(m)
|
||||
return m
|
||||
}
|
||||
|
||||
// PlatformFromOs
|
||||
func (t *AddressBookService) PlatformFromOs(os string) string {
|
||||
if strings.Contains(os, "Android") || strings.Contains(os, "android") {
|
||||
return "Android"
|
||||
}
|
||||
if strings.Contains(os, "Windows") || strings.Contains(os, "windows") {
|
||||
return "Windows"
|
||||
}
|
||||
if strings.Contains(os, "Linux") || strings.Contains(os, "linux") {
|
||||
return "Linux"
|
||||
}
|
||||
if strings.Contains(os, "mac") || strings.Contains(os, "Mac") {
|
||||
return "Mac OS"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ func (os *OauthService) BeginAuth(op string) (error error, code, url string) {
|
||||
return err, code, conf.AuthCodeURL(code)
|
||||
}
|
||||
|
||||
return errors.New("op错误"), code, ""
|
||||
return err, code, ""
|
||||
}
|
||||
|
||||
// GetOauthConfig 获取配置
|
||||
@@ -141,7 +141,7 @@ func (os *OauthService) GetOauthConfig(op string) (error, *oauth2.Config) {
|
||||
if op == model.OauthTypeGithub {
|
||||
g := os.InfoByOp(model.OauthTypeGithub)
|
||||
if g.Id == 0 || g.ClientId == "" || g.ClientSecret == "" || g.RedirectUrl == "" {
|
||||
return errors.New("配置不存在"), nil
|
||||
return errors.New("ConfigNotFound"), nil
|
||||
}
|
||||
return nil, &oauth2.Config{
|
||||
ClientID: g.ClientId,
|
||||
@@ -154,7 +154,7 @@ func (os *OauthService) GetOauthConfig(op string) (error, *oauth2.Config) {
|
||||
if op == model.OauthTypeGoogle {
|
||||
g := os.InfoByOp(model.OauthTypeGoogle)
|
||||
if g.Id == 0 || g.ClientId == "" || g.ClientSecret == "" || g.RedirectUrl == "" {
|
||||
return errors.New("配置不存在"), nil
|
||||
return errors.New("ConfigNotFound"), nil
|
||||
}
|
||||
return nil, &oauth2.Config{
|
||||
ClientID: g.ClientId,
|
||||
@@ -164,7 +164,7 @@ func (os *OauthService) GetOauthConfig(op string) (error, *oauth2.Config) {
|
||||
Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"},
|
||||
}
|
||||
}
|
||||
return errors.New("op错误"), nil
|
||||
return errors.New("ConfigNotFound"), nil
|
||||
}
|
||||
|
||||
func (os *OauthService) GithubCallback(code string) (error error, userData *GithubUserdata) {
|
||||
@@ -175,7 +175,7 @@ func (os *OauthService) GithubCallback(code string) (error error, userData *Gith
|
||||
token, err := oauthConfig.Exchange(context.Background(), code)
|
||||
if err != nil {
|
||||
global.Logger.Warn(fmt.Printf("oauthConfig.Exchange() failed: %s\n", err))
|
||||
error = errors.New("获取token失败")
|
||||
error = errors.New("GetOauthTokenError")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ func (os *OauthService) GithubCallback(code string) (error error, userData *Gith
|
||||
resp, err := client.Get("https://api.github.com/user")
|
||||
if err != nil {
|
||||
global.Logger.Warn("failed getting user info: %s\n", err)
|
||||
error = errors.New("获取user info失败")
|
||||
error = errors.New("GetOauthUserInfoError")
|
||||
return
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
@@ -197,7 +197,7 @@ func (os *OauthService) GithubCallback(code string) (error error, userData *Gith
|
||||
// 在这里处理 GitHub 用户信息
|
||||
if err = json.NewDecoder(resp.Body).Decode(&userData); err != nil {
|
||||
global.Logger.Warn("failed decoding user info: %s\n", err)
|
||||
error = errors.New("解析user info失败")
|
||||
error = errors.New("DecodeOauthUserInfoError")
|
||||
return
|
||||
}
|
||||
return
|
||||
@@ -208,7 +208,7 @@ func (os *OauthService) GoogleCallback(code string) (error error, userData *Goog
|
||||
token, err := oauthConfig.Exchange(context.Background(), code)
|
||||
if err != nil {
|
||||
global.Logger.Warn(fmt.Printf("oauthConfig.Exchange() failed: %s\n", err))
|
||||
error = errors.New("获取token失败")
|
||||
error = errors.New("GetOauthTokenError")
|
||||
return
|
||||
}
|
||||
// 创建 HTTP 客户端,并将 access_token 添加到 Authorization 头中
|
||||
@@ -216,7 +216,7 @@ func (os *OauthService) GoogleCallback(code string) (error error, userData *Goog
|
||||
resp, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo")
|
||||
if err != nil {
|
||||
global.Logger.Warn("failed getting user info: %s\n", err)
|
||||
error = errors.New("获取user info失败: " + err.Error())
|
||||
error = errors.New("GetOauthUserInfoError")
|
||||
return
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
@@ -228,7 +228,7 @@ func (os *OauthService) GoogleCallback(code string) (error error, userData *Goog
|
||||
|
||||
if err = json.NewDecoder(resp.Body).Decode(&userData); err != nil {
|
||||
global.Logger.Warn("failed decoding user info: %s\n", err)
|
||||
error = errors.New("解析user info失败:" + err.Error())
|
||||
error = errors.New("DecodeOauthUserInfoError")
|
||||
return
|
||||
}
|
||||
return
|
||||
@@ -258,7 +258,13 @@ func (os *OauthService) BindOauthUser(thirdType, openid, username string, userId
|
||||
}
|
||||
|
||||
func (os *OauthService) UnBindGithubUser(userid uint) error {
|
||||
return global.DB.Where("user_id = ? and third_type = ?", userid, model.OauthTypeGithub).Delete(&model.UserThird{}).Error
|
||||
return os.UnBindThird(model.OauthTypeGithub, userid)
|
||||
}
|
||||
func (os *OauthService) UnBindGoogleUser(userid uint) error {
|
||||
return os.UnBindThird(model.OauthTypeGoogle, userid)
|
||||
}
|
||||
func (os *OauthService) UnBindThird(thirdType string, userid uint) error {
|
||||
return global.DB.Where("user_id = ? and third_type = ?", userid, thirdType).Delete(&model.UserThird{}).Error
|
||||
}
|
||||
|
||||
// InfoById 根据id取用户信息
|
||||
|
||||
@@ -15,24 +15,38 @@ func (ps *PeerService) FindById(id string) *model.Peer {
|
||||
global.DB.Where("id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
func (ps *PeerService) FindByUuid(uuid string) *model.Peer {
|
||||
p := &model.Peer{}
|
||||
global.DB.Where("uuid = ?", uuid).First(p)
|
||||
return p
|
||||
}
|
||||
func (ps *PeerService) InfoByRowId(id uint) *model.Peer {
|
||||
p := &model.Peer{}
|
||||
global.DB.Where("row_id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
|
||||
//// ListByUserIds 根据用户id取列表
|
||||
//func (ps *PeerService) ListByUserIds(userIds []uint, page, pageSize uint) (res *model.PeerList) {
|
||||
// res = &model.PeerList{}
|
||||
// res.Page = int64(page)
|
||||
// res.PageSize = int64(pageSize)
|
||||
// tx := global.DB.Model(&model.Peer{}).Preload("User")
|
||||
// tx.Where("user_id in (?)", userIds)
|
||||
// tx.Count(&res.Total)
|
||||
// tx.Scopes(Paginate(page, pageSize))
|
||||
// tx.Find(&res.Peers)
|
||||
// return
|
||||
//}
|
||||
// UuidBindUserId 绑定用户id
|
||||
func (ps *PeerService) UuidBindUserId(uuid string, userId uint) {
|
||||
peer := ps.FindByUuid(uuid)
|
||||
if peer.RowId > 0 {
|
||||
peer.UserId = userId
|
||||
ps.Update(peer)
|
||||
}
|
||||
}
|
||||
|
||||
// ListByUserIds 根据用户id取列表
|
||||
func (ps *PeerService) ListByUserIds(userIds []uint, page, pageSize uint) (res *model.PeerList) {
|
||||
res = &model.PeerList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.Peer{})
|
||||
tx.Where("user_id in (?)", userIds)
|
||||
tx.Count(&res.Total)
|
||||
tx.Scopes(Paginate(page, pageSize))
|
||||
tx.Find(&res.Peers)
|
||||
return
|
||||
}
|
||||
|
||||
func (ps *PeerService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *model.PeerList) {
|
||||
res = &model.PeerList{}
|
||||
@@ -57,6 +71,11 @@ func (ps *PeerService) Delete(u *model.Peer) error {
|
||||
return global.DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// BatchDelete
|
||||
func (ps *PeerService) BatchDelete(ids []uint) error {
|
||||
return global.DB.Where("row_id in (?)", ids).Delete(&model.Peer{}).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (ps *PeerService) Update(u *model.Peer) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
|
||||
@@ -14,6 +14,11 @@ func (s *TagService) Info(id uint) *model.Tag {
|
||||
global.DB.Where("id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
func (s *TagService) InfoByUserIdAndName(userid uint, name string) *model.Tag {
|
||||
p := &model.Tag{}
|
||||
global.DB.Where("user_id = ? and name = ?", userid, name).First(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (s *TagService) ListByUserId(userId uint) (res *model.TagList) {
|
||||
res = s.List(1, 1000, func(tx *gorm.DB) {
|
||||
|
||||
@@ -66,6 +66,9 @@ func (us *UserService) Login(u *model.User, llog *model.LoginLog) *model.UserTok
|
||||
}
|
||||
global.DB.Create(ut)
|
||||
global.DB.Create(llog)
|
||||
if llog.Uuid != "" {
|
||||
AllService.PeerService.UuidBindUserId(llog.Uuid, u.Id)
|
||||
}
|
||||
return ut
|
||||
}
|
||||
|
||||
@@ -259,3 +262,10 @@ func (us *UserService) UserThirdInfo(userId uint, op string) *model.UserThird {
|
||||
global.DB.Where("user_id = ? and third_type = ?", userId, op).First(ut)
|
||||
return ut
|
||||
}
|
||||
|
||||
// FindLatestUserIdFromLoginLogByUuid 根据uuid查找最后登录的用户id
|
||||
func (us *UserService) FindLatestUserIdFromLoginLogByUuid(uuid string) uint {
|
||||
llog := &model.LoginLog{}
|
||||
global.DB.Where("uuid = ?", uuid).Order("id desc").First(llog)
|
||||
return llog.UserId
|
||||
}
|
||||
|
||||