github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/model/user.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package model
     5  
     6  import (
     7  	"crypto/sha256"
     8  	"encoding/json"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"math/rand"
    13  	"net/http"
    14  	"regexp"
    15  	"sort"
    16  	"strings"
    17  	"time"
    18  	"unicode/utf8"
    19  
    20  	"github.com/mattermost/mattermost-server/v5/services/timezones"
    21  	"golang.org/x/crypto/bcrypt"
    22  	"golang.org/x/text/language"
    23  )
    24  
    25  const (
    26  	ME                                 = "me"
    27  	USER_NOTIFY_ALL                    = "all"
    28  	USER_NOTIFY_HERE                   = "here"
    29  	USER_NOTIFY_MENTION                = "mention"
    30  	USER_NOTIFY_NONE                   = "none"
    31  	DESKTOP_NOTIFY_PROP                = "desktop"
    32  	DESKTOP_SOUND_NOTIFY_PROP          = "desktop_sound"
    33  	MARK_UNREAD_NOTIFY_PROP            = "mark_unread"
    34  	PUSH_NOTIFY_PROP                   = "push"
    35  	PUSH_STATUS_NOTIFY_PROP            = "push_status"
    36  	EMAIL_NOTIFY_PROP                  = "email"
    37  	CHANNEL_MENTIONS_NOTIFY_PROP       = "channel"
    38  	COMMENTS_NOTIFY_PROP               = "comments"
    39  	MENTION_KEYS_NOTIFY_PROP           = "mention_keys"
    40  	COMMENTS_NOTIFY_NEVER              = "never"
    41  	COMMENTS_NOTIFY_ROOT               = "root"
    42  	COMMENTS_NOTIFY_ANY                = "any"
    43  	FIRST_NAME_NOTIFY_PROP             = "first_name"
    44  	AUTO_RESPONDER_ACTIVE_NOTIFY_PROP  = "auto_responder_active"
    45  	AUTO_RESPONDER_MESSAGE_NOTIFY_PROP = "auto_responder_message"
    46  
    47  	DEFAULT_LOCALE          = "en"
    48  	USER_AUTH_SERVICE_EMAIL = "email"
    49  
    50  	USER_EMAIL_MAX_LENGTH     = 128
    51  	USER_NICKNAME_MAX_RUNES   = 64
    52  	USER_POSITION_MAX_RUNES   = 128
    53  	USER_FIRST_NAME_MAX_RUNES = 64
    54  	USER_LAST_NAME_MAX_RUNES  = 64
    55  	USER_AUTH_DATA_MAX_LENGTH = 128
    56  	USER_NAME_MAX_LENGTH      = 64
    57  	USER_NAME_MIN_LENGTH      = 1
    58  	USER_PASSWORD_MAX_LENGTH  = 72
    59  	USER_LOCALE_MAX_LENGTH    = 5
    60  )
    61  
    62  type User struct {
    63  	Id                     string    `json:"id"`
    64  	CreateAt               int64     `json:"create_at,omitempty"`
    65  	UpdateAt               int64     `json:"update_at,omitempty"`
    66  	DeleteAt               int64     `json:"delete_at"`
    67  	Username               string    `json:"username"`
    68  	Password               string    `json:"password,omitempty"`
    69  	AuthData               *string   `json:"auth_data,omitempty"`
    70  	AuthService            string    `json:"auth_service"`
    71  	Email                  string    `json:"email"`
    72  	EmailVerified          bool      `json:"email_verified,omitempty"`
    73  	Nickname               string    `json:"nickname"`
    74  	FirstName              string    `json:"first_name"`
    75  	LastName               string    `json:"last_name"`
    76  	Position               string    `json:"position"`
    77  	Roles                  string    `json:"roles"`
    78  	AllowMarketing         bool      `json:"allow_marketing,omitempty"`
    79  	Props                  StringMap `json:"props,omitempty"`
    80  	NotifyProps            StringMap `json:"notify_props,omitempty"`
    81  	LastPasswordUpdate     int64     `json:"last_password_update,omitempty"`
    82  	LastPictureUpdate      int64     `json:"last_picture_update,omitempty"`
    83  	FailedAttempts         int       `json:"failed_attempts,omitempty"`
    84  	Locale                 string    `json:"locale"`
    85  	Timezone               StringMap `json:"timezone"`
    86  	MfaActive              bool      `json:"mfa_active,omitempty"`
    87  	MfaSecret              string    `json:"mfa_secret,omitempty"`
    88  	LastActivityAt         int64     `db:"-" json:"last_activity_at,omitempty"`
    89  	IsBot                  bool      `db:"-" json:"is_bot,omitempty"`
    90  	BotDescription         string    `db:"-" json:"bot_description,omitempty"`
    91  	BotLastIconUpdate      int64     `db:"-" json:"bot_last_icon_update,omitempty"`
    92  	TermsOfServiceId       string    `db:"-" json:"terms_of_service_id,omitempty"`
    93  	TermsOfServiceCreateAt int64     `db:"-" json:"terms_of_service_create_at,omitempty"`
    94  }
    95  
    96  type UserUpdate struct {
    97  	Old *User
    98  	New *User
    99  }
   100  
   101  type UserPatch struct {
   102  	Username    *string   `json:"username"`
   103  	Password    *string   `json:"password,omitempty"`
   104  	Nickname    *string   `json:"nickname"`
   105  	FirstName   *string   `json:"first_name"`
   106  	LastName    *string   `json:"last_name"`
   107  	Position    *string   `json:"position"`
   108  	Email       *string   `json:"email"`
   109  	Props       StringMap `json:"props,omitempty"`
   110  	NotifyProps StringMap `json:"notify_props,omitempty"`
   111  	Locale      *string   `json:"locale"`
   112  	Timezone    StringMap `json:"timezone"`
   113  }
   114  
   115  type UserAuth struct {
   116  	Password    string  `json:"password,omitempty"`
   117  	AuthData    *string `json:"auth_data,omitempty"`
   118  	AuthService string  `json:"auth_service,omitempty"`
   119  }
   120  
   121  type UserForIndexing struct {
   122  	Id          string   `json:"id"`
   123  	Username    string   `json:"username"`
   124  	Nickname    string   `json:"nickname"`
   125  	FirstName   string   `json:"first_name"`
   126  	LastName    string   `json:"last_name"`
   127  	Roles       string   `json:"roles"`
   128  	CreateAt    int64    `json:"create_at"`
   129  	DeleteAt    int64    `json:"delete_at"`
   130  	TeamsIds    []string `json:"team_id"`
   131  	ChannelsIds []string `json:"channel_id"`
   132  }
   133  
   134  type ViewUsersRestrictions struct {
   135  	Teams    []string
   136  	Channels []string
   137  }
   138  
   139  func (r *ViewUsersRestrictions) Hash() string {
   140  	if r == nil {
   141  		return ""
   142  	}
   143  	ids := append(r.Teams, r.Channels...)
   144  	sort.Strings(ids)
   145  	hash := sha256.New()
   146  	hash.Write([]byte(strings.Join(ids, "")))
   147  	return fmt.Sprintf("%x", hash.Sum(nil))
   148  }
   149  
   150  type UserSlice []*User
   151  
   152  func (u UserSlice) Usernames() []string {
   153  	usernames := []string{}
   154  	for _, user := range u {
   155  		usernames = append(usernames, user.Username)
   156  	}
   157  	sort.Strings(usernames)
   158  	return usernames
   159  }
   160  
   161  func (u UserSlice) IDs() []string {
   162  	ids := []string{}
   163  	for _, user := range u {
   164  		ids = append(ids, user.Id)
   165  	}
   166  	return ids
   167  }
   168  
   169  func (u UserSlice) FilterWithoutBots() UserSlice {
   170  	var matches []*User
   171  
   172  	for _, user := range u {
   173  		if !user.IsBot {
   174  			matches = append(matches, user)
   175  		}
   176  	}
   177  	return UserSlice(matches)
   178  }
   179  
   180  func (u UserSlice) FilterByActive(active bool) UserSlice {
   181  	var matches []*User
   182  
   183  	for _, user := range u {
   184  		if user.DeleteAt == 0 && active {
   185  			matches = append(matches, user)
   186  		} else if user.DeleteAt != 0 && !active {
   187  			matches = append(matches, user)
   188  		}
   189  	}
   190  	return UserSlice(matches)
   191  }
   192  
   193  func (u UserSlice) FilterByID(ids []string) UserSlice {
   194  	var matches []*User
   195  	for _, user := range u {
   196  		for _, id := range ids {
   197  			if id == user.Id {
   198  				matches = append(matches, user)
   199  			}
   200  		}
   201  	}
   202  	return UserSlice(matches)
   203  }
   204  
   205  func (u UserSlice) FilterWithoutID(ids []string) UserSlice {
   206  	var keep []*User
   207  	for _, user := range u {
   208  		present := false
   209  		for _, id := range ids {
   210  			if id == user.Id {
   211  				present = true
   212  			}
   213  		}
   214  		if !present {
   215  			keep = append(keep, user)
   216  		}
   217  	}
   218  	return UserSlice(keep)
   219  }
   220  
   221  func (u *User) DeepCopy() *User {
   222  	copyUser := *u
   223  	if u.AuthData != nil {
   224  		copyUser.AuthData = NewString(*u.AuthData)
   225  	}
   226  	if u.Props != nil {
   227  		copyUser.Props = CopyStringMap(u.Props)
   228  	}
   229  	if u.NotifyProps != nil {
   230  		copyUser.NotifyProps = CopyStringMap(u.NotifyProps)
   231  	}
   232  	if u.Timezone != nil {
   233  		copyUser.Timezone = CopyStringMap(u.Timezone)
   234  	}
   235  	return &copyUser
   236  }
   237  
   238  // IsValid validates the user and returns an error if it isn't configured
   239  // correctly.
   240  func (u *User) IsValid() *AppError {
   241  
   242  	if !IsValidId(u.Id) {
   243  		return InvalidUserError("id", "")
   244  	}
   245  
   246  	if u.CreateAt == 0 {
   247  		return InvalidUserError("create_at", u.Id)
   248  	}
   249  
   250  	if u.UpdateAt == 0 {
   251  		return InvalidUserError("update_at", u.Id)
   252  	}
   253  
   254  	if !IsValidUsername(u.Username) {
   255  		return InvalidUserError("username", u.Id)
   256  	}
   257  
   258  	if len(u.Email) > USER_EMAIL_MAX_LENGTH || len(u.Email) == 0 || !IsValidEmail(u.Email) {
   259  		return InvalidUserError("email", u.Id)
   260  	}
   261  
   262  	if utf8.RuneCountInString(u.Nickname) > USER_NICKNAME_MAX_RUNES {
   263  		return InvalidUserError("nickname", u.Id)
   264  	}
   265  
   266  	if utf8.RuneCountInString(u.Position) > USER_POSITION_MAX_RUNES {
   267  		return InvalidUserError("position", u.Id)
   268  	}
   269  
   270  	if utf8.RuneCountInString(u.FirstName) > USER_FIRST_NAME_MAX_RUNES {
   271  		return InvalidUserError("first_name", u.Id)
   272  	}
   273  
   274  	if utf8.RuneCountInString(u.LastName) > USER_LAST_NAME_MAX_RUNES {
   275  		return InvalidUserError("last_name", u.Id)
   276  	}
   277  
   278  	if u.AuthData != nil && len(*u.AuthData) > USER_AUTH_DATA_MAX_LENGTH {
   279  		return InvalidUserError("auth_data", u.Id)
   280  	}
   281  
   282  	if u.AuthData != nil && len(*u.AuthData) > 0 && len(u.AuthService) == 0 {
   283  		return InvalidUserError("auth_data_type", u.Id)
   284  	}
   285  
   286  	if len(u.Password) > 0 && u.AuthData != nil && len(*u.AuthData) > 0 {
   287  		return InvalidUserError("auth_data_pwd", u.Id)
   288  	}
   289  
   290  	if len(u.Password) > USER_PASSWORD_MAX_LENGTH {
   291  		return InvalidUserError("password_limit", u.Id)
   292  	}
   293  
   294  	if !IsValidLocale(u.Locale) {
   295  		return InvalidUserError("locale", u.Id)
   296  	}
   297  
   298  	return nil
   299  }
   300  
   301  func InvalidUserError(fieldName string, userId string) *AppError {
   302  	id := fmt.Sprintf("model.user.is_valid.%s.app_error", fieldName)
   303  	details := ""
   304  	if userId != "" {
   305  		details = "user_id=" + userId
   306  	}
   307  	return NewAppError("User.IsValid", id, nil, details, http.StatusBadRequest)
   308  }
   309  
   310  func NormalizeUsername(username string) string {
   311  	return strings.ToLower(username)
   312  }
   313  
   314  func NormalizeEmail(email string) string {
   315  	return strings.ToLower(email)
   316  }
   317  
   318  // PreSave will set the Id and Username if missing.  It will also fill
   319  // in the CreateAt, UpdateAt times.  It will also hash the password.  It should
   320  // be run before saving the user to the db.
   321  func (u *User) PreSave() {
   322  	if u.Id == "" {
   323  		u.Id = NewId()
   324  	}
   325  
   326  	if u.Username == "" {
   327  		u.Username = NewId()
   328  	}
   329  
   330  	if u.AuthData != nil && *u.AuthData == "" {
   331  		u.AuthData = nil
   332  	}
   333  
   334  	u.Username = SanitizeUnicode(u.Username)
   335  	u.FirstName = SanitizeUnicode(u.FirstName)
   336  	u.LastName = SanitizeUnicode(u.LastName)
   337  	u.Nickname = SanitizeUnicode(u.Nickname)
   338  
   339  	u.Username = NormalizeUsername(u.Username)
   340  	u.Email = NormalizeEmail(u.Email)
   341  
   342  	u.CreateAt = GetMillis()
   343  	u.UpdateAt = u.CreateAt
   344  
   345  	u.LastPasswordUpdate = u.CreateAt
   346  
   347  	u.MfaActive = false
   348  
   349  	if u.Locale == "" {
   350  		u.Locale = DEFAULT_LOCALE
   351  	}
   352  
   353  	if u.Props == nil {
   354  		u.Props = make(map[string]string)
   355  	}
   356  
   357  	if u.NotifyProps == nil || len(u.NotifyProps) == 0 {
   358  		u.SetDefaultNotifications()
   359  	}
   360  
   361  	if u.Timezone == nil {
   362  		u.Timezone = timezones.DefaultUserTimezone()
   363  	}
   364  
   365  	if len(u.Password) > 0 {
   366  		u.Password = HashPassword(u.Password)
   367  	}
   368  }
   369  
   370  // PreUpdate should be run before updating the user in the db.
   371  func (u *User) PreUpdate() {
   372  	u.Username = SanitizeUnicode(u.Username)
   373  	u.FirstName = SanitizeUnicode(u.FirstName)
   374  	u.LastName = SanitizeUnicode(u.LastName)
   375  	u.Nickname = SanitizeUnicode(u.Nickname)
   376  	u.BotDescription = SanitizeUnicode(u.BotDescription)
   377  
   378  	u.Username = NormalizeUsername(u.Username)
   379  	u.Email = NormalizeEmail(u.Email)
   380  	u.UpdateAt = GetMillis()
   381  
   382  	u.FirstName = SanitizeUnicode(u.FirstName)
   383  	u.LastName = SanitizeUnicode(u.LastName)
   384  	u.Nickname = SanitizeUnicode(u.Nickname)
   385  	u.BotDescription = SanitizeUnicode(u.BotDescription)
   386  
   387  	if u.AuthData != nil && *u.AuthData == "" {
   388  		u.AuthData = nil
   389  	}
   390  
   391  	if u.NotifyProps == nil || len(u.NotifyProps) == 0 {
   392  		u.SetDefaultNotifications()
   393  	} else if _, ok := u.NotifyProps[MENTION_KEYS_NOTIFY_PROP]; ok {
   394  		// Remove any blank mention keys
   395  		splitKeys := strings.Split(u.NotifyProps[MENTION_KEYS_NOTIFY_PROP], ",")
   396  		goodKeys := []string{}
   397  		for _, key := range splitKeys {
   398  			if len(key) > 0 {
   399  				goodKeys = append(goodKeys, strings.ToLower(key))
   400  			}
   401  		}
   402  		u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = strings.Join(goodKeys, ",")
   403  	}
   404  }
   405  
   406  func (u *User) SetDefaultNotifications() {
   407  	u.NotifyProps = make(map[string]string)
   408  	u.NotifyProps[EMAIL_NOTIFY_PROP] = "true"
   409  	u.NotifyProps[PUSH_NOTIFY_PROP] = USER_NOTIFY_MENTION
   410  	u.NotifyProps[DESKTOP_NOTIFY_PROP] = USER_NOTIFY_MENTION
   411  	u.NotifyProps[DESKTOP_SOUND_NOTIFY_PROP] = "true"
   412  	u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = ""
   413  	u.NotifyProps[CHANNEL_MENTIONS_NOTIFY_PROP] = "true"
   414  	u.NotifyProps[PUSH_STATUS_NOTIFY_PROP] = STATUS_AWAY
   415  	u.NotifyProps[COMMENTS_NOTIFY_PROP] = COMMENTS_NOTIFY_NEVER
   416  	u.NotifyProps[FIRST_NAME_NOTIFY_PROP] = "false"
   417  }
   418  
   419  func (u *User) UpdateMentionKeysFromUsername(oldUsername string) {
   420  	nonUsernameKeys := []string{}
   421  	for _, key := range u.GetMentionKeys() {
   422  		if key != oldUsername && key != "@"+oldUsername {
   423  			nonUsernameKeys = append(nonUsernameKeys, key)
   424  		}
   425  	}
   426  
   427  	u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = ""
   428  	if len(nonUsernameKeys) > 0 {
   429  		u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] += "," + strings.Join(nonUsernameKeys, ",")
   430  	}
   431  }
   432  
   433  func (u *User) GetMentionKeys() []string {
   434  	var keys []string
   435  
   436  	for _, key := range strings.Split(u.NotifyProps[MENTION_KEYS_NOTIFY_PROP], ",") {
   437  		trimmedKey := strings.TrimSpace(key)
   438  
   439  		if trimmedKey == "" {
   440  			continue
   441  		}
   442  
   443  		keys = append(keys, trimmedKey)
   444  	}
   445  
   446  	return keys
   447  }
   448  
   449  func (u *User) Patch(patch *UserPatch) {
   450  	if patch.Username != nil {
   451  		u.Username = *patch.Username
   452  	}
   453  
   454  	if patch.Nickname != nil {
   455  		u.Nickname = *patch.Nickname
   456  	}
   457  
   458  	if patch.FirstName != nil {
   459  		u.FirstName = *patch.FirstName
   460  	}
   461  
   462  	if patch.LastName != nil {
   463  		u.LastName = *patch.LastName
   464  	}
   465  
   466  	if patch.Position != nil {
   467  		u.Position = *patch.Position
   468  	}
   469  
   470  	if patch.Email != nil {
   471  		u.Email = *patch.Email
   472  	}
   473  
   474  	if patch.Props != nil {
   475  		u.Props = patch.Props
   476  	}
   477  
   478  	if patch.NotifyProps != nil {
   479  		u.NotifyProps = patch.NotifyProps
   480  	}
   481  
   482  	if patch.Locale != nil {
   483  		u.Locale = *patch.Locale
   484  	}
   485  
   486  	if patch.Timezone != nil {
   487  		u.Timezone = patch.Timezone
   488  	}
   489  }
   490  
   491  // ToJson convert a User to a json string
   492  func (u *User) ToJson() string {
   493  	b, _ := json.Marshal(u)
   494  	return string(b)
   495  }
   496  
   497  func (u *UserPatch) ToJson() string {
   498  	b, _ := json.Marshal(u)
   499  	return string(b)
   500  }
   501  
   502  func (u *UserAuth) ToJson() string {
   503  	b, _ := json.Marshal(u)
   504  	return string(b)
   505  }
   506  
   507  // Generate a valid strong etag so the browser can cache the results
   508  func (u *User) Etag(showFullName, showEmail bool) string {
   509  	return Etag(u.Id, u.UpdateAt, u.TermsOfServiceId, u.TermsOfServiceCreateAt, showFullName, showEmail, u.BotLastIconUpdate)
   510  }
   511  
   512  // Remove any private data from the user object
   513  func (u *User) Sanitize(options map[string]bool) {
   514  	u.Password = ""
   515  	u.AuthData = NewString("")
   516  	u.MfaSecret = ""
   517  
   518  	if len(options) != 0 && !options["email"] {
   519  		u.Email = ""
   520  	}
   521  	if len(options) != 0 && !options["fullname"] {
   522  		u.FirstName = ""
   523  		u.LastName = ""
   524  	}
   525  	if len(options) != 0 && !options["passwordupdate"] {
   526  		u.LastPasswordUpdate = 0
   527  	}
   528  	if len(options) != 0 && !options["authservice"] {
   529  		u.AuthService = ""
   530  	}
   531  }
   532  
   533  // Remove any input data from the user object that is not user controlled
   534  func (u *User) SanitizeInput(isAdmin bool) {
   535  	if !isAdmin {
   536  		u.AuthData = NewString("")
   537  		u.AuthService = ""
   538  	}
   539  	u.LastPasswordUpdate = 0
   540  	u.LastPictureUpdate = 0
   541  	u.FailedAttempts = 0
   542  	u.EmailVerified = false
   543  	u.MfaActive = false
   544  	u.MfaSecret = ""
   545  }
   546  
   547  func (u *User) ClearNonProfileFields() {
   548  	u.Password = ""
   549  	u.AuthData = NewString("")
   550  	u.MfaSecret = ""
   551  	u.EmailVerified = false
   552  	u.AllowMarketing = false
   553  	u.NotifyProps = StringMap{}
   554  	u.LastPasswordUpdate = 0
   555  	u.FailedAttempts = 0
   556  }
   557  
   558  func (u *User) SanitizeProfile(options map[string]bool) {
   559  	u.ClearNonProfileFields()
   560  
   561  	u.Sanitize(options)
   562  }
   563  
   564  func (u *User) MakeNonNil() {
   565  	if u.Props == nil {
   566  		u.Props = make(map[string]string)
   567  	}
   568  
   569  	if u.NotifyProps == nil {
   570  		u.NotifyProps = make(map[string]string)
   571  	}
   572  }
   573  
   574  func (u *User) AddNotifyProp(key string, value string) {
   575  	u.MakeNonNil()
   576  
   577  	u.NotifyProps[key] = value
   578  }
   579  
   580  func (u *User) GetFullName() string {
   581  	if len(u.FirstName) > 0 && len(u.LastName) > 0 {
   582  		return u.FirstName + " " + u.LastName
   583  	} else if len(u.FirstName) > 0 {
   584  		return u.FirstName
   585  	} else if len(u.LastName) > 0 {
   586  		return u.LastName
   587  	} else {
   588  		return ""
   589  	}
   590  }
   591  
   592  func (u *User) getDisplayName(baseName, nameFormat string) string {
   593  	displayName := baseName
   594  
   595  	if nameFormat == SHOW_NICKNAME_FULLNAME {
   596  		if len(u.Nickname) > 0 {
   597  			displayName = u.Nickname
   598  		} else if fullName := u.GetFullName(); len(fullName) > 0 {
   599  			displayName = fullName
   600  		}
   601  	} else if nameFormat == SHOW_FULLNAME {
   602  		if fullName := u.GetFullName(); len(fullName) > 0 {
   603  			displayName = fullName
   604  		}
   605  	}
   606  
   607  	return displayName
   608  }
   609  
   610  func (u *User) GetDisplayName(nameFormat string) string {
   611  	displayName := u.Username
   612  
   613  	return u.getDisplayName(displayName, nameFormat)
   614  }
   615  
   616  func (u *User) GetDisplayNameWithPrefix(nameFormat, prefix string) string {
   617  	displayName := prefix + u.Username
   618  
   619  	return u.getDisplayName(displayName, nameFormat)
   620  }
   621  
   622  func (u *User) GetRoles() []string {
   623  	return strings.Fields(u.Roles)
   624  }
   625  
   626  func (u *User) GetRawRoles() string {
   627  	return u.Roles
   628  }
   629  
   630  func IsValidUserRoles(userRoles string) bool {
   631  
   632  	roles := strings.Fields(userRoles)
   633  
   634  	for _, r := range roles {
   635  		if !IsValidRoleName(r) {
   636  			return false
   637  		}
   638  	}
   639  
   640  	// Exclude just the system_admin role explicitly to prevent mistakes
   641  	if len(roles) == 1 && roles[0] == "system_admin" {
   642  		return false
   643  	}
   644  
   645  	return true
   646  }
   647  
   648  // Make sure you acually want to use this function. In context.go there are functions to check permissions
   649  // This function should not be used to check permissions.
   650  func (u *User) IsGuest() bool {
   651  	return IsInRole(u.Roles, SYSTEM_GUEST_ROLE_ID)
   652  }
   653  
   654  func (u *User) IsSystemAdmin() bool {
   655  	return IsInRole(u.Roles, SYSTEM_ADMIN_ROLE_ID)
   656  }
   657  
   658  // Make sure you acually want to use this function. In context.go there are functions to check permissions
   659  // This function should not be used to check permissions.
   660  func (u *User) IsInRole(inRole string) bool {
   661  	return IsInRole(u.Roles, inRole)
   662  }
   663  
   664  // Make sure you acually want to use this function. In context.go there are functions to check permissions
   665  // This function should not be used to check permissions.
   666  func IsInRole(userRoles string, inRole string) bool {
   667  	roles := strings.Split(userRoles, " ")
   668  
   669  	for _, r := range roles {
   670  		if r == inRole {
   671  			return true
   672  		}
   673  	}
   674  
   675  	return false
   676  }
   677  
   678  func (u *User) IsSSOUser() bool {
   679  	return u.AuthService != "" && u.AuthService != USER_AUTH_SERVICE_EMAIL
   680  }
   681  
   682  func (u *User) IsOAuthUser() bool {
   683  	return u.AuthService == USER_AUTH_SERVICE_GITLAB
   684  }
   685  
   686  func (u *User) IsLDAPUser() bool {
   687  	return u.AuthService == USER_AUTH_SERVICE_LDAP
   688  }
   689  
   690  func (u *User) IsSAMLUser() bool {
   691  	return u.AuthService == USER_AUTH_SERVICE_SAML
   692  }
   693  
   694  func (u *User) GetPreferredTimezone() string {
   695  	return GetPreferredTimezone(u.Timezone)
   696  }
   697  
   698  // UserFromJson will decode the input and return a User
   699  func UserFromJson(data io.Reader) *User {
   700  	var user *User
   701  	json.NewDecoder(data).Decode(&user)
   702  	return user
   703  }
   704  
   705  func UserPatchFromJson(data io.Reader) *UserPatch {
   706  	var user *UserPatch
   707  	json.NewDecoder(data).Decode(&user)
   708  	return user
   709  }
   710  
   711  func UserAuthFromJson(data io.Reader) *UserAuth {
   712  	var user *UserAuth
   713  	json.NewDecoder(data).Decode(&user)
   714  	return user
   715  }
   716  
   717  func UserMapToJson(u map[string]*User) string {
   718  	b, _ := json.Marshal(u)
   719  	return string(b)
   720  }
   721  
   722  func UserMapFromJson(data io.Reader) map[string]*User {
   723  	var users map[string]*User
   724  	json.NewDecoder(data).Decode(&users)
   725  	return users
   726  }
   727  
   728  func UserListToJson(u []*User) string {
   729  	b, _ := json.Marshal(u)
   730  	return string(b)
   731  }
   732  
   733  func UserListFromJson(data io.Reader) []*User {
   734  	var users []*User
   735  	json.NewDecoder(data).Decode(&users)
   736  	return users
   737  }
   738  
   739  // HashPassword generates a hash using the bcrypt.GenerateFromPassword
   740  func HashPassword(password string) string {
   741  	hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
   742  	if err != nil {
   743  		panic(err)
   744  	}
   745  
   746  	return string(hash)
   747  }
   748  
   749  // ComparePassword compares the hash
   750  func ComparePassword(hash string, password string) bool {
   751  
   752  	if len(password) == 0 || len(hash) == 0 {
   753  		return false
   754  	}
   755  
   756  	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
   757  	return err == nil
   758  }
   759  
   760  var validUsernameChars = regexp.MustCompile(`^[a-z0-9\.\-_]+$`)
   761  
   762  var restrictedUsernames = []string{
   763  	"all",
   764  	"channel",
   765  	"matterbot",
   766  	"system",
   767  }
   768  
   769  func IsValidUsername(s string) bool {
   770  	if len(s) < USER_NAME_MIN_LENGTH || len(s) > USER_NAME_MAX_LENGTH {
   771  		return false
   772  	}
   773  
   774  	if !validUsernameChars.MatchString(s) {
   775  		return false
   776  	}
   777  
   778  	for _, restrictedUsername := range restrictedUsernames {
   779  		if s == restrictedUsername {
   780  			return false
   781  		}
   782  	}
   783  
   784  	return true
   785  }
   786  
   787  func CleanUsername(s string) string {
   788  	s = NormalizeUsername(strings.Replace(s, " ", "-", -1))
   789  
   790  	for _, value := range reservedName {
   791  		if s == value {
   792  			s = strings.Replace(s, value, "", -1)
   793  		}
   794  	}
   795  
   796  	s = strings.TrimSpace(s)
   797  
   798  	for _, c := range s {
   799  		char := fmt.Sprintf("%c", c)
   800  		if !validUsernameChars.MatchString(char) {
   801  			s = strings.Replace(s, char, "-", -1)
   802  		}
   803  	}
   804  
   805  	s = strings.Trim(s, "-")
   806  
   807  	if !IsValidUsername(s) {
   808  		s = "a" + NewId()
   809  	}
   810  
   811  	return s
   812  }
   813  
   814  func IsValidUserNotifyLevel(notifyLevel string) bool {
   815  	return notifyLevel == CHANNEL_NOTIFY_ALL ||
   816  		notifyLevel == CHANNEL_NOTIFY_MENTION ||
   817  		notifyLevel == CHANNEL_NOTIFY_NONE
   818  }
   819  
   820  func IsValidPushStatusNotifyLevel(notifyLevel string) bool {
   821  	return notifyLevel == STATUS_ONLINE ||
   822  		notifyLevel == STATUS_AWAY ||
   823  		notifyLevel == STATUS_OFFLINE
   824  }
   825  
   826  func IsValidCommentsNotifyLevel(notifyLevel string) bool {
   827  	return notifyLevel == COMMENTS_NOTIFY_ANY ||
   828  		notifyLevel == COMMENTS_NOTIFY_ROOT ||
   829  		notifyLevel == COMMENTS_NOTIFY_NEVER
   830  }
   831  
   832  func IsValidEmailBatchingInterval(emailInterval string) bool {
   833  	return emailInterval == PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY ||
   834  		emailInterval == PREFERENCE_EMAIL_INTERVAL_FIFTEEN ||
   835  		emailInterval == PREFERENCE_EMAIL_INTERVAL_HOUR
   836  }
   837  
   838  func IsValidLocale(locale string) bool {
   839  	if locale != "" {
   840  		if len(locale) > USER_LOCALE_MAX_LENGTH {
   841  			return false
   842  		} else if _, err := language.Parse(locale); err != nil {
   843  			return false
   844  		}
   845  	}
   846  
   847  	return true
   848  }
   849  
   850  type UserWithGroups struct {
   851  	User
   852  	GroupIDs    *string  `json:"-"`
   853  	Groups      []*Group `json:"groups"`
   854  	SchemeGuest bool     `json:"scheme_guest"`
   855  	SchemeUser  bool     `json:"scheme_user"`
   856  	SchemeAdmin bool     `json:"scheme_admin"`
   857  }
   858  
   859  func (u *UserWithGroups) GetGroupIDs() []string {
   860  	if u.GroupIDs == nil {
   861  		return nil
   862  	}
   863  	trimmed := strings.TrimSpace(*u.GroupIDs)
   864  	if len(trimmed) == 0 {
   865  		return nil
   866  	}
   867  	return strings.Split(trimmed, ",")
   868  }
   869  
   870  type UsersWithGroupsAndCount struct {
   871  	Users []*UserWithGroups `json:"users"`
   872  	Count int64             `json:"total_count"`
   873  }
   874  
   875  func UsersWithGroupsAndCountFromJson(data io.Reader) *UsersWithGroupsAndCount {
   876  	uwg := &UsersWithGroupsAndCount{}
   877  	bodyBytes, _ := ioutil.ReadAll(data)
   878  	json.Unmarshal(bodyBytes, uwg)
   879  	return uwg
   880  }
   881  
   882  var passwordRandomSource = rand.NewSource(time.Now().Unix())
   883  var passwordSpecialChars = "!$%^&*(),."
   884  var passwordNumbers = "0123456789"
   885  var passwordUpperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   886  var passwordLowerCaseLetters = "abcdefghijklmnopqrstuvwxyz"
   887  var passwordAllChars = passwordSpecialChars + passwordNumbers + passwordUpperCaseLetters + passwordLowerCaseLetters
   888  
   889  func GeneratePassword(minimumLength int) string {
   890  	r := rand.New(passwordRandomSource)
   891  
   892  	// Make sure we are guaranteed at least one of each type to meet any possible password complexity requirements.
   893  	password := string([]rune(passwordUpperCaseLetters)[r.Intn(len(passwordUpperCaseLetters))]) +
   894  		string([]rune(passwordNumbers)[r.Intn(len(passwordNumbers))]) +
   895  		string([]rune(passwordLowerCaseLetters)[r.Intn(len(passwordLowerCaseLetters))]) +
   896  		string([]rune(passwordSpecialChars)[r.Intn(len(passwordSpecialChars))])
   897  
   898  	for len(password) < minimumLength {
   899  		i := r.Intn(len(passwordAllChars))
   900  		password = password + string([]rune(passwordAllChars)[i])
   901  	}
   902  
   903  	return password
   904  }