Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix wrong permissions check when issues/prs shared operations #9885

Merged
merged 5 commits into from
Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/context/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (r *Repository) CanUseTimetracker(issue *models.Issue, user *models.User) b
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
isAssigned, _ := models.IsUserAssignedToIssue(issue, user)
return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() ||
r.Permission.CanWrite(models.UnitTypeIssues) || issue.IsPoster(user.ID) || isAssigned)
r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
}

// CanCreateIssueDependencies returns whether or not a user can create dependencies.
Expand Down
4 changes: 2 additions & 2 deletions modules/repofiles/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ func UpdateIssuesCommit(doer *models.User, repo *models.Repository, commits []*r
refMarked[key] = true

// FIXME: this kind of condition is all over the code, it should be consolidated in a single place
canclose := perm.IsAdmin() || perm.IsOwner() || perm.CanWrite(models.UnitTypeIssues) || refIssue.PosterID == doer.ID
cancomment := canclose || perm.CanRead(models.UnitTypeIssues)
canclose := perm.IsAdmin() || perm.IsOwner() || perm.CanWriteIssuesOrPulls(refIssue.IsPull) || refIssue.PosterID == doer.ID
cancomment := canclose || perm.CanReadIssuesOrPulls(refIssue.IsPull)

// Don't proceed if the user can't comment
if !cancomment {
Expand Down
26 changes: 21 additions & 5 deletions routers/api/v1/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ func ListIssues(ctx *context.APIContext) {
// in: query
// description: search string
// type: string
// - name: type
// in: query
// description: filter by type (issues / pulls) if set
// type: string
// responses:
// "200":
// "$ref": "#/responses/IssueList"
Expand Down Expand Up @@ -241,6 +245,16 @@ func ListIssues(ctx *context.APIContext) {
}
}

var isPull util.OptionalBool
switch ctx.Query("type") {
case "pulls":
isPull = util.OptionalBoolTrue
case "issues":
isPull = util.OptionalBoolFalse
default:
isPull = util.OptionalBoolNone
}

// Only fetch the issues if we either don't have a keyword or the search returned issues
// This would otherwise return all issues if no issues were found by the search.
if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
Expand All @@ -251,6 +265,7 @@ func ListIssues(ctx *context.APIContext) {
IsClosed: isClosed,
IssueIDs: issueIDs,
LabelIDs: labelIDs,
IsPull: isPull,
})
}

Expand Down Expand Up @@ -475,14 +490,15 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
return
}
issue.Repo = ctx.Repo.Repository
canWrite := ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)

err = issue.LoadAttributes()
if err != nil {
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return
}

if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(models.UnitTypeIssues) {
if !issue.IsPoster(ctx.User.ID) && !canWrite {
ctx.Status(http.StatusForbidden)
return
}
Expand All @@ -495,7 +511,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
}

// Update or remove the deadline, only if set and allowed
if (form.Deadline != nil || form.RemoveDeadline != nil) && ctx.Repo.CanWrite(models.UnitTypeIssues) {
if (form.Deadline != nil || form.RemoveDeadline != nil) && canWrite {
var deadlineUnix timeutil.TimeStamp

if (form.RemoveDeadline == nil || !*form.RemoveDeadline) && !form.Deadline.IsZero() {
Expand All @@ -519,7 +535,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
// Pass one or more user logins to replace the set of assignees on this Issue.
// Send an empty array ([]) to clear all assignees from the Issue.

if ctx.Repo.CanWrite(models.UnitTypeIssues) && (form.Assignees != nil || form.Assignee != nil) {
if canWrite && (form.Assignees != nil || form.Assignee != nil) {
oneAssignee := ""
if form.Assignee != nil {
oneAssignee = *form.Assignee
Expand All @@ -532,7 +548,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
}
}

if ctx.Repo.CanWrite(models.UnitTypeIssues) && form.Milestone != nil &&
if canWrite && form.Milestone != nil &&
issue.MilestoneID != *form.Milestone {
oldMilestoneID := issue.MilestoneID
issue.MilestoneID = *form.Milestone
Expand Down Expand Up @@ -618,7 +634,7 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) {
return
}

if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
ctx.Error(http.StatusForbidden, "", "Not repo writer")
return
}
Expand Down
2 changes: 1 addition & 1 deletion routers/api/v1/repo/issue_comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func CreateIssueComment(ctx *context.APIContext, form api.CreateIssueCommentOpti
return
}

if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin {
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.User.IsAdmin {
ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
return
}
Expand Down
4 changes: 2 additions & 2 deletions routers/api/v1/repo/issue_reaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err)
}

if comment.Issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) {
if comment.Issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull) {
ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction"))
return
}
Expand Down Expand Up @@ -380,7 +380,7 @@ func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, i
return
}

if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) {
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction"))
return
}
Expand Down
2 changes: 1 addition & 1 deletion routers/api/v1/repo/issue_stopwatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func prepareIssueStopwatch(ctx *context.APIContext, shouldExist bool) (*models.I
return nil, err
}

if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
ctx.Status(http.StatusForbidden)
return nil, err
}
Expand Down
9 changes: 4 additions & 5 deletions routers/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,12 @@ var (
// If locked and user has permissions to write to the repository,
// then the comment is allowed, else it is blocked
func MustAllowUserComment(ctx *context.Context) {

issue := GetActionIssue(ctx)
if ctx.Written() {
return
}

if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin {
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.User.IsAdmin {
ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked"))
ctx.Redirect(issue.HTMLURL())
return
Expand Down Expand Up @@ -344,7 +343,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repos

// RetrieveRepoMetas find all the meta information of a repository
func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository, isPull bool) []*models.Label {
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
if !ctx.Repo.CanWriteIssuesOrPulls(isPull) {
return nil
}

Expand Down Expand Up @@ -1022,7 +1021,6 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
ctx.Data["IsIssueWriter"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.IsAdmin() || ctx.User.IsAdmin)
ctx.Data["IsRepoIssuesWriter"] = ctx.IsSigned && (ctx.Repo.CanWrite(models.UnitTypeIssues) || ctx.User.IsAdmin)
ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons
ctx.HTML(200, tplIssueView)
}
Expand Down Expand Up @@ -1283,9 +1281,10 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
}

ctx.Error(403)
return
}

if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin {
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.User.IsAdmin {
ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked"))
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
return
Expand Down
6 changes: 3 additions & 3 deletions routers/repo/issue_dependency.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,6 @@ func RemoveDependency(ctx *context.Context) {
return
}

// Redirect
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)

// Dependency Type
depTypeStr := ctx.Req.PostForm.Get("dependencyType")

Expand Down Expand Up @@ -126,4 +123,7 @@ func RemoveDependency(ctx *context.Context) {
ctx.ServerError("RemoveIssueDependency", err)
return
}

// Redirect
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
}
8 changes: 1 addition & 7 deletions routers/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,19 +508,13 @@ func RegisterRoutes(m *macaron.Macaron) {
reqRepoReleaseWriter := context.RequireRepoWriter(models.UnitTypeReleases)
reqRepoReleaseReader := context.RequireRepoReader(models.UnitTypeReleases)
reqRepoWikiWriter := context.RequireRepoWriter(models.UnitTypeWiki)
reqRepoIssueWriter := context.RequireRepoWriter(models.UnitTypeIssues)
reqRepoIssueReader := context.RequireRepoReader(models.UnitTypeIssues)
reqRepoPullsWriter := context.RequireRepoWriter(models.UnitTypePullRequests)
reqRepoPullsReader := context.RequireRepoReader(models.UnitTypePullRequests)
reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(models.UnitTypeIssues, models.UnitTypePullRequests)
reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(models.UnitTypeIssues, models.UnitTypePullRequests)

reqRepoIssueWriter := func(ctx *context.Context) {
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
ctx.Error(403)
return
}
}

// ***** START: Organization *****
m.Group("/org", func() {
m.Group("", func() {
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/issue/view_content.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
{{ template "repo/issue/view_content/pull". }}
{{end}}
{{if .IsSigned}}
{{ if and (or .IsRepoAdmin .IsRepoIssuesWriter (or (not .Issue.IsLocked))) (not .Repository.IsArchived) }}
{{ if and (or .IsRepoAdmin .IsIssueWriter (or (not .Issue.IsLocked))) (not .Repository.IsArchived) }}
<div class="comment form">
<a class="avatar" href="{{.SignedUser.HomeLink}}">
<img src="{{.SignedUser.RelAvatarLink}}">
Expand Down
6 changes: 6 additions & 0 deletions templates/swagger/v1_json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3133,6 +3133,12 @@
"description": "search string",
"name": "q",
"in": "query"
},
{
"type": "string",
"description": "filter by type (issues / pulls) if set",
"name": "type",
"in": "query"
}
],
"responses": {
Expand Down