Skip to content

Add black list and white list support for migrating repositories #8040

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions custom/conf/app.ini.sample
Original file line number Diff line number Diff line change
Expand Up @@ -803,3 +803,11 @@ IS_INPUT_FILE = false
ENABLED = false
; If you want to add authorization, specify a token here
TOKEN =

[migration]
; Whitelist for migrating, default is blank. Blank means everything will be allowed.
; Multiple domains could be separated by commas.
WHITELISTED_DOMAINS =
; Blacklist for migrating, default is blank. Multiple domains could be separated by commas.
; When WHITELISTED_DOMAINS is not blank, this option will be ignored.
BLACKLISTED_DOMAINS =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing EOL

6 changes: 6 additions & 0 deletions docs/content/doc/advanced/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -511,9 +511,15 @@ Two special environment variables are passed to the render command:
- `GITEA_PREFIX_RAW`, which contains the current URL prefix in the `raw` path tree. To be used as prefix for image paths.

## Time (`time`)

- `FORMAT`: Time format to diplay on UI. i.e. RFC1123 or 2006-01-02 15:04:05
- `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Shanghai/Asia

## Migraions (`migration`)

- `WHITELISTED_DOMAINS`: ****: Domains whitelist for migrating repositories, default is blank. It means everything will be allowed. Multiple domains could be separated by commas.
- `BLACKLISTED_DOMAINS`: ****: Domains blacklist for migrating repositories, default is blank. Multiple domains could be separated by commas. When `WHITELISTED_DOMAINS` is not blank, this option will be ignored.

## Other (`other`)

- `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer.
Expand Down
6 changes: 6 additions & 0 deletions docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,15 @@ IS_INPUT_FILE = false
- IS_INPUT_FILE: 输入方式是最后一个参数为文件路径还是从标准输入读取。

## Time (`time`)

- `FORMAT`: 显示在界面上的时间格式。比如: RFC1123 或者 2006-01-02 15:04:05
- `DEFAULT_UI_LOCATION`: 默认显示在界面上的时区,默认为本地时区。比如: Asia/Shanghai

## Migraions (`migration`)

- `WHITELISTED_DOMAINS`: ****: 迁移仓库的域名白名单,默认为空,表示允许从任意域名迁移仓库,多个域名用逗号分隔。
- `BLACKLISTED_DOMAINS`: ****: 迁移仓库的域名黑名单,默认为空,多个域名用逗号分隔。如果 `WHITELISTED_DOMAINS` 不为空,此选项将会被忽略。

## Other (`other`)

- `SHOW_FOOTER_BRANDING`: 为真则在页面底部显示Gitea的字样。
Expand Down
43 changes: 43 additions & 0 deletions modules/matchlist/matchlist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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 matchlist

import (
"github.com/gobwas/glob"
)

// Matchlist represents a black or white list
type Matchlist struct {
rules []string
ruleGlobs []glob.Glob
}

// NewMatchlist creates a new black or white list
func NewMatchlist(rules ...string) (*Matchlist, error) {
list := Matchlist{
rules: rules,
ruleGlobs: make([]glob.Glob, 0, len(rules)),
}

for _, rule := range list.rules {
rg, err := glob.Compile(rule)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rg, err := glob.Compile(rule)
rg, err := glob.Compile(rule,[]string{".","/"})

I think that separators should work better if specified, so the tokenization is aware of the different parts of the glob.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some case normalization should be used. For instance, if I black list: "google.com", someone could work around that by using "GOOGLE.COM".

if err != nil {
return nil, err
}
list.ruleGlobs = append(list.ruleGlobs, rg)
}

return &list, nil
}

// Match will matches
func (b *Matchlist) Match(u string) bool {
for _, r := range b.ruleGlobs {
if r.Match(u) {
return true
}
}
return false
}
52 changes: 52 additions & 0 deletions modules/migrations/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@
package migrations

import (
"fmt"
"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"
)

// MigrateOptions is equal to base.MigrateOptions
Expand All @@ -23,8 +29,34 @@ func RegisterDownloaderFactory(factory base.DownloaderFactory) {
factories = append(factories, factory)
}

func isMigrateURLAllowed(remoteURL string) (bool, error) {
u, err := url.Parse(remoteURL)
if err != nil {
return false, err
}

if strings.EqualFold(u.Scheme, "http") || strings.EqualFold(u.Scheme, "https") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why check the protocol? This will let ftp:, git: and ssh: pass if one day they are supported. Perhaps it's better to check if the url is local and make any other protocol go through whitelisting/blacklisting.

if len(setting.Migration.WhitelistedDomains) > 0 {
if !whitelist.Match(u.Host) {
return false, fmt.Errorf("Migrate from %v is not allowed", u.Host)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a translatable error should be better?

}
} else {
if blacklist.Match(u.Host) {
return false, fmt.Errorf("Migrate from %v is not allowed", u.Host)
}
}
}

return true, nil
}

// MigrateRepository migrate repository according MigrateOptions
func MigrateRepository(doer *models.User, ownerName string, opts base.MigrateOptions) (*models.Repository, error) {
allowed, err := isMigrateURLAllowed(opts.RemoteURL)
if !allowed {
return nil, err
}

var (
downloader base.Downloader
uploader = NewGiteaLocalUploader(doer, ownerName, opts.Name)
Expand Down Expand Up @@ -250,3 +282,23 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts

return nil
}

var (
whitelist *matchlist.Matchlist
blacklist *matchlist.Matchlist
)

// Init migrations service
func Init() error {
var err error
whitelist, err = matchlist.NewMatchlist(setting.Migration.WhitelistedDomains...)
if err != nil {
return fmt.Errorf("Init migration whitelist domains failed: %v", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error will show up when the instance starts, right? I mean, the admin needs to see the errors as soon as possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It will display when gitea start.

}

blacklist, err = matchlist.NewMatchlist(setting.Migration.BlacklistedDomains...)
if err != nil {
return fmt.Errorf("Init migration blacklist domains failed: %v", err)
}
return nil
}
38 changes: 38 additions & 0 deletions modules/migrations/migrate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 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 TestMigrateWhiteBlacklist(t *testing.T) {
setting.Migration.WhitelistedDomains = []string{"github.com"}
assert.NoError(t, Init())

allowed, err := isMigrateURLAllowed("https://gitlab.com/gitlab/gitlab.git")
assert.False(t, allowed)
assert.Error(t, err)

allowed, err = isMigrateURLAllowed("https://github.com/go-gitea/gitea.git")
assert.True(t, allowed)
assert.NoError(t, err)

setting.Migration.WhitelistedDomains = []string{}
setting.Migration.BlacklistedDomains = []string{"github.com"}
assert.NoError(t, Init())

allowed, err = isMigrateURLAllowed("https://gitlab.com/gitlab/gitlab.git")
assert.True(t, allowed)
assert.NoError(t, err)

allowed, err = isMigrateURLAllowed("https://github.com/go-gitea/gitea.git")
assert.False(t, allowed)
assert.Error(t, err)
}
26 changes: 26 additions & 0 deletions modules/setting/migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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 setting

import (
"fmt"
)

// Migration represents migrations' settings
var Migration = struct {
WhitelistedDomains []string
BlacklistedDomains []string
}{
WhitelistedDomains: []string{},
BlacklistedDomains: []string{},
}

// InitMigrationConfig represents load migration configurations
func InitMigrationConfig() error {
if err := Cfg.Section("migration").MapTo(&Migration); err != nil {
return fmt.Errorf("Failed to map Migration settings: %v", err)
}
return nil
}
5 changes: 5 additions & 0 deletions routers/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/mailer"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/external"
repo_migrations "code.gitea.io/gitea/modules/migrations"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/ssh"

Expand Down Expand Up @@ -101,6 +102,10 @@ func GlobalInit() {
models.InitSyncMirrors()
models.InitDeliverHooks()
models.InitTestPullRequests()

if err := repo_migrations.Init(); err != nil {
log.Fatal("Failed to initialize migrations: %v", err)
}
}
if setting.EnableSQLite3 {
log.Info("SQLite3 Supported")
Expand Down