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 ©User 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 }