Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f1380f24a | ||
|
|
ece3328e94 | ||
|
|
fdd26d87be | ||
|
|
2ade0dda42 | ||
|
|
a87ae5cf65 | ||
|
|
fe7b8b53a6 | ||
|
|
b929f3efdb | ||
|
|
f847fc076f | ||
|
|
60d0a701ce | ||
|
|
0dedaf6824 | ||
|
|
ab231b3fed | ||
|
|
e7f28cca36 | ||
|
|
505e8aac4b | ||
|
|
746e2a6052 | ||
|
|
dc03d5d83d | ||
|
|
b770ab178d | ||
|
|
fd7e022e88 |
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@@ -380,7 +380,7 @@ jobs:
|
||||
|
||||
- name: Create and push manifest Docker Hub (:version)
|
||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
uses: Noelware/docker-manifest-action@v0.2.3
|
||||
with:
|
||||
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||
@@ -390,7 +390,7 @@ jobs:
|
||||
|
||||
- name: Create and push manifest GHCR (:version)
|
||||
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
uses: Noelware/docker-manifest-action@v0.2.3
|
||||
with:
|
||||
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||
@@ -401,7 +401,7 @@ jobs:
|
||||
|
||||
- name: Create and push manifest Docker Hub (:latest)
|
||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
uses: Noelware/docker-manifest-action@v0.2.3
|
||||
with:
|
||||
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
|
||||
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64,
|
||||
@@ -411,7 +411,7 @@ jobs:
|
||||
|
||||
- name: Create and push manifest GHCR (:latest)
|
||||
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
uses: Noelware/docker-manifest-action@v0.2.3
|
||||
with:
|
||||
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
|
||||
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64,
|
||||
@@ -422,7 +422,7 @@ jobs:
|
||||
|
||||
- name: Create and push Full S6 manifest Docker Hub (:version)
|
||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
uses: Noelware/docker-manifest-action@v0.2.3
|
||||
with:
|
||||
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:full-s6
|
||||
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-amd64,
|
||||
@@ -433,7 +433,7 @@ jobs:
|
||||
|
||||
- name: Create and push Full S6 manifest GHCR (:latest)
|
||||
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
uses: Noelware/docker-manifest-action@v0.2.3
|
||||
with:
|
||||
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:full-s6
|
||||
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:full-s6-amd64,
|
||||
|
||||
4
.github/workflows/build_test.yml
vendored
4
.github/workflows/build_test.yml
vendored
@@ -317,7 +317,7 @@ jobs:
|
||||
|
||||
- name: Create and push manifest Docker Hub (:version)
|
||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
uses: Noelware/docker-manifest-action@v0.2.3
|
||||
with:
|
||||
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||
@@ -327,7 +327,7 @@ jobs:
|
||||
|
||||
- name: Create and push manifest GHCR (:version)
|
||||
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
uses: Noelware/docker-manifest-action@v0.2.3
|
||||
with:
|
||||
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||
|
||||
@@ -76,7 +76,6 @@ COPY --from=builder-backend /app/release /app/
|
||||
COPY --from=builder-backend /app/conf /app/conf/
|
||||
COPY --from=builder-backend /app/resources /app/resources/
|
||||
COPY --from=builder-backend /app/docs /app/docs/
|
||||
COPY --from=builder-backend /app/http/templates /app/http/templates
|
||||
# Copy frontend build from builder2 stage
|
||||
COPY --from=builder-admin-frontend /frontend/dist/ /app/resources/admin/
|
||||
|
||||
|
||||
@@ -64,21 +64,3 @@ ldap:
|
||||
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
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
en_translations "github.com/go-playground/validator/v10/translations/en"
|
||||
es_translations "github.com/go-playground/validator/v10/translations/es"
|
||||
fr_translations "github.com/go-playground/validator/v10/translations/fr"
|
||||
ko_translations "github.com/go-playground/validator/v10/translations/ko"
|
||||
ru_translations "github.com/go-playground/validator/v10/translations/ru"
|
||||
zh_translations "github.com/go-playground/validator/v10/translations/zh"
|
||||
zh_tw_translations "github.com/go-playground/validator/v10/translations/zh_tw"
|
||||
@@ -51,8 +52,7 @@ func ApiInitValidator() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//validate没有ko的翻译,使用zh的翻译
|
||||
err = zh_translations.RegisterDefaultTranslations(validate, koTrans)
|
||||
err = ko_translations.RegisterDefaultTranslations(validate, koTrans)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
13
go.mod
13
go.mod
@@ -10,7 +10,7 @@ require (
|
||||
github.com/gin-gonic/gin v1.9.0
|
||||
github.com/go-playground/locales v0.14.1
|
||||
github.com/go-playground/universal-translator v0.18.1
|
||||
github.com/go-playground/validator/v10 v10.11.2
|
||||
github.com/go-playground/validator/v10 v10.26.0
|
||||
github.com/go-redis/redis/v8 v8.11.4
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/google/uuid v1.6.0
|
||||
@@ -22,7 +22,7 @@ require (
|
||||
github.com/swaggo/gin-swagger v1.6.0
|
||||
github.com/swaggo/swag v1.16.3
|
||||
golang.org/x/oauth2 v0.23.0
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/text v0.22.0
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/driver/sqlite v1.5.6
|
||||
gorm.io/gorm v1.25.7
|
||||
@@ -38,6 +38,7 @@ require (
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.12.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||
@@ -56,7 +57,7 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
@@ -75,10 +76,10 @@ 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.31.0 // indirect
|
||||
golang.org/x/crypto v0.33.0 // indirect
|
||||
golang.org/x/image v0.13.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||
|
||||
@@ -120,7 +120,7 @@ func (abcr *AddressBookCollectionRule) CheckForm(t *model.AddressBookCollectionR
|
||||
//check to_id
|
||||
if t.Type == model.ShareAddressBookRuleTypePersonal {
|
||||
if t.ToId == t.UserId {
|
||||
return "ParamsError", false
|
||||
return "CannotShareToSelf", false
|
||||
}
|
||||
tou := service.AllService.UserService.InfoById(t.ToId)
|
||||
if tou.Id == 0 {
|
||||
@@ -135,7 +135,7 @@ func (abcr *AddressBookCollectionRule) CheckForm(t *model.AddressBookCollectionR
|
||||
return "ParamsError", false
|
||||
}
|
||||
// 重复检查
|
||||
ex := service.AllService.AddressBookService.RulePersonalInfoByToIdAndCid(t.ToId, t.CollectionId)
|
||||
ex := service.AllService.AddressBookService.RuleInfoByToIdAndCid(t.Type, t.ToId, t.CollectionId)
|
||||
if t.Id == 0 && ex.Id > 0 {
|
||||
return "ItemExists", false
|
||||
}
|
||||
|
||||
@@ -100,21 +100,21 @@ func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.Address
|
||||
//check to_id
|
||||
if t.Type == model.ShareAddressBookRuleTypePersonal {
|
||||
if t.ToId == t.UserId {
|
||||
return "ParamsError", false
|
||||
return "CannotShareToSelf", false
|
||||
}
|
||||
tou := service.AllService.UserService.InfoById(t.ToId)
|
||||
if tou.Id == 0 {
|
||||
return "ItemNotFound", false
|
||||
}
|
||||
//非管理员不能分享给非本组织用户
|
||||
if tou.GroupId != u.GroupId {
|
||||
return "NoAccess", false
|
||||
}
|
||||
//if tou.GroupId != u.GroupId {
|
||||
// return "NoAccess", false
|
||||
//}
|
||||
} else if t.Type == model.ShareAddressBookRuleTypeGroup {
|
||||
//非管理员不能分享给其他组
|
||||
if t.ToId != u.GroupId {
|
||||
return "NoAccess", false
|
||||
}
|
||||
//if t.ToId != u.GroupId {
|
||||
// return "NoAccess", false
|
||||
//}
|
||||
|
||||
tog := service.AllService.GroupService.InfoById(t.ToId)
|
||||
if tog.Id == 0 {
|
||||
@@ -124,7 +124,7 @@ func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.Address
|
||||
return "ParamsError", false
|
||||
}
|
||||
// 重复检查
|
||||
ex := service.AllService.AddressBookService.RulePersonalInfoByToIdAndCid(t.ToId, t.CollectionId)
|
||||
ex := service.AllService.AddressBookService.RuleInfoByToIdAndCid(t.Type, t.ToId, t.CollectionId)
|
||||
if t.Id == 0 && ex.Id > 0 {
|
||||
return "ItemExists", false
|
||||
}
|
||||
|
||||
@@ -108,6 +108,12 @@ func (ct *Peer) List(c *gin.Context) {
|
||||
if query.Uuids != "" {
|
||||
tx.Where("uuid in (?)", query.Uuids)
|
||||
}
|
||||
if query.Username != "" {
|
||||
tx.Where("username like ?", "%"+query.Username+"%")
|
||||
}
|
||||
if query.Ip != "" {
|
||||
tx.Where("last_online_ip like ?", "%"+query.Ip+"%")
|
||||
}
|
||||
})
|
||||
response.Success(c, res)
|
||||
}
|
||||
|
||||
@@ -296,32 +296,12 @@ func (ct *User) MyOauth(c *gin.Context) {
|
||||
|
||||
// groupUsers
|
||||
func (ct *User) GroupUsers(c *gin.Context) {
|
||||
q := &admin.GroupUsersQuery{}
|
||||
if err := c.ShouldBindJSON(q); err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
gid := u.GroupId
|
||||
uid := u.Id
|
||||
if service.AllService.UserService.IsAdmin(u) && q.UserId > 0 {
|
||||
nu := service.AllService.UserService.InfoById(q.UserId)
|
||||
gid = nu.GroupId
|
||||
uid = q.UserId
|
||||
}
|
||||
res := service.AllService.UserService.List(1, 999, func(tx *gorm.DB) {
|
||||
tx.Where("group_id = ?", gid)
|
||||
aG := service.AllService.GroupService.List(1, 999, nil)
|
||||
aU := service.AllService.UserService.List(1, 9999, nil)
|
||||
response.Success(c, gin.H{
|
||||
"groups": aG.Groups,
|
||||
"users": aU.Users,
|
||||
})
|
||||
var data []*adResp.GroupUsersPayload
|
||||
for _, _u := range res.Users {
|
||||
gup := &adResp.GroupUsersPayload{}
|
||||
gup.FromUser(_u)
|
||||
if _u.Id == uid {
|
||||
gup.Status = 0
|
||||
}
|
||||
data = append(data, gup)
|
||||
}
|
||||
response.Success(c, data)
|
||||
}
|
||||
|
||||
// Register
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -56,7 +55,7 @@ func (i *Index) Heartbeat(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
//如果在40s以内则不更新
|
||||
if time.Now().Unix()-peer.LastOnlineTime > 40 {
|
||||
if time.Now().Unix()-peer.LastOnlineTime >= 30 {
|
||||
upp := &model.Peer{RowId: peer.RowId, LastOnlineTime: time.Now().Unix(), LastOnlineIp: c.ClientIP()}
|
||||
service.AllService.PeerService.Update(upp)
|
||||
}
|
||||
@@ -74,13 +73,9 @@ func (i *Index) Heartbeat(c *gin.Context) {
|
||||
// @Router /version [get]
|
||||
func (i *Index) Version(c *gin.Context) {
|
||||
//读取resources/version文件
|
||||
v, err := os.ReadFile("resources/version")
|
||||
if err != nil {
|
||||
response.Fail(c, 101, err.Error())
|
||||
return
|
||||
}
|
||||
v := service.AllService.AppService.GetAppVersion()
|
||||
response.Success(
|
||||
c,
|
||||
string(v),
|
||||
v,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -145,7 +147,8 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
state := c.Query("state")
|
||||
if state == "" {
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateParamMsg(c, "ParamIsEmpty", "state"),
|
||||
"message": "ParamIsEmpty",
|
||||
"sub_message": "state",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -155,7 +158,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
oauthCache := oauthService.GetOauthCache(cacheKey)
|
||||
if oauthCache == nil {
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthExpired"),
|
||||
"message": "OauthExpired",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -169,7 +172,8 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
err, oauthUser := oauthService.Callback(code, verifier, op, nonce)
|
||||
if err != nil {
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthFailed") + response.TranslateMsg(c, err.Error()),
|
||||
"message": "OauthFailed",
|
||||
"sub_message": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -182,7 +186,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
utr := oauthService.UserThirdInfo(op, openid)
|
||||
if utr.UserId > 0 {
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthHasBindOtherUser"),
|
||||
"message": "OauthHasBindOtherUser",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -190,7 +194,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
user = service.AllService.UserService.InfoById(userId)
|
||||
if user == nil {
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "ItemNotFound"),
|
||||
"message": "ItemNotFound",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -198,12 +202,12 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
err := oauthService.BindOauthUser(userId, oauthUser, op)
|
||||
if err != nil {
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "BindFail"),
|
||||
"message": "BindFail",
|
||||
})
|
||||
return
|
||||
}
|
||||
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "BindSuccess"),
|
||||
"message": "BindSuccess",
|
||||
})
|
||||
return
|
||||
|
||||
@@ -211,7 +215,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
//登录
|
||||
if userId != 0 {
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthHasBeenSuccess"),
|
||||
"message": "OauthHasBeenSuccess",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -230,7 +234,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
err, user = service.AllService.UserService.RegisterByOauth(oauthUser, op)
|
||||
if err != nil {
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, err.Error()),
|
||||
"message": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -252,14 +256,50 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "OauthSuccess"),
|
||||
"message": "OauthSuccess",
|
||||
})
|
||||
return
|
||||
} else {
|
||||
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||
"message": response.TranslateMsg(c, "ParamsError"),
|
||||
"message": "ParamsError",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type MessageParams struct {
|
||||
Lang string `json:"lang" form:"lang"`
|
||||
Title string `json:"title" form:"title"`
|
||||
Msg string `json:"msg" form:"msg"`
|
||||
}
|
||||
|
||||
func (o *Oauth) Message(c *gin.Context) {
|
||||
mp := &MessageParams{}
|
||||
if err := c.ShouldBindQuery(mp); err != nil {
|
||||
return
|
||||
}
|
||||
localizer := global.Localizer(mp.Lang)
|
||||
res := ""
|
||||
if mp.Title != "" {
|
||||
title, err := localizer.LocalizeMessage(&i18n.Message{
|
||||
ID: mp.Title,
|
||||
})
|
||||
if err == nil {
|
||||
res = utils.StringConcat(";title='", title, "';")
|
||||
}
|
||||
|
||||
}
|
||||
if mp.Msg != "" {
|
||||
msg, err := localizer.LocalizeMessage(&i18n.Message{
|
||||
ID: mp.Msg,
|
||||
})
|
||||
if err == nil {
|
||||
res = utils.StringConcat(res, "msg = '", msg, "';")
|
||||
}
|
||||
}
|
||||
|
||||
//返回js内容
|
||||
c.Header("Content-Type", "application/javascript")
|
||||
c.String(http.StatusOK, res)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
fpe := f.ToPeer()
|
||||
pe := service.AllService.PeerService.FindById(f.Id)
|
||||
pe := service.AllService.PeerService.FindByUuid(f.Uuid)
|
||||
if pe.RowId == 0 {
|
||||
pe = f.ToPeer()
|
||||
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
|
||||
@@ -56,3 +56,9 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
||||
//直接响应文本
|
||||
c.String(http.StatusOK, "SYSINFO_UPDATED")
|
||||
}
|
||||
|
||||
func (p *Peer) SysInfoVer(c *gin.Context) {
|
||||
//读取resources/version文件
|
||||
v := service.AllService.AppService.GetAppVersion()
|
||||
c.String(http.StatusOK, v)
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ type PeerQuery struct {
|
||||
Id string `json:"id" form:"id"`
|
||||
Hostname string `json:"hostname" form:"hostname"`
|
||||
Uuids string `json:"uuids" form:"uuids"`
|
||||
Ip string `json:"ip" form:"ip"`
|
||||
Username string `json:"username" form:"username"`
|
||||
}
|
||||
|
||||
type SimpleDataQuery struct {
|
||||
|
||||
@@ -40,14 +40,14 @@ type LoginForm struct {
|
||||
|
||||
type UserListQuery struct {
|
||||
Page uint `json:"page" form:"page" validate:"required" label:"页码"`
|
||||
PageSize uint `json:"page_size" form:"page_size" validate:"required" label:"每页数量"`
|
||||
PageSize uint `json:"pageSize" form:"pageSize" validate:"required" label:"每页数量"`
|
||||
Status int `json:"status" form:"status" label:"状态"`
|
||||
Accessible string `json:"accessible" form:"accessible"`
|
||||
}
|
||||
|
||||
type PeerListQuery struct {
|
||||
Page uint `json:"page" form:"page" validate:"required" label:"页码"`
|
||||
PageSize uint `json:"page_size" form:"page_size" validate:"required" label:"每页数量"`
|
||||
PageSize uint `json:"pageSize" form:"pageSize" validate:"required" label:"每页数量"`
|
||||
Status int `json:"status" form:"status" label:"状态"`
|
||||
Accessible string `json:"accessible" form:"accessible"`
|
||||
}
|
||||
|
||||
@@ -22,15 +22,3 @@ type UserOauthItem struct {
|
||||
Op string `json:"op"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
type GroupUsersPayload struct {
|
||||
Id uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func (g *GroupUsersPayload) FromUser(user *model.User) {
|
||||
g.Id = user.Id
|
||||
g.Username = user.Username
|
||||
g.Status = 1
|
||||
}
|
||||
|
||||
@@ -48,11 +48,13 @@ func ApiInit(g *gin.Engine) {
|
||||
//api/oauth/callback
|
||||
frg.GET("/oauth/callback", o.OauthCallback)
|
||||
frg.GET("/oauth/login", o.OauthCallback)
|
||||
frg.GET("/oauth/msg", o.Message)
|
||||
}
|
||||
{
|
||||
pe := &api.Peer{}
|
||||
//提交系统信息
|
||||
frg.POST("/sysinfo", pe.SysInfo)
|
||||
frg.POST("/sysinfo_ver", pe.SysInfoVer)
|
||||
}
|
||||
|
||||
if global.Config.App.WebClient == 1 {
|
||||
|
||||
@@ -137,4 +137,9 @@ other = "Captcha error."
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "Password login disabled."
|
||||
other = "Password login disabled."
|
||||
other = "Password login disabled."
|
||||
|
||||
[CannotShareToSelf]
|
||||
description = "Cannot share to self."
|
||||
one = "Cannot share to self."
|
||||
other = "Cannot share to self."
|
||||
@@ -146,4 +146,9 @@ other = "Error de captcha."
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "Inicio de sesión con contraseña deshabilitado."
|
||||
other = "Inicio de sesión con contraseña deshabilitado."
|
||||
other = "Inicio de sesión con contraseña deshabilitado."
|
||||
|
||||
[CannotShareToSelf]
|
||||
description = "Cannot share to self."
|
||||
one = "No se puede compartir con uno mismo."
|
||||
other = "No se puede compartir con uno mismo."
|
||||
@@ -146,4 +146,9 @@ other = "Erreur de captcha."
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "Connexion par mot de passe désactivée."
|
||||
other = "Connexion par mot de passe désactivée."
|
||||
other = "Connexion par mot de passe désactivée."
|
||||
|
||||
[CannotShareToSelf]
|
||||
description = "Cannot share to self."
|
||||
one = "Impossible de partager avec soi-même."
|
||||
other = "Impossible de partager avec soi-même."
|
||||
@@ -141,3 +141,8 @@ other = "Captcha 오류."
|
||||
description = "Password login disabled."
|
||||
one = "비밀번호 로그인이 비활성화되었습니다."
|
||||
other = "비밀번호 로그인이 비활성화되었습니다."
|
||||
|
||||
[CannotShareToSelf]
|
||||
description = "Cannot share to self."
|
||||
one = "자기 자신에게 공유할 수 없습니다."
|
||||
other = "자기 자신에게 공유할 수 없습니다."
|
||||
@@ -146,4 +146,9 @@ other = "Ошибка капчи."
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "Вход по паролю отключен."
|
||||
other = "Вход по паролю отключен."
|
||||
other = "Вход по паролю отключен."
|
||||
|
||||
[CannotShareToSelf]
|
||||
description = "Cannot share to self."
|
||||
one = "Нельзя поделиться с собой."
|
||||
other = "Нельзя поделиться с собой."
|
||||
@@ -139,4 +139,9 @@ other = "验证码错误。"
|
||||
[PwdLoginDisabled]
|
||||
description = "Password login disabled."
|
||||
one = "密码登录已禁用。"
|
||||
other = "密码登录已禁用。"
|
||||
other = "密码登录已禁用。"
|
||||
|
||||
[CannotShareToSelf]
|
||||
description = "Cannot share to self."
|
||||
one = "不能共享给自己。"
|
||||
other = "不能共享给自己。"
|
||||
@@ -140,3 +140,8 @@ other = "驗證碼錯誤。"
|
||||
description = "Password login disabled."
|
||||
one = "密碼登錄已禁用。"
|
||||
other = "密碼登錄已禁用。"
|
||||
|
||||
[CannotShareToSelf]
|
||||
description = "Cannot share to self."
|
||||
one = "無法共享給自己。"
|
||||
other = "無法共享給自己。"
|
||||
0
resources/public/upload/.gitkeep
Normal file
0
resources/public/upload/.gitkeep
Normal file
@@ -1,9 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>授权失败 - RustDesk API</title>
|
||||
<title>OauthFailed - RustDesk API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
|
||||
@@ -57,17 +57,25 @@
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/6.0.0/css/all.min.css">
|
||||
<script>
|
||||
var lang = navigator.language || navigator.userLanguage || 'zh-CN';
|
||||
var title = 'OauthFailed'
|
||||
var msg = '{{.message}}'
|
||||
var btn = 'Close'
|
||||
document.writeln('<script src="/api/oauth/msg?lang=' + lang + '&msg=' + msg + '&title=OauthFailed"><\/script>');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="success-container">
|
||||
<i class="fas fa-triangle-exclamation checkmark"></i>
|
||||
<h1>授权失败!</h1>
|
||||
<p>{{.message}}</p>
|
||||
<a href="javascript:window.close()" class="return-link">关闭页面</a>
|
||||
<i class="fas fa-triangle-exclamation checkmark"></i>
|
||||
<h1 id="h1"></h1>
|
||||
<p id="msg"></p>
|
||||
<a href="javascript:window.close()" class="return-link" id="btn">Close</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
document.title = title + ' - RustDesk API';
|
||||
document.getElementById('h1').innerText = title;
|
||||
document.getElementById('msg').innerText = msg;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>授权成功 - RustDesk API</title>
|
||||
<title>OauthSuccess - RustDesk API</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
|
||||
@@ -56,18 +56,27 @@
|
||||
background-color: #45a049;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var lang = navigator.language || navigator.userLanguage || 'zh-CN';
|
||||
var title = 'OauthSuccess'
|
||||
var msg = '{{.message}}'
|
||||
var btn = 'Close'
|
||||
document.writeln('<script src="/api/oauth/msg?lang=' + lang + '&msg=' + msg + '&title=OauthSuccess"><\/script>');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="success-container">
|
||||
<i class="fas fa-check-circle checkmark"></i>
|
||||
<h1>授权成功!</h1>
|
||||
<p>您已成功授权访问您的账户。</p>
|
||||
<p>现在可以关闭本页面或返回应用继续操作。</p>
|
||||
<a href="javascript:window.close()" class="return-link">关闭页面</a>
|
||||
<h1 id="h1"></h1>
|
||||
<!-- <p>您已成功授权访问您的账户。</p>-->
|
||||
<!-- <p>现在可以关闭本页面或返回应用继续操作。</p>-->
|
||||
<a href="javascript:window.close()" class="return-link">Close</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
document.title = title + ' - RustDesk API';
|
||||
document.getElementById('h1').innerText = title;
|
||||
document.getElementById('msg').innerText = msg;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
16
resources/web2/assets/FontManifest.json
vendored
16
resources/web2/assets/FontManifest.json
vendored
@@ -38,5 +38,21 @@
|
||||
"asset": "assets/address_book.ttf"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "DeviceGroup",
|
||||
"fonts": [
|
||||
{
|
||||
"asset": "assets/device_group.ttf"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "More",
|
||||
"fonts": [
|
||||
{
|
||||
"asset": "assets/more.ttf"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
BIN
resources/web2/assets/assets/device_group.ttf
vendored
Normal file
BIN
resources/web2/assets/assets/device_group.ttf
vendored
Normal file
Binary file not shown.
BIN
resources/web2/assets/assets/more.ttf
vendored
Normal file
BIN
resources/web2/assets/assets/more.ttf
vendored
Normal file
Binary file not shown.
Binary file not shown.
513
resources/web2/index.html
vendored
513
resources/web2/index.html
vendored
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<head>
|
||||
<!--
|
||||
If you are serving your web app in a path other than the root, change the
|
||||
href value below to reflect the base path you are serving from.
|
||||
@@ -16,195 +16,196 @@
|
||||
-->
|
||||
<base href="/webclient2/" />
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible" />
|
||||
<meta name="description" content="Remote Desktop." />
|
||||
<meta charset="UTF-8"/>
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
|
||||
<meta name="description" content="Remote Desktop."/>
|
||||
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<meta name="apple-mobile-web-app-title" content="RustDesk" />
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png?v=1a7ad736" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
|
||||
<meta name="apple-mobile-web-app-title" content="RustDesk"/>
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png?v=1a7ad736"/>
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg?v=8fcccd9a" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg?v=8fcccd9a"/>
|
||||
|
||||
<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=cabfd933"></script>
|
||||
<link rel="modulepreload" href="js/dist/vendor.js?v=0b990c6e" />
|
||||
<link rel="manifest" href="manifest.json"/>
|
||||
<script type="module" crossorigin src="js/dist/index.js?v=ddbe54f1"></script>
|
||||
<link rel="modulepreload" href="js/dist/vendor.js?v=0b990c6e"/>
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#root {
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% auto;
|
||||
}
|
||||
|
||||
.loading-title {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.loading-sub-title {
|
||||
margin-top: 20px;
|
||||
font-size: 1rem;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.page-loading-warp {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 26px;
|
||||
}
|
||||
.ant-spin {
|
||||
position: absolute;
|
||||
display: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
color: #1890ff;
|
||||
font-size: 14px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
list-style: none;
|
||||
opacity: 0;
|
||||
-webkit-transition: -webkit-transform 0.3s
|
||||
cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
|
||||
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
-webkit-font-feature-settings: "tnum";
|
||||
font-feature-settings: "tnum";
|
||||
}
|
||||
|
||||
.ant-spin-spinning {
|
||||
position: static;
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ant-spin-dot {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
background-color: #1890ff;
|
||||
border-radius: 100%;
|
||||
-webkit-transform: scale(0.75);
|
||||
-ms-transform: scale(0.75);
|
||||
transform: scale(0.75);
|
||||
-webkit-transform-origin: 50% 50%;
|
||||
-ms-transform-origin: 50% 50%;
|
||||
transform-origin: 50% 50%;
|
||||
opacity: 0.3;
|
||||
-webkit-animation: antspinmove 1s infinite linear alternate;
|
||||
animation: antSpinMove 1s infinite linear alternate;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(1) {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(2) {
|
||||
top: 0;
|
||||
right: 0;
|
||||
-webkit-animation-delay: 0.4s;
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(3) {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
-webkit-animation-delay: 0.8s;
|
||||
animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(4) {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
-webkit-animation-delay: 1.2s;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
.ant-spin-dot-spin {
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
-webkit-animation: antrotate 1.2s infinite linear;
|
||||
animation: antRotate 1.2s infinite linear;
|
||||
}
|
||||
|
||||
.ant-spin-lg .ant-spin-dot {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.ant-spin-lg .ant-spin-dot i {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
||||
.ant-spin-blur {
|
||||
background: #fff;
|
||||
opacity: 0.5;
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 1;
|
||||
#root {
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% auto;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 1;
|
||||
.loading-title {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antRotate {
|
||||
to {
|
||||
-webkit-transform: rotate(405deg);
|
||||
transform: rotate(405deg);
|
||||
.loading-sub-title {
|
||||
margin-top: 20px;
|
||||
font-size: 1rem;
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antRotate {
|
||||
to {
|
||||
-webkit-transform: rotate(405deg);
|
||||
transform: rotate(405deg);
|
||||
.page-loading-warp {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 26px;
|
||||
}
|
||||
|
||||
.ant-spin {
|
||||
position: absolute;
|
||||
display: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
color: #1890ff;
|
||||
font-size: 14px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
list-style: none;
|
||||
opacity: 0;
|
||||
-webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
|
||||
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
-webkit-font-feature-settings: "tnum";
|
||||
font-feature-settings: "tnum";
|
||||
}
|
||||
|
||||
.ant-spin-spinning {
|
||||
position: static;
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ant-spin-dot {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
background-color: #1890ff;
|
||||
border-radius: 100%;
|
||||
-webkit-transform: scale(0.75);
|
||||
-ms-transform: scale(0.75);
|
||||
transform: scale(0.75);
|
||||
-webkit-transform-origin: 50% 50%;
|
||||
-ms-transform-origin: 50% 50%;
|
||||
transform-origin: 50% 50%;
|
||||
opacity: 0.3;
|
||||
-webkit-animation: antspinmove 1s infinite linear alternate;
|
||||
animation: antSpinMove 1s infinite linear alternate;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(1) {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(2) {
|
||||
top: 0;
|
||||
right: 0;
|
||||
-webkit-animation-delay: 0.4s;
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(3) {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
-webkit-animation-delay: 0.8s;
|
||||
animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(4) {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
-webkit-animation-delay: 1.2s;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
.ant-spin-dot-spin {
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
-webkit-animation: antrotate 1.2s infinite linear;
|
||||
animation: antRotate 1.2s infinite linear;
|
||||
}
|
||||
|
||||
.ant-spin-lg .ant-spin-dot {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.ant-spin-lg .ant-spin-dot i {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
||||
.ant-spin-blur {
|
||||
background: #fff;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antRotate {
|
||||
to {
|
||||
-webkit-transform: rotate(405deg);
|
||||
transform: rotate(405deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antRotate {
|
||||
to {
|
||||
-webkit-transform: rotate(405deg);
|
||||
transform: rotate(405deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root">
|
||||
<div
|
||||
id="div-background"
|
||||
style="
|
||||
<body>
|
||||
<div id="root">
|
||||
<div
|
||||
id="div-background"
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -212,117 +213,119 @@
|
||||
height: 100%;
|
||||
min-height: 420px;
|
||||
"
|
||||
>
|
||||
<img src="./favicon.svg?v=8fcccd9a" alt="logo" width="256" />
|
||||
>
|
||||
<img src="./favicon.svg?v=8fcccd9a" alt="logo" width="256"/>
|
||||
<div class="page-loading-warp">
|
||||
<div class="ant-spin ant-spin-lg ant-spin-spinning">
|
||||
<div class="ant-spin ant-spin-lg ant-spin-spinning">
|
||||
<span class="ant-spin-dot ant-spin-dot-spin">
|
||||
<i class="ant-spin-dot-item"></i>
|
||||
<i class="ant-spin-dot-item"></i>
|
||||
<i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="display: flex; align-items: center; justify-content: center"
|
||||
style="display: flex; align-items: center; justify-content: center"
|
||||
>
|
||||
<img src="./favicon.svg?v=8fcccd9a" width="32" style="margin-right: 8px" />
|
||||
<span id="span-text">RustDesk Web Client V2 Preview</span>
|
||||
<img src="./favicon.svg?v=8fcccd9a" width="32" style="margin-right: 8px"/>
|
||||
<span id="span-text">RustDesk Web Client V2 Preview</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||
application. For more information, see:
|
||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||
<script>
|
||||
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
||||
</div>
|
||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||
application. For more information, see:
|
||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||
<script>
|
||||
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
||||
.matches
|
||||
? "dark"
|
||||
: "light";
|
||||
const myTheme = localStorage.getItem("wc-option:local:theme");
|
||||
const them = myTheme || systemTheme;
|
||||
const myTheme = localStorage.getItem("wc-option:local:theme");
|
||||
const them = myTheme || systemTheme;
|
||||
|
||||
const divBackground = document.querySelector("#div-background");
|
||||
if (divBackground) {
|
||||
const divBackground = document.querySelector("#div-background");
|
||||
if (divBackground) {
|
||||
divBackground.style.backgroundColor = them === "dark" ? "#000" : "#fff";
|
||||
}
|
||||
const spanConsole = document.querySelector("#span-text");
|
||||
if (spanConsole) {
|
||||
}
|
||||
const spanConsole = document.querySelector("#span-text");
|
||||
if (spanConsole) {
|
||||
spanConsole.style.color = them === "dark" ? "#fff" : "#000";
|
||||
}
|
||||
}
|
||||
|
||||
const serviceWorkerVersion = "3267265270";
|
||||
var scriptLoaded = false;
|
||||
function loadMainDartJs() {
|
||||
const serviceWorkerVersion = "461457302";
|
||||
var scriptLoaded = false;
|
||||
|
||||
function loadMainDartJs() {
|
||||
if (scriptLoaded) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
scriptLoaded = true;
|
||||
var scriptTag = document.createElement("script");
|
||||
scriptTag.src = "main.dart.js?v=060a626e";
|
||||
scriptTag.src = "main.dart.js?v=6d16cb80";
|
||||
scriptTag.type = "application/javascript";
|
||||
document.body.append(scriptTag);
|
||||
}
|
||||
}
|
||||
|
||||
if ("serviceWorker" in navigator) {
|
||||
if ("serviceWorker" in navigator) {
|
||||
// Service workers are supported. Use them.
|
||||
window.addEventListener("load", function () {
|
||||
// Wait for registration to finish before dropping the <script> tag.
|
||||
// Otherwise, the browser will load the script multiple times,
|
||||
// potentially different versions.
|
||||
var serviceWorkerUrl =
|
||||
"flutter_service_worker.js?v=" + serviceWorkerVersion;
|
||||
navigator.serviceWorker.register(serviceWorkerUrl).then((reg) => {
|
||||
function waitForActivation(serviceWorker) {
|
||||
serviceWorker.addEventListener("statechange", () => {
|
||||
if (serviceWorker.state == "activated") {
|
||||
console.log("Installed new service worker.");
|
||||
loadMainDartJs();
|
||||
// Wait for registration to finish before dropping the <script> tag.
|
||||
// Otherwise, the browser will load the script multiple times,
|
||||
// potentially different versions.
|
||||
var serviceWorkerUrl =
|
||||
"flutter_service_worker.js?v=" + serviceWorkerVersion;
|
||||
navigator.serviceWorker.register(serviceWorkerUrl).then((reg) => {
|
||||
function waitForActivation(serviceWorker) {
|
||||
serviceWorker.addEventListener("statechange", () => {
|
||||
if (serviceWorker.state == "activated") {
|
||||
console.log("Installed new service worker.");
|
||||
loadMainDartJs();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!reg.active && (reg.installing || reg.waiting)) {
|
||||
// No active web worker and we have installed or are installing
|
||||
// one for the first time. Simply wait for it to activate.
|
||||
waitForActivation(reg.installing || reg.waiting);
|
||||
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
|
||||
// When the app updates the serviceWorkerVersion changes, so we
|
||||
// need to ask the service worker to update.
|
||||
console.log("New service worker available.");
|
||||
reg.update();
|
||||
waitForActivation(reg.installing);
|
||||
} else {
|
||||
// Existing service worker is still good.
|
||||
console.log("Loading app from service worker.");
|
||||
loadMainDartJs();
|
||||
}
|
||||
});
|
||||
|
||||
// If service worker doesn't succeed in a reasonable amount of time,
|
||||
// fallback to plaint <script> tag.
|
||||
setTimeout(() => {
|
||||
if (!scriptLoaded) {
|
||||
console.warn(
|
||||
"Failed to load app from service worker. Falling back to plain <script> tag."
|
||||
);
|
||||
loadMainDartJs();
|
||||
}
|
||||
}, 4000);
|
||||
if (!reg.active && (reg.installing || reg.waiting)) {
|
||||
// No active web worker and we have installed or are installing
|
||||
// one for the first time. Simply wait for it to activate.
|
||||
waitForActivation(reg.installing || reg.waiting);
|
||||
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
|
||||
// When the app updates the serviceWorkerVersion changes, so we
|
||||
// need to ask the service worker to update.
|
||||
console.log("New service worker available.");
|
||||
reg.update();
|
||||
waitForActivation(reg.installing);
|
||||
} else {
|
||||
// Existing service worker is still good.
|
||||
console.log("Loading app from service worker.");
|
||||
loadMainDartJs();
|
||||
}
|
||||
});
|
||||
|
||||
// If service worker doesn't succeed in a reasonable amount of time,
|
||||
// fallback to plaint <script> tag.
|
||||
setTimeout(() => {
|
||||
if (!scriptLoaded) {
|
||||
console.warn(
|
||||
"Failed to load app from service worker. Falling back to plain <script> tag."
|
||||
);
|
||||
loadMainDartJs();
|
||||
}
|
||||
}, 4000);
|
||||
});
|
||||
} else {
|
||||
} else {
|
||||
// Service workers not supported. Just drop the <script> tag.
|
||||
loadMainDartJs();
|
||||
}
|
||||
</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>
|
||||
<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 = {
|
||||
<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",
|
||||
@@ -331,11 +334,11 @@
|
||||
messagingSenderId: "768133699366",
|
||||
appId: "1:768133699366:web:d50faf0792cb208d7993e7",
|
||||
measurementId: "G-9PEH85N6ZQ",
|
||||
};
|
||||
};
|
||||
|
||||
// Initialize Firebase
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
firebase.analytics();
|
||||
</script>
|
||||
</body>
|
||||
// Initialize Firebase
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
firebase.analytics();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
6565
resources/web2/js/dist/index.js
vendored
6565
resources/web2/js/dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
7419
resources/web2/js/dist/lang.js
vendored
7419
resources/web2/js/dist/lang.js
vendored
File diff suppressed because it is too large
Load Diff
8
resources/web2/js/dist/ljw.js
vendored
8
resources/web2/js/dist/ljw.js
vendored
@@ -1,5 +1,11 @@
|
||||
window._gwen = {}
|
||||
window._gwen.kv = {}
|
||||
|
||||
//fix 语言
|
||||
if(!localStorage.getItem('wc-option:local:lang') && navigator.language){
|
||||
localStorage.setItem('wc-option:local:lang', navigator.language.toLowerCase())
|
||||
}
|
||||
|
||||
const storage_prefix = 'wc-'
|
||||
const apiserver = localStorage.getItem('wc-api-server')
|
||||
|
||||
@@ -46,7 +52,7 @@ if (share_token) {
|
||||
password: peer.tmppwd,
|
||||
}*/
|
||||
//修改location
|
||||
window.location.href = `/webclient2/#/${peer.info.id}?password=${peer.tmppwd}`
|
||||
window.location.href = `/webclient2/#/${peer.info.id}?password=${encodeURIComponent(peer.tmppwd)}`
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
163526
resources/web2/main.dart.js
vendored
163526
resources/web2/main.dart.js
vendored
File diff suppressed because one or more lines are too long
@@ -293,8 +293,11 @@ func (s *AddressBookService) RuleInfoById(u uint) *model.AddressBookCollectionRu
|
||||
return p
|
||||
}
|
||||
func (s *AddressBookService) RulePersonalInfoByToIdAndCid(toid, cid uint) *model.AddressBookCollectionRule {
|
||||
return s.RuleInfoByToIdAndCid(model.ShareAddressBookRuleTypePersonal, toid, cid)
|
||||
}
|
||||
func (s *AddressBookService) RuleInfoByToIdAndCid(t int, toid, cid uint) *model.AddressBookCollectionRule {
|
||||
p := &model.AddressBookCollectionRule{}
|
||||
DB.Where("type = ? and to_id = ? and collection_id = ?", model.ShareAddressBookRuleTypePersonal, toid, cid).First(p)
|
||||
DB.Where("type = ? and to_id = ? and collection_id = ?", t, toid, cid).First(p)
|
||||
return p
|
||||
}
|
||||
func (s *AddressBookService) CreateRule(t *model.AddressBookCollectionRule) error {
|
||||
|
||||
28
service/app.go
Normal file
28
service/app.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type AppService struct {
|
||||
}
|
||||
|
||||
var version = ""
|
||||
|
||||
var once = &sync.Once{}
|
||||
|
||||
func (a *AppService) GetAppVersion() string {
|
||||
if version != "" {
|
||||
return version
|
||||
}
|
||||
once.Do(func() {
|
||||
v, err := os.ReadFile("resources/version")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
version = string(v)
|
||||
|
||||
})
|
||||
return version
|
||||
}
|
||||
33
service/app_test.go
Normal file
33
service/app_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestGetAppVersion
|
||||
func TestGetAppVersion(t *testing.T) {
|
||||
s := &AppService{}
|
||||
v := s.GetAppVersion()
|
||||
// 打印结果
|
||||
t.Logf("App Version: %s", v)
|
||||
}
|
||||
|
||||
func TestMultipleGetAppVersion(t *testing.T) {
|
||||
s := &AppService{}
|
||||
//并发测试
|
||||
// 使用 WaitGroup 等待所有 goroutine 完成
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(10) // 启动 10 个 goroutine
|
||||
// 启动 10 个 goroutine
|
||||
for i := 0; i < 10; i++ {
|
||||
go func() {
|
||||
defer wg.Done() // 完成后减少计数
|
||||
v := s.GetAppVersion()
|
||||
// 打印结果
|
||||
t.Logf("App Version: %s", v)
|
||||
}()
|
||||
}
|
||||
// 等待所有 goroutine 完成
|
||||
wg.Wait()
|
||||
}
|
||||
@@ -30,6 +30,7 @@ var (
|
||||
ErrLdapBindFailed = errors.New("LdapBindFailed")
|
||||
ErrLdapToLocalUserFailed = errors.New("LdapToLocalUserFailed")
|
||||
ErrLdapCreateUserFailed = errors.New("LdapCreateUserFailed")
|
||||
ErrLdapPasswordNotMatch = errors.New("PasswordNotMatch")
|
||||
)
|
||||
|
||||
// LdapService is responsible for LDAP authentication and user synchronization.
|
||||
@@ -119,7 +120,7 @@ func (ls *LdapService) connectAndBindAdmin(cfg *config.Ldap) (*ldap.Conn, error)
|
||||
func (ls *LdapService) verifyCredentials(cfg *config.Ldap, username, password string) error {
|
||||
ldapConn, err := ls.connectAndBind(cfg, username, password)
|
||||
if err != nil {
|
||||
return err
|
||||
return ErrLdapPasswordNotMatch
|
||||
}
|
||||
defer ldapConn.Close()
|
||||
return nil
|
||||
@@ -136,6 +137,10 @@ func (ls *LdapService) Authenticate(username, password string) (*model.User, err
|
||||
return nil, ErrLdapUserDisabled
|
||||
}
|
||||
cfg := &Config.Ldap
|
||||
err = ls.verifyCredentials(cfg, ldapUser.Dn, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err := ls.mapToLocalUser(cfg, ldapUser)
|
||||
if err != nil {
|
||||
return nil, errors.Join(ErrLdapToLocalUserFailed, err)
|
||||
|
||||
@@ -126,7 +126,14 @@ func (ps *PeerService) GetUuidListByIDs(ids []uint) ([]string, error) {
|
||||
err := DB.Model(&model.Peer{}).
|
||||
Where("row_id in (?)", ids).
|
||||
Pluck("uuid", &uuids).Error
|
||||
return uuids, err
|
||||
//过滤uuids中的空字符串
|
||||
var newUuids []string
|
||||
for _, uuid := range uuids {
|
||||
if uuid != "" {
|
||||
newUuids = append(newUuids, uuid)
|
||||
}
|
||||
}
|
||||
return newUuids, err
|
||||
}
|
||||
|
||||
// BatchDelete 批量删除, 同时也应该删除token
|
||||
|
||||
@@ -23,6 +23,7 @@ type Service struct {
|
||||
*ShareRecordService
|
||||
*ServerCmdService
|
||||
*LdapService
|
||||
*AppService
|
||||
}
|
||||
|
||||
type Dependencies struct {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Md5(str string) string {
|
||||
@@ -100,3 +101,11 @@ func InArray(k string, arr []string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func StringConcat(strs ...string) string {
|
||||
var builder strings.Builder
|
||||
for _, str := range strs {
|
||||
builder.WriteString(str)
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user