Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f64022e411 | ||
|
|
2d37302cf9 | ||
|
|
1a1856257d | ||
|
|
24f570b64f | ||
|
|
6322177b71 | ||
|
|
d2390d1cb3 | ||
|
|
6fe6f6b708 | ||
|
|
a656f4fec3 | ||
|
|
399c32da7d | ||
|
|
62167836dc | ||
|
|
caef3897a0 | ||
|
|
5ef6810e3f | ||
|
|
ae2079f583 | ||
|
|
aa65382a0f | ||
|
|
18c61a2bfc | ||
|
|
7cc1a8a58a | ||
|
|
cf9feac702 | ||
|
|
a963cd0209 | ||
|
|
6a5408f9b8 | ||
|
|
9aad62d1e4 | ||
|
|
867eab40f8 | ||
|
|
eb5c7efc4c | ||
|
|
857abc16e7 | ||
|
|
a27deb0a41 |
128
.github/workflows/build.yml
vendored
128
.github/workflows/build.yml
vendored
@@ -2,6 +2,31 @@ 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)时触发工作流
|
||||
@@ -9,6 +34,12 @@ on:
|
||||
|
||||
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
|
||||
@@ -38,7 +69,7 @@ jobs:
|
||||
|
||||
- name: build rustdesk-api-web
|
||||
run: |
|
||||
git clone https://github.com/lejianwen/rustdesk-api-web
|
||||
git clone ${{ env.WEBCLIENT_SOURCE_LOCATION }}
|
||||
cd rustdesk-api-web
|
||||
npm install
|
||||
npm run build
|
||||
@@ -86,13 +117,13 @@ jobs:
|
||||
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 }}
|
||||
|
||||
@@ -117,20 +148,34 @@ jobs:
|
||||
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: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||
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: lejianwen/rustdesk-api
|
||||
images: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api
|
||||
|
||||
- name: Download binaries
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -144,7 +189,8 @@ jobs:
|
||||
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 ${{ matrix.job.platform }}
|
||||
- name: Build and push Docker image to Docker Hub ${{ matrix.job.platform }}
|
||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only run this step if SKIP_DOCKER_HUB is false
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: "."
|
||||
@@ -155,8 +201,24 @@ jobs:
|
||||
build-args: |
|
||||
BUILDARCH=${{ matrix.job.platform }}
|
||||
tags: |
|
||||
lejianwen/rustdesk-api:${{ env.LATEST_TAG }}-${{ matrix.job.platform }}
|
||||
lejianwen/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
||||
${{ 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 }}
|
||||
|
||||
#
|
||||
@@ -167,24 +229,62 @@ jobs:
|
||||
steps:
|
||||
- name: Extract version from tag
|
||||
id: vars
|
||||
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||
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: Create and push manifest (:version)
|
||||
- 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: lejianwen/rustdesk-api:${{ env.TAG }}
|
||||
extra-images: lejianwen/rustdesk-api:${{ env.TAG }}-amd64,lejianwen/rustdesk-api:${{ env.TAG }}-arm64
|
||||
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 (:latest)
|
||||
- name: Create and push manifest GHCR (:version)
|
||||
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
base-image: lejianwen/rustdesk-api:latest
|
||||
extra-images: lejianwen/rustdesk-api:latest-amd64,lejianwen/rustdesk-api:latest-arm64
|
||||
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
|
||||
439
README.md
439
README.md
@@ -30,33 +30,62 @@
|
||||
- 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+*** 都可以
|
||||
|
||||
```bash
|
||||
hbbs -r <relay-server-ip[:port]> -k <key>
|
||||
hbbr -k <key>
|
||||
```
|
||||
#### 关于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`编译,链接加密,直接下载使用
|
||||
- 缺点:可能跟不上官方版本更新
|
||||
|
||||
```bash
|
||||
hbbs -r <relay-server-ip[:port]> -k abc1234567
|
||||
hbbr -k abc1234567
|
||||
```
|
||||
***对链接加密要求不高的可以使用`1`,对链接加密要求高的可以使用`3`或`4`***
|
||||
|
||||
## 功能
|
||||
|
||||
### API 服务: 基本实现了PC端基础的接口。支持Personal版本接口,可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
|
||||
### API 服务
|
||||
基本实现了PC端基础的接口。支持Personal版本接口,可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
|
||||
|
||||
#### 登录
|
||||
|
||||
@@ -69,26 +98,27 @@
|
||||
|
||||

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

|
||||
|
||||
### 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. 可以直接打开webclient,方便使用
|
||||
4. 可以直接打开webclient,方便使用;也可以分享给游客,游客可以直接通过webclient远程到设备
|
||||

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

|
||||
@@ -121,6 +151,8 @@
|
||||
|
||||
```yaml
|
||||
lang: "en"
|
||||
app:
|
||||
web-client: 1 # 1:启用 0:禁用
|
||||
gin:
|
||||
api-addr: "0.0.0.0:21114"
|
||||
mode: "release"
|
||||
@@ -141,54 +173,59 @@ rustdesk:
|
||||
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` |
|
||||
| -----GIN配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
||||
| -----------GORM配置------------------ | ------------------------------------ | --------------------------- |
|
||||
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
||||
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
||||
| -----MYSQL配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
||||
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
||||
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
||||
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
||||
| -----RUSTDESK配置----- | --------------- | ---------- |
|
||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
|
||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
||||
| 变量名 | 说明 | 示例 |
|
||||
|------------------------------------|--------------------------------------|-----------------------------|
|
||||
| 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配置---------------- | ------------------------------------ | --------------------------- |
|
||||
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
||||
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
||||
| -----MYSQL配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
||||
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
||||
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
||||
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
||||
| -----RUSTDESK配置----- | --------------- | ---------- |
|
||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
|
||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
||||
|
||||
### 安装步骤
|
||||
### 运行
|
||||
|
||||
#### docker运行
|
||||
|
||||
1. 直接docker运行,配置可以通过挂载配置文件`/app/conf/config.yaml`来修改,或者通过环境变量覆盖配置文件中的配置
|
||||
|
||||
```bash
|
||||
docker run -d --name rustdesk-api -p 21114:21114 \
|
||||
-v /data/rustdesk/api:/app/data \
|
||||
-e TZ=Asia/Shanghai \
|
||||
-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 \
|
||||
lejianwen/rustdesk-api
|
||||
```
|
||||
```bash
|
||||
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=<key> \
|
||||
lejianwen/rustdesk-api
|
||||
```
|
||||
|
||||
2. 使用`docker compose`
|
||||
|
||||
- 简单示例
|
||||
|
||||
```docker-compose
|
||||
- 简单示例
|
||||
```yaml
|
||||
services:
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
@@ -197,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
|
||||
@@ -208,73 +245,70 @@ lejianwen/rustdesk-api
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
- 根据rustdesk提供的示例加上自己的rustdesk-api
|
||||
|
||||
```docker-compose
|
||||
networks:
|
||||
rustdesk-net:
|
||||
external: false
|
||||
services:
|
||||
hbbs:
|
||||
container_name: hbbs
|
||||
ports:
|
||||
- 21115:21115
|
||||
- 21116:21116 # 自定义 hbbs 映射端口
|
||||
- 21116:21116/udp # 自定义 hbbs 映射端口
|
||||
- 21118:21118 # web client 需要
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbs -r <relay-server-ip[:port]> -k 123456789 # 填入个人域名或 IP + hbbr 暴露端口
|
||||
volumes:
|
||||
- /data/rustdesk/hbbs:/root # 自定义挂载目录
|
||||
networks:
|
||||
- rustdesk-net
|
||||
depends_on:
|
||||
- hbbr
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 64M
|
||||
hbbr:
|
||||
container_name: hbbr
|
||||
ports:
|
||||
- 21117:21117 # 自定义 hbbr 映射端口
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbr -k 123456789
|
||||
#command: hbbr
|
||||
volumes:
|
||||
- /data/rustdesk/hbbr:/root # 自定义挂载目录
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 64M
|
||||
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
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data #将数据库挂载出来方便备份
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
|
||||
```
|
||||
|
||||
- 如果使用的是S6的镜像,会需要修改启动脚本,覆盖镜像中的`/etc/s6-overlay/s6-rc.d/hbbr/run`
|
||||
和`/etc/s6-overlay/s6-rc.d/hbbr/run`
|
||||
|
||||
1. 创建`hbbr/run`
|
||||
- 根据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
|
||||
services:
|
||||
hbbs:
|
||||
container_name: hbbs
|
||||
ports:
|
||||
- 21115:21115
|
||||
- 21116:21116 # 自定义 hbbs 映射端口
|
||||
- 21116:21116/udp # 自定义 hbbs 映射端口
|
||||
- 21118:21118 # web client
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbs -r <relay-server-ip[:port]> -k <key> # 填入个人域名或 IP + hbbr 暴露端口
|
||||
volumes:
|
||||
- ./data:/root # 自定义挂载目录
|
||||
networks:
|
||||
- rustdesk-net
|
||||
depends_on:
|
||||
- hbbr
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 64M
|
||||
hbbr:
|
||||
container_name: hbbr
|
||||
ports:
|
||||
- 21117:21117 # 自定义 hbbr 映射端口
|
||||
- 21119:21119 # web client
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbr -k <key>
|
||||
volumes:
|
||||
- ./data:/root
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 64M
|
||||
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=<key>
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data #将数据库挂载出来方便备份
|
||||
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
|
||||
@@ -282,63 +316,99 @@ lejianwen/rustdesk-api
|
||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
||||
/usr/bin/hbbr $PARAMS
|
||||
```
|
||||
|
||||
2. 创建`hbbs/run`
|
||||
```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`部分
|
||||
|
||||
```
|
||||
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=abc123456789
|
||||
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=abc123456789
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data #将数据库挂载
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
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)
|
||||
|
||||
#### 源码安装
|
||||
|
||||
@@ -378,7 +448,22 @@ lejianwen/rustdesk-api
|
||||
|
||||
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)
|
||||
480
README_EN.md
480
README_EN.md
@@ -29,34 +29,64 @@ desktop software that provides self-hosted solutions.
|
||||
- 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.
|
||||
|
||||
```bash
|
||||
hbbs -r <relay-server-ip[:port]> -k <key>
|
||||
hbbr -k <key>
|
||||
```
|
||||
#### The PC client uses version ***1.3.0***, and versions ***1.2.6+*** have been tested to work.
|
||||
|
||||
Example:
|
||||
#### 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);
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
hbbs -r <relay-server-ip[:port]> -k abc1234567
|
||||
hbbr -k abc1234567
|
||||
```
|
||||
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>
|
||||
```
|
||||
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
|
||||
|
||||
***If encryption is not a high priority, use `1`. If encryption is important, use `3` or `4`.***
|
||||
|
||||
## Overview
|
||||
|
||||
### API Service: Basic implementation of the PC client's primary interfaces.Supports the Personal version api, which can be enabled by configuring the `rustdesk.personal` file or the `RUSTDESK_API_RUSTDESK_PERSONAL` environment variable.
|
||||
### API 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
|
||||
|
||||
@@ -70,17 +100,18 @@ desktop software that provides self-hosted solutions.
|
||||
|
||||

|
||||
|
||||
#### 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.
|
||||
#### 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 Admin
|
||||
|
||||
***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)***
|
||||
* 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:
|
||||

|
||||
@@ -90,7 +121,7 @@ installation are `admin` `admin`, please change the password immediately.***
|
||||

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

|
||||
4. You can open the web client directly for convenience:
|
||||
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
|
||||
@@ -126,6 +157,8 @@ installation are `admin` `admin`, please change the password immediately.***
|
||||
|
||||
```yaml
|
||||
lang: "en"
|
||||
app:
|
||||
web-client: 1 # web client route 1:open 0:close
|
||||
gin:
|
||||
api-addr: "0.0.0.0:21114"
|
||||
mode: "release"
|
||||
@@ -146,33 +179,37 @@ rustdesk:
|
||||
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_RUSTDESK_PERSONAL`, 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 |
|
||||
|------------------------------------|-----------------------------------------------------------|--------------------------------|
|
||||
| TZ | timezone | Asia/Shanghai |
|
||||
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
||||
| ----- GIN Configuration ----- | --------------------------------------- | ------------------------------ |
|
||||
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
||||
| ----- GORM Configuration ----- | --------------------------------------- | ------------------------------ |
|
||||
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
||||
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
||||
| ----- MYSQL Configuration ----- | --------------------------------------- | ------------------------------ |
|
||||
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
||||
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
||||
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
||||
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
||||
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ------------------------------ |
|
||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
|
||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
||||
| Variable Name | Description | Example |
|
||||
|------------------------------------|-----------------------------------------------------------|-------------------------------|
|
||||
| TZ | timezone | Asia/Shanghai |
|
||||
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
||||
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, 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 ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
||||
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
||||
| ----- MYSQL Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
||||
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
||||
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
||||
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
||||
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
|
||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
||||
|
||||
### Installation Steps
|
||||
|
||||
@@ -181,164 +218,200 @@ rustdesk:
|
||||
1. Run directly with Docker. Configuration can be modified by mounting the config file `/app/conf/config.yaml`, or by
|
||||
using environment variables to override settings.
|
||||
|
||||
```bash
|
||||
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 \
|
||||
lejianwen/rustdesk-api
|
||||
```
|
||||
```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=abc123456 \
|
||||
lejianwen/rustdesk-api
|
||||
```
|
||||
|
||||
2. Using `docker-compose`
|
||||
|
||||
- Simple example:
|
||||
|
||||
```docker-compose
|
||||
services:
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
environment:
|
||||
- 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
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data # Mount the database for easy backup
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
```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=<key>
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data # Mount the database for easy backup
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
- Example with RustDesk's official Docker Compose file, adding your `rustdesk-api` service:
|
||||
- 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
|
||||
services:
|
||||
hbbs:
|
||||
container_name: hbbs
|
||||
ports:
|
||||
- 21115:21115
|
||||
- 21116:21116 # 自定义 hbbs 映射端口
|
||||
- 21116:21116/udp # 自定义 hbbs 映射端口
|
||||
- 21118:21118 # web client
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbs -r <relay-server-ip[:port]> -k <key> # 填入个人域名或 IP + hbbr 暴露端口
|
||||
volumes:
|
||||
- ./data:/root # 自定义挂载目录
|
||||
networks:
|
||||
- rustdesk-net
|
||||
depends_on:
|
||||
- hbbr
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 64M
|
||||
hbbr:
|
||||
container_name: hbbr
|
||||
ports:
|
||||
- 21117:21117 # 自定义 hbbr 映射端口
|
||||
- 21119:21119 # web client
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbr -k <key>
|
||||
volumes:
|
||||
- ./data:/root
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 64M
|
||||
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=<key>
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data #将数据库挂载出来方便备份
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
```docker-compose
|
||||
networks:
|
||||
rustdesk-net:
|
||||
external: false
|
||||
services:
|
||||
hbbs:
|
||||
container_name: hbbs
|
||||
ports:
|
||||
- 21115:21115
|
||||
- 21116:21116 # 自定义 hbbs 映射端口
|
||||
- 21116:21116/udp # 自定义 hbbs 映射端口
|
||||
- 21118:21118 # web client 需要
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbs -r <relay-server-ip[:port]> -k 123456789 # 填入个人域名或 IP + hbbr 暴露端口
|
||||
volumes:
|
||||
- /data/rustdesk/hbbs:/root # 自定义挂载目录
|
||||
- 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
|
||||
depends_on:
|
||||
- hbbr
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 64M
|
||||
hbbr:
|
||||
container_name: hbbr
|
||||
ports:
|
||||
- 21117:21117 # 自定义 hbbr 映射端口
|
||||
image: rustdesk/rustdesk-server
|
||||
command: hbbr -k 123456789
|
||||
#command: hbbr
|
||||
volumes:
|
||||
- /data/rustdesk/hbbr:/root # 自定义挂载目录
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 64M
|
||||
rustdesk-api:
|
||||
container_name: rustdesk-api
|
||||
environment:
|
||||
- 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
|
||||
ports:
|
||||
- 21114:21114
|
||||
image: lejianwen/rustdesk-api
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data #将数据库挂载出来方便备份
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
|
||||
```
|
||||
- If you are using an S6 image, you need to modify the startup script `/etc/s6-overlay/s6-rc.d/hbbr/run`
|
||||
and `/etc/s6-overlay/s6-rc.d/hbbr/run`
|
||||
|
||||
1. create `hbbr/run`
|
||||
|
||||
```bash
|
||||
#!/command/with-contenv sh
|
||||
cd /data
|
||||
PARAMS=
|
||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
||||
/usr/bin/hbbr $PARAMS
|
||||
```
|
||||
|
||||
2. create `hbbs/run`
|
||||
```bash
|
||||
#!/command/with-contenv sh
|
||||
sleep 2
|
||||
cd /data
|
||||
PARAMS=
|
||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
||||
/usr/bin/hbbs -r $RELAY $PARAMS
|
||||
```
|
||||
3. edit `docker-compose.yml`
|
||||
```
|
||||
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=abc123456789
|
||||
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=abc123456789
|
||||
volumes:
|
||||
- /data/rustdesk/api:/app/data #将数据库挂载
|
||||
networks:
|
||||
- rustdesk-net
|
||||
restart: unless-stopped
|
||||
```
|
||||
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
|
||||
|
||||
@@ -387,7 +460,22 @@ Download the release from [release](https://github.com/lejianwen/rustdesk-api/re
|
||||
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)
|
||||
@@ -200,7 +200,7 @@ func getTranslatorForLang(lang string) ut.Translator {
|
||||
}
|
||||
}
|
||||
func DatabaseAutoUpdate() {
|
||||
version := 212
|
||||
version := 233
|
||||
|
||||
db := global.DB
|
||||
|
||||
@@ -261,6 +261,8 @@ func Migrate(version uint) {
|
||||
&model.UserThird{},
|
||||
&model.Oauth{},
|
||||
&model.LoginLog{},
|
||||
&model.ShareRecord{},
|
||||
&model.AuditConn{},
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println("migrate err :=>", err)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
lang: "zh-CN"
|
||||
app:
|
||||
web-client: 1 # 1:启用 0:禁用
|
||||
gin:
|
||||
api-addr: "0.0.0.0:21114"
|
||||
mode: "release" #release,debug,test
|
||||
@@ -16,7 +18,7 @@ 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:
|
||||
|
||||
@@ -14,8 +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
|
||||
|
||||
@@ -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,157 @@ 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/audit_conn/delete": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "链接日志删除",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"链接日志"
|
||||
],
|
||||
"summary": "链接日志删除",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "链接日志信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.AuditConn"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/audit_conn/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "链接日志列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"链接日志"
|
||||
],
|
||||
"summary": "链接日志列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页大小",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "目标设备",
|
||||
"name": "peer_id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "来源设备",
|
||||
"name": "from_peer",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.AuditConnList"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/file/oss_token": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -1242,7 +1438,7 @@ const docTemplateadmin = `{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备删除",
|
||||
"description": "批量设备删除",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1252,15 +1448,15 @@ const docTemplateadmin = `{
|
||||
"tags": [
|
||||
"设备"
|
||||
],
|
||||
"summary": "设备删除",
|
||||
"summary": "批量设备删除",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "设备信息",
|
||||
"description": "设备id",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.PeerForm"
|
||||
"$ref": "#/definitions/admin.PeerBatchDeleteForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1365,6 +1561,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": {
|
||||
@@ -1469,7 +1683,7 @@ const docTemplateadmin = `{
|
||||
"tags": [
|
||||
"ADMIN"
|
||||
],
|
||||
"summary": "服务配置",
|
||||
"summary": "RUSTDESK服务配置",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -2311,6 +2525,12 @@ const docTemplateadmin = `{
|
||||
"user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -2398,6 +2618,20 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.PeerBatchDeleteForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"row_ids"
|
||||
],
|
||||
"properties": {
|
||||
"row_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.PeerForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2430,6 +2664,33 @@ 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": [
|
||||
@@ -2600,6 +2861,70 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.AuditConn": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"close_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"conn_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"from_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"from_peer": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ip": {
|
||||
"type": "string"
|
||||
},
|
||||
"peer_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"session_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "integer"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.AuditConnList": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"list": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/model.AuditConn"
|
||||
}
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"page_size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.Group": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -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,157 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/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/audit_conn/delete": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "链接日志删除",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"链接日志"
|
||||
],
|
||||
"summary": "链接日志删除",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "链接日志信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.AuditConn"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/audit_conn/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "链接日志列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"链接日志"
|
||||
],
|
||||
"summary": "链接日志列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页大小",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "目标设备",
|
||||
"name": "peer_id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "来源设备",
|
||||
"name": "from_peer",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.AuditConnList"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/file/oss_token": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -1235,7 +1431,7 @@
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备删除",
|
||||
"description": "批量设备删除",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -1245,15 +1441,15 @@
|
||||
"tags": [
|
||||
"设备"
|
||||
],
|
||||
"summary": "设备删除",
|
||||
"summary": "批量设备删除",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "设备信息",
|
||||
"description": "设备id",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.PeerForm"
|
||||
"$ref": "#/definitions/admin.PeerBatchDeleteForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1358,6 +1554,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": {
|
||||
@@ -1462,7 +1676,7 @@
|
||||
"tags": [
|
||||
"ADMIN"
|
||||
],
|
||||
"summary": "服务配置",
|
||||
"summary": "RUSTDESK服务配置",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -2304,6 +2518,12 @@
|
||||
"user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"user_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -2391,6 +2611,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.PeerBatchDeleteForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"row_ids"
|
||||
],
|
||||
"properties": {
|
||||
"row_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.PeerForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2423,6 +2657,33 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"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": [
|
||||
@@ -2593,6 +2854,70 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.AuditConn": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"close_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"conn_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"from_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"from_peer": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ip": {
|
||||
"type": "string"
|
||||
},
|
||||
"peer_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"session_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "integer"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.AuditConnList": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"list": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/model.AuditConn"
|
||||
}
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"page_size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.Group": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -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:
|
||||
@@ -241,6 +273,48 @@ definitions:
|
||||
total:
|
||||
type: integer
|
||||
type: object
|
||||
model.AuditConn:
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
close_time:
|
||||
type: integer
|
||||
conn_id:
|
||||
type: integer
|
||||
created_at:
|
||||
type: string
|
||||
from_name:
|
||||
type: string
|
||||
from_peer:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
ip:
|
||||
type: string
|
||||
peer_id:
|
||||
type: string
|
||||
session_id:
|
||||
type: string
|
||||
type:
|
||||
type: integer
|
||||
updated_at:
|
||||
type: string
|
||||
uuid:
|
||||
type: string
|
||||
type: object
|
||||
model.AuditConnList:
|
||||
properties:
|
||||
list:
|
||||
items:
|
||||
$ref: '#/definitions/model.AuditConn'
|
||||
type: array
|
||||
page:
|
||||
type: integer
|
||||
page_size:
|
||||
type: integer
|
||||
total:
|
||||
type: integer
|
||||
type: object
|
||||
model.Group:
|
||||
properties:
|
||||
created_at:
|
||||
@@ -473,7 +547,7 @@ paths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建地址簿
|
||||
description: 批量创建地址簿
|
||||
parameters:
|
||||
- description: 地址簿信息
|
||||
in: body
|
||||
@@ -499,7 +573,7 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 创建地址簿
|
||||
summary: 批量创建地址簿
|
||||
tags:
|
||||
- 地址簿
|
||||
/admin/address_book/delete:
|
||||
@@ -605,6 +679,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 +740,98 @@ 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/audit_conn/delete:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 链接日志删除
|
||||
parameters:
|
||||
- description: 链接日志信息
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/model.AuditConn'
|
||||
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/audit_conn/list:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 链接日志列表
|
||||
parameters:
|
||||
- description: 页码
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: 页大小
|
||||
in: query
|
||||
name: page_size
|
||||
type: integer
|
||||
- description: 目标设备
|
||||
in: query
|
||||
name: peer_id
|
||||
type: integer
|
||||
- description: 来源设备
|
||||
in: query
|
||||
name: from_peer
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/response.Response'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/model.AuditConnList'
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 链接日志列表
|
||||
tags:
|
||||
- 链接日志
|
||||
/admin/file/oss_token:
|
||||
get:
|
||||
consumes:
|
||||
@@ -1196,14 +1390,14 @@ paths:
|
||||
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,7 +1411,7 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 设备删除
|
||||
summary: 批量设备删除
|
||||
tags:
|
||||
- 设备
|
||||
/admin/peer/detail/{id}:
|
||||
@@ -1266,6 +1460,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:
|
||||
@@ -1338,7 +1544,7 @@ paths:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 服务配置
|
||||
summary: RUSTDESK服务配置
|
||||
tags:
|
||||
- ADMIN
|
||||
/admin/tag/create:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 46 KiB |
@@ -121,40 +121,6 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/add": {
|
||||
"post": {
|
||||
"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/peer/add/{guid}": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -176,8 +142,8 @@ const docTemplateapi = `{
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
@@ -217,8 +183,8 @@ const docTemplateapi = `{
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
@@ -260,8 +226,8 @@ const docTemplateapi = `{
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
@@ -302,12 +268,22 @@ const docTemplateapi = `{
|
||||
"summary": "地址列表",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "current",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "每页数量",
|
||||
"name": "pageSize",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "ab",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -434,12 +410,16 @@ const docTemplateapi = `{
|
||||
"summary": "共享地址簿",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "current",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "每页数量",
|
||||
"name": "pageSize",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -458,6 +438,49 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/add/{guid}": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签添加",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/rename/{guid}": {
|
||||
"put": {
|
||||
"security": [
|
||||
@@ -476,6 +499,15 @@ const docTemplateapi = `{
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签重命名",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -510,6 +542,15 @@ const docTemplateapi = `{
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签修改颜色",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -544,6 +585,15 @@ const docTemplateapi = `{
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签删除",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -581,8 +631,8 @@ const docTemplateapi = `{
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
@@ -637,6 +687,46 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/audit/conn": {
|
||||
"post": {
|
||||
"description": "审计连接",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"审计"
|
||||
],
|
||||
"summary": "审计连接",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "审计连接",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.AuditConnForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/heartbeat": {
|
||||
"post": {
|
||||
"description": "心跳",
|
||||
@@ -945,13 +1035,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"
|
||||
@@ -1113,6 +1227,38 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.AuditConnForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"conn_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"ip": {
|
||||
"type": "string"
|
||||
},
|
||||
"peer": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"session_id": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "integer"
|
||||
},
|
||||
"uuid": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.DeviceInfoInLogin": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -114,40 +114,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/add": {
|
||||
"post": {
|
||||
"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/peer/add/{guid}": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -169,8 +135,8 @@
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
@@ -210,8 +176,8 @@
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
@@ -253,8 +219,8 @@
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
@@ -295,12 +261,22 @@
|
||||
"summary": "地址列表",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "current",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "每页数量",
|
||||
"name": "pageSize",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "ab",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -427,12 +403,16 @@
|
||||
"summary": "共享地址簿",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "string valid",
|
||||
"name": "string",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "current",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "每页数量",
|
||||
"name": "pageSize",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -451,6 +431,49 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/add/{guid}": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "标签",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签添加",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ab/tag/rename/{guid}": {
|
||||
"put": {
|
||||
"security": [
|
||||
@@ -469,6 +492,15 @@
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签重命名",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -503,6 +535,15 @@
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签修改颜色",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -537,6 +578,15 @@
|
||||
"地址[Personal]"
|
||||
],
|
||||
"summary": "标签删除",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -574,8 +624,8 @@
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id",
|
||||
"name": "id",
|
||||
"description": "guid",
|
||||
"name": "guid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
@@ -630,6 +680,46 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/audit/conn": {
|
||||
"post": {
|
||||
"description": "审计连接",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"审计"
|
||||
],
|
||||
"summary": "审计连接",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "审计连接",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.AuditConnForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/heartbeat": {
|
||||
"post": {
|
||||
"description": "心跳",
|
||||
@@ -938,13 +1028,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"
|
||||
@@ -1106,6 +1220,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.AuditConnForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"conn_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"ip": {
|
||||
"type": "string"
|
||||
},
|
||||
"peer": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"session_id": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "integer"
|
||||
},
|
||||
"uuid": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"api.DeviceInfoInLogin": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -6,6 +6,27 @@ definitions:
|
||||
example: '{"tags":["tag1","tag2","tag3"],"peers":[{"id":"abc","username":"abv-l","hostname":"","platform":"Windows","alias":"","tags":["tag1","tag2"],"hash":"hash"}],"tag_colors":"{\"tag1\":4288585374,\"tag2\":4278238420,\"tag3\":4291681337}"}'
|
||||
type: string
|
||||
type: object
|
||||
api.AuditConnForm:
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
conn_id:
|
||||
type: integer
|
||||
id:
|
||||
type: string
|
||||
ip:
|
||||
type: string
|
||||
peer:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
session_id:
|
||||
type: number
|
||||
type:
|
||||
type: integer
|
||||
uuid:
|
||||
type: string
|
||||
type: object
|
||||
api.DeviceInfoInLogin:
|
||||
properties:
|
||||
name:
|
||||
@@ -208,36 +229,15 @@ paths:
|
||||
summary: 地址更新
|
||||
tags:
|
||||
- 地址
|
||||
/ab/add:
|
||||
post:
|
||||
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/peer/add/{guid}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 删除地址
|
||||
parameters:
|
||||
- description: id
|
||||
- description: guid
|
||||
in: path
|
||||
name: id
|
||||
name: guid
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
@@ -261,9 +261,9 @@ paths:
|
||||
- application/json
|
||||
description: 添加地址
|
||||
parameters:
|
||||
- description: id
|
||||
- description: guid
|
||||
in: path
|
||||
name: id
|
||||
name: guid
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
@@ -288,9 +288,9 @@ paths:
|
||||
- application/json
|
||||
description: 更新地址
|
||||
parameters:
|
||||
- description: id
|
||||
- description: guid
|
||||
in: path
|
||||
name: id
|
||||
name: guid
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
@@ -315,11 +315,18 @@ paths:
|
||||
- application/json
|
||||
description: 地址
|
||||
parameters:
|
||||
- description: string valid
|
||||
in: body
|
||||
name: string
|
||||
schema:
|
||||
type: string
|
||||
- description: 页码
|
||||
in: query
|
||||
name: current
|
||||
type: integer
|
||||
- description: 每页数量
|
||||
in: query
|
||||
name: pageSize
|
||||
type: integer
|
||||
- description: guid
|
||||
in: query
|
||||
name: ab
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -396,11 +403,14 @@ paths:
|
||||
- application/json
|
||||
description: 共享
|
||||
parameters:
|
||||
- description: string valid
|
||||
in: body
|
||||
name: string
|
||||
schema:
|
||||
type: string
|
||||
- description: 页码
|
||||
in: query
|
||||
name: current
|
||||
type: integer
|
||||
- description: 每页数量
|
||||
in: query
|
||||
name: pageSize
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -422,6 +432,12 @@ paths:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 标签
|
||||
parameters:
|
||||
- description: guid
|
||||
in: path
|
||||
name: guid
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -438,11 +454,44 @@ paths:
|
||||
summary: 标签删除
|
||||
tags:
|
||||
- 地址[Personal]
|
||||
/ab/tag/add/{guid}:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 标签
|
||||
parameters:
|
||||
- description: guid
|
||||
in: path
|
||||
name: guid
|
||||
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/tag/rename/{guid}:
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 标签
|
||||
parameters:
|
||||
- description: guid
|
||||
in: path
|
||||
name: guid
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -464,6 +513,12 @@ paths:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 标签
|
||||
parameters:
|
||||
- description: guid
|
||||
in: path
|
||||
name: guid
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -486,9 +541,9 @@ paths:
|
||||
- application/json
|
||||
description: 标签
|
||||
parameters:
|
||||
- description: id
|
||||
- description: guid
|
||||
in: path
|
||||
name: id
|
||||
name: guid
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
@@ -528,6 +583,32 @@ paths:
|
||||
summary: 用户信息
|
||||
tags:
|
||||
- 用户
|
||||
/audit/conn:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 审计连接
|
||||
parameters:
|
||||
- description: 审计连接
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/api.AuditConnForm'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
summary: 审计连接
|
||||
tags:
|
||||
- 审计
|
||||
/heartbeat:
|
||||
post:
|
||||
consumes:
|
||||
@@ -727,6 +808,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:
|
||||
@@ -750,8 +850,6 @@ paths:
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 提交系统信息
|
||||
tags:
|
||||
- 地址
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 50 KiB |
1
go.mod
1
go.mod
@@ -13,6 +13,7 @@ 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
|
||||
|
||||
@@ -257,3 +257,44 @@ func (ct *AddressBook) Delete(c *gin.Context) {
|
||||
}
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
81
http/controller/admin/audit.go
Normal file
81
http/controller/admin/audit.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Audit struct {
|
||||
}
|
||||
|
||||
// ConnList 列表
|
||||
// @Tags 链接日志
|
||||
// @Summary 链接日志列表
|
||||
// @Description 链接日志列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "页码"
|
||||
// @Param page_size query int false "页大小"
|
||||
// @Param peer_id query int false "目标设备"
|
||||
// @Param from_peer query int false "来源设备"
|
||||
// @Success 200 {object} response.Response{data=model.AuditConnList}
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/audit_conn/list [get]
|
||||
// @Security token
|
||||
func (a *Audit) ConnList(c *gin.Context) {
|
||||
query := &admin.AuditQuery{}
|
||||
if err := c.ShouldBindQuery(query); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
res := service.AllService.AuditService.AuditConnList(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||
if query.PeerId != "" {
|
||||
tx.Where("peer_id like ?", "%"+query.PeerId+"%")
|
||||
}
|
||||
if query.FromPeer != "" {
|
||||
tx.Where("from_peer like ?", "%"+query.FromPeer+"%")
|
||||
}
|
||||
})
|
||||
response.Success(c, res)
|
||||
}
|
||||
|
||||
// ConnDelete 删除
|
||||
// @Tags 链接日志
|
||||
// @Summary 链接日志删除
|
||||
// @Description 链接日志删除
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body model.AuditConn true "链接日志信息"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/audit_conn/delete [post]
|
||||
// @Security token
|
||||
func (a *Audit) ConnDelete(c *gin.Context) {
|
||||
f := &model.AuditConn{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
id := f.Id
|
||||
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
l := service.AllService.AuditService.InfoById(f.Id)
|
||||
if l.Id > 0 {
|
||||
err := service.AllService.AuditService.DeleteAuditConn(l)
|
||||
if err == nil {
|
||||
response.Success(c, nil)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, err.Error())
|
||||
return
|
||||
}
|
||||
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,18 +29,21 @@ func (ct *Login) Login(c *gin.Context) {
|
||||
f := &admin.Login{}
|
||||
err := c.ShouldBindJSON(f)
|
||||
if err != nil {
|
||||
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(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 {
|
||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -77,6 +77,8 @@ func (ct *Peer) Create(c *gin.Context) {
|
||||
// @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]
|
||||
@@ -96,6 +98,12 @@ func (ct *Peer) List(c *gin.Context) {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -119,9 +118,10 @@ func (a *Ab) Tags(c *gin.Context) {
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param guid path string true "guid"
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/add [post]
|
||||
// @Router /ab/tag/add/{guid} [post]
|
||||
// @Security BearerAuth
|
||||
func (a *Ab) TagAdd(c *gin.Context) {
|
||||
t := &model.Tag{}
|
||||
@@ -151,6 +151,7 @@ func (a *Ab) TagAdd(c *gin.Context) {
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param guid path string true "guid"
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/tag/rename/{guid} [put]
|
||||
@@ -188,6 +189,7 @@ func (a *Ab) TagRename(c *gin.Context) {
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param guid path string true "guid"
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/tag/update/{guid} [put]
|
||||
@@ -220,6 +222,7 @@ func (a *Ab) TagUpdate(c *gin.Context) {
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param guid path string true "guid"
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/tag/{guid} [delete]
|
||||
@@ -274,7 +277,7 @@ func (a *Ab) Personal(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"guid": guid,
|
||||
"name": user.Username,
|
||||
"rule": 0,
|
||||
"rule": 3,
|
||||
})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, nil)
|
||||
@@ -305,7 +308,8 @@ func (a *Ab) Settings(c *gin.Context) {
|
||||
// @Description 共享
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param string body string false "string valid"
|
||||
// @Param current query int false "页码"
|
||||
// @Param pageSize query int false "每页数量"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /ab/shared/profiles [post]
|
||||
@@ -323,14 +327,14 @@ func (a *Ab) SharedProfiles(c *gin.Context) {
|
||||
"name": "admin",
|
||||
"owner": "admin",
|
||||
"note": "admin11",
|
||||
"rule": 0,
|
||||
"rule": 3,
|
||||
}
|
||||
item2 := map[string]interface{}{
|
||||
"guid": "2",
|
||||
"name": "admin2",
|
||||
"owner": "admin2",
|
||||
"note": "admin22",
|
||||
"rule": 0,
|
||||
"rule": 2,
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"total": 2,
|
||||
@@ -349,7 +353,9 @@ func (a *Ab) SharedProfiles(c *gin.Context) {
|
||||
// @Description 地址
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param string body string false "string valid"
|
||||
// @Param current query int false "页码"
|
||||
// @Param pageSize query int false "每页数量"
|
||||
// @Param ab query string false "guid"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /ab/peers [post]
|
||||
@@ -370,7 +376,7 @@ func (a *Ab) Peers(c *gin.Context) {
|
||||
// @Description 标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Param guid path string true "guid"
|
||||
// @Success 200 {object} model.TagList
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/tags/{guid} [post]
|
||||
@@ -388,24 +394,35 @@ func (a *Ab) PTags(c *gin.Context) {
|
||||
// @Description 添加地址
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Param guid path string true "guid"
|
||||
// @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",真是坑
|
||||
// forceAlwaysRelay永远是字符串"false"
|
||||
//f := &gin.H{}
|
||||
//guid := c.Param("guid")
|
||||
f := &requstform.PersonalAddressBookForm{}
|
||||
err := c.ShouldBindJSON(f)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Println(f)
|
||||
//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())
|
||||
@@ -420,7 +437,7 @@ func (a *Ab) PeerAdd(c *gin.Context) {
|
||||
// @Description 删除地址
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Param guid path string true "guid"
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/peer/add/{guid} [delete]
|
||||
@@ -455,7 +472,7 @@ func (a *Ab) PeerDel(c *gin.Context) {
|
||||
// @Description 更新地址
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Param guid path string true "guid"
|
||||
// @Success 200 {string} string
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /ab/peer/update/{guid} [put]
|
||||
|
||||
56
http/controller/api/audit.go
Normal file
56
http/controller/api/audit.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
request "Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Audit struct {
|
||||
}
|
||||
|
||||
// AuditConn
|
||||
// @Tags 审计
|
||||
// @Summary 审计连接
|
||||
// @Description 审计连接
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body request.AuditConnForm true "审计连接"
|
||||
// @Success 200 {string} string ""
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /audit/conn [post]
|
||||
func (a *Audit) AuditConn(c *gin.Context) {
|
||||
af := &request.AuditConnForm{}
|
||||
err := c.ShouldBindBodyWith(af, binding.JSON)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
//fmt.Println(af)
|
||||
ac := af.ToAuditConn()
|
||||
if af.Action == model.AuditActionNew {
|
||||
service.AllService.AuditService.CreateAuditConn(ac)
|
||||
} else if af.Action == model.AuditActionClose {
|
||||
ex := service.AllService.AuditService.InfoByPeerIdAndConnId(af.Id, af.ConnId)
|
||||
if ex.Id != 0 {
|
||||
ex.CloseTime = time.Now().Unix()
|
||||
service.AllService.AuditService.UpdateAuditConn(ex)
|
||||
}
|
||||
} else if af.Action == "" {
|
||||
ex := service.AllService.AuditService.InfoByPeerIdAndConnId(af.Id, af.ConnId)
|
||||
if ex.Id != 0 {
|
||||
up := &model.AuditConn{
|
||||
IdModel: model.IdModel{Id: ex.Id},
|
||||
FromPeer: ac.FromPeer,
|
||||
FromName: ac.FromName,
|
||||
SessionId: ac.SessionId,
|
||||
}
|
||||
service.AllService.AuditService.UpdateAuditConn(up)
|
||||
}
|
||||
}
|
||||
response.Success(c, "")
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
requstform "Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
@@ -53,7 +54,11 @@ func (i *Index) Heartbeat(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
return
|
||||
}
|
||||
peer.LastOnlineTime = time.Now().Unix()
|
||||
service.AllService.PeerService.Update(peer)
|
||||
//如果在一分钟以内则不更新
|
||||
if time.Now().Unix()-peer.LastOnlineTime > 60 {
|
||||
peer.LastOnlineTime = time.Now().Unix()
|
||||
upp := &model.Peer{RowId: peer.RowId, LastOnlineTime: peer.LastOnlineTime}
|
||||
service.AllService.PeerService.Update(upp)
|
||||
}
|
||||
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 {
|
||||
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(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,6 +46,7 @@ func (l *Login) Login(c *gin.Context) {
|
||||
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
||||
|
||||
if u.Id == 0 {
|
||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
||||
response.Error(c, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ 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)
|
||||
@@ -30,19 +29,30 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
||||
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, 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 下次心跳会上传
|
||||
//直接响应文本
|
||||
c.String(http.StatusOK, "")
|
||||
c.String(http.StatusOK, "SYSINFO_UPDATED")
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ type User struct {
|
||||
// @Security token
|
||||
//func (u *User) currentUser(c *gin.Context) {
|
||||
// user := service.AllService.UserService.CurUser(c)
|
||||
// up := (&apiResp.UserPayload{}).FromUser(user)
|
||||
// up := (&apiResp.UserPayload{}).FromName(user)
|
||||
// c.JSON(http.StatusOK, up)
|
||||
//}
|
||||
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,85 +16,7 @@ func (i *Index) ConfigJs(c *gin.Context) {
|
||||
apiServer := global.Config.Rustdesk.ApiServer
|
||||
|
||||
tmp := `
|
||||
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
|
||||
}
|
||||
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')) || {}
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} 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.Header)
|
||||
//fmt.Println(c.Request.URL, c.Request.Header)
|
||||
//获取HTTP_AUTHORIZATION
|
||||
token := c.GetHeader("Authorization")
|
||||
if token == "" {
|
||||
|
||||
@@ -85,3 +85,20 @@ type AddressBookQuery struct {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
7
http/request/admin/audit.go
Normal file
7
http/request/admin/audit.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package admin
|
||||
|
||||
type AuditQuery struct {
|
||||
PeerId string `form:"peer_id"`
|
||||
FromPeer string `form:"from_peer"`
|
||||
PageQuery
|
||||
}
|
||||
@@ -35,5 +35,7 @@ func (f *PeerForm) ToPeer() *model.Peer {
|
||||
|
||||
type PeerQuery struct {
|
||||
PageQuery
|
||||
TimeAgo int `json:"time_ago" form:"time_ago"`
|
||||
TimeAgo int `json:"time_ago" form:"time_ago"`
|
||||
Id string `json:"id" form:"id"`
|
||||
Hostname string `json:"hostname" form:"hostname"`
|
||||
}
|
||||
|
||||
40
http/request/api/audit.go
Normal file
40
http/request/api/audit.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"Gwen/model"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type AuditConnForm struct {
|
||||
Action string `json:"action"`
|
||||
ConnId int64 `json:"conn_id"`
|
||||
Id string `json:"id"`
|
||||
Peer []string `json:"peer"`
|
||||
Ip string `json:"ip"`
|
||||
SessionId float64 `json:"session_id"`
|
||||
Type int `json:"type"`
|
||||
Uuid string `json:"uuid"`
|
||||
}
|
||||
|
||||
func (a *AuditConnForm) ToAuditConn() *model.AuditConn {
|
||||
fp := ""
|
||||
fn := ""
|
||||
if len(a.Peer) >= 1 {
|
||||
fp = a.Peer[0]
|
||||
if len(a.Peer) == 2 {
|
||||
fn = a.Peer[1]
|
||||
}
|
||||
}
|
||||
ssid := strconv.FormatFloat(a.SessionId, 'f', -1, 64)
|
||||
return &model.AuditConn{
|
||||
Action: a.Action,
|
||||
ConnId: a.ConnId,
|
||||
PeerId: a.Id,
|
||||
FromPeer: fp,
|
||||
FromName: fn,
|
||||
Ip: a.Ip,
|
||||
SessionId: ssid,
|
||||
Type: a.Type,
|
||||
Uuid: a.Uuid,
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ type WebClientPeerPayload struct {
|
||||
ViewStyle string `json:"view-style"`
|
||||
Tm int64 `json:"tm"`
|
||||
Info WebClientPeerInfoPayload `json:"info"`
|
||||
Tmppwd string `json:"tmppwd"`
|
||||
}
|
||||
|
||||
type WebClientPeerInfoPayload struct {
|
||||
@@ -16,6 +17,7 @@ type WebClientPeerInfoPayload struct {
|
||||
Hostname string `json:"hostname"`
|
||||
Platform string `json:"platform"`
|
||||
Hash string `json:"hash"`
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
func (wcpp *WebClientPeerPayload) FromAddressBook(a *model.AddressBook) {
|
||||
@@ -29,3 +31,16 @@ func (wcpp *WebClientPeerPayload) FromAddressBook(a *model.AddressBook) {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,10 @@ func Init(g *gin.Engine) {
|
||||
PeerBind(adg)
|
||||
OauthBind(adg)
|
||||
LoginLogBind(adg)
|
||||
|
||||
AuditBind(adg)
|
||||
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,7 @@ 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)
|
||||
@@ -141,6 +143,12 @@ func LoginLogBind(rg *gin.RouterGroup) {
|
||||
aR.GET("/list", cont.List)
|
||||
aR.POST("/delete", cont.Delete)
|
||||
}
|
||||
func AuditBind(rg *gin.RouterGroup) {
|
||||
cont := &admin.Audit{}
|
||||
aR := rg.Group("/audit_conn").Use(middleware.AdminPrivilege())
|
||||
aR.GET("/list", cont.ConnList)
|
||||
aR.POST("/delete", cont.ConnDelete)
|
||||
}
|
||||
|
||||
/*
|
||||
func FileBind(rg *gin.RouterGroup) {
|
||||
|
||||
@@ -46,12 +46,14 @@ 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)
|
||||
}
|
||||
au := &api.Audit{}
|
||||
//[method:POST] [uri:/api/audit/conn]
|
||||
frg.POST("/audit/conn", au.AuditConn)
|
||||
frg.Use(middleware.RustAuth())
|
||||
{
|
||||
u := &api.User{}
|
||||
frg.GET("/user/info", u.Info)
|
||||
@@ -109,3 +111,14 @@ func PersonalRoutes(frg *gin.RouterGroup) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func WebClientRoutes(frg *gin.RouterGroup) {
|
||||
w := &api.WebClient{}
|
||||
{
|
||||
frg.POST("/shared-peer", w.SharedPeer)
|
||||
}
|
||||
{
|
||||
frg.POST("/server-config", middleware.RustAuth(), w.ServerConfig)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,13 @@ import (
|
||||
func WebInit(g *gin.Engine) {
|
||||
i := &web.Index{}
|
||||
g.GET("/", i.Index)
|
||||
g.GET("/webclient-config/index.js", i.ConfigJs)
|
||||
g.StaticFS("/webclient", http.Dir(global.Config.Gin.ResourcesPath+"/web"))
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
26
model/audit.go
Normal file
26
model/audit.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package model
|
||||
|
||||
const (
|
||||
AuditActionNew = "new"
|
||||
AuditActionClose = "close"
|
||||
)
|
||||
|
||||
type AuditConn struct {
|
||||
IdModel
|
||||
Action string `json:"action" gorm:"default:'';not null;"`
|
||||
ConnId int64 `json:"conn_id" gorm:"default:0;not null;index"`
|
||||
PeerId string `json:"peer_id" gorm:"default:'';not null;index"`
|
||||
FromPeer string `json:"from_peer" gorm:"default:'';not null;"`
|
||||
FromName string `json:"from_name" gorm:"default:'';not null;"`
|
||||
Ip string `json:"ip" gorm:"default:'';not null;"`
|
||||
SessionId string `json:"session_id" gorm:"default:'';not null;"`
|
||||
Type int `json:"type" gorm:"default:0;not null;"`
|
||||
Uuid string `json:"uuid" gorm:"default:'';not null;"`
|
||||
CloseTime int64 `json:"close_time" gorm:"default:0;not null;"`
|
||||
TimeModel
|
||||
}
|
||||
|
||||
type AuditConnList struct {
|
||||
AuditConns []*AuditConn `json:"list"`
|
||||
Pagination
|
||||
}
|
||||
12
model/shareRecord.go
Normal file
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
|
||||
}
|
||||
292
resources/web/index.html
vendored
292
resources/web/index.html
vendored
@@ -2,188 +2,188 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<!--
|
||||
If you are serving your web app in a path other than the root, change the
|
||||
href value below to reflect the base path you are serving from.
|
||||
<!--
|
||||
If you are serving your web app in a path other than the root, change the
|
||||
href value below to reflect the base path you are serving from.
|
||||
|
||||
The path provided below has to start and end with a slash "/" in order for
|
||||
it to work correctly.
|
||||
The path provided below has to start and end with a slash "/" in order for
|
||||
it to work correctly.
|
||||
|
||||
For more details:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||
For more details:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||
|
||||
This is a placeholder for base href that will be replaced by the value of
|
||||
the `--base-href` argument provided to `flutter build`.
|
||||
-->
|
||||
<base href="/webclient/">
|
||||
This is a placeholder for base href that will be replaced by the value of
|
||||
the `--base-href` argument provided to `flutter build`.
|
||||
-->
|
||||
<base href="/webclient/">
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||
<meta name="description" content="Remote Desktop.">
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||
<meta name="description" content="Remote Desktop.">
|
||||
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="RustDesk">
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="RustDesk">
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg"/>
|
||||
|
||||
<title>RustDesk</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<script src="/webclient-config/index.js"></script>
|
||||
<script>
|
||||
<title>RustDesk</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<script src="/webclient-config/index.js"></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>
|
||||
|
||||
<style>
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-ms-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
</script>
|
||||
<script src="ogvjs-1.8.6/ogv.js"></script>
|
||||
<script type="module" crossorigin src="js/dist/index.js"></script>
|
||||
<link rel="modulepreload" href="js/dist/vendor.js">
|
||||
<script src="yuv-canvas-1.2.6.js"></script>
|
||||
.loader {
|
||||
border: 16px solid #f3f3f3;
|
||||
border-radius: 50%;
|
||||
border: 15px solid;
|
||||
border-top: 16px solid #024eff;
|
||||
border-right: 16px solid white;
|
||||
border-bottom: 16px solid #024eff;
|
||||
border-left: 16px solid white;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
-webkit-animation: spin 2s linear infinite;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
<style>
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-ms-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.loader {
|
||||
border: 16px solid #f3f3f3;
|
||||
border-radius: 50%;
|
||||
border: 15px solid;
|
||||
border-top: 16px solid #024eff;
|
||||
border-right: 16px solid white;
|
||||
border-bottom: 16px solid #024eff;
|
||||
border-left: 16px solid white;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
-webkit-animation: spin 2s linear infinite;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
}
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="loading">
|
||||
<div class="loading">
|
||||
<div class="loader"></div>
|
||||
</div>
|
||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||
application. For more information, see:
|
||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||
<script>
|
||||
</div>
|
||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||
application. For more information, see:
|
||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||
<script>
|
||||
var serviceWorkerVersion = '1200232272';
|
||||
var scriptLoaded = false;
|
||||
|
||||
function loadMainDartJs() {
|
||||
if (scriptLoaded) {
|
||||
return;
|
||||
}
|
||||
scriptLoaded = true;
|
||||
var scriptTag = document.createElement('script');
|
||||
scriptTag.src = 'main.dart.js';
|
||||
scriptTag.type = 'application/javascript';
|
||||
document.body.append(scriptTag);
|
||||
if (scriptLoaded) {
|
||||
return;
|
||||
}
|
||||
scriptLoaded = true;
|
||||
var scriptTag = document.createElement('script');
|
||||
scriptTag.src = 'main.dart.js';
|
||||
scriptTag.type = 'application/javascript';
|
||||
document.body.append(scriptTag);
|
||||
}
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
// Service workers are supported. Use them.
|
||||
window.addEventListener('load', function () {
|
||||
// Wait for registration to finish before dropping the <script> tag.
|
||||
// Otherwise, the browser will load the script multiple times,
|
||||
// potentially different versions.
|
||||
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
|
||||
navigator.serviceWorker.register(serviceWorkerUrl)
|
||||
.then((reg) => {
|
||||
function waitForActivation(serviceWorker) {
|
||||
serviceWorker.addEventListener('statechange', () => {
|
||||
if (serviceWorker.state == 'activated') {
|
||||
console.log('Installed new service worker.');
|
||||
loadMainDartJs();
|
||||
// Service workers are supported. Use them.
|
||||
window.addEventListener('load', function () {
|
||||
// Wait for registration to finish before dropping the <script> tag.
|
||||
// Otherwise, the browser will load the script multiple times,
|
||||
// potentially different versions.
|
||||
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
|
||||
navigator.serviceWorker.register(serviceWorkerUrl)
|
||||
.then((reg) => {
|
||||
function waitForActivation(serviceWorker) {
|
||||
serviceWorker.addEventListener('statechange', () => {
|
||||
if (serviceWorker.state == 'activated') {
|
||||
console.log('Installed new service worker.');
|
||||
loadMainDartJs();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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.
|
||||
waitForActivation(reg.installing || reg.waiting);
|
||||
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
|
||||
// When the app updates the serviceWorkerVersion changes, so we
|
||||
// need to ask the service worker to update.
|
||||
console.log('New service worker available.');
|
||||
reg.update();
|
||||
waitForActivation(reg.installing);
|
||||
} else {
|
||||
// Existing service worker is still good.
|
||||
console.log('Loading app from service worker.');
|
||||
loadMainDartJs();
|
||||
}
|
||||
});
|
||||
|
||||
// If service worker doesn't succeed in a reasonable amount of time,
|
||||
// fallback to plaint <script> tag.
|
||||
setTimeout(() => {
|
||||
if (!scriptLoaded) {
|
||||
console.warn(
|
||||
'Failed to load app from service worker. Falling back to plain <script> tag.',
|
||||
);
|
||||
loadMainDartJs();
|
||||
}
|
||||
});
|
||||
}
|
||||
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.
|
||||
waitForActivation(reg.installing || reg.waiting);
|
||||
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
|
||||
// When the app updates the serviceWorkerVersion changes, so we
|
||||
// need to ask the service worker to update.
|
||||
console.log('New service worker available.');
|
||||
reg.update();
|
||||
waitForActivation(reg.installing);
|
||||
} else {
|
||||
// Existing service worker is still good.
|
||||
console.log('Loading app from service worker.');
|
||||
loadMainDartJs();
|
||||
}
|
||||
});
|
||||
|
||||
// If service worker doesn't succeed in a reasonable amount of time,
|
||||
// fallback to plaint <script> tag.
|
||||
setTimeout(() => {
|
||||
if (!scriptLoaded) {
|
||||
console.warn(
|
||||
'Failed to load app from service worker. Falling back to plain <script> tag.',
|
||||
);
|
||||
loadMainDartJs();
|
||||
}
|
||||
}, 4000);
|
||||
});
|
||||
}, 4000);
|
||||
});
|
||||
} else {
|
||||
// Service workers not supported. Just drop the <script> tag.
|
||||
loadMainDartJs();
|
||||
// Service workers not supported. Just drop the <script> tag.
|
||||
loadMainDartJs();
|
||||
}
|
||||
</script>
|
||||
<script src="libs/firebase-app.js?8.10.1"></script>
|
||||
<script src="libs/firebase-analytics.js?8.10.1"></script>
|
||||
</script>
|
||||
<script src="libs/firebase-app.js?8.10.1"></script>
|
||||
<script src="libs/firebase-analytics.js?8.10.1"></script>
|
||||
|
||||
<script>
|
||||
<script>
|
||||
// Your web app's Firebase configuration
|
||||
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
|
||||
const firebaseConfig = {
|
||||
apiKey: "AIzaSyCgehIZk1aFP0E7wZtYRRqrfvNiNAF39-A",
|
||||
authDomain: "rustdesk.firebaseapp.com",
|
||||
databaseURL: "https://rustdesk.firebaseio.com",
|
||||
projectId: "rustdesk",
|
||||
storageBucket: "rustdesk.appspot.com",
|
||||
messagingSenderId: "768133699366",
|
||||
appId: "1:768133699366:web:d50faf0792cb208d7993e7",
|
||||
measurementId: "G-9PEH85N6ZQ"
|
||||
apiKey: "AIzaSyCgehIZk1aFP0E7wZtYRRqrfvNiNAF39-A",
|
||||
authDomain: "rustdesk.firebaseapp.com",
|
||||
databaseURL: "https://rustdesk.firebaseio.com",
|
||||
projectId: "rustdesk",
|
||||
storageBucket: "rustdesk.appspot.com",
|
||||
messagingSenderId: "768133699366",
|
||||
appId: "1:768133699366:web:d50faf0792cb208d7993e7",
|
||||
measurementId: "G-9PEH85N6ZQ"
|
||||
};
|
||||
|
||||
// Initialize Firebase
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
firebase.analytics();
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
3
resources/web/js/dist/index.html
vendored
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
4
resources/web/js/dist/index.js
vendored
File diff suppressed because one or more lines are too long
797
resources/web/js/package-lock.json
generated
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
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
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();
|
||||
|
||||
545
resources/web/js/src/globals.js
vendored
545
resources/web/js/src/globals.js
vendored
@@ -1,41 +1,44 @@
|
||||
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 {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)
|
||||
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4));
|
||||
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)
|
||||
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4));
|
||||
}
|
||||
|
||||
export function isDesktop() {
|
||||
return !isMobile();
|
||||
return !isMobile();
|
||||
}
|
||||
|
||||
export function msgbox(type, title, text) {
|
||||
if (!type || (type == 'error' && !text)) return;
|
||||
const text2 = text.toLowerCase();
|
||||
var hasRetry = checkIfRetry(type, title, text) ? 'true' : '';
|
||||
onGlobalEvent(JSON.stringify({ name: 'msgbox', type, title, text, hasRetry }));
|
||||
if (!type || (type == 'error' && !text)) return;
|
||||
const text2 = text.toLowerCase();
|
||||
var hasRetry = checkIfRetry(type, title, text) ? 'true' : '';
|
||||
onGlobalEvent(JSON.stringify({name: 'msgbox', type, title, text, hasRetry}));
|
||||
}
|
||||
|
||||
function jsonfyForDart(payload) {
|
||||
var tmp = {};
|
||||
for (const [key, value] of Object.entries(payload)) {
|
||||
if (!key) continue;
|
||||
tmp[key] = value instanceof Uint8Array ? '[' + value.toString() + ']' : JSON.stringify(value);
|
||||
}
|
||||
return tmp;
|
||||
var tmp = {};
|
||||
for (const [key, value] of Object.entries(payload)) {
|
||||
if (!key) continue;
|
||||
tmp[key] = value instanceof Uint8Array ? '[' + value.toString() + ']' : JSON.stringify(value);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
export function pushEvent(name, payload) {
|
||||
payload = jsonfyForDart(payload);
|
||||
payload.name = name;
|
||||
onGlobalEvent(JSON.stringify(payload));
|
||||
payload = jsonfyForDart(payload);
|
||||
payload.name = name;
|
||||
onGlobalEvent(JSON.stringify(payload));
|
||||
}
|
||||
|
||||
let yuvWorker;
|
||||
@@ -45,339 +48,347 @@ let pixels;
|
||||
let flipPixels;
|
||||
let oldSize;
|
||||
if (YUVCanvas.WebGLFrameSink.isAvailable()) {
|
||||
var canvas = document.createElement('canvas');
|
||||
yuvCanvas = YUVCanvas.attach(canvas, { webGL: true });
|
||||
gl = canvas.getContext("webgl");
|
||||
var canvas = document.createElement('canvas');
|
||||
yuvCanvas = YUVCanvas.attach(canvas, {webGL: true});
|
||||
gl = canvas.getContext("webgl");
|
||||
} else {
|
||||
yuvWorker = new Worker("./yuv.js");
|
||||
yuvWorker = new Worker("./yuv.js");
|
||||
}
|
||||
let testSpeed = [0, 0];
|
||||
|
||||
export function draw(frame) {
|
||||
if (yuvWorker) {
|
||||
// frame's (y/u/v).bytes already detached, can not transferrable any more.
|
||||
yuvWorker.postMessage(frame);
|
||||
} else {
|
||||
var tm0 = new Date().getTime();
|
||||
yuvCanvas.drawFrame(frame);
|
||||
var width = canvas.width;
|
||||
var height = canvas.height;
|
||||
var size = width * height * 4;
|
||||
if (size != oldSize) {
|
||||
pixels = new Uint8Array(size);
|
||||
flipPixels = new Uint8Array(size);
|
||||
oldSize = size;
|
||||
if (yuvWorker) {
|
||||
// frame's (y/u/v).bytes already detached, can not transferrable any more.
|
||||
yuvWorker.postMessage(frame);
|
||||
} else {
|
||||
var tm0 = new Date().getTime();
|
||||
yuvCanvas.drawFrame(frame);
|
||||
var width = canvas.width;
|
||||
var height = canvas.height;
|
||||
var size = width * height * 4;
|
||||
if (size != oldSize) {
|
||||
pixels = new Uint8Array(size);
|
||||
flipPixels = new Uint8Array(size);
|
||||
oldSize = size;
|
||||
}
|
||||
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
||||
const row = width * 4;
|
||||
const end = (height - 1) * row;
|
||||
for (let i = 0; i < size; i += row) {
|
||||
flipPixels.set(pixels.subarray(i, i + row), end - i);
|
||||
}
|
||||
onRgba(flipPixels);
|
||||
testSpeed[1] += new Date().getTime() - tm0;
|
||||
testSpeed[0] += 1;
|
||||
if (testSpeed[0] > 30) {
|
||||
console.log('gl: ' + parseInt('' + testSpeed[1] / testSpeed[0]));
|
||||
testSpeed = [0, 0];
|
||||
}
|
||||
}
|
||||
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
||||
const row = width * 4;
|
||||
const end = (height - 1) * row;
|
||||
for (let i = 0; i < size; i += row) {
|
||||
flipPixels.set(pixels.subarray(i, i + row), end - i);
|
||||
/*
|
||||
var testCanvas = document.getElementById("test-yuv-decoder-canvas");
|
||||
if (testCanvas && currentFrame) {
|
||||
var ctx = testCanvas.getContext("2d");
|
||||
testCanvas.width = frame.format.displayWidth;
|
||||
testCanvas.height = frame.format.displayHeight;
|
||||
var img = ctx.createImageData(testCanvas.width, testCanvas.height);
|
||||
img.data.set(currentFrame);
|
||||
ctx.putImageData(img, 0, 0);
|
||||
}
|
||||
onRgba(flipPixels);
|
||||
testSpeed[1] += new Date().getTime() - tm0;
|
||||
testSpeed[0] += 1;
|
||||
if (testSpeed[0] > 30) {
|
||||
console.log('gl: ' + parseInt('' + testSpeed[1] / testSpeed[0]));
|
||||
testSpeed = [0, 0];
|
||||
}
|
||||
}
|
||||
/*
|
||||
var testCanvas = document.getElementById("test-yuv-decoder-canvas");
|
||||
if (testCanvas && currentFrame) {
|
||||
var ctx = testCanvas.getContext("2d");
|
||||
testCanvas.width = frame.format.displayWidth;
|
||||
testCanvas.height = frame.format.displayHeight;
|
||||
var img = ctx.createImageData(testCanvas.width, testCanvas.height);
|
||||
img.data.set(currentFrame);
|
||||
ctx.putImageData(img, 0, 0);
|
||||
}
|
||||
*/
|
||||
*/
|
||||
}
|
||||
|
||||
export function sendOffCanvas(c) {
|
||||
let canvas = c.transferControlToOffscreen();
|
||||
yuvWorker.postMessage({ canvas }, [canvas]);
|
||||
let canvas = c.transferControlToOffscreen();
|
||||
yuvWorker.postMessage({canvas}, [canvas]);
|
||||
}
|
||||
|
||||
export function setConn(conn) {
|
||||
window.curConn = conn;
|
||||
window.curConn = conn;
|
||||
}
|
||||
|
||||
export function getConn() {
|
||||
return window.curConn;
|
||||
return window.curConn;
|
||||
}
|
||||
|
||||
export async function startConn(id) {
|
||||
setByName('remote_id', id);
|
||||
await curConn.start(id);
|
||||
setByName('remote_id', id);
|
||||
await curConn.start(id);
|
||||
}
|
||||
|
||||
export function close() {
|
||||
getConn()?.close();
|
||||
setConn(undefined);
|
||||
getConn()?.close();
|
||||
setConn(undefined);
|
||||
}
|
||||
|
||||
export function newConn() {
|
||||
window.curConn?.close();
|
||||
const conn = new Connection();
|
||||
setConn(conn);
|
||||
return conn;
|
||||
window.curConn?.close();
|
||||
const conn = new Connection();
|
||||
setConn(conn);
|
||||
return conn;
|
||||
}
|
||||
|
||||
let sodium;
|
||||
|
||||
export async function verify(signed, pk) {
|
||||
if (!sodium) {
|
||||
await _sodium.ready;
|
||||
sodium = _sodium;
|
||||
}
|
||||
if (typeof pk == 'string') {
|
||||
pk = decodeBase64(pk);
|
||||
}
|
||||
return sodium.crypto_sign_open(signed, pk);
|
||||
if (!sodium) {
|
||||
await _sodium.ready;
|
||||
sodium = _sodium;
|
||||
}
|
||||
if (typeof pk == 'string') {
|
||||
pk = decodeBase64(pk);
|
||||
}
|
||||
return sodium.crypto_sign_open(signed, pk);
|
||||
}
|
||||
|
||||
export function decodeBase64(pk) {
|
||||
return sodium.from_base64(pk, sodium.base64_variants.ORIGINAL);
|
||||
return sodium.from_base64(pk, sodium.base64_variants.ORIGINAL);
|
||||
}
|
||||
|
||||
export function genBoxKeyPair() {
|
||||
const pair = sodium.crypto_box_keypair();
|
||||
const sk = pair.privateKey;
|
||||
const pk = pair.publicKey;
|
||||
return [sk, pk];
|
||||
const pair = sodium.crypto_box_keypair();
|
||||
const sk = pair.privateKey;
|
||||
const pk = pair.publicKey;
|
||||
return [sk, pk];
|
||||
}
|
||||
|
||||
export function genSecretKey() {
|
||||
return sodium.crypto_secretbox_keygen();
|
||||
return sodium.crypto_secretbox_keygen();
|
||||
}
|
||||
|
||||
export function seal(unsigned, theirPk, ourSk) {
|
||||
const nonce = Uint8Array.from(Array(24).fill(0));
|
||||
return sodium.crypto_box_easy(unsigned, nonce, theirPk, ourSk);
|
||||
const nonce = Uint8Array.from(Array(24).fill(0));
|
||||
return sodium.crypto_box_easy(unsigned, nonce, theirPk, ourSk);
|
||||
}
|
||||
|
||||
function makeOnce(value) {
|
||||
var byteArray = Array(24).fill(0);
|
||||
var byteArray = Array(24).fill(0);
|
||||
|
||||
for (var index = 0; index < byteArray.length && value > 0; index++) {
|
||||
var byte = value & 0xff;
|
||||
byteArray[index] = byte;
|
||||
value = (value - byte) / 256;
|
||||
}
|
||||
for (var index = 0; index < byteArray.length && value > 0; index++) {
|
||||
var byte = value & 0xff;
|
||||
byteArray[index] = byte;
|
||||
value = (value - byte) / 256;
|
||||
}
|
||||
|
||||
return Uint8Array.from(byteArray);
|
||||
return Uint8Array.from(byteArray);
|
||||
};
|
||||
|
||||
export function encrypt(unsigned, nonce, key) {
|
||||
return sodium.crypto_secretbox_easy(unsigned, makeOnce(nonce), key);
|
||||
return sodium.crypto_secretbox_easy(unsigned, makeOnce(nonce), key);
|
||||
}
|
||||
|
||||
export function decrypt(signed, nonce, key) {
|
||||
return sodium.crypto_secretbox_open_easy(signed, makeOnce(nonce), key);
|
||||
return sodium.crypto_secretbox_open_easy(signed, makeOnce(nonce), key);
|
||||
}
|
||||
|
||||
window.setByName = (name, value) => {
|
||||
switch (name) {
|
||||
case 'remote_id':
|
||||
localStorage.setItem('remote-id', value);
|
||||
break;
|
||||
case 'connect':
|
||||
newConn();
|
||||
startConn(value);
|
||||
break;
|
||||
case 'login':
|
||||
value = JSON.parse(value);
|
||||
curConn.setRemember(value.remember == 'true');
|
||||
curConn.login(value.password);
|
||||
break;
|
||||
case 'close':
|
||||
close();
|
||||
break;
|
||||
case 'refresh':
|
||||
curConn.refresh();
|
||||
break;
|
||||
case 'reconnect':
|
||||
curConn.reconnect();
|
||||
break;
|
||||
case 'toggle_option':
|
||||
curConn.toggleOption(value);
|
||||
break;
|
||||
case 'image_quality':
|
||||
curConn.setImageQuality(value);
|
||||
break;
|
||||
case 'lock_screen':
|
||||
curConn.lockScreen();
|
||||
break;
|
||||
case 'ctrl_alt_del':
|
||||
curConn.ctrlAltDel();
|
||||
break;
|
||||
case 'switch_display':
|
||||
curConn.switchDisplay(value);
|
||||
break;
|
||||
case 'remove':
|
||||
const peers = getPeers();
|
||||
delete peers[value];
|
||||
localStorage.setItem('peers', JSON.stringify(peers));
|
||||
break;
|
||||
case 'input_key':
|
||||
value = JSON.parse(value);
|
||||
curConn.inputKey(value.name, value.down == 'true', value.press == 'true', value.alt == 'true', value.ctrl == 'true', value.shift == 'true', value.command == 'true');
|
||||
break;
|
||||
case 'input_string':
|
||||
curConn.inputString(value);
|
||||
break;
|
||||
case 'send_mouse':
|
||||
let mask = 0;
|
||||
value = JSON.parse(value);
|
||||
switch (value.type) {
|
||||
case 'down':
|
||||
mask = 1;
|
||||
break;
|
||||
case 'up':
|
||||
mask = 2;
|
||||
break;
|
||||
case 'wheel':
|
||||
mask = 3;
|
||||
break;
|
||||
}
|
||||
switch (value.buttons) {
|
||||
case 'left':
|
||||
mask |= 1 << 3;
|
||||
break;
|
||||
case 'right':
|
||||
mask |= 2 << 3;
|
||||
break;
|
||||
case 'wheel':
|
||||
mask |= 4 << 3;
|
||||
}
|
||||
curConn.inputMouse(mask, parseInt(value.x || '0'), parseInt(value.y || '0'), value.alt == 'true', value.ctrl == 'true', value.shift == 'true', value.command == 'true');
|
||||
break;
|
||||
case 'option':
|
||||
value = JSON.parse(value);
|
||||
localStorage.setItem(value.name, value.value);
|
||||
break;
|
||||
case 'peer_option':
|
||||
value = JSON.parse(value);
|
||||
curConn.setOption(value.name, value.value);
|
||||
break;
|
||||
case 'input_os_password':
|
||||
curConn.inputOsPassword(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
myconsole('setByName', name, value);
|
||||
switch (name) {
|
||||
case 'remote_id':
|
||||
localStorage.setItem('remote-id', value);
|
||||
break;
|
||||
case 'connect':
|
||||
newConn();
|
||||
startConn(value);
|
||||
break;
|
||||
case 'login':
|
||||
value = JSON.parse(value);
|
||||
curConn.setRemember(value.remember == 'true');
|
||||
curConn.login(value.password);
|
||||
break;
|
||||
case 'close':
|
||||
close();
|
||||
break;
|
||||
case 'refresh':
|
||||
curConn.refresh();
|
||||
break;
|
||||
case 'reconnect':
|
||||
curConn.reconnect();
|
||||
break;
|
||||
case 'toggle_option':
|
||||
curConn.toggleOption(value);
|
||||
break;
|
||||
case 'image_quality':
|
||||
curConn.setImageQuality(value);
|
||||
break;
|
||||
case 'lock_screen':
|
||||
curConn.lockScreen();
|
||||
break;
|
||||
case 'ctrl_alt_del':
|
||||
curConn.ctrlAltDel();
|
||||
break;
|
||||
case 'switch_display':
|
||||
curConn.switchDisplay(value);
|
||||
break;
|
||||
case 'remove':
|
||||
const peers = getPeers();
|
||||
delete peers[value];
|
||||
localStorage.setItem('peers', JSON.stringify(peers));
|
||||
break;
|
||||
case 'input_key':
|
||||
value = JSON.parse(value);
|
||||
curConn.inputKey(value.name, value.down == 'true', value.press == 'true', value.alt == 'true', value.ctrl == 'true', value.shift == 'true', value.command == 'true');
|
||||
break;
|
||||
case 'input_string':
|
||||
curConn.inputString(value);
|
||||
break;
|
||||
case 'send_mouse':
|
||||
let mask = 0;
|
||||
value = JSON.parse(value);
|
||||
switch (value.type) {
|
||||
case 'down':
|
||||
mask = 1;
|
||||
break;
|
||||
case 'up':
|
||||
mask = 2;
|
||||
break;
|
||||
case 'wheel':
|
||||
mask = 3;
|
||||
break;
|
||||
}
|
||||
switch (value.buttons) {
|
||||
case 'left':
|
||||
mask |= 1 << 3;
|
||||
break;
|
||||
case 'right':
|
||||
mask |= 2 << 3;
|
||||
break;
|
||||
case 'wheel':
|
||||
mask |= 4 << 3;
|
||||
}
|
||||
curConn.inputMouse(mask, parseInt(value.x || '0'), parseInt(value.y || '0'), value.alt == 'true', value.ctrl == 'true', value.shift == 'true', value.command == 'true');
|
||||
break;
|
||||
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);
|
||||
curConn.setOption(value.name, value.value);
|
||||
break;
|
||||
case 'input_os_password':
|
||||
curConn.inputOsPassword(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
window.getByName = (name, arg) => {
|
||||
let v = _getByName(name, arg);
|
||||
if (typeof v == 'string' || v instanceof String) return v;
|
||||
if (v == undefined || v == null) return '';
|
||||
return JSON.stringify(v);
|
||||
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);
|
||||
}
|
||||
|
||||
function getPeersForDart() {
|
||||
const peers = [];
|
||||
for (const [id, value] of Object.entries(getPeers())) {
|
||||
if (!id) continue;
|
||||
const tm = value['tm'];
|
||||
const info = value['info'];
|
||||
if (!tm || !info) continue;
|
||||
peers.push([tm, id, info]);
|
||||
}
|
||||
return peers.sort().reverse().map(x => x.slice(1));
|
||||
const peers = [];
|
||||
for (const [id, value] of Object.entries(getPeers())) {
|
||||
if (!id) continue;
|
||||
const tm = value['tm'];
|
||||
const info = value['info'];
|
||||
if (!tm || !info) continue;
|
||||
peers.push([tm, id, info]);
|
||||
}
|
||||
return peers.sort().reverse().map(x => x.slice(1));
|
||||
}
|
||||
|
||||
function _getByName(name, arg) {
|
||||
switch (name) {
|
||||
case 'peers':
|
||||
return getPeersForDart();
|
||||
case 'remote_id':
|
||||
return localStorage.getItem('remote-id');
|
||||
case 'remember':
|
||||
return curConn.getRemember();
|
||||
case 'toggle_option':
|
||||
return curConn.getOption(arg) || false;
|
||||
case 'option':
|
||||
return localStorage.getItem(arg);
|
||||
case 'image_quality':
|
||||
return curConn.getImageQuality();
|
||||
case 'translate':
|
||||
arg = JSON.parse(arg);
|
||||
return translate(arg.locale, arg.text);
|
||||
case 'peer_option':
|
||||
return curConn.getOption(arg);
|
||||
case 'test_if_valid_server':
|
||||
break;
|
||||
case 'version':
|
||||
return version;
|
||||
}
|
||||
return '';
|
||||
switch (name) {
|
||||
case 'peers':
|
||||
return getPeersForDart();
|
||||
case 'remote_id':
|
||||
return localStorage.getItem('remote-id');
|
||||
case 'remember':
|
||||
return curConn.getRemember();
|
||||
case 'toggle_option':
|
||||
return curConn.getOption(arg) || false;
|
||||
case 'option':
|
||||
const v = localStorage.getItem(arg);
|
||||
if (arg === 'access_token' && v) {
|
||||
getServerConf(v);
|
||||
}
|
||||
return v;
|
||||
case 'image_quality':
|
||||
return curConn.getImageQuality();
|
||||
case 'translate':
|
||||
arg = JSON.parse(arg);
|
||||
return translate(arg.locale, arg.text);
|
||||
case 'peer_option':
|
||||
return curConn.getOption(arg);
|
||||
case 'test_if_valid_server':
|
||||
break;
|
||||
case 'version':
|
||||
return version;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
let opusWorker = new Worker("./libopus.js");
|
||||
let pcmPlayer;
|
||||
|
||||
export function initAudio(channels, sampleRate) {
|
||||
pcmPlayer = newAudioPlayer(channels, sampleRate);
|
||||
opusWorker.postMessage({ channels, sampleRate });
|
||||
pcmPlayer = newAudioPlayer(channels, sampleRate);
|
||||
opusWorker.postMessage({channels, sampleRate});
|
||||
}
|
||||
|
||||
export function playAudio(packet) {
|
||||
opusWorker.postMessage(packet, [packet.buffer]);
|
||||
opusWorker.postMessage(packet, [packet.buffer]);
|
||||
}
|
||||
|
||||
window.init = async () => {
|
||||
if (yuvWorker) {
|
||||
yuvWorker.onmessage = (e) => {
|
||||
onRgba(e.data);
|
||||
if (yuvWorker) {
|
||||
yuvWorker.onmessage = (e) => {
|
||||
onRgba(e.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
opusWorker.onmessage = (e) => {
|
||||
pcmPlayer.feed(e.data);
|
||||
}
|
||||
loadVp9(() => { });
|
||||
await initZstd();
|
||||
console.log('init done');
|
||||
opusWorker.onmessage = (e) => {
|
||||
pcmPlayer.feed(e.data);
|
||||
}
|
||||
loadVp9(() => {
|
||||
});
|
||||
await initZstd();
|
||||
console.log('init done');
|
||||
}
|
||||
|
||||
export function getPeers() {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem('peers')) || {};
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem('peers')) || {};
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function newAudioPlayer(channels, sampleRate) {
|
||||
return new PCMPlayer({
|
||||
channels,
|
||||
sampleRate,
|
||||
flushingTime: 2000
|
||||
});
|
||||
return new PCMPlayer({
|
||||
channels,
|
||||
sampleRate,
|
||||
flushingTime: 2000
|
||||
});
|
||||
}
|
||||
|
||||
export function copyToClipboard(text) {
|
||||
if (window.clipboardData && window.clipboardData.setData) {
|
||||
// Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
|
||||
return window.clipboardData.setData("Text", text);
|
||||
if (window.clipboardData && window.clipboardData.setData) {
|
||||
// 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")) {
|
||||
var textarea = document.createElement("textarea");
|
||||
textarea.textContent = text;
|
||||
textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in Microsoft Edge.
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
try {
|
||||
return document.execCommand("copy"); // Security exception may be thrown by some browsers.
|
||||
} 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.
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
try {
|
||||
return document.execCommand("copy"); // Security exception may be thrown by some browsers.
|
||||
} catch (ex) {
|
||||
console.warn("Copy to clipboard failed.", ex);
|
||||
// return prompt("Copy to clipboard: Ctrl+C, Enter", text);
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
console.warn("Copy to clipboard failed.", ex);
|
||||
// return prompt("Copy to clipboard: Ctrl+C, Enter", text);
|
||||
}
|
||||
finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
}
|
||||
}
|
||||
99
resources/web/js/src/ljw.js
vendored
Normal file
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
resources/web/js/src/main.ts
vendored
@@ -1,2 +1,3 @@
|
||||
import "./ljw";
|
||||
import "./globals";
|
||||
import "./ui";
|
||||
@@ -3,7 +3,9 @@ package service
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AddressBookService struct {
|
||||
@@ -68,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 {
|
||||
//更新
|
||||
@@ -113,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 ""
|
||||
}
|
||||
|
||||
52
service/audit.go
Normal file
52
service/audit.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type AuditService struct {
|
||||
}
|
||||
|
||||
func (as *AuditService) AuditConnList(page, pageSize uint, where func(tx *gorm.DB)) (res *model.AuditConnList) {
|
||||
res = &model.AuditConnList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.AuditConn{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
tx.Count(&res.Total)
|
||||
tx.Scopes(Paginate(page, pageSize))
|
||||
tx.Find(&res.AuditConns)
|
||||
return
|
||||
}
|
||||
|
||||
// Create 创建
|
||||
func (as *AuditService) CreateAuditConn(u *model.AuditConn) error {
|
||||
res := global.DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
func (as *AuditService) DeleteAuditConn(u *model.AuditConn) error {
|
||||
return global.DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (as *AuditService) UpdateAuditConn(u *model.AuditConn) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
// InfoByPeerIdAndConnId
|
||||
func (as *AuditService) InfoByPeerIdAndConnId(peerId string, connId int64) (res *model.AuditConn) {
|
||||
res = &model.AuditConn{}
|
||||
global.DB.Where("peer_id = ? and conn_id = ?", peerId, connId).First(res)
|
||||
return
|
||||
}
|
||||
|
||||
// InfoById
|
||||
func (as *AuditService) InfoById(id uint) (res *model.AuditConn) {
|
||||
res = &model.AuditConn{}
|
||||
global.DB.Where("id = ?", id).First(res)
|
||||
return
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/github"
|
||||
"golang.org/x/oauth2/google"
|
||||
@@ -174,7 +173,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))
|
||||
global.Logger.Warn("oauthConfig.Exchange() failed: ", err)
|
||||
error = errors.New("GetOauthTokenError")
|
||||
return
|
||||
}
|
||||
@@ -183,20 +182,20 @@ func (os *OauthService) GithubCallback(code string) (error error, userData *Gith
|
||||
client := oauthConfig.Client(context.Background(), token)
|
||||
resp, err := client.Get("https://api.github.com/user")
|
||||
if err != nil {
|
||||
global.Logger.Warn("failed getting user info: %s\n", err)
|
||||
global.Logger.Warn("failed getting user info: ", err)
|
||||
error = errors.New("GetOauthUserInfoError")
|
||||
return
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
global.Logger.Warn("failed closing response body: %s\n", err)
|
||||
global.Logger.Warn("failed closing response body: ", err)
|
||||
}
|
||||
}(resp.Body)
|
||||
|
||||
// 在这里处理 GitHub 用户信息
|
||||
if err = json.NewDecoder(resp.Body).Decode(&userData); err != nil {
|
||||
global.Logger.Warn("failed decoding user info: %s\n", err)
|
||||
global.Logger.Warn("failed decoding user info: ", err)
|
||||
error = errors.New("DecodeOauthUserInfoError")
|
||||
return
|
||||
}
|
||||
@@ -207,7 +206,7 @@ func (os *OauthService) GoogleCallback(code string) (error error, userData *Goog
|
||||
err, oauthConfig := os.GetOauthConfig(model.OauthTypeGoogle)
|
||||
token, err := oauthConfig.Exchange(context.Background(), code)
|
||||
if err != nil {
|
||||
global.Logger.Warn(fmt.Printf("oauthConfig.Exchange() failed: %s\n", err))
|
||||
global.Logger.Warn("oauthConfig.Exchange() failed: ", err)
|
||||
error = errors.New("GetOauthTokenError")
|
||||
return
|
||||
}
|
||||
@@ -215,14 +214,14 @@ func (os *OauthService) GoogleCallback(code string) (error error, userData *Goog
|
||||
client := oauthConfig.Client(context.Background(), token)
|
||||
resp, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo")
|
||||
if err != nil {
|
||||
global.Logger.Warn("failed getting user info: %s\n", err)
|
||||
global.Logger.Warn("failed getting user info: ", err)
|
||||
error = errors.New("GetOauthUserInfoError")
|
||||
return
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
err := Body.Close()
|
||||
if err != nil {
|
||||
global.Logger.Warn("failed closing response body: %s\n", err)
|
||||
global.Logger.Warn("failed closing response body: ", err)
|
||||
}
|
||||
}(resp.Body)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ type Service struct {
|
||||
*GroupService
|
||||
*OauthService
|
||||
*LoginLogService
|
||||
*AuditService
|
||||
}
|
||||
|
||||
func New() *Service {
|
||||
|
||||
@@ -21,6 +21,11 @@ func (us *UserService) InfoById(id uint) *model.User {
|
||||
global.DB.Where("id = ?", id).First(u)
|
||||
return u
|
||||
}
|
||||
func (us *UserService) InfoByUsername(un string) *model.User {
|
||||
u := &model.User{}
|
||||
global.DB.Where("username = ?", un).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
// InfoByOpenid 根据openid取用户信息
|
||||
func (us *UserService) InfoByOpenid(openid string) *model.User {
|
||||
@@ -262,3 +267,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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user