CVE-2023-4124: Missing Authorization (CWE-862)
value: Missing Authorization in GitHub repository answerdev/answer prior to v1.1.1.
CWE description: The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
CVSS v3 base score: 6.5
Published: 2023-08-03T04:15Z
Repository: https://github.com/answerdev/answer
Language: Go
Files changed: internal/migrations/init.go, internal/migrations/init_data.go, internal/migrations/v3.go, internal/schema/siteinfo_schema.go, internal/service/siteinfo/siteinfo_service.go
Commit date: 2023-07-04 14:33:31 +0800
Commit message: feat(init): set default privileges when init

Diff: diff --git a/internal/migrations/init.go b/internal/migrations/init.go
index 19b039253..0dc3b35d5 100644
--- a/internal/migrations/init.go
+++ b/internal/migrations/init.go
@@ -2,10 +2,12 @@ package migrations
 
 import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"github.com/answerdev/answer/internal/schema"
+	"github.com/segmentfault/pacman/log"
 
 	"github.com/answerdev/answer/internal/entity"
 	"golang.org/x/crypto/bcrypt"
 	"xorm.io/xorm"
 )
@@ -36,20 +38,22 @@ func (m *Mentor) InitDB() error {
 	m.do("check table exist", m.checkTableExist)
 	m.do("sync table", m.syncTable)
 	m.do("init version table", m.initVersionTable)
 	m.do("init admin user", m.initAdminUser)
 	m.do("init config", m.initConfig)
+	m.do("init default privileges config", m.initDefaultRankPrivileges)
 	m.do("init role", m.initRole)
 	m.do("init power", m.initPower)
 	m.do("init role power rel", m.initRolePowerRel)
 	m.do("init admin user role rel", m.initAdminUserRoleRel)
 	m.do("init site info interface", m.initSiteInfoInterface)
 	m.do("init site info general config", m.initSiteInfoGeneralData)
 	m.do("init site info login config", m.initSiteInfoLoginConfig)
 	m.do("init site info theme config", m.initSiteInfoThemeConfig)
 	m.do("init site info seo config", m.initSiteInfoSEOConfig)
 	m.do("init site info user config", m.initSiteInfoUsersConfig)
+	m.do("init site info privilege rank", m.initSiteInfoPrivilegeRank)
 	return m.err
 }
 
 func (m *Mentor) do(taskName string, fn func()) {
 	if m.err != nil || m.Done {
@@ -93,10 +97,23 @@ func (m *Mentor) initAdminUser() {
 
 func (m *Mentor) initConfig() {
 	_, m.err = m.engine.Context(m.ctx).Insert(defaultConfigTable)
 }
 
+func (m *Mentor) initDefaultRankPrivileges() {
+	chooseOption := schema.DefaultPrivilegeOptions.Choose(schema.PrivilegeLevel2)
+	for _, privilege := range chooseOption.Privileges {
+		_, err := m.engine.Context(m.ctx).Update(
+			&entity.Config{Value: fmt.Sprintf("%d", privilege.Value)},
+			&entity.Config{Key: privilege.Key},
+		)
+		if err != nil {
+			log.Error(err)
+		}
+	}
+}
+
 func (m *Mentor) initRole() {
 	_, m.err = m.engine.Context(m.ctx).Insert(roles)
 }
 
 func (m *Mentor) initPower() {
@@ -190,5 +207,17 @@ func (m *Mentor) initSiteInfoUsersConfig() {
 		Type:    "users",
 		Content: string(usersDataBytes),
 		Status:  1,
 	})
 }
+
+func (m *Mentor) initSiteInfoPrivilegeRank() {
+	privilegeRankData := map[string]interface{}{
+		"level": schema.PrivilegeLevel2,
+	}
+	privilegeRankDataBytes, _ := json.Marshal(privilegeRankData)
+	_, m.err = m.engine.Context(m.ctx).Insert(&entity.SiteInfo{
+		Type:    "privileges",
+		Content: string(privilegeRankDataBytes),
+		Status:  1,
+	})
+}
diff --git a/internal/migrations/init_data.go b/internal/migrations/init_data.go
index 623fa5d28..fc2d8aa8e 100644
--- a/internal/migrations/init_data.go
+++ b/internal/migrations/init_data.go
@@ -230,11 +230,11 @@ var (
 		{ID: 46, Key: "rank.answer.vote_down", Value: `125`},
 		{ID: 47, Key: "rank.comment.add", Value: `1`},
 		{ID: 48, Key: "rank.comment.edit", Value: `-1`},
 		{ID: 49, Key: "rank.comment.delete", Value: `-1`},
 		{ID: 50, Key: "rank.report.add", Value: `1`},
-		{ID: 51, Key: "rank.tag.add", Value: `1`},
+		{ID: 51, Key: "rank.tag.add", Value: `1500`},
 		{ID: 52, Key: "rank.tag.edit", Value: `100`},
 		{ID: 53, Key: "rank.tag.delete", Value: `-1`},
 		{ID: 54, Key: "rank.tag.synonym", Value: `20000`},
 		{ID: 55, Key: "rank.link.url_limit", Value: `10`},
 		{ID: 56, Key: "rank.vote.detail", Value: `0`},
diff --git a/internal/migrations/v3.go b/internal/migrations/v3.go
index 2d9b28eb0..5b32bb819 100644
--- a/internal/migrations/v3.go
+++ b/internal/migrations/v3.go
@@ -115,11 +115,11 @@ ON "question" (
 		{ID: 46, Key: "rank.answer.vote_down", Value: `125`},
 		{ID: 47, Key: "rank.comment.add", Value: `1`},
 		{ID: 48, Key: "rank.comment.edit", Value: `-1`},
 		{ID: 49, Key: "rank.comment.delete", Value: `-1`},
 		{ID: 50, Key: "rank.report.add", Value: `1`},
-		{ID: 51, Key: "rank.tag.add", Value: `1`},
+		{ID: 51, Key: "rank.tag.add", Value: `1500`},
 		{ID: 52, Key: "rank.tag.edit", Value: `100`},
 		{ID: 53, Key: "rank.tag.delete", Value: `-1`},
 		{ID: 54, Key: "rank.tag.synonym", Value: `20000`},
 		{ID: 55, Key: "rank.link.url_limit", Value: `10`},
 		{ID: 56, Key: "rank.vote.detail", Value: `0`},
diff --git a/internal/schema/siteinfo_schema.go b/internal/schema/siteinfo_schema.go
index bef9cf8ea..8f54ab995 100644
--- a/internal/schema/siteinfo_schema.go
+++ b/internal/schema/siteinfo_schema.go
@@ -263,10 +263,20 @@ const (
 	// PrivilegeLevel3 high
 	PrivilegeLevel3 PrivilegeLevel = 3
 )
 
 type PrivilegeLevel int
+type PrivilegeOptions []*PrivilegeOption
+
+func (p PrivilegeOptions) Choose(level PrivilegeLevel) (option *PrivilegeOption) {
+	for _, op := range p {
+		if op.Level == level {
+			return op
+		}
+	}
+	return nil
+}
 
 // GetPrivilegesConfigResp get privileges config response
 type GetPrivilegesConfigResp struct {
 	Options       []*PrivilegeOption `json:"options"`
 	SelectedLevel PrivilegeLevel     `json:"selected_level"`
@@ -283,11 +293,11 @@ type PrivilegeOption struct {
 type UpdatePrivilegesConfigReq struct {
 	Level PrivilegeLevel `validate:"required,min=1,max=3" json:"level"`
 }
 
 var (
-	DefaultPrivilegeOptions      []*PrivilegeOption
+	DefaultPrivilegeOptions      PrivilegeOptions
 	privilegeOptionsLevelMapping = map[string][]int{
 		constant.RankQuestionAddKey:               {1, 1, 1},
 		constant.RankAnswerAddKey:                 {1, 1, 1},
 		constant.RankCommentAddKey:                {1, 1, 1},
 		constant.RankReportAddKey:                 {1, 1, 1},
diff --git a/internal/service/siteinfo/siteinfo_service.go b/internal/service/siteinfo/siteinfo_service.go
index 70ddadba2..daf20e656 100644
--- a/internal/service/siteinfo/siteinfo_service.go
+++ b/internal/service/siteinfo/siteinfo_service.go
@@ -320,17 +320,11 @@ func (s *SiteInfoService) translatePrivilegeOptions(ctx context.Context) (option
 	}
 	return
 }
 
 func (s *SiteInfoService) UpdatePrivilegesConfig(ctx context.Context, req *schema.UpdatePrivilegesConfigReq) (err error) {
-	var chooseOption *schema.PrivilegeOption
-	for _, option := range schema.DefaultPrivilegeOptions {
-		if option.Level == req.Level {
-			chooseOption = option
-			break
-		}
-	}
+	chooseOption := schema.DefaultPrivilegeOptions.Choose(req.Level)
 	if chooseOption == nil {
 		return nil
 	}
 
 	// update site info that user choose which privilege level

Vulnerable code: 		{ID: 51, Key: "rank.tag.add", Value: `1`},
		{ID: 51, Key: "rank.tag.add", Value: `1`},
	DefaultPrivilegeOptions      []*PrivilegeOption
	var chooseOption *schema.PrivilegeOption
	for _, option := range schema.DefaultPrivilegeOptions {
		if option.Level == req.Level {
			chooseOption = option
			break
		}
	}
Fixed code: 	"github.com/answerdev/answer/internal/schema"
	"github.com/segmentfault/pacman/log"
	m.do("init default privileges config", m.initDefaultRankPrivileges)
	m.do("init site info privilege rank", m.initSiteInfoPrivilegeRank)
func (m *Mentor) initDefaultRankPrivileges() {
	chooseOption := schema.DefaultPrivilegeOptions.Choose(schema.PrivilegeLevel2)
	for _, privilege := range chooseOption.Privileges {
		_, err := m.engine.Context(m.ctx).Update(
			&entity.Config{Value: fmt.Sprintf("%d", privilege.Value)},
			&entity.Config{Key: privilege.Key},
		)
		if err != nil {
			log.Error(err)
		}
	}
}


func (m *Mentor) initSiteInfoPrivilegeRank() {
	privilegeRankData := map[string]interface{}{
		"level": schema.PrivilegeLevel2,
	}
	privilegeRankDataBytes, _ := json.Marshal(privilegeRankData)
	_, m.err = m.engine.Context(m.ctx).Insert(&entity.SiteInfo{
		Type:    "privileges",
		Content: string(privilegeRankDataBytes),
		Status:  1,
	})
}
		{ID: 51, Key: "rank.tag.add", Value: `1500`},
		{ID: 51, Key: "rank.tag.add", Value: `1500`},
type PrivilegeOptions []*PrivilegeOption

func (p PrivilegeOptions) Choose(level PrivilegeLevel) (option *PrivilegeOption) {
	for _, op := range p {
		if op.Level == level {
			return op
		}
	}
	return nil
}
	DefaultPrivilegeOptions      PrivilegeOptions
	chooseOption := schema.DefaultPrivilegeOptions.Choose(req.Level)