Compare commits

...

12 Commits

Author SHA1 Message Date
lejianwen
e318f1fd58 feat: WebClient 1.4.2 2025-09-12 15:11:49 +08:00
nomoneynolife
ee19eb9729 feat:ldap allow-group (#388) 2025-09-05 12:53:45 +08:00
Tom
fcdea1ad6d feat: add TLS configuration option for MySQL (#384) 2025-09-03 19:43:16 +08:00
lejianwen
c88d8cc359 docs: readme 2025-09-01 21:36:27 +08:00
lejianwen
ade6e6355a feat(peer): add alias field and support filtering by alias 2025-08-31 13:39:22 +08:00
lejianwen
9b769b99dc fix!: Update peer to use ID instead of UUID 2025-08-31 12:46:54 +08:00
lejianwen
c14c4d478b fix: The callback URL is based on the configured API SERVER because the project might be behind an Nginx reverse proxy. If the Origin/Host is forgotten to configure the reverse proxy, it will be incorrect 2025-08-10 15:48:11 +08:00
lejianwen
9d08c61390 fix: Normal user can not change the name of their own address book (#341) 2025-08-10 11:17:51 +08:00
Tao Chen
6f092472b1 feat: Optimize login workflow (#345)
* add "disable_pwd" and "auto_oidc" at /admin/login-options

* fix: build RedirectURL by host and scheme, not Origin
2025-07-31 10:46:11 +08:00
caicob
4876746f7a docs: README_EN.md (#340) 2025-07-31 10:42:56 +08:00
startgo
05d2d1642a feat: Update zh_TW.toml (#322)
Corrected translation to match Taiwanese Traditional Chinese usage
2025-07-19 21:08:40 +08:00
lejianwen
59fdd6424b feat(captcha): The captcha generates uppercase letter images, but it can only recognize them as lowercase (#319) 2025-07-14 20:36:33 +08:00
26 changed files with 104242 additions and 96392 deletions

View File

@@ -2,7 +2,8 @@
[English Doc](README_EN.md)
本项目使用 Go 实现了 RustDesk 的 API并包含了 Web Admin 和 Web 客户端。RustDesk 是一个远程桌面软件,提供了自托管的解决方案。
本项目使用 Go 实现了 RustDesk 的 API并包含了 Web Admin 和 Web 客户端。
<div align=center>
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
@@ -13,6 +14,14 @@
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
</div>
## 搭配[lejianwen/rustdesk-server]使用更佳。
> [lejianwen/rustdesk-server]fork自RustDesk Server官方仓库
> 1. 解决了使用API链接超时问题
> 2. 可以强制登录后才能发起链接
> 3. 支持客户端websocket
# 特性
- PC端API
@@ -182,6 +191,7 @@
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
| RUSTDESK_API_MYSQL_TLS | 是否启用TLS, 可选值: `true`, `false`, `skip-verify`, `custom` | `false` |
| -----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 |
@@ -325,3 +335,5 @@
</a>
## 感谢你的支持!如果这个项目对你有帮助,请点个⭐️鼓励一下,谢谢!
[lejianwen/rustdesk-server]: https://github.com/lejianwen/rustdesk-server

View File

@@ -12,6 +12,13 @@ desktop software that provides self-hosted solutions.
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
</div>
## Better used with [lejianwen/rustdesk-server].
> [lejianwen/rustdesk-server] is a fork of the official RustDesk Server repository.
> 1. Solves the API connection timeout issue.
> 2. Can enforce login before initiating a connection.
> 3. Supports client websocket.
# Features
- PC API
@@ -164,8 +171,7 @@ The table below does not list all configurations. Please refer to the configurat
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | disable password login | `false` |
| RUSTDESK_API_APP_REGISTER_STATUS | register user default status ; 1 enabled , 2 disabled ; default 1 | `1` |
| RUSTDESK_API_APP_CAPTCHA_THRESHOLD | captcha threshold; -1 disabled, 0 always enable, >0 threshold ;default `3` | `3` |
| RUSTDESK_API_APP_BAN_THRESHOLD | ban ip threshold; 0 disabled, >0 threshold ; default `0`
| `0` |
| RUSTDESK_API_APP_BAN_THRESHOLD | ban ip threshold; 0 disabled, >0 threshold ; default `0` | `0` |
| ----- ADMIN Configuration----- | ---------- | ---------- |
| RUSTDESK_API_ADMIN_TITLE | Admin Title | `RustDesk Api Admin` |
| RUSTDESK_API_ADMIN_HELLO | Admin welcome message, you can use `html` | |
@@ -182,6 +188,7 @@ The table below does not list all configurations. Please refer to the configurat
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
| RUSTDESK_API_MYSQL_TLS | Whether to enable TLS, optional values: `true`, `false`, `skip-verify`, `custom` | `false` |
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ----------------------------- |
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
@@ -325,4 +332,7 @@ Thanks to everyone who contributed!
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
</a>
## Thanks for your support! If you find this project useful, please give it a ⭐️. Thank you!
## Thanks for your support! If you find this project useful, please give it a ⭐️. Thank you!
[lejianwen/rustdesk-server]: https://github.com/lejianwen/rustdesk-server

View File

@@ -23,7 +23,7 @@ import (
"github.com/spf13/cobra"
)
const DatabaseVersion = 264
const DatabaseVersion = 265
// @title 管理系统API
// @version 1.0
@@ -145,11 +145,12 @@ func InitGlobal() {
//gorm
if global.Config.Gorm.Type == config.TypeMysql {
dsn := fmt.Sprintf("%s:%s@(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
dsn := fmt.Sprintf("%s:%s@(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local&tls=%s",
global.Config.Mysql.Username,
global.Config.Mysql.Password,
global.Config.Mysql.Addr,
global.Config.Mysql.Dbname,
global.Config.Mysql.Tls,
)
global.DB = orm.NewMysql(&orm.MysqlConfig{

View File

@@ -31,6 +31,7 @@ mysql:
password: ""
addr: ""
dbname: ""
tls: "false" # true / false / skip-verify / custom
postgresql:
host: "127.0.0.1"
@@ -80,4 +81,4 @@ 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.
allow-group: "cn=users,dc=example,dc=com" # The group name of the users group, if the user is in this group, the user will be an login.

View File

@@ -17,6 +17,7 @@ type Mysql struct {
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Dbname string `mapstructure:"dbname"`
Tls string `mapstructure:"tls"` // true / false / skip-verify / custom
}
type Postgresql struct {

View File

@@ -11,6 +11,7 @@ type LdapUser struct {
LastName string `mapstructure:"last-name"`
Sync bool `mapstructure:"sync"` // Will sync the user's information to the internal database
AdminGroup string `mapstructure:"admin-group"` // Which group is the admin group
AllowGroup string `mapstructure:"allow-group"` // Which group is allowed to login
}
// type LdapGroup struct {

2
go.mod
View File

@@ -25,6 +25,7 @@ require (
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.3
golang.org/x/crypto v0.33.0
golang.org/x/oauth2 v0.23.0
golang.org/x/text v0.22.0
gorm.io/driver/mysql v1.5.7
@@ -84,7 +85,6 @@ require (
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/image v0.13.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sync v0.11.0 // indirect

View File

@@ -169,6 +169,8 @@ func (ct *Login) LoginOptions(c *gin.Context) {
"ops": ops,
"register": global.Config.App.Register,
"need_captcha": needCaptcha,
"disable_pwd": global.Config.App.DisablePwdLogin,
"auto_oidc": global.Config.App.DisablePwdLogin && len(ops) == 1,
})
}
@@ -189,7 +191,7 @@ func (ct *Login) OidcAuth(c *gin.Context) {
return
}
err, state, verifier, nonce, url := service.AllService.OauthService.BeginAuth(c, 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

View File

@@ -98,10 +98,10 @@ func (abc *AddressBookCollection) Update(c *gin.Context) {
return
}
u := service.AllService.UserService.CurUser(c)
if f.UserId != u.Id {
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
return
}
//if f.UserId != u.Id {
// response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
// return
//}
ex := service.AllService.AddressBookService.CollectionInfoById(f.Id)
if ex.Id == 0 {
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))

View File

@@ -44,7 +44,7 @@ func (o *Oauth) ToBind(c *gin.Context) {
return
}
err, state, verifier, nonce, url := service.AllService.OauthService.BeginAuth(c, 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

View File

@@ -114,6 +114,9 @@ func (ct *Peer) List(c *gin.Context) {
if query.Ip != "" {
tx.Where("last_online_ip like ?", "%"+query.Ip+"%")
}
if query.Alias != "" {
tx.Where("alias like ?", "%"+query.Alias+"%")
}
})
response.Success(c, res)
}

View File

@@ -49,7 +49,7 @@ func (i *Index) Heartbeat(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{})
return
}
peer := service.AllService.PeerService.FindByUuid(info.Uuid)
peer := service.AllService.PeerService.FindById(info.Id)
if peer == nil || peer.RowId == 0 {
c.JSON(http.StatusOK, gin.H{})
return

View File

@@ -36,7 +36,7 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
oauthService := service.AllService.OauthService
err, state, verifier, nonce, url := oauthService.BeginAuth(c, f.Op)
err, state, verifier, nonce, url := oauthService.BeginAuth(f.Op)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
@@ -80,7 +80,8 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken)
// 如果 UserId 为 0说明还在授权中
if v.UserId == 0 {
c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress, please login and bind"})
//fix: 1.4.2 webclient oidc
c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress, please login and bind", "error": "No authed oidc is found"})
return nil, nil
}
@@ -170,7 +171,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
var user *model.User
// 获取用户信息
code := c.Query("code")
err, oauthUser := oauthService.Callback(c, code, verifier, op, nonce)
err, oauthUser := oauthService.Callback(code, verifier, op, nonce)
if err != nil {
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
"message": "OauthFailed",

View File

@@ -31,10 +31,10 @@ func (p *Peer) SysInfo(c *gin.Context) {
return
}
fpe := f.ToPeer()
pe := service.AllService.PeerService.FindByUuid(f.Uuid)
pe := service.AllService.PeerService.FindById(f.Id)
if pe.RowId == 0 {
pe = f.ToPeer()
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid, pe.Id)
err = service.AllService.PeerService.Create(pe)
if err != nil {
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
@@ -42,7 +42,7 @@ func (p *Peer) SysInfo(c *gin.Context) {
}
} else {
if pe.UserId == 0 {
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid, pe.Id)
}
fpe.RowId = pe.RowId
fpe.UserId = pe.UserId

View File

@@ -13,6 +13,7 @@ type PeerForm struct {
Uuid string `json:"uuid"`
Version string `json:"version"`
GroupId uint `json:"group_id"`
Alias string `json:"alias"`
}
type PeerBatchDeleteForm struct {
@@ -32,6 +33,7 @@ func (f *PeerForm) ToPeer() *model.Peer {
Uuid: f.Uuid,
Version: f.Version,
GroupId: f.GroupId,
Alias: f.Alias,
}
}
@@ -43,6 +45,7 @@ type PeerQuery struct {
Uuids string `json:"uuids" form:"uuids"`
Ip string `json:"ip" form:"ip"`
Username string `json:"username" form:"username"`
Alias string `json:"alias" form:"alias"`
}
type SimpleDataQuery struct {

View File

@@ -41,6 +41,7 @@ type Oauth struct {
OauthType string `json:"oauth_type"`
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
//RedirectUrl string `json:"redirect_url"`
AutoRegister *bool `json:"auto_register"`
Scopes string `json:"scopes"`
Issuer string `json:"issuer"`

View File

@@ -15,6 +15,7 @@ type Peer struct {
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"`
Alias string `json:"alias" gorm:"default:'';not null;index"`
TimeModel
}

View File

@@ -5,8 +5,8 @@ other = "測試2 {{.P0}}"
[ParamsError]
description = "Params validation failed."
one = "引數錯誤。"
other = "引數錯誤。"
one = "參數驗證失敗。"
other = "參數驗證失敗。"
[OperationFailed]
description = "OperationFailed."
@@ -20,18 +20,18 @@ other = "操作成功。"
[ItemExists]
description = "Item already exists."
one = "資料已存在。"
other = "資料已存在。"
one = "項目已存在。"
other = "項目已存在。"
[ItemNotFound]
description = "Item not found."
one = "資料不存在。"
other = "資料不存在。"
one = "找不到項目。"
other = "找不到項目。"
[NoAccess]
description = "No access."
one = "無許可權。"
other = "無許可權。"
one = "無權限存取。"
other = "無權限存取。"
[NeedLogin]
description = "Need login."
@@ -50,24 +50,23 @@ other = "系統錯誤。"
[ConfigNotFound]
description = "Config not found."
one = "配置不存在。"
other = "配置不存在。"
one = "找不到設定。"
other = "找不到設定。"
#授權過期
[OauthExpired]
description = "Oauth expired."
one = "授權過期,請重新授權。"
other = "授權過期,請重新授權。"
one = "OAuth 已過期,請重。"
other = "OAuth 已過期,請重。"
[OauthFailed]
description = "Oauth failed."
one = "授權失敗。"
other = "授權失敗。"
one = "OAuth 失敗。"
other = "OAuth 失敗。"
[OauthHasBindOtherUser]
description = "Oauth has bind other user."
one = "授權已繫結其他使用者。"
other = "授權已繫結其他使用者。"
one = "OAuth 已綁定其他使用者。"
other = "OAuth 已綁定其他使用者。"
[ParamIsEmpty]
description = "Param is empty."
@@ -76,56 +75,64 @@ other = "{{.P0}} 為空。"
[BindFail]
description = "Bind fail."
one = "繫結失敗。"
other = "繫結失敗。"
one = "綁定失敗。"
other = "綁定失敗。"
[BindSuccess]
description = "Bind success."
one = "繫結成功。"
other = "繫結成功。"
one = "綁定成功。"
other = "綁定成功。"
[OauthHasBeenSuccess]
description = "Oauth has been success."
one = "授權已成功。"
other = "授權已成功。"
one = "OAuth 已成功。"
other = "OAuth 已成功。"
[OauthSuccess]
description = "Oauth success."
one = "授權成功。"
other = "授權成功。"
one = "OAuth 成功。"
other = "OAuth 成功。"
[OauthRegisterSuccess]
description = "Oauth register success."
one = "授權註冊成功。"
other = "授權註冊成功。"
one = "OAuth 註冊成功。"
other = "OAuth 註冊成功。"
[OauthRegisterFailed]
description = "Oauth register failed."
one = "授權註冊失敗。"
other = "授權註冊失敗。"
one = "OAuth 註冊失敗。"
other = "OAuth 註冊失敗。"
[GetOauthTokenError]
description = "Get oauth token error."
one = "獲取授權token失敗。"
other = "獲取授權token失敗。"
one = "取得 OAuth 權杖錯誤。"
other = "取得 OAuth 權杖錯誤。"
[GetOauthUserInfoError]
description = "Get oauth user info error."
one = "獲取授權使用者資訊失敗。"
other = "獲取授權使用者資訊失敗。"
one = "取得 OAuth 使用者資訊錯誤。"
other = "取得 OAuth 使用者資訊錯誤。"
[DecodeOauthUserInfoError]
description = "Decode oauth user info error."
one = "解析授權使用者資訊失敗。"
other = "解析授權使用者資訊失敗。"
one = "解析 OAuth 使用者資訊錯誤。"
other = "解析 OAuth 使用者資訊錯誤。"
[OldPasswordError]
description = "Old password error."
one = "舊密碼錯誤。"
other = "舊密碼錯誤。"
[DefaultGroup]
description = "Default group."
one = "預設組"
other = "預設組"
one = "預設組"
other = "預設組"
[ShareGroup]
description = "Share group."
one = "共享組"
other = "共享組"
one = "共享組"
other = "共享組"
[RegisterClosed]
description = "Register closed."
one = "註冊已關閉。"
@@ -143,20 +150,20 @@ other = "驗證碼錯誤。"
[PwdLoginDisabled]
description = "Password login disabled."
one = "密碼登錄已禁用。"
other = "密碼登錄已禁用。"
one = "密碼登入已停用。"
other = "密碼登入已停用。"
[CannotShareToSelf]
description = "Cannot share to self."
one = "無法享給自己。"
other = "無法享給自己。"
one = "無法享給自己。"
other = "無法享給自己。"
[Banned]
description = "Banned."
one = "禁止使用。"
other = "禁止使用。"
one = "已被禁用。"
other = "已被禁用。"
[RegisterSuccessWaitAdminConfirm]
description = "Register success wait admin confirm."
one = "註冊成功,等待管理員確認。"
other = "註冊成功,等待管理員確認。"
description = "Register success, wait admin confirm."
one = "註冊成功,等待管理員確認。"
other = "註冊成功,等待管理員確認。"

View File

@@ -32,7 +32,7 @@
<title>RustDesk</title>
<script src="/webclient-config/index.js"></script>
<link rel="manifest" href="manifest.json"/>
<script type="module" crossorigin src="js/dist/index.js?v=ddbe54f1"></script>
<script type="module" crossorigin src="js/dist/index.js?v=bd4ac5e9"></script>
<link rel="modulepreload" href="js/dist/vendor.js?v=0b990c6e"/>
<style>
html,
@@ -319,26 +319,5 @@
</script>
<script src="libs/stream/ponyfill.min.js"></script>
<script src="libs/stream/StreamSaver.min.js"></script>
<script src="libs/firebase-app.js?8.10.1"></script>
<script src="libs/firebase-analytics.js?8.10.1"></script>
<script>
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "AIzaSyCgehIZk1aFP0E7wZtYRRqrfvNiNAF39-A",
authDomain: "rustdesk.firebaseapp.com",
databaseURL: "https://rustdesk.firebaseio.com",
projectId: "rustdesk",
storageBucket: "rustdesk.appspot.com",
messagingSenderId: "768133699366",
appId: "1:768133699366:web:d50faf0792cb208d7993e7",
measurementId: "G-9PEH85N6ZQ",
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

188657
resources/web2/main.dart.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -137,6 +137,17 @@ func (ls *LdapService) Authenticate(username, password string) (*model.User, err
return nil, ErrLdapUserDisabled
}
cfg := &Config.Ldap
// Skip allow-group check for admins
isAdmin := ls.isUserAdmin(cfg, ldapUser)
// non-admins only check if allow-group is configured
if !isAdmin && cfg.User.AllowGroup != "" {
if !ls.isUserInGroup(cfg, ldapUser, cfg.User.AllowGroup) {
return nil, errors.New("user not in allowed group")
}
}
err = ls.verifyCredentials(cfg, ldapUser.Dn, password)
if err != nil {
return nil, err
@@ -148,6 +159,46 @@ func (ls *LdapService) Authenticate(username, password string) (*model.User, err
return user, nil
}
// isUserInGroup checks if the user is a member of the specified group. by_sw
func (ls *LdapService) isUserInGroup(cfg *config.Ldap, ldapUser *LdapUser, groupDN string) bool {
// Check "memberOf" directly
if len(ldapUser.MemberOf) > 0 {
for _, group := range ldapUser.MemberOf {
if strings.EqualFold(group, groupDN) {
return true
}
}
}
// For "member" attribute, perform a reverse search on the group
member := "member"
userDN := ldap.EscapeFilter(ldapUser.Dn)
groupDN = ldap.EscapeFilter(groupDN)
groupFilter := fmt.Sprintf("(%s=%s)", member, userDN)
// Create the LDAP search request
groupSearchRequest := ldap.NewSearchRequest(
groupDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0, // Unlimited search results
0, // No time limit
false, // Return both attributes and DN
groupFilter,
[]string{"dn"},
nil,
)
// Perform the group search
groupResult, err := ls.searchResult(cfg, groupSearchRequest)
if err != nil {
return false
}
// If any results are returned, the user is part of the group
return len(groupResult.Entries) > 0
}
// mapToLocalUser checks whether the user exists locally; if not, creates one.
// If the user exists and Ldap.Sync is enabled, it updates local info.
func (ls *LdapService) mapToLocalUser(cfg *config.Ldap, lu *LdapUser) (*model.User, error) {

View File

@@ -6,7 +6,6 @@ import (
"errors"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/gin-gonic/gin"
"github.com/lejianwen/rustdesk-api/v2/model"
"github.com/lejianwen/rustdesk-api/v2/utils"
"golang.org/x/oauth2"
@@ -96,20 +95,16 @@ func (os *OauthService) DeleteOauthCache(key string) {
OauthCache.Delete(key)
}
func (os *OauthService) BeginAuth(c *gin.Context, op string) (error error, state, verifier, nonce, url string) {
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 {
host := c.GetHeader("Origin")
if host == "" {
host = Config.Rustdesk.ApiServer
}
url = host + "/_admin/#/oauth/" + state
url = Config.Rustdesk.ApiServer + "/_admin/#/oauth/" + state
//url = "http://localhost:8888/_admin/#/oauth/" + code
return nil, state, verifier, nonce, url
}
err, oauthInfo, oauthConfig, _ := os.GetOauthConfig(c, op)
err, oauthInfo, oauthConfig, _ := os.GetOauthConfig(op)
if err == nil {
extras := make([]oauth2.AuthCodeOption, 0, 3)
@@ -174,20 +169,16 @@ func (os *OauthService) LinuxdoProvider() *oidc.Provider {
}
// GetOauthConfig retrieves the OAuth2 configuration based on the provider name
func (os *OauthService) GetOauthConfig(c *gin.Context, op string) (err error, oauthInfo *model.Oauth, oauthConfig *oauth2.Config, provider *oidc.Provider) {
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
}
host := c.GetHeader("Origin")
if host == "" {
host = Config.Rustdesk.ApiServer
}
oauthConfig = &oauth2.Config{
ClientID: oauthInfo.ClientId,
ClientSecret: oauthInfo.ClientSecret,
RedirectURL: host + "/api/oidc/callback",
RedirectURL: Config.Rustdesk.ApiServer + "/api/oidc/callback",
}
// Maybe should validate the oauthConfig here
@@ -342,8 +333,8 @@ func (os *OauthService) oidcCallback(oauthConfig *oauth2.Config, provider *oidc.
}
// Callback: Get user information by code and op(Oauth provider)
func (os *OauthService) Callback(c *gin.Context, code, verifier, op, nonce string) (err error, oauthUser *model.OauthUser) {
err, oauthInfo, oauthConfig, provider := os.GetOauthConfig(c, 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

View File

@@ -395,10 +395,10 @@ func (us *UserService) UserThirdInfo(userId uint, op string) *model.UserThird {
return ut
}
// FindLatestUserIdFromLoginLogByUuid 根据uuid查找最后登录的用户id
func (us *UserService) FindLatestUserIdFromLoginLogByUuid(uuid string) uint {
// FindLatestUserIdFromLoginLogByUuid 根据uuid和设备id查找最后登录的用户id
func (us *UserService) FindLatestUserIdFromLoginLogByUuid(uuid string, deviceId string) uint {
llog := &model.LoginLog{}
DB.Where("uuid = ?", uuid).Order("id desc").First(llog)
DB.Where("uuid = ? and device_id = ?", uuid, deviceId).Order("id desc").First(llog)
return llog.UserId
}

View File

@@ -5,7 +5,8 @@ import (
"time"
)
var capdString = base64Captcha.NewDriverString(50, 150, 0, 5, 4, "123456789abcdefghijklmnopqrstuvwxyz", nil, nil, nil)
var capdString = base64Captcha.NewDriverString(50, 150, 0, 5, 4, "123456789abcdefghijklmnopqrstuvwxyz", nil, nil,
[]string{"3Dumb.ttf", "ApothecaryFont.ttf", "Comismsh.ttf", "Flim-Flam.ttf", "RitaSmith.ttf", "wqy-microhei.ttc"})
var capdMath = base64Captcha.NewDriverMath(50, 150, 3, 10, nil, nil, nil)