diff --git a/internal/form/repo.go b/internal/form/repo.go index 4a82a5b89..30335a1e2 100644 --- a/internal/form/repo.go +++ b/internal/form/repo.go @@ -52,12 +52,19 @@ func (f *MigrateRepo) Validate(ctx *macaron.Context, errs binding.Errors) bindin return validate(errs, ctx.Data, f, ctx.Locale) } +type ParseRemoteAddrOptions struct { + CloneAddr string + User *database.User + AuthUsername string + AuthPassword string +} + // ParseRemoteAddr checks if given remote address is valid, // and returns composed URL with needed username and password. // It also checks if given user has permission when remote address // is actually a local path. -func (f MigrateRepo) ParseRemoteAddr(user *database.User) (string, error) { - remoteAddr := strings.TrimSpace(f.CloneAddr) +func ParseRemoteAddr(options ParseRemoteAddrOptions) (string, error) { + remoteAddr := strings.TrimSpace(options.CloneAddr) // Remote address can be HTTP/HTTPS/Git URL or local path. if strings.HasPrefix(remoteAddr, "http://") || @@ -72,15 +79,15 @@ func (f MigrateRepo) ParseRemoteAddr(user *database.User) (string, error) { return "", database.ErrInvalidCloneAddr{IsBlockedLocalAddress: true} } - if len(f.AuthUsername)+len(f.AuthPassword) > 0 { - u.User = url.UserPassword(f.AuthUsername, f.AuthPassword) + if len(options.AuthUsername)+len(options.AuthPassword) > 0 { + u.User = url.UserPassword(options.AuthUsername, options.AuthPassword) } // To prevent CRLF injection in git protocol, see https://github.com/gogs/gogs/issues/6413 if u.Scheme == "git" && (strings.Contains(remoteAddr, "%0d") || strings.Contains(remoteAddr, "%0a")) { return "", database.ErrInvalidCloneAddr{IsURLError: true} } remoteAddr = u.String() - } else if !user.CanImportLocal() { + } else if !options.User.CanImportLocal() { return "", database.ErrInvalidCloneAddr{IsPermissionDenied: true} } else if !osx.IsDir(remoteAddr) { return "", database.ErrInvalidCloneAddr{IsInvalidPath: true} diff --git a/internal/route/api/v1/repo_repo.go b/internal/route/api/v1/repo_repo.go index f181bfdd5..26c57223f 100644 --- a/internal/route/api/v1/repo_repo.go +++ b/internal/route/api/v1/repo_repo.go @@ -251,7 +251,12 @@ func migrate(c *context.APIContext, f form.MigrateRepo) { } } - remoteAddr, err := f.ParseRemoteAddr(c.User) + remoteAddr, err := form.ParseRemoteAddr(form.ParseRemoteAddrOptions{ + CloneAddr: f.CloneAddr, + User: c.User, + AuthUsername: f.AuthUsername, + AuthPassword: f.AuthPassword, + }) if err != nil { if database.IsErrInvalidCloneAddr(err) { addrErr := err.(database.ErrInvalidCloneAddr) diff --git a/internal/route/repo/repo.go b/internal/route/repo/repo.go index 4280b3ec9..5d635658c 100644 --- a/internal/route/repo/repo.go +++ b/internal/route/repo/repo.go @@ -170,7 +170,12 @@ func MigratePost(c *context.Context, f form.MigrateRepo) { return } - remoteAddr, err := f.ParseRemoteAddr(c.User) + remoteAddr, err := form.ParseRemoteAddr(form.ParseRemoteAddrOptions{ + CloneAddr: f.CloneAddr, + User: c.User, + AuthUsername: f.AuthUsername, + AuthPassword: f.AuthPassword, + }) if err != nil { if database.IsErrInvalidCloneAddr(err) { c.Data["Err_CloneAddr"] = true diff --git a/internal/route/repo/setting.go b/internal/route/repo/setting.go index 549e26e6e..4f45c8774 100644 --- a/internal/route/repo/setting.go +++ b/internal/route/repo/setting.go @@ -121,7 +121,34 @@ func SettingsPost(c *context.Context, f form.RepoSetting) { return } } - if err := c.Repo.Mirror.SaveAddress(f.MirrorAddress); err != nil { + + remoteAddr, err := form.ParseRemoteAddr(form.ParseRemoteAddrOptions{ + CloneAddr: f.MirrorAddress, + User: c.User, + }) + if err != nil { + if database.IsErrInvalidCloneAddr(err) { + c.Data["Err_CloneAddr"] = true + addrErr := err.(database.ErrInvalidCloneAddr) + switch { + case addrErr.IsURLError: + c.RenderWithErr(c.Tr("repo.migrate.clone_address")+c.Tr("form.url_error"), http.StatusBadRequest, tmplRepoSettingsOptions, &f) + case addrErr.IsPermissionDenied: + c.RenderWithErr(c.Tr("repo.migrate.permission_denied"), http.StatusForbidden, tmplRepoSettingsOptions, &f) + case addrErr.IsInvalidPath: + c.RenderWithErr(c.Tr("repo.migrate.invalid_local_path"), http.StatusBadRequest, tmplRepoSettingsOptions, &f) + case addrErr.IsBlockedLocalAddress: + c.RenderWithErr(c.Tr("repo.migrate.clone_address_resolved_to_blocked_local_address"), http.StatusForbidden, tmplRepoSettingsOptions, &f) + default: + c.Error(err, "unexpected error") + } + } else { + c.Error(err, "parse remote address") + } + return + } + + if err := c.Repo.Mirror.SaveAddress(remoteAddr); err != nil { c.Error(err, "save address") return }