summaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
Diffstat (limited to 'routers')
-rw-r--r--routers/api/packages/generic/generic.go29
-rw-r--r--routers/api/packages/generic/generic_test.go65
-rw-r--r--routers/api/v1/repo/file.go2
-rw-r--r--routers/api/v1/repo/pull_review.go17
-rw-r--r--routers/web/org/projects.go108
-rw-r--r--routers/web/org/setting.go2
-rw-r--r--routers/web/repo/blame.go4
-rw-r--r--routers/web/repo/issue.go6
-rw-r--r--routers/web/repo/issue_content_history.go2
-rw-r--r--routers/web/repo/projects.go52
-rw-r--r--routers/web/repo/pull_review.go4
-rw-r--r--routers/web/repo/pull_review_test.go27
-rw-r--r--routers/web/repo/release.go43
-rw-r--r--routers/web/repo/render.go15
-rw-r--r--routers/web/repo/setting/webhook.go10
-rw-r--r--routers/web/repo/view.go4
-rw-r--r--routers/web/user/setting/webhooks.go2
-rw-r--r--routers/web/web.go2
18 files changed, 235 insertions, 159 deletions
diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go
index b65870a8d0..8232931134 100644
--- a/routers/api/packages/generic/generic.go
+++ b/routers/api/packages/generic/generic.go
@@ -8,6 +8,7 @@ import (
"net/http"
"regexp"
"strings"
+ "unicode"
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/log"
@@ -18,8 +19,8 @@ import (
)
var (
- packageNameRegex = regexp.MustCompile(`\A[A-Za-z0-9\.\_\-\+]+\z`)
- filenameRegex = packageNameRegex
+ packageNameRegex = regexp.MustCompile(`\A[-_+.\w]+\z`)
+ filenameRegex = regexp.MustCompile(`\A[-_+=:;.()\[\]{}~!@#$%^& \w]+\z`)
)
func apiError(ctx *context.Context, status int, obj any) {
@@ -54,20 +55,38 @@ func DownloadPackageFile(ctx *context.Context) {
helper.ServePackageFile(ctx, s, u, pf)
}
+func isValidPackageName(packageName string) bool {
+ if len(packageName) == 1 && !unicode.IsLetter(rune(packageName[0])) && !unicode.IsNumber(rune(packageName[0])) {
+ return false
+ }
+ return packageNameRegex.MatchString(packageName) && packageName != ".."
+}
+
+func isValidFileName(filename string) bool {
+ return filenameRegex.MatchString(filename) &&
+ strings.TrimSpace(filename) == filename &&
+ filename != "." && filename != ".."
+}
+
// UploadPackage uploads the specific generic package.
// Duplicated packages get rejected.
func UploadPackage(ctx *context.Context) {
packageName := ctx.Params("packagename")
filename := ctx.Params("filename")
- if !packageNameRegex.MatchString(packageName) || !filenameRegex.MatchString(filename) {
- apiError(ctx, http.StatusBadRequest, errors.New("Invalid package name or filename"))
+ if !isValidPackageName(packageName) {
+ apiError(ctx, http.StatusBadRequest, errors.New("invalid package name"))
+ return
+ }
+
+ if !isValidFileName(filename) {
+ apiError(ctx, http.StatusBadRequest, errors.New("invalid filename"))
return
}
packageVersion := ctx.Params("packageversion")
if packageVersion != strings.TrimSpace(packageVersion) {
- apiError(ctx, http.StatusBadRequest, errors.New("Invalid package version"))
+ apiError(ctx, http.StatusBadRequest, errors.New("invalid package version"))
return
}
diff --git a/routers/api/packages/generic/generic_test.go b/routers/api/packages/generic/generic_test.go
new file mode 100644
index 0000000000..1acaafe576
--- /dev/null
+++ b/routers/api/packages/generic/generic_test.go
@@ -0,0 +1,65 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package generic
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestValidatePackageName(t *testing.T) {
+ bad := []string{
+ "",
+ ".",
+ "..",
+ "-",
+ "a?b",
+ "a b",
+ "a/b",
+ }
+ for _, name := range bad {
+ assert.False(t, isValidPackageName(name), "bad=%q", name)
+ }
+
+ good := []string{
+ "a",
+ "1",
+ "a-",
+ "a_b",
+ "c.d+",
+ }
+ for _, name := range good {
+ assert.True(t, isValidPackageName(name), "good=%q", name)
+ }
+}
+
+func TestValidateFileName(t *testing.T) {
+ bad := []string{
+ "",
+ ".",
+ "..",
+ "a?b",
+ "a/b",
+ " a",
+ "a ",
+ }
+ for _, name := range bad {
+ assert.False(t, isValidFileName(name), "bad=%q", name)
+ }
+
+ good := []string{
+ "-",
+ "a",
+ "1",
+ "a-",
+ "a_b",
+ "a b",
+ "c.d+",
+ `-_+=:;.()[]{}~!@#$%^& aA1`,
+ }
+ for _, name := range good {
+ assert.True(t, isValidFileName(name), "good=%q", name)
+ }
+}
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index 72ada25ec7..712cba7455 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -150,7 +150,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
return
}
- // OK, now the blob is known to have at most 1024 bytes we can simply read this in in one go (This saves reading it twice)
+ // OK, now the blob is known to have at most 1024 bytes we can simply read this in one go (This saves reading it twice)
dataRc, err := blob.DataAsync()
if err != nil {
ctx.ServerError("DataAsync", err)
diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go
index 9ccbb57c52..77c0d25e2a 100644
--- a/routers/api/v1/repo/pull_review.go
+++ b/routers/api/v1/repo/pull_review.go
@@ -787,6 +787,8 @@ func DeleteReviewRequests(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "422":
// "$ref": "#/responses/validationError"
+ // "403":
+ // "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
opts := web.GetForm(ctx).(*api.PullReviewRequestOptions)
@@ -855,6 +857,10 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions
for _, reviewer := range reviewers {
comment, err := issue_service.ReviewRequest(ctx, pr.Issue, ctx.Doer, reviewer, isAdd)
if err != nil {
+ if issues_model.IsErrReviewRequestOnClosedPR(err) {
+ ctx.Error(http.StatusForbidden, "", err)
+ return
+ }
ctx.Error(http.StatusInternalServerError, "ReviewRequest", err)
return
}
@@ -1068,7 +1074,7 @@ func dismissReview(ctx *context.APIContext, msg string, isDismiss, dismissPriors
ctx.Error(http.StatusForbidden, "", "Must be repo admin")
return
}
- review, pr, isWrong := prepareSingleReview(ctx)
+ review, _, isWrong := prepareSingleReview(ctx)
if isWrong {
return
}
@@ -1078,13 +1084,12 @@ func dismissReview(ctx *context.APIContext, msg string, isDismiss, dismissPriors
return
}
- if pr.Issue.IsClosed {
- ctx.Error(http.StatusForbidden, "", "not need to dismiss this review because this pr is closed")
- return
- }
-
_, err := pull_service.DismissReview(ctx, review.ID, ctx.Repo.Repository.ID, msg, ctx.Doer, isDismiss, dismissPriors)
if err != nil {
+ if pull_service.IsErrDismissRequestOnClosedPR(err) {
+ ctx.Error(http.StatusForbidden, "", err)
+ return
+ }
ctx.Error(http.StatusInternalServerError, "pull_service.DismissReview", err)
return
}
diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go
index ad8bb90d9e..db1dac0120 100644
--- a/routers/web/org/projects.go
+++ b/routers/web/org/projects.go
@@ -207,11 +207,7 @@ func ChangeProjectStatus(ctx *context.Context) {
id := ctx.ParamsInt64(":id")
if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, 0, id, toClose); err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", err)
- } else {
- ctx.ServerError("ChangeProjectStatusByRepoIDAndID", err)
- }
+ ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err)
return
}
ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects?state=" + url.QueryEscape(ctx.Params(":action")))
@@ -221,11 +217,7 @@ func ChangeProjectStatus(ctx *context.Context) {
func DeleteProject(ctx *context.Context) {
p, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
if err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", nil)
- } else {
- ctx.ServerError("GetProjectByID", err)
- }
+ ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err)
return
}
if p.OwnerID != ctx.ContextUser.ID {
@@ -254,11 +246,7 @@ func RenderEditProject(ctx *context.Context) {
p, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
if err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", nil)
- } else {
- ctx.ServerError("GetProjectByID", err)
- }
+ ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err)
return
}
if p.OwnerID != ctx.ContextUser.ID {
@@ -303,11 +291,7 @@ func EditProjectPost(ctx *context.Context) {
p, err := project_model.GetProjectByID(ctx, projectID)
if err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", nil)
- } else {
- ctx.ServerError("GetProjectByID", err)
- }
+ ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err)
return
}
if p.OwnerID != ctx.ContextUser.ID {
@@ -335,11 +319,7 @@ func EditProjectPost(ctx *context.Context) {
func ViewProject(ctx *context.Context) {
project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
if err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", nil)
- } else {
- ctx.ServerError("GetProjectByID", err)
- }
+ ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err)
return
}
if project.OwnerID != ctx.ContextUser.ID {
@@ -353,10 +333,6 @@ func ViewProject(ctx *context.Context) {
return
}
- if boards[0].ID == 0 {
- boards[0].Title = ctx.Locale.TrString("repo.projects.type.uncategorized")
- }
-
issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards)
if err != nil {
ctx.ServerError("LoadIssuesOfBoards", err)
@@ -493,11 +469,7 @@ func DeleteProjectBoard(ctx *context.Context) {
project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
if err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", nil)
- } else {
- ctx.ServerError("GetProjectByID", err)
- }
+ ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err)
return
}
@@ -534,11 +506,7 @@ func AddBoardToProjectPost(ctx *context.Context) {
project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
if err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", nil)
- } else {
- ctx.ServerError("GetProjectByID", err)
- }
+ ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err)
return
}
@@ -566,11 +534,7 @@ func CheckProjectBoardChangePermissions(ctx *context.Context) (*project_model.Pr
project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
if err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", nil)
- } else {
- ctx.ServerError("GetProjectByID", err)
- }
+ ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err)
return nil, nil
}
@@ -636,21 +600,6 @@ func SetDefaultProjectBoard(ctx *context.Context) {
ctx.JSONOK()
}
-// UnsetDefaultProjectBoard unset default board for uncategorized issues/pulls
-func UnsetDefaultProjectBoard(ctx *context.Context) {
- project, _ := CheckProjectBoardChangePermissions(ctx)
- if ctx.Written() {
- return
- }
-
- if err := project_model.SetDefaultBoard(ctx, project.ID, 0); err != nil {
- ctx.ServerError("SetDefaultBoard", err)
- return
- }
-
- ctx.JSONOK()
-}
-
// MoveIssues moves or keeps issues in a column and sorts them inside that column
func MoveIssues(ctx *context.Context) {
if ctx.Doer == nil {
@@ -662,11 +611,7 @@ func MoveIssues(ctx *context.Context) {
project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
if err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("ProjectNotExist", nil)
- } else {
- ctx.ServerError("GetProjectByID", err)
- }
+ ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err)
return
}
if project.OwnerID != ctx.ContextUser.ID {
@@ -674,28 +619,15 @@ func MoveIssues(ctx *context.Context) {
return
}
- var board *project_model.Board
+ board, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
+ if err != nil {
+ ctx.NotFoundOrServerError("GetProjectBoard", project_model.IsErrProjectBoardNotExist, err)
+ return
+ }
- if ctx.ParamsInt64(":boardID") == 0 {
- board = &project_model.Board{
- ID: 0,
- ProjectID: project.ID,
- Title: ctx.Locale.TrString("repo.projects.type.uncategorized"),
- }
- } else {
- board, err = project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
- if err != nil {
- if project_model.IsErrProjectBoardNotExist(err) {
- ctx.NotFound("ProjectBoardNotExist", nil)
- } else {
- ctx.ServerError("GetProjectBoard", err)
- }
- return
- }
- if board.ProjectID != project.ID {
- ctx.NotFound("BoardNotInProject", nil)
- return
- }
+ if board.ProjectID != project.ID {
+ ctx.NotFound("BoardNotInProject", nil)
+ return
}
type movedIssuesForm struct {
@@ -718,11 +650,7 @@ func MoveIssues(ctx *context.Context) {
}
movedIssues, err := issues_model.GetIssuesByIDs(ctx, issueIDs)
if err != nil {
- if issues_model.IsErrIssueNotExist(err) {
- ctx.NotFound("IssueNotExisting", nil)
- } else {
- ctx.ServerError("GetIssueByID", err)
- }
+ ctx.NotFoundOrServerError("GetIssueByID", issues_model.IsErrIssueNotExist, err)
return
}
diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go
index 494ada4323..0be734abaf 100644
--- a/routers/web/org/setting.go
+++ b/routers/web/org/setting.go
@@ -26,6 +26,7 @@ import (
org_service "code.gitea.io/gitea/services/org"
repo_service "code.gitea.io/gitea/services/repository"
user_service "code.gitea.io/gitea/services/user"
+ webhook_service "code.gitea.io/gitea/services/webhook"
)
const (
@@ -210,6 +211,7 @@ func Webhooks(ctx *context.Context) {
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["BaseLink"] = ctx.Org.OrgLink + "/settings/hooks"
ctx.Data["BaseLinkNew"] = ctx.Org.OrgLink + "/settings/hooks"
+ ctx.Data["WebhookList"] = webhook_service.List()
ctx.Data["Description"] = ctx.Tr("org.settings.hooks_desc")
ws, err := db.Find[webhook.Webhook](ctx, webhook.ListWebhookOptions{OwnerID: ctx.Org.Organization.ID})
diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go
index 0f464ad076..eea3d4dc00 100644
--- a/routers/web/repo/blame.go
+++ b/routers/web/repo/blame.go
@@ -258,9 +258,9 @@ func renderBlame(ctx *context.Context, blameParts []*git.BlamePart, commitNames
var avatar string
if commit.User != nil {
- avatar = string(avatarUtils.Avatar(commit.User, 18, "gt-mr-3"))
+ avatar = string(avatarUtils.Avatar(commit.User, 18))
} else {
- avatar = string(avatarUtils.AvatarByEmail(commit.Author.Email, commit.Author.Name, 18, "gt-mr-3"))
+ avatar = string(avatarUtils.AvatarByEmail(commit.Author.Email, commit.Author.Name, 18, "tw-mr-2"))
}
br.Avatar = gotemplate.HTML(avatar)
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index c0ec121336..a4e3f7165a 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -1600,7 +1600,7 @@ func ViewIssue(ctx *context.Context) {
}
marked[issue.PosterID] = issue.ShowRole
- // Render comments and and fetch participants.
+ // Render comments and fetch participants.
participants[0] = issue.Poster
for _, comment = range issue.Comments {
comment.Issue = issue
@@ -2494,6 +2494,10 @@ func UpdatePullReviewRequest(ctx *context.Context) {
_, err = issue_service.ReviewRequest(ctx, issue, ctx.Doer, reviewer, action == "attach")
if err != nil {
+ if issues_model.IsErrReviewRequestOnClosedPR(err) {
+ ctx.Status(http.StatusForbidden)
+ return
+ }
ctx.ServerError("ReviewRequest", err)
return
}
diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go
index dfee2863b5..c817d6aa96 100644
--- a/routers/web/repo/issue_content_history.go
+++ b/routers/web/repo/issue_content_history.go
@@ -70,7 +70,7 @@ func GetContentHistoryList(ctx *context.Context) {
}
src := html.EscapeString(item.UserAvatarLink)
- class := avatars.DefaultAvatarClass + " gt-mr-3"
+ class := avatars.DefaultAvatarClass + " tw-mr-2"
name := html.EscapeString(username)
avatarHTML := string(templates.AvatarHTML(src, 28, class, username))
timeSinceText := string(timeutil.TimeSinceUnix(item.EditedUnix, ctx.Locale))
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index 4c171defbd..aa42585590 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -314,10 +314,6 @@ func ViewProject(ctx *context.Context) {
return
}
- if boards[0].ID == 0 {
- boards[0].Title = ctx.Locale.TrString("repo.projects.type.uncategorized")
- }
-
issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards)
if err != nil {
ctx.ServerError("LoadIssuesOfBoards", err)
@@ -582,21 +578,6 @@ func SetDefaultProjectBoard(ctx *context.Context) {
ctx.JSONOK()
}
-// UnSetDefaultProjectBoard unset default board for uncategorized issues/pulls
-func UnSetDefaultProjectBoard(ctx *context.Context) {
- project, _ := checkProjectBoardChangePermissions(ctx)
- if ctx.Written() {
- return
- }
-
- if err := project_model.SetDefaultBoard(ctx, project.ID, 0); err != nil {
- ctx.ServerError("SetDefaultBoard", err)
- return
- }
-
- ctx.JSONOK()
-}
-
// MoveIssues moves or keeps issues in a column and sorts them inside that column
func MoveIssues(ctx *context.Context) {
if ctx.Doer == nil {
@@ -627,28 +608,19 @@ func MoveIssues(ctx *context.Context) {
return
}
- var board *project_model.Board
-
- if ctx.ParamsInt64(":boardID") == 0 {
- board = &project_model.Board{
- ID: 0,
- ProjectID: project.ID,
- Title: ctx.Locale.TrString("repo.projects.type.uncategorized"),
- }
- } else {
- board, err = project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
- if err != nil {
- if project_model.IsErrProjectBoardNotExist(err) {
- ctx.NotFound("ProjectBoardNotExist", nil)
- } else {
- ctx.ServerError("GetProjectBoard", err)
- }
- return
- }
- if board.ProjectID != project.ID {
- ctx.NotFound("BoardNotInProject", nil)
- return
+ board, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
+ if err != nil {
+ if project_model.IsErrProjectBoardNotExist(err) {
+ ctx.NotFound("ProjectBoardNotExist", nil)
+ } else {
+ ctx.ServerError("GetProjectBoard", err)
}
+ return
+ }
+
+ if board.ProjectID != project.ID {
+ ctx.NotFound("BoardNotInProject", nil)
+ return
}
type movedIssuesForm struct {
diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go
index ead7592fd0..afa3b17d31 100644
--- a/routers/web/repo/pull_review.go
+++ b/routers/web/repo/pull_review.go
@@ -263,6 +263,10 @@ func DismissReview(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.DismissReviewForm)
comm, err := pull_service.DismissReview(ctx, form.ReviewID, ctx.Repo.Repository.ID, form.Message, ctx.Doer, true, true)
if err != nil {
+ if pull_service.IsErrDismissRequestOnClosedPR(err) {
+ ctx.Status(http.StatusForbidden)
+ return
+ }
ctx.ServerError("pull_service.DismissReview", err)
return
}
diff --git a/routers/web/repo/pull_review_test.go b/routers/web/repo/pull_review_test.go
index d87656f796..70f6a0e055 100644
--- a/routers/web/repo/pull_review_test.go
+++ b/routers/web/repo/pull_review_test.go
@@ -4,6 +4,7 @@
package repo
import (
+ "net/http"
"net/http/httptest"
"testing"
@@ -75,4 +76,30 @@ func TestRenderConversation(t *testing.T) {
renderConversation(ctx, preparedComment, "timeline")
assert.Contains(t, resp.Body.String(), `<div id="code-comments-`)
})
+ run("diff non-existing review", func(t *testing.T, ctx *context.Context, resp *httptest.ResponseRecorder) {
+ reviews, err := issues_model.FindReviews(db.DefaultContext, issues_model.FindReviewOptions{
+ IssueID: 2,
+ })
+ assert.NoError(t, err)
+ for _, r := range reviews {
+ assert.NoError(t, issues_model.DeleteReview(db.DefaultContext, r))
+ }
+ ctx.Data["ShowOutdatedComments"] = true
+ renderConversation(ctx, preparedComment, "diff")
+ assert.Equal(t, http.StatusOK, resp.Code)
+ assert.NotContains(t, resp.Body.String(), `status-page-500`)
+ })
+ run("timeline non-existing review", func(t *testing.T, ctx *context.Context, resp *httptest.ResponseRecorder) {
+ reviews, err := issues_model.FindReviews(db.DefaultContext, issues_model.FindReviewOptions{
+ IssueID: 2,
+ })
+ assert.NoError(t, err)
+ for _, r := range reviews {
+ assert.NoError(t, issues_model.DeleteReview(db.DefaultContext, r))
+ }
+ ctx.Data["ShowOutdatedComments"] = true
+ renderConversation(ctx, preparedComment, "timeline")
+ assert.Equal(t, http.StatusOK, resp.Code)
+ assert.NotContains(t, resp.Body.String(), `status-page-500`)
+ })
}
diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go
index 38bb1305fb..54e9aed207 100644
--- a/routers/web/repo/release.go
+++ b/routers/web/repo/release.go
@@ -11,6 +11,7 @@ import (
"strings"
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo"
@@ -18,6 +19,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
@@ -192,6 +194,7 @@ func Releases(ctx *context.Context) {
}
ctx.Data["Releases"] = releases
+ addVerifyTagToContext(ctx)
numReleases := ctx.Data["NumReleases"].(int64)
pager := context.NewPagination(int(numReleases), listOptions.PageSize, listOptions.Page, 5)
@@ -201,6 +204,44 @@ func Releases(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplReleasesList)
}
+func verifyTagSignature(ctx *context.Context, r *repo_model.Release) (*asymkey.ObjectVerification, error) {
+ if err := r.LoadAttributes(ctx); err != nil {
+ return nil, err
+ }
+ gitRepo, err := gitrepo.OpenRepository(ctx, r.Repo)
+ if err != nil {
+ return nil, err
+ }
+ defer gitRepo.Close()
+
+ tag, err := gitRepo.GetTag(r.TagName)
+ if err != nil {
+ return nil, err
+ }
+ if tag.Signature == nil {
+ return nil, nil
+ }
+
+ verification := asymkey.ParseTagWithSignature(ctx, gitRepo, tag)
+ return verification, nil
+}
+
+func addVerifyTagToContext(ctx *context.Context) {
+ ctx.Data["VerifyTag"] = func(r *repo_model.Release) *asymkey.ObjectVerification {
+ v, err := verifyTagSignature(ctx, r)
+ if err != nil {
+ return nil
+ }
+ return v
+ }
+ ctx.Data["HasSignature"] = func(verification *asymkey.ObjectVerification) bool {
+ if verification == nil {
+ return false
+ }
+ return verification.Reason != "gpg.error.not_signed_commit"
+ }
+}
+
// TagsList render tags list page
func TagsList(ctx *context.Context) {
ctx.Data["PageIsTagList"] = true
@@ -240,6 +281,7 @@ func TagsList(ctx *context.Context) {
}
ctx.Data["Releases"] = releases
+ addVerifyTagToContext(ctx)
numTags := ctx.Data["NumTags"].(int64)
pager := context.NewPagination(int(numTags), opts.PageSize, opts.Page, 5)
@@ -304,6 +346,7 @@ func SingleRelease(ctx *context.Context) {
if release.IsTag && release.Title == "" {
release.Title = release.TagName
}
+ addVerifyTagToContext(ctx)
ctx.Data["PageIsSingleTag"] = release.IsTag
if release.IsTag {
diff --git a/routers/web/repo/render.go b/routers/web/repo/render.go
index 10fa21c60e..e64db03e20 100644
--- a/routers/web/repo/render.go
+++ b/routers/web/repo/render.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
@@ -44,20 +45,17 @@ func RenderFile(ctx *context.Context) {
isTextFile := st.IsText()
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{})
+ ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'; sandbox allow-scripts")
if markupType := markup.Type(blob.Name()); markupType == "" {
if isTextFile {
- _, err = io.Copy(ctx.Resp, rd)
- if err != nil {
- ctx.ServerError("Copy", err)
- }
- return
+ _, _ = io.Copy(ctx.Resp, rd)
+ } else {
+ http.Error(ctx.Resp, "Unsupported file type render", http.StatusInternalServerError)
}
- ctx.Error(http.StatusInternalServerError, "Unsupported file type render")
return
}
- ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'; sandbox allow-scripts")
err = markup.Render(&markup.RenderContext{
Ctx: ctx,
RelativePath: ctx.Repo.TreePath,
@@ -71,7 +69,8 @@ func RenderFile(ctx *context.Context) {
InStandalonePage: true,
}, rd, ctx.Resp)
if err != nil {
- ctx.ServerError("Render", err)
+ log.Error("Failed to render file %q: %v", ctx.Repo.TreePath, err)
+ http.Error(ctx.Resp, "Failed to render file", http.StatusInternalServerError)
return
}
}
diff --git a/routers/web/repo/setting/webhook.go b/routers/web/repo/setting/webhook.go
index bf7770bfdb..4469eac9e8 100644
--- a/routers/web/repo/setting/webhook.go
+++ b/routers/web/repo/setting/webhook.go
@@ -45,6 +45,7 @@ func WebhookList(ctx *context.Context) {
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["BaseLink"] = ctx.Repo.RepoLink + "/settings/hooks"
ctx.Data["BaseLinkNew"] = ctx.Repo.RepoLink + "/settings/hooks"
+ ctx.Data["WebhookList"] = webhook_service.List()
ctx.Data["Description"] = ctx.Tr("repo.settings.hooks_desc", "https://forgejo.org/docs/latest/user/webhooks/")
ws, err := db.Find[webhook.Webhook](ctx, webhook.ListWebhookOptions{RepoID: ctx.Repo.Repository.ID})
@@ -132,13 +133,16 @@ func WebhookNew(ctx *context.Context) {
}
hookType := ctx.Params(":type")
- if webhook_service.GetWebhookHandler(hookType) == nil {
+ handler := webhook_service.GetWebhookHandler(hookType)
+ if handler == nil {
ctx.NotFound("GetWebhookHandler", nil)
return
}
ctx.Data["HookType"] = hookType
+ ctx.Data["WebhookHandler"] = handler
ctx.Data["BaseLink"] = orCtx.LinkNew
ctx.Data["BaseLinkNew"] = orCtx.LinkNew
+ ctx.Data["WebhookList"] = webhook_service.List()
ctx.HTML(http.StatusOK, orCtx.NewTemplate)
}
@@ -194,6 +198,7 @@ func WebhookCreate(ctx *context.Context) {
ctx.Data["PageIsSettingsHooksNew"] = true
ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}}
ctx.Data["HookType"] = hookType
+ ctx.Data["WebhookHandler"] = handler
orCtx, err := getOwnerRepoCtx(ctx)
if err != nil {
@@ -202,6 +207,7 @@ func WebhookCreate(ctx *context.Context) {
}
ctx.Data["BaseLink"] = orCtx.LinkNew
ctx.Data["BaseLinkNew"] = orCtx.LinkNew
+ ctx.Data["WebhookList"] = webhook_service.List()
if ctx.HasError() {
// pre-fill the form with the submitted data
@@ -336,6 +342,7 @@ func checkWebhook(ctx *context.Context) (*ownerRepoCtx, *webhook.Webhook) {
}
ctx.Data["BaseLink"] = orCtx.Link
ctx.Data["BaseLinkNew"] = orCtx.LinkNew
+ ctx.Data["WebhookList"] = webhook_service.List()
var w *webhook.Webhook
if orCtx.RepoID > 0 {
@@ -358,6 +365,7 @@ func checkWebhook(ctx *context.Context) (*ownerRepoCtx, *webhook.Webhook) {
if handler := webhook_service.GetWebhookHandler(w.Type); handler != nil {
ctx.Data["HookMetadata"] = handler.Metadata(w)
+ ctx.Data["WebhookHandler"] = handler
}
ctx.Data["History"], err = w.History(ctx, 1)
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index becb8748cd..a65a100212 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -938,9 +938,9 @@ func prepareOpenWithEditorApps(ctx *context.Context) {
schema, _, _ := strings.Cut(app.OpenURL, ":")
var iconHTML template.HTML
if schema == "vscode" || schema == "vscodium" || schema == "jetbrains" {
- iconHTML = svg.RenderHTML(fmt.Sprintf("gitea-open-with-%s", schema), 16, "gt-mr-3")
+ iconHTML = svg.RenderHTML(fmt.Sprintf("gitea-open-with-%s", schema), 16, "tw-mr-2")
} else {
- iconHTML = svg.RenderHTML("gitea-git", 16, "gt-mr-3") // TODO: it could support user's customized icon in the future
+ iconHTML = svg.RenderHTML("gitea-git", 16, "tw-mr-2") // TODO: it could support user's customized icon in the future
}
tmplApps = append(tmplApps, map[string]any{
"DisplayName": app.DisplayName,
diff --git a/routers/web/user/setting/webhooks.go b/routers/web/user/setting/webhooks.go
index 4423b62781..3cc67d9def 100644
--- a/routers/web/user/setting/webhooks.go
+++ b/routers/web/user/setting/webhooks.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/context"
+ webhook_service "code.gitea.io/gitea/services/webhook"
)
const (
@@ -23,6 +24,7 @@ func Webhooks(ctx *context.Context) {
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["BaseLink"] = setting.AppSubURL + "/user/settings/hooks"
ctx.Data["BaseLinkNew"] = setting.AppSubURL + "/user/settings/hooks"
+ ctx.Data["WebhookList"] = webhook_service.List()
ctx.Data["Description"] = ctx.Tr("settings.hooks.desc")
ws, err := db.Find[webhook.Webhook](ctx, webhook.ListWebhookOptions{OwnerID: ctx.Doer.ID})
diff --git a/routers/web/web.go b/routers/web/web.go
index 7329acd155..40f4ffc018 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -986,7 +986,6 @@ func registerRoutes(m *web.Route) {
m.Put("", web.Bind(forms.EditProjectBoardForm{}), org.EditProjectBoard)
m.Delete("", org.DeleteProjectBoard)
m.Post("/default", org.SetDefaultProjectBoard)
- m.Post("/unsetdefault", org.UnsetDefaultProjectBoard)
m.Post("/move", org.MoveIssues)
})
@@ -1360,7 +1359,6 @@ func registerRoutes(m *web.Route) {
m.Put("", web.Bind(forms.EditProjectBoardForm{}), repo.EditProjectBoard)
m.Delete("", repo.DeleteProjectBoard)
m.Post("/default", repo.SetDefaultProjectBoard)
- m.Post("/unsetdefault", repo.UnSetDefaultProjectBoard)
m.Post("/move", repo.MoveIssues)
})