forked from NYANDEV/forgejo
bb2ad0dd87
- Fix problem caused by the clearer confirmation for dangerous actions commit.
(cherry picked from commit 3488f4a9cb1f7f73103ae0017d644f13ca3ab798)
(cherry picked from commit ed7de91f6ace23a1459bc6552edf719d62c7c941)
(cherry picked from commit 2d97929b9b7b8d979eb12bf0994d3f169d41f7fd)
(cherry picked from commit 50d035a7b058b9c4486c38cd4be0b02a4e1bf4d9)
(cherry picked from commit 0a0c07d78a1dee3489b97ab359bb957e3f7fb94b)
(cherry picked from commit 85e55c4dbc2f513f3d5254dac20915e8c3c22886)
(cherry picked from commit d8282122ad6e8b497de35d1ed89e3093a2cd5ee2)
(cherry picked from commit 3f0b3b6cc5
)
388 lines
14 KiB
Go
388 lines
14 KiB
Go
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package integration
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"path"
|
|
"strconv"
|
|
"testing"
|
|
|
|
issue_model "code.gitea.io/gitea/models/issues"
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
|
"code.gitea.io/gitea/models/unittest"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
forgejo_context "code.gitea.io/gitea/modules/context"
|
|
"code.gitea.io/gitea/modules/translation"
|
|
"code.gitea.io/gitea/tests"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func BlockUser(t *testing.T, doer, blockedUser *user_model.User) {
|
|
t.Helper()
|
|
|
|
unittest.AssertNotExistsBean(t, &user_model.BlockedUser{BlockID: blockedUser.ID, UserID: doer.ID})
|
|
|
|
session := loginUser(t, doer.Name)
|
|
req := NewRequestWithValues(t, "POST", "/"+blockedUser.Name, map[string]string{
|
|
"_csrf": GetCSRF(t, session, "/"+blockedUser.Name),
|
|
"action": "block",
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
type redirect struct {
|
|
Redirect string `json:"redirect"`
|
|
}
|
|
|
|
var respBody redirect
|
|
DecodeJSON(t, resp, &respBody)
|
|
assert.EqualValues(t, "/"+blockedUser.Name, respBody.Redirect)
|
|
assert.True(t, unittest.BeanExists(t, &user_model.BlockedUser{BlockID: blockedUser.ID, UserID: doer.ID}))
|
|
}
|
|
|
|
// TestBlockUser ensures that users can execute blocking related actions can
|
|
// happen under the correct conditions.
|
|
func TestBlockUser(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 8})
|
|
blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
session := loginUser(t, doer.Name)
|
|
|
|
t.Run("Block", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
BlockUser(t, doer, blockedUser)
|
|
})
|
|
|
|
// Unblock user.
|
|
t.Run("Unblock", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
req := NewRequestWithValues(t, "POST", "/"+blockedUser.Name, map[string]string{
|
|
"_csrf": GetCSRF(t, session, "/"+blockedUser.Name),
|
|
"action": "unblock",
|
|
})
|
|
session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
unittest.AssertNotExistsBean(t, &user_model.BlockedUser{BlockID: blockedUser.ID, UserID: doer.ID})
|
|
})
|
|
|
|
t.Run("Organization as target", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
targetOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3, Type: user_model.UserTypeOrganization})
|
|
|
|
t.Run("Block", func(t *testing.T) {
|
|
req := NewRequestWithValues(t, "POST", "/"+targetOrg.Name, map[string]string{
|
|
"_csrf": GetCSRF(t, session, "/"+targetOrg.Name),
|
|
"action": "block",
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusBadRequest)
|
|
|
|
assert.Contains(t, resp.Body.String(), "Action \\\"block\\\" failed")
|
|
})
|
|
|
|
t.Run("Unblock", func(t *testing.T) {
|
|
req := NewRequestWithValues(t, "POST", "/"+targetOrg.Name, map[string]string{
|
|
"_csrf": GetCSRF(t, session, "/"+targetOrg.Name),
|
|
"action": "unblock",
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusBadRequest)
|
|
|
|
assert.Contains(t, resp.Body.String(), "Action \\\"unblock\\\" failed")
|
|
})
|
|
})
|
|
}
|
|
|
|
// TestBlockUserFromOrganization ensures that an organisation can block and unblock an user.
|
|
func TestBlockUserFromOrganization(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
|
|
blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17, Type: user_model.UserTypeOrganization})
|
|
unittest.AssertNotExistsBean(t, &user_model.BlockedUser{BlockID: blockedUser.ID, UserID: org.ID})
|
|
session := loginUser(t, doer.Name)
|
|
|
|
t.Run("Block user", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
req := NewRequestWithValues(t, "POST", org.OrganisationLink()+"/settings/blocked_users/block", map[string]string{
|
|
"_csrf": GetCSRF(t, session, org.OrganisationLink()+"/settings/blocked_users"),
|
|
"uname": blockedUser.Name,
|
|
})
|
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
|
assert.True(t, unittest.BeanExists(t, &user_model.BlockedUser{BlockID: blockedUser.ID, UserID: org.ID}))
|
|
})
|
|
|
|
t.Run("Unblock user", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
req := NewRequestWithValues(t, "POST", org.OrganisationLink()+"/settings/blocked_users/unblock", map[string]string{
|
|
"_csrf": GetCSRF(t, session, org.OrganisationLink()+"/settings/blocked_users"),
|
|
"user_id": strconv.FormatInt(blockedUser.ID, 10),
|
|
})
|
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
|
unittest.AssertNotExistsBean(t, &user_model.BlockedUser{BlockID: blockedUser.ID, UserID: org.ID})
|
|
})
|
|
|
|
t.Run("Organization as target", func(t *testing.T) {
|
|
targetOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3, Type: user_model.UserTypeOrganization})
|
|
|
|
t.Run("Block", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
req := NewRequestWithValues(t, "POST", org.OrganisationLink()+"/settings/blocked_users/block", map[string]string{
|
|
"_csrf": GetCSRF(t, session, org.OrganisationLink()+"/settings/blocked_users"),
|
|
"uname": targetOrg.Name,
|
|
})
|
|
session.MakeRequest(t, req, http.StatusInternalServerError)
|
|
unittest.AssertNotExistsBean(t, &user_model.BlockedUser{BlockID: blockedUser.ID, UserID: targetOrg.ID})
|
|
})
|
|
|
|
t.Run("Unblock", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
req := NewRequestWithValues(t, "POST", org.OrganisationLink()+"/settings/blocked_users/unblock", map[string]string{
|
|
"_csrf": GetCSRF(t, session, org.OrganisationLink()+"/settings/blocked_users"),
|
|
"user_id": strconv.FormatInt(targetOrg.ID, 10),
|
|
})
|
|
session.MakeRequest(t, req, http.StatusInternalServerError)
|
|
})
|
|
})
|
|
}
|
|
|
|
// TestBlockActions ensures that certain actions cannot be performed as a doer
|
|
// and as a blocked user and are handled cleanly after the blocking has taken
|
|
// place.
|
|
func TestBlockActions(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
blockedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
blockedUser2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10})
|
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerID: doer.ID})
|
|
repo7 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 7, OwnerID: blockedUser2.ID})
|
|
issue4 := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4, RepoID: repo2.ID})
|
|
issue4URL := fmt.Sprintf("/%s/issues/%d", repo2.FullName(), issue4.Index)
|
|
// NOTE: Sessions shouldn't be shared, because in some situations flash
|
|
// messages are persistent and that would interfere with accurate test
|
|
// results.
|
|
|
|
BlockUser(t, doer, blockedUser)
|
|
BlockUser(t, doer, blockedUser2)
|
|
|
|
// Ensures that issue creation on doer's ownen repositories are blocked.
|
|
t.Run("Issue creation", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
session := loginUser(t, blockedUser.Name)
|
|
link := fmt.Sprintf("%s/issues/new", repo2.FullName())
|
|
|
|
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
|
"_csrf": GetCSRF(t, session, link),
|
|
"title": "Title",
|
|
"content": "Hello!",
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
|
assert.Contains(t,
|
|
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
|
translation.NewLocale("en-US").Tr("repo.issues.blocked_by_user"),
|
|
)
|
|
})
|
|
|
|
// Ensures that comment creation on doer's owned repositories and doer's
|
|
// posted issues are blocked.
|
|
t.Run("Comment creation", func(t *testing.T) {
|
|
expectedFlash := "error%3DYou%2Bcannot%2Bcreate%2Ba%2Bcomment%2Bon%2Bthis%2Bissue%2Bbecause%2Byou%2Bare%2Bblocked%2Bby%2Bthe%2Brepository%2Bowner%2Bor%2Bthe%2Bposter%2Bof%2Bthe%2Bissue."
|
|
|
|
t.Run("Blocked by repository owner", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
session := loginUser(t, blockedUser.Name)
|
|
|
|
req := NewRequestWithValues(t, "POST", path.Join(issue4URL, "/comments"), map[string]string{
|
|
"_csrf": GetCSRF(t, session, issue4URL),
|
|
"content": "Not a kind comment",
|
|
})
|
|
session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
flashCookie := session.GetCookie(forgejo_context.CookieNameFlash)
|
|
assert.NotNil(t, flashCookie)
|
|
assert.EqualValues(t, expectedFlash, flashCookie.Value)
|
|
})
|
|
|
|
t.Run("Blocked by issue poster", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
repo5 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5})
|
|
issue15 := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 15, RepoID: repo5.ID, PosterID: doer.ID})
|
|
|
|
session := loginUser(t, blockedUser.Name)
|
|
issueURL := fmt.Sprintf("/%s/%s/issues/%d", url.PathEscape(repo5.OwnerName), url.PathEscape(repo5.Name), issue15.Index)
|
|
|
|
req := NewRequestWithValues(t, "POST", path.Join(issueURL, "/comments"), map[string]string{
|
|
"_csrf": GetCSRF(t, session, issueURL),
|
|
"content": "Not a kind comment",
|
|
})
|
|
session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
flashCookie := session.GetCookie(forgejo_context.CookieNameFlash)
|
|
assert.NotNil(t, flashCookie)
|
|
assert.EqualValues(t, expectedFlash, flashCookie.Value)
|
|
})
|
|
})
|
|
|
|
// Ensures that reactions on doer's owned issues and doer's owned comments are
|
|
// blocked.
|
|
t.Run("Add a reaction", func(t *testing.T) {
|
|
type reactionResponse struct {
|
|
Empty bool `json:"empty"`
|
|
}
|
|
|
|
t.Run("On a issue", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
session := loginUser(t, blockedUser.Name)
|
|
|
|
req := NewRequestWithValues(t, "POST", path.Join(issue4URL, "/reactions/react"), map[string]string{
|
|
"_csrf": GetCSRF(t, session, issue4URL),
|
|
"content": "eyes",
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
var respBody reactionResponse
|
|
DecodeJSON(t, resp, &respBody)
|
|
|
|
assert.EqualValues(t, true, respBody.Empty)
|
|
})
|
|
|
|
t.Run("On a comment", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{ID: 8, PosterID: doer.ID, IssueID: issue4.ID})
|
|
|
|
session := loginUser(t, blockedUser.Name)
|
|
|
|
req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/comments/%d/reactions/react", repo2.FullName(), comment.ID), map[string]string{
|
|
"_csrf": GetCSRF(t, session, issue4URL),
|
|
"content": "eyes",
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
var respBody reactionResponse
|
|
DecodeJSON(t, resp, &respBody)
|
|
|
|
assert.EqualValues(t, true, respBody.Empty)
|
|
})
|
|
})
|
|
|
|
// Ensures that the doer and blocked user cannot follow each other.
|
|
t.Run("Follow", func(t *testing.T) {
|
|
// Sanity checks to make sure doing these tests are valid.
|
|
unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: doer.ID, FollowID: blockedUser.ID})
|
|
unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: blockedUser.ID, FollowID: doer.ID})
|
|
|
|
// Doer cannot follow blocked user.
|
|
t.Run("Doer follow blocked user", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
session := loginUser(t, doer.Name)
|
|
|
|
req := NewRequestWithValues(t, "POST", "/"+blockedUser.Name, map[string]string{
|
|
"_csrf": GetCSRF(t, session, "/"+blockedUser.Name),
|
|
"action": "follow",
|
|
})
|
|
session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
flashCookie := session.GetCookie(forgejo_context.CookieNameFlash)
|
|
assert.NotNil(t, flashCookie)
|
|
assert.EqualValues(t, "error%3DYou%2Bcannot%2Bfollow%2Bthis%2Buser%2Bbecause%2Byou%2Bhave%2Bblocked%2Bthis%2Buser%2Bor%2Bthis%2Buser%2Bhas%2Bblocked%2Byou.", flashCookie.Value)
|
|
|
|
// Assert it still doesn't exist.
|
|
unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: doer.ID, FollowID: blockedUser.ID})
|
|
})
|
|
|
|
// Blocked user cannot follow doer.
|
|
t.Run("Blocked user follow doer", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
session := loginUser(t, blockedUser.Name)
|
|
|
|
req := NewRequestWithValues(t, "POST", "/"+doer.Name, map[string]string{
|
|
"_csrf": GetCSRF(t, session, "/"+doer.Name),
|
|
"action": "follow",
|
|
})
|
|
session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
flashCookie := session.GetCookie(forgejo_context.CookieNameFlash)
|
|
assert.NotNil(t, flashCookie)
|
|
assert.EqualValues(t, "error%3DYou%2Bcannot%2Bfollow%2Bthis%2Buser%2Bbecause%2Byou%2Bhave%2Bblocked%2Bthis%2Buser%2Bor%2Bthis%2Buser%2Bhas%2Bblocked%2Byou.", flashCookie.Value)
|
|
|
|
unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: blockedUser.ID, FollowID: doer.ID})
|
|
})
|
|
})
|
|
|
|
// Ensures that the doer and blocked user cannot add each each other as collaborators.
|
|
t.Run("Add collaborator", func(t *testing.T) {
|
|
t.Run("Doer Add BlockedUser", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
session := loginUser(t, doer.Name)
|
|
link := fmt.Sprintf("/%s/settings/collaboration", repo2.FullName())
|
|
|
|
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
|
"_csrf": GetCSRF(t, session, link),
|
|
"collaborator": blockedUser2.Name,
|
|
})
|
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
flashCookie := session.GetCookie(forgejo_context.CookieNameFlash)
|
|
assert.NotNil(t, flashCookie)
|
|
assert.EqualValues(t, "error%3DCannot%2Badd%2Bthe%2Bcollaborator%252C%2Bbecause%2Bthe%2Brepository%2Bowner%2Bhas%2Bblocked%2Bthem.", flashCookie.Value)
|
|
})
|
|
|
|
t.Run("BlockedUser Add doer", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
session := loginUser(t, blockedUser2.Name)
|
|
link := fmt.Sprintf("/%s/settings/collaboration", repo7.FullName())
|
|
|
|
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
|
"_csrf": GetCSRF(t, session, link),
|
|
"collaborator": doer.Name,
|
|
})
|
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
flashCookie := session.GetCookie(forgejo_context.CookieNameFlash)
|
|
assert.NotNil(t, flashCookie)
|
|
assert.EqualValues(t, "error%3DCannot%2Badd%2Bthe%2Bcollaborator%252C%2Bbecause%2Bthey%2Bhave%2Bblocked%2Bthe%2Brepository%2Bowner.", flashCookie.Value)
|
|
})
|
|
})
|
|
|
|
// Ensures that the blocked user cannot transfer a repository to the doer.
|
|
t.Run("Repository transfer", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
session := loginUser(t, blockedUser2.Name)
|
|
link := fmt.Sprintf("%s/settings", repo7.FullName())
|
|
|
|
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
|
"_csrf": GetCSRF(t, session, link),
|
|
"action": "transfer",
|
|
"repo_name": repo7.FullName(),
|
|
"new_owner_name": doer.Name,
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
|
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
|
assert.Contains(t,
|
|
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
|
translation.NewLocale("en-US").Tr("repo.settings.new_owner_blocked_doer"),
|
|
)
|
|
})
|
|
}
|