Skip to content

Commit

Permalink
Check for permission when fetching user controlled issues (go-gitea#2…
Browse files Browse the repository at this point in the history
…0133) (go-gitea#20196)

* 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>
  • Loading branch information
3 people authored Jul 1, 2022
1 parent df0b330 commit 6162fb0
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 29 deletions.
16 changes: 16 additions & 0 deletions models/issue_milestone.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down
11 changes: 11 additions & 0 deletions models/project_issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion routers/api/v1/repo/pull_review.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 28 additions & 20 deletions routers/web/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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")

Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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])
}
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down
11 changes: 9 additions & 2 deletions routers/web/repo/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package repo

import (
"errors"
"fmt"
"net/http"
"net/url"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion routers/web/repo/pull_review.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package repo

import (
"errors"
"fmt"
"net/http"

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
16 changes: 11 additions & 5 deletions services/pull/review.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down

0 comments on commit 6162fb0

Please sign in to comment.