Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee0cbabffc | ||
|
|
d6a5af890a | ||
|
|
dc313441e5 | ||
|
|
c75320f4f4 | ||
|
|
c788f78416 | ||
|
|
49cf954d4a | ||
|
|
014e3db54f | ||
|
|
6d9c245c81 | ||
|
|
7fa9b79f31 | ||
|
|
c7f3d13b7f | ||
|
|
46f08a89d2 | ||
|
|
0dcfedb4dc | ||
|
|
918bf85a2d | ||
|
|
99db5f7190 | ||
|
|
18eff791b2 | ||
|
|
624dcacac5 | ||
|
|
878d5fd27c | ||
|
|
4b893ce0e8 | ||
|
|
472524f836 | ||
|
|
dbf8b23b15 | ||
|
|
79a5dd53ae | ||
|
|
8a5b20685c | ||
|
|
5a9c972de0 | ||
|
|
fc0e67122d | ||
|
|
eb642f66ca | ||
|
|
8cac15f7dd | ||
|
|
5011e2b7c1 | ||
|
|
b0008143b1 | ||
|
|
a3c3ab5a72 | ||
|
|
3a16269215 | ||
|
|
151145b0c3 |
134
README.md
134
README.md
@@ -4,11 +4,12 @@
|
||||
|
||||
本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web Admin 和 Web 客户端。RustDesk 是一个远程桌面软件,提供了自托管的解决方案。
|
||||
|
||||
<div align=center>
|
||||
<div align=center>
|
||||
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
||||
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
|
||||
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
|
||||
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
|
||||
<img src="https://goreportcard.com/badge/github.com/lejianwen/rustdesk-api/v2"/>
|
||||
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +20,10 @@
|
||||
- 登录
|
||||
- 地址簿
|
||||
- 群组
|
||||
- 授权登录,支持`github`, `google` 和 `OIDC` 登录,支持`web后台`授权登录
|
||||
- 授权登录
|
||||
- 支持`github`, `google` 和 `OIDC` 登录,
|
||||
- 支持`web后台`授权登录
|
||||
- 支持`LDAP`(AD和OpenLDAP已测试), 如果API Server配置了LDAP
|
||||
- i18n
|
||||
- Web Admin
|
||||
- 用户管理
|
||||
@@ -28,6 +32,7 @@
|
||||
- 标签管理
|
||||
- 群组管理
|
||||
- Oauth 管理
|
||||
- 配置LDAP, 配置文件或者环境变量
|
||||
- 登录日志
|
||||
- 链接日志
|
||||
- 文件传输日志
|
||||
@@ -46,6 +51,7 @@
|
||||
|
||||
## 功能
|
||||
|
||||
|
||||
### API 服务
|
||||
基本实现了PC端基础的接口。支持Personal版本接口,可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
|
||||
|
||||
@@ -70,23 +76,20 @@
|
||||
|
||||
* 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
||||
|
||||
* 后台访问地址是`http://<your server>[:port]/_admin/`初次安装管理员为用户名密码为`admin` `admin`,请即时更改密码
|
||||
* 后台访问地址是`http://<your server>[:port]/_admin/`
|
||||
* 初次安装管理员为用户名为`admin`,密码将在控制台打印,可以通过[命令行](#CLI)更改密码
|
||||
|
||||

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

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

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

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

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

|
||||
- 对于`Google` 和 `Github`, `Issuer` 和 `Scopes`不需要填写.
|
||||
- 对于`OIDC`, `Issuer`是必须的。`Scopes`是可选的,默认为 `openid,profile,email`. 确保可以获取 `sub`,`email` 和`preferred_username`
|
||||
- `github oauth app`在`Settings`->`Developer settings`->`OAuth Apps`->`New OAuth App`
|
||||
@@ -108,6 +111,7 @@
|
||||
|
||||

|
||||
|
||||
11. **LDAP 支持**, 当在API Server上设置了LDAP(已测试AD和LDAP),可以通过LDAP中的用户信息进行登录 https://github.com/lejianwen/rustdesk-api/issues/114 ,如果LDAP验证失败,返回本地用户
|
||||
|
||||
### Web Client:
|
||||
|
||||
@@ -127,6 +131,7 @@
|
||||

|
||||
|
||||
### CLI
|
||||
|
||||
```bash
|
||||
# 查看帮助
|
||||
./apimain -h
|
||||
@@ -151,6 +156,9 @@ app:
|
||||
web-client: 1 # 1:启用 0:禁用
|
||||
register: false #是否开启注册
|
||||
show-swagger: 0 #是否显示swagger文档
|
||||
web-sso: true #是否显示web sso
|
||||
token-expire: 168h #token有效时长
|
||||
disable-pwd-login: false #是否禁用密码登录
|
||||
gin:
|
||||
api-addr: "0.0.0.0:21114"
|
||||
mode: "release"
|
||||
@@ -180,49 +188,72 @@ proxy:
|
||||
host: ""
|
||||
jwt:
|
||||
key: ""
|
||||
expire-duration: 360000
|
||||
expire-duration: 168h
|
||||
ldap:
|
||||
enable: false
|
||||
url: "ldap://ldap.example.com:389"
|
||||
tls: false
|
||||
tls-verify: false
|
||||
base-dn: "dc=example,dc=com"
|
||||
bind-dn: "cn=admin,dc=example,dc=com"
|
||||
bind-password: "password"
|
||||
|
||||
user:
|
||||
base-dn: "ou=users,dc=example,dc=com"
|
||||
enable-attr: "" #The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
|
||||
enable-attr-value: "" # The value of the enable attribute when the user is enabled. If you are using AD, just set random value, it will be ignored.
|
||||
filter: "(cn=*)"
|
||||
username: "uid" # The attribute name of the user for usernamem if you are using AD, it should be "sAMAccountName"
|
||||
email: "mail"
|
||||
first-name: "givenName"
|
||||
last-name: "sn"
|
||||
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
|
||||
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
|
||||
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
变量名前缀是`RUSTDESK_API`,环境变量如果存在将覆盖配置文件中的配置
|
||||
环境变量和配置文件`conf/config.yaml`中的配置一一对应,变量名前缀是`RUSTDESK_API`
|
||||
下面表格并未全部列出,可以参考`conf/config.yaml`中的配置。
|
||||
|
||||
| 变量名 | 说明 | 示例 |
|
||||
|---------------------------------------------------|---------------------------------------------------------|------------------------------|
|
||||
| TZ | 时区 | Asia/Shanghai |
|
||||
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
|
||||
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
|
||||
| RUSTDESK_API_APP_REGISTER | 是否开启注册; `true`, `false` 默认`false` | `false` |
|
||||
| RUSTDESK_API_APP_SHOW_SWAGGER | 是否可见swagger文档;`1`显示,`0`不显示,默认`0`不显示 | `1` |
|
||||
| RUSTDESK_API_APP_TOKEN_EXPIRE | token有效时长(秒) | `3600` |
|
||||
| -----ADMIN配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_ADMIN_TITLE | 后台标题 | `RustDesk Api Admin` |
|
||||
| RUSTDESK_API_ADMIN_HELLO | 后台欢迎语,可以使用`html` | |
|
||||
| RUSTDESK_API_ADMIN_HELLO_FILE | 后台欢迎语文件,如果内容多,使用文件更方便。<br>会覆盖`RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
||||
| -----GIN配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
||||
| -----------GORM配置---------------- | ------------------------------------ | --------------------------- |
|
||||
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
||||
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
||||
| -----MYSQL配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
||||
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
||||
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
||||
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
||||
| -----RUSTDESK配置----- | --------------- | ---------- |
|
||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
|
||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk存放key的文件 | `./conf/data/id_ed25519.pub` |
|
||||
| RUSTDESK_API_RUSTDESK_WEBCLIENT_MAGIC_QUERYONLINE | Web client v2 中是否启用新的在线状态查询方法; `1`:启用,`0`:不启用,默认不启用 | `0` |
|
||||
| ----PROXY配置----- | --------------- | ---------- |
|
||||
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
|
||||
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
|
||||
| ----JWT配置---- | -------- | -------- |
|
||||
| RUSTDESK_API_JWT_KEY | 自定义JWT KEY,为空则不启用JWT | |
|
||||
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT有效时间 | 360000 |
|
||||
| 变量名 | 说明 | 示例 |
|
||||
|--------------------------------------------------------|--------------------------------------------------------------------------------|------------------------------|
|
||||
| TZ | 时区 | Asia/Shanghai |
|
||||
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
|
||||
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
|
||||
| RUSTDESK_API_APP_REGISTER | 是否开启注册; `true`, `false` 默认`false` | `false` |
|
||||
| RUSTDESK_API_APP_SHOW_SWAGGER | 是否可见swagger文档;`1`显示,`0`不显示,默认`0`不显示 | `1` |
|
||||
| RUSTDESK_API_APP_TOKEN_EXPIRE | token有效时长 | `168h` |
|
||||
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | 是否禁用密码登录; `true`, `false` 默认`false` | `false` |
|
||||
| -----ADMIN配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_ADMIN_TITLE | 后台标题 | `RustDesk Api Admin` |
|
||||
| RUSTDESK_API_ADMIN_HELLO | 后台欢迎语,可以使用`html` | |
|
||||
| RUSTDESK_API_ADMIN_HELLO_FILE | 后台欢迎语文件,如果内容多,使用文件更方便。<br>会覆盖`RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
||||
| -----GIN配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
||||
| -----GORM配置----- | ---------- | --------------------------- |
|
||||
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
||||
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
||||
| -----MYSQL配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
||||
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
||||
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
||||
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
||||
| -----RUSTDESK配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
|
||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk存放key的文件 | `./conf/data/id_ed25519.pub` |
|
||||
| RUSTDESK_API_RUSTDESK_WEBCLIENT<br/>_MAGIC_QUERYONLINE | Web client v2 中是否启用新的在线状态查询方法; `1`:启用,`0`:不启用,默认不启用 | `0` |
|
||||
| ----PROXY配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
|
||||
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
|
||||
| ----JWT配置---- | -------- | -------- |
|
||||
| RUSTDESK_API_JWT_KEY | 自定义JWT KEY,为空则不启用JWT<br/>如果没使用`lejianwen/rustdesk-server`中的`MUST_LOGIN`,建议设置为空 | |
|
||||
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT有效时间 | `168h` |
|
||||
|
||||
|
||||
### 运行
|
||||
@@ -288,10 +319,11 @@ jwt:
|
||||
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
||||
|
||||
|
||||
#### 使用我fork后的server-s6镜像运行
|
||||
#### 使用`lejianwen/server-s6`镜像运行
|
||||
|
||||
- 已解决链接超时问题
|
||||
- 可以强制登录后才能发起链接
|
||||
- github https://github.com/lejianwen/rustdesk-server
|
||||
- docker hub https://hub.docker.com/r/lejianwen/rustdesk-server-s6
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
@@ -344,4 +376,4 @@ jwt:
|
||||
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
|
||||
</a>
|
||||
|
||||
|
||||
## 感谢你的支持!如果这个项目对你有帮助,请点个⭐️鼓励一下,谢谢!
|
||||
|
||||
138
README_EN.md
138
README_EN.md
@@ -8,6 +8,7 @@ desktop software that provides self-hosted solutions.
|
||||
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
|
||||
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
|
||||
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
|
||||
<img src="https://goreportcard.com/badge/github.com/lejianwen/rustdesk-api/v2"/>
|
||||
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +19,10 @@ desktop software that provides self-hosted solutions.
|
||||
- Login
|
||||
- Address Book
|
||||
- Groups
|
||||
- Authorized login, supports `GitHub`, `Google` and `OIDC` login, supports `web admin` authorized login
|
||||
- Authorized login,
|
||||
- supports `GitHub`, `Google` and `OIDC` login,
|
||||
- supports `web admin` authorized login,
|
||||
- supports LDAP(test AD and openladp) if API Server config
|
||||
- i18n
|
||||
- Web Admin
|
||||
- User Management
|
||||
@@ -27,6 +31,7 @@ desktop software that provides self-hosted solutions.
|
||||
- Tag Management
|
||||
- Group Management
|
||||
- OAuth Management
|
||||
- LDAP Config by config file or ENV
|
||||
- Login Logs
|
||||
- Connection Logs
|
||||
- File Transfer Logs
|
||||
@@ -69,23 +74,22 @@ Basic implementation of the PC client's primary interfaces.Supports the Personal
|
||||
* 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/`
|
||||
* For the initial installation, the admin username is `admin`, and the password will be printed in the console. You can change the password via the [command line](#CLI).
|
||||
|
||||

|
||||
|
||||
|
||||
1. Admin interface:
|
||||

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

|
||||
In the top right corner, you can change the password, switch languages, and toggle between `day/night` mode.
|
||||
|
||||

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

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

|
||||
- For `Google` and `Github`, you don't need to fill the `Issuer` and `Scpoes`
|
||||
- For `OIDC`, you must set the `Issuer`. And `Scopes` is optional which default is `openid,email,profile`, please make sure this `Oauth App` can access `sub`, `email` and `preferred_username`
|
||||
- Create a `GitHub OAuth App`
|
||||
@@ -97,19 +101,18 @@ installation are `admin` `admin`, please change the password immediately.
|
||||
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
|
||||

|
||||
|
||||
- `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
|
||||
- `Advanced mode`, commands can be executed directly in the backend
|
||||
* Official commands can be used
|
||||
* Custom commands can be added
|
||||
* Custom commands can be executed
|
||||
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
11. **LDAP Support**, When you setup the LDAP(test for OpenLDAP and AD), you can login with the LDAP's user. https://github.com/lejianwen/rustdesk-api/issues/114 , if LDAP fail fallback local user
|
||||
|
||||
### Web Client:
|
||||
|
||||
1. If you're already logged into the admin panel, the web client will log in automatically.
|
||||
@@ -152,6 +155,9 @@ app:
|
||||
web-client: 1 # web client route 1:open 0:close
|
||||
register: false #register enable
|
||||
show-swagger: 0 #show swagger 1:open 0:close
|
||||
web-sso: true #web sso
|
||||
token-expire: 168h #token expire duration
|
||||
disable-pwd-login: false #disable password login
|
||||
gin:
|
||||
api-addr: "0.0.0.0:21114"
|
||||
mode: "release"
|
||||
@@ -182,48 +188,71 @@ proxy:
|
||||
jwt:
|
||||
key: ""
|
||||
expire-duration: 360000
|
||||
ldap:
|
||||
enable: false
|
||||
url: "ldap://ldap.example.com:389"
|
||||
tls: false
|
||||
tls-verify: false
|
||||
base-dn: "dc=example,dc=com"
|
||||
bind-dn: "cn=admin,dc=example,dc=com"
|
||||
bind-password: "password"
|
||||
|
||||
user:
|
||||
base-dn: "ou=users,dc=example,dc=com"
|
||||
enable-attr: "" #The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
|
||||
enable-attr-value: "" # The value of the enable attribute when the user is enabled. If you are using AD, just set random value, it will be ignored.
|
||||
filter: "(cn=*)"
|
||||
username: "uid" # The attribute name of the user for usernamem if you are using AD, it should be "sAMAccountName"
|
||||
email: "mail"
|
||||
first-name: "givenName"
|
||||
last-name: "sn"
|
||||
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
|
||||
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
|
||||
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
The prefix for variable names is `RUSTDESK_API`. If environment variables exist, they will override the configurations in the configuration file.
|
||||
The environment variables correspond one-to-one with the configurations in the `conf/config.yaml` file. The prefix for variable names is `RUSTDESK_API`.
|
||||
The table below does not list all configurations. Please refer to the configurations in `conf/config.yaml`.
|
||||
|
||||
| Variable Name | Description | Example |
|
||||
|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------|-------------------------------|
|
||||
| TZ | timezone | Asia/Shanghai |
|
||||
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
||||
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, default: 1 | 1 |
|
||||
| RUSTDESK_API_APP_REGISTER | register enable; `true`, `false`; default:`false` | `false` |
|
||||
| RUSTDESK_API_APP_SHOW_SWAGGER | swagger visible; 1: yes, 0: no; default: 0 | `0` |
|
||||
| RUSTDESK_API_APP_TOKEN_EXPIRE | token expire duration(second) | `3600` |
|
||||
| ----- ADMIN Configuration----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_ADMIN_TITLE | Admin Title | `RustDesk Api Admin` |
|
||||
| RUSTDESK_API_ADMIN_HELLO | Admin welcome message, you can use `html` | |
|
||||
| RUSTDESK_API_ADMIN_HELLO_FILE | Admin welcome message file,<br>will override `RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
||||
| ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
||||
| ----- GORM Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
||||
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
||||
| ----- MYSQL Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
||||
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
||||
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
||||
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
||||
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
|
||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk key file | `./conf/data/id_ed25519.pub` |
|
||||
| RUSTDESK_API_RUSTDESK_WEBCLIENT_MAGIC_QUERYONLINE | New online query method is enabled in the web client v2; '1': Enabled, '0': Disabled, not enabled by default | `0` |
|
||||
| ---- PROXY ----- | --------------- | ---------- |
|
||||
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
|
||||
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
|
||||
| ----JWT---- | -------- | -------- |
|
||||
| RUSTDESK_API_JWT_KEY | JWT KEY. Set empty to disable jwt | |
|
||||
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT expire duration | 360000 |
|
||||
| Variable Name | Description | Example |
|
||||
|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|
|
||||
| TZ | timezone | Asia/Shanghai |
|
||||
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
||||
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, default: 1 | 1 |
|
||||
| RUSTDESK_API_APP_REGISTER | register enable; `true`, `false`; default:`false` | `false` |
|
||||
| RUSTDESK_API_APP_SHOW_SWAGGER | swagger visible; 1: yes, 0: no; default: 0 | `0` |
|
||||
| RUSTDESK_API_APP_TOKEN_EXPIRE | token expire duration | `168h` |
|
||||
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | disable password login | `false` |
|
||||
| ----- ADMIN Configuration----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_ADMIN_TITLE | Admin Title | `RustDesk Api Admin` |
|
||||
| RUSTDESK_API_ADMIN_HELLO | Admin welcome message, you can use `html` | |
|
||||
| RUSTDESK_API_ADMIN_HELLO_FILE | Admin welcome message file,<br>will override `RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
||||
| ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
||||
| ----- GORM Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
||||
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
||||
| ----- MYSQL Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
||||
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
||||
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
||||
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
||||
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
|
||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk key file | `./conf/data/id_ed25519.pub` |
|
||||
| RUSTDESK_API_RUSTDESK<br/>_WEBCLIENT_MAGIC_QUERYONLINE | New online query method is enabled in the web client v2; '1': Enabled, '0': Disabled, not enabled by default | `0` |
|
||||
| ---- PROXY ----- | --------------- | ---------- |
|
||||
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
|
||||
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
|
||||
| ----JWT---- | -------- | -------- |
|
||||
| RUSTDESK_API_JWT_KEY | Custom JWT KEY, if empty JWT is not enabled.<br/>If `MUST_LOGIN` from `lejianwen/rustdesk-server` is not used, it is recommended to leave it empty. | |
|
||||
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT expire duration | `168h` |
|
||||
|
||||
### Installation Steps
|
||||
|
||||
@@ -294,8 +323,9 @@ Download the release from [release](https://github.com/lejianwen/rustdesk-api/re
|
||||
|
||||
#### Running with my forked server-s6 image
|
||||
|
||||
- Connection timeout issue resolved
|
||||
- Can enforce login before initiating a connection
|
||||
- github https://github.com/lejianwen/rustdesk-server
|
||||
- docker hub https://hub.docker.com/r/lejianwen/rustdesk-server-s6
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
@@ -344,3 +374,5 @@ Thanks to everyone who contributed!
|
||||
<a href="https://github.com/lejianwen/rustdesk-api/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
|
||||
</a>
|
||||
|
||||
## Thanks for your support! If you find this project useful, please give it a ⭐️. Thank you!
|
||||
@@ -1,24 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"Gwen/config"
|
||||
"Gwen/global"
|
||||
"Gwen/http"
|
||||
"Gwen/lib/cache"
|
||||
"Gwen/lib/jwt"
|
||||
"Gwen/lib/lock"
|
||||
"Gwen/lib/logger"
|
||||
"Gwen/lib/orm"
|
||||
"Gwen/lib/upload"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"fmt"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/lejianwen/rustdesk-api/v2/config"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/cache"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/jwt"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/lock"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/logger"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/orm"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/upload"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// @title 管理系统API
|
||||
@@ -54,10 +53,10 @@ var resetPwdCmd = &cobra.Command{
|
||||
admin := service.AllService.UserService.InfoById(1)
|
||||
err := service.AllService.UserService.UpdatePassword(admin, pwd)
|
||||
if err != nil {
|
||||
fmt.Printf("reset password fail! %v \n", err)
|
||||
global.Logger.Error("reset password fail! ", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("reset password success! \n")
|
||||
global.Logger.Info("reset password success! ")
|
||||
},
|
||||
}
|
||||
var resetUserPwdCmd = &cobra.Command{
|
||||
@@ -70,20 +69,20 @@ var resetUserPwdCmd = &cobra.Command{
|
||||
pwd := args[1]
|
||||
uid, err := strconv.Atoi(userId)
|
||||
if err != nil {
|
||||
fmt.Printf("userId must be int! \n")
|
||||
global.Logger.Warn("userId must be int!")
|
||||
return
|
||||
}
|
||||
if uid <= 0 {
|
||||
fmt.Printf("userId must be greater than 0! \n")
|
||||
global.Logger.Warn("userId must be greater than 0! ")
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.InfoById(uint(uid))
|
||||
err = service.AllService.UserService.UpdatePassword(u, pwd)
|
||||
if err != nil {
|
||||
fmt.Printf("reset password fail! %v \n", err)
|
||||
global.Logger.Warn("reset password fail! ", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("reset password success! \n")
|
||||
global.Logger.Info("reset password success!")
|
||||
},
|
||||
}
|
||||
|
||||
@@ -93,7 +92,7 @@ func init() {
|
||||
}
|
||||
func main() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
global.Logger.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -162,20 +161,18 @@ func InitGlobal() {
|
||||
|
||||
//jwt
|
||||
//fmt.Println(global.Config.Jwt.PrivateKey)
|
||||
global.Jwt = jwt.NewJwt(global.Config.Jwt.Key, global.Config.Jwt.ExpireDuration*time.Second)
|
||||
|
||||
global.Jwt = jwt.NewJwt(global.Config.Jwt.Key, global.Config.Jwt.ExpireDuration)
|
||||
//locker
|
||||
global.Lock = lock.NewLocal()
|
||||
}
|
||||
func DatabaseAutoUpdate() {
|
||||
version := 260
|
||||
version := 261
|
||||
|
||||
db := global.DB
|
||||
|
||||
if global.Config.Gorm.Type == config.TypeMysql {
|
||||
//检查存不存在数据库,不存在则创建
|
||||
dbName := db.Migrator().CurrentDatabase()
|
||||
fmt.Println("dbName", dbName)
|
||||
if dbName == "" {
|
||||
dbName = global.Config.Mysql.Dbname
|
||||
// 移除 DSN 中的数据库名称,以便初始连接时不指定数据库
|
||||
@@ -187,18 +184,18 @@ func DatabaseAutoUpdate() {
|
||||
// 获取底层的 *sql.DB 对象,并确保在程序退出时关闭连接
|
||||
sqlDBWithoutDB, err := dbWithoutDB.DB()
|
||||
if err != nil {
|
||||
fmt.Printf("获取底层 *sql.DB 对象失败: %v\n", err)
|
||||
global.Logger.Errorf("获取底层 *sql.DB 对象失败: %v", err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err := sqlDBWithoutDB.Close(); err != nil {
|
||||
fmt.Printf("关闭连接失败: %v\n", err)
|
||||
global.Logger.Errorf("关闭连接失败: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = dbWithoutDB.Exec("CREATE DATABASE IF NOT EXISTS " + dbName + " DEFAULT CHARSET utf8mb4").Error
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
global.Logger.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -213,6 +210,7 @@ func DatabaseAutoUpdate() {
|
||||
if v.Version < uint(version) {
|
||||
Migrate(uint(version))
|
||||
}
|
||||
|
||||
// 245迁移
|
||||
if v.Version < 245 {
|
||||
//oauths 表的 oauth_type 字段设置为 op同样的值
|
||||
@@ -235,7 +233,7 @@ func DatabaseAutoUpdate() {
|
||||
|
||||
}
|
||||
func Migrate(version uint) {
|
||||
fmt.Println("migrating....", version)
|
||||
global.Logger.Info("Migrating....", version)
|
||||
err := global.DB.AutoMigrate(
|
||||
&model.Version{},
|
||||
&model.User{},
|
||||
@@ -255,7 +253,7 @@ func Migrate(version uint) {
|
||||
&model.ServerCmd{},
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println("migrate err :=>", err)
|
||||
global.Logger.Error("migrate err :=>", err)
|
||||
}
|
||||
global.DB.Create(&model.Version{Version: version})
|
||||
//如果是初次则创建一个默认用户
|
||||
@@ -289,7 +287,11 @@ func Migrate(version uint) {
|
||||
IsAdmin: &is_admin,
|
||||
GroupId: 1,
|
||||
}
|
||||
admin.Password = service.AllService.UserService.EncryptPassword("admin")
|
||||
|
||||
// 生成随机密码
|
||||
pwd := utils.RandomString(8)
|
||||
global.Logger.Info("Admin Password Is: ", pwd)
|
||||
admin.Password = service.AllService.UserService.EncryptPassword(pwd)
|
||||
global.DB.Create(admin)
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
### 👏👏👏 你好 ***{{username}}***, 欢迎使用 [RustDesk Api](https://github.com/lejianwen/rustdesk-api)
|
||||
### 👏👏👏 你好 ***{{username}}***, 欢迎使用 [RustDesk API](https://github.com/lejianwen/rustdesk-api)
|
||||
@@ -3,7 +3,9 @@ app:
|
||||
web-client: 1 # 1:启用 0:禁用
|
||||
register: false #是否开启注册
|
||||
show-swagger: 0 # 1:启用 0:禁用
|
||||
token-expire: 360000
|
||||
token-expire: 168h
|
||||
web-sso: true #web auth sso
|
||||
disable-pwd-login: false #禁用密码登录
|
||||
admin:
|
||||
title: "RustDesk Api Admin"
|
||||
hello-file: "./conf/admin/hello.html" #优先使用file
|
||||
@@ -39,7 +41,28 @@ proxy:
|
||||
host: "http://127.0.0.1:1080"
|
||||
jwt:
|
||||
key: ""
|
||||
expire-duration: 360000
|
||||
expire-duration: 168h
|
||||
ldap:
|
||||
enable: false
|
||||
url: "ldap://ldap.example.com:389"
|
||||
tls: false
|
||||
tls-verify: false
|
||||
base-dn: "dc=example,dc=com"
|
||||
bind-dn: "cn=admin,dc=example,dc=com"
|
||||
bind-password: "password"
|
||||
|
||||
user:
|
||||
base-dn: "ou=users,dc=example,dc=com"
|
||||
enable-attr: "" #The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
|
||||
enable-attr-value: "" # The value of the enable attribute when the user is enabled. If you are using AD, just set random value, it will be ignored.
|
||||
filter: "(cn=*)"
|
||||
username: "uid" # The attribute name of the user for usernamem if you are using AD, it should be "sAMAccountName"
|
||||
email: "mail"
|
||||
first-name: "givenName"
|
||||
last-name: "sn"
|
||||
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
|
||||
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
|
||||
|
||||
redis:
|
||||
addr: "127.0.0.1:6379"
|
||||
password: ""
|
||||
@@ -58,23 +81,3 @@ oss:
|
||||
expire-time: 30
|
||||
max-byte: 10240
|
||||
|
||||
ldap:
|
||||
enable: false
|
||||
url: "ldap://ldap.example.com:389"
|
||||
tls: false
|
||||
tls-verify: false
|
||||
base-dn: "dc=example,dc=com"
|
||||
bind-dn: "cn=admin,dc=example,dc=com"
|
||||
bind-password: "password"
|
||||
|
||||
user:
|
||||
base-dn: "ou=users,dc=example,dc=com"
|
||||
enable-attr: "" #The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
|
||||
enable-attr-value: "" # The value of the enable attribute when the user is enabled. If you are using AD, just set random value, it will be ignored.
|
||||
filter: "(cn=*)"
|
||||
username: "uid" # The attribute name of the user for usernamem if you are using AD, it should be "sAMAccountName"
|
||||
email: "mail"
|
||||
first-name: "givenName"
|
||||
last-name: "sn"
|
||||
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
|
||||
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
|
||||
|
||||
@@ -2,9 +2,9 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/viper"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -14,10 +14,12 @@ const (
|
||||
)
|
||||
|
||||
type App struct {
|
||||
WebClient int `mapstructure:"web-client"`
|
||||
Register bool `mapstructure:"register"`
|
||||
ShowSwagger int `mapstructure:"show-swagger"`
|
||||
TokenExpire int `mapstructure:"token-expire"`
|
||||
WebClient int `mapstructure:"web-client"`
|
||||
Register bool `mapstructure:"register"`
|
||||
ShowSwagger int `mapstructure:"show-swagger"`
|
||||
TokenExpire time.Duration `mapstructure:"token-expire"`
|
||||
WebSso bool `mapstructure:"web-sso"`
|
||||
DisablePwdLogin bool `mapstructure:"disable-pwd-login"`
|
||||
}
|
||||
type Admin struct {
|
||||
Title string `mapstructure:"title"`
|
||||
@@ -38,7 +40,7 @@ type Config struct {
|
||||
Jwt Jwt
|
||||
Rustdesk Rustdesk
|
||||
Proxy Proxy
|
||||
Ldap Ldap
|
||||
Ldap Ldap
|
||||
}
|
||||
|
||||
// Init 初始化配置
|
||||
@@ -56,18 +58,23 @@ func Init(rowVal *Config, path string) *viper.Viper {
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Fatal error config file: %s \n", err))
|
||||
}
|
||||
v.WatchConfig()
|
||||
v.OnConfigChange(func(e fsnotify.Event) {
|
||||
//配置文件修改监听
|
||||
fmt.Println("config file changed:", e.Name)
|
||||
if err2 := v.Unmarshal(rowVal); err2 != nil {
|
||||
fmt.Println(err2)
|
||||
}
|
||||
rowVal.Rustdesk.LoadKeyFile()
|
||||
rowVal.Rustdesk.ParsePort()
|
||||
})
|
||||
/*
|
||||
v.WatchConfig()
|
||||
|
||||
|
||||
//监听配置修改没什么必要
|
||||
v.OnConfigChange(func(e fsnotify.Event) {
|
||||
//配置文件修改监听
|
||||
fmt.Println("config file changed:", e.Name)
|
||||
if err2 := v.Unmarshal(rowVal); err2 != nil {
|
||||
fmt.Println(err2)
|
||||
}
|
||||
rowVal.Rustdesk.LoadKeyFile()
|
||||
rowVal.Rustdesk.ParsePort()
|
||||
})
|
||||
*/
|
||||
if err := v.Unmarshal(rowVal); err != nil {
|
||||
fmt.Println(err)
|
||||
panic(fmt.Errorf("Fatal error config: %s \n", err))
|
||||
}
|
||||
rowVal.Rustdesk.LoadKeyFile()
|
||||
rowVal.Rustdesk.ParsePort()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package config
|
||||
|
||||
type LdapUser struct {
|
||||
BaseDn string `mapstructure:"base-dn"` // The base DN of the user for searching
|
||||
EnableAttr string `mapstructure:"enable-attr"` // The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
|
||||
EnableAttrValue string `mapstructure:"enable-attr-value"` // The value of the enable attribute when the user is enabled. If you are using AD, just leave it random str, it will be ignored.
|
||||
Filter string `mapstructure:"filter"`
|
||||
Username string `mapstructure:"username"`
|
||||
Email string `mapstructure:"email"`
|
||||
FirstName string `mapstructure:"first-name"`
|
||||
LastName string `mapstructure:"last-name"`
|
||||
Sync bool `mapstructure:"sync"` // Will sync the user's information to the internal database
|
||||
AdminGroup string `mapstructure:"admin-group"` // Which group is the admin group
|
||||
BaseDn string `mapstructure:"base-dn"` // The base DN of the user for searching
|
||||
EnableAttr string `mapstructure:"enable-attr"` // The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
|
||||
EnableAttrValue string `mapstructure:"enable-attr-value"` // The value of the enable attribute when the user is enabled. If you are using AD, just leave it random str, it will be ignored.
|
||||
Filter string `mapstructure:"filter"`
|
||||
Username string `mapstructure:"username"`
|
||||
Email string `mapstructure:"email"`
|
||||
FirstName string `mapstructure:"first-name"`
|
||||
LastName string `mapstructure:"last-name"`
|
||||
Sync bool `mapstructure:"sync"` // Will sync the user's information to the internal database
|
||||
AdminGroup string `mapstructure:"admin-group"` // Which group is the admin group
|
||||
}
|
||||
|
||||
// type LdapGroup struct {
|
||||
@@ -24,13 +24,13 @@ type LdapUser struct {
|
||||
// }
|
||||
|
||||
type Ldap struct {
|
||||
Enable bool `mapstructure:"enable"`
|
||||
Url string `mapstructure:"url"`
|
||||
TLS bool `mapstructure:"tls"`
|
||||
TlsVerify bool `mapstructure:"tls-verify"`
|
||||
BaseDn string `mapstructure:"base-dn"`
|
||||
BindDn string `mapstructure:"bind-dn"`
|
||||
BindPassword string `mapstructure:"bind-password"`
|
||||
User LdapUser `mapstructure:"user"`
|
||||
Enable bool `mapstructure:"enable"`
|
||||
Url string `mapstructure:"url"`
|
||||
TLS bool `mapstructure:"tls"`
|
||||
TlsVerify bool `mapstructure:"tls-verify"`
|
||||
BaseDn string `mapstructure:"base-dn"`
|
||||
BindDn string `mapstructure:"bind-dn"`
|
||||
BindPassword string `mapstructure:"bind-password"`
|
||||
User LdapUser `mapstructure:"user"`
|
||||
// Group LdapGroup `mapstructure:"group"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,4 @@ type OidcOauth struct {
|
||||
ClientId string `mapstructure:"client-id"`
|
||||
ClientSecret string `mapstructure:"client-secret"`
|
||||
RedirectUrl string `mapstructure:"redirect-url"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1783,7 +1783,7 @@ const docTemplateadmin = `{
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Gwen_http_request_admin.Login"
|
||||
"$ref": "#/definitions/github_com_lejianwen_rustdesk-api_http_request_admin.Login"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -5104,27 +5104,6 @@ const docTemplateadmin = `{
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Gwen_http_request_admin.Login": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"captcha": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.AddressBookForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -5542,6 +5521,27 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"github_com_lejianwen_rustdesk-api_http_request_admin.Login": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"captcha": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.AddressBook": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1776,7 +1776,7 @@
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Gwen_http_request_admin.Login"
|
||||
"$ref": "#/definitions/github_com_lejianwen_rustdesk-api_http_request_admin.Login"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -5097,27 +5097,6 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Gwen_http_request_admin.Login": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"captcha": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.AddressBookForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -5535,6 +5514,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"github_com_lejianwen_rustdesk-api_http_request_admin.Login": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"captcha": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.AddressBook": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
basePath: /api
|
||||
definitions:
|
||||
Gwen_http_request_admin.Login:
|
||||
properties:
|
||||
captcha:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
platform:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
required:
|
||||
- password
|
||||
- username
|
||||
type: object
|
||||
admin.AddressBookForm:
|
||||
properties:
|
||||
alias:
|
||||
@@ -292,6 +278,20 @@ definitions:
|
||||
required:
|
||||
- ids
|
||||
type: object
|
||||
github_com_lejianwen_rustdesk-api_http_request_admin.Login:
|
||||
properties:
|
||||
captcha:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
platform:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
required:
|
||||
- password
|
||||
- username
|
||||
type: object
|
||||
model.AddressBook:
|
||||
properties:
|
||||
alias:
|
||||
@@ -1830,7 +1830,7 @@ paths:
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/Gwen_http_request_admin.Login'
|
||||
$ref: '#/definitions/github_com_lejianwen_rustdesk-api_http_request_admin.Login'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
||||
BIN
docs/init_admin_pwd.png
Normal file
BIN
docs/init_admin_pwd.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -1,4 +1,4 @@
|
||||
package Gwen
|
||||
package main
|
||||
|
||||
//go:generate swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
|
||||
//go:generate swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package Gwen
|
||||
package main
|
||||
|
||||
//go:generate go run cmd/apimain.go
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"Gwen/config"
|
||||
"Gwen/lib/cache"
|
||||
"Gwen/lib/jwt"
|
||||
"Gwen/lib/lock"
|
||||
"Gwen/lib/upload"
|
||||
"github.com/gin-gonic/gin"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/lejianwen/rustdesk-api/v2/config"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/cache"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/jwt"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/lock"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/upload"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
@@ -15,7 +15,6 @@ func InitI18n() {
|
||||
fileInfos, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return
|
||||
}
|
||||
for _, fileInfo := range fileInfos {
|
||||
//如果文件名不是.toml结尾
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"encoding/json"
|
||||
_ "encoding/json"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
@@ -60,7 +61,22 @@ func (co *Config) AppConfig(c *gin.Context) {
|
||||
// @Security token
|
||||
func (co *Config) AdminConfig(c *gin.Context) {
|
||||
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
u := &model.User{}
|
||||
token := c.GetHeader("api-token")
|
||||
if token != "" {
|
||||
u, _ = service.AllService.UserService.InfoByAccessToken(token)
|
||||
if !service.AllService.UserService.CheckUserEnable(u) {
|
||||
u.Id = 0
|
||||
}
|
||||
}
|
||||
|
||||
if u.Id == 0 {
|
||||
response.Success(c, &gin.H{
|
||||
"title": global.Config.Admin.Title,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
hello := global.Config.Admin.Hello
|
||||
helloFile := global.Config.Admin.HelloFile
|
||||
if helloFile != "" {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/response"
|
||||
"Gwen/lib/upload"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/upload"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/controller/api"
|
||||
"Gwen/http/request/admin"
|
||||
apiReq "Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
adResp "Gwen/http/response/admin"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/controller/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
apiReq "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
adResp "github.com/lejianwen/rustdesk-api/v2/http/response/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -152,6 +152,10 @@ var loginLimiter = NewLoginLimiter(3, 5*time.Minute)
|
||||
// @Router /admin/login [post]
|
||||
// @Security token
|
||||
func (ct *Login) Login(c *gin.Context) {
|
||||
if global.Config.App.DisablePwdLogin {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "PwdLoginDisabled"))
|
||||
return
|
||||
}
|
||||
f := &admin.Login{}
|
||||
err := c.ShouldBindJSON(f)
|
||||
clientIp := c.ClientIP()
|
||||
@@ -182,15 +186,20 @@ func (ct *Login) Login(c *gin.Context) {
|
||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), clientIp))
|
||||
loginLimiter.RecordFailure(clientIp)
|
||||
if loginLimiter.NeedsCaptcha(clientIp) {
|
||||
// 移除原验证码,重新生成
|
||||
loginLimiter.RemoveCaptcha(clientIp)
|
||||
response.Fail(c, 110, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||
return
|
||||
}
|
||||
|
||||
if !service.AllService.UserService.CheckUserEnable(u) {
|
||||
if loginLimiter.NeedsCaptcha(clientIp) {
|
||||
loginLimiter.RemoveCaptcha(clientIp)
|
||||
}
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "UserDisabled"))
|
||||
return
|
||||
}
|
||||
|
||||
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
||||
UserId: u.Id,
|
||||
Client: model.LoginLogClientWebAdmin,
|
||||
@@ -274,13 +283,13 @@ func (ct *Login) OidcAuth(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||
err, state, verifier, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{
|
||||
service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
|
||||
Action: service.OauthActionTypeLogin,
|
||||
Op: f.Op,
|
||||
Id: f.Id,
|
||||
@@ -288,10 +297,11 @@ func (ct *Login) OidcAuth(c *gin.Context) {
|
||||
// DeviceOs: ct.Platform(c),
|
||||
DeviceOs: f.DeviceInfo.Os,
|
||||
Uuid: f.Uuid,
|
||||
Verifier: verifier,
|
||||
}, 5*60)
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"code": code,
|
||||
"code": state,
|
||||
"url": url,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package my
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"encoding/json"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package my
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package my
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package my
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package my
|
||||
|
||||
import (
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package my
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package my
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
adminReq "Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
adminReq "github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -43,20 +43,21 @@ func (o *Oauth) ToBind(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||
err, state, verifier, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{
|
||||
service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
|
||||
Action: service.OauthActionTypeBind,
|
||||
Op: f.Op,
|
||||
UserId: u.Id,
|
||||
Op: f.Op,
|
||||
UserId: u.Id,
|
||||
Verifier: verifier,
|
||||
}, 5*60)
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"code": code,
|
||||
"code": state,
|
||||
"url": url,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
)
|
||||
|
||||
type Rustdesk struct {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
adResp "Gwen/http/response/admin"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
adResp "github.com/lejianwen/rustdesk-api/v2/http/response/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/admin"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
requstform "Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
"Gwen/http/response/api"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"Gwen/utils"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
requstform "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
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"
|
||||
request "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
apiReq "Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
apiResp "Gwen/http/response/api"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
apiReq "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
requstform "Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
requstform "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
apiResp "Gwen/http/response/api"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -27,6 +27,10 @@ type Login struct {
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /login [post]
|
||||
func (l *Login) Login(c *gin.Context) {
|
||||
if global.Config.App.DisablePwdLogin {
|
||||
response.Error(c, response.TranslateMsg(c, "PwdLoginDisabled"))
|
||||
return
|
||||
}
|
||||
f := &api.LoginForm{}
|
||||
err := c.ShouldBindJSON(f)
|
||||
//fmt.Println(f)
|
||||
@@ -51,6 +55,11 @@ func (l *Login) Login(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !service.AllService.UserService.CheckUserEnable(u) {
|
||||
response.Error(c, response.TranslateMsg(c, "UserDisabled"))
|
||||
return
|
||||
}
|
||||
|
||||
//根据refer判断是webclient还是app
|
||||
ref := c.GetHeader("referer")
|
||||
if ref != "" {
|
||||
@@ -85,7 +94,9 @@ func (l *Login) Login(c *gin.Context) {
|
||||
// @Router /login-options [get]
|
||||
func (l *Login) LoginOptions(c *gin.Context) {
|
||||
ops := service.AllService.OauthService.GetOauthProviders()
|
||||
ops = append(ops, model.OauthTypeWebauth)
|
||||
if global.Config.App.WebSso {
|
||||
ops = append(ops, model.OauthTypeWebauth)
|
||||
}
|
||||
var oidcItems []map[string]string
|
||||
for _, v := range ops {
|
||||
oidcItems = append(oidcItems, map[string]string{"name": v})
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
apiResp "Gwen/http/response/api"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -32,15 +32,16 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
|
||||
}
|
||||
|
||||
oauthService := service.AllService.OauthService
|
||||
var code string
|
||||
var state string
|
||||
var url string
|
||||
err, code, url = oauthService.BeginAuth(f.Op)
|
||||
var verifier string
|
||||
err, state, verifier, url = oauthService.BeginAuth(f.Op)
|
||||
if err != nil {
|
||||
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{
|
||||
service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
|
||||
Action: service.OauthActionTypeLogin,
|
||||
Id: f.Id,
|
||||
Op: f.Op,
|
||||
@@ -48,10 +49,11 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
|
||||
DeviceName: f.DeviceInfo.Name,
|
||||
DeviceOs: f.DeviceInfo.Os,
|
||||
DeviceType: f.DeviceInfo.Type,
|
||||
Verifier: verifier,
|
||||
}, 5*60)
|
||||
//fmt.Println("code url", code, url)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": code,
|
||||
"code": state,
|
||||
"url": url,
|
||||
})
|
||||
}
|
||||
@@ -156,10 +158,11 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
}
|
||||
op := oauthCache.Op
|
||||
action := oauthCache.Action
|
||||
verifier := oauthCache.Verifier
|
||||
var user *model.User
|
||||
// 获取用户信息
|
||||
code := c.Query("code")
|
||||
err, oauthUser := oauthService.Callback(code, op)
|
||||
err, oauthUser := oauthService.Callback(code, verifier, op)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
|
||||
return
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
requstform "Gwen/http/request/api"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
requstform "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
apiResp "Gwen/http/response/api"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/response"
|
||||
"Gwen/http/response/api"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -23,5 +23,6 @@ localStorage.setItem(ws2_prefix+'api-server', "` + apiServer + `")
|
||||
|
||||
window.webclient_magic_queryonline = ` + magicQueryonline + ``
|
||||
|
||||
c.Header("Content-Type", "application/javascript")
|
||||
c.String(200, tmp)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/middleware"
|
||||
"Gwen/http/router"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/middleware"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/router"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
)
|
||||
|
||||
// AdminAuth 后台权限验证中间件
|
||||
func AdminAuth() gin.HandlerFunc {
|
||||
// BackendUserAuth 后台权限验证中间件
|
||||
func BackendUserAuth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
//测试先关闭
|
||||
@@ -24,6 +24,14 @@ func AdminAuth() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if !service.AllService.UserService.CheckUserEnable(user) {
|
||||
c.JSON(401, gin.H{
|
||||
"error": "Unauthorized",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("curUser", user)
|
||||
c.Set("token", token)
|
||||
//如果时间小于1天,token自动续期
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
)
|
||||
|
||||
// AdminPrivilege ...
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/response"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
)
|
||||
|
||||
func JwtAuth() gin.HandlerFunc {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
)
|
||||
|
||||
func RustAuth() gin.HandlerFunc {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/model"
|
||||
"encoding/json"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
)
|
||||
|
||||
type AddressBookForm struct {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package admin
|
||||
|
||||
import "Gwen/model"
|
||||
import "github.com/lejianwen/rustdesk-api/v2/model"
|
||||
|
||||
type GroupForm struct {
|
||||
Id uint `json:"id"`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
)
|
||||
|
||||
type BindOauthForm struct {
|
||||
@@ -15,27 +15,31 @@ type UnBindOauthForm struct {
|
||||
Op string `json:"op" binding:"required"`
|
||||
}
|
||||
type OauthForm struct {
|
||||
Id uint `json:"id"`
|
||||
Op string `json:"op" validate:"omitempty"`
|
||||
OauthType string `json:"oauth_type" validate:"required"`
|
||||
Issuer string `json:"issuer" validate:"omitempty,url"`
|
||||
Scopes string `json:"scopes" validate:"omitempty"`
|
||||
ClientId string `json:"client_id" validate:"required"`
|
||||
ClientSecret string `json:"client_secret" validate:"required"`
|
||||
RedirectUrl string `json:"redirect_url" validate:"required"`
|
||||
AutoRegister *bool `json:"auto_register"`
|
||||
Id uint `json:"id"`
|
||||
Op string `json:"op" validate:"omitempty"`
|
||||
OauthType string `json:"oauth_type" validate:"required"`
|
||||
Issuer string `json:"issuer" validate:"omitempty,url"`
|
||||
Scopes string `json:"scopes" validate:"omitempty"`
|
||||
ClientId string `json:"client_id" validate:"required"`
|
||||
ClientSecret string `json:"client_secret" validate:"required"`
|
||||
RedirectUrl string `json:"redirect_url" validate:"required"`
|
||||
AutoRegister *bool `json:"auto_register"`
|
||||
PkceEnable *bool `json:"pkce_enable"`
|
||||
PkceMethod string `json:"pkce_method"`
|
||||
}
|
||||
|
||||
func (of *OauthForm) ToOauth() *model.Oauth {
|
||||
oa := &model.Oauth{
|
||||
Op: of.Op,
|
||||
OauthType: of.OauthType,
|
||||
OauthType: of.OauthType,
|
||||
ClientId: of.ClientId,
|
||||
ClientSecret: of.ClientSecret,
|
||||
RedirectUrl: of.RedirectUrl,
|
||||
AutoRegister: of.AutoRegister,
|
||||
Issuer: of.Issuer,
|
||||
Scopes: of.Scopes,
|
||||
PkceEnable: of.PkceEnable,
|
||||
PkceMethod: of.PkceMethod,
|
||||
}
|
||||
oa.Id = of.Id
|
||||
return oa
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package admin
|
||||
|
||||
import "Gwen/model"
|
||||
import "github.com/lejianwen/rustdesk-api/v2/model"
|
||||
|
||||
type PeerForm struct {
|
||||
RowId uint `json:"row_id" `
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package admin
|
||||
|
||||
import "Gwen/model"
|
||||
import "github.com/lejianwen/rustdesk-api/v2/model"
|
||||
|
||||
type TagForm struct {
|
||||
Id uint `json:"id"`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
)
|
||||
|
||||
type UserForm struct {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"encoding/json"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package api
|
||||
|
||||
import "Gwen/model"
|
||||
import "github.com/lejianwen/rustdesk-api/v2/model"
|
||||
|
||||
type AddressBookFormData struct {
|
||||
Tags []string `json:"tags"`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package admin
|
||||
|
||||
import "Gwen/model"
|
||||
import "github.com/lejianwen/rustdesk-api/v2/model"
|
||||
|
||||
type LoginPayload struct {
|
||||
Username string `json:"username"`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package api
|
||||
|
||||
import "Gwen/model"
|
||||
import "github.com/lejianwen/rustdesk-api/v2/model"
|
||||
|
||||
type AbList struct {
|
||||
Peers []*model.AddressBook `json:"peers,omitempty"`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package api
|
||||
|
||||
import "Gwen/model"
|
||||
import "github.com/lejianwen/rustdesk-api/v2/model"
|
||||
|
||||
/*
|
||||
GroupPeerPayload
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package api
|
||||
|
||||
import "Gwen/model"
|
||||
import "github.com/lejianwen/rustdesk-api/v2/model"
|
||||
|
||||
/*
|
||||
pub enum UserStatus {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
_ "Gwen/docs/admin"
|
||||
"Gwen/global"
|
||||
"Gwen/http/controller/admin"
|
||||
"Gwen/http/controller/admin/my"
|
||||
"Gwen/http/middleware"
|
||||
"github.com/gin-gonic/gin"
|
||||
_ "github.com/lejianwen/rustdesk-api/v2/docs/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/controller/admin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/controller/admin/my"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/middleware"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
)
|
||||
@@ -22,7 +22,10 @@ func Init(g *gin.Engine) {
|
||||
adg := g.Group("/api/admin")
|
||||
LoginBind(adg)
|
||||
adg.POST("/user/register", (&admin.User{}).Register)
|
||||
adg.Use(middleware.AdminAuth())
|
||||
|
||||
ConfigBind(adg)
|
||||
|
||||
adg.Use(middleware.BackendUserAuth())
|
||||
//FileBind(adg)
|
||||
UserBind(adg)
|
||||
GroupBind(adg)
|
||||
@@ -35,7 +38,6 @@ func Init(g *gin.Engine) {
|
||||
AddressBookCollectionBind(adg)
|
||||
AddressBookCollectionRuleBind(adg)
|
||||
UserTokenBind(adg)
|
||||
ConfigBind(adg)
|
||||
|
||||
//deprecated by ConfigBind
|
||||
//rs := &admin.Rustdesk{}
|
||||
@@ -221,9 +223,13 @@ func UserTokenBind(rg *gin.RouterGroup) {
|
||||
func ConfigBind(rg *gin.RouterGroup) {
|
||||
aR := rg.Group("/config")
|
||||
rs := &admin.Config{}
|
||||
|
||||
aR.GET("/admin", rs.AdminConfig)
|
||||
|
||||
aR.Use(middleware.BackendUserAuth())
|
||||
aR.GET("/server", rs.ServerConfig)
|
||||
aR.GET("/app", rs.AppConfig)
|
||||
aR.GET("/admin", rs.AdminConfig)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
_ "Gwen/docs/api"
|
||||
"Gwen/global"
|
||||
"Gwen/http/controller/api"
|
||||
"Gwen/http/middleware"
|
||||
"github.com/gin-gonic/gin"
|
||||
_ "github.com/lejianwen/rustdesk-api/v2/docs/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/controller/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/middleware"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
"net/http"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/http/controller/web"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/http/controller/web"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ type Config struct {
|
||||
func New(c *Config) *log.Logger {
|
||||
log.SetFormatter(&nested.Formatter{
|
||||
// HideKeys: true,
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
TimestampFormat: "[2006-01-02 15:04:05]",
|
||||
NoColors: true,
|
||||
NoFieldsColors: true,
|
||||
//FieldsOrder: []string{"name", "age"},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package orm
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"fmt"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package orm
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"fmt"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package model
|
||||
|
||||
import "Gwen/model/custom_types"
|
||||
import "github.com/lejianwen/rustdesk-api/v2/model/custom_types"
|
||||
|
||||
// final String id;
|
||||
// String hash; // personal ab hash password
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"Gwen/model/custom_types"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model/custom_types"
|
||||
)
|
||||
|
||||
type StatusCode int
|
||||
|
||||
@@ -14,6 +14,8 @@ const (
|
||||
OauthTypeGoogle string = "google"
|
||||
OauthTypeOidc string = "oidc"
|
||||
OauthTypeWebauth string = "webauth"
|
||||
PKCEMethodS256 string = "S256"
|
||||
PKCEMethodPlain string = "plain"
|
||||
)
|
||||
|
||||
// Validate the oauth type
|
||||
@@ -41,6 +43,8 @@ type Oauth struct {
|
||||
AutoRegister *bool `json:"auto_register"`
|
||||
Scopes string `json:"scopes"`
|
||||
Issuer string `json:"issuer"`
|
||||
PkceEnable *bool `json:"pkce_enable"`
|
||||
PkceMethod string `json:"pkce_method"`
|
||||
TimeModel
|
||||
}
|
||||
|
||||
@@ -68,6 +72,13 @@ func (oa *Oauth) FormatOauthInfo() error {
|
||||
if oauthType == OauthTypeGoogle && issuer == "" {
|
||||
oa.Issuer = IssuerGoogle
|
||||
}
|
||||
if oa.PkceEnable == nil {
|
||||
oa.PkceEnable = new(bool)
|
||||
*oa.PkceEnable = false
|
||||
}
|
||||
if oa.PkceMethod == "" {
|
||||
oa.PkceMethod = PKCEMethodS256
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@ package model
|
||||
|
||||
type UserToken struct {
|
||||
IdModel
|
||||
UserId uint `json:"user_id" gorm:"default:0;not null;index"`
|
||||
DeviceUuid string `json:"device_uuid" gorm:"default:'';omitempty;"`
|
||||
DeviceId string `json:"device_id" gorm:"default:'';omitempty;"`
|
||||
Token string `json:"token" gorm:"default:'';not null;index"`
|
||||
ExpiredAt int64 `json:"expired_at" gorm:"default:0;not null;"`
|
||||
UserId uint `json:"user_id" gorm:"default:0;not null;index"`
|
||||
DeviceUuid string `json:"device_uuid" gorm:"default:'';omitempty;"`
|
||||
DeviceId string `json:"device_id" gorm:"default:'';omitempty;"`
|
||||
Token string `json:"token" gorm:"default:'';not null;index"`
|
||||
ExpiredAt int64 `json:"expired_at" gorm:"default:0;not null;"`
|
||||
TimeModel
|
||||
}
|
||||
|
||||
|
||||
@@ -133,3 +133,8 @@ other = "Captcha required."
|
||||
description = "Captcha error."
|
||||
one = "Captcha error."
|
||||
other = "Captcha error."
|
||||
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "Password login disabled."
|
||||
other = "Password login disabled."
|
||||
@@ -141,4 +141,9 @@ other = "Captcha requerido."
|
||||
[CaptchaError]
|
||||
description = "Captcha error."
|
||||
one = "Error de captcha."
|
||||
other = "Error de captcha."
|
||||
other = "Error de captcha."
|
||||
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "Inicio de sesión con contraseña deshabilitado."
|
||||
other = "Inicio de sesión con contraseña deshabilitado."
|
||||
@@ -142,3 +142,8 @@ other = "Captcha requis."
|
||||
description = "Captcha error."
|
||||
one = "Erreur de captcha."
|
||||
other = "Erreur de captcha."
|
||||
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "Connexion par mot de passe désactivée."
|
||||
other = "Connexion par mot de passe désactivée."
|
||||
@@ -135,4 +135,9 @@ other = "Captcha가 필요합니다."
|
||||
[CaptchaError]
|
||||
description = "Captcha error."
|
||||
one = "Captcha 오류."
|
||||
other = "Captcha 오류."
|
||||
other = "Captcha 오류."
|
||||
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "비밀번호 로그인이 비활성화되었습니다."
|
||||
other = "비밀번호 로그인이 비활성화되었습니다."
|
||||
|
||||
@@ -141,4 +141,9 @@ other = "Требуется капча."
|
||||
[CaptchaError]
|
||||
description = "Captcha error."
|
||||
one = "Ошибка капчи."
|
||||
other = "Ошибка капчи."
|
||||
other = "Ошибка капчи."
|
||||
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "Вход по паролю отключен."
|
||||
other = "Вход по паролю отключен."
|
||||
@@ -134,4 +134,9 @@ other = "需要验证码。"
|
||||
[CaptchaError]
|
||||
description = "Captcha error."
|
||||
one = "验证码错误。"
|
||||
other = "验证码错误。"
|
||||
other = "验证码错误。"
|
||||
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "密码登录已禁用。"
|
||||
other = "密码登录已禁用。"
|
||||
@@ -134,4 +134,9 @@ other = "需要驗證碼。"
|
||||
[CaptchaError]
|
||||
description = "Captcha error."
|
||||
one = "驗證碼錯誤。"
|
||||
other = "驗證碼錯誤。"
|
||||
other = "驗證碼錯誤。"
|
||||
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "密碼登錄已禁用。"
|
||||
other = "密碼登錄已禁用。"
|
||||
|
||||
22
resources/web2/js/dist/index.js
vendored
22
resources/web2/js/dist/index.js
vendored
@@ -11090,16 +11090,24 @@ function R4(u = !1) {
|
||||
function getUriFromRs(uri, isRelay = false, roffset = 0) {
|
||||
const p = isHttps() ? "wss://" : "ws://"
|
||||
const [domain, uriport] = uri.split(":")
|
||||
if (isHttps() && (!uriport)) {
|
||||
return p + domain + "/ws/" + (isRelay ? "relay" : "id");
|
||||
if (!isHttps()) {
|
||||
// http 直接走端口
|
||||
if (uriport) {
|
||||
const port = parseInt(uriport)
|
||||
return p + domain + ":" + (port + (isRelay ? roffset || 3 : 2))
|
||||
}
|
||||
return p + domain + ":" + (defaultIdServerPort + (isRelay ? 3 : 2))
|
||||
}
|
||||
if (uriport) {
|
||||
const port = parseInt(uriport);
|
||||
uri = domain + ":" + (port + (isRelay ? roffset || 3 : 2))
|
||||
} else uri += ":" + (defaultIdServerPort + (isRelay ? 3 : 2));
|
||||
return p + uri
|
||||
// https 分情况
|
||||
if (!window.location.port) {
|
||||
// 443
|
||||
return p + domain + "/ws/" + (isRelay ? "relay" : "id")
|
||||
}
|
||||
// 非443
|
||||
return p + domain + ":" + window.location.port + "/ws/" + (isRelay ? "relay" : "id")
|
||||
}
|
||||
|
||||
|
||||
function isHttps() {
|
||||
return window.location.protocol === "https:"
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"encoding/json"
|
||||
"github.com/google/uuid"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
111
service/ldap.go
111
service/ldap.go
@@ -4,13 +4,28 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"Gwen/config"
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
|
||||
"github.com/lejianwen/rustdesk-api/v2/config"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrLdapNotEnabled = errors.New("LdapNotEnabled")
|
||||
ErrLdapUserDisabled = errors.New("UserDisabledAtLdap")
|
||||
ErrLdapUserNotFound = errors.New("UserNotFound")
|
||||
ErrLdapMailNotMatch = errors.New("MailNotMatch")
|
||||
ErrLdapConnectFailed = errors.New("LdapConnectFailed")
|
||||
ErrLdapSearchFailed = errors.New("LdapSearchRequestFailed")
|
||||
ErrLdapTlsFailed = errors.New("LdapStartTLSFailed")
|
||||
ErrLdapBindService = errors.New("LdapBindServiceFailed")
|
||||
ErrLdapBindFailed = errors.New("LdapBindFailed")
|
||||
ErrLdapToLocalUserFailed = errors.New("LdapToLocalUserFailed")
|
||||
ErrLdapCreateUserFailed = errors.New("LdapCreateUserFailed")
|
||||
)
|
||||
|
||||
// LdapService is responsible for LDAP authentication and user synchronization.
|
||||
@@ -43,6 +58,11 @@ func (lu *LdapUser) ToUser(u *model.User) *model.User {
|
||||
u.Username = lu.Username
|
||||
u.Email = lu.Email
|
||||
u.Nickname = lu.Name()
|
||||
if lu.Enabled {
|
||||
u.Status = model.COMMON_STATUS_ENABLE
|
||||
} else {
|
||||
u.Status = model.COMMON_STATUS_DISABLED
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
@@ -50,21 +70,21 @@ func (lu *LdapUser) ToUser(u *model.User) *model.User {
|
||||
func (ls *LdapService) connectAndBind(cfg *config.Ldap, username, password string) (*ldap.Conn, error) {
|
||||
conn, err := ldap.DialURL(cfg.Url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to dial LDAP: %w", err)
|
||||
return nil, errors.Join(ErrLdapConnectFailed, err)
|
||||
}
|
||||
|
||||
if cfg.TLS {
|
||||
// WARNING: InsecureSkipVerify: true is not recommended for production
|
||||
if err = conn.StartTLS(&tls.Config{InsecureSkipVerify: !cfg.TlsVerify}); err != nil {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("failed to start TLS: %w", err)
|
||||
return nil, errors.Join(ErrLdapTlsFailed, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Bind as the "service" user
|
||||
if err = conn.Bind(username, password); err != nil {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("failed to bind with service account: %w", err)
|
||||
return nil, errors.Join(ErrLdapBindService, err)
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
@@ -87,29 +107,17 @@ func (ls *LdapService) verifyCredentials(cfg *config.Ldap, username, password st
|
||||
// Authenticate checks the provided username and password against LDAP.
|
||||
// Returns the corresponding *model.User if successful, or an error if not.
|
||||
func (ls *LdapService) Authenticate(username, password string) (*model.User, error) {
|
||||
cfg := &global.Config.Ldap
|
||||
// 1. Use a service bind to search for the user DN
|
||||
sr, err := ls.usernameSearchResult(cfg, username)
|
||||
ldapUser, err := ls.GetUserInfoByUsernameLdap(username)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("LDAP search request failed: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
if len(sr.Entries) != 1 {
|
||||
return nil, errors.New("user does not exist or too many entries returned")
|
||||
}
|
||||
entry := sr.Entries[0]
|
||||
userDN := entry.DN
|
||||
|
||||
err = ls.verifyCredentials(cfg, userDN, password)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("LDAP authentication failed: %w", err)
|
||||
}
|
||||
ldapUser := ls.userResultToLdapUser(cfg, entry)
|
||||
if !ldapUser.Enabled {
|
||||
return nil, errors.New("UserDisabledAtLdap")
|
||||
return nil, ErrLdapUserDisabled
|
||||
}
|
||||
cfg := &global.Config.Ldap
|
||||
user, err := ls.mapToLocalUser(cfg, ldapUser)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to map LDAP user to local user: %w", err)
|
||||
return nil, errors.Join(ErrLdapToLocalUserFailed, err)
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
@@ -126,8 +134,9 @@ func (ls *LdapService) mapToLocalUser(cfg *config.Ldap, lu *LdapUser) (*model.Us
|
||||
// Typically, you don’t store LDAP user passwords locally.
|
||||
// If needed, you can set a random password here.
|
||||
newUser.IsAdmin = &isAdmin
|
||||
newUser.GroupId = 1
|
||||
if err := global.DB.Create(newUser).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to create new user: %w", err)
|
||||
return nil, errors.Join(ErrLdapCreateUserFailed, err)
|
||||
}
|
||||
return userService.InfoByUsername(lu.Username), nil
|
||||
}
|
||||
@@ -137,6 +146,7 @@ func (ls *LdapService) mapToLocalUser(cfg *config.Ldap, lu *LdapUser) (*model.Us
|
||||
originalEmail := localUser.Email
|
||||
originalNickname := localUser.Nickname
|
||||
originalIsAdmin := localUser.IsAdmin
|
||||
originalStatus := localUser.Status
|
||||
lu.ToUser(localUser) // merges LDAP data into the existing user
|
||||
localUser.IsAdmin = &isAdmin
|
||||
if err := userService.Update(localUser); err != nil {
|
||||
@@ -144,6 +154,7 @@ func (ls *LdapService) mapToLocalUser(cfg *config.Ldap, lu *LdapUser) (*model.Us
|
||||
localUser.Email = originalEmail
|
||||
localUser.Nickname = originalNickname
|
||||
localUser.IsAdmin = originalIsAdmin
|
||||
localUser.Status = originalStatus
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +188,56 @@ func (ls *LdapService) IsEmailExists(email string) bool {
|
||||
return len(sr.Entries) > 0
|
||||
}
|
||||
|
||||
// GetUserInfoByUsernameLdap returns the user info from LDAP for the given username.
|
||||
func (ls *LdapService) GetUserInfoByUsernameLdap(username string) (*LdapUser, error) {
|
||||
cfg := &global.Config.Ldap
|
||||
if !cfg.Enable {
|
||||
return nil, ErrLdapNotEnabled
|
||||
}
|
||||
sr, err := ls.usernameSearchResult(cfg, username)
|
||||
if err != nil {
|
||||
return nil, errors.Join(ErrLdapSearchFailed, err)
|
||||
}
|
||||
if len(sr.Entries) != 1 {
|
||||
return nil, ErrLdapUserNotFound
|
||||
}
|
||||
return ls.userResultToLdapUser(cfg, sr.Entries[0]), nil
|
||||
}
|
||||
|
||||
// GetUserInfoByUsernameLocal returns the user info from LDAP for the given username. If the user exists, it will sync the user info to the local database.
|
||||
func (ls *LdapService) GetUserInfoByUsernameLocal(username string) (*model.User, error) {
|
||||
ldapUser, err := ls.GetUserInfoByUsernameLdap(username)
|
||||
if err != nil {
|
||||
return &model.User{}, err
|
||||
}
|
||||
return ls.mapToLocalUser(&global.Config.Ldap, ldapUser)
|
||||
}
|
||||
|
||||
// GetUserInfoByEmailLdap returns the user info from LDAP for the given email.
|
||||
func (ls *LdapService) GetUserInfoByEmailLdap(email string) (*LdapUser, error) {
|
||||
cfg := &global.Config.Ldap
|
||||
if !cfg.Enable {
|
||||
return nil, ErrLdapNotEnabled
|
||||
}
|
||||
sr, err := ls.emailSearchResult(cfg, email)
|
||||
if err != nil {
|
||||
return nil, errors.Join(ErrLdapSearchFailed, err)
|
||||
}
|
||||
if len(sr.Entries) != 1 {
|
||||
return nil, ErrLdapUserNotFound
|
||||
}
|
||||
return ls.userResultToLdapUser(cfg, sr.Entries[0]), nil
|
||||
}
|
||||
|
||||
// GetUserInfoByEmailLocal returns the user info from LDAP for the given email. if the user exists, it will synchronize the user information to local database.
|
||||
func (ls *LdapService) GetUserInfoByEmailLocal(email string) (*model.User, error) {
|
||||
ldapUser, err := ls.GetUserInfoByEmailLdap(email)
|
||||
if err != nil {
|
||||
return &model.User{}, err
|
||||
}
|
||||
return ls.mapToLocalUser(&global.Config.Ldap, ldapUser)
|
||||
}
|
||||
|
||||
// usernameSearchResult returns the search result for the given username.
|
||||
func (ls *LdapService) usernameSearchResult(cfg *config.Ldap, username string) (*ldap.SearchResult, error) {
|
||||
// Build the combined filter for the username
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"Gwen/utils"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/github"
|
||||
// "golang.org/x/oauth2/google"
|
||||
@@ -45,6 +45,7 @@ type OauthCacheItem struct {
|
||||
Username string `json:"username"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Verifier string `json:"verifier"` // used for oauth pkce
|
||||
}
|
||||
|
||||
func (oci *OauthCacheItem) ToOauthUser() *model.OauthUser {
|
||||
@@ -92,19 +93,32 @@ func (os *OauthService) DeleteOauthCache(key string) {
|
||||
OauthCache.Delete(key)
|
||||
}
|
||||
|
||||
func (os *OauthService) BeginAuth(op string) (error error, code, url string) {
|
||||
code = utils.RandomString(10) + strconv.FormatInt(time.Now().Unix(), 10)
|
||||
func (os *OauthService) BeginAuth(op string) (error error, state, verifier, url string) {
|
||||
state = utils.RandomString(10) + strconv.FormatInt(time.Now().Unix(), 10)
|
||||
verifier = ""
|
||||
if op == string(model.OauthTypeWebauth) {
|
||||
url = global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/" + code
|
||||
url = global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/" + state
|
||||
//url = "http://localhost:8888/_admin/#/oauth/" + code
|
||||
return nil, code, url
|
||||
return nil, state, verifier, url
|
||||
}
|
||||
err, _, oauthConfig := os.GetOauthConfig(op)
|
||||
err, oauthInfo, oauthConfig := os.GetOauthConfig(op)
|
||||
if err == nil {
|
||||
return err, code, oauthConfig.AuthCodeURL(code)
|
||||
extras := make([]oauth2.AuthCodeOption, 0, 3)
|
||||
if oauthInfo.PkceEnable != nil && *oauthInfo.PkceEnable {
|
||||
extras = append(extras, oauth2.AccessTypeOffline)
|
||||
verifier = oauth2.GenerateVerifier()
|
||||
switch oauthInfo.PkceMethod {
|
||||
case model.PKCEMethodS256:
|
||||
extras = append(extras, oauth2.S256ChallengeOption(verifier))
|
||||
case model.PKCEMethodPlain:
|
||||
// oauth2 does not have a plain challenge option, so we add it manually
|
||||
extras = append(extras, oauth2.SetAuthURLParam("code_challenge_method", "plain"), oauth2.SetAuthURLParam("code_challenge", verifier))
|
||||
}
|
||||
}
|
||||
return err, state, verifier, oauthConfig.AuthCodeURL(state, extras...)
|
||||
}
|
||||
|
||||
return err, code, ""
|
||||
return err, state, verifier, ""
|
||||
}
|
||||
|
||||
// Method to fetch OIDC configuration dynamically
|
||||
@@ -207,15 +221,20 @@ func getHTTPClientWithProxy() *http.Client {
|
||||
return http.DefaultClient
|
||||
}
|
||||
|
||||
func (os *OauthService) callbackBase(oauthConfig *oauth2.Config, code string, userEndpoint string, userData interface{}) (err error, client *http.Client) {
|
||||
func (os *OauthService) callbackBase(oauthConfig *oauth2.Config, code string, verifier string, userEndpoint string, userData interface{}) (err error, client *http.Client) {
|
||||
|
||||
// 设置代理客户端
|
||||
httpClient := getHTTPClientWithProxy()
|
||||
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, httpClient)
|
||||
|
||||
var exchangeOpts []oauth2.AuthCodeOption
|
||||
if verifier != "" {
|
||||
exchangeOpts = []oauth2.AuthCodeOption{oauth2.VerifierOption(verifier)}
|
||||
}
|
||||
|
||||
// 使用 code 换取 token
|
||||
var token *oauth2.Token
|
||||
token, err = oauthConfig.Exchange(ctx, code)
|
||||
token, err = oauthConfig.Exchange(ctx, code, exchangeOpts...)
|
||||
if err != nil {
|
||||
global.Logger.Warn("oauthConfig.Exchange() failed: ", err)
|
||||
return errors.New("GetOauthTokenError"), nil
|
||||
@@ -244,9 +263,9 @@ func (os *OauthService) callbackBase(oauthConfig *oauth2.Config, code string, us
|
||||
}
|
||||
|
||||
// githubCallback github回调
|
||||
func (os *OauthService) githubCallback(oauthConfig *oauth2.Config, code string) (error, *model.OauthUser) {
|
||||
func (os *OauthService) githubCallback(oauthConfig *oauth2.Config, code string, verifier string) (error, *model.OauthUser) {
|
||||
var user = &model.GithubUser{}
|
||||
err, client := os.callbackBase(oauthConfig, code, model.UserEndpointGithub, user)
|
||||
err, client := os.callbackBase(oauthConfig, code, verifier, model.UserEndpointGithub, user)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
@@ -258,16 +277,16 @@ func (os *OauthService) githubCallback(oauthConfig *oauth2.Config, code string)
|
||||
}
|
||||
|
||||
// oidcCallback oidc回调, 通过code获取用户信息
|
||||
func (os *OauthService) oidcCallback(oauthConfig *oauth2.Config, code string, userInfoEndpoint string) (error, *model.OauthUser) {
|
||||
func (os *OauthService) oidcCallback(oauthConfig *oauth2.Config, code string, verifier string, userInfoEndpoint string) (error, *model.OauthUser) {
|
||||
var user = &model.OidcUser{}
|
||||
if err, _ := os.callbackBase(oauthConfig, code, userInfoEndpoint, user); err != nil {
|
||||
if err, _ := os.callbackBase(oauthConfig, code, verifier, userInfoEndpoint, user); err != nil {
|
||||
return err, nil
|
||||
}
|
||||
return nil, user.ToOauthUser()
|
||||
}
|
||||
|
||||
// Callback: Get user information by code and op(Oauth provider)
|
||||
func (os *OauthService) Callback(code string, op string) (err error, oauthUser *model.OauthUser) {
|
||||
func (os *OauthService) Callback(code, verifier, op string) (err error, oauthUser *model.OauthUser) {
|
||||
var oauthInfo *model.Oauth
|
||||
var oauthConfig *oauth2.Config
|
||||
err, oauthInfo, oauthConfig = os.GetOauthConfig(op)
|
||||
@@ -278,13 +297,13 @@ func (os *OauthService) Callback(code string, op string) (err error, oauthUser *
|
||||
oauthType := oauthInfo.OauthType
|
||||
switch oauthType {
|
||||
case model.OauthTypeGithub:
|
||||
err, oauthUser = os.githubCallback(oauthConfig, code)
|
||||
err, oauthUser = os.githubCallback(oauthConfig, code, verifier)
|
||||
case model.OauthTypeOidc, model.OauthTypeGoogle:
|
||||
err, endpoint := os.FetchOidcEndpoint(oauthInfo.Issuer)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
err, oauthUser = os.oidcCallback(oauthConfig, code, endpoint.UserInfo)
|
||||
err, oauthUser = os.oidcCallback(oauthConfig, code, verifier, endpoint.UserInfo)
|
||||
default:
|
||||
return errors.New("unsupported OAuth type"), nil
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"fmt"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"Gwen/global"
|
||||
"Gwen/model"
|
||||
"Gwen/utils"
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UserService struct {
|
||||
@@ -51,7 +52,7 @@ func (us *UserService) InfoByUsernamePassword(username, password string) *model.
|
||||
if err == nil {
|
||||
return u
|
||||
}
|
||||
global.Logger.Error("LDAP authentication failed, %v", err)
|
||||
global.Logger.Errorf("LDAP authentication failed, %v", err)
|
||||
global.Logger.Warn("Fallback to local database")
|
||||
}
|
||||
u := &model.User{}
|
||||
@@ -279,7 +280,7 @@ func (us *UserService) UpdatePassword(u *model.User, password string) error {
|
||||
|
||||
// IsAdmin 是否管理员
|
||||
func (us *UserService) IsAdmin(u *model.User) bool {
|
||||
return *u.IsAdmin
|
||||
return u != nil && *u.IsAdmin
|
||||
}
|
||||
|
||||
// RouteNames
|
||||
@@ -322,7 +323,16 @@ func (us *UserService) RegisterByOauth(oauthUser *model.OauthUser, op string) (e
|
||||
email = strings.ToLower(email)
|
||||
// update email to oauthUser, in case it contain upper case
|
||||
oauthUser.Email = email
|
||||
user := us.InfoByEmail(email)
|
||||
// call this, if find user by email, it will update the email to local database
|
||||
user, ldapErr := AllService.LdapService.GetUserInfoByEmailLocal(email)
|
||||
// If we enable ldap, and the error is not ErrLdapUserNotFound, return the error because we could not sure if the user is not found in ldap
|
||||
if !(errors.Is(ldapErr, ErrLdapNotEnabled) || errors.Is(ldapErr, ErrLdapUserNotFound) || ldapErr == nil) {
|
||||
return ldapErr, user
|
||||
}
|
||||
if user.Id == 0 {
|
||||
// this means the user is not found in ldap, maybe ldao is not enabled
|
||||
user = us.InfoByEmail(email)
|
||||
}
|
||||
if user.Id != 0 {
|
||||
ut.FromOauthUser(user.Id, oauthUser, oauthType, op)
|
||||
global.DB.Create(ut)
|
||||
@@ -466,9 +476,10 @@ func (us *UserService) getAdminUserCount() int64 {
|
||||
func (us *UserService) UserTokenExpireTimestamp() int64 {
|
||||
exp := global.Config.App.TokenExpire
|
||||
if exp == 0 {
|
||||
exp = 3600 * 24 * 7
|
||||
//默认七天
|
||||
exp = 604800
|
||||
}
|
||||
return time.Now().Add(time.Second * time.Duration(exp)).Unix()
|
||||
return time.Now().Add(exp).Unix()
|
||||
}
|
||||
|
||||
func (us *UserService) RefreshAccessToken(ut *model.UserToken) {
|
||||
@@ -491,8 +502,15 @@ func (us *UserService) VerifyJWT(token string) (uint, error) {
|
||||
|
||||
// IsUsernameExists 判断用户名是否存在, it will check the internal database and LDAP(if enabled)
|
||||
func (us *UserService) IsUsernameExists(username string) bool {
|
||||
return us.IsUsernameExistsLocal(username) || AllService.LdapService.IsUsernameExists(username)
|
||||
}
|
||||
|
||||
func (us *UserService) IsUsernameExistsLocal(username string) bool {
|
||||
u := &model.User{}
|
||||
global.DB.Where("username = ?", username).First(u)
|
||||
existsInLdap := AllService.LdapService.IsUsernameExists(username)
|
||||
return u.Id != 0 || existsInLdap
|
||||
return u.Id != 0
|
||||
}
|
||||
|
||||
func (us *UserService) IsEmailExistsLdap(email string) bool {
|
||||
return AllService.LdapService.IsEmailExists(email)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user