fix platform workflow integrity and permissions
This commit is contained in:
@@ -19,36 +19,35 @@ func platformMenuAllowsPath(menus []platformbase.Menu, requestPath string) bool
|
||||
}
|
||||
relative := strings.Trim(requestPath[index+len(marker):], "/")
|
||||
resource := strings.Split(relative, "/")[0]
|
||||
domain := platformRouteDomain(resource)
|
||||
menuIdentity := platformRouteMenuIdentity(resource)
|
||||
for _, menu := range menus {
|
||||
if menu.MenuCode == domain {
|
||||
return true
|
||||
}
|
||||
menuPath := strings.Trim(menu.Path, "/")
|
||||
if menuPath != "" && strings.Split(menuPath, "/")[0] == domain {
|
||||
if menu.Identity == menuIdentity {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func platformRouteDomain(resource string) string {
|
||||
prefix := strings.Split(resource, "_")[0]
|
||||
switch prefix {
|
||||
case "product":
|
||||
return "device"
|
||||
case "gasorder":
|
||||
return "delivery"
|
||||
case "fin":
|
||||
return "finance"
|
||||
case "cms":
|
||||
return "content"
|
||||
case "cs":
|
||||
return "customer_service"
|
||||
case "platform":
|
||||
return "platform"
|
||||
func platformRouteMenuIdentity(resource string) string {
|
||||
switch {
|
||||
case resource == "dashboard":
|
||||
return "dashboard_overview"
|
||||
case strings.HasPrefix(resource, "gasorder_contract"):
|
||||
return "gasorder_contract"
|
||||
case resource == "gasorder_track" || resource == "gasorder_track_point":
|
||||
return "gasorder_track"
|
||||
case strings.HasPrefix(resource, "gasorder_"):
|
||||
return "gasorder_basic"
|
||||
case resource == "product_type" || resource == "product_warehouse":
|
||||
return resource
|
||||
case strings.HasPrefix(resource, "product_"):
|
||||
return "product_info"
|
||||
case strings.HasPrefix(resource, "cms_"):
|
||||
return "cms_content"
|
||||
case strings.HasPrefix(resource, "cs_"):
|
||||
return "cs_ticket"
|
||||
default:
|
||||
return prefix
|
||||
return resource
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
30
backend/api/internal/logic/platform/platform/access_test.go
Normal file
30
backend/api/internal/logic/platform/platform/access_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
platformbase "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/platform"
|
||||
)
|
||||
|
||||
func TestSecondLevelMenuPermissionDoesNotGrantSibling(t *testing.T) {
|
||||
menus := []platformbase.Menu{{Identity: "delivery_basic"}}
|
||||
if !platformMenuAllowsPath(menus, "/heqi/platform/v1/delivery_basic") {
|
||||
t.Fatal("selected second-level menu did not grant its resource")
|
||||
}
|
||||
if platformMenuAllowsPath(menus, "/heqi/platform/v1/delivery_account") {
|
||||
t.Fatal("selected second-level menu granted a sibling resource")
|
||||
}
|
||||
if platformMenuAllowsPath(menus, "/heqi/platform/v1/gasorder_basic") {
|
||||
t.Fatal("delivery permission leaked into gasorder")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHiddenGasorderResourcesFollowOwningSecondLevelMenu(t *testing.T) {
|
||||
orderMenus := []platformbase.Menu{{Identity: "gasorder_basic"}}
|
||||
if !platformMenuAllowsPath(orderMenus, "/heqi/platform/v1/gasorder_confirm") {
|
||||
t.Fatal("order confirmation was not covered by order menu")
|
||||
}
|
||||
if platformMenuAllowsPath(orderMenus, "/heqi/platform/v1/gasorder_contract") {
|
||||
t.Fatal("order menu granted contract management")
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package platform
|
||||
import (
|
||||
"git.apinb.com/bsm-sdk/core/errcode"
|
||||
"git.apinb.com/bsm-sdk/core/infra"
|
||||
"git.apinb.com/bsm-sdk/core/middleware"
|
||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
|
||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
||||
@@ -15,7 +16,7 @@ func ListPlatformAccount(ctx *gin.Context) {
|
||||
page, size := common.PageSize(ctx)
|
||||
var list []models.PlatformAccount
|
||||
var total int64
|
||||
query := common.ApplyKeywordFilter(ctx, impl.DBService.Model(&models.PlatformAccount{}), &models.PlatformAccount{})
|
||||
query := common.ApplyKeywordFilter(ctx, common.ActiveRecords(impl.DBService.Model(&models.PlatformAccount{})), &models.PlatformAccount{})
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
@@ -98,6 +99,15 @@ func UpdatePlatformAccount(ctx *gin.Context) {
|
||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||
return
|
||||
}
|
||||
claims, err := middleware.ParseAuth(ctx)
|
||||
if err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
if claims.Role != "root" && claims.Identity != ctx.Param("identity") {
|
||||
infra.Response.Error(ctx, errcode.ErrPermissionDenied)
|
||||
return
|
||||
}
|
||||
values := gin.H{"display_name": request.DisplayName, "avatar": request.Avatar, "phone": request.Phone}
|
||||
if request.PlatformRoleCode != nil {
|
||||
if !common.RequirePlatformRoot(ctx) {
|
||||
|
||||
@@ -36,19 +36,21 @@ func ReplacePlatformRoleMenus(ctx *gin.Context) {
|
||||
if role.IsSystem {
|
||||
return errSystemPlatformRole
|
||||
}
|
||||
menuCodes := make(map[string]struct{}, len(request.MenuIdentities))
|
||||
menuIdentities := make(map[string]struct{}, len(request.MenuIdentities))
|
||||
for _, identity := range request.MenuIdentities {
|
||||
menu, ok := platformbase.FindPlatformMenu(identity)
|
||||
if !ok {
|
||||
return gorm.ErrRecordNotFound
|
||||
}
|
||||
menuCodes[menu.MenuCode] = struct{}{}
|
||||
if menu.ParentIdentity != "" {
|
||||
menuIdentities[menu.Identity] = struct{}{}
|
||||
}
|
||||
}
|
||||
if err := transaction.Where("platform_role_id = ?", role.ID).Delete(&models.PlatformRoleMenu{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
for menuCode := range menuCodes {
|
||||
relation := models.PlatformRoleMenu{PlatformRoleID: role.ID, MenuCode: menuCode}
|
||||
for menuIdentity := range menuIdentities {
|
||||
relation := models.PlatformRoleMenu{PlatformRoleID: role.ID, MenuIdentity: menuIdentity}
|
||||
if err := transaction.Create(&relation).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -79,22 +81,12 @@ func ListPlatformRoleMenuIdentities(ctx *gin.Context) {
|
||||
common.RespondRecordError(ctx, err)
|
||||
return
|
||||
}
|
||||
var codes []string
|
||||
var identities []string
|
||||
if err := impl.DBService.Model(&models.PlatformRoleMenu{}).
|
||||
Where("platform_role_id = ?", role.ID).
|
||||
Pluck("menu_code", &codes).Error; err != nil {
|
||||
Pluck("menu_identity", &identities).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
assigned := make(map[string]struct{}, len(codes))
|
||||
for _, code := range codes {
|
||||
assigned[code] = struct{}{}
|
||||
}
|
||||
identities := make([]string, 0, len(codes))
|
||||
for _, menu := range platformbase.AllPlatformMenus() {
|
||||
if _, ok := assigned[menu.MenuCode]; ok {
|
||||
identities = append(identities, menu.Identity)
|
||||
}
|
||||
}
|
||||
infra.Response.Success(ctx, gin.H{"menu_identities": identities})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user