forked from NYANDEV/forgejo
[GITEA] Make confirmation clearer for dangerous actions
- Currently the confirmation for dangerous actions such as transferring the repository or deleting it only requires the user to ~~copy paste~~ type the repository name. - This can be problematic when the user has a fork or another repository with the same name as an organization's repository, and the confirmation doesn't make clear that it could be deleting the wrong repository. While it's mentioned in the dialog, it's better to be on the safe side and also add the owner's name to be an element that has to be typed for these dangerous actions. - Added integration tests. (cherry picked from commit bf679b24dd23c9ed586b9439e293bbd27cc89232) (cherry picked from commit 1963085dd9d1521b7a4aa8558d409bd1a9f2e1da) (cherry picked from commit fb94095d1992c3e47f03e0fccc98a90707a5271b) (cherry picked from commit e1d1e46afee6891becdb6ccd027fc66843b56db9) (cherry picked from commit 93993029e4ec8a20a8bc38d80bb4b801e52ee1b7) (cherry picked from commit df3b058179d8f3e06cc6fb335b287c72c8952821) (cherry picked from commit 8ccc6b9cba46a736665e4b25523da0baf1679702)
This commit is contained in:
parent
6d882ede35
commit
9fbe28fca3
4 changed files with 150 additions and 11 deletions
|
@ -681,7 +681,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
ctx.Error(http.StatusNotFound)
|
ctx.Error(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if repo.Name != form.RepoName {
|
if repo.FullName() != form.RepoName {
|
||||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -712,7 +712,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
ctx.ServerError("Convert Fork", err)
|
ctx.ServerError("Convert Fork", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if repo.Name != form.RepoName {
|
if repo.FullName() != form.RepoName {
|
||||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -745,7 +745,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
ctx.Error(http.StatusNotFound)
|
ctx.Error(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if repo.Name != form.RepoName {
|
if repo.FullName() != form.RepoName {
|
||||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -827,7 +827,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
ctx.Error(http.StatusNotFound)
|
ctx.Error(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if repo.Name != form.RepoName {
|
if repo.FullName() != form.RepoName {
|
||||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -851,7 +851,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
ctx.Error(http.StatusNotFound)
|
ctx.Error(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if repo.Name != form.RepoName {
|
if repo.FullName() != form.RepoName {
|
||||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -816,7 +816,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>
|
<label>
|
||||||
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
||||||
<span class="text red">{{.Repository.Name}}</span>
|
<span class="text red">{{.Repository.FullName}}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="required field">
|
<div class="required field">
|
||||||
|
@ -847,7 +847,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>
|
<label>
|
||||||
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
||||||
<span class="text red">{{.Repository.Name}}</span>
|
<span class="text red">{{.Repository.FullName}}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="required field">
|
<div class="required field">
|
||||||
|
@ -879,7 +879,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>
|
<label>
|
||||||
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
||||||
<span class="text red">{{.Repository.Name}}</span>
|
<span class="text red">{{.Repository.FullName}}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="required field">
|
<div class="required field">
|
||||||
|
@ -917,7 +917,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>
|
<label>
|
||||||
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
||||||
<span class="text red">{{.Repository.Name}}</span>
|
<span class="text red">{{.Repository.FullName}}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="required field">
|
<div class="required field">
|
||||||
|
@ -949,7 +949,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>
|
<label>
|
||||||
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
{{ctx.Locale.Tr "repo.settings.transfer_form_title"}}
|
||||||
<span class="text red">{{.Repository.Name}}</span>
|
<span class="text red">{{.Repository.FullName}}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="required field">
|
<div class="required field">
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -129,7 +130,7 @@ func testDeleteRepository(t *testing.T, session *TestSession, ownerName, repoNam
|
||||||
|
|
||||||
req = NewRequestWithValues(t, "POST", relURL+"?action=delete", map[string]string{
|
req = NewRequestWithValues(t, "POST", relURL+"?action=delete", map[string]string{
|
||||||
"_csrf": htmlDoc.GetCSRF(),
|
"_csrf": htmlDoc.GetCSRF(),
|
||||||
"repo_name": repoName,
|
"repo_name": fmt.Sprintf("%s/%s", ownerName, repoName),
|
||||||
})
|
})
|
||||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,15 @@ package integration
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
gitea_context "code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/translation"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
|
@ -448,3 +451,138 @@ func TestGeneratedSourceLink(t *testing.T) {
|
||||||
assert.Equal(t, "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
|
assert.Equal(t, "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDangerZoneConfirmation(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
mustInvalidRepoName := func(resp *httptest.ResponseRecorder) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
assert.Contains(t,
|
||||||
|
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
||||||
|
translation.NewLocale("en-US").Tr("form.enterred_invalid_repo_name"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Transfer ownership", func(t *testing.T) {
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
|
||||||
|
t.Run("Fail", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings", map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, "/user2/repo1/settings"),
|
||||||
|
"action": "transfer",
|
||||||
|
"repo_name": "repo1",
|
||||||
|
"new_owner_name": "user1",
|
||||||
|
})
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
mustInvalidRepoName(resp)
|
||||||
|
})
|
||||||
|
t.Run("Pass", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings", map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, "/user2/repo1/settings"),
|
||||||
|
"action": "transfer",
|
||||||
|
"repo_name": "user2/repo1",
|
||||||
|
"new_owner_name": "user1",
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
|
||||||
|
flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
|
||||||
|
assert.NotNil(t, flashCookie)
|
||||||
|
assert.EqualValues(t, flashCookie.Value, "success%3DThis%2Brepository%2Bhas%2Bbeen%2Bmarked%2Bfor%2Btransfer%2Band%2Bawaits%2Bconfirmation%2Bfrom%2B%2522User%2BOne%2522")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Convert fork", func(t *testing.T) {
|
||||||
|
session := loginUser(t, "user20")
|
||||||
|
|
||||||
|
t.Run("Fail", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequestWithValues(t, "POST", "/user20/big_test_public_fork_7/settings", map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, "/user20/big_test_public_fork_7/settings"),
|
||||||
|
"action": "convert_fork",
|
||||||
|
"repo_name": "big_test_public_fork_7",
|
||||||
|
})
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
mustInvalidRepoName(resp)
|
||||||
|
})
|
||||||
|
t.Run("Pass", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequestWithValues(t, "POST", "/user20/big_test_public_fork_7/settings", map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, "/user20/big_test_public_fork_7/settings"),
|
||||||
|
"action": "convert_fork",
|
||||||
|
"repo_name": "user20/big_test_public_fork_7",
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
|
||||||
|
flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
|
||||||
|
assert.NotNil(t, flashCookie)
|
||||||
|
assert.EqualValues(t, flashCookie.Value, "success%3DThe%2Bfork%2Bhas%2Bbeen%2Bconverted%2Binto%2Ba%2Bregular%2Brepository.")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Delete wiki", func(t *testing.T) {
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
|
||||||
|
t.Run("Fail", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings", map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, "/user2/repo1/settings"),
|
||||||
|
"action": "delete-wiki",
|
||||||
|
"repo_name": "repo1",
|
||||||
|
})
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
mustInvalidRepoName(resp)
|
||||||
|
})
|
||||||
|
t.Run("Pass", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings", map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, "/user2/repo1/settings"),
|
||||||
|
"action": "delete-wiki",
|
||||||
|
"repo_name": "user2/repo1",
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
|
||||||
|
flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
|
||||||
|
assert.NotNil(t, flashCookie)
|
||||||
|
assert.EqualValues(t, flashCookie.Value, "success%3DThe%2Brepository%2Bwiki%2Bdata%2Bhas%2Bbeen%2Bdeleted.")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Delete", func(t *testing.T) {
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
|
||||||
|
t.Run("Fail", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings", map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, "/user2/repo1/settings"),
|
||||||
|
"action": "delete",
|
||||||
|
"repo_name": "repo1",
|
||||||
|
})
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
mustInvalidRepoName(resp)
|
||||||
|
})
|
||||||
|
t.Run("Pass", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings", map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, "/user2/repo1/settings"),
|
||||||
|
"action": "delete",
|
||||||
|
"repo_name": "user2/repo1",
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
|
||||||
|
flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
|
||||||
|
assert.NotNil(t, flashCookie)
|
||||||
|
assert.EqualValues(t, flashCookie.Value, "success%3DThe%2Brepository%2Bhas%2Bbeen%2Bdeleted.")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue