]> source.dussan.org Git - gitea.git/commitdiff
Check for permission when fetching user controlled issues (#20133) (#20196)
authorGusted <williamzijl7@hotmail.com>
Fri, 1 Jul 2022 15:39:10 +0000 (17:39 +0200)
committerGitHub <noreply@github.com>
Fri, 1 Jul 2022 15:39:10 +0000 (17:39 +0200)
* Check if project has the same repository id with issue when assign project to issue

* Check if issue's repository id match project's repository id

* Add more permission checking

* Remove invalid argument

* Fix errors

* Add generic check

* Remove duplicated check

* Return error + add check for new issues

* Apply suggestions from code review

Co-authored-by: Gusted <williamzijl7@hotmail.com>
Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
Co-authored-by: 6543 <6543@obermui.de>
models/issue_milestone.go
models/project_issue.go
routers/api/v1/repo/pull_review.go
routers/web/repo/issue.go
routers/web/repo/projects.go
routers/web/repo/pull_review.go
services/pull/review.go

index a3217185134e44b3ffc7ecd5fef3c37bb8941eac..4c778158201cfbbecc4d794cd9d35fd9e51b6682 100644 (file)
@@ -116,6 +116,11 @@ func getMilestoneByRepoID(e db.Engine, repoID, id int64) (*Milestone, error) {
        return m, nil
 }
 
+// HasMilestoneByRepoID returns if the milestone exists in the repository.
+func HasMilestoneByRepoID(repoID, id int64) (bool, error) {
+       return db.GetEngine(db.DefaultContext).ID(id).Where("repo_id=?", repoID).Exist(new(Milestone))
+}
+
 // GetMilestoneByRepoID returns the milestone in a repository.
 func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
        return getMilestoneByRepoID(db.GetEngine(db.DefaultContext), repoID, id)
@@ -251,6 +256,17 @@ func changeMilestoneStatus(ctx context.Context, m *Milestone, isClosed bool) err
 }
 
 func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *Issue, oldMilestoneID int64) error {
+       // Only check if milestone exists if we don't remove it.
+       if issue.MilestoneID > 0 {
+               has, err := HasMilestoneByRepoID(issue.RepoID, issue.MilestoneID)
+               if err != nil {
+                       return fmt.Errorf("HasMilestoneByRepoID: %v", err)
+               }
+               if !has {
+                       return fmt.Errorf("HasMilestoneByRepoID: issue doesn't exist")
+               }
+       }
+
        if err := updateIssueCols(ctx, issue, "milestone_id"); err != nil {
                return err
        }
index c7735addcca58ed41d6746e5a464922c29199e2a..024ab914faad59062325005adb2c744636ecc240 100644 (file)
@@ -150,6 +150,17 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U
        e := db.GetEngine(ctx)
        oldProjectID := issue.projectID(e)
 
+       // Only check if we add a new project and not remove it.
+       if newProjectID > 0 {
+               newProject, err := GetProjectByID(newProjectID)
+               if err != nil {
+                       return err
+               }
+               if newProject.RepoID != issue.RepoID {
+                       return fmt.Errorf("issue's repository is not the same as project's repository")
+               }
+       }
+
        if _, err := e.Where("project_issue.issue_id=?", issue.ID).Delete(&ProjectIssue{}); err != nil {
                return err
        }
index ec5f0456476e0cc2f5c653ab767383a191f9094f..2d8550bb5f1b3b3c22662613cd7d19834b193686 100644 (file)
@@ -883,7 +883,7 @@ func dismissReview(ctx *context.APIContext, msg string, isDismiss bool) {
                return
        }
 
-       _, err := pull_service.DismissReview(review.ID, msg, ctx.User, isDismiss)
+       _, err := pull_service.DismissReview(review.ID, ctx.Repo.Repository.ID, msg, ctx.User, isDismiss)
        if err != nil {
                ctx.Error(http.StatusInternalServerError, "pull_service.DismissReview", err)
                return
index 248743471b2a5cf4e17ace8ec7156a436f6bd064..cc384bd013bb99fb4043977606fc05e1a580ae37 100644 (file)
@@ -57,17 +57,15 @@ const (
        issueTemplateTitleKey = "IssueTemplateTitle"
 )
 
-var (
-       // IssueTemplateCandidates issue templates
-       IssueTemplateCandidates = []string{
-               "ISSUE_TEMPLATE.md",
-               "issue_template.md",
-               ".gitea/ISSUE_TEMPLATE.md",
-               ".gitea/issue_template.md",
-               ".github/ISSUE_TEMPLATE.md",
-               ".github/issue_template.md",
-       }
-)
+// IssueTemplateCandidates issue templates
+var IssueTemplateCandidates = []string{
+       "ISSUE_TEMPLATE.md",
+       "issue_template.md",
+       ".gitea/ISSUE_TEMPLATE.md",
+       ".gitea/issue_template.md",
+       ".github/ISSUE_TEMPLATE.md",
+       ".github/issue_template.md",
+}
 
 // MustAllowUserComment checks to make sure if an issue is locked.
 // If locked and user has permissions to write to the repository,
@@ -245,7 +243,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
                }
        }
 
-       var issueList = models.IssueList(issues)
+       issueList := models.IssueList(issues)
        approvalCounts, err := issueList.GetApprovalCounts()
        if err != nil {
                ctx.ServerError("ApprovalCounts", err)
@@ -311,8 +309,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
                assigneeID = 0 // Reset ID to prevent unexpected selection of assignee.
        }
 
-       ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] =
-               issue_service.GetRefEndNamesAndURLs(issues, ctx.Repo.RepoLink)
+       ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, ctx.Repo.RepoLink)
 
        ctx.Data["ApprovalCounts"] = func(issueID int64, typ string) int64 {
                counts, ok := approvalCounts[issueID]
@@ -442,7 +439,6 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R
 }
 
 func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) {
-
        var err error
 
        ctx.Data["OpenProjects"], _, err = models.GetProjects(models.ProjectSearchOptions{
@@ -796,7 +792,8 @@ func NewIssue(ctx *context.Context) {
        body := ctx.FormString("body")
        ctx.Data["BodyQuery"] = body
 
-       ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(unit.TypeProjects)
+       isProjectsEnabled := ctx.Repo.CanRead(unit.TypeProjects)
+       ctx.Data["IsProjectsEnabled"] = isProjectsEnabled
        ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
        upload.AddUploadContext(ctx, "comment")
 
@@ -812,7 +809,7 @@ func NewIssue(ctx *context.Context) {
        }
 
        projectID := ctx.FormInt64("project")
-       if projectID > 0 {
+       if projectID > 0 && isProjectsEnabled {
                project, err := models.GetProjectByID(projectID)
                if err != nil {
                        log.Error("GetProjectByID: %d: %v", projectID, err)
@@ -1017,6 +1014,12 @@ func NewIssuePost(ctx *context.Context) {
        }
 
        if projectID > 0 {
+               if !ctx.Repo.CanRead(unit.TypeProjects) {
+                       // User must also be able to see the project.
+                       ctx.Error(http.StatusBadRequest, "user hasn't permissions to read projects")
+                       return
+               }
+
                if err := models.ChangeProjectAssign(issue, ctx.User, projectID); err != nil {
                        ctx.ServerError("ChangeProjectAssign", err)
                        return
@@ -1713,6 +1716,11 @@ func getActionIssues(ctx *context.Context) []*models.Issue {
        issueUnitEnabled := ctx.Repo.CanRead(unit.TypeIssues)
        prUnitEnabled := ctx.Repo.CanRead(unit.TypePullRequests)
        for _, issue := range issues {
+               if issue.RepoID != ctx.Repo.Repository.ID {
+                       ctx.NotFound("some issue's RepoID is incorrect", errors.New("some issue's RepoID is incorrect"))
+                       return nil
+               }
+
                if issue.IsPull && !prUnitEnabled || !issue.IsPull && !issueUnitEnabled {
                        ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil)
                        return nil
@@ -2515,7 +2523,7 @@ func filterXRefComments(ctx *context.Context, issue *models.Issue) error {
 // GetIssueAttachments returns attachments for the issue
 func GetIssueAttachments(ctx *context.Context) {
        issue := GetActionIssue(ctx)
-       var attachments = make([]*api.Attachment, len(issue.Attachments))
+       attachments := make([]*api.Attachment, len(issue.Attachments))
        for i := 0; i < len(issue.Attachments); i++ {
                attachments[i] = convert.ToReleaseAttachment(issue.Attachments[i])
        }
@@ -2529,7 +2537,7 @@ func GetCommentAttachments(ctx *context.Context) {
                ctx.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err)
                return
        }
-       var attachments = make([]*api.Attachment, 0)
+       attachments := make([]*api.Attachment, 0)
        if comment.Type == models.CommentTypeComment {
                if err := comment.LoadAttachments(); err != nil {
                        ctx.ServerError("LoadAttachments", err)
@@ -2674,7 +2682,7 @@ func handleTeamMentions(ctx *context.Context) {
        var isAdmin bool
        var err error
        var teams []*models.Team
-       var org = models.OrgFromUser(ctx.Repo.Owner)
+       org := models.OrgFromUser(ctx.Repo.Owner)
        // Admin has super access.
        if ctx.User.IsAdmin {
                isAdmin = true
index f6be8add0b04aba8e53e46df9fe14cfa07b60915..aae973511e45e1b6e8a76fd42926560cf704e203 100644 (file)
@@ -5,6 +5,7 @@
 package repo
 
 import (
+       "errors"
        "fmt"
        "net/http"
        "net/url"
@@ -531,7 +532,6 @@ func EditProjectBoard(ctx *context.Context) {
 
 // SetDefaultProjectBoard set default board for uncategorized issues/pulls
 func SetDefaultProjectBoard(ctx *context.Context) {
-
        project, board := checkProjectBoardChangePermissions(ctx)
        if ctx.Written() {
                return
@@ -631,10 +631,17 @@ func MoveIssues(ctx *context.Context) {
        }
 
        if len(movedIssues) != len(form.Issues) {
-               ctx.ServerError("IssuesNotFound", err)
+               ctx.ServerError("some issues do not exist", errors.New("some issues do not exist"))
                return
        }
 
+       for _, issue := range movedIssues {
+               if issue.RepoID != project.RepoID {
+                       ctx.ServerError("Some issue's repoID is not equal to project's repoID", errors.New("Some issue's repoID is not equal to project's repoID"))
+                       return
+               }
+       }
+
        if err = models.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil {
                ctx.ServerError("MoveIssuesOnProjectBoard", err)
                return
index 257aa737f652757715ef29df6b58909d051017cc..383e2d6cabc86071585c0c19ab93d48cb976a609 100644 (file)
@@ -5,6 +5,7 @@
 package repo
 
 import (
+       "errors"
        "fmt"
        "net/http"
 
@@ -116,6 +117,11 @@ func UpdateResolveConversation(ctx *context.Context) {
                return
        }
 
+       if comment.Issue.RepoID != ctx.Repo.Repository.ID {
+               ctx.NotFound("comment's repoID is incorrect", errors.New("comment's repoID is incorrect"))
+               return
+       }
+
        var permResult bool
        if permResult, err = models.CanMarkConversation(comment.Issue, ctx.User); err != nil {
                ctx.ServerError("CanMarkConversation", err)
@@ -234,7 +240,7 @@ func SubmitReview(ctx *context.Context) {
 // DismissReview dismissing stale review by repo admin
 func DismissReview(ctx *context.Context) {
        form := web.GetForm(ctx).(*forms.DismissReviewForm)
-       comm, err := pull_service.DismissReview(form.ReviewID, form.Message, ctx.User, true)
+       comm, err := pull_service.DismissReview(form.ReviewID, ctx.Repo.Repository.ID, form.Message, ctx.User, true)
        if err != nil {
                ctx.ServerError("pull_service.DismissReview", err)
                return
index 42292ac209c4b2f88dc43db7d2049cf04c7d637a..b80c55aeae8652c0e60d20f1377d49163d61781d 100644 (file)
@@ -271,7 +271,7 @@ func SubmitReview(doer *user_model.User, gitRepo *git.Repository, issue *models.
 }
 
 // DismissReview dismissing stale review by repo admin
-func DismissReview(reviewID int64, message string, doer *user_model.User, isDismiss bool) (comment *models.Comment, err error) {
+func DismissReview(reviewID, repoID int64, message string, doer *user_model.User, isDismiss bool) (comment *models.Comment, err error) {
        review, err := models.GetReviewByID(reviewID)
        if err != nil {
                return
@@ -281,6 +281,16 @@ func DismissReview(reviewID int64, message string, doer *user_model.User, isDism
                return nil, fmt.Errorf("not need to dismiss this review because it's type is not Approve or change request")
        }
 
+       // load data for notify
+       if err = review.LoadAttributes(); err != nil {
+               return nil, err
+       }
+
+       // Check if the review's repoID is the one we're currently expecting.
+       if review.Issue.RepoID != repoID {
+               return nil, fmt.Errorf("reviews's repository is not the same as the one we expect")
+       }
+
        if err = models.DismissReview(review, isDismiss); err != nil {
                return
        }
@@ -289,10 +299,6 @@ func DismissReview(reviewID int64, message string, doer *user_model.User, isDism
                return nil, nil
        }
 
-       // load data for notify
-       if err = review.LoadAttributes(); err != nil {
-               return
-       }
        if err = review.Issue.LoadPullRequest(); err != nil {
                return
        }