diff options
author | 6543 <6543@obermui.de> | 2020-11-29 01:37:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-28 19:37:58 -0500 |
commit | b2435af9be75a0cdeea08881c162e65740225f56 (patch) | |
tree | 42a3db956042e3777acebad03e0157c6cca3c881 /modules/migrations | |
parent | 0f14f69e6070c9aca09f57c419e7d6007d0e520b (diff) | |
download | gitea-b2435af9be75a0cdeea08881c162e65740225f56.tar.gz gitea-b2435af9be75a0cdeea08881c162e65740225f56.zip |
Add Allow-/Block-List for Migrate & Mirrors (#13610)
* add black list and white list support for migrating repositories
* fix fmt
* fix lint
* fix vendor
* fix modules.txt
* clean diff
* specify log message
* use blocklist/allowlist
* allways use lowercase to match url
* Apply allow/block
* Settings: use existing "migrations" section
* convert domains lower case
* dont store unused value
* Block private addresses for migration by default
* fix lint
* use proposed-upstream func to detect private IP addr
* a nit
* add own error for blocked migration, add tests, imprufe api
* fix test
* fix-if-localhost-is-ipv4
* rename error & error message
* rename setting options
* Apply suggestions from code review
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Diffstat (limited to 'modules/migrations')
-rw-r--r-- | modules/migrations/migrate.go | 75 | ||||
-rw-r--r-- | modules/migrations/migrate_test.go | 34 |
2 files changed, 108 insertions, 1 deletions
diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 3c505d82b6..b3ecb8114a 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -8,9 +8,13 @@ package migrations import ( "context" "fmt" + "net" + "net/url" + "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/matchlist" "code.gitea.io/gitea/modules/migrations/base" "code.gitea.io/gitea/modules/setting" ) @@ -20,6 +24,9 @@ type MigrateOptions = base.MigrateOptions var ( factories []base.DownloaderFactory + + allowList *matchlist.Matchlist + blockList *matchlist.Matchlist ) // RegisterDownloaderFactory registers a downloader factory @@ -27,12 +34,49 @@ func RegisterDownloaderFactory(factory base.DownloaderFactory) { factories = append(factories, factory) } +func isMigrateURLAllowed(remoteURL string) error { + u, err := url.Parse(strings.ToLower(remoteURL)) + if err != nil { + return err + } + + if strings.EqualFold(u.Scheme, "http") || strings.EqualFold(u.Scheme, "https") { + if len(setting.Migrations.AllowedDomains) > 0 { + if !allowList.Match(u.Host) { + return &models.ErrMigrationNotAllowed{Host: u.Host} + } + } else { + if blockList.Match(u.Host) { + return &models.ErrMigrationNotAllowed{Host: u.Host} + } + } + } + + if !setting.Migrations.AllowLocalNetworks { + addrList, err := net.LookupIP(strings.Split(u.Host, ":")[0]) + if err != nil { + return &models.ErrMigrationNotAllowed{Host: u.Host, NotResolvedIP: true} + } + for _, addr := range addrList { + if isIPPrivate(addr) || !addr.IsGlobalUnicast() { + return &models.ErrMigrationNotAllowed{Host: u.Host, PrivateNet: addr.String()} + } + } + } + + return nil +} + // MigrateRepository migrate repository according MigrateOptions func MigrateRepository(ctx context.Context, doer *models.User, ownerName string, opts base.MigrateOptions) (*models.Repository, error) { + err := isMigrateURLAllowed(opts.CloneAddr) + if err != nil { + return nil, err + } + var ( downloader base.Downloader uploader = NewGiteaLocalUploader(ctx, doer, ownerName, opts.RepoName) - err error ) for _, factory := range factories { @@ -308,3 +352,32 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return nil } + +// Init migrations service +func Init() error { + var err error + allowList, err = matchlist.NewMatchlist(setting.Migrations.AllowedDomains...) + if err != nil { + return fmt.Errorf("init migration allowList domains failed: %v", err) + } + + blockList, err = matchlist.NewMatchlist(setting.Migrations.BlockedDomains...) + if err != nil { + return fmt.Errorf("init migration blockList domains failed: %v", err) + } + + return nil +} + +// isIPPrivate reports whether ip is a private address, according to +// RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses). +// from https://github.com/golang/go/pull/42793 +// TODO remove if https://github.com/golang/go/issues/29146 got resolved +func isIPPrivate(ip net.IP) bool { + if ip4 := ip.To4(); ip4 != nil { + return ip4[0] == 10 || + (ip4[0] == 172 && ip4[1]&0xf0 == 16) || + (ip4[0] == 192 && ip4[1] == 168) + } + return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc +} diff --git a/modules/migrations/migrate_test.go b/modules/migrations/migrate_test.go new file mode 100644 index 0000000000..3bad5cfd73 --- /dev/null +++ b/modules/migrations/migrate_test.go @@ -0,0 +1,34 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "testing" + + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" +) + +func TestMigrateWhiteBlocklist(t *testing.T) { + setting.Migrations.AllowedDomains = []string{"github.com"} + assert.NoError(t, Init()) + + err := isMigrateURLAllowed("https://gitlab.com/gitlab/gitlab.git") + assert.Error(t, err) + + err = isMigrateURLAllowed("https://github.com/go-gitea/gitea.git") + assert.NoError(t, err) + + setting.Migrations.AllowedDomains = []string{} + setting.Migrations.BlockedDomains = []string{"github.com"} + assert.NoError(t, Init()) + + err = isMigrateURLAllowed("https://gitlab.com/gitlab/gitlab.git") + assert.NoError(t, err) + + err = isMigrateURLAllowed("https://github.com/go-gitea/gitea.git") + assert.Error(t, err) +} |