Compare commits

...

6 Commits

Author SHA1 Message Date
lejianwen
8cac15f7dd style: Log time 2025-02-07 17:57:28 +08:00
lejianwen
5011e2b7c1 feat: Web sso env (#125) 2025-02-07 17:52:40 +08:00
lejianwen
b0008143b1 docs: Up readme 2025-02-07 17:52:40 +08:00
lejianwen
a3c3ab5a72 style: Up conf 2025-02-07 17:52:40 +08:00
lejianwen
3a16269215 docs: Up readme 2025-02-07 17:52:40 +08:00
lejianwen
151145b0c3 feat: Random Initial Password for Admin (#117) 2025-02-07 17:52:39 +08:00
8 changed files with 204 additions and 146 deletions

View File

@@ -9,6 +9,7 @@
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
<img src="https://img.shields.io/badge/i18n-7-green"/>
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
</div>
@@ -46,6 +47,7 @@
## 功能
### API 服务
基本实现了PC端基础的接口。支持Personal版本接口可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
@@ -70,23 +72,20 @@
* 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
* 后台访问地址是`http://<your server>[:port]/_admin/`初次安装管理员为用户名密码为`admin` `admin`,请即时更改密码
* 后台访问地址是`http://<your server>[:port]/_admin/`
* 初次安装管理员为用户名为`admin`,密码将在控制台打印,可以通过[命令行](#CLI)更改密码
![img.png](./docs/init_admin_pwd.png)
1. 管理员界面
![web_admin](docs/web_admin.png)
2. 普通用户界面
![web_user](docs/web_admin_user.png)
右上角可以更改密码,可以切换语言,可以切换`白天/黑夜`模式
![web_resetpwd](docs/web_resetpwd.png)
3. 每个用户可以多个地址簿,也可以将地址簿共享给其他用户
4. 分组可以自定义,方便管理,暂时支持两种类型: `共享组``普通组`
5. 可以直接打开webclient方便使用也可以分享给游客游客可以直接通过webclient远程到设备
![web_webclient](docs/admin_webclient.png)
6. Oauth,支持了`Github`, `Google` 以及 `OIDC`, 需要创建一个`OAuth App`,然后配置到后台
![web_admin_oauth](docs/web_admin_oauth.png)
- 对于`Google``Github`, `Issuer``Scopes`不需要填写.
- 对于`OIDC`, `Issuer`是必须的。`Scopes`是可选的,默认为 `openid,profile,email`. 确保可以获取 `sub`,`email``preferred_username`
- `github oauth app``Settings`->`Developer settings`->`OAuth Apps`->`New OAuth App`
@@ -127,6 +126,7 @@
![api_swag](docs/api_swag.png)
### CLI
```bash
# 查看帮助
./apimain -h
@@ -181,13 +181,35 @@ proxy:
jwt:
key: ""
expire-duration: 360000
ldap:
enable: false
url: "ldap://ldap.example.com:389"
tls: false
tls-verify: false
base-dn: "dc=example,dc=com"
bind-dn: "cn=admin,dc=example,dc=com"
bind-password: "password"
user:
base-dn: "ou=users,dc=example,dc=com"
enable-attr: "" #The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
enable-attr-value: "" # The value of the enable attribute when the user is enabled. If you are using AD, just set random value, it will be ignored.
filter: "(cn=*)"
username: "uid" # The attribute name of the user for usernamem if you are using AD, it should be "sAMAccountName"
email: "mail"
first-name: "givenName"
last-name: "sn"
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
```
### 环境变量
变量名前缀是`RUSTDESK_API`,环境变量如果存在将覆盖配置文件中的配置
环境变量和配置文件`conf/config.yaml`中的配置一一对应,变量名前缀是`RUSTDESK_API`
下面表格并未全部列出,可以参考`conf/config.yaml`中的配置。
| 变量名 | 说明 | 示例 |
|---------------------------------------------------|---------------------------------------------------------|------------------------------|
|---------------------------------------------------|--------------------------------------------------------------------------------|------------------------------|
| TZ | 时区 | Asia/Shanghai |
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
@@ -200,7 +222,7 @@ jwt:
| RUSTDESK_API_ADMIN_HELLO_FILE | 后台欢迎语文件,如果内容多,使用文件更方便。<br>会覆盖`RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
| -----GIN配置----- | ---------- | ---------- |
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
| -----------GORM配置---------------- | ------------------------------------ | --------------------------- |
| -----GORM配置----- | ---------- | --------------------------- |
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql默认sqlite | sqlite |
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
@@ -210,18 +232,18 @@ jwt:
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
| -----RUSTDESK配置----- | --------------- | ---------- |
| -----RUSTDESK配置----- | ---------- | ---------- |
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk存放key的文件 | `./conf/data/id_ed25519.pub` |
| RUSTDESK_API_RUSTDESK_WEBCLIENT_MAGIC_QUERYONLINE | Web client v2 中是否启用新的在线状态查询方法; `1`:启用,`0`:不启用,默认不启用 | `0` |
| ----PROXY配置----- | --------------- | ---------- |
| ----PROXY配置----- | ---------- | ---------- |
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
| ----JWT配置---- | -------- | -------- |
| RUSTDESK_API_JWT_KEY | 自定义JWT KEY,为空则不启用JWT | |
| RUSTDESK_API_JWT_KEY | 自定义JWT KEY,为空则不启用JWT<br/>如果没使用`lejianwen/rustdesk-server`中的`MUST_LOGIN`,建议设置为空 | |
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT有效时间 | 360000 |
@@ -288,10 +310,11 @@ jwt:
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
#### 使用我fork后的server-s6镜像运行
#### 使用`lejianwen/server-s6`镜像运行
- 已解决链接超时问题
- 可以强制登录后才能发起链接
- github https://github.com/lejianwen/rustdesk-server
- docker hub https://hub.docker.com/r/lejianwen/rustdesk-server-s6
```yaml
networks:
@@ -344,4 +367,4 @@ jwt:
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
</a>
## 如果觉得这个项目对你有帮助请给一个star谢谢

View File

@@ -8,6 +8,7 @@ desktop software that provides self-hosted solutions.
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
<img src="https://img.shields.io/badge/i18n-7-green"/>
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
</div>
@@ -69,23 +70,22 @@ Basic implementation of the PC client's primary interfaces.Supports the Personal
* The frontend and backend are separated to provide a user-friendly management interface, primarily for managing and
displaying data.Frontend code is available at [rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
* Admin panel URL: `http://<your server[:port]>/_admin/`. The default username and password for the initial
installation are `admin` `admin`, please change the password immediately.
* Admin panel URL: `http://<your server[:port]>/_admin/`
* For the initial installation, the admin username is `admin`, and the password will be printed in the console. You can change the password via the [command line](#CLI).
![img.png](./docs/init_admin_pwd.png)
1. Admin interface:
![web_admin](docs/en_img/web_admin.png)
2. Regular user interface:
![web_user](docs/en_img/web_admin_user.png)
In the top right corner, you can change the password, switch languages, and toggle between `day/night` mode.
![web_resetpwd](docs/en_img/web_resetpwd.png)
3. Each user can have multiple address books, which can also be shared with other users.
4. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
5. You can directly launch the client or open the web client for convenience; you can also share it with guests, who can remotely access the device via the web client.
![web_webclient](docs/en_img/admin_webclient.png)
6. OAuth support: Currently, `GitHub`, `Google` and `OIDC` are supported. You need to create an `OAuth App` and configure it in
the admin panel.
![web_admin_oauth](docs/en_img/web_admin_oauth.png)
- For `Google` and `Github`, you don't need to fill the `Issuer` and `Scpoes`
- For `OIDC`, you must set the `Issuer`. And `Scopes` is optional which default is `openid,email,profile`, please make sure this `Oauth App` can access `sub`, `email` and `preferred_username`
- Create a `GitHub OAuth App`
@@ -97,7 +97,6 @@ installation are `admin` `admin`, please change the password immediately.
8. Connection logs
9. File transfer logs
10. Server control
- `Simple mode`, some simple commands have been GUI-ized and can be executed directly in the backend
![rustdesk_command_simple](./docs/en_img/rustdesk_command_simple.png)
@@ -182,13 +181,35 @@ proxy:
jwt:
key: ""
expire-duration: 360000
ldap:
enable: false
url: "ldap://ldap.example.com:389"
tls: false
tls-verify: false
base-dn: "dc=example,dc=com"
bind-dn: "cn=admin,dc=example,dc=com"
bind-password: "password"
user:
base-dn: "ou=users,dc=example,dc=com"
enable-attr: "" #The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
enable-attr-value: "" # The value of the enable attribute when the user is enabled. If you are using AD, just set random value, it will be ignored.
filter: "(cn=*)"
username: "uid" # The attribute name of the user for usernamem if you are using AD, it should be "sAMAccountName"
email: "mail"
first-name: "givenName"
last-name: "sn"
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
```
### Environment Variables
The prefix for variable names is `RUSTDESK_API`. If environment variables exist, they will override the configurations in the configuration file.
The environment variables correspond one-to-one with the configurations in the `conf/config.yaml` file. The prefix for variable names is `RUSTDESK_API`.
The table below does not list all configurations. Please refer to the configurations in `conf/config.yaml`.
| Variable Name | Description | Example |
|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------|-------------------------------|
|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|
| TZ | timezone | Asia/Shanghai |
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, default: 1 | 1 |
@@ -222,7 +243,7 @@ The prefix for variable names is `RUSTDESK_API`. If environment variables exist,
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
| ----JWT---- | -------- | -------- |
| RUSTDESK_API_JWT_KEY | JWT KEY. Set empty to disable jwt | |
| RUSTDESK_API_JWT_KEY | Custom JWT KEY, if empty JWT is not enabled.<br/>If `MUST_LOGIN` from `lejianwen/rustdesk-server` is not used, it is recommended to leave it empty. | |
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT expire duration | 360000 |
### Installation Steps
@@ -294,8 +315,9 @@ Download the release from [release](https://github.com/lejianwen/rustdesk-api/re
#### Running with my forked server-s6 image
- Connection timeout issue resolved
- Can enforce login before initiating a connection
- github https://github.com/lejianwen/rustdesk-server
- docker hub https://hub.docker.com/r/lejianwen/rustdesk-server-s6
```yaml
networks:
@@ -344,3 +366,5 @@ Thanks to everyone who contributed!
<a href="https://github.com/lejianwen/rustdesk-api/graphs/contributors">
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
</a>
## If you find this project helpful, please give it a star, thank you!

View File

@@ -12,7 +12,7 @@ import (
"Gwen/lib/upload"
"Gwen/model"
"Gwen/service"
"fmt"
"Gwen/utils"
"github.com/go-redis/redis/v8"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/spf13/cobra"
@@ -54,10 +54,10 @@ var resetPwdCmd = &cobra.Command{
admin := service.AllService.UserService.InfoById(1)
err := service.AllService.UserService.UpdatePassword(admin, pwd)
if err != nil {
fmt.Printf("reset password fail! %v \n", err)
global.Logger.Error("reset password fail! ", err)
return
}
fmt.Printf("reset password success! \n")
global.Logger.Info("reset password success! ")
},
}
var resetUserPwdCmd = &cobra.Command{
@@ -70,20 +70,20 @@ var resetUserPwdCmd = &cobra.Command{
pwd := args[1]
uid, err := strconv.Atoi(userId)
if err != nil {
fmt.Printf("userId must be int! \n")
global.Logger.Warn("userId must be int!")
return
}
if uid <= 0 {
fmt.Printf("userId must be greater than 0! \n")
global.Logger.Warn("userId must be greater than 0! ")
return
}
u := service.AllService.UserService.InfoById(uint(uid))
err = service.AllService.UserService.UpdatePassword(u, pwd)
if err != nil {
fmt.Printf("reset password fail! %v \n", err)
global.Logger.Warn("reset password fail! ", err)
return
}
fmt.Printf("reset password success! \n")
global.Logger.Info("reset password success!")
},
}
@@ -93,7 +93,7 @@ func init() {
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
global.Logger.Error(err)
os.Exit(1)
}
}
@@ -175,7 +175,6 @@ func DatabaseAutoUpdate() {
if global.Config.Gorm.Type == config.TypeMysql {
//检查存不存在数据库,不存在则创建
dbName := db.Migrator().CurrentDatabase()
fmt.Println("dbName", dbName)
if dbName == "" {
dbName = global.Config.Mysql.Dbname
// 移除 DSN 中的数据库名称,以便初始连接时不指定数据库
@@ -187,18 +186,18 @@ func DatabaseAutoUpdate() {
// 获取底层的 *sql.DB 对象,并确保在程序退出时关闭连接
sqlDBWithoutDB, err := dbWithoutDB.DB()
if err != nil {
fmt.Printf("获取底层 *sql.DB 对象失败: %v\n", err)
global.Logger.Error("获取底层 *sql.DB 对象失败: %v\n", err)
return
}
defer func() {
if err := sqlDBWithoutDB.Close(); err != nil {
fmt.Printf("关闭连接失败: %v\n", err)
global.Logger.Error("关闭连接失败: %v\n", err)
}
}()
err = dbWithoutDB.Exec("CREATE DATABASE IF NOT EXISTS " + dbName + " DEFAULT CHARSET utf8mb4").Error
if err != nil {
fmt.Println(err)
global.Logger.Error(err)
return
}
}
@@ -235,7 +234,7 @@ func DatabaseAutoUpdate() {
}
func Migrate(version uint) {
fmt.Println("migrating....", version)
global.Logger.Info("migrating....", version)
err := global.DB.AutoMigrate(
&model.Version{},
&model.User{},
@@ -255,7 +254,7 @@ func Migrate(version uint) {
&model.ServerCmd{},
)
if err != nil {
fmt.Println("migrate err :=>", err)
global.Logger.Error("migrate err :=>", err)
}
global.DB.Create(&model.Version{Version: version})
//如果是初次则创建一个默认用户
@@ -289,7 +288,11 @@ func Migrate(version uint) {
IsAdmin: &is_admin,
GroupId: 1,
}
admin.Password = service.AllService.UserService.EncryptPassword("admin")
// 生成随机密码
pwd := utils.RandomString(8)
global.Logger.Info("Admin Password Is: ", pwd)
admin.Password = service.AllService.UserService.EncryptPassword(pwd)
global.DB.Create(admin)
}

View File

@@ -4,6 +4,7 @@ app:
register: false #是否开启注册
show-swagger: 0 # 1:启用 0:禁用
token-expire: 360000
web-sso: true #web auth sso
admin:
title: "RustDesk Api Admin"
hello-file: "./conf/admin/hello.html" #优先使用file
@@ -40,24 +41,6 @@ proxy:
jwt:
key: ""
expire-duration: 360000
redis:
addr: "127.0.0.1:6379"
password: ""
db: 0
cache:
type: "file"
file-dir: "./runtime/cache"
redis-addr: "127.0.0.1:6379"
redis-pwd: ""
redis-db: 0
oss:
access-key-id: ""
access-key-secret: ""
host: ""
callback-url: ""
expire-time: 30
max-byte: 10240
ldap:
enable: false
url: "ldap://ldap.example.com:389"
@@ -78,3 +61,22 @@ ldap:
last-name: "sn"
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
redis:
addr: "127.0.0.1:6379"
password: ""
db: 0
cache:
type: "file"
file-dir: "./runtime/cache"
redis-addr: "127.0.0.1:6379"
redis-pwd: ""
redis-db: 0
oss:
access-key-id: ""
access-key-secret: ""
host: ""
callback-url: ""
expire-time: 30
max-byte: 10240

View File

@@ -2,7 +2,6 @@ package config
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"strings"
)
@@ -18,6 +17,7 @@ type App struct {
Register bool `mapstructure:"register"`
ShowSwagger int `mapstructure:"show-swagger"`
TokenExpire int `mapstructure:"token-expire"`
WebSso bool `mapstructure:"web-sso"`
}
type Admin struct {
Title string `mapstructure:"title"`
@@ -57,6 +57,9 @@ func Init(rowVal *Config, path string) *viper.Viper {
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
v.WatchConfig()
/*
//监听配置修改没什么必要
v.OnConfigChange(func(e fsnotify.Event) {
//配置文件修改监听
fmt.Println("config file changed:", e.Name)
@@ -66,6 +69,7 @@ func Init(rowVal *Config, path string) *viper.Viper {
rowVal.Rustdesk.LoadKeyFile()
rowVal.Rustdesk.ParsePort()
})
*/
if err := v.Unmarshal(rowVal); err != nil {
fmt.Println(err)
}

BIN
docs/init_admin_pwd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -85,7 +85,9 @@ func (l *Login) Login(c *gin.Context) {
// @Router /login-options [get]
func (l *Login) LoginOptions(c *gin.Context) {
ops := service.AllService.OauthService.GetOauthProviders()
if global.Config.App.WebSso {
ops = append(ops, model.OauthTypeWebauth)
}
var oidcItems []map[string]string
for _, v := range ops {
oidcItems = append(oidcItems, map[string]string{"name": v})

View File

@@ -21,7 +21,7 @@ type Config struct {
func New(c *Config) *log.Logger {
log.SetFormatter(&nested.Formatter{
// HideKeys: true,
TimestampFormat: "2006-01-02 15:04:05",
TimestampFormat: "[2006-01-02 15:04:05]",
NoColors: true,
NoFieldsColors: true,
//FieldsOrder: []string{"name", "age"},