From 9430badc5c8245b287c6ec2ba9432324c2e95417 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20Dachary?= <loic@dachary.org>
Date: Mon, 20 Nov 2023 16:34:04 +0100
Subject: [PATCH] [GITEA] test POST
 /{username}/{reponame}/{type:issues|pulls}/move_pin

Refs: https://forgejo.org/2023-11-release-v1-20-5-1/#api-and-web-endpoint-vulnerable-to-manually-crafted-identifiers

(cherry picked from commit 52f50792606a22cbf1e144e1bd480984abf6f53f)
(cherry picked from commit 65b942fa1ee50f9098bebc8948d7924a5a4668fa)
(cherry picked from commit e140c5c983e3413dcfab45f5e522dfdc3feda26e)
(cherry picked from commit 4d108fa1cf07d2ecc7a482010e75f36140657dd4)
---
 tests/integration/issue_test.go | 42 +++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go
index b1080c998a..82eea374b8 100644
--- a/tests/integration/issue_test.go
+++ b/tests/integration/issue_test.go
@@ -607,3 +607,45 @@ func TestUpdateIssueDeadline(t *testing.T) {
 
 	assert.EqualValues(t, "2022-04-06", apiIssue.Deadline.Format("2006-01-02"))
 }
+
+func TestIssuePinMove(t *testing.T) {
+	defer tests.PrepareTestEnv(t)()
+	session := loginUser(t, "user2")
+	issueURL, issue := testIssueWithBean(t, "user2", 1, "Title", "Content")
+	assert.EqualValues(t, 0, issue.PinOrder)
+
+	req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/pin", issueURL), map[string]string{
+		"_csrf": GetCSRF(t, session, issueURL),
+	})
+	session.MakeRequest(t, req, http.StatusOK)
+	issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID})
+
+	position := 1
+	assert.EqualValues(t, position, issue.PinOrder)
+
+	newPosition := 2
+
+	// Using the ID of an issue that does not belong to the repository must fail
+	{
+		session5 := loginUser(t, "user5")
+		movePinURL := "/user5/repo4/issues/move_pin?_csrf=" + GetCSRF(t, session5, issueURL)
+		req = NewRequestWithJSON(t, "POST", movePinURL, map[string]any{
+			"id":       issue.ID,
+			"position": newPosition,
+		})
+		session5.MakeRequest(t, req, http.StatusNotFound)
+
+		issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID})
+		assert.EqualValues(t, position, issue.PinOrder)
+	}
+
+	movePinURL := issueURL[:strings.LastIndexByte(issueURL, '/')] + "/move_pin?_csrf=" + GetCSRF(t, session, issueURL)
+	req = NewRequestWithJSON(t, "POST", movePinURL, map[string]any{
+		"id":       issue.ID,
+		"position": newPosition,
+	})
+	session.MakeRequest(t, req, http.StatusNoContent)
+
+	issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID})
+	assert.EqualValues(t, newPosition, issue.PinOrder)
+}