Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac5df6826b | ||
|
|
91908859bc | ||
|
|
9c8822f857 | ||
|
|
9709da7fb6 | ||
|
|
1852f10131 | ||
|
|
77d7b43e21 | ||
|
|
7410b539a0 | ||
|
|
0403d71502 | ||
|
|
2af1d93a7d | ||
|
|
76281ad761 | ||
|
|
d1ec9b4916 | ||
|
|
448e7460a9 | ||
|
|
ee0cbabffc | ||
|
|
d6a5af890a | ||
|
|
dc313441e5 | ||
|
|
c75320f4f4 |
@@ -76,6 +76,7 @@ COPY --from=builder-backend /app/release /app/
|
||||
COPY --from=builder-backend /app/conf /app/conf/
|
||||
COPY --from=builder-backend /app/resources /app/resources/
|
||||
COPY --from=builder-backend /app/docs /app/docs/
|
||||
COPY --from=builder-backend /app/http/templates /app/http/templates
|
||||
# Copy frontend build from builder2 stage
|
||||
COPY --from=builder-admin-frontend /frontend/dist/ /app/resources/admin/
|
||||
|
||||
|
||||
67
README.md
67
README.md
@@ -108,8 +108,7 @@
|
||||
* 可以官方指令
|
||||
* 可以添加自定义指令
|
||||
* 可以执行自定义指令
|
||||
|
||||

|
||||
|
||||
|
||||
11. **LDAP 支持**, 当在API Server上设置了LDAP(已测试AD和LDAP),可以通过LDAP中的用户信息进行登录 https://github.com/lejianwen/rustdesk-api/issues/114 ,如果LDAP验证失败,返回本地用户
|
||||
|
||||
@@ -146,72 +145,11 @@
|
||||
|
||||
### 相关配置
|
||||
|
||||
* [配置文件](./conf/config.yaml)
|
||||
* 参考`conf/config.yaml`配置文件,修改相关配置。
|
||||
* 如果`gorm.type`是`sqlite`,则不需要配置mysql相关配置。
|
||||
* 语言如果不设置默认为`zh-CN`
|
||||
|
||||
```yaml
|
||||
lang: "en"
|
||||
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"
|
||||
resources-path: 'resources'
|
||||
trust-proxy: ""
|
||||
gorm:
|
||||
type: "sqlite"
|
||||
max-idle-conns: 10
|
||||
max-open-conns: 100
|
||||
mysql:
|
||||
username: "root"
|
||||
password: "111111"
|
||||
addr: "192.168.1.66:3308"
|
||||
dbname: "rustdesk"
|
||||
rustdesk:
|
||||
id-server: "192.168.1.66:21116"
|
||||
relay-server: "192.168.1.66:21117"
|
||||
api-server: "http://192.168.1.66:21114"
|
||||
key: "123456789"
|
||||
personal: 1
|
||||
logger:
|
||||
path: "./runtime/log.txt"
|
||||
level: "warn" #trace,debug,info,warn,error,fatal
|
||||
report-caller: true
|
||||
proxy:
|
||||
enable: false
|
||||
host: ""
|
||||
jwt:
|
||||
key: ""
|
||||
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.
|
||||
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
环境变量和配置文件`conf/config.yaml`中的配置一一对应,变量名前缀是`RUSTDESK_API`
|
||||
下面表格并未全部列出,可以参考`conf/config.yaml`中的配置。
|
||||
@@ -248,6 +186,7 @@ ldap:
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk存放key的文件 | `./conf/data/id_ed25519.pub` |
|
||||
| RUSTDESK_API_RUSTDESK_WEBCLIENT<br/>_MAGIC_QUERYONLINE | Web client v2 中是否启用新的在线状态查询方法; `1`:启用,`0`:不启用,默认不启用 | `0` |
|
||||
| RUSTDESK_API_RUSTDESK_WS_HOST | 自定义Websocket Host | `wss://192.168.1.123:1234` |
|
||||
| ----PROXY配置----- | ---------- | ---------- |
|
||||
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
|
||||
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
|
||||
|
||||
65
README_EN.md
65
README_EN.md
@@ -109,8 +109,6 @@ displaying data.Frontend code is available at [rustdesk-api-web](https://github.
|
||||
* 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:
|
||||
@@ -145,71 +143,11 @@ displaying data.Frontend code is available at [rustdesk-api-web](https://github.
|
||||
|
||||
### Configuration
|
||||
|
||||
* [Config File](./conf/config.yaml)
|
||||
* Modify the configuration in `conf/config.yaml`.
|
||||
* If `gorm.type` is set to `sqlite`, MySQL-related configurations are not required.
|
||||
* Language support: `en` and `zh-CN` are supported. The default is `zh-CN`.
|
||||
|
||||
```yaml
|
||||
lang: "en"
|
||||
app:
|
||||
web-client: 1 # web client route 1:open 0:close
|
||||
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"
|
||||
resources-path: 'resources'
|
||||
trust-proxy: ""
|
||||
gorm:
|
||||
type: "sqlite"
|
||||
max-idle-conns: 10
|
||||
max-open-conns: 100
|
||||
mysql:
|
||||
username: "root"
|
||||
password: "111111"
|
||||
addr: "192.168.1.66:3308"
|
||||
dbname: "rustdesk"
|
||||
rustdesk:
|
||||
id-server: "192.168.1.66:21116"
|
||||
relay-server: "192.168.1.66:21117"
|
||||
api-server: "http://192.168.1.66:21114"
|
||||
key: "123456789"
|
||||
personal: 1
|
||||
logger:
|
||||
path: "./runtime/log.txt"
|
||||
level: "warn" #trace,debug,info,warn,error,fatal
|
||||
report-caller: true
|
||||
proxy:
|
||||
enable: false
|
||||
host: ""
|
||||
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 environment variables correspond one-to-one with the configurations in the `conf/config.yaml` file. The prefix for variable names is `RUSTDESK_API`.
|
||||
@@ -247,6 +185,7 @@ The table below does not list all configurations. Please refer to the configurat
|
||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk key file | `./conf/data/id_ed25519.pub` |
|
||||
| RUSTDESK_API_RUSTDESK<br/>_WEBCLIENT_MAGIC_QUERYONLINE | New online query method is enabled in the web client v2; '1': Enabled, '0': Disabled, not enabled by default | `0` |
|
||||
| RUSTDESK_API_RUSTDESK_WS_HOST | Custom Websocket Host | `wss://192.168.1.123:1234` |
|
||||
| ---- PROXY ----- | --------------- | ---------- |
|
||||
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
|
||||
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
|
||||
|
||||
@@ -51,6 +51,10 @@ var resetPwdCmd = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
pwd := args[0]
|
||||
admin := service.AllService.UserService.InfoById(1)
|
||||
if admin.Id == 0 {
|
||||
global.Logger.Warn("user not found! ")
|
||||
return
|
||||
}
|
||||
err := service.AllService.UserService.UpdatePassword(admin, pwd)
|
||||
if err != nil {
|
||||
global.Logger.Error("reset password fail! ", err)
|
||||
@@ -77,6 +81,10 @@ var resetUserPwdCmd = &cobra.Command{
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.InfoById(uint(uid))
|
||||
if u.Id == 0 {
|
||||
global.Logger.Warn("user not found! ")
|
||||
return
|
||||
}
|
||||
err = service.AllService.UserService.UpdatePassword(u, pwd)
|
||||
if err != nil {
|
||||
global.Logger.Warn("reset password fail! ", err)
|
||||
@@ -144,7 +152,6 @@ func InitGlobal() {
|
||||
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
||||
})
|
||||
}
|
||||
DatabaseAutoUpdate()
|
||||
|
||||
//validator
|
||||
global.ApiInitValidator()
|
||||
@@ -164,9 +171,14 @@ func InitGlobal() {
|
||||
global.Jwt = jwt.NewJwt(global.Config.Jwt.Key, global.Config.Jwt.ExpireDuration)
|
||||
//locker
|
||||
global.Lock = lock.NewLocal()
|
||||
|
||||
//service
|
||||
service.New(&global.Config, global.DB, global.Logger, global.Jwt, global.Lock)
|
||||
|
||||
DatabaseAutoUpdate()
|
||||
}
|
||||
func DatabaseAutoUpdate() {
|
||||
version := 260
|
||||
version := 262
|
||||
|
||||
db := global.DB
|
||||
|
||||
@@ -210,6 +222,7 @@ func DatabaseAutoUpdate() {
|
||||
if v.Version < uint(version) {
|
||||
Migrate(uint(version))
|
||||
}
|
||||
|
||||
// 245迁移
|
||||
if v.Version < 245 {
|
||||
//oauths 表的 oauth_type 字段设置为 op同样的值
|
||||
@@ -232,7 +245,7 @@ func DatabaseAutoUpdate() {
|
||||
|
||||
}
|
||||
func Migrate(version uint) {
|
||||
global.Logger.Info("migrating....", version)
|
||||
global.Logger.Info("Migrating....", version)
|
||||
err := global.DB.AutoMigrate(
|
||||
&model.Version{},
|
||||
&model.User{},
|
||||
@@ -250,6 +263,7 @@ func Migrate(version uint) {
|
||||
&model.AddressBookCollection{},
|
||||
&model.AddressBookCollectionRule{},
|
||||
&model.ServerCmd{},
|
||||
&model.DeviceGroup{},
|
||||
)
|
||||
if err != nil {
|
||||
global.Logger.Error("migrate err :=>", err)
|
||||
|
||||
@@ -32,6 +32,7 @@ rustdesk:
|
||||
key-file: "/data/id_ed25519.pub"
|
||||
personal: 1
|
||||
webclient-magic-queryonline: 0
|
||||
ws-host: "" #eg: wss://192.168.1.3:4443
|
||||
logger:
|
||||
path: "./runtime/log.txt"
|
||||
level: "info" #trace,debug,info,warn,error,fatal
|
||||
@@ -45,7 +46,7 @@ jwt:
|
||||
ldap:
|
||||
enable: false
|
||||
url: "ldap://ldap.example.com:389"
|
||||
tls: false
|
||||
tls-ca-file: ""
|
||||
tls-verify: false
|
||||
base-dn: "dc=example,dc=com"
|
||||
bind-dn: "cn=admin,dc=example,dc=com"
|
||||
|
||||
@@ -26,7 +26,7 @@ type LdapUser struct {
|
||||
type Ldap struct {
|
||||
Enable bool `mapstructure:"enable"`
|
||||
Url string `mapstructure:"url"`
|
||||
TLS bool `mapstructure:"tls"`
|
||||
TlsCaFile string `mapstructure:"tls-ca-file"`
|
||||
TlsVerify bool `mapstructure:"tls-verify"`
|
||||
BaseDn string `mapstructure:"base-dn"`
|
||||
BindDn string `mapstructure:"bind-dn"`
|
||||
|
||||
@@ -21,7 +21,8 @@ type Rustdesk struct {
|
||||
KeyFile string `mapstructure:"key-file"`
|
||||
Personal int `mapstructure:"personal"`
|
||||
//webclient-magic-queryonline
|
||||
WebclientMagicQueryonline int `mapstructure:"webclient-magic-queryonline"`
|
||||
WebclientMagicQueryonline int `mapstructure:"webclient-magic-queryonline"`
|
||||
WsHost string `mapstructure:"ws-host"`
|
||||
}
|
||||
|
||||
func (rd *Rustdesk) LoadKeyFile() {
|
||||
|
||||
@@ -1407,6 +1407,280 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/create": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "创建设备群组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备群组"
|
||||
],
|
||||
"summary": "创建设备群组",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "设备群组信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.DeviceGroupForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.DeviceGroup"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/delete": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备群组删除",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备群组"
|
||||
],
|
||||
"summary": "设备群组删除",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "群组信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.DeviceGroupForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/detail/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备群组详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备群组"
|
||||
],
|
||||
"summary": "设备群组详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.Group"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "群组列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"群组"
|
||||
],
|
||||
"summary": "群组列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页大小",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.GroupList"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备群组编辑",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备群组"
|
||||
],
|
||||
"summary": "设备群组编辑",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "群组信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.DeviceGroupForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.Group"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/file/oss_token": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -1783,7 +2057,7 @@ const docTemplateadmin = `{
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/github_com_lejianwen_rustdesk-api_http_request_admin.Login"
|
||||
"$ref": "#/definitions/github_com_lejianwen_rustdesk-api_v2_http_request_admin.Login"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -5219,6 +5493,20 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.DeviceGroupForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.GroupForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -5306,6 +5594,12 @@ const docTemplateadmin = `{
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
"pkce_enable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"pkce_method": {
|
||||
"type": "string"
|
||||
},
|
||||
"redirect_url": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -5334,6 +5628,9 @@ const docTemplateadmin = `{
|
||||
"cpu": {
|
||||
"type": "string"
|
||||
},
|
||||
"group_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hostname": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -5521,7 +5818,7 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"github_com_lejianwen_rustdesk-api_http_request_admin.Login": {
|
||||
"github_com_lejianwen_rustdesk-api_v2_http_request_admin.Login": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
@@ -5842,6 +6139,23 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.DeviceGroup": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.Group": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5973,6 +6287,12 @@ const docTemplateadmin = `{
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
"pkce_enable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"pkce_method": {
|
||||
"type": "string"
|
||||
},
|
||||
"redirect_url": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -6013,6 +6333,9 @@ const docTemplateadmin = `{
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"group_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hostname": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1400,6 +1400,280 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/create": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "创建设备群组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备群组"
|
||||
],
|
||||
"summary": "创建设备群组",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "设备群组信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.DeviceGroupForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.DeviceGroup"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/delete": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备群组删除",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备群组"
|
||||
],
|
||||
"summary": "设备群组删除",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "群组信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.DeviceGroupForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/detail/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备群组详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备群组"
|
||||
],
|
||||
"summary": "设备群组详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.Group"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "群组列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"群组"
|
||||
],
|
||||
"summary": "群组列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页大小",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.GroupList"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/device_group/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备群组编辑",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备群组"
|
||||
],
|
||||
"summary": "设备群组编辑",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "群组信息",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/admin.DeviceGroupForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.Group"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/file/oss_token": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -1776,7 +2050,7 @@
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/github_com_lejianwen_rustdesk-api_http_request_admin.Login"
|
||||
"$ref": "#/definitions/github_com_lejianwen_rustdesk-api_v2_http_request_admin.Login"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -5212,6 +5486,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.DeviceGroupForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.GroupForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -5299,6 +5587,12 @@
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
"pkce_enable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"pkce_method": {
|
||||
"type": "string"
|
||||
},
|
||||
"redirect_url": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -5327,6 +5621,9 @@
|
||||
"cpu": {
|
||||
"type": "string"
|
||||
},
|
||||
"group_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hostname": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -5514,7 +5811,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"github_com_lejianwen_rustdesk-api_http_request_admin.Login": {
|
||||
"github_com_lejianwen_rustdesk-api_v2_http_request_admin.Login": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password",
|
||||
@@ -5835,6 +6132,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.DeviceGroup": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.Group": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5966,6 +6280,12 @@
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
"pkce_enable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"pkce_method": {
|
||||
"type": "string"
|
||||
},
|
||||
"redirect_url": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -6006,6 +6326,9 @@
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"group_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hostname": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -77,6 +77,15 @@ definitions:
|
||||
- new_password
|
||||
- old_password
|
||||
type: object
|
||||
admin.DeviceGroupForm:
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
admin.GroupForm:
|
||||
properties:
|
||||
id:
|
||||
@@ -130,6 +139,10 @@ definitions:
|
||||
type: string
|
||||
op:
|
||||
type: string
|
||||
pkce_enable:
|
||||
type: boolean
|
||||
pkce_method:
|
||||
type: string
|
||||
redirect_url:
|
||||
type: string
|
||||
scopes:
|
||||
@@ -153,6 +166,8 @@ definitions:
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
group_id:
|
||||
type: integer
|
||||
hostname:
|
||||
type: string
|
||||
id:
|
||||
@@ -278,7 +293,7 @@ definitions:
|
||||
required:
|
||||
- ids
|
||||
type: object
|
||||
github_com_lejianwen_rustdesk-api_http_request_admin.Login:
|
||||
github_com_lejianwen_rustdesk-api_v2_http_request_admin.Login:
|
||||
properties:
|
||||
captcha:
|
||||
type: string
|
||||
@@ -492,6 +507,17 @@ definitions:
|
||||
total:
|
||||
type: integer
|
||||
type: object
|
||||
model.DeviceGroup:
|
||||
properties:
|
||||
created_at:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
updated_at:
|
||||
type: string
|
||||
type: object
|
||||
model.Group:
|
||||
properties:
|
||||
created_at:
|
||||
@@ -579,6 +605,10 @@ definitions:
|
||||
type: string
|
||||
op:
|
||||
type: string
|
||||
pkce_enable:
|
||||
type: boolean
|
||||
pkce_method:
|
||||
type: string
|
||||
redirect_url:
|
||||
type: string
|
||||
scopes:
|
||||
@@ -605,6 +635,8 @@ definitions:
|
||||
type: string
|
||||
created_at:
|
||||
type: string
|
||||
group_id:
|
||||
type: integer
|
||||
hostname:
|
||||
type: string
|
||||
id:
|
||||
@@ -1610,6 +1642,167 @@ paths:
|
||||
summary: RUSTDESK服务配置
|
||||
tags:
|
||||
- ADMIN
|
||||
/admin/device_group/create:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建设备群组
|
||||
parameters:
|
||||
- description: 设备群组信息
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/admin.DeviceGroupForm'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/response.Response'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/model.DeviceGroup'
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 创建设备群组
|
||||
tags:
|
||||
- 设备群组
|
||||
/admin/device_group/delete:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 设备群组删除
|
||||
parameters:
|
||||
- description: 群组信息
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/admin.DeviceGroupForm'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 设备群组删除
|
||||
tags:
|
||||
- 设备群组
|
||||
/admin/device_group/detail/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 设备群组详情
|
||||
parameters:
|
||||
- description: ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/response.Response'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/model.Group'
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 设备群组详情
|
||||
tags:
|
||||
- 设备群组
|
||||
/admin/device_group/list:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 群组列表
|
||||
parameters:
|
||||
- description: 页码
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: 页大小
|
||||
in: query
|
||||
name: page_size
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/response.Response'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/model.GroupList'
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 群组列表
|
||||
tags:
|
||||
- 群组
|
||||
/admin/device_group/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 设备群组编辑
|
||||
parameters:
|
||||
- description: 群组信息
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/admin.DeviceGroupForm'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/response.Response'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/model.Group'
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 设备群组编辑
|
||||
tags:
|
||||
- 设备群组
|
||||
/admin/file/oss_token:
|
||||
get:
|
||||
consumes:
|
||||
@@ -1830,7 +2023,7 @@ paths:
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/github_com_lejianwen_rustdesk-api_http_request_admin.Login'
|
||||
$ref: '#/definitions/github_com_lejianwen_rustdesk-api_v2_http_request_admin.Login'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
||||
@@ -767,6 +767,66 @@ const docTemplateapi = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/device-group/accessible": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "机器",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"群组"
|
||||
],
|
||||
"summary": "设备",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "每页数量",
|
||||
"name": "pageSize",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "状态",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "accessible",
|
||||
"name": "accessible",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.DataResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/heartbeat": {
|
||||
"post": {
|
||||
"description": "心跳",
|
||||
|
||||
@@ -760,6 +760,66 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/device-group/accessible": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "机器",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"群组"
|
||||
],
|
||||
"summary": "设备",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "每页数量",
|
||||
"name": "pageSize",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "状态",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "accessible",
|
||||
"name": "accessible",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.DataResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/heartbeat": {
|
||||
"post": {
|
||||
"description": "心跳",
|
||||
|
||||
@@ -671,6 +671,44 @@ paths:
|
||||
summary: 用户信息
|
||||
tags:
|
||||
- 用户
|
||||
/device-group/accessible:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 机器
|
||||
parameters:
|
||||
- description: 页码
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: 每页数量
|
||||
in: query
|
||||
name: pageSize
|
||||
type: integer
|
||||
- description: 状态
|
||||
in: query
|
||||
name: status
|
||||
type: integer
|
||||
- description: accessible
|
||||
in: query
|
||||
name: accessible
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.DataResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 设备
|
||||
tags:
|
||||
- 群组
|
||||
/heartbeat:
|
||||
post:
|
||||
consumes:
|
||||
|
||||
2
go.mod
2
go.mod
@@ -36,9 +36,11 @@ require (
|
||||
github.com/bytedance/sonic v1.8.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.12.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||
github.com/go-ldap/ldap/v3 v3.4.10 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"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,13 +61,22 @@ func (co *Config) AppConfig(c *gin.Context) {
|
||||
// @Security token
|
||||
func (co *Config) AdminConfig(c *gin.Context) {
|
||||
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
if u == nil || u.Id == 0 {
|
||||
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 != "" {
|
||||
|
||||
160
http/controller/admin/deviceGroup.go
Normal file
160
http/controller/admin/deviceGroup.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
type DeviceGroup struct {
|
||||
}
|
||||
|
||||
// Detail 设备群组
|
||||
// @Tags 设备群组
|
||||
// @Summary 设备群组详情
|
||||
// @Description 设备群组详情
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "ID"
|
||||
// @Success 200 {object} response.Response{data=model.Group}
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/device_group/detail/{id} [get]
|
||||
// @Security token
|
||||
func (ct *DeviceGroup) Detail(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
iid, _ := strconv.Atoi(id)
|
||||
u := service.AllService.GroupService.DeviceGroupInfoById(uint(iid))
|
||||
if u.Id > 0 {
|
||||
response.Success(c, u)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
return
|
||||
}
|
||||
|
||||
// Create 创建设备群组
|
||||
// @Tags 设备群组
|
||||
// @Summary 创建设备群组
|
||||
// @Description 创建设备群组
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body admin.DeviceGroupForm true "设备群组信息"
|
||||
// @Success 200 {object} response.Response{data=model.DeviceGroup}
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/device_group/create [post]
|
||||
// @Security token
|
||||
func (ct *DeviceGroup) Create(c *gin.Context) {
|
||||
f := &admin.DeviceGroupForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
u := f.ToDeviceGroup()
|
||||
err := service.AllService.GroupService.DeviceGroupCreate(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
}
|
||||
|
||||
// List 列表
|
||||
// @Tags 群组
|
||||
// @Summary 群组列表
|
||||
// @Description 群组列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "页码"
|
||||
// @Param page_size query int false "页大小"
|
||||
// @Success 200 {object} response.Response{data=model.GroupList}
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/device_group/list [get]
|
||||
// @Security token
|
||||
func (ct *DeviceGroup) List(c *gin.Context) {
|
||||
query := &admin.PageQuery{}
|
||||
if err := c.ShouldBindQuery(query); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
res := service.AllService.GroupService.DeviceGroupList(query.Page, query.PageSize, nil)
|
||||
response.Success(c, res)
|
||||
}
|
||||
|
||||
// Update 编辑
|
||||
// @Tags 设备群组
|
||||
// @Summary 设备群组编辑
|
||||
// @Description 设备群组编辑
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body admin.DeviceGroupForm true "群组信息"
|
||||
// @Success 200 {object} response.Response{data=model.Group}
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/device_group/update [post]
|
||||
// @Security token
|
||||
func (ct *DeviceGroup) Update(c *gin.Context) {
|
||||
f := &admin.DeviceGroupForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
if f.Id == 0 {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
errList := global.Validator.ValidStruct(c, f)
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
u := f.ToDeviceGroup()
|
||||
err := service.AllService.GroupService.DeviceGroupUpdate(u)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, nil)
|
||||
}
|
||||
|
||||
// Delete 删除
|
||||
// @Tags 设备群组
|
||||
// @Summary 设备群组删除
|
||||
// @Description 设备群组删除
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body admin.DeviceGroupForm true "群组信息"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /admin/device_group/delete [post]
|
||||
// @Security token
|
||||
func (ct *DeviceGroup) Delete(c *gin.Context) {
|
||||
f := &admin.DeviceGroupForm{}
|
||||
if err := c.ShouldBindJSON(f); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
id := f.Id
|
||||
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||
if len(errList) > 0 {
|
||||
response.Fail(c, 101, errList[0])
|
||||
return
|
||||
}
|
||||
u := service.AllService.GroupService.DeviceGroupInfoById(f.Id)
|
||||
if u.Id > 0 {
|
||||
err := service.AllService.GroupService.DeviceGroupDelete(u)
|
||||
if err == nil {
|
||||
response.Success(c, nil)
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||
return
|
||||
}
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||
}
|
||||
@@ -283,13 +283,13 @@ func (ct *Login) OidcAuth(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||
err, state, verifier, nonce, 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,
|
||||
@@ -297,10 +297,12 @@ func (ct *Login) OidcAuth(c *gin.Context) {
|
||||
// DeviceOs: ct.Platform(c),
|
||||
DeviceOs: f.DeviceInfo.Os,
|
||||
Uuid: f.Uuid,
|
||||
Verifier: verifier,
|
||||
Nonce: nonce,
|
||||
}, 5*60)
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"code": code,
|
||||
"code": state,
|
||||
"url": url,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -43,20 +43,22 @@ func (o *Oauth) ToBind(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||
err, state, verifier, nonce, 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{
|
||||
Action: service.OauthActionTypeBind,
|
||||
Op: f.Op,
|
||||
UserId: u.Id,
|
||||
service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
|
||||
Action: service.OauthActionTypeBind,
|
||||
Op: f.Op,
|
||||
UserId: u.Id,
|
||||
Verifier: verifier,
|
||||
Nonce: nonce,
|
||||
}, 5*60)
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"code": code,
|
||||
"code": state,
|
||||
"url": url,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (g *Group) Users(c *gin.Context) {
|
||||
userList = service.AllService.UserService.ListByGroupId(u.GroupId, q.Page, q.PageSize)
|
||||
}
|
||||
|
||||
var data []*apiResp.UserPayload
|
||||
data := make([]*apiResp.UserPayload, 0, len(userList.Users))
|
||||
for _, user := range userList.Users {
|
||||
up := &apiResp.UserPayload{}
|
||||
up.FromUser(user)
|
||||
@@ -88,21 +88,30 @@ func (g *Group) Peers(c *gin.Context) {
|
||||
users = service.AllService.UserService.ListIdAndNameByGroupId(u.GroupId)
|
||||
}
|
||||
|
||||
namesById := make(map[uint]string)
|
||||
userIds := make([]uint, 0)
|
||||
namesById := make(map[uint]string, len(users))
|
||||
userIds := make([]uint, 0, len(users))
|
||||
for _, user := range users {
|
||||
namesById[user.Id] = user.Username
|
||||
userIds = append(userIds, user.Id)
|
||||
}
|
||||
dGroupNameById := make(map[uint]string)
|
||||
allGroup := service.AllService.GroupService.DeviceGroupList(1, 999, nil)
|
||||
for _, group := range allGroup.DeviceGroups {
|
||||
dGroupNameById[group.Id] = group.Name
|
||||
}
|
||||
peerList := service.AllService.PeerService.ListByUserIds(userIds, q.Page, q.PageSize)
|
||||
var data []*apiResp.GroupPeerPayload
|
||||
data := make([]*apiResp.GroupPeerPayload, 0, len(peerList.Peers))
|
||||
for _, peer := range peerList.Peers {
|
||||
uname, ok := namesById[peer.UserId]
|
||||
if !ok {
|
||||
uname = ""
|
||||
}
|
||||
dGroupName, ok2 := dGroupNameById[peer.GroupId]
|
||||
if !ok2 {
|
||||
dGroupName = ""
|
||||
}
|
||||
pp := &apiResp.GroupPeerPayload{}
|
||||
pp.FromPeer(peer, uname)
|
||||
pp.FromPeer(peer, uname, dGroupName)
|
||||
data = append(data, pp)
|
||||
|
||||
}
|
||||
@@ -111,3 +120,31 @@ func (g *Group) Peers(c *gin.Context) {
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// Device
|
||||
// @Tags 群组
|
||||
// @Summary 设备
|
||||
// @Description 机器
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "页码"
|
||||
// @Param pageSize query int false "每页数量"
|
||||
// @Param status query int false "状态"
|
||||
// @Param accessible query string false "accessible"
|
||||
// @Success 200 {object} response.DataResponse
|
||||
// @Failure 500 {object} response.Response
|
||||
// @Router /device-group/accessible [get]
|
||||
// @Security BearerAuth
|
||||
func (g *Group) Device(c *gin.Context) {
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
if !service.AllService.UserService.IsAdmin(u) {
|
||||
response.Error(c, "Permission denied")
|
||||
return
|
||||
}
|
||||
allGroup := service.AllService.GroupService.DeviceGroupList(1, 999, nil)
|
||||
|
||||
c.JSON(http.StatusOK, response.DataResponse{
|
||||
Total: 0,
|
||||
Data: allGroup.DeviceGroups,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -32,15 +32,14 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
|
||||
}
|
||||
|
||||
oauthService := service.AllService.OauthService
|
||||
var code string
|
||||
var url string
|
||||
err, code, url = oauthService.BeginAuth(f.Op)
|
||||
|
||||
err, state, verifier, nonce, 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 +47,12 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
|
||||
DeviceName: f.DeviceInfo.Name,
|
||||
DeviceOs: f.DeviceInfo.Os,
|
||||
DeviceType: f.DeviceInfo.Type,
|
||||
Verifier: verifier,
|
||||
Nonce: nonce,
|
||||
}, 5*60)
|
||||
//fmt.Println("code url", code, url)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": code,
|
||||
"code": state,
|
||||
"url": url,
|
||||
})
|
||||
}
|
||||
@@ -143,7 +144,9 @@ func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
||||
func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
state := c.Query("state")
|
||||
if state == "" {
|
||||
c.String(http.StatusInternalServerError, response.TranslateParamMsg(c, "ParamIsEmpty", "state"))
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateParamMsg(c, "ParamIsEmpty", "state"),
|
||||
})
|
||||
return
|
||||
}
|
||||
cacheKey := state
|
||||
@@ -151,17 +154,23 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
//从缓存中获取
|
||||
oauthCache := oauthService.GetOauthCache(cacheKey)
|
||||
if oauthCache == nil {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthExpired"))
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthExpired"),
|
||||
})
|
||||
return
|
||||
}
|
||||
nonce := oauthCache.Nonce
|
||||
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, nonce)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthFailed") + response.TranslateMsg(c, err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
userId := oauthCache.UserId
|
||||
@@ -172,28 +181,38 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
// 检查此openid是否已经绑定过
|
||||
utr := oauthService.UserThirdInfo(op, openid)
|
||||
if utr.UserId > 0 {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthHasBindOtherUser"),
|
||||
})
|
||||
return
|
||||
}
|
||||
//绑定
|
||||
user = service.AllService.UserService.InfoById(userId)
|
||||
if user == nil {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "ItemNotFound"),
|
||||
})
|
||||
return
|
||||
}
|
||||
//绑定
|
||||
err := oauthService.BindOauthUser(userId, oauthUser, op)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "BindFail"),
|
||||
})
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
|
||||
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "BindSuccess"),
|
||||
})
|
||||
return
|
||||
|
||||
} else if action == service.OauthActionTypeLogin {
|
||||
//登录
|
||||
if userId != 0 {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthHasBeenSuccess"),
|
||||
})
|
||||
return
|
||||
}
|
||||
user = service.AllService.UserService.InfoByOauthId(op, openid)
|
||||
@@ -210,7 +229,9 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
//自动注册
|
||||
err, user = service.AllService.UserService.RegisterByOauth(oauthUser, op)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, err.Error()))
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -230,10 +251,14 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
c.Redirect(http.StatusFound, url)
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
||||
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthSuccess"),
|
||||
})
|
||||
return
|
||||
} else {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "ParamsError"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Index struct {
|
||||
@@ -15,13 +15,21 @@ func (i *Index) Index(c *gin.Context) {
|
||||
|
||||
func (i *Index) ConfigJs(c *gin.Context) {
|
||||
apiServer := global.Config.Rustdesk.ApiServer
|
||||
magicQueryonline := strconv.Itoa(global.Config.Rustdesk.WebclientMagicQueryonline)
|
||||
tmp := `
|
||||
localStorage.setItem('api-server', "` + apiServer + `")
|
||||
const ws2_prefix = 'wc-'
|
||||
localStorage.setItem(ws2_prefix+'api-server', "` + apiServer + `")
|
||||
magicQueryonline := global.Config.Rustdesk.WebclientMagicQueryonline
|
||||
tmp := fmt.Sprintf(`localStorage.setItem('api-server', '%v');
|
||||
const ws2_prefix = 'wc-';
|
||||
localStorage.setItem(ws2_prefix+'api-server', '%v');
|
||||
|
||||
window.webclient_magic_queryonline = ` + magicQueryonline + ``
|
||||
window.webclient_magic_queryonline = %d;
|
||||
window.ws_host = '%v';
|
||||
`, apiServer, apiServer, magicQueryonline, global.Config.Rustdesk.WsHost)
|
||||
// tmp := `
|
||||
//localStorage.setItem('api-server', "` + apiServer + `")
|
||||
//const ws2_prefix = 'wc-'
|
||||
//localStorage.setItem(ws2_prefix+'api-server', "` + apiServer + `")
|
||||
//
|
||||
//window.webclient_magic_queryonline = ` + magicQueryonline + ``
|
||||
|
||||
c.Header("Content-Type", "application/javascript")
|
||||
c.String(200, tmp)
|
||||
}
|
||||
|
||||
@@ -22,3 +22,15 @@ func (gf *GroupForm) ToGroup() *model.Group {
|
||||
group.Type = gf.Type
|
||||
return group
|
||||
}
|
||||
|
||||
type DeviceGroupForm struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
}
|
||||
|
||||
func (gf *DeviceGroupForm) ToDeviceGroup() *model.DeviceGroup {
|
||||
group := &model.DeviceGroup{}
|
||||
group.Id = gf.Id
|
||||
group.Name = gf.Name
|
||||
return group
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ type OauthForm struct {
|
||||
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 {
|
||||
@@ -36,6 +38,8 @@ func (of *OauthForm) ToOauth() *model.Oauth {
|
||||
AutoRegister: of.AutoRegister,
|
||||
Issuer: of.Issuer,
|
||||
Scopes: of.Scopes,
|
||||
PkceEnable: of.PkceEnable,
|
||||
PkceMethod: of.PkceMethod,
|
||||
}
|
||||
oa.Id = of.Id
|
||||
return oa
|
||||
|
||||
@@ -12,6 +12,7 @@ type PeerForm struct {
|
||||
Username string `json:"username"`
|
||||
Uuid string `json:"uuid"`
|
||||
Version string `json:"version"`
|
||||
GroupId uint `json:"group_id"`
|
||||
}
|
||||
|
||||
type PeerBatchDeleteForm struct {
|
||||
@@ -30,6 +31,7 @@ func (f *PeerForm) ToPeer() *model.Peer {
|
||||
Username: f.Username,
|
||||
Uuid: f.Uuid,
|
||||
Version: f.Version,
|
||||
GroupId: f.GroupId,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,13 @@ https://github.com/rustdesk/rustdesk/blob/master/flutter/lib/common/hbbs/hbbs.da
|
||||
}
|
||||
*/
|
||||
type GroupPeerPayload struct {
|
||||
Id string `json:"id"`
|
||||
Info *PeerPayloadInfo `json:"info"`
|
||||
Status int `json:"status"`
|
||||
User string `json:"user"`
|
||||
UserName string `json:"user_name"`
|
||||
Note string `json:"note"`
|
||||
Id string `json:"id"`
|
||||
Info *PeerPayloadInfo `json:"info"`
|
||||
Status int `json:"status"`
|
||||
User string `json:"user"`
|
||||
UserName string `json:"user_name"`
|
||||
Note string `json:"note"`
|
||||
DeviceGroupName string `json:"device_group_name"`
|
||||
}
|
||||
type PeerPayloadInfo struct {
|
||||
DeviceName string `json:"device_name"`
|
||||
@@ -59,7 +60,7 @@ func (gpp *GroupPeerPayload) FromAddressBook(a *model.AddressBook, username stri
|
||||
gpp.UserName = username
|
||||
}
|
||||
|
||||
func (gpp *GroupPeerPayload) FromPeer(p *model.Peer, username string) {
|
||||
func (gpp *GroupPeerPayload) FromPeer(p *model.Peer, username string, dGroupName string) {
|
||||
gpp.Id = p.Id
|
||||
gpp.Info = &PeerPayloadInfo{
|
||||
DeviceName: p.Hostname,
|
||||
@@ -68,4 +69,5 @@ func (gpp *GroupPeerPayload) FromPeer(p *model.Peer, username string) {
|
||||
}
|
||||
gpp.Note = ""
|
||||
gpp.UserName = username
|
||||
gpp.DeviceGroupName = dGroupName
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ func Init(g *gin.Engine) {
|
||||
MyBind(adg)
|
||||
|
||||
RustdeskCmdBind(adg)
|
||||
|
||||
DeviceGroupBind(adg)
|
||||
//访问静态文件
|
||||
//g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload"))
|
||||
}
|
||||
@@ -106,6 +106,18 @@ func GroupBind(rg *gin.RouterGroup) {
|
||||
}
|
||||
}
|
||||
|
||||
func DeviceGroupBind(rg *gin.RouterGroup) {
|
||||
aR := rg.Group("/device_group").Use(middleware.AdminPrivilege())
|
||||
{
|
||||
cont := &admin.DeviceGroup{}
|
||||
aR.GET("/list", cont.List)
|
||||
aR.GET("/detail/:id", cont.Detail)
|
||||
aR.POST("/create", cont.Create)
|
||||
aR.POST("/update", cont.Update)
|
||||
aR.POST("/delete", cont.Delete)
|
||||
}
|
||||
}
|
||||
|
||||
func TagBind(rg *gin.RouterGroup) {
|
||||
aR := rg.Group("/tag").Use(middleware.AdminPrivilege())
|
||||
{
|
||||
|
||||
@@ -18,6 +18,8 @@ func ApiInit(g *gin.Engine) {
|
||||
if global.Config.App.ShowSwagger == 1 {
|
||||
g.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.InstanceName("api")))
|
||||
}
|
||||
// 加载 HTML 模板
|
||||
g.LoadHTMLGlob("resources/templates/*")
|
||||
|
||||
frg := g.Group("/api")
|
||||
|
||||
@@ -79,6 +81,8 @@ func ApiInit(g *gin.Engine) {
|
||||
gr := &api.Group{}
|
||||
frg.GET("/users", gr.Users)
|
||||
frg.GET("/peers", gr.Peers)
|
||||
// /api/device-group/accessible?current=1&pageSize=100
|
||||
frg.GET("/device-group/accessible", gr.Device)
|
||||
}
|
||||
|
||||
{
|
||||
@@ -88,6 +92,7 @@ func ApiInit(g *gin.Engine) {
|
||||
//更新地址
|
||||
frg.POST("/ab", ab.UpAb)
|
||||
}
|
||||
|
||||
PersonalRoutes(frg)
|
||||
//访问静态文件
|
||||
g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/public/upload"))
|
||||
|
||||
@@ -16,3 +16,14 @@ type GroupList struct {
|
||||
Groups []*Group `json:"list"`
|
||||
Pagination
|
||||
}
|
||||
|
||||
type DeviceGroup struct {
|
||||
IdModel
|
||||
Name string `json:"name" gorm:"default:'';not null;"`
|
||||
TimeModel
|
||||
}
|
||||
|
||||
type DeviceGroupList struct {
|
||||
DeviceGroups []*DeviceGroup `json:"list"`
|
||||
Pagination
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ type Peer struct {
|
||||
User *User `json:"user,omitempty"`
|
||||
LastOnlineTime int64 `json:"last_online_time" gorm:"default:0;not null;"`
|
||||
LastOnlineIp string `json:"last_online_ip" gorm:"default:'';not null;"`
|
||||
GroupId uint `json:"group_id" gorm:"default:0;not null;index"`
|
||||
TimeModel
|
||||
}
|
||||
|
||||
|
||||
73
resources/templates/oauth_fail.html
Normal file
73
resources/templates/oauth_fail.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>授权失败 - RustDesk API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.success-container {
|
||||
text-align: center;
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
color: #ba363a;
|
||||
font-size: 4rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.return-link {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background-color: #ba363a;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.return-link:hover {
|
||||
background-color: #ba363a;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/6.0.0/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="success-container">
|
||||
<i class="fas fa-triangle-exclamation checkmark"></i>
|
||||
<h1>授权失败!</h1>
|
||||
<p>{{.message}}</p>
|
||||
<a href="javascript:window.close()" class="return-link">关闭页面</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
73
resources/templates/oauth_success.html
Normal file
73
resources/templates/oauth_success.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>授权成功 - RustDesk API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.success-container {
|
||||
text-align: center;
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
color: #4CAF50;
|
||||
font-size: 4rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.return-link {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.return-link:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="success-container">
|
||||
<i class="fas fa-check-circle checkmark"></i>
|
||||
<h1>授权成功!</h1>
|
||||
<p>您已成功授权访问您的账户。</p>
|
||||
<p>现在可以关闭本页面或返回应用继续操作。</p>
|
||||
<a href="javascript:window.close()" class="return-link">关闭页面</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
3
resources/web2/js/dist/index.js
vendored
3
resources/web2/js/dist/index.js
vendored
@@ -11088,6 +11088,9 @@ function R4(u = !1) {
|
||||
}
|
||||
|
||||
function getUriFromRs(uri, isRelay = false, roffset = 0) {
|
||||
if (window.ws_host) {
|
||||
return window.ws_host + "/ws/" + (isRelay ? "relay" : "id")
|
||||
}
|
||||
const p = isHttps() ? "wss://" : "ws://"
|
||||
const [domain, uriport] = uri.split(":")
|
||||
if (!isHttps()) {
|
||||
|
||||
@@ -3,7 +3,6 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/google/uuid"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
@@ -14,24 +13,24 @@ type AddressBookService struct {
|
||||
|
||||
func (s *AddressBookService) Info(id string) *model.AddressBook {
|
||||
p := &model.AddressBook{}
|
||||
global.DB.Where("id = ?", id).First(p)
|
||||
DB.Where("id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (s *AddressBookService) InfoByUserIdAndId(userid uint, id string) *model.AddressBook {
|
||||
p := &model.AddressBook{}
|
||||
global.DB.Where("user_id = ? and id = ?", userid, id).First(p)
|
||||
DB.Where("user_id = ? and id = ?", userid, id).First(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (s *AddressBookService) InfoByUserIdAndIdAndCid(userid uint, id string, cid uint) *model.AddressBook {
|
||||
p := &model.AddressBook{}
|
||||
global.DB.Where("user_id = ? and id = ? and collection_id = ?", userid, id, cid).First(p)
|
||||
DB.Where("user_id = ? and id = ? and collection_id = ?", userid, id, cid).First(p)
|
||||
return p
|
||||
}
|
||||
func (s *AddressBookService) InfoByRowId(id uint) *model.AddressBook {
|
||||
p := &model.AddressBook{}
|
||||
global.DB.Where("row_id = ?", id).First(p)
|
||||
DB.Where("row_id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
func (s *AddressBookService) ListByUserId(userId, page, pageSize uint) (res *model.AddressBookList) {
|
||||
@@ -49,14 +48,14 @@ func (s *AddressBookService) ListByUserIds(userIds []uint, page, pageSize uint)
|
||||
|
||||
// AddAddressBook
|
||||
func (s *AddressBookService) AddAddressBook(ab *model.AddressBook) error {
|
||||
return global.DB.Create(ab).Error
|
||||
return DB.Create(ab).Error
|
||||
}
|
||||
|
||||
// UpdateAddressBook
|
||||
func (s *AddressBookService) UpdateAddressBook(abs []*model.AddressBook, userId uint) error {
|
||||
//比较peers和数据库中的数据,如果peers中的数据在数据库中不存在,则添加,如果存在则更新,如果数据库中的数据在peers中不存在,则删除
|
||||
// 开始事务
|
||||
tx := global.DB.Begin()
|
||||
tx := DB.Begin()
|
||||
//1. 获取数据库中的数据
|
||||
var dbABs []*model.AddressBook
|
||||
tx.Where("user_id = ?", userId).Find(&dbABs)
|
||||
@@ -107,7 +106,7 @@ func (s *AddressBookService) List(page, pageSize uint, where func(tx *gorm.DB))
|
||||
res = &model.AddressBookList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.AddressBook{})
|
||||
tx := DB.Model(&model.AddressBook{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -129,38 +128,38 @@ func (s *AddressBookService) FromPeer(peer *model.Peer) (a *model.AddressBook) {
|
||||
|
||||
// Create 创建
|
||||
func (s *AddressBookService) Create(u *model.AddressBook) error {
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
func (s *AddressBookService) Delete(u *model.AddressBook) error {
|
||||
return global.DB.Delete(u).Error
|
||||
return DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (s *AddressBookService) Update(u *model.AddressBook) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
return DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
// UpdateByMap 更新
|
||||
func (s *AddressBookService) UpdateByMap(u *model.AddressBook, data map[string]interface{}) error {
|
||||
return global.DB.Model(u).Updates(data).Error
|
||||
return DB.Model(u).Updates(data).Error
|
||||
}
|
||||
|
||||
// UpdateAll 更新
|
||||
func (s *AddressBookService) UpdateAll(u *model.AddressBook) error {
|
||||
return global.DB.Model(u).Select("*").Omit("created_at").Updates(u).Error
|
||||
return DB.Model(u).Select("*").Omit("created_at").Updates(u).Error
|
||||
}
|
||||
|
||||
// ShareByWebClient 分享
|
||||
func (s *AddressBookService) ShareByWebClient(m *model.ShareRecord) error {
|
||||
m.ShareToken = uuid.New().String()
|
||||
return global.DB.Create(m).Error
|
||||
return DB.Create(m).Error
|
||||
}
|
||||
|
||||
// SharedPeer
|
||||
func (s *AddressBookService) SharedPeer(shareToken string) *model.ShareRecord {
|
||||
m := &model.ShareRecord{}
|
||||
global.DB.Where("share_token = ?", shareToken).First(m)
|
||||
DB.Where("share_token = ?", shareToken).First(m)
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -190,7 +189,7 @@ func (s *AddressBookService) ListCollection(page, pageSize uint, where func(tx *
|
||||
res = &model.AddressBookCollectionList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.AddressBookCollection{})
|
||||
tx := DB.Model(&model.AddressBookCollection{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -200,7 +199,7 @@ func (s *AddressBookService) ListCollection(page, pageSize uint, where func(tx *
|
||||
return
|
||||
}
|
||||
func (s *AddressBookService) ListCollectionByIds(ids []uint) (res []*model.AddressBookCollection) {
|
||||
global.DB.Where("id in ?", ids).Find(&res)
|
||||
DB.Where("id in ?", ids).Find(&res)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -212,20 +211,20 @@ func (s *AddressBookService) ListCollectionByUserId(userId uint) (res *model.Add
|
||||
}
|
||||
func (s *AddressBookService) CollectionInfoById(id uint) *model.AddressBookCollection {
|
||||
p := &model.AddressBookCollection{}
|
||||
global.DB.Where("id = ?", id).First(p)
|
||||
DB.Where("id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (s *AddressBookService) CollectionReadRules(user *model.User) (res []*model.AddressBookCollectionRule) {
|
||||
// personalRules
|
||||
var personalRules []*model.AddressBookCollectionRule
|
||||
tx2 := global.DB.Model(&model.AddressBookCollectionRule{})
|
||||
tx2 := DB.Model(&model.AddressBookCollectionRule{})
|
||||
tx2.Where("type = ? and to_id = ? and rule > 0", model.ShareAddressBookRuleTypePersonal, user.Id).Find(&personalRules)
|
||||
res = append(res, personalRules...)
|
||||
|
||||
//group
|
||||
var groupRules []*model.AddressBookCollectionRule
|
||||
tx3 := global.DB.Model(&model.AddressBookCollectionRule{})
|
||||
tx3 := DB.Model(&model.AddressBookCollectionRule{})
|
||||
tx3.Where("type = ? and to_id = ? and rule > 0", model.ShareAddressBookRuleTypeGroup, user.GroupId).Find(&groupRules)
|
||||
res = append(res, groupRules...)
|
||||
return
|
||||
@@ -238,7 +237,7 @@ func (s *AddressBookService) UserMaxRule(user *model.User, uid, cid uint) int {
|
||||
}
|
||||
max := 0
|
||||
personalRules := &model.AddressBookCollectionRule{}
|
||||
tx := global.DB.Model(personalRules)
|
||||
tx := DB.Model(personalRules)
|
||||
tx.Where("type = ? and collection_id = ? and to_id = ?", model.ShareAddressBookRuleTypePersonal, cid, user.Id).First(&personalRules)
|
||||
if personalRules.Id != 0 {
|
||||
max = personalRules.Rule
|
||||
@@ -248,7 +247,7 @@ func (s *AddressBookService) UserMaxRule(user *model.User, uid, cid uint) int {
|
||||
}
|
||||
|
||||
groupRules := &model.AddressBookCollectionRule{}
|
||||
tx2 := global.DB.Model(groupRules)
|
||||
tx2 := DB.Model(groupRules)
|
||||
tx2.Where("type = ? and collection_id = ? and to_id = ?", model.ShareAddressBookRuleTypeGroup, cid, user.GroupId).First(&groupRules)
|
||||
if groupRules.Id != 0 {
|
||||
if groupRules.Rule > max {
|
||||
@@ -272,16 +271,16 @@ func (s *AddressBookService) CheckUserFullControlPrivilege(user *model.User, uid
|
||||
}
|
||||
|
||||
func (s *AddressBookService) CreateCollection(t *model.AddressBookCollection) error {
|
||||
return global.DB.Create(t).Error
|
||||
return DB.Create(t).Error
|
||||
}
|
||||
|
||||
func (s *AddressBookService) UpdateCollection(t *model.AddressBookCollection) error {
|
||||
return global.DB.Model(t).Updates(t).Error
|
||||
return DB.Model(t).Updates(t).Error
|
||||
}
|
||||
|
||||
func (s *AddressBookService) DeleteCollection(t *model.AddressBookCollection) error {
|
||||
//删除集合下的所有规则、地址簿,再删除集合
|
||||
tx := global.DB.Begin()
|
||||
tx := DB.Begin()
|
||||
tx.Where("collection_id = ?", t.Id).Delete(&model.AddressBookCollectionRule{})
|
||||
tx.Where("collection_id = ?", t.Id).Delete(&model.AddressBook{})
|
||||
tx.Delete(t)
|
||||
@@ -290,23 +289,23 @@ func (s *AddressBookService) DeleteCollection(t *model.AddressBookCollection) er
|
||||
|
||||
func (s *AddressBookService) RuleInfoById(u uint) *model.AddressBookCollectionRule {
|
||||
p := &model.AddressBookCollectionRule{}
|
||||
global.DB.Where("id = ?", u).First(p)
|
||||
DB.Where("id = ?", u).First(p)
|
||||
return p
|
||||
}
|
||||
func (s *AddressBookService) RulePersonalInfoByToIdAndCid(toid, cid uint) *model.AddressBookCollectionRule {
|
||||
p := &model.AddressBookCollectionRule{}
|
||||
global.DB.Where("type = ? and to_id = ? and collection_id = ?", model.ShareAddressBookRuleTypePersonal, toid, cid).First(p)
|
||||
DB.Where("type = ? and to_id = ? and collection_id = ?", model.ShareAddressBookRuleTypePersonal, toid, cid).First(p)
|
||||
return p
|
||||
}
|
||||
func (s *AddressBookService) CreateRule(t *model.AddressBookCollectionRule) error {
|
||||
return global.DB.Create(t).Error
|
||||
return DB.Create(t).Error
|
||||
}
|
||||
|
||||
func (s *AddressBookService) ListRules(page uint, size uint, f func(tx *gorm.DB)) *model.AddressBookCollectionRuleList {
|
||||
res := &model.AddressBookCollectionRuleList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(size)
|
||||
tx := global.DB.Model(&model.AddressBookCollectionRule{})
|
||||
tx := DB.Model(&model.AddressBookCollectionRule{})
|
||||
if f != nil {
|
||||
f(tx)
|
||||
}
|
||||
@@ -317,11 +316,11 @@ func (s *AddressBookService) ListRules(page uint, size uint, f func(tx *gorm.DB)
|
||||
}
|
||||
|
||||
func (s *AddressBookService) UpdateRule(t *model.AddressBookCollectionRule) error {
|
||||
return global.DB.Model(t).Updates(t).Error
|
||||
return DB.Model(t).Updates(t).Error
|
||||
}
|
||||
|
||||
func (s *AddressBookService) DeleteRule(t *model.AddressBookCollectionRule) error {
|
||||
return global.DB.Delete(t).Error
|
||||
return DB.Delete(t).Error
|
||||
}
|
||||
|
||||
// CheckCollectionOwner 检查Collection的所有者
|
||||
@@ -336,5 +335,5 @@ func (s *AddressBookService) BatchUpdateTags(abs []*model.AddressBook, tags []st
|
||||
ids = append(ids, ab.RowId)
|
||||
}
|
||||
tagsv, _ := json.Marshal(tags)
|
||||
return global.DB.Model(&model.AddressBook{}).Where("row_id in ?", ids).Update("tags", tagsv).Error
|
||||
return DB.Model(&model.AddressBook{}).Where("row_id in ?", ids).Update("tags", tagsv).Error
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -13,7 +12,7 @@ func (as *AuditService) AuditConnList(page, pageSize uint, where func(tx *gorm.D
|
||||
res = &model.AuditConnList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.AuditConn{})
|
||||
tx := DB.Model(&model.AuditConn{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -25,36 +24,36 @@ func (as *AuditService) AuditConnList(page, pageSize uint, where func(tx *gorm.D
|
||||
|
||||
// Create 创建
|
||||
func (as *AuditService) CreateAuditConn(u *model.AuditConn) error {
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
func (as *AuditService) DeleteAuditConn(u *model.AuditConn) error {
|
||||
return global.DB.Delete(u).Error
|
||||
return DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (as *AuditService) UpdateAuditConn(u *model.AuditConn) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
return DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
// InfoByPeerIdAndConnId
|
||||
func (as *AuditService) InfoByPeerIdAndConnId(peerId string, connId int64) (res *model.AuditConn) {
|
||||
res = &model.AuditConn{}
|
||||
global.DB.Where("peer_id = ? and conn_id = ?", peerId, connId).First(res)
|
||||
DB.Where("peer_id = ? and conn_id = ?", peerId, connId).First(res)
|
||||
return
|
||||
}
|
||||
|
||||
// ConnInfoById
|
||||
func (as *AuditService) ConnInfoById(id uint) (res *model.AuditConn) {
|
||||
res = &model.AuditConn{}
|
||||
global.DB.Where("id = ?", id).First(res)
|
||||
DB.Where("id = ?", id).First(res)
|
||||
return
|
||||
}
|
||||
|
||||
// FileInfoById
|
||||
func (as *AuditService) FileInfoById(id uint) (res *model.AuditFile) {
|
||||
res = &model.AuditFile{}
|
||||
global.DB.Where("id = ?", id).First(res)
|
||||
DB.Where("id = ?", id).First(res)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -62,7 +61,7 @@ func (as *AuditService) AuditFileList(page, pageSize uint, where func(tx *gorm.D
|
||||
res = &model.AuditFileList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.AuditFile{})
|
||||
tx := DB.Model(&model.AuditFile{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -74,22 +73,22 @@ func (as *AuditService) AuditFileList(page, pageSize uint, where func(tx *gorm.D
|
||||
|
||||
// CreateAuditFile
|
||||
func (as *AuditService) CreateAuditFile(u *model.AuditFile) error {
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
func (as *AuditService) DeleteAuditFile(u *model.AuditFile) error {
|
||||
return global.DB.Delete(u).Error
|
||||
return DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (as *AuditService) UpdateAuditFile(u *model.AuditFile) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
return DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
func (as *AuditService) BatchDeleteAuditConn(ids []uint) error {
|
||||
return global.DB.Where("id in (?)", ids).Delete(&model.AuditConn{}).Error
|
||||
return DB.Where("id in (?)", ids).Delete(&model.AuditConn{}).Error
|
||||
}
|
||||
|
||||
func (as *AuditService) BatchDeleteAuditFile(ids []uint) error {
|
||||
return global.DB.Where("id in (?)", ids).Delete(&model.AuditFile{}).Error
|
||||
return DB.Where("id in (?)", ids).Delete(&model.AuditFile{}).Error
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -12,7 +11,7 @@ type GroupService struct {
|
||||
// InfoById 根据用户id取用户信息
|
||||
func (us *GroupService) InfoById(id uint) *model.Group {
|
||||
u := &model.Group{}
|
||||
global.DB.Where("id = ?", id).First(u)
|
||||
DB.Where("id = ?", id).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
@@ -20,7 +19,7 @@ func (us *GroupService) List(page, pageSize uint, where func(tx *gorm.DB)) (res
|
||||
res = &model.GroupList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.Group{})
|
||||
tx := DB.Model(&model.Group{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -32,14 +31,47 @@ func (us *GroupService) List(page, pageSize uint, where func(tx *gorm.DB)) (res
|
||||
|
||||
// Create 创建
|
||||
func (us *GroupService) Create(u *model.Group) error {
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
func (us *GroupService) Delete(u *model.Group) error {
|
||||
return global.DB.Delete(u).Error
|
||||
return DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (us *GroupService) Update(u *model.Group) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
return DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
// DeviceGroupInfoById 根据用户id取用户信息
|
||||
func (us *GroupService) DeviceGroupInfoById(id uint) *model.DeviceGroup {
|
||||
u := &model.DeviceGroup{}
|
||||
DB.Where("id = ?", id).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
func (us *GroupService) DeviceGroupList(page, pageSize uint, where func(tx *gorm.DB)) (res *model.DeviceGroupList) {
|
||||
res = &model.DeviceGroupList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := DB.Model(&model.DeviceGroup{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
tx.Count(&res.Total)
|
||||
tx.Scopes(Paginate(page, pageSize))
|
||||
tx.Find(&res.DeviceGroups)
|
||||
return
|
||||
}
|
||||
|
||||
func (us *GroupService) DeviceGroupCreate(u *model.DeviceGroup) error {
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
func (us *GroupService) DeviceGroupDelete(u *model.DeviceGroup) error {
|
||||
return DB.Delete(u).Error
|
||||
}
|
||||
|
||||
func (us *GroupService) DeviceGroupUpdate(u *model.DeviceGroup) error {
|
||||
return DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
@@ -2,19 +2,23 @@ package service
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"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 (
|
||||
ErrUrlParseFailed = errors.New("UrlParseFailed")
|
||||
ErrFileReadFailed = errors.New("FileReadFailed")
|
||||
ErrLdapNotEnabled = errors.New("LdapNotEnabled")
|
||||
ErrLdapUserDisabled = errors.New("UserDisabledAtLdap")
|
||||
ErrLdapUserNotFound = errors.New("UserNotFound")
|
||||
@@ -68,21 +72,38 @@ func (lu *LdapUser) ToUser(u *model.User) *model.User {
|
||||
|
||||
// connectAndBind creates an LDAP connection, optionally starts TLS, and then binds using the provided credentials.
|
||||
func (ls *LdapService) connectAndBind(cfg *config.Ldap, username, password string) (*ldap.Conn, error) {
|
||||
conn, err := ldap.DialURL(cfg.Url)
|
||||
u, err := url.Parse(cfg.Url)
|
||||
if err != nil {
|
||||
return nil, errors.Join(ErrUrlParseFailed, err)
|
||||
}
|
||||
|
||||
var conn *ldap.Conn
|
||||
if u.Scheme == "ldaps" {
|
||||
// WARNING: InsecureSkipVerify: true is not recommended for production
|
||||
tlsConfig := &tls.Config{InsecureSkipVerify: !cfg.TlsVerify}
|
||||
if cfg.TlsCaFile != "" {
|
||||
caCert, err := os.ReadFile(cfg.TlsCaFile)
|
||||
if err != nil {
|
||||
return nil, errors.Join(ErrFileReadFailed, err)
|
||||
}
|
||||
caCertPool := x509.NewCertPool()
|
||||
if !caCertPool.AppendCertsFromPEM(caCert) {
|
||||
return nil, errors.Join(ErrLdapTlsFailed, errors.New("failed to append CA certificate"))
|
||||
}
|
||||
tlsConfig.RootCAs = caCertPool
|
||||
}
|
||||
conn, err = ldap.DialURL(cfg.Url, ldap.DialWithTLSConfig(tlsConfig))
|
||||
} else {
|
||||
conn, err = ldap.DialURL(cfg.Url)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
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, errors.Join(ErrLdapTlsFailed, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Bind as the "service" user
|
||||
if err = conn.Bind(username, password); err != nil {
|
||||
fmt.Println("Bind failed")
|
||||
conn.Close()
|
||||
return nil, errors.Join(ErrLdapBindService, err)
|
||||
}
|
||||
@@ -114,7 +135,7 @@ func (ls *LdapService) Authenticate(username, password string) (*model.User, err
|
||||
if !ldapUser.Enabled {
|
||||
return nil, ErrLdapUserDisabled
|
||||
}
|
||||
cfg := &global.Config.Ldap
|
||||
cfg := &Config.Ldap
|
||||
user, err := ls.mapToLocalUser(cfg, ldapUser)
|
||||
if err != nil {
|
||||
return nil, errors.Join(ErrLdapToLocalUserFailed, err)
|
||||
@@ -135,7 +156,7 @@ func (ls *LdapService) mapToLocalUser(cfg *config.Ldap, lu *LdapUser) (*model.Us
|
||||
// If needed, you can set a random password here.
|
||||
newUser.IsAdmin = &isAdmin
|
||||
newUser.GroupId = 1
|
||||
if err := global.DB.Create(newUser).Error; err != nil {
|
||||
if err := DB.Create(newUser).Error; err != nil {
|
||||
return nil, errors.Join(ErrLdapCreateUserFailed, err)
|
||||
}
|
||||
return userService.InfoByUsername(lu.Username), nil
|
||||
@@ -164,7 +185,7 @@ func (ls *LdapService) mapToLocalUser(cfg *config.Ldap, lu *LdapUser) (*model.Us
|
||||
// IsUsernameExists checks if a username exists in LDAP (can be useful for local registration checks).
|
||||
func (ls *LdapService) IsUsernameExists(username string) bool {
|
||||
|
||||
cfg := &global.Config.Ldap
|
||||
cfg := &Config.Ldap
|
||||
if !cfg.Enable {
|
||||
return false
|
||||
}
|
||||
@@ -177,7 +198,7 @@ func (ls *LdapService) IsUsernameExists(username string) bool {
|
||||
|
||||
// IsEmailExists checks if an email exists in LDAP (can be useful for local registration checks).
|
||||
func (ls *LdapService) IsEmailExists(email string) bool {
|
||||
cfg := &global.Config.Ldap
|
||||
cfg := &Config.Ldap
|
||||
if !cfg.Enable {
|
||||
return false
|
||||
}
|
||||
@@ -190,7 +211,7 @@ func (ls *LdapService) IsEmailExists(email string) bool {
|
||||
|
||||
// GetUserInfoByUsernameLdap returns the user info from LDAP for the given username.
|
||||
func (ls *LdapService) GetUserInfoByUsernameLdap(username string) (*LdapUser, error) {
|
||||
cfg := &global.Config.Ldap
|
||||
cfg := &Config.Ldap
|
||||
if !cfg.Enable {
|
||||
return nil, ErrLdapNotEnabled
|
||||
}
|
||||
@@ -210,12 +231,12 @@ func (ls *LdapService) GetUserInfoByUsernameLocal(username string) (*model.User,
|
||||
if err != nil {
|
||||
return &model.User{}, err
|
||||
}
|
||||
return ls.mapToLocalUser(&global.Config.Ldap, ldapUser)
|
||||
return ls.mapToLocalUser(&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
|
||||
cfg := &Config.Ldap
|
||||
if !cfg.Enable {
|
||||
return nil, ErrLdapNotEnabled
|
||||
}
|
||||
@@ -235,7 +256,7 @@ func (ls *LdapService) GetUserInfoByEmailLocal(email string) (*model.User, error
|
||||
if err != nil {
|
||||
return &model.User{}, err
|
||||
}
|
||||
return ls.mapToLocalUser(&global.Config.Ldap, ldapUser)
|
||||
return ls.mapToLocalUser(&Config.Ldap, ldapUser)
|
||||
}
|
||||
|
||||
// usernameSearchResult returns the search result for the given username.
|
||||
@@ -453,12 +474,12 @@ func (ls *LdapService) isUserEnabled(cfg *config.Ldap, ldapUser *LdapUser) bool
|
||||
|
||||
// Account is disabled if the ACCOUNTDISABLE flag (0x2) is set
|
||||
const ACCOUNTDISABLE = 0x2
|
||||
ldapUser.Enabled = (userAccountControl&ACCOUNTDISABLE == 0)
|
||||
ldapUser.Enabled = userAccountControl&ACCOUNTDISABLE == 0
|
||||
return ldapUser.Enabled
|
||||
}
|
||||
|
||||
// For other attributes, perform a direct comparison with the expected value
|
||||
ldapUser.Enabled = (ldapUser.EnableAttrValue == enableAttrValue)
|
||||
ldapUser.Enabled = ldapUser.EnableAttrValue == enableAttrValue
|
||||
return ldapUser.Enabled
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -12,7 +11,7 @@ type LoginLogService struct {
|
||||
// InfoById 根据用户id取用户信息
|
||||
func (us *LoginLogService) InfoById(id uint) *model.LoginLog {
|
||||
u := &model.LoginLog{}
|
||||
global.DB.Where("id = ?", id).First(u)
|
||||
DB.Where("id = ?", id).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
@@ -20,7 +19,7 @@ func (us *LoginLogService) List(page, pageSize uint, where func(tx *gorm.DB)) (r
|
||||
res = &model.LoginLogList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.LoginLog{})
|
||||
tx := DB.Model(&model.LoginLog{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -32,20 +31,20 @@ func (us *LoginLogService) List(page, pageSize uint, where func(tx *gorm.DB)) (r
|
||||
|
||||
// Create 创建
|
||||
func (us *LoginLogService) Create(u *model.LoginLog) error {
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
func (us *LoginLogService) Delete(u *model.LoginLog) error {
|
||||
return global.DB.Delete(u).Error
|
||||
return DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (us *LoginLogService) Update(u *model.LoginLog) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
return DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
func (us *LoginLogService) BatchDelete(ids []uint) error {
|
||||
return global.DB.Where("id in (?)", ids).Delete(&model.LoginLog{}).Error
|
||||
return DB.Where("id in (?)", ids).Delete(&model.LoginLog{}).Error
|
||||
}
|
||||
|
||||
func (us *LoginLogService) SoftDelete(l *model.LoginLog) error {
|
||||
@@ -54,5 +53,5 @@ func (us *LoginLogService) SoftDelete(l *model.LoginLog) error {
|
||||
}
|
||||
|
||||
func (us *LoginLogService) BatchSoftDelete(uid uint, ids []uint) error {
|
||||
return global.DB.Model(&model.LoginLog{}).Where("user_id = ? and id in (?)", uid, ids).Update("is_deleted", model.IsDeletedYes).Error
|
||||
return DB.Model(&model.LoginLog{}).Where("user_id = ? and id in (?)", uid, ids).Update("is_deleted", model.IsDeletedYes).Error
|
||||
}
|
||||
|
||||
248
service/oauth.go
248
service/oauth.go
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||
"golang.org/x/oauth2"
|
||||
@@ -45,6 +45,8 @@ type OauthCacheItem struct {
|
||||
Username string `json:"username"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Verifier string `json:"verifier"` // used for oauth pkce
|
||||
Nonce string `json:"nonce"`
|
||||
}
|
||||
|
||||
func (oci *OauthCacheItem) ToOauthUser() *model.OauthUser {
|
||||
@@ -81,10 +83,9 @@ func (os *OauthService) GetOauthCache(key string) *OauthCacheItem {
|
||||
func (os *OauthService) SetOauthCache(key string, item *OauthCacheItem, expire uint) {
|
||||
OauthCache.Store(key, item)
|
||||
if expire > 0 {
|
||||
go func() {
|
||||
time.Sleep(time.Duration(expire) * time.Second)
|
||||
time.AfterFunc(time.Duration(expire)*time.Second, func() {
|
||||
os.DeleteOauthCache(key)
|
||||
}()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,151 +93,192 @@ 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)
|
||||
if op == string(model.OauthTypeWebauth) {
|
||||
url = global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/" + code
|
||||
func (os *OauthService) BeginAuth(op string) (error error, state, verifier, nonce, url string) {
|
||||
state = utils.RandomString(10) + strconv.FormatInt(time.Now().Unix(), 10)
|
||||
verifier = ""
|
||||
nonce = ""
|
||||
if op == model.OauthTypeWebauth {
|
||||
url = Config.Rustdesk.ApiServer + "/_admin/#/oauth/" + state
|
||||
//url = "http://localhost:8888/_admin/#/oauth/" + code
|
||||
return nil, code, url
|
||||
return nil, state, verifier, nonce, 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)
|
||||
|
||||
nonce = utils.RandomString(10)
|
||||
extras = append(extras, oauth2.SetAuthURLParam("nonce", nonce))
|
||||
|
||||
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, nonce, oauthConfig.AuthCodeURL(state, extras...)
|
||||
}
|
||||
|
||||
return err, code, ""
|
||||
return err, state, verifier, nonce, ""
|
||||
}
|
||||
|
||||
// Method to fetch OIDC configuration dynamically
|
||||
func (os *OauthService) FetchOidcEndpoint(issuer string) (error, OidcEndpoint) {
|
||||
configURL := strings.TrimSuffix(issuer, "/") + "/.well-known/openid-configuration"
|
||||
func (os *OauthService) FetchOidcProvider(issuer string) (error, *oidc.Provider) {
|
||||
|
||||
// Get the HTTP client (with or without proxy based on configuration)
|
||||
client := getHTTPClientWithProxy()
|
||||
|
||||
resp, err := client.Get(configURL)
|
||||
ctx := oidc.ClientContext(context.Background(), client)
|
||||
|
||||
provider, err := oidc.NewProvider(ctx, issuer)
|
||||
if err != nil {
|
||||
return errors.New("failed to fetch OIDC configuration"), OidcEndpoint{}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.New("OIDC configuration not found, status code: %d"), OidcEndpoint{}
|
||||
return err, nil
|
||||
}
|
||||
|
||||
var endpoint OidcEndpoint
|
||||
if err := json.NewDecoder(resp.Body).Decode(&endpoint); err != nil {
|
||||
return errors.New("failed to parse OIDC configuration"), OidcEndpoint{}
|
||||
}
|
||||
|
||||
return nil, endpoint
|
||||
return nil, provider
|
||||
}
|
||||
|
||||
func (os *OauthService) FetchOidcEndpointByOp(op string) (error, OidcEndpoint) {
|
||||
oauthInfo := os.InfoByOp(op)
|
||||
if oauthInfo.Issuer == "" {
|
||||
return errors.New("issuer is empty"), OidcEndpoint{}
|
||||
}
|
||||
return os.FetchOidcEndpoint(oauthInfo.Issuer)
|
||||
func (os *OauthService) GithubProvider() *oidc.Provider {
|
||||
return (&oidc.ProviderConfig{
|
||||
IssuerURL: "",
|
||||
AuthURL: github.Endpoint.AuthURL,
|
||||
TokenURL: github.Endpoint.TokenURL,
|
||||
DeviceAuthURL: github.Endpoint.DeviceAuthURL,
|
||||
UserInfoURL: model.UserEndpointGithub,
|
||||
JWKSURL: "",
|
||||
Algorithms: nil,
|
||||
}).NewProvider(context.Background())
|
||||
}
|
||||
|
||||
// GetOauthConfig retrieves the OAuth2 configuration based on the provider name
|
||||
func (os *OauthService) GetOauthConfig(op string) (err error, oauthInfo *model.Oauth, oauthConfig *oauth2.Config) {
|
||||
err, oauthInfo, oauthConfig = os.getOauthConfigGeneral(op)
|
||||
if err != nil {
|
||||
return err, nil, nil
|
||||
func (os *OauthService) GetOauthConfig(op string) (err error, oauthInfo *model.Oauth, oauthConfig *oauth2.Config, provider *oidc.Provider) {
|
||||
//err, oauthInfo, oauthConfig = os.getOauthConfigGeneral(op)
|
||||
oauthInfo = os.InfoByOp(op)
|
||||
if oauthInfo.Id == 0 || oauthInfo.ClientId == "" || oauthInfo.ClientSecret == "" {
|
||||
return errors.New("ConfigNotFound"), nil, nil, nil
|
||||
}
|
||||
// If the redirect URL is empty, use the default redirect URL
|
||||
if oauthInfo.RedirectUrl == "" {
|
||||
oauthInfo.RedirectUrl = Config.Rustdesk.ApiServer + "/api/oidc/callback"
|
||||
}
|
||||
oauthConfig = &oauth2.Config{
|
||||
ClientID: oauthInfo.ClientId,
|
||||
ClientSecret: oauthInfo.ClientSecret,
|
||||
RedirectURL: oauthInfo.RedirectUrl,
|
||||
}
|
||||
|
||||
// Maybe should validate the oauthConfig here
|
||||
oauthType := oauthInfo.OauthType
|
||||
err = model.ValidateOauthType(oauthType)
|
||||
if err != nil {
|
||||
return err, nil, nil
|
||||
return err, nil, nil, nil
|
||||
}
|
||||
switch oauthType {
|
||||
case model.OauthTypeGithub:
|
||||
oauthConfig.Endpoint = github.Endpoint
|
||||
oauthConfig.Scopes = []string{"read:user", "user:email"}
|
||||
provider = os.GithubProvider()
|
||||
//case model.OauthTypeGoogle: //google单独出来,可以少一次FetchOidcEndpoint请求
|
||||
// oauthConfig.Endpoint = google.Endpoint
|
||||
// oauthConfig.Scopes = os.constructScopes(oauthInfo.Scopes)
|
||||
case model.OauthTypeOidc, model.OauthTypeGoogle:
|
||||
var endpoint OidcEndpoint
|
||||
err, endpoint = os.FetchOidcEndpoint(oauthInfo.Issuer)
|
||||
err, provider = os.FetchOidcProvider(oauthInfo.Issuer)
|
||||
if err != nil {
|
||||
return err, nil, nil
|
||||
return err, nil, nil, nil
|
||||
}
|
||||
oauthConfig.Endpoint = oauth2.Endpoint{AuthURL: endpoint.AuthURL, TokenURL: endpoint.TokenURL}
|
||||
oauthConfig.Endpoint = provider.Endpoint()
|
||||
oauthConfig.Scopes = os.constructScopes(oauthInfo.Scopes)
|
||||
default:
|
||||
return errors.New("unsupported OAuth type"), nil, nil
|
||||
}
|
||||
return nil, oauthInfo, oauthConfig
|
||||
}
|
||||
|
||||
// GetOauthConfig retrieves the OAuth2 configuration based on the provider name
|
||||
func (os *OauthService) getOauthConfigGeneral(op string) (err error, oauthInfo *model.Oauth, oauthConfig *oauth2.Config) {
|
||||
oauthInfo = os.InfoByOp(op)
|
||||
if oauthInfo.Id == 0 || oauthInfo.ClientId == "" || oauthInfo.ClientSecret == "" {
|
||||
return errors.New("ConfigNotFound"), nil, nil
|
||||
}
|
||||
// If the redirect URL is empty, use the default redirect URL
|
||||
if oauthInfo.RedirectUrl == "" {
|
||||
oauthInfo.RedirectUrl = global.Config.Rustdesk.ApiServer + "/api/oidc/callback"
|
||||
}
|
||||
return nil, oauthInfo, &oauth2.Config{
|
||||
ClientID: oauthInfo.ClientId,
|
||||
ClientSecret: oauthInfo.ClientSecret,
|
||||
RedirectURL: oauthInfo.RedirectUrl,
|
||||
return errors.New("unsupported OAuth type"), nil, nil, nil
|
||||
}
|
||||
return nil, oauthInfo, oauthConfig, provider
|
||||
}
|
||||
|
||||
func getHTTPClientWithProxy() *http.Client {
|
||||
//todo add timeout
|
||||
if global.Config.Proxy.Enable {
|
||||
if global.Config.Proxy.Host == "" {
|
||||
global.Logger.Warn("Proxy is enabled but proxy host is empty.")
|
||||
//add timeout 30s
|
||||
timeout := time.Duration(60) * time.Second
|
||||
if Config.Proxy.Enable {
|
||||
if Config.Proxy.Host == "" {
|
||||
Logger.Warn("Proxy is enabled but proxy host is empty.")
|
||||
return http.DefaultClient
|
||||
}
|
||||
proxyURL, err := url.Parse(global.Config.Proxy.Host)
|
||||
proxyURL, err := url.Parse(Config.Proxy.Host)
|
||||
if err != nil {
|
||||
global.Logger.Warn("Invalid proxy URL: ", err)
|
||||
Logger.Warn("Invalid proxy URL: ", err)
|
||||
return http.DefaultClient
|
||||
}
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyURL(proxyURL),
|
||||
}
|
||||
return &http.Client{Transport: transport}
|
||||
return &http.Client{Transport: transport, Timeout: timeout}
|
||||
}
|
||||
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, provider *oidc.Provider, code string, verifier string, nonce string, userData interface{}) (err error, client *http.Client) {
|
||||
|
||||
// 设置代理客户端
|
||||
httpClient := getHTTPClientWithProxy()
|
||||
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, httpClient)
|
||||
|
||||
// 使用 code 换取 token
|
||||
var token *oauth2.Token
|
||||
token, err = oauthConfig.Exchange(ctx, code)
|
||||
exchangeOpts := make([]oauth2.AuthCodeOption, 0, 1)
|
||||
if verifier != "" {
|
||||
exchangeOpts = append(exchangeOpts, oauth2.VerifierOption(verifier))
|
||||
}
|
||||
|
||||
token, err := oauthConfig.Exchange(ctx, code, exchangeOpts...)
|
||||
|
||||
if err != nil {
|
||||
global.Logger.Warn("oauthConfig.Exchange() failed: ", err)
|
||||
Logger.Warn("oauthConfig.Exchange() failed: ", err)
|
||||
return errors.New("GetOauthTokenError"), nil
|
||||
}
|
||||
|
||||
// 获取 ID Token, github没有id_token
|
||||
rawIDToken, ok := token.Extra("id_token").(string)
|
||||
if ok && rawIDToken != "" {
|
||||
// 验证 ID Token
|
||||
v := provider.Verifier(&oidc.Config{ClientID: oauthConfig.ClientID})
|
||||
idToken, err2 := v.Verify(ctx, rawIDToken)
|
||||
if err2 != nil {
|
||||
Logger.Warn("IdTokenVerifyError: ", err2)
|
||||
return errors.New("IdTokenVerifyError"), nil
|
||||
}
|
||||
if nonce != "" {
|
||||
// 验证 nonce
|
||||
var claims struct {
|
||||
Nonce string `json:"nonce"`
|
||||
}
|
||||
if err2 = idToken.Claims(&claims); err2 != nil {
|
||||
Logger.Warn("Failed to parse ID Token claims: ", err)
|
||||
return errors.New("IDTokenClaimsError"), nil
|
||||
}
|
||||
|
||||
if claims.Nonce != nonce {
|
||||
Logger.Warn("Nonce does not match")
|
||||
return errors.New("NonceDoesNotMatch"), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
client = oauthConfig.Client(ctx, token)
|
||||
resp, err := client.Get(userEndpoint)
|
||||
resp, err := client.Get(provider.UserInfoEndpoint())
|
||||
if err != nil {
|
||||
global.Logger.Warn("failed getting user info: ", err)
|
||||
Logger.Warn("failed getting user info: ", err)
|
||||
return errors.New("GetOauthUserInfoError"), nil
|
||||
}
|
||||
defer func() {
|
||||
if closeErr := resp.Body.Close(); closeErr != nil {
|
||||
global.Logger.Warn("failed closing response body: ", closeErr)
|
||||
Logger.Warn("failed closing response body: ", closeErr)
|
||||
}
|
||||
}()
|
||||
|
||||
// 解析用户信息
|
||||
if err = json.NewDecoder(resp.Body).Decode(userData); err != nil {
|
||||
global.Logger.Warn("failed decoding user info: ", err)
|
||||
Logger.Warn("failed decoding user info: ", err)
|
||||
return errors.New("DecodeOauthUserInfoError"), nil
|
||||
}
|
||||
|
||||
@@ -244,9 +286,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, provider *oidc.Provider, code, verifier, nonce string) (error, *model.OauthUser) {
|
||||
var user = &model.GithubUser{}
|
||||
err, client := os.callbackBase(oauthConfig, code, model.UserEndpointGithub, user)
|
||||
err, client := os.callbackBase(oauthConfig, provider, code, verifier, nonce, user)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
@@ -258,19 +300,17 @@ 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, provider *oidc.Provider, code, verifier, nonce string) (error, *model.OauthUser) {
|
||||
var user = &model.OidcUser{}
|
||||
if err, _ := os.callbackBase(oauthConfig, code, userInfoEndpoint, user); err != nil {
|
||||
if err, _ := os.callbackBase(oauthConfig, provider, code, verifier, nonce, 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) {
|
||||
var oauthInfo *model.Oauth
|
||||
var oauthConfig *oauth2.Config
|
||||
err, oauthInfo, oauthConfig = os.GetOauthConfig(op)
|
||||
func (os *OauthService) Callback(code, verifier, op, nonce string) (err error, oauthUser *model.OauthUser) {
|
||||
err, oauthInfo, oauthConfig, provider := os.GetOauthConfig(op)
|
||||
// oauthType is already validated in GetOauthConfig
|
||||
if err != nil {
|
||||
return err, nil
|
||||
@@ -278,13 +318,9 @@ 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, provider, code, verifier, nonce)
|
||||
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, provider, code, verifier, nonce)
|
||||
default:
|
||||
return errors.New("unsupported OAuth type"), nil
|
||||
}
|
||||
@@ -293,7 +329,7 @@ func (os *OauthService) Callback(code string, op string) (err error, oauthUser *
|
||||
|
||||
func (os *OauthService) UserThirdInfo(op string, openId string) *model.UserThird {
|
||||
ut := &model.UserThird{}
|
||||
global.DB.Where("open_id = ? and op = ?", openId, op).First(ut)
|
||||
DB.Where("open_id = ? and op = ?", openId, op).First(ut)
|
||||
return ut
|
||||
}
|
||||
|
||||
@@ -305,7 +341,7 @@ func (os *OauthService) BindOauthUser(userId uint, oauthUser *model.OauthUser, o
|
||||
return err
|
||||
}
|
||||
utr.FromOauthUser(userId, oauthUser, oauthType, op)
|
||||
return global.DB.Create(utr).Error
|
||||
return DB.Create(utr).Error
|
||||
}
|
||||
|
||||
// UnBindOauthUser: Unbind third party account
|
||||
@@ -315,25 +351,25 @@ func (os *OauthService) UnBindOauthUser(userId uint, op string) error {
|
||||
|
||||
// UnBindThird: Unbind third party account
|
||||
func (os *OauthService) UnBindThird(op string, userId uint) error {
|
||||
return global.DB.Where("user_id = ? and op = ?", userId, op).Delete(&model.UserThird{}).Error
|
||||
return DB.Where("user_id = ? and op = ?", userId, op).Delete(&model.UserThird{}).Error
|
||||
}
|
||||
|
||||
// DeleteUserByUserId: When user is deleted, delete all third party bindings
|
||||
func (os *OauthService) DeleteUserByUserId(userId uint) error {
|
||||
return global.DB.Where("user_id = ?", userId).Delete(&model.UserThird{}).Error
|
||||
return DB.Where("user_id = ?", userId).Delete(&model.UserThird{}).Error
|
||||
}
|
||||
|
||||
// InfoById 根据id获取Oauth信息
|
||||
func (os *OauthService) InfoById(id uint) *model.Oauth {
|
||||
oauthInfo := &model.Oauth{}
|
||||
global.DB.Where("id = ?", id).First(oauthInfo)
|
||||
DB.Where("id = ?", id).First(oauthInfo)
|
||||
return oauthInfo
|
||||
}
|
||||
|
||||
// InfoByOp 根据op获取Oauth信息
|
||||
func (os *OauthService) InfoByOp(op string) *model.Oauth {
|
||||
oauthInfo := &model.Oauth{}
|
||||
global.DB.Where("op = ?", op).First(oauthInfo)
|
||||
DB.Where("op = ?", op).First(oauthInfo)
|
||||
return oauthInfo
|
||||
}
|
||||
|
||||
@@ -356,7 +392,7 @@ func (os *OauthService) List(page, pageSize uint, where func(tx *gorm.DB)) (res
|
||||
res = &model.OauthList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.Oauth{})
|
||||
tx := DB.Model(&model.Oauth{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -369,7 +405,7 @@ func (os *OauthService) List(page, pageSize uint, where func(tx *gorm.DB)) (res
|
||||
// GetTypeByOp 根据op获取OauthType
|
||||
func (os *OauthService) GetTypeByOp(op string) (error, string) {
|
||||
oauthInfo := &model.Oauth{}
|
||||
if global.DB.Where("op = ?", op).First(oauthInfo).Error != nil {
|
||||
if DB.Where("op = ?", op).First(oauthInfo).Error != nil {
|
||||
return fmt.Errorf("OAuth provider with op '%s' not found", op), ""
|
||||
}
|
||||
return nil, oauthInfo.OauthType
|
||||
@@ -387,7 +423,7 @@ func (os *OauthService) ValidateOauthProvider(op string) error {
|
||||
func (os *OauthService) IsOauthProviderExist(op string) bool {
|
||||
oauthInfo := &model.Oauth{}
|
||||
// 使用 Gorm 的 Take 方法查找符合条件的记录
|
||||
if err := global.DB.Where("op = ?", op).Take(oauthInfo).Error; err != nil {
|
||||
if err := DB.Where("op = ?", op).Take(oauthInfo).Error; err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -399,11 +435,11 @@ func (os *OauthService) Create(oauthInfo *model.Oauth) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res := global.DB.Create(oauthInfo).Error
|
||||
res := DB.Create(oauthInfo).Error
|
||||
return res
|
||||
}
|
||||
func (os *OauthService) Delete(oauthInfo *model.Oauth) error {
|
||||
return global.DB.Delete(oauthInfo).Error
|
||||
return DB.Delete(oauthInfo).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
@@ -412,13 +448,13 @@ func (os *OauthService) Update(oauthInfo *model.Oauth) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return global.DB.Model(oauthInfo).Updates(oauthInfo).Error
|
||||
return DB.Model(oauthInfo).Updates(oauthInfo).Error
|
||||
}
|
||||
|
||||
// GetOauthProviders 获取所有的provider
|
||||
func (os *OauthService) GetOauthProviders() []string {
|
||||
var res []string
|
||||
global.DB.Model(&model.Oauth{}).Pluck("op", &res)
|
||||
DB.Model(&model.Oauth{}).Pluck("op", &res)
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -12,24 +11,24 @@ type PeerService struct {
|
||||
// FindById 根据id查找
|
||||
func (ps *PeerService) FindById(id string) *model.Peer {
|
||||
p := &model.Peer{}
|
||||
global.DB.Where("id = ?", id).First(p)
|
||||
DB.Where("id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
func (ps *PeerService) FindByUuid(uuid string) *model.Peer {
|
||||
p := &model.Peer{}
|
||||
global.DB.Where("uuid = ?", uuid).First(p)
|
||||
DB.Where("uuid = ?", uuid).First(p)
|
||||
return p
|
||||
}
|
||||
func (ps *PeerService) InfoByRowId(id uint) *model.Peer {
|
||||
p := &model.Peer{}
|
||||
global.DB.Where("row_id = ?", id).First(p)
|
||||
DB.Where("row_id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
|
||||
// FindByUserIdAndUuid 根据用户id和uuid查找peer
|
||||
func (ps *PeerService) FindByUserIdAndUuid(uuid string, userId uint) *model.Peer {
|
||||
p := &model.Peer{}
|
||||
global.DB.Where("uuid = ? and user_id = ?", uuid, userId).First(p)
|
||||
DB.Where("uuid = ? and user_id = ?", uuid, userId).First(p)
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -43,7 +42,7 @@ func (ps *PeerService) UuidBindUserId(deviceId string, uuid string, userId uint)
|
||||
} else {
|
||||
// 不存在则创建
|
||||
/*if deviceId != "" {
|
||||
global.DB.Create(&model.Peer{
|
||||
DB.Create(&model.Peer{
|
||||
Id: deviceId,
|
||||
Uuid: uuid,
|
||||
UserId: userId,
|
||||
@@ -56,13 +55,13 @@ func (ps *PeerService) UuidBindUserId(deviceId string, uuid string, userId uint)
|
||||
func (ps *PeerService) UuidUnbindUserId(uuid string, userId uint) {
|
||||
peer := ps.FindByUserIdAndUuid(uuid, userId)
|
||||
if peer.RowId > 0 {
|
||||
global.DB.Model(peer).Update("user_id", 0)
|
||||
DB.Model(peer).Update("user_id", 0)
|
||||
}
|
||||
}
|
||||
|
||||
// EraseUserId 清除用户id, 用于用户删除
|
||||
func (ps *PeerService) EraseUserId(userId uint) error {
|
||||
return global.DB.Model(&model.Peer{}).Where("user_id = ?", userId).Update("user_id", 0).Error
|
||||
return DB.Model(&model.Peer{}).Where("user_id = ?", userId).Update("user_id", 0).Error
|
||||
}
|
||||
|
||||
// ListByUserIds 根据用户id取列表
|
||||
@@ -70,7 +69,7 @@ func (ps *PeerService) ListByUserIds(userIds []uint, page, pageSize uint) (res *
|
||||
res = &model.PeerList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.Peer{})
|
||||
tx := DB.Model(&model.Peer{})
|
||||
tx.Where("user_id in (?)", userIds)
|
||||
tx.Count(&res.Total)
|
||||
tx.Scopes(Paginate(page, pageSize))
|
||||
@@ -82,7 +81,7 @@ func (ps *PeerService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *
|
||||
res = &model.PeerList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.Peer{})
|
||||
tx := DB.Model(&model.Peer{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -106,14 +105,14 @@ func (ps *PeerService) ListFilterByUserId(page, pageSize uint, where func(tx *go
|
||||
|
||||
// Create 创建
|
||||
func (ps *PeerService) Create(u *model.Peer) error {
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
|
||||
// Delete 删除, 同时也应该删除token
|
||||
func (ps *PeerService) Delete(u *model.Peer) error {
|
||||
uuid := u.Uuid
|
||||
err := global.DB.Delete(u).Error
|
||||
err := DB.Delete(u).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -124,7 +123,7 @@ func (ps *PeerService) Delete(u *model.Peer) error {
|
||||
// GetUuidListByIDs 根据ids获取uuid列表
|
||||
func (ps *PeerService) GetUuidListByIDs(ids []uint) ([]string, error) {
|
||||
var uuids []string
|
||||
err := global.DB.Model(&model.Peer{}).
|
||||
err := DB.Model(&model.Peer{}).
|
||||
Where("row_id in (?)", ids).
|
||||
Pluck("uuid", &uuids).Error
|
||||
return uuids, err
|
||||
@@ -133,7 +132,7 @@ func (ps *PeerService) GetUuidListByIDs(ids []uint) ([]string, error) {
|
||||
// BatchDelete 批量删除, 同时也应该删除token
|
||||
func (ps *PeerService) BatchDelete(ids []uint) error {
|
||||
uuids, err := ps.GetUuidListByIDs(ids)
|
||||
err = global.DB.Where("row_id in (?)", ids).Delete(&model.Peer{}).Error
|
||||
err = DB.Where("row_id in (?)", ids).Delete(&model.Peer{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -143,5 +142,5 @@ func (ps *PeerService) BatchDelete(ids []uint) error {
|
||||
|
||||
// Update 更新
|
||||
func (ps *PeerService) Update(u *model.Peer) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
return DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"net"
|
||||
"time"
|
||||
@@ -15,7 +14,7 @@ func (is *ServerCmdService) List(page, pageSize uint) (res *model.ServerCmdList)
|
||||
res = &model.ServerCmdList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.ServerCmd{})
|
||||
tx := DB.Model(&model.ServerCmd{})
|
||||
tx.Count(&res.Total)
|
||||
tx.Scopes(Paginate(page, pageSize))
|
||||
tx.Find(&res.ServerCmds)
|
||||
@@ -25,18 +24,18 @@ func (is *ServerCmdService) List(page, pageSize uint) (res *model.ServerCmdList)
|
||||
// Info
|
||||
func (is *ServerCmdService) Info(id uint) *model.ServerCmd {
|
||||
u := &model.ServerCmd{}
|
||||
global.DB.Where("id = ?", id).First(u)
|
||||
DB.Where("id = ?", id).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
// Delete
|
||||
func (is *ServerCmdService) Delete(u *model.ServerCmd) error {
|
||||
return global.DB.Delete(u).Error
|
||||
return DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// Create
|
||||
func (is *ServerCmdService) Create(u *model.ServerCmd) error {
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -45,9 +44,9 @@ func (is *ServerCmdService) SendCmd(target string, cmd string, arg string) (stri
|
||||
port := 0
|
||||
switch target {
|
||||
case model.ServerCmdTargetIdServer:
|
||||
port = global.Config.Rustdesk.IdServerPort - 1
|
||||
port = Config.Rustdesk.IdServerPort - 1
|
||||
case model.ServerCmdTargetRelayServer:
|
||||
port = global.Config.Rustdesk.RelayServerPort
|
||||
port = Config.Rustdesk.RelayServerPort
|
||||
}
|
||||
//组装命令
|
||||
cmd = cmd + " " + arg
|
||||
@@ -73,14 +72,14 @@ func (is *ServerCmdService) SendSocketCmd(ty string, port int, cmd string) (stri
|
||||
}
|
||||
conn, err := net.Dial(tcp, fmt.Sprintf("%s:%v", addr, port))
|
||||
if err != nil {
|
||||
global.Logger.Debugf("%s connect to id server failed: %v", ty, err)
|
||||
Logger.Debugf("%s connect to id server failed: %v", ty, err)
|
||||
return "", err
|
||||
}
|
||||
defer conn.Close()
|
||||
//发送命令
|
||||
_, err = conn.Write([]byte(cmd))
|
||||
if err != nil {
|
||||
global.Logger.Debugf("%s send cmd failed: %v", ty, err)
|
||||
Logger.Debugf("%s send cmd failed: %v", ty, err)
|
||||
return "", err
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
@@ -88,12 +87,12 @@ func (is *ServerCmdService) SendSocketCmd(ty string, port int, cmd string) (stri
|
||||
buf := make([]byte, 1024)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil && err.Error() != "EOF" {
|
||||
global.Logger.Debugf("%s read response failed: %v", ty, err)
|
||||
Logger.Debugf("%s read response failed: %v", ty, err)
|
||||
return "", err
|
||||
}
|
||||
return string(buf[:n]), nil
|
||||
}
|
||||
|
||||
func (is *ServerCmdService) Update(f *model.ServerCmd) error {
|
||||
return global.DB.Model(f).Updates(f).Error
|
||||
return DB.Model(f).Updates(f).Error
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/lejianwen/rustdesk-api/v2/config"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/jwt"
|
||||
"github.com/lejianwen/rustdesk-api/v2/lib/lock"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -21,12 +25,31 @@ type Service struct {
|
||||
*LdapService
|
||||
}
|
||||
|
||||
func New() *Service {
|
||||
all := new(Service)
|
||||
return all
|
||||
type Dependencies struct {
|
||||
Config *config.Config
|
||||
DB *gorm.DB
|
||||
Logger *log.Logger
|
||||
Jwt *jwt.Jwt
|
||||
Lock *lock.Locker
|
||||
}
|
||||
|
||||
var AllService = New()
|
||||
var Config *config.Config
|
||||
var DB *gorm.DB
|
||||
var Logger *log.Logger
|
||||
var Jwt *jwt.Jwt
|
||||
var Lock lock.Locker
|
||||
|
||||
var AllService *Service
|
||||
|
||||
func New(c *config.Config, g *gorm.DB, l *log.Logger, j *jwt.Jwt, lo lock.Locker) *Service {
|
||||
Config = c
|
||||
DB = g
|
||||
Logger = l
|
||||
Jwt = j
|
||||
Lock = lo
|
||||
AllService = new(Service)
|
||||
return AllService
|
||||
}
|
||||
|
||||
func Paginate(page, pageSize uint) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -12,7 +11,7 @@ type ShareRecordService struct {
|
||||
// InfoById 根据用户id取用户信息
|
||||
func (srs *ShareRecordService) InfoById(id uint) *model.ShareRecord {
|
||||
u := &model.ShareRecord{}
|
||||
global.DB.Where("id = ?", id).First(u)
|
||||
DB.Where("id = ?", id).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
@@ -20,7 +19,7 @@ func (srs *ShareRecordService) List(page, pageSize uint, where func(tx *gorm.DB)
|
||||
res = &model.ShareRecordList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.ShareRecord{})
|
||||
tx := DB.Model(&model.ShareRecord{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -32,18 +31,18 @@ func (srs *ShareRecordService) List(page, pageSize uint, where func(tx *gorm.DB)
|
||||
|
||||
// Create 创建
|
||||
func (srs *ShareRecordService) Create(u *model.ShareRecord) error {
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
func (srs *ShareRecordService) Delete(u *model.ShareRecord) error {
|
||||
return global.DB.Delete(u).Error
|
||||
return DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (srs *ShareRecordService) Update(u *model.ShareRecord) error {
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
return DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
func (srs *ShareRecordService) BatchDelete(ids []uint) error {
|
||||
return global.DB.Where("id in (?)", ids).Delete(&model.ShareRecord{}).Error
|
||||
return DB.Where("id in (?)", ids).Delete(&model.ShareRecord{}).Error
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -11,12 +10,12 @@ type TagService struct {
|
||||
|
||||
func (s *TagService) Info(id uint) *model.Tag {
|
||||
p := &model.Tag{}
|
||||
global.DB.Where("id = ?", id).First(p)
|
||||
DB.Where("id = ?", id).First(p)
|
||||
return p
|
||||
}
|
||||
func (s *TagService) InfoByUserIdAndNameAndCollectionId(userid uint, name string, cid uint) *model.Tag {
|
||||
p := &model.Tag{}
|
||||
global.DB.Where("user_id = ? and name = ? and collection_id = ?", userid, name, cid).First(p)
|
||||
DB.Where("user_id = ? and name = ? and collection_id = ?", userid, name, cid).First(p)
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -34,7 +33,7 @@ func (s *TagService) ListByUserIdAndCollectionId(userId, cid uint) (res *model.T
|
||||
return
|
||||
}
|
||||
func (s *TagService) UpdateTags(userId uint, tags map[string]uint) {
|
||||
tx := global.DB.Begin()
|
||||
tx := DB.Begin()
|
||||
//先查询所有tag
|
||||
var allTags []*model.Tag
|
||||
tx.Where("user_id = ?", userId).Find(&allTags)
|
||||
@@ -66,7 +65,7 @@ func (s *TagService) UpdateTags(userId uint, tags map[string]uint) {
|
||||
// InfoById 根据用户id取用户信息
|
||||
func (s *TagService) InfoById(id uint) *model.Tag {
|
||||
u := &model.Tag{}
|
||||
global.DB.Where("id = ?", id).First(u)
|
||||
DB.Where("id = ?", id).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
@@ -74,7 +73,7 @@ func (s *TagService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *mo
|
||||
res = &model.TagList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.Tag{})
|
||||
tx := DB.Model(&model.Tag{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -86,14 +85,14 @@ func (s *TagService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *mo
|
||||
|
||||
// Create 创建
|
||||
func (s *TagService) Create(u *model.Tag) error {
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
func (s *TagService) Delete(u *model.Tag) error {
|
||||
return global.DB.Delete(u).Error
|
||||
return DB.Delete(u).Error
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (s *TagService) Update(u *model.Tag) error {
|
||||
return global.DB.Model(u).Select("*").Omit("created_at").Updates(u).Error
|
||||
return DB.Model(u).Select("*").Omit("created_at").Updates(u).Error
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||
"math/rand"
|
||||
@@ -20,43 +19,43 @@ type UserService struct {
|
||||
// InfoById 根据用户id取用户信息
|
||||
func (us *UserService) InfoById(id uint) *model.User {
|
||||
u := &model.User{}
|
||||
global.DB.Where("id = ?", id).First(u)
|
||||
DB.Where("id = ?", id).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
// InfoByUsername 根据用户名取用户信息
|
||||
func (us *UserService) InfoByUsername(un string) *model.User {
|
||||
u := &model.User{}
|
||||
global.DB.Where("username = ?", un).First(u)
|
||||
DB.Where("username = ?", un).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
// InfoByEmail 根据邮箱取用户信息
|
||||
func (us *UserService) InfoByEmail(email string) *model.User {
|
||||
u := &model.User{}
|
||||
global.DB.Where("email = ?", email).First(u)
|
||||
DB.Where("email = ?", email).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
// InfoByOpenid 根据openid取用户信息
|
||||
func (us *UserService) InfoByOpenid(openid string) *model.User {
|
||||
u := &model.User{}
|
||||
global.DB.Where("openid = ?", openid).First(u)
|
||||
DB.Where("openid = ?", openid).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
// InfoByUsernamePassword 根据用户名密码取用户信息
|
||||
func (us *UserService) InfoByUsernamePassword(username, password string) *model.User {
|
||||
if global.Config.Ldap.Enable {
|
||||
if Config.Ldap.Enable {
|
||||
u, err := AllService.LdapService.Authenticate(username, password)
|
||||
if err == nil {
|
||||
return u
|
||||
}
|
||||
global.Logger.Errorf("LDAP authentication failed, %v", err)
|
||||
global.Logger.Warn("Fallback to local database")
|
||||
Logger.Errorf("LDAP authentication failed, %v", err)
|
||||
Logger.Warn("Fallback to local database")
|
||||
}
|
||||
u := &model.User{}
|
||||
global.DB.Where("username = ? and password = ?", username, us.EncryptPassword(password)).First(u)
|
||||
DB.Where("username = ? and password = ?", username, us.EncryptPassword(password)).First(u)
|
||||
return u
|
||||
}
|
||||
|
||||
@@ -64,21 +63,21 @@ func (us *UserService) InfoByUsernamePassword(username, password string) *model.
|
||||
func (us *UserService) InfoByAccessToken(token string) (*model.User, *model.UserToken) {
|
||||
u := &model.User{}
|
||||
ut := &model.UserToken{}
|
||||
global.DB.Where("token = ?", token).First(ut)
|
||||
DB.Where("token = ?", token).First(ut)
|
||||
if ut.Id == 0 {
|
||||
return u, ut
|
||||
}
|
||||
if ut.ExpiredAt < time.Now().Unix() {
|
||||
return u, ut
|
||||
}
|
||||
global.DB.Where("id = ?", ut.UserId).First(u)
|
||||
DB.Where("id = ?", ut.UserId).First(u)
|
||||
return u, ut
|
||||
}
|
||||
|
||||
// GenerateToken 生成token
|
||||
func (us *UserService) GenerateToken(u *model.User) string {
|
||||
if len(global.Jwt.Key) > 0 {
|
||||
return global.Jwt.GenerateToken(u.Id)
|
||||
if len(Jwt.Key) > 0 {
|
||||
return Jwt.GenerateToken(u.Id)
|
||||
}
|
||||
return utils.Md5(u.Username + time.Now().String())
|
||||
}
|
||||
@@ -93,9 +92,9 @@ func (us *UserService) Login(u *model.User, llog *model.LoginLog) *model.UserTok
|
||||
DeviceId: llog.DeviceId,
|
||||
ExpiredAt: us.UserTokenExpireTimestamp(),
|
||||
}
|
||||
global.DB.Create(ut)
|
||||
DB.Create(ut)
|
||||
llog.UserTokenId = ut.UserId
|
||||
global.DB.Create(llog)
|
||||
DB.Create(llog)
|
||||
if llog.Uuid != "" {
|
||||
AllService.PeerService.UuidBindUserId(llog.DeviceId, llog.Uuid, u.Id)
|
||||
}
|
||||
@@ -116,7 +115,7 @@ func (us *UserService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *
|
||||
res = &model.UserList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(pageSize)
|
||||
tx := global.DB.Model(&model.User{})
|
||||
tx := DB.Model(&model.User{})
|
||||
if where != nil {
|
||||
where(tx)
|
||||
}
|
||||
@@ -127,7 +126,7 @@ func (us *UserService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *
|
||||
}
|
||||
|
||||
func (us *UserService) ListByIds(ids []uint) (res []*model.User) {
|
||||
global.DB.Where("id in ?", ids).Find(&res)
|
||||
DB.Where("id in ?", ids).Find(&res)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -141,14 +140,14 @@ func (us *UserService) ListByGroupId(groupId, page, pageSize uint) (res *model.U
|
||||
|
||||
// ListIdsByGroupId 根据组id取用户id列表
|
||||
func (us *UserService) ListIdsByGroupId(groupId uint) (ids []uint) {
|
||||
global.DB.Model(&model.User{}).Where("group_id = ?", groupId).Pluck("id", &ids)
|
||||
DB.Model(&model.User{}).Where("group_id = ?", groupId).Pluck("id", &ids)
|
||||
return ids
|
||||
|
||||
}
|
||||
|
||||
// ListIdAndNameByGroupId 根据组id取用户id和用户名列表
|
||||
func (us *UserService) ListIdAndNameByGroupId(groupId uint) (res []*model.User) {
|
||||
global.DB.Model(&model.User{}).Where("group_id = ?", groupId).Select("id, username").Find(&res)
|
||||
DB.Model(&model.User{}).Where("group_id = ?", groupId).Select("id, username").Find(&res)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -170,14 +169,14 @@ func (us *UserService) Create(u *model.User) error {
|
||||
}
|
||||
u.Username = us.formatUsername(u.Username)
|
||||
u.Password = us.EncryptPassword(u.Password)
|
||||
res := global.DB.Create(u).Error
|
||||
res := DB.Create(u).Error
|
||||
return res
|
||||
}
|
||||
|
||||
// GetUuidByToken 根据token和user取uuid
|
||||
func (us *UserService) GetUuidByToken(u *model.User, token string) string {
|
||||
ut := &model.UserToken{}
|
||||
err := global.DB.Where("user_id = ? and token = ?", u.Id, token).First(ut).Error
|
||||
err := DB.Where("user_id = ? and token = ?", u.Id, token).First(ut).Error
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
@@ -187,7 +186,7 @@ func (us *UserService) GetUuidByToken(u *model.User, token string) string {
|
||||
// Logout 退出登录 -> 删除token, 解绑uuid
|
||||
func (us *UserService) Logout(u *model.User, token string) error {
|
||||
uuid := us.GetUuidByToken(u, token)
|
||||
err := global.DB.Where("user_id = ? and token = ?", u.Id, token).Delete(&model.UserToken{}).Error
|
||||
err := DB.Where("user_id = ? and token = ?", u.Id, token).Delete(&model.UserToken{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -203,7 +202,7 @@ func (us *UserService) Delete(u *model.User) error {
|
||||
if userCount <= 1 && us.IsAdmin(u) {
|
||||
return errors.New("The last admin user cannot be deleted")
|
||||
}
|
||||
tx := global.DB.Begin()
|
||||
tx := DB.Begin()
|
||||
// 删除用户
|
||||
if err := tx.Delete(u).Error; err != nil {
|
||||
tx.Rollback()
|
||||
@@ -232,7 +231,7 @@ func (us *UserService) Delete(u *model.User) error {
|
||||
tx.Commit()
|
||||
// 删除关联的peer
|
||||
if err := AllService.PeerService.EraseUserId(u.Id); err != nil {
|
||||
global.Logger.Warn("User deleted successfully, but failed to unlink peer.")
|
||||
Logger.Warn("User deleted successfully, but failed to unlink peer.")
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
@@ -249,28 +248,28 @@ func (us *UserService) Update(u *model.User) error {
|
||||
return errors.New("The last admin user cannot be disabled or demoted")
|
||||
}
|
||||
}
|
||||
return global.DB.Model(u).Updates(u).Error
|
||||
return DB.Model(u).Updates(u).Error
|
||||
}
|
||||
|
||||
// FlushToken 清空token
|
||||
func (us *UserService) FlushToken(u *model.User) error {
|
||||
return global.DB.Where("user_id = ?", u.Id).Delete(&model.UserToken{}).Error
|
||||
return DB.Where("user_id = ?", u.Id).Delete(&model.UserToken{}).Error
|
||||
}
|
||||
|
||||
// FlushTokenByUuid 清空token
|
||||
func (us *UserService) FlushTokenByUuid(uuid string) error {
|
||||
return global.DB.Where("device_uuid = ?", uuid).Delete(&model.UserToken{}).Error
|
||||
return DB.Where("device_uuid = ?", uuid).Delete(&model.UserToken{}).Error
|
||||
}
|
||||
|
||||
// FlushTokenByUuids 清空token
|
||||
func (us *UserService) FlushTokenByUuids(uuids []string) error {
|
||||
return global.DB.Where("device_uuid in (?)", uuids).Delete(&model.UserToken{}).Error
|
||||
return DB.Where("device_uuid in (?)", uuids).Delete(&model.UserToken{}).Error
|
||||
}
|
||||
|
||||
// UpdatePassword 更新密码
|
||||
func (us *UserService) UpdatePassword(u *model.User, password string) error {
|
||||
u.Password = us.EncryptPassword(password)
|
||||
err := global.DB.Model(u).Update("password", u.Password).Error
|
||||
err := DB.Model(u).Update("password", u.Password).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -306,8 +305,8 @@ func (us *UserService) InfoByOauthId(op string, openId string) *model.User {
|
||||
|
||||
// RegisterByOauth 注册
|
||||
func (us *UserService) RegisterByOauth(oauthUser *model.OauthUser, op string) (error, *model.User) {
|
||||
global.Lock.Lock("registerByOauth")
|
||||
defer global.Lock.UnLock("registerByOauth")
|
||||
Lock.Lock("registerByOauth")
|
||||
defer Lock.UnLock("registerByOauth")
|
||||
ut := AllService.OauthService.UserThirdInfo(op, oauthUser.OpenId)
|
||||
if ut.Id != 0 {
|
||||
return nil, us.InfoById(ut.UserId)
|
||||
@@ -335,12 +334,12 @@ func (us *UserService) RegisterByOauth(oauthUser *model.OauthUser, op string) (e
|
||||
}
|
||||
if user.Id != 0 {
|
||||
ut.FromOauthUser(user.Id, oauthUser, oauthType, op)
|
||||
global.DB.Create(ut)
|
||||
DB.Create(ut)
|
||||
return nil, user
|
||||
}
|
||||
}
|
||||
|
||||
tx := global.DB.Begin()
|
||||
tx := DB.Begin()
|
||||
ut = &model.UserThird{}
|
||||
ut.FromOauthUser(0, oauthUser, oauthType, op)
|
||||
// The initial username should be formatted
|
||||
@@ -372,27 +371,27 @@ func (us *UserService) GenerateUsernameByOauth(name string) string {
|
||||
|
||||
// UserThirdsByUserId
|
||||
func (us *UserService) UserThirdsByUserId(userId uint) (res []*model.UserThird) {
|
||||
global.DB.Where("user_id = ?", userId).Find(&res)
|
||||
DB.Where("user_id = ?", userId).Find(&res)
|
||||
return res
|
||||
}
|
||||
|
||||
func (us *UserService) UserThirdInfo(userId uint, op string) *model.UserThird {
|
||||
ut := &model.UserThird{}
|
||||
global.DB.Where("user_id = ? and op = ?", userId, op).First(ut)
|
||||
DB.Where("user_id = ? and op = ?", userId, op).First(ut)
|
||||
return ut
|
||||
}
|
||||
|
||||
// FindLatestUserIdFromLoginLogByUuid 根据uuid查找最后登录的用户id
|
||||
func (us *UserService) FindLatestUserIdFromLoginLogByUuid(uuid string) uint {
|
||||
llog := &model.LoginLog{}
|
||||
global.DB.Where("uuid = ?", uuid).Order("id desc").First(llog)
|
||||
DB.Where("uuid = ?", uuid).Order("id desc").First(llog)
|
||||
return llog.UserId
|
||||
}
|
||||
|
||||
// IsPasswordEmptyById 根据用户id判断密码是否为空,主要用于第三方登录的自动注册
|
||||
func (us *UserService) IsPasswordEmptyById(id uint) bool {
|
||||
u := &model.User{}
|
||||
if global.DB.Where("id = ?", id).First(u).Error != nil {
|
||||
if DB.Where("id = ?", id).First(u).Error != nil {
|
||||
return false
|
||||
}
|
||||
return u.Password == ""
|
||||
@@ -401,7 +400,7 @@ func (us *UserService) IsPasswordEmptyById(id uint) bool {
|
||||
// IsPasswordEmptyByUsername 根据用户id判断密码是否为空,主要用于第三方登录的自动注册
|
||||
func (us *UserService) IsPasswordEmptyByUsername(username string) bool {
|
||||
u := &model.User{}
|
||||
if global.DB.Where("username = ?", username).First(u).Error != nil {
|
||||
if DB.Where("username = ?", username).First(u).Error != nil {
|
||||
return false
|
||||
}
|
||||
return u.Password == ""
|
||||
@@ -431,7 +430,7 @@ func (us *UserService) TokenList(page uint, size uint, f func(tx *gorm.DB)) *mod
|
||||
res := &model.UserTokenList{}
|
||||
res.Page = int64(page)
|
||||
res.PageSize = int64(size)
|
||||
tx := global.DB.Model(&model.UserToken{})
|
||||
tx := DB.Model(&model.UserToken{})
|
||||
if f != nil {
|
||||
f(tx)
|
||||
}
|
||||
@@ -443,12 +442,12 @@ func (us *UserService) TokenList(page uint, size uint, f func(tx *gorm.DB)) *mod
|
||||
|
||||
func (us *UserService) TokenInfoById(id uint) *model.UserToken {
|
||||
ut := &model.UserToken{}
|
||||
global.DB.Where("id = ?", id).First(ut)
|
||||
DB.Where("id = ?", id).First(ut)
|
||||
return ut
|
||||
}
|
||||
|
||||
func (us *UserService) DeleteToken(l *model.UserToken) error {
|
||||
return global.DB.Delete(l).Error
|
||||
return DB.Delete(l).Error
|
||||
}
|
||||
|
||||
// Helper functions, used for formatting username
|
||||
@@ -461,20 +460,20 @@ func (us *UserService) formatUsername(username string) string {
|
||||
// Helper functions, getUserCount
|
||||
func (us *UserService) getUserCount() int64 {
|
||||
var count int64
|
||||
global.DB.Model(&model.User{}).Count(&count)
|
||||
DB.Model(&model.User{}).Count(&count)
|
||||
return count
|
||||
}
|
||||
|
||||
// helper functions, getAdminUserCount
|
||||
func (us *UserService) getAdminUserCount() int64 {
|
||||
var count int64
|
||||
global.DB.Model(&model.User{}).Where("is_admin = ?", true).Count(&count)
|
||||
DB.Model(&model.User{}).Where("is_admin = ?", true).Count(&count)
|
||||
return count
|
||||
}
|
||||
|
||||
// UserTokenExpireTimestamp 生成用户token过期时间
|
||||
func (us *UserService) UserTokenExpireTimestamp() int64 {
|
||||
exp := global.Config.App.TokenExpire
|
||||
exp := Config.App.TokenExpire
|
||||
if exp == 0 {
|
||||
//默认七天
|
||||
exp = 604800
|
||||
@@ -484,7 +483,7 @@ func (us *UserService) UserTokenExpireTimestamp() int64 {
|
||||
|
||||
func (us *UserService) RefreshAccessToken(ut *model.UserToken) {
|
||||
ut.ExpiredAt = us.UserTokenExpireTimestamp()
|
||||
global.DB.Model(ut).Update("expired_at", ut.ExpiredAt)
|
||||
DB.Model(ut).Update("expired_at", ut.ExpiredAt)
|
||||
}
|
||||
func (us *UserService) AutoRefreshAccessToken(ut *model.UserToken) {
|
||||
if ut.ExpiredAt-time.Now().Unix() < 86400 {
|
||||
@@ -493,11 +492,11 @@ func (us *UserService) AutoRefreshAccessToken(ut *model.UserToken) {
|
||||
}
|
||||
|
||||
func (us *UserService) BatchDeleteUserToken(ids []uint) error {
|
||||
return global.DB.Where("id in ?", ids).Delete(&model.UserToken{}).Error
|
||||
return DB.Where("id in ?", ids).Delete(&model.UserToken{}).Error
|
||||
}
|
||||
|
||||
func (us *UserService) VerifyJWT(token string) (uint, error) {
|
||||
return global.Jwt.ParseToken(token)
|
||||
return Jwt.ParseToken(token)
|
||||
}
|
||||
|
||||
// IsUsernameExists 判断用户名是否存在, it will check the internal database and LDAP(if enabled)
|
||||
@@ -507,7 +506,7 @@ func (us *UserService) IsUsernameExists(username string) bool {
|
||||
|
||||
func (us *UserService) IsUsernameExistsLocal(username string) bool {
|
||||
u := &model.User{}
|
||||
global.DB.Where("username = ?", username).First(u)
|
||||
DB.Where("username = ?", username).First(u)
|
||||
return u.Id != 0
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user