diff --git a/models/repo.go b/models/repo.go index 8b51f14043..f180179440 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1077,9 +1077,11 @@ func CleanUpMigrateInfo(repo *Repository) (*Repository, error) { } } - if err := cleanUpMigrateGitConfig(repo.GitConfigPath()); err != nil { - return repo, fmt.Errorf("cleanUpMigrateGitConfig: %v", err) + _, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath) + if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { + return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err) } + if repo.HasWiki() { if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil { return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %v", err) diff --git a/models/repo_mirror.go b/models/repo_mirror.go index 759241e461..b63fba5741 100644 --- a/models/repo_mirror.go +++ b/models/repo_mirror.go @@ -20,7 +20,6 @@ import ( "github.com/Unknwon/com" "github.com/go-xorm/xorm" - "gopkg.in/ini.v1" ) // MirrorQueue holds an UniqueQueue object of the mirror @@ -71,11 +70,18 @@ func (m *Mirror) ScheduleNextUpdate() { } func remoteAddress(repoPath string) (string, error) { - cfg, err := ini.Load(GitConfigPath(repoPath)) + cmd := git.NewCommand("remote", "get-url", "origin") + result, err := cmd.RunInDir(repoPath) if err != nil { + if strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { + return "", nil + } return "", err } - return cfg.Section("remote \"origin\"").Key("url").Value(), nil + if len(result) > 0 { + return result[:len(result)-1], nil + } + return "", nil } func (m *Mirror) readAddress() { @@ -115,14 +121,15 @@ func (m *Mirror) FullAddress() string { // SaveAddress writes new address to Git repository config. func (m *Mirror) SaveAddress(addr string) error { - configPath := m.Repo.GitConfigPath() - cfg, err := ini.Load(configPath) - if err != nil { - return fmt.Errorf("Load: %v", err) + repoPath := m.Repo.RepoPath() + // Remove old origin + _, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath) + if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { + return err } - cfg.Section("remote \"origin\"").Key("url").SetValue(addr) - return cfg.SaveToIndent(configPath, "\t") + _, err = git.NewCommand("remote", "add", "origin", addr).RunInDir(repoPath) + return err } // gitShortEmptySha Git short empty SHA diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ce726ed562..23d1949203 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -567,7 +567,9 @@ mirror_prune_desc = Remove obsolete remote-tracking references mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable automatic sync. mirror_interval_invalid = The mirror interval is not valid. mirror_address = Clone From URL -mirror_address_desc = Include any required authorization credentials in the URL. +mirror_address_desc = Include any required authorization credentials in the URL. These must be url escaped as appropriate +mirror_address_url_invalid = The provided url is invalid. You must escape all components of the url correctly. +mirror_address_protocol_invalid = The provided url is invalid. Only http(s):// or git:// locations can be mirrored from. mirror_last_synced = Last Synchronized watchers = Watchers stargazers = Stargazers diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 0101b2362b..f58601633a 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -7,9 +7,13 @@ package repo import ( "errors" + "net/url" + "regexp" "strings" "time" + "mvdan.cc/xurls/v2" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" @@ -32,6 +36,8 @@ 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") @@ -145,7 +151,38 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { return } } - if err := ctx.Repo.Mirror.SaveAddress(form.MirrorAddress); err != nil { + + // 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 + } + + 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 + } + + // 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() { + ctx.Data["Err_MirrorAddress"] = true + ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form) + return + } + + address = u.String() + + if err := ctx.Repo.Mirror.SaveAddress(address); err != nil { ctx.ServerError("SaveAddress", err) return } @@ -682,3 +719,11 @@ func DeleteDeployKey(ctx *context.Context) { "redirect": ctx.Repo.RepoLink + "/settings/keys", }) } + +func init() { + var err error + validFormAddress, err = xurls.StrictMatchingScheme(`(https?)|(git)://`) + if err != nil { + panic(err) + } +} diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 7e25206c9d..25120fcb9f 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -62,7 +62,7 @@ -
+

{{.i18n.Tr "repo.mirror_address_desc"}}