enhance(repo): check full repo name for dangerous operations (#39213)

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Mitrahsoft
2026-09-02 22:37:04 +05:30
committed by GitHub
parent f735df4dee
commit 8cf7330556
8 changed files with 67 additions and 70 deletions

View File

@@ -790,7 +790,7 @@ func handleSettingsPostConvert(ctx *context.Context) {
form := web.GetForm[*forms.RepoSettingForm](ctx) form := web.GetForm[*forms.RepoSettingForm](ctx)
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
if repo.Name != form.RepoName { if repo.FullName() != form.RepoName {
ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return return
} }
@@ -824,7 +824,7 @@ func handleSettingsPostConvertFork(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.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return return
} }
@@ -860,7 +860,7 @@ func handleSettingsPostTransfer(ctx *context.Context) {
form := web.GetForm[*forms.RepoSettingForm](ctx) form := web.GetForm[*forms.RepoSettingForm](ctx)
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
if repo.Name != form.RepoName { if repo.FullName() != form.RepoName {
ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return return
} }
@@ -951,7 +951,7 @@ func handleSettingsPostDelete(ctx *context.Context) {
form := web.GetForm[*forms.RepoSettingForm](ctx) form := web.GetForm[*forms.RepoSettingForm](ctx)
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
if repo.Name != form.RepoName { if repo.FullName() != form.RepoName {
ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return return
} }
@@ -977,7 +977,7 @@ func handleSettingsPostDeleteWiki(ctx *context.Context) {
} }
form := web.GetForm[*forms.RepoSettingForm](ctx) form := web.GetForm[*forms.RepoSettingForm](ctx)
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
if repo.Name != form.RepoName { if repo.FullName() != form.RepoName {
ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return return
} }

View File

@@ -79,7 +79,7 @@ type MigrateRepoForm struct {
// RepoSettingForm form for changing repository settings // RepoSettingForm form for changing repository settings
type RepoSettingForm struct { type RepoSettingForm struct {
middleware.FormDefaultValidator middleware.FormDefaultValidator
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"` RepoName string `binding:"TrimSpace;Required;AlphaDashDot;MaxSize(100)"`
Description string `binding:"MaxSize(2048)"` Description string `binding:"MaxSize(2048)"`
Website string `binding:"ValidUrl;MaxSize(1024)"` Website string `binding:"ValidUrl;MaxSize(1024)"`
Interval string Interval string

View File

@@ -59,28 +59,13 @@
<div class="ui warning message"> <div class="ui warning message">
{{ctx.Locale.Tr "repo.settings.delete_notices_1"}}<br> {{ctx.Locale.Tr "repo.settings.delete_notices_1"}}<br>
{{ctx.Locale.Tr "repo.settings.delete_notices_2" .Repository.FullName}} {{ctx.Locale.Tr "repo.settings.delete_notices_2" .Repository.FullName}}
{{if .Repository.NumForks}}<br>
{{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}
{{end}}
</div> </div>
<form class="ui form form-fetch-action" action="{{.Link}}/settings" method="post"> {{template "repo/settings/dangerous_operation_form" (dict
<input type="hidden" name="action" value="delete"> "RepoFullName" .Repository.FullName
<div class="field"> "RepoOperationLink" (print .Repository.Link "/settings")
<label> "RepoOperationAction" "delete"
{{ctx.Locale.Tr "repo.settings.enter_repo_name_to_confirm"}} "RepoOperationText" (ctx.Locale.Tr "repo.settings.confirm_delete")
<span class="tw-text-red">{{.Repository.Name}}</span> )}}
</label>
</div>
<div class="required field">
<label>{{ctx.Locale.Tr "repo.repo_name"}}</label>
<input name="repo_name" required>
</div>
<div class="actions">
<button class="ui cancel button">{{ctx.Locale.Tr "settings.cancel"}}</button>
<button class="ui red button">{{ctx.Locale.Tr "repo.settings.confirm_delete"}}</button>
</div>
</form>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,22 @@
{{$repoFullName := .RepoFullName}}
{{$repoOperationLink := .RepoOperationLink}}
{{$repoOperationAction := .RepoOperationAction}}
{{$repoOperationText := .RepoOperationText}}
<form class="ui form form-fetch-action" action="{{$repoOperationLink}}" method="post">
<input type="hidden" name="action" value="{{$repoOperationAction}}">
<div class="field">
<label>{{ctx.Locale.Tr "repo.settings.enter_repo_name_to_confirm"}} <span class="tw-text-red">{{$repoFullName}}</span></label>
</div>
<div class="required field">
<label>{{ctx.Locale.Tr "repo.repo_name"}}</label>
<input name="repo_name" required>
</div>
{{if eq $repoOperationAction "transfer"}}
<div class="required field">
<label>{{ctx.Locale.Tr "repo.settings.transfer_owner"}}</label>
<input name="new_owner_name" required>
</div>
{{end}}
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" $repoOperationText)}}
</form>

View File

@@ -909,11 +909,12 @@
<div class="ui warning message"> <div class="ui warning message">
{{ctx.Locale.Tr "repo.settings.convert_notices_1"}} {{ctx.Locale.Tr "repo.settings.convert_notices_1"}}
</div> </div>
<form class="ui form form-fetch-action" action="{{.Link}}" method="post"> {{template "repo/settings/dangerous_operation_form" (dict
<input type="hidden" name="action" value="convert"> "RepoFullName" .Repository.FullName
{{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} "RepoOperationLink" .Link
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.convert_confirm"))}} "RepoOperationAction" "convert"
</form> "RepoOperationText" (ctx.Locale.Tr "repo.settings.convert_confirm")
)}}
</div> </div>
</div> </div>
{{end}} {{end}}
@@ -926,11 +927,12 @@
<div class="ui warning message"> <div class="ui warning message">
{{ctx.Locale.Tr "repo.settings.convert_fork_notices_1"}} {{ctx.Locale.Tr "repo.settings.convert_fork_notices_1"}}
</div> </div>
<form class="ui form form-fetch-action" action="{{.Link}}" method="post"> {{template "repo/settings/dangerous_operation_form" (dict
<input type="hidden" name="action" value="convert_fork"> "RepoFullName" .Repository.FullName
{{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} "RepoOperationLink" .Link
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.convert_fork_confirm"))}} "RepoOperationAction" "convert_fork"
</form> "RepoOperationText" (ctx.Locale.Tr "repo.settings.convert_fork_confirm")
)}}
</div> </div>
</div> </div>
{{end}} {{end}}
@@ -945,16 +947,12 @@
{{ctx.Locale.Tr "repo.settings.transfer_notices_3"}} <br> {{ctx.Locale.Tr "repo.settings.transfer_notices_3"}} <br>
{{ctx.Locale.Tr "repo.settings.transfer_notices_4"}} {{ctx.Locale.Tr "repo.settings.transfer_notices_4"}}
</div> </div>
<form class="ui form form-fetch-action" action="{{.Link}}" method="post"> {{template "repo/settings/dangerous_operation_form" (dict
<input type="hidden" name="action" value="transfer"> "RepoFullName" .Repository.FullName
{{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} "RepoOperationLink" .Link
<div class="required field"> "RepoOperationAction" "transfer"
<label for="new_owner_name">{{ctx.Locale.Tr "repo.settings.transfer_owner"}}</label> "RepoOperationText" (ctx.Locale.Tr "repo.settings.transfer_perform")
<input id="new_owner_name" name="new_owner_name" required> )}}
</div>
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.transfer_perform"))}}
</form>
</div> </div>
</div> </div>
@@ -970,11 +968,12 @@
{{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}} {{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}
{{end}} {{end}}
</div> </div>
<form class="ui form form-fetch-action" action="{{.Link}}" method="post"> {{template "repo/settings/dangerous_operation_form" (dict
<input type="hidden" name="action" value="delete"> "RepoFullName" .Repository.FullName
{{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} "RepoOperationLink" .Link
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.confirm_delete"))}} "RepoOperationAction" "delete"
</form> "RepoOperationText" (ctx.Locale.Tr "repo.settings.confirm_delete")
)}}
</div> </div>
</div> </div>
@@ -1036,11 +1035,12 @@
{{ctx.Locale.Tr "repo.settings.delete_notices_1"}}<br> {{ctx.Locale.Tr "repo.settings.delete_notices_1"}}<br>
{{ctx.Locale.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name}} {{ctx.Locale.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name}}
</div> </div>
<form class="ui form form-fetch-action" action="{{.Link}}" method="post"> {{template "repo/settings/dangerous_operation_form" (dict
<input type="hidden" name="action" value="delete-wiki"> "RepoFullName" .Repository.FullName
{{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} "RepoOperationLink" .Link
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.confirm_wiki_delete"))}} "RepoOperationAction" "delete-wiki"
</form> "RepoOperationText" (ctx.Locale.Tr "repo.settings.confirm_wiki_delete")
)}}
</div> </div>
</div> </div>
{{end}} {{end}}

View File

@@ -1,10 +0,0 @@
<div class="field">
<label>
{{ctx.Locale.Tr "repo.settings.enter_repo_name_to_confirm"}}
<span class="tw-text-red">{{.RepoName}}</span>
</label>
</div>
<div class="required field">
<label>{{ctx.Locale.Tr "repo.repo_name"}}</label>
<input name="repo_name" required maxlength="100">
</div>

View File

@@ -388,7 +388,7 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b
// Archive the repository // Archive the repository
req := NewRequestWithValues(t, "POST", "/"+path.Join(user, repo, "settings"), req := NewRequestWithValues(t, "POST", "/"+path.Join(user, repo, "settings"),
map[string]string{ map[string]string{
"repo_name": repo, "repo_name": user + "/" + repo,
"action": "archive", "action": "archive",
}, },
) )
@@ -402,7 +402,7 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b
// Unfork the repository // Unfork the repository
req = NewRequestWithValues(t, "POST", "/"+path.Join(user, repo, "settings"), req = NewRequestWithValues(t, "POST", "/"+path.Join(user, repo, "settings"),
map[string]string{ map[string]string{
"repo_name": repo, "repo_name": user + "/" + repo,
"action": "convert_fork", "action": "convert_fork",
}, },
) )

View File

@@ -187,7 +187,7 @@ func testUIDeleteBranch(t *testing.T, session *TestSession, ownerName, repoName,
func testDeleteRepository(t *testing.T, session *TestSession, ownerName, repoName string) { func testDeleteRepository(t *testing.T, session *TestSession, ownerName, repoName string) {
relURL := "/" + path.Join(ownerName, repoName, "settings") relURL := "/" + path.Join(ownerName, repoName, "settings")
req := NewRequestWithValues(t, "POST", relURL+"?action=delete", map[string]string{ req := NewRequestWithValues(t, "POST", relURL+"?action=delete", map[string]string{
"repo_name": repoName, "repo_name": ownerName + "/" + repoName,
}) })
resp := session.MakeRequest(t, req, http.StatusOK) resp := session.MakeRequest(t, req, http.StatusOK)
assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect)