mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-28 16:47:01 +09:00
fix(migrations): only allow local paths for plain git migration (#40006)
Only the plain git migration can clone from a local server path. Other services (Gitea, GitLab, Gogs, OneDev, GitBucket, Codebase, CodeCommit, Bitbucket Server) are accessed through their remote API, so a local path never works, yet their migrate forms advertised "or a local server path". - Remove the local path hint from those templates. - Add `IsMigrateURLAllowedForService` and use it in the web and API migrate handlers and in `MigrateRepository`, rejecting local paths for any service other than plain git. - Add a unit test. Raised in review of #39913. _Authored with Codet (AI assistant) on behalf of @lunny._ --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
1 parent
ff68b39c93
commit
f10f7e7f91
15 files changed
+50
-75
No files matched your search
@@ -98,17 +98,17 @@ func Migrate(ctx *context.APIContext) {
|
||||
}
|
||||
}
|
||||
|
||||
gitServiceType := convert.ToGitServiceType(form.Service)
|
||||
|
||||
remoteAddr, err := git.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
|
||||
if err == nil {
|
||||
err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.Doer)
|
||||
err = migrations.IsMigrateURLAllowedForService(remoteAddr, gitServiceType, ctx.Doer)
|
||||
}
|
||||
if err != nil {
|
||||
handleRemoteAddrError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
gitServiceType := convert.ToGitServiceType(form.Service)
|
||||
|
||||
if form.Mirror && setting.Mirror.DisableNewPull {
|
||||
ctx.APIError(http.StatusForbidden, "the site administrator has disabled the creation of new pull mirrors")
|
||||
return
|
||||
|
||||
@@ -153,7 +153,7 @@ func MigratePost(ctx *context.Context) {
|
||||
|
||||
remoteAddr, err := git.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword)
|
||||
if err == nil {
|
||||
err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.Doer)
|
||||
err = migrations.IsMigrateURLAllowedForService(remoteAddr, form.Service, ctx.Doer)
|
||||
}
|
||||
if err != nil {
|
||||
handleMigrateRemoteAddrError(ctx, err, "clone_addr")
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"gitea.dev/modules/log"
|
||||
base "gitea.dev/modules/migration"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/structs"
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
@@ -35,6 +36,17 @@ func RegisterDownloaderFactory(factory base.DownloaderFactory) {
|
||||
factories = append(factories, factory)
|
||||
}
|
||||
|
||||
// IsMigrateURLAllowedForService checks the URL like IsMigrateURLAllowed, and additionally rejects local paths
|
||||
// unless it is a plain git migration, because other services are accessed by their remote API.
|
||||
func IsMigrateURLAllowedForService(remoteURL string, serviceType structs.GitServiceType, doer *user_model.User) error {
|
||||
if serviceType != structs.PlainGitService {
|
||||
if u, err := url.Parse(remoteURL); err == nil && (u.Scheme == "file" || u.Scheme == "") {
|
||||
return &git.ErrInvalidCloneAddr{Host: remoteURL, IsProtocolInvalid: true}
|
||||
}
|
||||
}
|
||||
return IsMigrateURLAllowed(remoteURL, doer)
|
||||
}
|
||||
|
||||
// IsMigrateURLAllowed checks if an URL is allowed to be migrated from
|
||||
func IsMigrateURLAllowed(remoteURL string, doer *user_model.User) error {
|
||||
// Remote address can be HTTP/HTTPS/Git URL or local path.
|
||||
@@ -79,7 +91,7 @@ func IsMigrateURLAllowed(remoteURL string, doer *user_model.User) error {
|
||||
|
||||
// MigrateRepository migrate repository according MigrateOptions
|
||||
func MigrateRepository(ctx context.Context, doer *user_model.User, ownerName string, opts base.MigrateOptions, messenger base.Messenger) (*repo_model.Repository, error) {
|
||||
err := IsMigrateURLAllowed(opts.CloneAddr, doer)
|
||||
err := IsMigrateURLAllowedForService(opts.CloneAddr, opts.GitServiceType, doer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@ import (
|
||||
"testing"
|
||||
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/git"
|
||||
"gitea.dev/modules/git/gitcmd"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/structs"
|
||||
"gitea.dev/modules/test"
|
||||
"gitea.dev/modules/util"
|
||||
|
||||
@@ -71,3 +73,15 @@ func TestMigrateWhiteBlocklist(t *testing.T) {
|
||||
|
||||
setting.ImportLocalPaths = old
|
||||
}
|
||||
|
||||
func TestIsMigrateURLAllowedForServiceLocalPath(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.ImportLocalPaths, true)()
|
||||
admin := &user_model.User{IsAdmin: true}
|
||||
for _, addr := range []string{"/tmp", "file:///tmp"} {
|
||||
assert.NoError(t, IsMigrateURLAllowedForService(addr, structs.PlainGitService, admin))
|
||||
for _, svc := range []structs.GitServiceType{structs.GithubService, structs.GiteaService, structs.GitlabService, structs.BitbucketServerService} {
|
||||
err := IsMigrateURLAllowedForService(addr, svc, admin)
|
||||
assert.ErrorAs(t, err, new(*git.ErrInvalidCloneAddr), "%s %d", addr, svc)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,7 @@
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
{{template "repo/migrate/variants" .}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{template "repo/migrate/common-clone-addr"}}
|
||||
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "username"}}</label>
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<form class="ui form left-right-form form-fetch-action" action="{{.Link}}" method="post">
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{template "repo/migrate/common-clone-addr"}}
|
||||
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "username"}}</label>
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<form class="ui form left-right-form form-fetch-action" action="{{.Link}}" method="post">
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{template "repo/migrate/common-clone-addr"}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.codecommit.aws_access_key_id"}}</label>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{{$allowImportLocal := $.AllowImportLocal}}
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}
|
||||
{{if $allowImportLocal}}{{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
@@ -8,14 +8,8 @@
|
||||
{{template "base/alert" .}}
|
||||
<form class="ui form left-right-form form-fetch-action" action="{{.Link}}" method="post">
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
{{template "repo/migrate/common-clone-addr" (dict "AllowImportLocal" ctx.RootData.SignedUser.CanImportLocal)}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "username"}}</label>
|
||||
<input name="auth_username">
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<form class="ui form left-right-form form-fetch-action" action="{{.Link}}" method="post">
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{template "repo/migrate/common-clone-addr"}}
|
||||
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "username"}}</label>
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<form class="ui form left-right-form form-fetch-action" action="{{.Link}}" method="post">
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{template "repo/migrate/common-clone-addr"}}
|
||||
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "access_token"}}</label>
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<form class="ui form left-right-form form-fetch-action" action="{{.Link}}" method="post">
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}
|
||||
</span>
|
||||
</div>
|
||||
{{template "repo/migrate/common-clone-addr"}}
|
||||
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "access_token"}}</label>
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<form class="ui form left-right-form form-fetch-action" action="{{.Link}}" method="post">
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{template "repo/migrate/common-clone-addr"}}
|
||||
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "access_token"}}</label>
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<form class="ui form left-right-form form-fetch-action" action="{{.Link}}" method="post">
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{template "repo/migrate/common-clone-addr"}}
|
||||
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "access_token"}}</label>
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<form class="ui form left-right-form form-fetch-action" action="{{.Link}}" method="post">
|
||||
{{template "repo/migrate/common-init" (dict "ServiceType" .service)}}
|
||||
|
||||
<div class="inline required field">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||
<input name="clone_addr" autofocus required>
|
||||
<span class="help">
|
||||
{{ctx.Locale.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{ctx.Locale.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{template "repo/migrate/common-clone-addr"}}
|
||||
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "username"}}</label>
|
||||
|
||||
Reference in new issue
Block a user