Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a951b982b3 | ||
|
|
a33be66504 | ||
|
|
f41b9d5887 | ||
|
|
3c608463e6 | ||
|
|
eeffbe124a | ||
|
|
d7f2d54faa | ||
|
|
7db4b03634 | ||
|
|
77760a681a | ||
|
|
f9c1447ceb | ||
|
|
fb749c1902 |
@@ -1,4 +1,4 @@
|
|||||||
FROM rustdesk/rustdesk-server-s6:latest as server
|
FROM rustdesk/rustdesk-server-s6:latest AS server
|
||||||
|
|
||||||
FROM alpine
|
FROM alpine
|
||||||
|
|
||||||
|
|||||||
73
README.md
@@ -34,6 +34,7 @@
|
|||||||
- 快速使用web client
|
- 快速使用web client
|
||||||
- i18n
|
- i18n
|
||||||
- 通过 web client 分享给游客
|
- 通过 web client 分享给游客
|
||||||
|
- server控制(一些官方的简单的指令 [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
||||||
- Web Client
|
- Web Client
|
||||||
- 自动获取API server
|
- 自动获取API server
|
||||||
- 自动获取ID服务器和KEY
|
- 自动获取ID服务器和KEY
|
||||||
@@ -75,14 +76,14 @@
|
|||||||
2. 普通用户界面
|
2. 普通用户界面
|
||||||

|

|
||||||
右上角可以更改密码,可以切换语言,可以切换`白天/黑夜`模式
|
右上角可以更改密码,可以切换语言,可以切换`白天/黑夜`模式
|
||||||
|
|
||||||

|

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

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

|

|
||||||
5. Oauth,支持了`Github`, `Google` 以及 `OIDC`, 需要创建一个`OAuth App`,然后配置到后台
|
6. Oauth,支持了`Github`, `Google` 以及 `OIDC`, 需要创建一个`OAuth App`,然后配置到后台
|
||||||

|

|
||||||
- 对于`Google` 和 `Github`, `Issuer` 和 `Scopes`不需要填写.
|
- 对于`Google` 和 `Github`, `Issuer` 和 `Scopes`不需要填写.
|
||||||
- 对于`OIDC`, `Issuer`是必须的。`Scopes`是可选的,默认为 `openid,profile,email`. 确保可以获取 `sub`,`email` 和`preferred_username`
|
- 对于`OIDC`, `Issuer`是必须的。`Scopes`是可选的,默认为 `openid,profile,email`. 确保可以获取 `sub`,`email` 和`preferred_username`
|
||||||
@@ -90,6 +91,21 @@
|
|||||||
中创建,地址 [https://github.com/settings/developers](https://github.com/settings/developers)
|
中创建,地址 [https://github.com/settings/developers](https://github.com/settings/developers)
|
||||||
- `Authorization callback URL`填写`http://<your server[:port]>/api/oauth/callback`
|
- `Authorization callback URL`填写`http://<your server[:port]>/api/oauth/callback`
|
||||||
,比如`http://127.0.0.1:21114/api/oauth/callback`
|
,比如`http://127.0.0.1:21114/api/oauth/callback`
|
||||||
|
7. 登录日志
|
||||||
|
8. 链接日志
|
||||||
|
9. 文件传输日志
|
||||||
|
10. server控制
|
||||||
|
|
||||||
|
- `简易模式`,已经界面化了一些简单的指令,可以直接在后台执行
|
||||||
|

|
||||||
|
|
||||||
|
- `高级模式`,直接在后台执行指令
|
||||||
|
* 可以官方指令
|
||||||
|
* 可以添加自定义指令
|
||||||
|
* 可以执行自定义指令
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
### Web Client:
|
### Web Client:
|
||||||
|
|
||||||
@@ -160,6 +176,9 @@ logger:
|
|||||||
proxy:
|
proxy:
|
||||||
enable: false
|
enable: false
|
||||||
host: ""
|
host: ""
|
||||||
|
jwt:
|
||||||
|
key: ""
|
||||||
|
expire-duration: 360000
|
||||||
```
|
```
|
||||||
|
|
||||||
### 环境变量
|
### 环境变量
|
||||||
@@ -198,6 +217,9 @@ proxy:
|
|||||||
| ----PROXY配置----- | --------------- | ---------- |
|
| ----PROXY配置----- | --------------- | ---------- |
|
||||||
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
|
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
|
||||||
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
|
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
|
||||||
|
| ----JWT配置---- | -------- | -------- |
|
||||||
|
| RUSTDESK_API_JWT_KEY | 自定义JWT KEY,为空则不启用JWT | |
|
||||||
|
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT有效时间 | 360000 |
|
||||||
|
|
||||||
|
|
||||||
### 运行
|
### 运行
|
||||||
@@ -263,8 +285,49 @@ proxy:
|
|||||||
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
||||||
|
|
||||||
|
|
||||||
|
#### 使用我fork后的server-s6镜像运行
|
||||||
|
|
||||||
|
- github https://github.com/lejianwen/rustdesk-server
|
||||||
|
- docker hub https://hub.docker.com/r/lejianwen/rustdesk-server-s6
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
networks:
|
||||||
|
rustdesk-net:
|
||||||
|
external: false
|
||||||
|
services:
|
||||||
|
rustdesk:
|
||||||
|
ports:
|
||||||
|
- 21114:21114
|
||||||
|
- 21115:21115
|
||||||
|
- 21116:21116
|
||||||
|
- 21116:21116/udp
|
||||||
|
- 21117:21117
|
||||||
|
- 21118:21118
|
||||||
|
- 21119:21119
|
||||||
|
image: lejianwen/rustdesk-server-s6:latest
|
||||||
|
environment:
|
||||||
|
- RELAY=<relay_server[:port]>
|
||||||
|
- ENCRYPTED_ONLY=1
|
||||||
|
- MUST_LOGIN=N
|
||||||
|
- TZ=Asia/Shanghai
|
||||||
|
- RUSTDESK_API_RUSTDESK_ID_SERVER=<id_server[:21116]>
|
||||||
|
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=<relay_server[:21117]>
|
||||||
|
- RUSTDESK_API_RUSTDESK_API_SERVER=http://<api_server[:21114]>
|
||||||
|
- RUSTDESK_API_KEY_FILE=/data/id_ed25519.pub
|
||||||
|
- RUSTDESK_API_JWT_KEY=xxxxxx # jwt key
|
||||||
|
volumes:
|
||||||
|
- /data/rustdesk/server:/data
|
||||||
|
- /data/rustdesk/api:/app/data #将数据库挂载
|
||||||
|
networks:
|
||||||
|
- rustdesk-net
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 其他
|
## 其他
|
||||||
|
|
||||||
|
- [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
- [链接超时问题](https://github.com/lejianwen/rustdesk-api/issues/92)
|
- [链接超时问题](https://github.com/lejianwen/rustdesk-api/issues/92)
|
||||||
- [修改客户端ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
- [修改客户端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)
|
||||||
73
README_EN.md
@@ -33,6 +33,7 @@ desktop software that provides self-hosted solutions.
|
|||||||
- Quick access to web client
|
- Quick access to web client
|
||||||
- i18n
|
- i18n
|
||||||
- Share to guest by web client
|
- Share to guest by web client
|
||||||
|
- Server control (some simple official commands [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
||||||
- Web Client
|
- Web Client
|
||||||
- Automatically obtain API server
|
- Automatically obtain API server
|
||||||
- Automatically obtain ID server and KEY
|
- Automatically obtain ID server and KEY
|
||||||
@@ -78,12 +79,11 @@ installation are `admin` `admin`, please change the password immediately.
|
|||||||
In the top right corner, you can change the password, switch languages, and toggle between `day/night` mode.
|
In the top right corner, you can change the password, switch languages, and toggle between `day/night` mode.
|
||||||
|
|
||||||

|

|
||||||
3. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
|
3. Each user can have multiple address books, which can also be shared with other users.
|
||||||

|
4. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
|
||||||
4. You can directly launch the client or open the web client for convenience; you can also share it with guests, who can remotely access the device via the web client.
|
5. You can directly launch the client or open the web client for convenience; you can also share it with guests, who can remotely access the device via the web client.
|
||||||
|
|
||||||

|

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

|

|
||||||
- For `Google` and `Github`, you don't need to fill the `Issuer` and `Scpoes`
|
- For `Google` and `Github`, you don't need to fill the `Issuer` and `Scpoes`
|
||||||
@@ -93,6 +93,23 @@ installation are `admin` `admin`, please change the password immediately.
|
|||||||
- Set the `Authorization callback URL` to `http://<your server[:port]>/api/oauth/callback`,
|
- Set the `Authorization callback URL` to `http://<your server[:port]>/api/oauth/callback`,
|
||||||
e.g., `http://127.0.0.1:21114/api/oauth/callback`.
|
e.g., `http://127.0.0.1:21114/api/oauth/callback`.
|
||||||
|
|
||||||
|
7. Login logs
|
||||||
|
8. Connection logs
|
||||||
|
9. File transfer logs
|
||||||
|
10. Server control
|
||||||
|
|
||||||
|
- `Simple mode`, some simple commands have been GUI-ized and can be executed directly in the backend
|
||||||
|

|
||||||
|
|
||||||
|
- `Advanced mode`, commands can be executed directly in the backend
|
||||||
|
* Official commands can be used
|
||||||
|
* Custom commands can be added
|
||||||
|
* Custom commands can be executed
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Web Client:
|
### Web Client:
|
||||||
|
|
||||||
1. If you're already logged into the admin panel, the web client will log in automatically.
|
1. If you're already logged into the admin panel, the web client will log in automatically.
|
||||||
@@ -162,13 +179,16 @@ logger:
|
|||||||
proxy:
|
proxy:
|
||||||
enable: false
|
enable: false
|
||||||
host: ""
|
host: ""
|
||||||
|
jwt:
|
||||||
|
key: ""
|
||||||
|
expire-duration: 360000
|
||||||
```
|
```
|
||||||
|
|
||||||
### Environment Variables
|
### Environment Variables
|
||||||
The prefix for variable names is `RUSTDESK_API`. If environment variables exist, they will override the configurations in the configuration file.
|
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 |
|
| Variable Name | Description | Example |
|
||||||
|-----------------------------------------------------|--------------------------------------------------------------------------------------------------------------|-------------------------------|
|
|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------|-------------------------------|
|
||||||
| TZ | timezone | Asia/Shanghai |
|
| TZ | timezone | Asia/Shanghai |
|
||||||
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
||||||
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, default: 1 | 1 |
|
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, default: 1 | 1 |
|
||||||
@@ -200,6 +220,9 @@ The prefix for variable names is `RUSTDESK_API`. If environment variables exist,
|
|||||||
| ---- PROXY ----- | --------------- | ---------- |
|
| ---- PROXY ----- | --------------- | ---------- |
|
||||||
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
|
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
|
||||||
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
|
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
|
||||||
|
| ----JWT---- | -------- | -------- |
|
||||||
|
| RUSTDESK_API_JWT_KEY | JWT KEY. Set empty to disable jwt | |
|
||||||
|
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT expire duration | 360000 |
|
||||||
|
|
||||||
### Installation Steps
|
### Installation Steps
|
||||||
|
|
||||||
@@ -268,9 +291,47 @@ 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
|
6. Open your browser and visit `http://<your server[:port]>/_admin/`, with default credentials `admin admin`. Please
|
||||||
change the password promptly.
|
change the password promptly.
|
||||||
|
|
||||||
|
#### Running with my forked server-s6 image
|
||||||
|
|
||||||
|
- github https://github.com/lejianwen/rustdesk-server
|
||||||
|
- docker hub https://hub.docker.com/r/lejianwen/rustdesk-server-s6
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
networks:
|
||||||
|
rustdesk-net:
|
||||||
|
external: false
|
||||||
|
services:
|
||||||
|
rustdesk:
|
||||||
|
ports:
|
||||||
|
- 21114:21114
|
||||||
|
- 21115:21115
|
||||||
|
- 21116:21116
|
||||||
|
- 21116:21116/udp
|
||||||
|
- 21117:21117
|
||||||
|
- 21118:21118
|
||||||
|
- 21119:21119
|
||||||
|
image: lejianwen/rustdesk-server-s6:latest
|
||||||
|
environment:
|
||||||
|
- RELAY=<relay_server[:port]>
|
||||||
|
- ENCRYPTED_ONLY=1
|
||||||
|
- MUST_LOGIN=N
|
||||||
|
- TZ=Asia/Shanghai
|
||||||
|
- RUSTDESK_API_RUSTDESK_ID_SERVER=<id_server[:21116]>
|
||||||
|
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=<relay_server[:21117]>
|
||||||
|
- RUSTDESK_API_RUSTDESK_API_SERVER=http://<api_server[:21114]>
|
||||||
|
- RUSTDESK_API_KEY_FILE=/data/id_ed25519.pub
|
||||||
|
- RUSTDESK_API_JWT_KEY=xxxxxx # jwt key
|
||||||
|
volumes:
|
||||||
|
- /data/rustdesk/server:/data
|
||||||
|
- /data/rustdesk/api:/app/data #将数据库挂载
|
||||||
|
networks:
|
||||||
|
- rustdesk-net
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
```
|
||||||
## Others
|
## Others
|
||||||
|
|
||||||
|
- [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
- [Connection Timeout](https://github.com/lejianwen/rustdesk-api/issues/92)
|
- [Connection Timeout](https://github.com/lejianwen/rustdesk-api/issues/92)
|
||||||
- [Change client ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
- [Change client ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
||||||
- [Web client source](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
- [Web client source](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"Gwen/global"
|
"Gwen/global"
|
||||||
"Gwen/http"
|
"Gwen/http"
|
||||||
"Gwen/lib/cache"
|
"Gwen/lib/cache"
|
||||||
|
"Gwen/lib/jwt"
|
||||||
"Gwen/lib/lock"
|
"Gwen/lib/lock"
|
||||||
"Gwen/lib/logger"
|
"Gwen/lib/logger"
|
||||||
"Gwen/lib/orm"
|
"Gwen/lib/orm"
|
||||||
@@ -17,6 +18,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @title 管理系统API
|
// @title 管理系统API
|
||||||
@@ -163,13 +165,13 @@ func InitGlobal() {
|
|||||||
|
|
||||||
//jwt
|
//jwt
|
||||||
//fmt.Println(global.Config.Jwt.PrivateKey)
|
//fmt.Println(global.Config.Jwt.PrivateKey)
|
||||||
//global.Jwt = jwt.NewJwt(global.Config.Jwt.PrivateKey, global.Config.Jwt.ExpireDuration*time.Second)
|
global.Jwt = jwt.NewJwt(global.Config.Jwt.Key, global.Config.Jwt.ExpireDuration*time.Second)
|
||||||
|
|
||||||
//locker
|
//locker
|
||||||
global.Lock = lock.NewLocal()
|
global.Lock = lock.NewLocal()
|
||||||
}
|
}
|
||||||
func DatabaseAutoUpdate() {
|
func DatabaseAutoUpdate() {
|
||||||
version := 251
|
version := 260
|
||||||
|
|
||||||
db := global.DB
|
db := global.DB
|
||||||
|
|
||||||
|
|||||||
@@ -26,16 +26,19 @@ rustdesk:
|
|||||||
relay-server: "192.168.1.66:21117"
|
relay-server: "192.168.1.66:21117"
|
||||||
api-server: "http://127.0.0.1:21114"
|
api-server: "http://127.0.0.1:21114"
|
||||||
key: ""
|
key: ""
|
||||||
key-file: "./conf/data/id_ed25519.pub"
|
key-file: "/data/id_ed25519.pub"
|
||||||
personal: 1
|
personal: 1
|
||||||
webclient-magic-queryonline: 0
|
webclient-magic-queryonline: 0
|
||||||
logger:
|
logger:
|
||||||
path: "./runtime/log.txt"
|
path: "./runtime/log.txt"
|
||||||
level: "warn" #trace,debug,info,warn,error,fatal
|
level: "debug" #trace,debug,info,warn,error,fatal
|
||||||
report-caller: true
|
report-caller: true
|
||||||
proxy:
|
proxy:
|
||||||
enable: false
|
enable: false
|
||||||
host: "http://127.0.0.1:1080"
|
host: "http://127.0.0.1:1080"
|
||||||
|
jwt:
|
||||||
|
key: ""
|
||||||
|
expire-duration: 360000
|
||||||
redis:
|
redis:
|
||||||
addr: "127.0.0.1:6379"
|
addr: "127.0.0.1:6379"
|
||||||
password: ""
|
password: ""
|
||||||
@@ -53,6 +56,4 @@ oss:
|
|||||||
callback-url: ""
|
callback-url: ""
|
||||||
expire-time: 30
|
expire-time: 30
|
||||||
max-byte: 10240
|
max-byte: 10240
|
||||||
jwt:
|
|
||||||
private-key: "./conf/jwt_pri.pem"
|
|
||||||
expire-duration: 360000
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ package config
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Jwt struct {
|
type Jwt struct {
|
||||||
PrivateKey string `mapstructure:"private-key"`
|
Key string `mapstructure:"key"`
|
||||||
ExpireDuration time.Duration `mapstructure:"expire-duration"`
|
ExpireDuration time.Duration `mapstructure:"expire-duration"`
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
docs/en_img/rustdesk_command_advance.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
docs/en_img/rustdesk_command_simple.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 19 KiB |
BIN
docs/rustdesk_command_advance.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
docs/rustdesk_command_simple.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 48 KiB |
@@ -15,6 +15,7 @@ type Rustdesk struct {
|
|||||||
type RustdeskCmd struct {
|
type RustdeskCmd struct {
|
||||||
Cmd string `json:"cmd"`
|
Cmd string `json:"cmd"`
|
||||||
Option string `json:"option"`
|
Option string `json:"option"`
|
||||||
|
Target string `json:"target"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rustdesk) CmdList(c *gin.Context) {
|
func (r *Rustdesk) CmdList(c *gin.Context) {
|
||||||
@@ -26,7 +27,8 @@ func (r *Rustdesk) CmdList(c *gin.Context) {
|
|||||||
res := service.AllService.ServerCmdService.List(q.Page, 9999)
|
res := service.AllService.ServerCmdService.List(q.Page, 9999)
|
||||||
//在列表前添加系统命令
|
//在列表前添加系统命令
|
||||||
list := make([]*model.ServerCmd, 0)
|
list := make([]*model.ServerCmd, 0)
|
||||||
list = append(list, model.SysServerCmds...)
|
list = append(list, model.SysIdServerCmds...)
|
||||||
|
list = append(list, model.SysRelayServerCmds...)
|
||||||
list = append(list, res.ServerCmds...)
|
list = append(list, res.ServerCmds...)
|
||||||
res.ServerCmds = list
|
res.ServerCmds = list
|
||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
@@ -101,12 +103,23 @@ func (r *Rustdesk) CmdUpdate(c *gin.Context) {
|
|||||||
|
|
||||||
func (r *Rustdesk) SendCmd(c *gin.Context) {
|
func (r *Rustdesk) SendCmd(c *gin.Context) {
|
||||||
rc := &RustdeskCmd{}
|
rc := &RustdeskCmd{}
|
||||||
c.ShouldBindJSON(rc)
|
if err := c.ShouldBindJSON(rc); err != nil {
|
||||||
if rc.Cmd == "" {
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
response.Fail(c, 101, "cmd is required")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res, err := service.AllService.ServerCmdService.SendCmd(rc.Cmd, rc.Option)
|
if rc.Cmd == "" {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rc.Target == "" {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rc.Target != model.ServerCmdTargetIdServer && rc.Target != model.ServerCmdTargetRelayServer {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := service.AllService.ServerCmdService.SendCmd(rc.Target, rc.Cmd, rc.Option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, err.Error())
|
response.Fail(c, 101, err.Error())
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"Gwen/global"
|
||||||
"Gwen/service"
|
"Gwen/service"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -27,7 +28,21 @@ func RustAuth() gin.HandlerFunc {
|
|||||||
//提取token,格式是Bearer {token}
|
//提取token,格式是Bearer {token}
|
||||||
//这里只是简单的提取
|
//这里只是简单的提取
|
||||||
token = token[7:]
|
token = token[7:]
|
||||||
|
|
||||||
//验证token
|
//验证token
|
||||||
|
|
||||||
|
//检查是否设置了jwt key
|
||||||
|
if len(global.Jwt.Key) > 0 {
|
||||||
|
uid, _ := service.AllService.UserService.VerifyJWT(token)
|
||||||
|
if uid == 0 {
|
||||||
|
c.JSON(401, gin.H{
|
||||||
|
"error": "Unauthorized",
|
||||||
|
})
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user, ut := service.AllService.UserService.InfoByAccessToken(token)
|
user, ut := service.AllService.UserService.InfoByAccessToken(token)
|
||||||
if user.Id == 0 {
|
if user.Id == 0 {
|
||||||
c.JSON(401, gin.H{
|
c.JSON(401, gin.H{
|
||||||
@@ -38,7 +53,7 @@ func RustAuth() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
if !service.AllService.UserService.CheckUserEnable(user) {
|
if !service.AllService.UserService.CheckUserEnable(user) {
|
||||||
c.JSON(401, gin.H{
|
c.JSON(401, gin.H{
|
||||||
"error": "账号已被禁用",
|
"error": "Unauthorized",
|
||||||
})
|
})
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package jwt
|
package jwt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
"fmt"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Jwt struct {
|
type Jwt struct {
|
||||||
privateKey *rsa.PrivateKey
|
Key []byte
|
||||||
TokenExpireDuration time.Duration
|
TokenExpireDuration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,31 +16,28 @@ type UserClaims struct {
|
|||||||
jwt.RegisteredClaims
|
jwt.RegisteredClaims
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewJwt(privateKeyFile string, tokenExpireDuration time.Duration) *Jwt {
|
func NewJwt(key string, tokenExpireDuration time.Duration) *Jwt {
|
||||||
privateKeyContent, err := os.ReadFile(privateKeyFile)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(privateKeyContent)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return &Jwt{
|
return &Jwt{
|
||||||
privateKey: privateKey,
|
Key: []byte(key),
|
||||||
TokenExpireDuration: tokenExpireDuration,
|
TokenExpireDuration: tokenExpireDuration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Jwt) GenerateToken(userId uint) string {
|
func (s *Jwt) GenerateToken(userId uint) string {
|
||||||
t := jwt.NewWithClaims(jwt.SigningMethodRS256,
|
if len(s.Key) == 0 {
|
||||||
|
fmt.Println("jwt key is nil")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
t := jwt.NewWithClaims(jwt.SigningMethodHS256,
|
||||||
UserClaims{
|
UserClaims{
|
||||||
UserId: userId,
|
UserId: userId,
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(s.TokenExpireDuration)),
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(s.TokenExpireDuration)),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
token, err := t.SignedString(s.privateKey)
|
token, err := t.SignedString(s.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Printf("jwt token generate error: %v", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return token
|
return token
|
||||||
@@ -49,7 +45,7 @@ func (s *Jwt) GenerateToken(userId uint) string {
|
|||||||
|
|
||||||
func (s *Jwt) ParseToken(tokenString string) (uint, error) {
|
func (s *Jwt) ParseToken(tokenString string) (uint, error) {
|
||||||
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
|
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
return s.privateKey.Public(), nil
|
return s.Key, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ type ServerCmd struct {
|
|||||||
Alias string `json:"alias" gorm:"default:'';not null;"`
|
Alias string `json:"alias" gorm:"default:'';not null;"`
|
||||||
Option string `json:"option" gorm:"default:'';not null;"`
|
Option string `json:"option" gorm:"default:'';not null;"`
|
||||||
Explain string `json:"explain" gorm:"default:'';not null;"`
|
Explain string `json:"explain" gorm:"default:'';not null;"`
|
||||||
|
Target string `json:"target" gorm:"default:'';not null;"`
|
||||||
TimeModel
|
TimeModel
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,11 +15,47 @@ type ServerCmdList struct {
|
|||||||
Pagination
|
Pagination
|
||||||
}
|
}
|
||||||
|
|
||||||
var SysServerCmds = []*ServerCmd{
|
const (
|
||||||
{Cmd: "h", Option: "", Explain: "show help"},
|
ServerCmdTargetIdServer = "21115"
|
||||||
{Cmd: "relay-servers", Alias: "rs", Option: "<separated by ,>", Explain: "set or show relay servers"},
|
ServerCmdTargetRelayServer = "21117"
|
||||||
{Cmd: "ip-blocker", Alias: "ib", Option: "[<ip>|<number>] [-]", Explain: "block or unblock ip or show blocked ip"},
|
)
|
||||||
{Cmd: "ip-changes", Alias: "ic", Option: "[<id>|<number>] [-]", Explain: "ip-changes(ic) [<id>|<number>] [-]"},
|
|
||||||
{Cmd: "always-use-relay(aur)", Alias: "aur", Option: "[y|n]", Explain: "always use relay"},
|
var SysIdServerCmds = []*ServerCmd{
|
||||||
{Cmd: "test-geo", Alias: "tg", Option: "<ip1> <ip2>", Explain: "test geo"},
|
{Cmd: "h", Option: "", Explain: "show help", Target: ServerCmdTargetIdServer},
|
||||||
|
{Cmd: "relay-servers", Alias: "rs", Option: "<separated by ,>", Explain: "set or show relay servers", Target: ServerCmdTargetIdServer},
|
||||||
|
{Cmd: "ip-blocker", Alias: "ib", Option: "[<ip>|<number>] [-]", Explain: "block or unblock ip or show blocked ip", Target: ServerCmdTargetIdServer},
|
||||||
|
{Cmd: "ip-changes", Alias: "ic", Option: "[<id>|<number>] [-]", Explain: "ip-changes(ic) [<id>|<number>] [-]", Target: ServerCmdTargetIdServer},
|
||||||
|
{Cmd: "always-use-relay", Alias: "aur", Option: "[y|n]", Explain: "always use relay", Target: ServerCmdTargetIdServer},
|
||||||
|
{Cmd: "test-geo", Alias: "tg", Option: "<ip1> <ip2>", Explain: "test geo", Target: ServerCmdTargetIdServer},
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
"blacklist-add(ba) <ip>",
|
||||||
|
"blacklist-remove(br) <ip>",
|
||||||
|
"blacklist(b) <ip>",
|
||||||
|
"blocklist-add(Ba) <ip>",
|
||||||
|
"blocklist-remove(Br) <ip>",
|
||||||
|
"blocklist(B) <ip>",
|
||||||
|
"downgrade-threshold(dt) [value]",
|
||||||
|
"downgrade-start-check(t) [value(second)]",
|
||||||
|
"limit-speed(ls) [value(Mb/s)]",
|
||||||
|
"total-bandwidth(tb) [value(Mb/s)]",
|
||||||
|
"single-bandwidth(sb) [value(Mb/s)]",
|
||||||
|
"usage(u)"
|
||||||
|
*/
|
||||||
|
|
||||||
|
var SysRelayServerCmds = []*ServerCmd{
|
||||||
|
{Cmd: "h", Option: "", Explain: "show help", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "blacklist-add", Alias: "ba", Option: "<ip>", Explain: "blacklist-add(ba) <ip>", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "blacklist-remove", Alias: "br", Option: "<ip>", Explain: "blacklist-remove(br) <ip>", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "blacklist", Alias: "b", Option: "<ip>", Explain: "blacklist(b) <ip>", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "blocklist-add", Alias: "Ba", Option: "<ip>", Explain: "blocklist-add(Ba) <ip>", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "blocklist-remove", Alias: "Br", Option: "<ip>", Explain: "blocklist-remove(Br) <ip>", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "blocklist", Alias: "B", Option: "<ip>", Explain: "blocklist(B) <ip>", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "downgrade-threshold", Alias: "dt", Option: "[value]", Explain: "downgrade-threshold(dt) [value]", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "downgrade-start-check", Alias: "t", Option: "[value(second)]", Explain: "downgrade-start-check(t) [value(second)]", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "limit-speed", Alias: "ls", Option: "[value(Mb/s)]", Explain: "limit-speed(ls) [value(Mb/s)]", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "total-bandwidth", Alias: "tb", Option: "[value(Mb/s)]", Explain: "total-bandwidth(tb) [value(Mb/s)]", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "single-bandwidth", Alias: "sb", Option: "[value(Mb/s)]", Explain: "single-bandwidth(sb) [value(Mb/s)]", Target: ServerCmdTargetRelayServer},
|
||||||
|
{Cmd: "usage", Alias: "u", Option: "", Explain: "usage(u)", Target: ServerCmdTargetRelayServer},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,15 +41,15 @@ func (is *ServerCmdService) Create(u *model.ServerCmd) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendCmd 发送命令
|
// SendCmd 发送命令
|
||||||
func (is *ServerCmdService) SendCmd(cmd string, arg string) (string, error) {
|
func (is *ServerCmdService) SendCmd(port string, cmd string, arg string) (string, error) {
|
||||||
//组装命令
|
//组装命令
|
||||||
cmd = cmd + " " + arg
|
cmd = cmd + " " + arg
|
||||||
res, err := is.SendSocketCmd("v6", cmd)
|
res, err := is.SendSocketCmd("v6", port, cmd)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
//v6连接失败,尝试v4
|
//v6连接失败,尝试v4
|
||||||
res, err = is.SendSocketCmd("v4", cmd)
|
res, err = is.SendSocketCmd("v4", port, cmd)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
@@ -57,23 +57,23 @@ func (is *ServerCmdService) SendCmd(cmd string, arg string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendSocketCmd
|
// SendSocketCmd
|
||||||
func (is *ServerCmdService) SendSocketCmd(ty string, cmd string) (string, error) {
|
func (is *ServerCmdService) SendSocketCmd(ty string, port string, cmd string) (string, error) {
|
||||||
addr := "[::1]"
|
addr := "[::1]"
|
||||||
tcp := "tcp6"
|
tcp := "tcp6"
|
||||||
if ty == "v4" {
|
if ty == "v4" {
|
||||||
tcp = "tcp"
|
tcp = "tcp"
|
||||||
addr = "127.0.0.1"
|
addr = "127.0.0.1"
|
||||||
}
|
}
|
||||||
conn, err := net.Dial(tcp, addr+":21115")
|
conn, err := net.Dial(tcp, fmt.Sprintf("%s:%s", addr, port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("connect to id %s server failed: %v\n", ty, err)
|
global.Logger.Debugf("%s connect to id server failed: %v", ty, err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
//发送命令
|
//发送命令
|
||||||
_, err = conn.Write([]byte(cmd))
|
_, err = conn.Write([]byte(cmd))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("send cmd failed: %v\n", err)
|
global.Logger.Debugf("%s send cmd failed: %v", ty, err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
@@ -81,7 +81,7 @@ func (is *ServerCmdService) SendSocketCmd(ty string, cmd string) (string, error)
|
|||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
n, err := conn.Read(buf)
|
n, err := conn.Read(buf)
|
||||||
if err != nil && err.Error() != "EOF" {
|
if err != nil && err.Error() != "EOF" {
|
||||||
fmt.Printf("read response failed: %v\n", err)
|
global.Logger.Debugf("%s read response failed: %v", ty, err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(buf[:n]), nil
|
return string(buf[:n]), nil
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ func (us *UserService) InfoByAccessToken(token string) (*model.User, *model.User
|
|||||||
|
|
||||||
// GenerateToken 生成token
|
// GenerateToken 生成token
|
||||||
func (us *UserService) GenerateToken(u *model.User) string {
|
func (us *UserService) GenerateToken(u *model.User) string {
|
||||||
|
if len(global.Jwt.Key) > 0 {
|
||||||
|
return global.Jwt.GenerateToken(u.Id)
|
||||||
|
}
|
||||||
return utils.Md5(u.Username + time.Now().String())
|
return utils.Md5(u.Username + time.Now().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,3 +464,7 @@ func (us *UserService) AutoRefreshAccessToken(ut *model.UserToken) {
|
|||||||
func (us *UserService) BatchDeleteUserToken(ids []uint) error {
|
func (us *UserService) BatchDeleteUserToken(ids []uint) error {
|
||||||
return global.DB.Where("id in ?", ids).Delete(&model.UserToken{}).Error
|
return global.DB.Where("id in ?", ids).Delete(&model.UserToken{}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (us *UserService) VerifyJWT(token string) (uint, error) {
|
||||||
|
return global.Jwt.ParseToken(token)
|
||||||
|
}
|
||||||
|
|||||||