Skip to content
This repository has been archived by the owner on Feb 28, 2023. It is now read-only.

Commit

Permalink
feat(multi-site): Isolate admin users among sites
Browse files Browse the repository at this point in the history
Signed-off-by: qwqcode <[email protected]>
  • Loading branch information
qwqcode committed Apr 29, 2022
1 parent fcd44bc commit 02b3173
Show file tree
Hide file tree
Showing 21 changed files with 136 additions and 137 deletions.
22 changes: 22 additions & 0 deletions http/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/ArtalkJS/ArtalkGo/config"
"github.com/ArtalkJS/ArtalkGo/lib"
"github.com/ArtalkJS/ArtalkGo/model"
"github.com/golang-jwt/jwt"
"github.com/labstack/echo/v4"
Expand Down Expand Up @@ -103,3 +104,24 @@ func GetUserByReq(c echo.Context) model.User {

return user
}

func GetIsSuperAdmin(c echo.Context) bool {
user := GetUserByReq(c)
return user.IsAdmin && user.SiteNames == ""
}

func IsAdminHasSiteAccess(c echo.Context, siteName string) bool {
user := GetUserByReq(c)
cookedUser := user.ToCooked()

if !user.IsAdmin {
return false
}

if !GetIsSuperAdmin(c) && !lib.ContainsStr(cookedUser.SiteNames, siteName) {
// 如果账户分配了站点,并且待操作的站点并非处于分配的站点列表
return false
}

return true
}
23 changes: 23 additions & 0 deletions http/admin_cache_flush.go → http/admin_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ import (
"github.com/labstack/echo/v4"
)

type ParamsAdminCacheWarm struct {
}

// 缓存预热
func (a *action) AdminCacheWarm(c echo.Context) error {
var p ParamsAdminCacheWarm
if isOK, resp := ParamsDecode(c, &p); !isOK {
return resp
}

if !GetIsSuperAdmin(c) {
return RespError(c, "无权访问")
}

go func() {
model.CacheWarmUp()
}()

return RespData(c, Map{
"msg": "缓存预热任务已在后台开始执行,稍等片刻完成...",
})
}

type ParamsAdminCacheFlush struct {
FlushAll bool `mapstructure:"flush_all"`
}
Expand Down
29 changes: 0 additions & 29 deletions http/admin_cache_warm.go

This file was deleted.

23 changes: 7 additions & 16 deletions http/admin_comment_del.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package http
import (
"github.com/ArtalkJS/ArtalkGo/model"
"github.com/labstack/echo/v4"
"gorm.io/gorm"
)

type ParamsCommentDel struct {
Expand All @@ -21,36 +20,28 @@ func (a *action) AdminCommentDel(c echo.Context) error {
}

// find site
if isOK, resp := AdminSiteInControl(c, &p.SiteName, &p.SiteID, &p.SiteAll); !isOK {
if isOK, resp := CheckSite(c, &p.SiteName, &p.SiteID, &p.SiteAll); !isOK {
return resp
}

// find comment
comment := model.FindComment(p.ID)
if comment.IsEmpty() {
return RespError(c, "comment not found")
}

if !IsAdminHasSiteManageAccess(c, comment.SiteName) {
if !IsAdminHasSiteAccess(c, comment.SiteName) {
return RespError(c, "无权操作")
}

// 删除主评论
if err := model.DelComment(comment.ID); err != nil {
return RespError(c, "comment delete error")
return RespError(c, "评论删除失败")
}

commentCooked := comment.ToCooked()

// 删除子评论
hasErr := false
children := commentCooked.FetchChildren(func(db *gorm.DB) *gorm.DB { return db })
for _, c := range children {
err := model.DelComment(c.ID)
if err != nil {
hasErr = true
}
}
if hasErr {
return RespError(c, "children comment delete error")
if err := model.DelCommentChildren(comment); err != nil {
return RespError(c, "子评论删除失败")
}

return RespSuccess(c)
Expand Down
6 changes: 4 additions & 2 deletions http/admin_comment_edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type ParamsCommentEdit struct {
ID uint `mapstructure:"id" param:"required"`
SiteName string `mapstructure:"site_name"`
SiteID uint
SiteAll bool

// 可修改
Content string `mapstructure:"content"`
Expand All @@ -34,16 +35,17 @@ func (a *action) AdminCommentEdit(c echo.Context) error {
}

// find site
if isOK, resp := AdminSiteInControl(c, &p.SiteName, &p.SiteID, nil); !isOK {
if isOK, resp := CheckSite(c, &p.SiteName, &p.SiteID, &p.SiteAll); !isOK {
return resp
}

// find comment
comment := model.FindComment(p.ID)
if comment.IsEmpty() {
return RespError(c, "comment not found")
}

if !IsAdminHasSiteManageAccess(c, comment.SiteName) {
if !IsAdminHasSiteAccess(c, comment.SiteName) {
return RespError(c, "无权操作")
}

Expand Down
6 changes: 5 additions & 1 deletion http/admin_page_del.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (a *action) AdminPageDel(c echo.Context) error {
}

// find site
if isOK, resp := AdminSiteInControl(c, &p.SiteName, &p.SiteID, nil); !isOK {
if isOK, resp := CheckSite(c, &p.SiteName, &p.SiteID, nil); !isOK {
return resp
}

Expand All @@ -27,6 +27,10 @@ func (a *action) AdminPageDel(c echo.Context) error {
return RespError(c, "page not found")
}

if !IsAdminHasSiteAccess(c, page.SiteName) {
return RespError(c, "无权操作")
}

err := model.DelPage(&page)
if err != nil {
return RespError(c, "Page 删除失败")
Expand Down
17 changes: 7 additions & 10 deletions http/admin_page_edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,20 @@ func (a *action) AdminPageEdit(c echo.Context) error {
}

// find site
if isOK, resp := AdminSiteInControl(c, &p.SiteName, &p.SiteID, nil); !isOK {
if isOK, resp := CheckSite(c, &p.SiteName, &p.SiteID, nil); !isOK {
return resp
}

// check create page
var page model.Page
if p.ID == 0 {
// create new page
page = model.FindCreatePage(p.Key, p.Title, p.SiteName)
} else {
page = model.FindPageByID(p.ID)
}

// find page
var page = model.FindPageByID(p.ID)
if page.IsEmpty() {
return RespError(c, "page not found")
}

if !IsAdminHasSiteAccess(c, page.SiteName) {
return RespError(c, "无权操作")
}

// 重命名合法性检测
modifyKey := p.Key != page.Key
if modifyKey && !model.FindPage(p.Key, p.SiteName).IsEmpty() {
Expand Down
4 changes: 4 additions & 0 deletions http/admin_page_fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ func (a *action) AdminPageFetch(c echo.Context) error {
return RespError(c, "page not found")
}

if !IsAdminHasSiteAccess(c, page.SiteName) {
return RespError(c, "无权操作")
}

if err := page.FetchURL(); err != nil {
return RespError(c, "page fetch error: "+err.Error())
}
Expand Down
6 changes: 5 additions & 1 deletion http/admin_page_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ func (a *action) AdminPageGet(c echo.Context) error {
}

// find site
if isOK, resp := AdminSiteInControl(c, &p.SiteName, &p.SiteID, &p.SiteAll); !isOK {
if isOK, resp := CheckSite(c, &p.SiteName, &p.SiteID, &p.SiteAll); !isOK {
return resp
}

if !IsAdminHasSiteAccess(c, p.SiteName) {
return RespError(c, "无权操作")
}

// 准备 query
query := a.db.Model(&model.Page{}).Order("created_at DESC")
if !p.SiteAll { // 不是查的所有站点
Expand Down
9 changes: 4 additions & 5 deletions http/admin_site_del.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,15 @@ func (a *action) AdminSiteDel(c echo.Context) error {
return resp
}

if !GetIsSuperAdmin(c) {
return RespError(c, "禁止删除站点")
}

site := model.FindSiteByID(p.ID)
if site.IsEmpty() {
return RespError(c, "site 不存在")
}

// 站点操作权限检查
if hasAccess := IsAdminHasSiteManageAccess(c, site.Name); !hasAccess {
return RespError(c, "无权操作该站点")
}

err := model.DelSite(&site, !p.DelContent)
if err != nil {
return RespError(c, "site 删除失败")
Expand Down
4 changes: 2 additions & 2 deletions http/admin_site_edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ func (a *action) AdminSiteEdit(c echo.Context) error {
}

// 站点操作权限检查
if hasAccess := IsAdminHasSiteManageAccess(c, site.Name); !hasAccess {
return RespError(c, "无权操作该站点")
if !IsAdminHasSiteAccess(c, site.Name) {
return RespError(c, "无权操作")
}

if strings.TrimSpace(p.Name) == "" {
Expand Down
12 changes: 3 additions & 9 deletions http/admin_site_get.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package http

import (
"github.com/ArtalkJS/ArtalkGo/lib"
"github.com/ArtalkJS/ArtalkGo/model"
"github.com/labstack/echo/v4"
)
Expand All @@ -17,19 +18,12 @@ func (a *action) AdminSiteGet(c echo.Context) error {
allSites := model.GetAllCookedSites()
sites := allSites

// 非超级管理员仅显示分配的站点
if !GetIsSuperAdmin(c) {
// 非超级管理员仅显示分配的站点
sites = []model.CookedSite{}
user := GetUserByReq(c).ToCooked()
for _, s := range allSites {
hasAccess := false
for _, us := range user.SiteNames {
if us == s.Name {
hasAccess = true
break
}
}
if hasAccess {
if lib.ContainsStr(user.SiteNames, s.Name) {
sites = append(sites, s)
}
}
Expand Down
30 changes: 17 additions & 13 deletions http/admin_transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,32 +58,36 @@ func (a *action) AdminImport(c echo.Context) error {
return resp
}

var payloadMap map[string]interface{}
err := json.Unmarshal([]byte(p.Payload), &payloadMap)
var payloadMapRaw map[string]interface{}
err := json.Unmarshal([]byte(p.Payload), &payloadMapRaw)
if err != nil {
return RespError(c, "payload 解析错误", Map{
"error": err,
})
}
payload := []string{}

payloadMap := map[string]string{}
for k, v := range payloadMap {
payload = append(payload, k+":"+lib.ToString(v))
payloadMap[k] = lib.ToString(v) // convert all value to string
}

payloadArr := []string{}
for k, v := range payloadMap {
payloadArr = append(payloadArr, k+":"+v)
}

if !GetIsSuperAdmin(c) {
user := GetUserByReq(c)
allow := false
for _, site := range user.ToCooked().SiteNames {
if lib.ContainsStr(payload, "t_name:"+site) {
allow = true
break
if sitName, isExist := payloadMap["t_name"]; isExist {
if !lib.ContainsStr(user.ToCooked().SiteNames, sitName) {
return RespError(c, "禁止导入的目标站点名")
}
}
if !allow {
return RespError(c, "禁止导入的目标站点名")
} else {
return RespError(c, "请填写目标站点名")
}
}

// TODO bcz 懒,先整这个缓冲输出,以后改成高级点的
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
c.Response().WriteHeader(http.StatusOK)

Expand All @@ -98,7 +102,7 @@ func (a *action) AdminImport(c echo.Context) error {
c.Response().Write([]byte("<script>scroll();</script>"))
c.Response().Flush()
}
artransfer.RunImportArtrans(payload)
artransfer.RunImportArtrans(payloadArr)

return nil
}
Expand Down
4 changes: 4 additions & 0 deletions http/admin_vote_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ func (a *action) AdminVoteSync(c echo.Context) error {
return resp
}

if !GetIsSuperAdmin(c) {
return RespError(c, "无权访问")
}

VoteSync(a)

return RespSuccess(c)
Expand Down
2 changes: 1 addition & 1 deletion http/comment_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (a *action) Add(c echo.Context) error {
page := model.FindCreatePage(p.PageKey, p.PageTitle, p.SiteName)

// check if the user is allowed to comment
if isAllowed, resp := CheckIfAllowed(c, p.Name, p.Email, page, p.SiteName); !isAllowed {
if isAllowed, resp := CheckIsAllowed(c, p.Name, p.Email, page, p.SiteName); !isAllowed {
return resp
}

Expand Down
2 changes: 1 addition & 1 deletion http/comment_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func MsgCenter(a *action, c echo.Context, p ParamsGet, siteID uint) func(db *gor
if !isAdminReq {
return db.Where("id = 0")
}
if !IsAdminHasSiteManageAccess(c, p.SiteName) {
if !IsAdminHasSiteAccess(c, p.SiteName) {
return db.Where("id = 0")
}
}
Expand Down
Loading

0 comments on commit 02b3173

Please sign in to comment.