aboutsummaryrefslogtreecommitdiff
path: root/models
diff options
context:
space:
mode:
Diffstat (limited to 'models')
-rw-r--r--models/action.go1
-rw-r--r--models/git_diff.go18
-rw-r--r--models/migrations/migrations.go53
-rw-r--r--models/models.go22
-rw-r--r--models/publickey.go81
-rw-r--r--models/repo.go35
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)