diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 5ae139cb3..226e54817 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -88,6 +88,8 @@ var migrations = []Migration{ NewMigration("add external login user", addExternalLoginUser), // v19 -> v20 NewMigration("generate and migrate Git hooks", generateAndMigrateGitHooks), + // v20 -> v21 + NewMigration("use new avtar path name for security reason", useNewNameAvatars), } // Migrate database to current version diff --git a/models/migrations/v20.go b/models/migrations/v20.go new file mode 100644 index 000000000..134a3d51e --- /dev/null +++ b/models/migrations/v20.go @@ -0,0 +1,66 @@ +// Copyright 2017 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 ( + "crypto/md5" + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + + "code.gitea.io/gitea/modules/setting" + + "github.com/go-xorm/xorm" +) + +func useNewNameAvatars(x *xorm.Engine) error { + d, err := os.Open(setting.AvatarUploadPath) + if err != nil { + return err + } + names, err := d.Readdirnames(0) + if err != nil { + return err + } + + type User struct { + Avatar string + UseCustomAvatar bool + } + + for _, name := range names { + userID, err := strconv.ParseInt(name, 10, 64) + if err != nil { + return err + } + + var user User + if has, err := x.ID(userID).Get(&user); err != nil { + return err + } else if !has { + return errors.New("Avatar user is not exist") + } + + fPath := filepath.Join(setting.AvatarUploadPath, name) + bs, err := ioutil.ReadFile(fPath) + if err != nil { + return err + } + + user.Avatar = fmt.Sprintf("%x", md5.Sum(bs)) + err = os.Rename(fPath, filepath.Join(setting.AvatarUploadPath, user.Avatar)) + if err != nil { + return err + } + _, err = x.ID(userID).Cols("avatar").Update(&user) + if err != nil { + return err + } + } + return nil +} diff --git a/models/user.go b/models/user.go index 4b019d8d3..e03506c31 100644 --- a/models/user.go +++ b/models/user.go @@ -7,6 +7,7 @@ package models import ( "bytes" "container/list" + "crypto/md5" "crypto/sha256" "crypto/subtle" "encoding/hex" @@ -281,7 +282,7 @@ func (u *User) GenerateActivateCode() string { // CustomAvatarPath returns user custom avatar file path. func (u *User) CustomAvatarPath() string { - return filepath.Join(setting.AvatarUploadPath, com.ToStr(u.ID)) + return filepath.Join(setting.AvatarUploadPath, u.Avatar) } // GenerateRandomAvatar generates a random avatar for user. @@ -326,7 +327,7 @@ func (u *User) RelAvatarLink() string { if !com.IsExist(u.CustomAvatarPath()) { return defaultImgURL } - return setting.AppSubURL + "/avatars/" + com.ToStr(u.ID) + return setting.AppSubURL + "/avatars/" + u.Avatar case setting.DisableGravatar, setting.OfflineMode: if !com.IsExist(u.CustomAvatarPath()) { if err := u.GenerateRandomAvatar(); err != nil { @@ -334,7 +335,7 @@ func (u *User) RelAvatarLink() string { } } - return setting.AppSubURL + "/avatars/" + com.ToStr(u.ID) + return setting.AppSubURL + "/avatars/" + u.Avatar } return base.AvatarLink(u.AvatarEmail) } @@ -425,6 +426,7 @@ func (u *User) UploadAvatar(data []byte) error { } u.UseCustomAvatar = true + u.Avatar = fmt.Sprintf("%x", md5.Sum(data)) if err = updateUser(sess, u); err != nil { return fmt.Errorf("updateUser: %v", err) }