summaryrefslogtreecommitdiffstats
path: root/app/user.go
diff options
context:
space:
mode:
Diffstat (limited to 'app/user.go')
-rw-r--r--app/user.go421
1 files changed, 421 insertions, 0 deletions
diff --git a/app/user.go b/app/user.go
index 5acd9dcaa..909c8cca9 100644
--- a/app/user.go
+++ b/app/user.go
@@ -4,11 +4,105 @@
package app
import (
+ "bytes"
+ "fmt"
+ "hash/fnv"
+ "image"
+ "image/color"
+ "image/draw"
+ _ "image/gif"
+ _ "image/jpeg"
+ "image/png"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "strconv"
+ "strings"
+
l4g "github.com/alecthomas/log4go"
+ "github.com/golang/freetype"
+ "github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
)
+func CreateUserWithHash(user *model.User, hash string, data string) (*model.User, *model.AppError) {
+ props := model.MapFromJson(strings.NewReader(data))
+
+ if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
+ return nil, model.NewLocAppError("CreateUserWithHash", "api.user.create_user.signup_link_invalid.app_error", nil, "")
+ }
+
+ if t, err := strconv.ParseInt(props["time"], 10, 64); err != nil || model.GetMillis()-t > 1000*60*60*48 { // 48 hours
+ return nil, model.NewLocAppError("CreateUserWithHash", "api.user.create_user.signup_link_expired.app_error", nil, "")
+ }
+
+ teamId := props["id"]
+
+ var team *model.Team
+ if result := <-Srv.Store.Team().Get(teamId); result.Err != nil {
+ return nil, result.Err
+ } else {
+ team = result.Data.(*model.Team)
+ }
+
+ user.Email = props["email"]
+ user.EmailVerified = true
+
+ var ruser *model.User
+ var err *model.AppError
+ if ruser, err = CreateUser(user); err != nil {
+ return nil, err
+ }
+
+ if err := JoinUserToTeam(team, ruser); err != nil {
+ return nil, err
+ }
+
+ AddDirectChannels(team.Id, ruser)
+
+ return ruser, nil
+}
+
+func CreateUserWithInviteId(user *model.User, inviteId string) (*model.User, *model.AppError) {
+ var team *model.Team
+ if result := <-Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil {
+ return nil, result.Err
+ } else {
+ team = result.Data.(*model.Team)
+ }
+
+ var ruser *model.User
+ var err *model.AppError
+ if ruser, err = CreateUser(user); err != nil {
+ return nil, err
+ }
+
+ if err := JoinUserToTeam(team, ruser); err != nil {
+ return nil, err
+ }
+
+ AddDirectChannels(team.Id, ruser)
+
+ return ruser, nil
+}
+
+func IsFirstUserAccount() bool {
+ if SessionCacheLength() == 0 {
+ if cr := <-Srv.Store.User().GetTotalUsersCount(); cr.Err != nil {
+ l4g.Error(cr.Err)
+ return false
+ } else {
+ count := cr.Data.(int64)
+ if count <= 0 {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
func CreateUser(user *model.User) (*model.User, *model.AppError) {
user.Roles = model.ROLE_SYSTEM_USER.Id
@@ -58,3 +152,330 @@ func CreateUser(user *model.User) (*model.User, *model.AppError) {
return ruser, nil
}
}
+
+func CreateOAuthUser(service string, userData io.Reader, teamId string) (*model.User, *model.AppError) {
+ var user *model.User
+ provider := einterfaces.GetOauthProvider(service)
+ if provider == nil {
+ return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.not_available.app_error", map[string]interface{}{"Service": strings.Title(service)}, "")
+ } else {
+ user = provider.GetUserFromJson(userData)
+ }
+
+ if user == nil {
+ return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.create.app_error", map[string]interface{}{"Service": service}, "")
+ }
+
+ suchan := Srv.Store.User().GetByAuth(user.AuthData, service)
+ euchan := Srv.Store.User().GetByEmail(user.Email)
+
+ found := true
+ count := 0
+ for found {
+ if found = IsUsernameTaken(user.Username); found {
+ user.Username = user.Username + strconv.Itoa(count)
+ count += 1
+ }
+ }
+
+ if result := <-suchan; result.Err == nil {
+ return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.already_used.app_error", map[string]interface{}{"Service": service}, "email="+user.Email)
+ }
+
+ if result := <-euchan; result.Err == nil {
+ authService := result.Data.(*model.User).AuthService
+ if authService == "" {
+ return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.already_attached.app_error",
+ map[string]interface{}{"Service": service, "Auth": model.USER_AUTH_SERVICE_EMAIL}, "email="+user.Email)
+ } else {
+ return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.already_attached.app_error",
+ map[string]interface{}{"Service": service, "Auth": authService}, "email="+user.Email)
+ }
+ }
+
+ user.EmailVerified = true
+
+ ruser, err := CreateUser(user)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(teamId) > 0 {
+ err = JoinUserToTeamById(teamId, user)
+ if err != nil {
+ return nil, err
+ }
+
+ err = AddDirectChannels(teamId, user)
+ if err != nil {
+ l4g.Error(err.Error())
+ }
+ }
+
+ return ruser, nil
+}
+
+// Check if the username is already used by another user. Return false if the username is invalid.
+func IsUsernameTaken(name string) bool {
+
+ if !model.IsValidUsername(name) {
+ return false
+ }
+
+ if result := <-Srv.Store.User().GetByUsername(name); result.Err != nil {
+ return false
+ } else {
+ return true
+ }
+
+ return false
+}
+
+func GetUser(userId string) (*model.User, *model.AppError) {
+ if result := <-Srv.Store.User().Get(userId); result.Err != nil {
+ return nil, result.Err
+ } else {
+ return result.Data.(*model.User), nil
+ }
+}
+
+func GetUserByUsername(username string) (*model.User, *model.AppError) {
+ if result := <-Srv.Store.User().GetByUsername(username); result.Err != nil {
+ return nil, result.Err
+ } else {
+ return result.Data.(*model.User), nil
+ }
+}
+
+func GetUserByEmail(email string) (*model.User, *model.AppError) {
+ if result := <-Srv.Store.User().GetByEmail(email); result.Err != nil {
+ return nil, result.Err
+ } else {
+ return result.Data.(*model.User), nil
+ }
+}
+
+func GetUserByAuth(authData *string, authService string) (*model.User, *model.AppError) {
+ if result := <-Srv.Store.User().GetByAuth(authData, authService); result.Err != nil {
+ return nil, result.Err
+ } else {
+ return result.Data.(*model.User), nil
+ }
+}
+
+func GetUserForLogin(loginId string, onlyLdap bool) (*model.User, *model.AppError) {
+ ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil && utils.IsLicensed && *utils.License.Features.LDAP
+
+ if result := <-Srv.Store.User().GetForLogin(
+ loginId,
+ *utils.Cfg.EmailSettings.EnableSignInWithUsername && !onlyLdap,
+ *utils.Cfg.EmailSettings.EnableSignInWithEmail && !onlyLdap,
+ ldapAvailable,
+ ); result.Err != nil && result.Err.Id == "store.sql_user.get_for_login.multiple_users" {
+ // don't fall back to LDAP in this case since we already know there's an LDAP user, but that it shouldn't work
+ result.Err.StatusCode = http.StatusBadRequest
+ return nil, result.Err
+ } else if result.Err != nil {
+ if !ldapAvailable {
+ // failed to find user and no LDAP server to fall back on
+ result.Err.StatusCode = http.StatusBadRequest
+ return nil, result.Err
+ }
+
+ // fall back to LDAP server to see if we can find a user
+ if ldapUser, ldapErr := einterfaces.GetLdapInterface().GetUser(loginId); ldapErr != nil {
+ ldapErr.StatusCode = http.StatusBadRequest
+ return nil, ldapErr
+ } else {
+ return ldapUser, nil
+ }
+ } else {
+ return result.Data.(*model.User), nil
+ }
+}
+
+func GetUsers(offset int, limit int) (map[string]*model.User, *model.AppError) {
+ if result := <-Srv.Store.User().GetAllProfiles(offset, limit); result.Err != nil {
+ return nil, result.Err
+ } else {
+ return result.Data.(map[string]*model.User), nil
+ }
+}
+
+func GetUsersEtag() string {
+ return (<-Srv.Store.User().GetEtagForAllProfiles()).Data.(string)
+}
+
+func GetUsersInTeam(teamId string, offset int, limit int) (map[string]*model.User, *model.AppError) {
+ if result := <-Srv.Store.User().GetProfiles(teamId, offset, limit); result.Err != nil {
+ return nil, result.Err
+ } else {
+ return result.Data.(map[string]*model.User), nil
+ }
+}
+
+func GetUsersInTeamEtag(teamId string) string {
+ return (<-Srv.Store.User().GetEtagForProfiles(teamId)).Data.(string)
+}
+
+func GetUsersInChannel(channelId string, offset int, limit int) (map[string]*model.User, *model.AppError) {
+ if result := <-Srv.Store.User().GetProfilesInChannel(channelId, offset, limit, false); result.Err != nil {
+ return nil, result.Err
+ } else {
+ return result.Data.(map[string]*model.User), nil
+ }
+}
+
+func GetUsersNotInChannel(teamId string, channelId string, offset int, limit int) (map[string]*model.User, *model.AppError) {
+ if result := <-Srv.Store.User().GetProfilesNotInChannel(teamId, channelId, offset, limit); result.Err != nil {
+ return nil, result.Err
+ } else {
+ return result.Data.(map[string]*model.User), nil
+ }
+}
+
+func ActivateMfa(userId, token string) *model.AppError {
+ mfaInterface := einterfaces.GetMfaInterface()
+ if mfaInterface == nil {
+ err := model.NewLocAppError("ActivateMfa", "api.user.update_mfa.not_available.app_error", nil, "")
+ err.StatusCode = http.StatusNotImplemented
+ return err
+ }
+
+ var user *model.User
+ if result := <-Srv.Store.User().Get(userId); result.Err != nil {
+ return result.Err
+ } else {
+ user = result.Data.(*model.User)
+ }
+
+ if len(user.AuthService) > 0 && user.AuthService != model.USER_AUTH_SERVICE_LDAP {
+ return model.NewLocAppError("ActivateMfa", "api.user.activate_mfa.email_and_ldap_only.app_error", nil, "")
+ }
+
+ if err := mfaInterface.Activate(user, token); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func DeactivateMfa(userId string) *model.AppError {
+ mfaInterface := einterfaces.GetMfaInterface()
+ if mfaInterface == nil {
+ err := model.NewLocAppError("DeactivateMfa", "api.user.update_mfa.not_available.app_error", nil, "")
+ err.StatusCode = http.StatusNotImplemented
+ return err
+ }
+
+ if err := mfaInterface.Deactivate(userId); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func CreateProfileImage(username string, userId string) ([]byte, *model.AppError) {
+ colors := []color.NRGBA{
+ {197, 8, 126, 255},
+ {227, 207, 18, 255},
+ {28, 181, 105, 255},
+ {35, 188, 224, 255},
+ {116, 49, 196, 255},
+ {197, 8, 126, 255},
+ {197, 19, 19, 255},
+ {250, 134, 6, 255},
+ {227, 207, 18, 255},
+ {123, 201, 71, 255},
+ {28, 181, 105, 255},
+ {35, 188, 224, 255},
+ {116, 49, 196, 255},
+ {197, 8, 126, 255},
+ {197, 19, 19, 255},
+ {250, 134, 6, 255},
+ {227, 207, 18, 255},
+ {123, 201, 71, 255},
+ {28, 181, 105, 255},
+ {35, 188, 224, 255},
+ {116, 49, 196, 255},
+ {197, 8, 126, 255},
+ {197, 19, 19, 255},
+ {250, 134, 6, 255},
+ {227, 207, 18, 255},
+ {123, 201, 71, 255},
+ }
+
+ h := fnv.New32a()
+ h.Write([]byte(userId))
+ seed := h.Sum32()
+
+ initial := string(strings.ToUpper(username)[0])
+
+ fontBytes, err := ioutil.ReadFile(utils.FindDir("fonts") + utils.Cfg.FileSettings.InitialFont)
+ if err != nil {
+ return nil, model.NewLocAppError("CreateProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error())
+ }
+ font, err := freetype.ParseFont(fontBytes)
+ if err != nil {
+ return nil, model.NewLocAppError("CreateProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error())
+ }
+
+ width := int(utils.Cfg.FileSettings.ProfileWidth)
+ height := int(utils.Cfg.FileSettings.ProfileHeight)
+ color := colors[int64(seed)%int64(len(colors))]
+ dstImg := image.NewRGBA(image.Rect(0, 0, width, height))
+ srcImg := image.White
+ draw.Draw(dstImg, dstImg.Bounds(), &image.Uniform{color}, image.ZP, draw.Src)
+ size := float64((width + height) / 4)
+
+ c := freetype.NewContext()
+ c.SetFont(font)
+ c.SetFontSize(size)
+ c.SetClip(dstImg.Bounds())
+ c.SetDst(dstImg)
+ c.SetSrc(srcImg)
+
+ pt := freetype.Pt(width/6, height*2/3)
+ _, err = c.DrawString(initial, pt)
+ if err != nil {
+ return nil, model.NewLocAppError("CreateProfileImage", "api.user.create_profile_image.initial.app_error", nil, err.Error())
+ }
+
+ buf := new(bytes.Buffer)
+
+ if imgErr := png.Encode(buf, dstImg); imgErr != nil {
+ return nil, model.NewLocAppError("CreateProfileImage", "api.user.create_profile_image.encode.app_error", nil, imgErr.Error())
+ } else {
+ return buf.Bytes(), nil
+ }
+}
+
+func GetProfileImage(user *model.User) ([]byte, *model.AppError) {
+ var img []byte
+
+ if len(utils.Cfg.FileSettings.DriverName) == 0 {
+ var err *model.AppError
+ if img, err = CreateProfileImage(user.Username, user.Id); err != nil {
+ return nil, err
+ }
+ } else {
+ path := "users/" + user.Id + "/profile.png"
+
+ if data, err := ReadFile(path); err != nil {
+ if img, err = CreateProfileImage(user.Username, user.Id); err != nil {
+ return nil, err
+ }
+
+ if user.LastPictureUpdate == 0 {
+ if err := WriteFile(img, path); err != nil {
+ return nil, err
+ }
+ }
+
+ } else {
+ img = data
+ }
+ }
+
+ return img, nil
+}