mirror of
https://github.com/lejianwen/rustdesk-api.git
synced 2025-11-29 08:33:21 +00:00
add login fail warn &
add web client on/off & up admin peer filter & upgrade web client
This commit is contained in:
45
README.md
45
README.md
@@ -151,6 +151,8 @@
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
lang: "en"
|
lang: "en"
|
||||||
|
app:
|
||||||
|
web-client: 1 # 1:启用 0:禁用
|
||||||
gin:
|
gin:
|
||||||
api-addr: "0.0.0.0:21114"
|
api-addr: "0.0.0.0:21114"
|
||||||
mode: "release"
|
mode: "release"
|
||||||
@@ -180,27 +182,28 @@ logger:
|
|||||||
### 环境变量
|
### 环境变量
|
||||||
变量名前缀是`RUSTDESK_API`,环境变量如果存在将覆盖配置文件中的配置
|
变量名前缀是`RUSTDESK_API`,环境变量如果存在将覆盖配置文件中的配置
|
||||||
|
|
||||||
| 变量名 | 说明 | 示例 |
|
| 变量名 | 说明 | 示例 |
|
||||||
|-------------------------------------|--------------------------------------|-----------------------------|
|
|------------------------------------|--------------------------------------|-----------------------------|
|
||||||
| TZ | 时区 | Asia/Shanghai |
|
| TZ | 时区 | Asia/Shanghai |
|
||||||
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
|
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
|
||||||
| -----GIN配置----- | ---------- | ---------- |
|
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
|
||||||
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
| -----GIN配置----- | ---------- | ---------- |
|
||||||
| -----------GORM配置------------------ | ------------------------------------ | --------------------------- |
|
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
||||||
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
| -----------GORM配置---------------- | ------------------------------------ | --------------------------- |
|
||||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
||||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
||||||
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
||||||
| -----MYSQL配置----- | ---------- | ---------- |
|
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
||||||
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
| -----MYSQL配置----- | ---------- | ---------- |
|
||||||
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
||||||
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
||||||
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
||||||
| -----RUSTDESK配置----- | --------------- | ---------- |
|
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
||||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
| -----RUSTDESK配置----- | --------------- | ---------- |
|
||||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
|
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
||||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
|
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
|
||||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
|
||||||
|
|
||||||
### 运行
|
### 运行
|
||||||
|
|
||||||
|
|||||||
45
README_EN.md
45
README_EN.md
@@ -157,6 +157,8 @@ installation are `admin` `admin`, please change the password immediately.
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
lang: "en"
|
lang: "en"
|
||||||
|
app:
|
||||||
|
web-client: 1 # web client route 1:open 0:close
|
||||||
gin:
|
gin:
|
||||||
api-addr: "0.0.0.0:21114"
|
api-addr: "0.0.0.0:21114"
|
||||||
mode: "release"
|
mode: "release"
|
||||||
@@ -186,27 +188,28 @@ logger:
|
|||||||
### Environment Variables
|
### Environment Variables
|
||||||
The prefix for variable names is `RUSTDESK_API`. If environment variables exist, they will override the configurations in the configuration file.
|
The prefix for variable names is `RUSTDESK_API`. If environment variables exist, they will override the configurations in the configuration file.
|
||||||
|
|
||||||
| Variable Name | Description | Example |
|
| Variable Name | Description | Example |
|
||||||
|------------------------------------|-----------------------------------------------------------|--------------------------------|
|
|------------------------------------|-----------------------------------------------------------|-------------------------------|
|
||||||
| TZ | timezone | Asia/Shanghai |
|
| TZ | timezone | Asia/Shanghai |
|
||||||
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
||||||
| ----- GIN Configuration ----- | --------------------------------------- | ------------------------------ |
|
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, deault 1 | 1 |
|
||||||
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
| ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
| ----- GORM Configuration ----- | --------------------------------------- | ------------------------------ |
|
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
||||||
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
| ----- GORM Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
||||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
||||||
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
||||||
| ----- MYSQL Configuration ----- | --------------------------------------- | ------------------------------ |
|
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
||||||
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
| ----- MYSQL Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
||||||
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
||||||
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
||||||
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ------------------------------ |
|
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
||||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
|
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
||||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
|
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
|
||||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
||||||
|
|
||||||
### Installation Steps
|
### Installation Steps
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
lang: "zh-CN"
|
lang: "zh-CN"
|
||||||
|
app:
|
||||||
|
web-client: 1 # 1:启用 0:禁用
|
||||||
gin:
|
gin:
|
||||||
api-addr: "0.0.0.0:21114"
|
api-addr: "0.0.0.0:21114"
|
||||||
mode: "release" #release,debug,test
|
mode: "release" #release,debug,test
|
||||||
@@ -16,7 +18,7 @@ mysql:
|
|||||||
rustdesk:
|
rustdesk:
|
||||||
id-server: "192.168.1.66:21116"
|
id-server: "192.168.1.66:21116"
|
||||||
relay-server: "192.168.1.66:21117"
|
relay-server: "192.168.1.66:21117"
|
||||||
api-server: "http://192.168.1.66:21114"
|
api-server: "http://127.0.0.1:21114"
|
||||||
key: "123456789"
|
key: "123456789"
|
||||||
personal: 1
|
personal: 1
|
||||||
logger:
|
logger:
|
||||||
|
|||||||
@@ -14,8 +14,13 @@ const (
|
|||||||
DefaultConfig = "conf/config.yaml"
|
DefaultConfig = "conf/config.yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
WebClient int `mapstructure:"web-client"`
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Lang string `mapstructure:"lang"`
|
Lang string `mapstructure:"lang"`
|
||||||
|
App App
|
||||||
Gorm Gorm
|
Gorm Gorm
|
||||||
Mysql Mysql
|
Mysql Mysql
|
||||||
Gin Gin
|
Gin Gin
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
adResp "Gwen/http/response/admin"
|
adResp "Gwen/http/response/admin"
|
||||||
"Gwen/model"
|
"Gwen/model"
|
||||||
"Gwen/service"
|
"Gwen/service"
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,18 +29,21 @@ func (ct *Login) Login(c *gin.Context) {
|
|||||||
f := &admin.Login{}
|
f := &admin.Login{}
|
||||||
err := c.ShouldBindJSON(f)
|
err := c.ShouldBindJSON(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errList := global.Validator.ValidStruct(c, f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
||||||
|
|
||||||
if u.Id == 0 {
|
if u.Id == 0 {
|
||||||
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,12 @@ func (ct *Peer) List(c *gin.Context) {
|
|||||||
lt := time.Now().Unix() + int64(query.TimeAgo)
|
lt := time.Now().Unix() + int64(query.TimeAgo)
|
||||||
tx.Where("last_online_time > ?", lt)
|
tx.Where("last_online_time > ?", lt)
|
||||||
}
|
}
|
||||||
|
if query.Id != "" {
|
||||||
|
tx.Where("id like ?", "%"+query.Id+"%")
|
||||||
|
}
|
||||||
|
if query.Hostname != "" {
|
||||||
|
tx.Where("hostname like ?", "%"+query.Hostname+"%")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
type Rustdesk struct {
|
type Rustdesk struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig 服务配置
|
// ServerConfig RUSTDESK服务配置
|
||||||
// @Tags ADMIN
|
// @Tags ADMIN
|
||||||
// @Summary 服务配置
|
// @Summary RUSTDESK服务配置
|
||||||
// @Description 服务配置,给webclient提供api-server
|
// @Description 服务配置,给webclient提供api-server
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
@@ -28,3 +28,19 @@ func (r *Rustdesk) ServerConfig(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
response.Success(c, cf)
|
response.Success(c, cf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AppConfig APP服务配置
|
||||||
|
// @Tags ADMIN
|
||||||
|
// @Summary APP服务配置
|
||||||
|
// @Description APP服务配置
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/app-config [get]
|
||||||
|
// @Security token
|
||||||
|
func (r *Rustdesk) AppConfig(c *gin.Context) {
|
||||||
|
response.Success(c, &gin.H{
|
||||||
|
"web_client": global.Config.App.WebClient,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"Gwen/model"
|
"Gwen/model"
|
||||||
"Gwen/service"
|
"Gwen/service"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -402,7 +401,7 @@ func (a *Ab) PeerAdd(c *gin.Context) {
|
|||||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println(f)
|
//fmt.Println(f)
|
||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
f.UserId = u.Id
|
f.UserId = u.Id
|
||||||
ab := f.ToAddressBook()
|
ab := f.ToAddressBook()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"Gwen/model"
|
"Gwen/model"
|
||||||
"Gwen/service"
|
"Gwen/service"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@@ -30,12 +31,14 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
err := c.ShouldBindJSON(f)
|
err := c.ShouldBindJSON(f)
|
||||||
//fmt.Println(f)
|
//fmt.Println(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errList := global.Validator.ValidStruct(c, f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Error(c, errList[0])
|
response.Error(c, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -43,6 +46,7 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
||||||
|
|
||||||
if u.Id == 0 {
|
if u.Id == 0 {
|
||||||
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Error(c, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
response.Error(c, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ type Peer struct {
|
|||||||
// @Success 200 {string} string "SYSINFO_UPDATED,ID_NOT_FOUND"
|
// @Success 200 {string} string "SYSINFO_UPDATED,ID_NOT_FOUND"
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /sysinfo [post]
|
// @Router /sysinfo [post]
|
||||||
// @Security BearerAuth
|
|
||||||
func (p *Peer) SysInfo(c *gin.Context) {
|
func (p *Peer) SysInfo(c *gin.Context) {
|
||||||
f := &requstform.PeerForm{}
|
f := &requstform.PeerForm{}
|
||||||
err := c.ShouldBindBodyWith(f, binding.JSON)
|
err := c.ShouldBindBodyWith(f, binding.JSON)
|
||||||
@@ -30,17 +29,28 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
|||||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
fpe := f.ToPeer()
|
||||||
pe := service.AllService.PeerService.FindById(f.Id)
|
pe := service.AllService.PeerService.FindById(f.Id)
|
||||||
if pe == nil || pe.RowId == 0 {
|
if pe.RowId == 0 {
|
||||||
pe = f.ToPeer()
|
pe = f.ToPeer()
|
||||||
|
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
|
||||||
err = service.AllService.PeerService.Create(pe)
|
err = service.AllService.PeerService.Create(pe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if pe.UserId == 0 {
|
||||||
|
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
|
||||||
|
}
|
||||||
|
fpe.RowId = pe.RowId
|
||||||
|
fpe.UserId = pe.UserId
|
||||||
|
err = service.AllService.PeerService.Update(fpe)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SYSINFO_UPDATED 上传成功
|
//SYSINFO_UPDATED 上传成功
|
||||||
//ID_NOT_FOUND 下次心跳会上传
|
//ID_NOT_FOUND 下次心跳会上传
|
||||||
//直接响应文本
|
//直接响应文本
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
func RustAuth() gin.HandlerFunc {
|
func RustAuth() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
//fmt.Println(c.Request.Header)
|
//fmt.Println(c.Request.URL, c.Request.Header)
|
||||||
//获取HTTP_AUTHORIZATION
|
//获取HTTP_AUTHORIZATION
|
||||||
token := c.GetHeader("Authorization")
|
token := c.GetHeader("Authorization")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
|
|||||||
@@ -35,5 +35,7 @@ func (f *PeerForm) ToPeer() *model.Peer {
|
|||||||
|
|
||||||
type PeerQuery struct {
|
type PeerQuery struct {
|
||||||
PageQuery
|
PageQuery
|
||||||
TimeAgo int `json:"time_ago" form:"time_ago"`
|
TimeAgo int `json:"time_ago" form:"time_ago"`
|
||||||
|
Id string `json:"id" form:"id"`
|
||||||
|
Hostname string `json:"hostname" form:"hostname"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ func Init(g *gin.Engine) {
|
|||||||
|
|
||||||
rs := &admin.Rustdesk{}
|
rs := &admin.Rustdesk{}
|
||||||
adg.GET("/server-config", rs.ServerConfig)
|
adg.GET("/server-config", rs.ServerConfig)
|
||||||
|
adg.GET("/app-config", rs.AppConfig)
|
||||||
|
|
||||||
//访问静态文件
|
//访问静态文件
|
||||||
//g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload"))
|
//g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload"))
|
||||||
|
|||||||
@@ -47,17 +47,11 @@ func ApiInit(g *gin.Engine) {
|
|||||||
frg.POST("/sysinfo", pe.SysInfo)
|
frg.POST("/sysinfo", pe.SysInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if global.Config.App.WebClient == 1 {
|
||||||
w := &api.WebClient{}
|
WebClientRoutes(frg)
|
||||||
frg.POST("/shared-peer", w.SharedPeer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frg.Use(middleware.RustAuth())
|
frg.Use(middleware.RustAuth())
|
||||||
{
|
|
||||||
w := &api.WebClient{}
|
|
||||||
frg.POST("/server-config", w.ServerConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
u := &api.User{}
|
u := &api.User{}
|
||||||
frg.GET("/user/info", u.Info)
|
frg.GET("/user/info", u.Info)
|
||||||
@@ -115,3 +109,14 @@ func PersonalRoutes(frg *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WebClientRoutes(frg *gin.RouterGroup) {
|
||||||
|
w := &api.WebClient{}
|
||||||
|
{
|
||||||
|
frg.POST("/shared-peer", w.SharedPeer)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
frg.POST("/server-config", middleware.RustAuth(), w.ServerConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,13 @@ import (
|
|||||||
func WebInit(g *gin.Engine) {
|
func WebInit(g *gin.Engine) {
|
||||||
i := &web.Index{}
|
i := &web.Index{}
|
||||||
g.GET("/", i.Index)
|
g.GET("/", i.Index)
|
||||||
g.GET("/webclient-config/index.js", i.ConfigJs)
|
|
||||||
g.StaticFS("/webclient", http.Dir(global.Config.Gin.ResourcesPath+"/web"))
|
if global.Config.App.WebClient == 1 {
|
||||||
|
g.GET("/webclient-config/index.js", i.ConfigJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if global.Config.App.WebClient == 1 {
|
||||||
|
g.StaticFS("/webclient", http.Dir(global.Config.Gin.ResourcesPath+"/web"))
|
||||||
|
}
|
||||||
g.StaticFS("/_admin", http.Dir(global.Config.Gin.ResourcesPath+"/admin"))
|
g.StaticFS("/_admin", http.Dir(global.Config.Gin.ResourcesPath+"/admin"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type SqliteConfig struct {
|
|||||||
|
|
||||||
func NewSqlite(sqliteConf *SqliteConfig) *gorm.DB {
|
func NewSqlite(sqliteConf *SqliteConfig) *gorm.DB {
|
||||||
db, err := gorm.Open(sqlite.Open("./data/rustdeskapi.db"), &gorm.Config{
|
db, err := gorm.Open(sqlite.Open("./data/rustdeskapi.db"), &gorm.Config{
|
||||||
|
DisableForeignKeyConstraintWhenMigrating: true,
|
||||||
Logger: logger.New(
|
Logger: logger.New(
|
||||||
global.Logger, // io writer
|
global.Logger, // io writer
|
||||||
logger.Config{
|
logger.Config{
|
||||||
|
|||||||
4
resources/web/js/dist/index.js
vendored
4
resources/web/js/dist/index.js
vendored
File diff suppressed because one or more lines are too long
545
resources/web/js/src/globals.js
vendored
545
resources/web/js/src/globals.js
vendored
@@ -1,41 +1,44 @@
|
|||||||
import Connection from "./connection";
|
import Connection from "./connection";
|
||||||
import _sodium from "libsodium-wrappers";
|
import _sodium from "libsodium-wrappers";
|
||||||
import { CursorData } from "./message";
|
import {loadVp9} from "./codec";
|
||||||
import { loadVp9 } from "./codec";
|
import {checkIfRetry, version} from "./gen_js_from_hbb";
|
||||||
import { checkIfRetry, version } from "./gen_js_from_hbb";
|
import {initZstd, translate} from "./common";
|
||||||
import { initZstd, translate } from "./common";
|
|
||||||
import PCMPlayer from "pcm-player";
|
import PCMPlayer from "pcm-player";
|
||||||
|
import {getServerConf} from "./ljw";
|
||||||
|
|
||||||
|
window.myconsole = (...args) => {
|
||||||
|
console.log(args);
|
||||||
|
}
|
||||||
window.curConn = undefined;
|
window.curConn = undefined;
|
||||||
window.isMobile = () => {
|
window.isMobile = () => {
|
||||||
return /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
|
return /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
|
||||||
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4));
|
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isDesktop() {
|
export function isDesktop() {
|
||||||
return !isMobile();
|
return !isMobile();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function msgbox(type, title, text) {
|
export function msgbox(type, title, text) {
|
||||||
if (!type || (type == 'error' && !text)) return;
|
if (!type || (type == 'error' && !text)) return;
|
||||||
const text2 = text.toLowerCase();
|
const text2 = text.toLowerCase();
|
||||||
var hasRetry = checkIfRetry(type, title, text) ? 'true' : '';
|
var hasRetry = checkIfRetry(type, title, text) ? 'true' : '';
|
||||||
onGlobalEvent(JSON.stringify({ name: 'msgbox', type, title, text, hasRetry }));
|
onGlobalEvent(JSON.stringify({name: 'msgbox', type, title, text, hasRetry}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function jsonfyForDart(payload) {
|
function jsonfyForDart(payload) {
|
||||||
var tmp = {};
|
var tmp = {};
|
||||||
for (const [key, value] of Object.entries(payload)) {
|
for (const [key, value] of Object.entries(payload)) {
|
||||||
if (!key) continue;
|
if (!key) continue;
|
||||||
tmp[key] = value instanceof Uint8Array ? '[' + value.toString() + ']' : JSON.stringify(value);
|
tmp[key] = value instanceof Uint8Array ? '[' + value.toString() + ']' : JSON.stringify(value);
|
||||||
}
|
}
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pushEvent(name, payload) {
|
export function pushEvent(name, payload) {
|
||||||
payload = jsonfyForDart(payload);
|
payload = jsonfyForDart(payload);
|
||||||
payload.name = name;
|
payload.name = name;
|
||||||
onGlobalEvent(JSON.stringify(payload));
|
onGlobalEvent(JSON.stringify(payload));
|
||||||
}
|
}
|
||||||
|
|
||||||
let yuvWorker;
|
let yuvWorker;
|
||||||
@@ -45,339 +48,347 @@ let pixels;
|
|||||||
let flipPixels;
|
let flipPixels;
|
||||||
let oldSize;
|
let oldSize;
|
||||||
if (YUVCanvas.WebGLFrameSink.isAvailable()) {
|
if (YUVCanvas.WebGLFrameSink.isAvailable()) {
|
||||||
var canvas = document.createElement('canvas');
|
var canvas = document.createElement('canvas');
|
||||||
yuvCanvas = YUVCanvas.attach(canvas, { webGL: true });
|
yuvCanvas = YUVCanvas.attach(canvas, {webGL: true});
|
||||||
gl = canvas.getContext("webgl");
|
gl = canvas.getContext("webgl");
|
||||||
} else {
|
} else {
|
||||||
yuvWorker = new Worker("./yuv.js");
|
yuvWorker = new Worker("./yuv.js");
|
||||||
}
|
}
|
||||||
let testSpeed = [0, 0];
|
let testSpeed = [0, 0];
|
||||||
|
|
||||||
export function draw(frame) {
|
export function draw(frame) {
|
||||||
if (yuvWorker) {
|
if (yuvWorker) {
|
||||||
// frame's (y/u/v).bytes already detached, can not transferrable any more.
|
// frame's (y/u/v).bytes already detached, can not transferrable any more.
|
||||||
yuvWorker.postMessage(frame);
|
yuvWorker.postMessage(frame);
|
||||||
} else {
|
} else {
|
||||||
var tm0 = new Date().getTime();
|
var tm0 = new Date().getTime();
|
||||||
yuvCanvas.drawFrame(frame);
|
yuvCanvas.drawFrame(frame);
|
||||||
var width = canvas.width;
|
var width = canvas.width;
|
||||||
var height = canvas.height;
|
var height = canvas.height;
|
||||||
var size = width * height * 4;
|
var size = width * height * 4;
|
||||||
if (size != oldSize) {
|
if (size != oldSize) {
|
||||||
pixels = new Uint8Array(size);
|
pixels = new Uint8Array(size);
|
||||||
flipPixels = new Uint8Array(size);
|
flipPixels = new Uint8Array(size);
|
||||||
oldSize = size;
|
oldSize = size;
|
||||||
|
}
|
||||||
|
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
||||||
|
const row = width * 4;
|
||||||
|
const end = (height - 1) * row;
|
||||||
|
for (let i = 0; i < size; i += row) {
|
||||||
|
flipPixels.set(pixels.subarray(i, i + row), end - i);
|
||||||
|
}
|
||||||
|
onRgba(flipPixels);
|
||||||
|
testSpeed[1] += new Date().getTime() - tm0;
|
||||||
|
testSpeed[0] += 1;
|
||||||
|
if (testSpeed[0] > 30) {
|
||||||
|
console.log('gl: ' + parseInt('' + testSpeed[1] / testSpeed[0]));
|
||||||
|
testSpeed = [0, 0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
/*
|
||||||
const row = width * 4;
|
var testCanvas = document.getElementById("test-yuv-decoder-canvas");
|
||||||
const end = (height - 1) * row;
|
if (testCanvas && currentFrame) {
|
||||||
for (let i = 0; i < size; i += row) {
|
var ctx = testCanvas.getContext("2d");
|
||||||
flipPixels.set(pixels.subarray(i, i + row), end - i);
|
testCanvas.width = frame.format.displayWidth;
|
||||||
|
testCanvas.height = frame.format.displayHeight;
|
||||||
|
var img = ctx.createImageData(testCanvas.width, testCanvas.height);
|
||||||
|
img.data.set(currentFrame);
|
||||||
|
ctx.putImageData(img, 0, 0);
|
||||||
}
|
}
|
||||||
onRgba(flipPixels);
|
*/
|
||||||
testSpeed[1] += new Date().getTime() - tm0;
|
|
||||||
testSpeed[0] += 1;
|
|
||||||
if (testSpeed[0] > 30) {
|
|
||||||
console.log('gl: ' + parseInt('' + testSpeed[1] / testSpeed[0]));
|
|
||||||
testSpeed = [0, 0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
var testCanvas = document.getElementById("test-yuv-decoder-canvas");
|
|
||||||
if (testCanvas && currentFrame) {
|
|
||||||
var ctx = testCanvas.getContext("2d");
|
|
||||||
testCanvas.width = frame.format.displayWidth;
|
|
||||||
testCanvas.height = frame.format.displayHeight;
|
|
||||||
var img = ctx.createImageData(testCanvas.width, testCanvas.height);
|
|
||||||
img.data.set(currentFrame);
|
|
||||||
ctx.putImageData(img, 0, 0);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendOffCanvas(c) {
|
export function sendOffCanvas(c) {
|
||||||
let canvas = c.transferControlToOffscreen();
|
let canvas = c.transferControlToOffscreen();
|
||||||
yuvWorker.postMessage({ canvas }, [canvas]);
|
yuvWorker.postMessage({canvas}, [canvas]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setConn(conn) {
|
export function setConn(conn) {
|
||||||
window.curConn = conn;
|
window.curConn = conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConn() {
|
export function getConn() {
|
||||||
return window.curConn;
|
return window.curConn;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function startConn(id) {
|
export async function startConn(id) {
|
||||||
setByName('remote_id', id);
|
setByName('remote_id', id);
|
||||||
await curConn.start(id);
|
await curConn.start(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function close() {
|
export function close() {
|
||||||
getConn()?.close();
|
getConn()?.close();
|
||||||
setConn(undefined);
|
setConn(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function newConn() {
|
export function newConn() {
|
||||||
window.curConn?.close();
|
window.curConn?.close();
|
||||||
const conn = new Connection();
|
const conn = new Connection();
|
||||||
setConn(conn);
|
setConn(conn);
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sodium;
|
let sodium;
|
||||||
|
|
||||||
export async function verify(signed, pk) {
|
export async function verify(signed, pk) {
|
||||||
if (!sodium) {
|
if (!sodium) {
|
||||||
await _sodium.ready;
|
await _sodium.ready;
|
||||||
sodium = _sodium;
|
sodium = _sodium;
|
||||||
}
|
}
|
||||||
if (typeof pk == 'string') {
|
if (typeof pk == 'string') {
|
||||||
pk = decodeBase64(pk);
|
pk = decodeBase64(pk);
|
||||||
}
|
}
|
||||||
return sodium.crypto_sign_open(signed, pk);
|
return sodium.crypto_sign_open(signed, pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decodeBase64(pk) {
|
export function decodeBase64(pk) {
|
||||||
return sodium.from_base64(pk, sodium.base64_variants.ORIGINAL);
|
return sodium.from_base64(pk, sodium.base64_variants.ORIGINAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function genBoxKeyPair() {
|
export function genBoxKeyPair() {
|
||||||
const pair = sodium.crypto_box_keypair();
|
const pair = sodium.crypto_box_keypair();
|
||||||
const sk = pair.privateKey;
|
const sk = pair.privateKey;
|
||||||
const pk = pair.publicKey;
|
const pk = pair.publicKey;
|
||||||
return [sk, pk];
|
return [sk, pk];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function genSecretKey() {
|
export function genSecretKey() {
|
||||||
return sodium.crypto_secretbox_keygen();
|
return sodium.crypto_secretbox_keygen();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function seal(unsigned, theirPk, ourSk) {
|
export function seal(unsigned, theirPk, ourSk) {
|
||||||
const nonce = Uint8Array.from(Array(24).fill(0));
|
const nonce = Uint8Array.from(Array(24).fill(0));
|
||||||
return sodium.crypto_box_easy(unsigned, nonce, theirPk, ourSk);
|
return sodium.crypto_box_easy(unsigned, nonce, theirPk, ourSk);
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeOnce(value) {
|
function makeOnce(value) {
|
||||||
var byteArray = Array(24).fill(0);
|
var byteArray = Array(24).fill(0);
|
||||||
|
|
||||||
for (var index = 0; index < byteArray.length && value > 0; index++) {
|
for (var index = 0; index < byteArray.length && value > 0; index++) {
|
||||||
var byte = value & 0xff;
|
var byte = value & 0xff;
|
||||||
byteArray[index] = byte;
|
byteArray[index] = byte;
|
||||||
value = (value - byte) / 256;
|
value = (value - byte) / 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Uint8Array.from(byteArray);
|
return Uint8Array.from(byteArray);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function encrypt(unsigned, nonce, key) {
|
export function encrypt(unsigned, nonce, key) {
|
||||||
return sodium.crypto_secretbox_easy(unsigned, makeOnce(nonce), key);
|
return sodium.crypto_secretbox_easy(unsigned, makeOnce(nonce), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decrypt(signed, nonce, key) {
|
export function decrypt(signed, nonce, key) {
|
||||||
return sodium.crypto_secretbox_open_easy(signed, makeOnce(nonce), key);
|
return sodium.crypto_secretbox_open_easy(signed, makeOnce(nonce), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.setByName = (name, value) => {
|
window.setByName = (name, value) => {
|
||||||
switch (name) {
|
myconsole('setByName', name, value);
|
||||||
case 'remote_id':
|
switch (name) {
|
||||||
localStorage.setItem('remote-id', value);
|
case 'remote_id':
|
||||||
break;
|
localStorage.setItem('remote-id', value);
|
||||||
case 'connect':
|
break;
|
||||||
newConn();
|
case 'connect':
|
||||||
startConn(value);
|
newConn();
|
||||||
break;
|
startConn(value);
|
||||||
case 'login':
|
break;
|
||||||
value = JSON.parse(value);
|
case 'login':
|
||||||
curConn.setRemember(value.remember == 'true');
|
value = JSON.parse(value);
|
||||||
curConn.login(value.password);
|
curConn.setRemember(value.remember == 'true');
|
||||||
break;
|
curConn.login(value.password);
|
||||||
case 'close':
|
break;
|
||||||
close();
|
case 'close':
|
||||||
break;
|
close();
|
||||||
case 'refresh':
|
break;
|
||||||
curConn.refresh();
|
case 'refresh':
|
||||||
break;
|
curConn.refresh();
|
||||||
case 'reconnect':
|
break;
|
||||||
curConn.reconnect();
|
case 'reconnect':
|
||||||
break;
|
curConn.reconnect();
|
||||||
case 'toggle_option':
|
break;
|
||||||
curConn.toggleOption(value);
|
case 'toggle_option':
|
||||||
break;
|
curConn.toggleOption(value);
|
||||||
case 'image_quality':
|
break;
|
||||||
curConn.setImageQuality(value);
|
case 'image_quality':
|
||||||
break;
|
curConn.setImageQuality(value);
|
||||||
case 'lock_screen':
|
break;
|
||||||
curConn.lockScreen();
|
case 'lock_screen':
|
||||||
break;
|
curConn.lockScreen();
|
||||||
case 'ctrl_alt_del':
|
break;
|
||||||
curConn.ctrlAltDel();
|
case 'ctrl_alt_del':
|
||||||
break;
|
curConn.ctrlAltDel();
|
||||||
case 'switch_display':
|
break;
|
||||||
curConn.switchDisplay(value);
|
case 'switch_display':
|
||||||
break;
|
curConn.switchDisplay(value);
|
||||||
case 'remove':
|
break;
|
||||||
const peers = getPeers();
|
case 'remove':
|
||||||
delete peers[value];
|
const peers = getPeers();
|
||||||
localStorage.setItem('peers', JSON.stringify(peers));
|
delete peers[value];
|
||||||
break;
|
localStorage.setItem('peers', JSON.stringify(peers));
|
||||||
case 'input_key':
|
break;
|
||||||
value = JSON.parse(value);
|
case 'input_key':
|
||||||
curConn.inputKey(value.name, value.down == 'true', value.press == 'true', value.alt == 'true', value.ctrl == 'true', value.shift == 'true', value.command == 'true');
|
value = JSON.parse(value);
|
||||||
break;
|
curConn.inputKey(value.name, value.down == 'true', value.press == 'true', value.alt == 'true', value.ctrl == 'true', value.shift == 'true', value.command == 'true');
|
||||||
case 'input_string':
|
break;
|
||||||
curConn.inputString(value);
|
case 'input_string':
|
||||||
break;
|
curConn.inputString(value);
|
||||||
case 'send_mouse':
|
break;
|
||||||
let mask = 0;
|
case 'send_mouse':
|
||||||
value = JSON.parse(value);
|
let mask = 0;
|
||||||
switch (value.type) {
|
value = JSON.parse(value);
|
||||||
case 'down':
|
switch (value.type) {
|
||||||
mask = 1;
|
case 'down':
|
||||||
break;
|
mask = 1;
|
||||||
case 'up':
|
break;
|
||||||
mask = 2;
|
case 'up':
|
||||||
break;
|
mask = 2;
|
||||||
case 'wheel':
|
break;
|
||||||
mask = 3;
|
case 'wheel':
|
||||||
break;
|
mask = 3;
|
||||||
}
|
break;
|
||||||
switch (value.buttons) {
|
}
|
||||||
case 'left':
|
switch (value.buttons) {
|
||||||
mask |= 1 << 3;
|
case 'left':
|
||||||
break;
|
mask |= 1 << 3;
|
||||||
case 'right':
|
break;
|
||||||
mask |= 2 << 3;
|
case 'right':
|
||||||
break;
|
mask |= 2 << 3;
|
||||||
case 'wheel':
|
break;
|
||||||
mask |= 4 << 3;
|
case 'wheel':
|
||||||
}
|
mask |= 4 << 3;
|
||||||
curConn.inputMouse(mask, parseInt(value.x || '0'), parseInt(value.y || '0'), value.alt == 'true', value.ctrl == 'true', value.shift == 'true', value.command == 'true');
|
}
|
||||||
break;
|
curConn.inputMouse(mask, parseInt(value.x || '0'), parseInt(value.y || '0'), value.alt == 'true', value.ctrl == 'true', value.shift == 'true', value.command == 'true');
|
||||||
case 'option':
|
break;
|
||||||
value = JSON.parse(value);
|
case 'option':
|
||||||
localStorage.setItem(value.name, value.value);
|
value = JSON.parse(value);
|
||||||
break;
|
localStorage.setItem(value.name, value.value);
|
||||||
case 'peer_option':
|
if (value.name === 'access_token' && value.value) {
|
||||||
value = JSON.parse(value);
|
getServerConf(value.value);
|
||||||
curConn.setOption(value.name, value.value);
|
}
|
||||||
break;
|
break;
|
||||||
case 'input_os_password':
|
case 'peer_option':
|
||||||
curConn.inputOsPassword(value);
|
value = JSON.parse(value);
|
||||||
break;
|
curConn.setOption(value.name, value.value);
|
||||||
default:
|
break;
|
||||||
break;
|
case 'input_os_password':
|
||||||
}
|
curConn.inputOsPassword(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.getByName = (name, arg) => {
|
window.getByName = (name, arg) => {
|
||||||
let v = _getByName(name, arg);
|
let v = _getByName(name, arg);
|
||||||
if (typeof v == 'string' || v instanceof String) return v;
|
myconsole('getByName', name, arg, v);
|
||||||
if (v == undefined || v == null) return '';
|
if (typeof v == 'string' || v instanceof String) return v;
|
||||||
return JSON.stringify(v);
|
if (v == undefined || v == null) return '';
|
||||||
|
return JSON.stringify(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPeersForDart() {
|
function getPeersForDart() {
|
||||||
const peers = [];
|
const peers = [];
|
||||||
for (const [id, value] of Object.entries(getPeers())) {
|
for (const [id, value] of Object.entries(getPeers())) {
|
||||||
if (!id) continue;
|
if (!id) continue;
|
||||||
const tm = value['tm'];
|
const tm = value['tm'];
|
||||||
const info = value['info'];
|
const info = value['info'];
|
||||||
if (!tm || !info) continue;
|
if (!tm || !info) continue;
|
||||||
peers.push([tm, id, info]);
|
peers.push([tm, id, info]);
|
||||||
}
|
}
|
||||||
return peers.sort().reverse().map(x => x.slice(1));
|
return peers.sort().reverse().map(x => x.slice(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getByName(name, arg) {
|
function _getByName(name, arg) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'peers':
|
case 'peers':
|
||||||
return getPeersForDart();
|
return getPeersForDart();
|
||||||
case 'remote_id':
|
case 'remote_id':
|
||||||
return localStorage.getItem('remote-id');
|
return localStorage.getItem('remote-id');
|
||||||
case 'remember':
|
case 'remember':
|
||||||
return curConn.getRemember();
|
return curConn.getRemember();
|
||||||
case 'toggle_option':
|
case 'toggle_option':
|
||||||
return curConn.getOption(arg) || false;
|
return curConn.getOption(arg) || false;
|
||||||
case 'option':
|
case 'option':
|
||||||
return localStorage.getItem(arg);
|
const v = localStorage.getItem(arg);
|
||||||
case 'image_quality':
|
if (arg === 'access_token' && v) {
|
||||||
return curConn.getImageQuality();
|
getServerConf(v);
|
||||||
case 'translate':
|
}
|
||||||
arg = JSON.parse(arg);
|
return v;
|
||||||
return translate(arg.locale, arg.text);
|
case 'image_quality':
|
||||||
case 'peer_option':
|
return curConn.getImageQuality();
|
||||||
return curConn.getOption(arg);
|
case 'translate':
|
||||||
case 'test_if_valid_server':
|
arg = JSON.parse(arg);
|
||||||
break;
|
return translate(arg.locale, arg.text);
|
||||||
case 'version':
|
case 'peer_option':
|
||||||
return version;
|
return curConn.getOption(arg);
|
||||||
}
|
case 'test_if_valid_server':
|
||||||
return '';
|
break;
|
||||||
|
case 'version':
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let opusWorker = new Worker("./libopus.js");
|
let opusWorker = new Worker("./libopus.js");
|
||||||
let pcmPlayer;
|
let pcmPlayer;
|
||||||
|
|
||||||
export function initAudio(channels, sampleRate) {
|
export function initAudio(channels, sampleRate) {
|
||||||
pcmPlayer = newAudioPlayer(channels, sampleRate);
|
pcmPlayer = newAudioPlayer(channels, sampleRate);
|
||||||
opusWorker.postMessage({ channels, sampleRate });
|
opusWorker.postMessage({channels, sampleRate});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function playAudio(packet) {
|
export function playAudio(packet) {
|
||||||
opusWorker.postMessage(packet, [packet.buffer]);
|
opusWorker.postMessage(packet, [packet.buffer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.init = async () => {
|
window.init = async () => {
|
||||||
if (yuvWorker) {
|
if (yuvWorker) {
|
||||||
yuvWorker.onmessage = (e) => {
|
yuvWorker.onmessage = (e) => {
|
||||||
onRgba(e.data);
|
onRgba(e.data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
opusWorker.onmessage = (e) => {
|
||||||
opusWorker.onmessage = (e) => {
|
pcmPlayer.feed(e.data);
|
||||||
pcmPlayer.feed(e.data);
|
}
|
||||||
}
|
loadVp9(() => {
|
||||||
loadVp9(() => { });
|
});
|
||||||
await initZstd();
|
await initZstd();
|
||||||
console.log('init done');
|
console.log('init done');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPeers() {
|
export function getPeers() {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(localStorage.getItem('peers')) || {};
|
return JSON.parse(localStorage.getItem('peers')) || {};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function newAudioPlayer(channels, sampleRate) {
|
function newAudioPlayer(channels, sampleRate) {
|
||||||
return new PCMPlayer({
|
return new PCMPlayer({
|
||||||
channels,
|
channels,
|
||||||
sampleRate,
|
sampleRate,
|
||||||
flushingTime: 2000
|
flushingTime: 2000
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function copyToClipboard(text) {
|
export function copyToClipboard(text) {
|
||||||
if (window.clipboardData && window.clipboardData.setData) {
|
if (window.clipboardData && window.clipboardData.setData) {
|
||||||
// Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
|
// Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
|
||||||
return window.clipboardData.setData("Text", text);
|
return window.clipboardData.setData("Text", text);
|
||||||
|
|
||||||
}
|
} else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
|
||||||
else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
|
var textarea = document.createElement("textarea");
|
||||||
var textarea = document.createElement("textarea");
|
textarea.textContent = text;
|
||||||
textarea.textContent = text;
|
textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in Microsoft Edge.
|
||||||
textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in Microsoft Edge.
|
document.body.appendChild(textarea);
|
||||||
document.body.appendChild(textarea);
|
textarea.select();
|
||||||
textarea.select();
|
try {
|
||||||
try {
|
return document.execCommand("copy"); // Security exception may be thrown by some browsers.
|
||||||
return document.execCommand("copy"); // Security exception may be thrown by some browsers.
|
} catch (ex) {
|
||||||
|
console.warn("Copy to clipboard failed.", ex);
|
||||||
|
// return prompt("Copy to clipboard: Ctrl+C, Enter", text);
|
||||||
|
} finally {
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (ex) {
|
|
||||||
console.warn("Copy to clipboard failed.", ex);
|
|
||||||
// return prompt("Copy to clipboard: Ctrl+C, Enter", text);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
document.body.removeChild(textarea);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
93
resources/web/js/src/ljw.js
vendored
93
resources/web/js/src/ljw.js
vendored
@@ -49,52 +49,51 @@ if (share_token) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let fetching = false
|
||||||
const autoWriteServer = () => {
|
export function getServerConf(token){
|
||||||
return setTimeout(() => {
|
console.log('getServerConf', token)
|
||||||
const token = localStorage.getItem('access_token')
|
if(fetching){
|
||||||
if (token && apiserver) {
|
return
|
||||||
fetch(apiserver + "/api/server-config", {
|
}
|
||||||
method: 'POST',
|
fetching = true
|
||||||
headers: {
|
fetch(apiserver + "/api/server-config", {
|
||||||
'Content-Type': 'application/json',
|
method: 'POST',
|
||||||
'Authorization': 'Bearer ' + token
|
headers: {
|
||||||
}
|
'Content-Type': 'application/json',
|
||||||
}
|
'Authorization': 'Bearer ' + token
|
||||||
).then(res => res.json()).then(res => {
|
}
|
||||||
if (res.code === 0) {
|
|
||||||
if (!localStorage.getItem('custom-rendezvous-server') || !localStorage.getItem('key')) {
|
|
||||||
localStorage.setItem('custom-rendezvous-server', res.data.id_server)
|
|
||||||
localStorage.setItem('key', res.data.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.data.peers) {
|
|
||||||
const oldPeers = JSON.parse(localStorage.getItem('peers')) || {}
|
|
||||||
let needUpdate = false
|
|
||||||
Object.keys(res.data.peers).forEach(k => {
|
|
||||||
if (!oldPeers[k]) {
|
|
||||||
oldPeers[k] = res.data.peers[k]
|
|
||||||
needUpdate = true
|
|
||||||
} else {
|
|
||||||
oldPeers[k].info = res.data.peers[k].info
|
|
||||||
}
|
|
||||||
if (oldPeers[k].info && oldPeers[k].info.hash && !oldPeers[k].password) {
|
|
||||||
let p1 = window.atob(oldPeers[k].info.hash)
|
|
||||||
const pwd = stringToUint8Array(p1)
|
|
||||||
oldPeers[k].password = pwd.toString()
|
|
||||||
oldPeers[k].remember = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
localStorage.setItem('peers', JSON.stringify(oldPeers))
|
|
||||||
if (needUpdate) {
|
|
||||||
window.location.reload()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
autoWriteServer()
|
|
||||||
}
|
}
|
||||||
}, 1000)
|
).then(res => res.json()).then(res => {
|
||||||
|
fetching = false
|
||||||
|
if (res.code === 0) {
|
||||||
|
if (!localStorage.getItem('custom-rendezvous-server') || !localStorage.getItem('key')) {
|
||||||
|
localStorage.setItem('custom-rendezvous-server', res.data.id_server)
|
||||||
|
localStorage.setItem('key', res.data.key)
|
||||||
|
}
|
||||||
|
if (res.data.peers) {
|
||||||
|
const oldPeers = JSON.parse(localStorage.getItem('peers')) || {}
|
||||||
|
let needUpdate = false
|
||||||
|
Object.keys(res.data.peers).forEach(k => {
|
||||||
|
if (!oldPeers[k]) {
|
||||||
|
oldPeers[k] = res.data.peers[k]
|
||||||
|
needUpdate = true
|
||||||
|
} else {
|
||||||
|
oldPeers[k].info = res.data.peers[k].info
|
||||||
|
}
|
||||||
|
if (oldPeers[k].info && oldPeers[k].info.hash && !oldPeers[k].password) {
|
||||||
|
let p1 = window.atob(oldPeers[k].info.hash)
|
||||||
|
const pwd = stringToUint8Array(p1)
|
||||||
|
oldPeers[k].password = pwd.toString()
|
||||||
|
oldPeers[k].remember = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
localStorage.setItem('peers', JSON.stringify(oldPeers))
|
||||||
|
if (needUpdate) {
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(_ => {
|
||||||
|
fetching = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
autoWriteServer()
|
|
||||||
@@ -262,3 +262,10 @@ func (us *UserService) UserThirdInfo(userId uint, op string) *model.UserThird {
|
|||||||
global.DB.Where("user_id = ? and third_type = ?", userId, op).First(ut)
|
global.DB.Where("user_id = ? and third_type = ?", userId, op).First(ut)
|
||||||
return ut
|
return ut
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindLatestUserIdFromLoginLogByUuid 根据uuid查找最后登录的用户id
|
||||||
|
func (us *UserService) FindLatestUserIdFromLoginLogByUuid(uuid string) uint {
|
||||||
|
llog := &model.LoginLog{}
|
||||||
|
global.DB.Where("uuid = ?", uuid).Order("id desc").First(llog)
|
||||||
|
return llog.UserId
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user