diff options
author | zeripath <art27@cantab.net> | 2021-03-15 21:52:11 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-15 17:52:11 -0400 |
commit | 6e423d5573c20b78d6e21cb044e8f4d5de5b288a (patch) | |
tree | 61d2e282bc652b8254271fdd9e19b87a386b5dc7 /routers | |
parent | f268b4896b1030761b28f1f8923d77d87adb8f0b (diff) | |
download | gitea-6e423d5573c20b78d6e21cb044e8f4d5de5b288a.tar.gz gitea-6e423d5573c20b78d6e21cb044e8f4d5de5b288a.zip |
Ensure validation occurs on clone addresses too (#14994)
* Ensure validation occurs on clone addresses too
Fix #14984
Signed-off-by: Andrew Thornton <art27@cantab.net>
* fix lint
Signed-off-by: Andrew Thornton <art27@cantab.net>
* fix test
Signed-off-by: Andrew Thornton <art27@cantab.net>
* Fix api tests
Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Diffstat (limited to 'routers')
-rw-r--r-- | routers/api/v1/repo/migrate.go | 17 | ||||
-rw-r--r-- | routers/repo/migrate.go | 26 | ||||
-rw-r--r-- | routers/repo/setting.go | 69 |
3 files changed, 60 insertions, 52 deletions
diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index 61cd12b991..1eefa78d57 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -96,15 +96,24 @@ func Migrate(ctx *context.APIContext) { } } - remoteAddr, err := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword, ctx.User) + remoteAddr, err := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword) + if err == nil { + err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.User) + } if err != nil { if models.IsErrInvalidCloneAddr(err) { - addrErr := err.(models.ErrInvalidCloneAddr) + addrErr := err.(*models.ErrInvalidCloneAddr) switch { case addrErr.IsURLError: ctx.Error(http.StatusUnprocessableEntity, "", err) case addrErr.IsPermissionDenied: - ctx.Error(http.StatusUnprocessableEntity, "", "You are not allowed to import local repositories.") + if addrErr.LocalPath { + ctx.Error(http.StatusUnprocessableEntity, "", "You are not allowed to import local repositories.") + } else if len(addrErr.PrivateNet) == 0 { + ctx.Error(http.StatusUnprocessableEntity, "", "You are not allowed to import from blocked hosts.") + } else { + ctx.Error(http.StatusUnprocessableEntity, "", "You are not allowed to import from private IPs.") + } case addrErr.IsInvalidPath: ctx.Error(http.StatusUnprocessableEntity, "", "Invalid local path, it does not exist or not a directory.") default: @@ -219,7 +228,7 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *models.User, remoteA ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The username '%s' contains invalid characters.", err.(models.ErrNameCharsNotAllowed).Name)) case models.IsErrNamePatternNotAllowed(err): ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(models.ErrNamePatternNotAllowed).Pattern)) - case models.IsErrMigrationNotAllowed(err): + case models.IsErrInvalidCloneAddr(err): ctx.Error(http.StatusUnprocessableEntity, "", err) case base.IsErrNotSupported(err): ctx.Error(http.StatusUnprocessableEntity, "", err) diff --git a/routers/repo/migrate.go b/routers/repo/migrate.go index e1ff8e1360..fbc4288c1e 100644 --- a/routers/repo/migrate.go +++ b/routers/repo/migrate.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" auth "code.gitea.io/gitea/modules/forms" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" @@ -97,7 +98,7 @@ func handleMigrateError(ctx *context.Context, owner *models.User, err error, nam ctx.Data["Err_RepoName"] = true ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form) default: - remoteAddr, _ := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword, owner) + remoteAddr, _ := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword) err = util.URLSanitizedError(err, remoteAddr) if strings.Contains(err.Error(), "Authentication failed") || strings.Contains(err.Error(), "Bad credentials") || @@ -138,23 +139,36 @@ func MigratePost(ctx *context.Context) { return } - remoteAddr, err := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword, ctx.User) + remoteAddr, err := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword) + if err == nil { + err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.User) + } if err != nil { if models.IsErrInvalidCloneAddr(err) { ctx.Data["Err_CloneAddr"] = true - addrErr := err.(models.ErrInvalidCloneAddr) + addrErr := err.(*models.ErrInvalidCloneAddr) switch { + case addrErr.IsProtocolInvalid: + ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tpl, &form) case addrErr.IsURLError: ctx.RenderWithErr(ctx.Tr("form.url_error"), tpl, &form) case addrErr.IsPermissionDenied: - ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tpl, &form) + if len(addrErr.PrivateNet) == 0 { + ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied_private_ip"), tpl, &form) + } else if !addrErr.LocalPath { + ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied_blocked"), tpl, &form) + } else { + ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tpl, &form) + } case addrErr.IsInvalidPath: ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tpl, &form) default: - ctx.ServerError("Unknown error", err) + log.Error("Error whilst updating url: %v", err) + ctx.RenderWithErr(ctx.Tr("form.url_error"), tpl, &form) } } else { - ctx.ServerError("ParseRemoteAddr", err) + log.Error("Error whilst updating url: %v", err) + ctx.RenderWithErr(ctx.Tr("form.url_error"), tpl, &form) } return } diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 692d65b44c..6b31ac4c71 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -9,8 +9,6 @@ import ( "errors" "fmt" "io/ioutil" - "net/url" - "regexp" "strings" "time" @@ -20,6 +18,7 @@ import ( auth "code.gitea.io/gitea/modules/forms" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" @@ -30,8 +29,6 @@ import ( "code.gitea.io/gitea/services/mailer" mirror_service "code.gitea.io/gitea/services/mirror" repo_service "code.gitea.io/gitea/services/repository" - - "mvdan.cc/xurls/v2" ) const ( @@ -44,8 +41,6 @@ const ( tplProtectedBranch base.TplName = "repo/settings/protected_branch" ) -var validFormAddress *regexp.Regexp - // Settings show a repository's settings page func Settings(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.settings") @@ -169,40 +164,38 @@ func SettingsPost(ctx *context.Context) { } } - // Validate the form.MirrorAddress - u, err := url.Parse(form.MirrorAddress) - if err != nil { - ctx.Data["Err_MirrorAddress"] = true - ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form) - return + address, err := auth.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword) + if err == nil { + err = migrations.IsMigrateURLAllowed(address, ctx.User) } - - if u.Opaque != "" || !(u.Scheme == "http" || u.Scheme == "https" || u.Scheme == "git") { - ctx.Data["Err_MirrorAddress"] = true - ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, &form) - return - } - - if form.MirrorUsername != "" || form.MirrorPassword != "" { - u.User = url.UserPassword(form.MirrorUsername, form.MirrorPassword) - } - - // Now use xurls - address := validFormAddress.FindString(form.MirrorAddress) - if address != form.MirrorAddress && form.MirrorAddress != "" { - ctx.Data["Err_MirrorAddress"] = true - ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form) - return - } - - if u.EscapedPath() == "" || u.Host == "" || !u.IsAbs() { + if err != nil { + if models.IsErrInvalidCloneAddr(err) { + ctx.Data["Err_MirrorAddress"] = true + addrErr := err.(*models.ErrInvalidCloneAddr) + switch { + case addrErr.IsProtocolInvalid: + ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, &form) + case addrErr.IsURLError: + ctx.RenderWithErr(ctx.Tr("form.url_error"), tplSettingsOptions, &form) + case addrErr.IsPermissionDenied: + if len(addrErr.PrivateNet) == 0 { + ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied_private_ip"), tplSettingsOptions, &form) + } else if !addrErr.LocalPath { + ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied_blocked"), tplSettingsOptions, &form) + } else { + ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplSettingsOptions, &form) + } + case addrErr.IsInvalidPath: + ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tplSettingsOptions, &form) + default: + ctx.ServerError("Unknown error", err) + } + } ctx.Data["Err_MirrorAddress"] = true ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form) return } - address = u.String() - if err := mirror_service.UpdateAddress(ctx.Repo.Mirror, address); err != nil { ctx.ServerError("UpdateAddress", err) return @@ -951,14 +944,6 @@ func DeleteDeployKey(ctx *context.Context) { }) } -func init() { - var err error - validFormAddress, err = xurls.StrictMatchingScheme(`(https?)|(git)://`) - if err != nil { - panic(err) - } -} - // UpdateAvatarSetting update repo's avatar func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm) error { ctxRepo := ctx.Repo.Repository |