Skip to content

Commit 53e65fa

Browse files
committed
Catch and handle unallowed file type errors in issue attachment API
Before, we would just throw 500 if a user passes an attachment that is not an allowed type (whether this means its sniffed MIME type or its file extension). This commit catches this error and throws a 422 instead since this is a validation error.
1 parent a988237 commit 53e65fa

File tree

5 files changed

+78
-2
lines changed

5 files changed

+78
-2
lines changed

routers/api/v1/repo/issue_attachment.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"code.gitea.io/gitea/modules/web"
1515
"code.gitea.io/gitea/services/attachment"
1616
"code.gitea.io/gitea/services/context"
17+
"code.gitea.io/gitea/services/context/upload"
1718
"code.gitea.io/gitea/services/convert"
1819
issue_service "code.gitea.io/gitea/services/issue"
1920
)
@@ -153,6 +154,8 @@ func CreateIssueAttachment(ctx *context.APIContext) {
153154
// "$ref": "#/responses/error"
154155
// "404":
155156
// "$ref": "#/responses/error"
157+
// "422":
158+
// "$ref": "#/responses/validationError"
156159
// "423":
157160
// "$ref": "#/responses/repoArchivedError"
158161

@@ -185,7 +188,11 @@ func CreateIssueAttachment(ctx *context.APIContext) {
185188
IssueID: issue.ID,
186189
})
187190
if err != nil {
188-
ctx.Error(http.StatusInternalServerError, "UploadAttachment", err)
191+
if upload.IsErrFileTypeForbidden(err) {
192+
ctx.Error(http.StatusUnprocessableEntity, "", err)
193+
} else {
194+
ctx.Error(http.StatusInternalServerError, "UploadAttachment", err)
195+
}
189196
return
190197
}
191198

routers/api/v1/repo/issue_comment_attachment.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"code.gitea.io/gitea/modules/web"
1717
"code.gitea.io/gitea/services/attachment"
1818
"code.gitea.io/gitea/services/context"
19+
"code.gitea.io/gitea/services/context/upload"
1920
"code.gitea.io/gitea/services/convert"
2021
issue_service "code.gitea.io/gitea/services/issue"
2122
)
@@ -160,6 +161,8 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
160161
// "$ref": "#/responses/forbidden"
161162
// "404":
162163
// "$ref": "#/responses/error"
164+
// "422":
165+
// "$ref": "#/responses/validationError"
163166
// "423":
164167
// "$ref": "#/responses/repoArchivedError"
165168

@@ -194,9 +197,14 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
194197
CommentID: comment.ID,
195198
})
196199
if err != nil {
197-
ctx.Error(http.StatusInternalServerError, "UploadAttachment", err)
200+
if upload.IsErrFileTypeForbidden(err) {
201+
ctx.Error(http.StatusUnprocessableEntity, "", err)
202+
} else {
203+
ctx.Error(http.StatusInternalServerError, "UploadAttachment", err)
204+
}
198205
return
199206
}
207+
200208
if err := comment.LoadAttachments(ctx); err != nil {
201209
ctx.Error(http.StatusInternalServerError, "LoadAttachments", err)
202210
return

templates/swagger/v1_json.tmpl

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/integration/api_comment_attachment_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,34 @@ func TestAPICreateCommentAttachment(t *testing.T) {
120120
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachment.ID, CommentID: comment.ID})
121121
}
122122

123+
func TestAPICreateCommentAttachmentWithUnallowedFile(t *testing.T) {
124+
defer tests.PrepareTestEnv(t)()
125+
126+
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2})
127+
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
128+
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
129+
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
130+
131+
session := loginUser(t, repoOwner.Name)
132+
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue)
133+
134+
filename := "iambad.bad"
135+
body := &bytes.Buffer{}
136+
137+
// Setup multi-part.
138+
writer := multipart.NewWriter(body)
139+
_, err := writer.CreateFormFile("attachment", filename)
140+
assert.NoError(t, err)
141+
err = writer.Close()
142+
assert.NoError(t, err)
143+
144+
req := NewRequestWithBody(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d/assets", repoOwner.Name, repo.Name, comment.ID), body).
145+
AddTokenAuth(token).
146+
SetHeader("Content-Type", writer.FormDataContentType())
147+
148+
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
149+
}
150+
123151
func TestAPIEditCommentAttachment(t *testing.T) {
124152
defer tests.PrepareTestEnv(t)()
125153

tests/integration/api_issue_attachment_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,33 @@ func TestAPICreateIssueAttachment(t *testing.T) {
9696
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: apiAttachment.ID, IssueID: issue.ID})
9797
}
9898

99+
func TestAPICreateIssueAttachmentWithUnallowedFile(t *testing.T) {
100+
defer tests.PrepareTestEnv(t)()
101+
102+
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
103+
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID})
104+
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
105+
106+
session := loginUser(t, repoOwner.Name)
107+
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue)
108+
109+
filename := "iambad.bad"
110+
body := &bytes.Buffer{}
111+
112+
// Setup multi-part.
113+
writer := multipart.NewWriter(body)
114+
_, err := writer.CreateFormFile("attachment", filename)
115+
assert.NoError(t, err)
116+
err = writer.Close()
117+
assert.NoError(t, err)
118+
119+
req := NewRequestWithBody(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/assets", repoOwner.Name, repo.Name, issue.Index), body).
120+
AddTokenAuth(token)
121+
req.Header.Add("Content-Type", writer.FormDataContentType())
122+
123+
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
124+
}
125+
99126
func TestAPIEditIssueAttachment(t *testing.T) {
100127
defer tests.PrepareTestEnv(t)()
101128

0 commit comments

Comments
 (0)