Check if project has the same repository id with issue when assign project to issue (#20133) (#20188)

* 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>
This commit is contained in:
Lunny Xiao 2022-07-01 21:00:05 +08:00 committed by GitHub
parent 1ffc700777
commit 3e4fe009e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 68 additions and 11 deletions

View file

@ -124,6 +124,17 @@ func ChangeProjectAssign(issue *Issue, doer *user_model.User, newProjectID int64
func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error { func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error {
oldProjectID := issue.projectID(ctx) oldProjectID := issue.projectID(ctx)
// Only check if we add a new project and not remove it.
if newProjectID > 0 {
newProject, err := project_model.GetProjectByID(ctx, 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 := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil { if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil {
return err return err
} }

View file

@ -124,6 +124,11 @@ func NewMilestone(m *Milestone) (err error) {
return committer.Commit() return committer.Commit()
} }
// HasMilestoneByRepoID returns if the milestone exists in the repository.
func HasMilestoneByRepoID(ctx context.Context, repoID, id int64) (bool, error) {
return db.GetEngine(ctx).ID(id).Where("repo_id=?", repoID).Exist(new(Milestone))
}
// GetMilestoneByRepoID returns the milestone in a repository. // GetMilestoneByRepoID returns the milestone in a repository.
func GetMilestoneByRepoID(ctx context.Context, repoID, id int64) (*Milestone, error) { func GetMilestoneByRepoID(ctx context.Context, repoID, id int64) (*Milestone, error) {
m := new(Milestone) m := new(Milestone)

View file

@ -886,7 +886,7 @@ func dismissReview(ctx *context.APIContext, msg string, isDismiss bool) {
return return
} }
_, err := pull_service.DismissReview(ctx, review.ID, msg, ctx.Doer, isDismiss) _, err := pull_service.DismissReview(ctx, review.ID, ctx.Repo.Repository.ID, msg, ctx.Doer, isDismiss)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "pull_service.DismissReview", err) ctx.Error(http.StatusInternalServerError, "pull_service.DismissReview", err)
return return

View file

@ -803,7 +803,8 @@ func NewIssue(ctx *context.Context) {
body := ctx.FormString("body") body := ctx.FormString("body")
ctx.Data["BodyQuery"] = 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 ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
upload.AddUploadContext(ctx, "comment") upload.AddUploadContext(ctx, "comment")
@ -819,7 +820,7 @@ func NewIssue(ctx *context.Context) {
} }
projectID := ctx.FormInt64("project") projectID := ctx.FormInt64("project")
if projectID > 0 { if projectID > 0 && isProjectsEnabled {
project, err := project_model.GetProjectByID(ctx, projectID) project, err := project_model.GetProjectByID(ctx, projectID)
if err != nil { if err != nil {
log.Error("GetProjectByID: %d: %v", projectID, err) log.Error("GetProjectByID: %d: %v", projectID, err)
@ -1043,6 +1044,11 @@ func NewIssuePost(ctx *context.Context) {
} }
if projectID > 0 { 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 := issues_model.ChangeProjectAssign(issue, ctx.Doer, projectID); err != nil { if err := issues_model.ChangeProjectAssign(issue, ctx.Doer, projectID); err != nil {
ctx.ServerError("ChangeProjectAssign", err) ctx.ServerError("ChangeProjectAssign", err)
return return
@ -1783,6 +1789,10 @@ func getActionIssues(ctx *context.Context) []*issues_model.Issue {
issueUnitEnabled := ctx.Repo.CanRead(unit.TypeIssues) issueUnitEnabled := ctx.Repo.CanRead(unit.TypeIssues)
prUnitEnabled := ctx.Repo.CanRead(unit.TypePullRequests) prUnitEnabled := ctx.Repo.CanRead(unit.TypePullRequests)
for _, issue := range issues { 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 { if issue.IsPull && !prUnitEnabled || !issue.IsPull && !issueUnitEnabled {
ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil) ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil)
return nil return nil

View file

@ -5,6 +5,7 @@
package repo package repo
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
@ -633,10 +634,17 @@ func MoveIssues(ctx *context.Context) {
} }
if len(movedIssues) != len(form.Issues) { 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 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 = project_model.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil { if err = project_model.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil {
ctx.ServerError("MoveIssuesOnProjectBoard", err) ctx.ServerError("MoveIssuesOnProjectBoard", err)
return return

View file

@ -5,6 +5,7 @@
package repo package repo
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
@ -118,6 +119,11 @@ func UpdateResolveConversation(ctx *context.Context) {
return 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 var permResult bool
if permResult, err = issues_model.CanMarkConversation(comment.Issue, ctx.Doer); err != nil { if permResult, err = issues_model.CanMarkConversation(comment.Issue, ctx.Doer); err != nil {
ctx.ServerError("CanMarkConversation", err) ctx.ServerError("CanMarkConversation", err)
@ -236,7 +242,7 @@ func SubmitReview(ctx *context.Context) {
// DismissReview dismissing stale review by repo admin // DismissReview dismissing stale review by repo admin
func DismissReview(ctx *context.Context) { func DismissReview(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.DismissReviewForm) form := web.GetForm(ctx).(*forms.DismissReviewForm)
comm, err := pull_service.DismissReview(ctx, form.ReviewID, form.Message, ctx.Doer, true) comm, err := pull_service.DismissReview(ctx, form.ReviewID, ctx.Repo.Repository.ID, form.Message, ctx.Doer, true)
if err != nil { if err != nil {
ctx.ServerError("pull_service.DismissReview", err) ctx.ServerError("pull_service.DismissReview", err)
return return

View file

@ -898,7 +898,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel) m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel)
m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone) m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone)
m.Post("/projects", reqRepoIssuesOrPullsWriter, repo.UpdateIssueProject) m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject)
m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee) m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest) m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest)
m.Post("/dismiss_review", reqRepoAdmin, bindIgnErr(forms.DismissReviewForm{}), repo.DismissReview) m.Post("/dismiss_review", reqRepoAdmin, bindIgnErr(forms.DismissReviewForm{}), repo.DismissReview)

View file

@ -15,6 +15,17 @@ import (
) )
func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) error { func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) error {
// Only check if milestone exists if we don't remove it.
if issue.MilestoneID > 0 {
has, err := issues_model.HasMilestoneByRepoID(ctx, 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 := issues_model.UpdateIssueCols(ctx, issue, "milestone_id"); err != nil { if err := issues_model.UpdateIssueCols(ctx, issue, "milestone_id"); err != nil {
return err return err
} }

View file

@ -271,7 +271,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos
} }
// DismissReview dismissing stale review by repo admin // DismissReview dismissing stale review by repo admin
func DismissReview(ctx context.Context, reviewID int64, message string, doer *user_model.User, isDismiss bool) (comment *issues_model.Comment, err error) { func DismissReview(ctx context.Context, reviewID, repoID int64, message string, doer *user_model.User, isDismiss bool) (comment *issues_model.Comment, err error) {
review, err := issues_model.GetReviewByID(ctx, reviewID) review, err := issues_model.GetReviewByID(ctx, reviewID)
if err != nil { if err != nil {
return return
@ -281,6 +281,16 @@ func DismissReview(ctx context.Context, reviewID int64, message string, doer *us
return nil, fmt.Errorf("not need to dismiss this review because it's type is not Approve or change request") 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(ctx); 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 = issues_model.DismissReview(review, isDismiss); err != nil { if err = issues_model.DismissReview(review, isDismiss); err != nil {
return return
} }
@ -289,10 +299,6 @@ func DismissReview(ctx context.Context, reviewID int64, message string, doer *us
return nil, nil return nil, nil
} }
// load data for notify
if err = review.LoadAttributes(ctx); err != nil {
return
}
if err = review.Issue.LoadPullRequest(); err != nil { if err = review.Issue.LoadPullRequest(); err != nil {
return return
} }