diff options
Diffstat (limited to 'models')
-rw-r--r-- | models/action.go | 1 | ||||
-rw-r--r-- | models/git_diff.go | 18 | ||||
-rw-r--r-- | models/migrations/migrations.go | 53 | ||||
-rw-r--r-- | models/models.go | 22 | ||||
-rw-r--r-- | models/publickey.go | 81 | ||||
-rw-r--r-- | models/repo.go | 35 |
6 files changed, 184 insertions, 26 deletions
diff --git a/models/action.go b/models/action.go index 98a4f5a0..de2cdd12 100644 --- a/models/action.go +++ b/models/action.go @@ -332,7 +332,6 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string, } } - go DeliverHooks() return nil } diff --git a/models/git_diff.go b/models/git_diff.go index 4bbe3c0e..7e91626f 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -14,12 +14,14 @@ import ( "strings" "time" + "golang.org/x/net/html/charset" + "golang.org/x/text/transform" + "github.com/Unknwon/com" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/git" "github.com/gogits/gogs/modules/log" - "github.com/gogits/gogs/modules/mahonia" "github.com/gogits/gogs/modules/process" ) @@ -192,14 +194,18 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff } // FIXME: use first 30 lines to detect file encoding. - charset, err := base.DetectEncoding(buf.Bytes()) - if charset != "utf8" && err == nil { - decoder := mahonia.NewDecoder(charset) - if decoder != nil { + charsetLabel, err := base.DetectEncoding(buf.Bytes()) + if charsetLabel != "utf8" && err == nil { + encoding, _ := charset.Lookup(charsetLabel) + + if encoding != nil { + d := encoding.NewDecoder() for _, f := range diff.Files { for _, sec := range f.Sections { for _, l := range sec.Lines { - l.Content = decoder.ConvertString(l.Content) + if c, _, err := transform.String(d, l.Content); err == nil { + l.Content = c + } } } } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go new file mode 100644 index 00000000..3586e5d0 --- /dev/null +++ b/models/migrations/migrations.go @@ -0,0 +1,53 @@ +package migrations + +import ( + "errors" + + "github.com/go-xorm/xorm" +) + +type migration func(*xorm.Engine) error + +// The version table. Should have only one row with id==1 +type Version struct { + Id int64 + Version int64 +} + +// This is a sequence of migrations. Add new migrations to the bottom of the list. +// If you want to "retire" a migration, replace it with "expiredMigration" +var migrations = []migration{} + +// Migrate database to current version +func Migrate(x *xorm.Engine) error { + if err := x.Sync(new(Version)); err != nil { + return err + } + + currentVersion := &Version{Id: 1} + has, err := x.Get(currentVersion) + if err != nil { + return err + } else if !has { + if _, err = x.InsertOne(currentVersion); err != nil { + return err + } + } + + v := currentVersion.Version + + for i, migration := range migrations[v:] { + if err = migration(x); err != nil { + return err + } + currentVersion.Version = v + int64(i) + 1 + if _, err = x.Id(1).Update(currentVersion); err != nil { + return err + } + } + return nil +} + +func expiredMigration(x *xorm.Engine) error { + return errors.New("You are migrating from a too old gogs version") +} diff --git a/models/models.go b/models/models.go index cf212441..df030e51 100644 --- a/models/models.go +++ b/models/models.go @@ -15,6 +15,7 @@ import ( "github.com/go-xorm/xorm" _ "github.com/lib/pq" + "github.com/gogits/gogs/models/migrations" "github.com/gogits/gogs/modules/setting" ) @@ -31,7 +32,7 @@ var ( HasEngine bool DbCfg struct { - Type, Host, Name, User, Pwd, Path, SslMode string + Type, Host, Name, User, Passwd, Path, SSLMode string } EnableSQLite3 bool @@ -57,10 +58,10 @@ func LoadModelsConfig() { DbCfg.Host = sec.Key("HOST").String() DbCfg.Name = sec.Key("NAME").String() DbCfg.User = sec.Key("USER").String() - if len(DbCfg.Pwd) == 0 { - DbCfg.Pwd = sec.Key("PASSWD").String() + if len(DbCfg.Passwd) == 0 { + DbCfg.Passwd = sec.Key("PASSWD").String() } - DbCfg.SslMode = sec.Key("SSL_MODE").String() + DbCfg.SSLMode = sec.Key("SSL_MODE").String() DbCfg.Path = sec.Key("PATH").MustString("data/gogs.db") } @@ -69,7 +70,7 @@ func getEngine() (*xorm.Engine, error) { switch DbCfg.Type { case "mysql": cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8", - DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name) + DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name) case "postgres": var host, port = "127.0.0.1", "5432" fields := strings.Split(DbCfg.Host, ":") @@ -80,7 +81,7 @@ func getEngine() (*xorm.Engine, error) { port = fields[1] } cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s", - DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode) + DbCfg.User, DbCfg.Passwd, host, port, DbCfg.Name, DbCfg.SSLMode) case "sqlite3": if !EnableSQLite3 { return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type) @@ -96,7 +97,7 @@ func getEngine() (*xorm.Engine, error) { func NewTestEngine(x *xorm.Engine) (err error) { x, err = getEngine() if err != nil { - return fmt.Errorf("models.init(fail to connect to database): %v", err) + return fmt.Errorf("connect to database: %v", err) } return x.Sync(tables...) @@ -105,7 +106,7 @@ func NewTestEngine(x *xorm.Engine) (err error) { func SetEngine() (err error) { x, err = getEngine() if err != nil { - return fmt.Errorf("models.init(fail to connect to database): %v", err) + return fmt.Errorf("connect to database: %v", err) } // WARNING: for serv command, MUST remove the output to os.stdout, @@ -131,6 +132,11 @@ func NewEngine() (err error) { if err = SetEngine(); err != nil { return err } + + if err = migrations.Migrate(x); err != nil { + return err + } + if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil { return fmt.Errorf("sync database struct error: %v\n", err) } diff --git a/models/publickey.go b/models/publickey.go index fbba691a..41233d0c 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -6,6 +6,8 @@ package models import ( "bufio" + "encoding/base64" + "encoding/binary" "errors" "fmt" "io" @@ -111,6 +113,85 @@ var ( } ) +func extractTypeFromBase64Key(key string) (string, error) { + b, err := base64.StdEncoding.DecodeString(key) + if err != nil || len(b) < 4 { + return "", errors.New("Invalid key format") + } + + keyLength := int(binary.BigEndian.Uint32(b)) + + if len(b) < 4+keyLength { + return "", errors.New("Invalid key format") + } + + return string(b[4 : 4+keyLength]), nil +} + +// Parse any key string in openssh or ssh2 format to clean openssh string (rfc4253) +func ParseKeyString(content string) (string, error) { + + // Transform all legal line endings to a single "\n" + s := strings.Replace(strings.Replace(strings.TrimSpace(content), "\r\n", "\n", -1), "\r", "\n", -1) + + lines := strings.Split(s, "\n") + + var keyType, keyContent, keyComment string + + if len(lines) == 1 { + // Parse openssh format + parts := strings.Fields(lines[0]) + switch len(parts) { + case 0: + return "", errors.New("Empty key") + case 1: + keyContent = parts[0] + case 2: + keyType = parts[0] + keyContent = parts[1] + default: + keyType = parts[0] + keyContent = parts[1] + keyComment = parts[2] + } + + // If keyType is not given, extract it from content. If given, validate it + if len(keyType) == 0 { + if t, err := extractTypeFromBase64Key(keyContent); err == nil { + keyType = t + } else { + return "", err + } + } else { + if t, err := extractTypeFromBase64Key(keyContent); err != nil || keyType != t { + return "", err + } + } + } else { + // Parse SSH2 file format. + continuationLine := false + + for _, line := range lines { + // Skip lines that: + // 1) are a continuation of the previous line, + // 2) contain ":" as that are comment lines + // 3) contain "-" as that are begin and end tags + if continuationLine || strings.ContainsAny(line, ":-") { + continuationLine = strings.HasSuffix(line, "\\") + } else { + keyContent = keyContent + line + } + } + + if t, err := extractTypeFromBase64Key(keyContent); err == nil { + keyType = t + } else { + return "", err + } + } + return keyType + " " + keyContent + " " + keyComment, nil +} + // CheckPublicKeyString checks if the given public key string is recognized by SSH. func CheckPublicKeyString(content string) (bool, error) { content = strings.TrimRight(content, "\n\r") diff --git a/models/repo.go b/models/repo.go index 50b2b3fc..58c099d4 100644 --- a/models/repo.go +++ b/models/repo.go @@ -7,7 +7,6 @@ package models import ( "errors" "fmt" - "html" "html/template" "io/ioutil" "os" @@ -218,11 +217,9 @@ func (repo *Repository) HasAccess(uname string) bool { // DescriptionHtml does special handles to description and return HTML string. func (repo *Repository) DescriptionHtml() template.HTML { sanitize := func(s string) string { - // TODO(nuss-justin): Improve sanitization. Strip all tags? - ss := html.EscapeString(s) - return fmt.Sprintf(`<a href="%s" target="_blank">%s</a>`, ss, ss) + return fmt.Sprintf(`<a href="%[1]s" target="_blank">%[1]s</a>`, s) } - return template.HTML(DescPattern.ReplaceAllStringFunc(base.XSSString(repo.Description), sanitize)) + return template.HTML(DescPattern.ReplaceAllStringFunc(base.Sanitizer.Sanitize(repo.Description), sanitize)) } // IsRepositoryExist returns true if the repository with given name under user has already existed. @@ -829,6 +826,8 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) error { // ChangeRepositoryName changes all corresponding setting from old repository name to new one. func ChangeRepositoryName(userName, oldRepoName, newRepoName string) (err error) { + userName = strings.ToLower(userName) + oldRepoName = strings.ToLower(oldRepoName) newRepoName = strings.ToLower(newRepoName) if !IsLegalName(newRepoName) { return ErrRepoNameIllegal @@ -836,7 +835,7 @@ func ChangeRepositoryName(userName, oldRepoName, newRepoName string) (err error) // Update accesses. accesses := make([]Access, 0, 10) - if err = x.Find(&accesses, &Access{RepoName: strings.ToLower(userName + "/" + oldRepoName)}); err != nil { + if err = x.Find(&accesses, &Access{RepoName: userName + "/" + oldRepoName}); err != nil { return err } @@ -1184,6 +1183,8 @@ func MirrorUpdate() { isMirrorUpdating = true defer func() { isMirrorUpdating = false }() + mirrors := make([]*Mirror, 0, 10) + if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error { m := bean.(*Mirror) if m.NextUpdate.After(time.Now()) { @@ -1194,13 +1195,25 @@ func MirrorUpdate() { if _, stderr, err := process.ExecDir(10*time.Minute, repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath), "git", "remote", "update"); err != nil { - return errors.New("git remote update: " + stderr) + desc := fmt.Sprintf("Fail to update mirror repository(%s): %s", repoPath, stderr) + log.Error(4, desc) + if err = CreateRepositoryNotice(desc); err != nil { + log.Error(4, "Fail to add notice: %v", err) + } + return nil } m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour) - return UpdateMirror(m) + mirrors = append(mirrors, m) + return nil }); err != nil { - log.Error(4, "repo.MirrorUpdate: %v", err) + log.Error(4, "MirrorUpdate: %v", err) + } + + for i := range mirrors { + if err := UpdateMirror(mirrors[i]); err != nil { + log.Error(4, "UpdateMirror", fmt.Sprintf("%s: %v", mirrors[i].RepoName, err)) + } } } @@ -1212,7 +1225,7 @@ func GitFsck() { isGitFscking = true defer func() { isGitFscking = false }() - args := append([]string{"fsck"}, setting.GitFsckArgs...) + args := append([]string{"fsck"}, setting.Git.Fsck.Args...) if err := x.Where("id > 0").Iterate(new(Repository), func(idx int, bean interface{}) error { repo := bean.(*Repository) @@ -1236,7 +1249,7 @@ func GitFsck() { } func GitGcRepos() error { - args := append([]string{"gc"}, setting.GitGcArgs...) + args := append([]string{"gc"}, setting.Git.GcArgs...) return x.Where("id > 0").Iterate(new(Repository), func(idx int, bean interface{}) error { repo := bean.(*Repository) |