From 911c597377b1f28533d1adee3f3bcff1c776927c Mon Sep 17 00:00:00 2001 From: Wim Date: Fri, 22 Jul 2016 23:14:13 +0200 Subject: [PATCH] Sync with mattermost 3.2.0 --- .../mattermost/platform/einterfaces/emoji.go | 22 ++ .../mattermost/platform/einterfaces/saml.go | 25 ++ .../mattermost/platform/model/client.go | 143 +++++++- .../mattermost/platform/model/config.go | 321 ++++++++++++++++-- .../mattermost/platform/model/emoji.go | 95 ++++++ .../mattermost/platform/model/job.go | 7 +- .../mattermost/platform/model/ldap.go | 1 + .../mattermost/platform/model/license.go | 28 +- .../mattermost/platform/model/message.go | 1 + .../mattermost/platform/model/saml.go | 18 + .../mattermost/platform/model/team_member.go | 7 +- .../mattermost/platform/model/user.go | 14 +- .../mattermost/platform/model/utils.go | 7 + .../mattermost/platform/model/version.go | 1 + vendor/manifest | 8 +- 15 files changed, 640 insertions(+), 58 deletions(-) create mode 100644 vendor/github.com/mattermost/platform/einterfaces/emoji.go create mode 100644 vendor/github.com/mattermost/platform/einterfaces/saml.go create mode 100644 vendor/github.com/mattermost/platform/model/emoji.go create mode 100644 vendor/github.com/mattermost/platform/model/saml.go diff --git a/vendor/github.com/mattermost/platform/einterfaces/emoji.go b/vendor/github.com/mattermost/platform/einterfaces/emoji.go new file mode 100644 index 00000000..f276f6a3 --- /dev/null +++ b/vendor/github.com/mattermost/platform/einterfaces/emoji.go @@ -0,0 +1,22 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package einterfaces + +import ( + "github.com/mattermost/platform/model" +) + +type EmojiInterface interface { + CanUserCreateEmoji(string, []*model.TeamMember) bool +} + +var theEmojiInterface EmojiInterface + +func RegisterEmojiInterface(newInterface EmojiInterface) { + theEmojiInterface = newInterface +} + +func GetEmojiInterface() EmojiInterface { + return theEmojiInterface +} diff --git a/vendor/github.com/mattermost/platform/einterfaces/saml.go b/vendor/github.com/mattermost/platform/einterfaces/saml.go new file mode 100644 index 00000000..af2e815a --- /dev/null +++ b/vendor/github.com/mattermost/platform/einterfaces/saml.go @@ -0,0 +1,25 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package einterfaces + +import ( + "github.com/mattermost/platform/model" +) + +type SamlInterface interface { + ConfigureSP() *model.AppError + BuildRequest(relayState string) (*model.SamlAuthRequest, *model.AppError) + DoLogin(encodedXML string, relayState map[string]string) (*model.User, *model.AppError) + GetMetadata() (string, *model.AppError) +} + +var theSamlInterface SamlInterface + +func RegisterSamlInterface(newInterface SamlInterface) { + theSamlInterface = newInterface +} + +func GetSamlInterface() SamlInterface { + return theSamlInterface +} diff --git a/vendor/github.com/mattermost/platform/model/client.go b/vendor/github.com/mattermost/platform/model/client.go index e8ce21ab..2f1e846c 100644 --- a/vendor/github.com/mattermost/platform/model/client.go +++ b/vendor/github.com/mattermost/platform/model/client.go @@ -7,7 +7,9 @@ import ( "bytes" "fmt" l4g "github.com/alecthomas/log4go" + "io" "io/ioutil" + "mime/multipart" "net/http" "net/url" "strconv" @@ -106,6 +108,10 @@ func (c *Client) GetChannelNameRoute(channelName string) string { return fmt.Sprintf("/teams/%v/channels/name/%v", c.GetTeamId(), channelName) } +func (c *Client) GetEmojiRoute() string { + return "/emoji" +} + func (c *Client) GetGeneralRoute() string { return "/general" } @@ -185,6 +191,17 @@ func (c *Client) Must(result *Result, err *AppError) *Result { return result } +// MustGeneric is a convenience function used for testing. +func (c *Client) MustGeneric(result interface{}, err *AppError) interface{} { + if err != nil { + l4g.Close() + time.Sleep(time.Second) + panic(err) + } + + return result +} + // CheckStatusOK is a convenience function for checking the return of Web Service // call that return the a map of status=OK. func (c *Client) CheckStatusOK(r *http.Response) bool { @@ -328,10 +345,18 @@ func (c *Client) FindTeamByName(name string) (*Result, *AppError) { } } -func (c *Client) AddUserToTeam(userId string) (*Result, *AppError) { +// Adds a user directly to the team without sending an invite. +// The teamId and userId are required. You must be a valid member of the team and/or +// have the correct role to add new users to the team. Returns a map of user_id=userId +// if successful, otherwise returns an AppError. +func (c *Client) AddUserToTeam(teamId string, userId string) (*Result, *AppError) { + if len(teamId) == 0 { + teamId = c.GetTeamId() + } + data := make(map[string]string) data["user_id"] = userId - if r, err := c.DoApiPost(c.GetTeamRoute()+"/add_user_to_team", MapToJson(data)); err != nil { + if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v", teamId)+"/add_user_to_team", MapToJson(data)); err != nil { return nil, err } else { defer closeBody(r) @@ -354,6 +379,26 @@ func (c *Client) AddUserToTeamFromInvite(hash, dataToHash, inviteId string) (*Re } } +// Removes a user directly from the team. +// The teamId and userId are required. You must be a valid member of the team and/or +// have the correct role to remove a user from the team. Returns a map of user_id=userId +// if successful, otherwise returns an AppError. +func (c *Client) RemoveUserFromTeam(teamId string, userId string) (*Result, *AppError) { + if len(teamId) == 0 { + teamId = c.GetTeamId() + } + + data := make(map[string]string) + data["user_id"] = userId + if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v", teamId)+"/remove_user_from_team", MapToJson(data)); err != nil { + return nil, err + } else { + defer closeBody(r) + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil + } +} + func (c *Client) InviteMembers(invites *Invites) (*Result, *AppError) { if r, err := c.DoApiPost(c.GetTeamRoute()+"/invite_members", invites.ToJson()); err != nil { return nil, err @@ -843,6 +888,20 @@ func (c *Client) GetSystemAnalytics(name string) (*Result, *AppError) { } } +// Initiate immediate synchronization of LDAP users. +// The synchronization will be performed asynchronously and this function will +// always return OK unless you don't have permissions. +// You must be the system administrator to use this function. +func (c *Client) LdapSyncNow() (*Result, *AppError) { + if r, err := c.DoApiPost("/admin/ldap_sync_now", ""); err != nil { + return nil, err + } else { + defer closeBody(r) + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil + } +} + func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) { if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create", channel.ToJson()); err != nil { return nil, err @@ -949,6 +1008,7 @@ func (c *Client) JoinChannel(id string) (*Result, *AppError) { if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/join", ""); err != nil { return nil, err } else { + defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), nil}, nil } @@ -958,6 +1018,7 @@ func (c *Client) JoinChannelByName(name string) (*Result, *AppError) { if r, err := c.DoApiPost(c.GetChannelNameRoute(name)+"/join", ""); err != nil { return nil, err } else { + defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), nil}, nil } @@ -967,6 +1028,7 @@ func (c *Client) LeaveChannel(id string) (*Result, *AppError) { if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/leave", ""); err != nil { return nil, err } else { + defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), nil}, nil } @@ -976,6 +1038,7 @@ func (c *Client) DeleteChannel(id string) (*Result, *AppError) { if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/delete", ""); err != nil { return nil, err } else { + defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), nil}, nil } @@ -987,6 +1050,7 @@ func (c *Client) AddChannelMember(id, user_id string) (*Result, *AppError) { if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/add", MapToJson(data)); err != nil { return nil, err } else { + defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), nil}, nil } @@ -998,6 +1062,7 @@ func (c *Client) RemoveChannelMember(id, user_id string) (*Result, *AppError) { if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/remove", MapToJson(data)); err != nil { return nil, err } else { + defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), nil}, nil } @@ -1007,6 +1072,7 @@ func (c *Client) UpdateLastViewedAt(channelId string) (*Result, *AppError) { if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/update_last_viewed_at", ""); err != nil { return nil, err } else { + defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), nil}, nil } @@ -1376,6 +1442,7 @@ func (c *Client) PostToWebhook(id, payload string) (*Result, *AppError) { if r, err := c.DoPost("/hooks/"+id, payload, "application/x-www-form-urlencoded"); err != nil { return nil, err } else { + defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), nil}, nil } @@ -1417,6 +1484,7 @@ func (c *Client) SetPreferences(preferences *Preferences) (*Result, *AppError) { if r, err := c.DoApiPost("/preferences/save", preferences.ToJson()); err != nil { return nil, err } else { + defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil } @@ -1509,3 +1577,74 @@ func (c *Client) GetInitialLoad() (*Result, *AppError) { r.Header.Get(HEADER_ETAG_SERVER), InitialLoadFromJson(r.Body)}, nil } } + +// ListEmoji returns a list of all user-created emoji for the server. +func (c *Client) ListEmoji() ([]*Emoji, *AppError) { + if r, err := c.DoApiGet(c.GetEmojiRoute()+"/list", "", ""); err != nil { + return nil, err + } else { + defer closeBody(r) + c.fillInExtraProperties(r) + return EmojiListFromJson(r.Body), nil + } +} + +// CreateEmoji will save an emoji to the server if the current user has permission +// to do so. If successful, the provided emoji will be returned with its Id field +// filled in. Otherwise, an error will be returned. +func (c *Client) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoji, *AppError) { + c.clearExtraProperties() + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + + if part, err := writer.CreateFormFile("image", filename); err != nil { + return nil, NewLocAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error()) + } else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil { + return nil, NewLocAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error()) + } + + if err := writer.WriteField("emoji", emoji.ToJson()); err != nil { + return nil, NewLocAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error()) + } + + if err := writer.Close(); err != nil { + return nil, NewLocAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error()) + } + + rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetEmojiRoute()+"/create", body) + rq.Header.Set("Content-Type", writer.FormDataContentType()) + + if len(c.AuthToken) > 0 { + rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken) + } + + if r, err := c.HttpClient.Do(rq); err != nil { + return nil, NewLocAppError("CreateEmoji", "model.client.connecting.app_error", nil, err.Error()) + } else if r.StatusCode >= 300 { + return nil, AppErrorFromJson(r.Body) + } else { + defer closeBody(r) + c.fillInExtraProperties(r) + return EmojiFromJson(r.Body), nil + } +} + +// DeleteEmoji will delete an emoji from the server if the current user has permission +// to do so. If successful, it will return status=ok. Otherwise, an error will be returned. +func (c *Client) DeleteEmoji(id string) (bool, *AppError) { + data := map[string]string{"id": id} + + if r, err := c.DoApiPost(c.GetEmojiRoute()+"/delete", MapToJson(data)); err != nil { + return false, err + } else { + c.fillInExtraProperties(r) + return c.CheckStatusOK(r), nil + } +} + +// GetCustomEmojiImageUrl returns the API route that can be used to get the image used by +// the given emoji. +func (c *Client) GetCustomEmojiImageUrl(id string) string { + return c.GetEmojiRoute() + "/" + id +} diff --git a/vendor/github.com/mattermost/platform/model/config.go b/vendor/github.com/mattermost/platform/model/config.go index 55606ee8..3a0d7f97 100644 --- a/vendor/github.com/mattermost/platform/model/config.go +++ b/vendor/github.com/mattermost/platform/model/config.go @@ -6,7 +6,6 @@ package model import ( "encoding/json" "io" - "strings" ) const ( @@ -20,6 +19,9 @@ const ( DATABASE_DRIVER_MYSQL = "mysql" DATABASE_DRIVER_POSTGRES = "postgres" + PASSWORD_MAXIMUM_LENGTH = 64 + PASSWORD_MINIMUM_LENGTH = 5 + SERVICE_GITLAB = "gitlab" SERVICE_GOOGLE = "google" @@ -33,17 +35,16 @@ const ( DIRECT_MESSAGE_ANY = "any" DIRECT_MESSAGE_TEAM = "team" - FAKE_SETTING = "********************************" -) + PERMISSIONS_ALL = "all" + PERMISSIONS_TEAM_ADMIN = "team_admin" + PERMISSIONS_SYSTEM_ADMIN = "system_admin" -// should match the values in webapp/i18n/i18n.jsx -var LOCALES = []string{ - "en", - "es", - "fr", - "ja", - "pt-BR", -} + FAKE_SETTING = "********************************" + + RESTRICT_EMOJI_CREATION_ALL = "all" + RESTRICT_EMOJI_CREATION_ADMIN = "admin" + RESTRICT_EMOJI_CREATION_SYSTEM_ADMIN = "system_admin" +) type ServiceSettings struct { ListenAddress string @@ -70,6 +71,8 @@ type ServiceSettings struct { WebsocketSecurePort *int WebsocketPort *int WebserverMode *string + EnableCustomEmoji *bool + RestrictCustomEmojiCreation *string } type SSOSettings struct { @@ -93,12 +96,21 @@ type SqlSettings struct { } type LogSettings struct { - EnableConsole bool - ConsoleLevel string - EnableFile bool - FileLevel string - FileFormat string - FileLocation string + EnableConsole bool + ConsoleLevel string + EnableFile bool + FileLevel string + FileFormat string + FileLocation string + EnableWebhookDebugging bool +} + +type PasswordSettings struct { + MinimumLength *int + Lowercase *bool + Number *bool + Uppercase *bool + Symbol *bool } type FileSettings struct { @@ -132,6 +144,7 @@ type EmailSettings struct { RequireEmailVerification bool FeedbackName string FeedbackEmail string + FeedbackOrganization *string SMTPUsername string SMTPPassword string SMTPServer string @@ -167,16 +180,19 @@ type SupportSettings struct { } type TeamSettings struct { - SiteName string - MaxUsersPerTeam int - EnableTeamCreation bool - EnableUserCreation bool - EnableOpenServer *bool - RestrictCreationToDomains string - RestrictTeamNames *bool - EnableCustomBrand *bool - CustomBrandText *string - RestrictDirectMessage *string + SiteName string + MaxUsersPerTeam int + EnableTeamCreation bool + EnableUserCreation bool + EnableOpenServer *bool + RestrictCreationToDomains string + RestrictTeamNames *bool + EnableCustomBrand *bool + CustomBrandText *string + RestrictDirectMessage *string + RestrictTeamInvite *string + RestrictPublicChannelManagement *string + RestrictPrivateChannelManagement *string } type LdapSettings struct { @@ -206,6 +222,7 @@ type LdapSettings struct { // Advanced SkipCertificateVerification *bool QueryTimeout *int + MaxPageSize *int // Customization LoginFieldName *string @@ -223,11 +240,37 @@ type LocalizationSettings struct { AvailableLocales *string } +type SamlSettings struct { + // Basic + Enable *bool + Verify *bool + Encrypt *bool + + IdpUrl *string + IdpDescriptorUrl *string + AssertionConsumerServiceURL *string + + IdpCertificateFile *string + PublicCertificateFile *string + PrivateKeyFile *string + + // User Mapping + FirstNameAttribute *string + LastNameAttribute *string + EmailAttribute *string + UsernameAttribute *string + NicknameAttribute *string + LocaleAttribute *string + + LoginButtonText *string +} + type Config struct { ServiceSettings ServiceSettings TeamSettings TeamSettings SqlSettings SqlSettings LogSettings LogSettings + PasswordSettings PasswordSettings FileSettings FileSettings EmailSettings EmailSettings RateLimitSettings RateLimitSettings @@ -238,6 +281,7 @@ type Config struct { LdapSettings LdapSettings ComplianceSettings ComplianceSettings LocalizationSettings LocalizationSettings + SamlSettings SamlSettings } func (o *Config) ToJson() string { @@ -324,6 +368,31 @@ func (o *Config) SetDefaults() { *o.ServiceSettings.EnableMultifactorAuthentication = false } + if o.PasswordSettings.MinimumLength == nil { + o.PasswordSettings.MinimumLength = new(int) + *o.PasswordSettings.MinimumLength = PASSWORD_MINIMUM_LENGTH + } + + if o.PasswordSettings.Lowercase == nil { + o.PasswordSettings.Lowercase = new(bool) + *o.PasswordSettings.Lowercase = false + } + + if o.PasswordSettings.Number == nil { + o.PasswordSettings.Number = new(bool) + *o.PasswordSettings.Number = false + } + + if o.PasswordSettings.Uppercase == nil { + o.PasswordSettings.Uppercase = new(bool) + *o.PasswordSettings.Uppercase = false + } + + if o.PasswordSettings.Symbol == nil { + o.PasswordSettings.Symbol = new(bool) + *o.PasswordSettings.Symbol = false + } + if o.TeamSettings.RestrictTeamNames == nil { o.TeamSettings.RestrictTeamNames = new(bool) *o.TeamSettings.RestrictTeamNames = true @@ -349,6 +418,21 @@ func (o *Config) SetDefaults() { *o.TeamSettings.RestrictDirectMessage = DIRECT_MESSAGE_ANY } + if o.TeamSettings.RestrictTeamInvite == nil { + o.TeamSettings.RestrictTeamInvite = new(string) + *o.TeamSettings.RestrictTeamInvite = PERMISSIONS_ALL + } + + if o.TeamSettings.RestrictPublicChannelManagement == nil { + o.TeamSettings.RestrictPublicChannelManagement = new(string) + *o.TeamSettings.RestrictPublicChannelManagement = PERMISSIONS_ALL + } + + if o.TeamSettings.RestrictPrivateChannelManagement == nil { + o.TeamSettings.RestrictPrivateChannelManagement = new(string) + *o.TeamSettings.RestrictPrivateChannelManagement = PERMISSIONS_ALL + } + if o.EmailSettings.EnableSignInWithEmail == nil { o.EmailSettings.EnableSignInWithEmail = new(bool) @@ -379,6 +463,11 @@ func (o *Config) SetDefaults() { *o.EmailSettings.PushNotificationContents = GENERIC_NOTIFICATION } + if o.EmailSettings.FeedbackOrganization == nil { + o.EmailSettings.FeedbackOrganization = new(string) + *o.EmailSettings.FeedbackOrganization = "" + } + if !IsSafeLink(o.SupportSettings.TermsOfServiceLink) { o.SupportSettings.TermsOfServiceLink = nil } @@ -484,6 +573,11 @@ func (o *Config) SetDefaults() { *o.LdapSettings.EmailAttribute = "" } + if o.LdapSettings.UsernameAttribute == nil { + o.LdapSettings.UsernameAttribute = new(string) + *o.LdapSettings.UsernameAttribute = "" + } + if o.LdapSettings.NicknameAttribute == nil { o.LdapSettings.NicknameAttribute = new(string) *o.LdapSettings.NicknameAttribute = "" @@ -509,6 +603,11 @@ func (o *Config) SetDefaults() { *o.LdapSettings.QueryTimeout = 60 } + if o.LdapSettings.MaxPageSize == nil { + o.LdapSettings.MaxPageSize = new(int) + *o.LdapSettings.MaxPageSize = 0 + } + if o.LdapSettings.LoginFieldName == nil { o.LdapSettings.LoginFieldName = new(string) *o.LdapSettings.LoginFieldName = "" @@ -561,7 +660,19 @@ func (o *Config) SetDefaults() { if o.ServiceSettings.WebserverMode == nil { o.ServiceSettings.WebserverMode = new(string) - *o.ServiceSettings.WebserverMode = "regular" + *o.ServiceSettings.WebserverMode = "gzip" + } else if *o.ServiceSettings.WebserverMode == "regular" { + *o.ServiceSettings.WebserverMode = "gzip" + } + + if o.ServiceSettings.EnableCustomEmoji == nil { + o.ServiceSettings.EnableCustomEmoji = new(bool) + *o.ServiceSettings.EnableCustomEmoji = true + } + + if o.ServiceSettings.RestrictCustomEmojiCreation == nil { + o.ServiceSettings.RestrictCustomEmojiCreation = new(string) + *o.ServiceSettings.RestrictCustomEmojiCreation = RESTRICT_EMOJI_CREATION_ALL } if o.ComplianceSettings.Enable == nil { @@ -591,7 +702,87 @@ func (o *Config) SetDefaults() { if o.LocalizationSettings.AvailableLocales == nil { o.LocalizationSettings.AvailableLocales = new(string) - *o.LocalizationSettings.AvailableLocales = strings.Join(LOCALES, ",") + *o.LocalizationSettings.AvailableLocales = "" + } + + if o.SamlSettings.Enable == nil { + o.SamlSettings.Enable = new(bool) + *o.SamlSettings.Enable = false + } + + if o.SamlSettings.Verify == nil { + o.SamlSettings.Verify = new(bool) + *o.SamlSettings.Verify = false + } + + if o.SamlSettings.Encrypt == nil { + o.SamlSettings.Encrypt = new(bool) + *o.SamlSettings.Encrypt = false + } + + if o.SamlSettings.IdpUrl == nil { + o.SamlSettings.IdpUrl = new(string) + *o.SamlSettings.IdpUrl = "" + } + + if o.SamlSettings.IdpDescriptorUrl == nil { + o.SamlSettings.IdpDescriptorUrl = new(string) + *o.SamlSettings.IdpDescriptorUrl = "" + } + + if o.SamlSettings.IdpCertificateFile == nil { + o.SamlSettings.IdpCertificateFile = new(string) + *o.SamlSettings.IdpCertificateFile = "" + } + + if o.SamlSettings.PublicCertificateFile == nil { + o.SamlSettings.PublicCertificateFile = new(string) + *o.SamlSettings.PublicCertificateFile = "" + } + + if o.SamlSettings.PrivateKeyFile == nil { + o.SamlSettings.PrivateKeyFile = new(string) + *o.SamlSettings.PrivateKeyFile = "" + } + + if o.SamlSettings.AssertionConsumerServiceURL == nil { + o.SamlSettings.AssertionConsumerServiceURL = new(string) + *o.SamlSettings.AssertionConsumerServiceURL = "" + } + + if o.SamlSettings.LoginButtonText == nil || *o.SamlSettings.LoginButtonText == "" { + o.SamlSettings.LoginButtonText = new(string) + *o.SamlSettings.LoginButtonText = USER_AUTH_SERVICE_SAML_TEXT + } + + if o.SamlSettings.FirstNameAttribute == nil { + o.SamlSettings.FirstNameAttribute = new(string) + *o.SamlSettings.FirstNameAttribute = "" + } + + if o.SamlSettings.LastNameAttribute == nil { + o.SamlSettings.LastNameAttribute = new(string) + *o.SamlSettings.LastNameAttribute = "" + } + + if o.SamlSettings.EmailAttribute == nil { + o.SamlSettings.EmailAttribute = new(string) + *o.SamlSettings.EmailAttribute = "" + } + + if o.SamlSettings.UsernameAttribute == nil { + o.SamlSettings.UsernameAttribute = new(string) + *o.SamlSettings.UsernameAttribute = "" + } + + if o.SamlSettings.NicknameAttribute == nil { + o.SamlSettings.NicknameAttribute = new(string) + *o.SamlSettings.NicknameAttribute = "" + } + + if o.SamlSettings.LocaleAttribute == nil { + o.SamlSettings.LocaleAttribute = new(string) + *o.SamlSettings.LocaleAttribute = "" } } @@ -697,6 +888,78 @@ func (o *Config) IsValid() *AppError { return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_sync_interval.app_error", nil, "") } + if *o.LdapSettings.MaxPageSize < 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_max_page_size.app_error", nil, "") + } + + if *o.LdapSettings.Enable { + if *o.LdapSettings.LdapServer == "" || + *o.LdapSettings.BaseDN == "" || + *o.LdapSettings.BindUsername == "" || + *o.LdapSettings.BindPassword == "" || + *o.LdapSettings.FirstNameAttribute == "" || + *o.LdapSettings.LastNameAttribute == "" || + *o.LdapSettings.EmailAttribute == "" || + *o.LdapSettings.UsernameAttribute == "" || + *o.LdapSettings.IdAttribute == "" { + return NewLocAppError("Config.IsValid", "Required LDAP field missing", nil, "") + } + } + + if *o.SamlSettings.Enable { + if len(*o.SamlSettings.IdpUrl) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_idp_url.app_error", nil, "") + } + + if len(*o.SamlSettings.IdpDescriptorUrl) == 0 || !IsValidHttpUrl(*o.SamlSettings.IdpDescriptorUrl) { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_idp_descriptor_url.app_error", nil, "") + } + + if len(*o.SamlSettings.IdpCertificateFile) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_idp_cert.app_error", nil, "") + } + + if len(*o.SamlSettings.EmailAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "") + } + + if len(*o.SamlSettings.UsernameAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_username_attribute.app_error", nil, "") + } + + if len(*o.SamlSettings.FirstNameAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_first_name_attribute.app_error", nil, "") + } + + if len(*o.SamlSettings.LastNameAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_last_name_attribute.app_error", nil, "") + } + + if *o.SamlSettings.Verify { + if len(*o.SamlSettings.AssertionConsumerServiceURL) == 0 || !IsValidHttpUrl(*o.SamlSettings.AssertionConsumerServiceURL) { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_assertion_consumer_service_url.app_error", nil, "") + } + } + + if *o.SamlSettings.Encrypt { + if len(*o.SamlSettings.PrivateKeyFile) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_private_key.app_error", nil, "") + } + + if len(*o.SamlSettings.PublicCertificateFile) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_public_cert.app_error", nil, "") + } + } + + if len(*o.SamlSettings.EmailAttribute) == 0 { + return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "") + } + } + + if *o.PasswordSettings.MinimumLength < PASSWORD_MINIMUM_LENGTH || *o.PasswordSettings.MinimumLength > PASSWORD_MAXIMUM_LENGTH { + return NewLocAppError("Config.IsValid", "model.config.is_valid.password_length.app_error", map[string]interface{}{"MinLength": PASSWORD_MINIMUM_LENGTH, "MaxLength": PASSWORD_MAXIMUM_LENGTH}, "") + } + return nil } diff --git a/vendor/github.com/mattermost/platform/model/emoji.go b/vendor/github.com/mattermost/platform/model/emoji.go new file mode 100644 index 00000000..a66053aa --- /dev/null +++ b/vendor/github.com/mattermost/platform/model/emoji.go @@ -0,0 +1,95 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/json" + "io" +) + +type Emoji struct { + Id string `json:"id"` + CreateAt int64 `json:"create_at"` + UpdateAt int64 `json:"update_at"` + DeleteAt int64 `json:"delete_at"` + CreatorId string `json:"creator_id"` + Name string `json:"name"` +} + +func (emoji *Emoji) IsValid() *AppError { + if len(emoji.Id) != 26 { + return NewLocAppError("Emoji.IsValid", "model.emoji.id.app_error", nil, "") + } + + if emoji.CreateAt == 0 { + return NewLocAppError("Emoji.IsValid", "model.emoji.create_at.app_error", nil, "id="+emoji.Id) + } + + if emoji.UpdateAt == 0 { + return NewLocAppError("Emoji.IsValid", "model.emoji.update_at.app_error", nil, "id="+emoji.Id) + } + + if len(emoji.CreatorId) != 26 { + return NewLocAppError("Emoji.IsValid", "model.emoji.user_id.app_error", nil, "") + } + + if len(emoji.Name) == 0 || len(emoji.Name) > 64 { + return NewLocAppError("Emoji.IsValid", "model.emoji.name.app_error", nil, "") + } + + return nil +} + +func (emoji *Emoji) PreSave() { + if emoji.Id == "" { + emoji.Id = NewId() + } + + emoji.CreateAt = GetMillis() + emoji.UpdateAt = emoji.CreateAt +} + +func (emoji *Emoji) PreUpdate() { + emoji.UpdateAt = GetMillis() +} + +func (emoji *Emoji) ToJson() string { + b, err := json.Marshal(emoji) + if err != nil { + return "" + } else { + return string(b) + } +} + +func EmojiFromJson(data io.Reader) *Emoji { + decoder := json.NewDecoder(data) + var emoji Emoji + err := decoder.Decode(&emoji) + if err == nil { + return &emoji + } else { + return nil + } +} + +func EmojiListToJson(emojiList []*Emoji) string { + b, err := json.Marshal(emojiList) + if err != nil { + return "" + } else { + return string(b) + } +} + +func EmojiListFromJson(data io.Reader) []*Emoji { + decoder := json.NewDecoder(data) + var emojiList []*Emoji + err := decoder.Decode(&emojiList) + if err == nil { + return emojiList + } else { + return nil + } +} diff --git a/vendor/github.com/mattermost/platform/model/job.go b/vendor/github.com/mattermost/platform/model/job.go index bcae7a83..b6c68dce 100644 --- a/vendor/github.com/mattermost/platform/model/job.go +++ b/vendor/github.com/mattermost/platform/model/job.go @@ -28,8 +28,11 @@ func removeTaskByName(name string) { delete(tasks, name) } -func getTaskByName(name string) *ScheduledTask { - return tasks[name] +func GetTaskByName(name string) *ScheduledTask { + if task, ok := tasks[name]; ok { + return task + } + return nil } func GetAllTasks() *map[string]*ScheduledTask { diff --git a/vendor/github.com/mattermost/platform/model/ldap.go b/vendor/github.com/mattermost/platform/model/ldap.go index 5fde06a6..71b1d8a6 100644 --- a/vendor/github.com/mattermost/platform/model/ldap.go +++ b/vendor/github.com/mattermost/platform/model/ldap.go @@ -5,4 +5,5 @@ package model const ( USER_AUTH_SERVICE_LDAP = "ldap" + LDAP_SYNC_TASK_NAME = "LDAP Syncronization" ) diff --git a/vendor/github.com/mattermost/platform/model/license.go b/vendor/github.com/mattermost/platform/model/license.go index bc72ff9a..a77a7349 100644 --- a/vendor/github.com/mattermost/platform/model/license.go +++ b/vendor/github.com/mattermost/platform/model/license.go @@ -32,14 +32,16 @@ type Customer struct { } type Features struct { - Users *int `json:"users"` - LDAP *bool `json:"ldap"` - MFA *bool `json:"mfa"` - GoogleSSO *bool `json:"google_sso"` - Compliance *bool `json:"compliance"` - CustomBrand *bool `json:"custom_brand"` - MHPNS *bool `json:"mhpns"` - FutureFeatures *bool `json:"future_features"` + Users *int `json:"users"` + LDAP *bool `json:"ldap"` + MFA *bool `json:"mfa"` + GoogleSSO *bool `json:"google_sso"` + Compliance *bool `json:"compliance"` + CustomBrand *bool `json:"custom_brand"` + MHPNS *bool `json:"mhpns"` + SAML *bool `json:"saml"` + PasswordRequirements *bool `json:"password_requirements"` + FutureFeatures *bool `json:"future_features"` } func (f *Features) SetDefaults() { @@ -82,6 +84,16 @@ func (f *Features) SetDefaults() { f.MHPNS = new(bool) *f.MHPNS = *f.FutureFeatures } + + if f.SAML == nil { + f.SAML = new(bool) + *f.SAML = *f.FutureFeatures + } + + if f.PasswordRequirements == nil { + f.PasswordRequirements = new(bool) + *f.PasswordRequirements = *f.FutureFeatures + } } func (l *License) IsExpired() bool { diff --git a/vendor/github.com/mattermost/platform/model/message.go b/vendor/github.com/mattermost/platform/model/message.go index a986af4d..12f3be66 100644 --- a/vendor/github.com/mattermost/platform/model/message.go +++ b/vendor/github.com/mattermost/platform/model/message.go @@ -17,6 +17,7 @@ const ( ACTION_CHANNEL_VIEWED = "channel_viewed" ACTION_DIRECT_ADDED = "direct_added" ACTION_NEW_USER = "new_user" + ACTION_LEAVE_TEAM = "leave_team" ACTION_USER_ADDED = "user_added" ACTION_USER_REMOVED = "user_removed" ACTION_PREFERENCE_CHANGED = "preference_changed" diff --git a/vendor/github.com/mattermost/platform/model/saml.go b/vendor/github.com/mattermost/platform/model/saml.go new file mode 100644 index 00000000..16d3845d --- /dev/null +++ b/vendor/github.com/mattermost/platform/model/saml.go @@ -0,0 +1,18 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +const ( + USER_AUTH_SERVICE_SAML = "saml" + USER_AUTH_SERVICE_SAML_TEXT = "With SAML" + SAML_IDP_CERTIFICATE = 1 + SAML_PRIVATE_KEY = 2 + SAML_PUBLIC_CERT = 3 +) + +type SamlAuthRequest struct { + Base64AuthRequest string + URL string + RelayState string +} diff --git a/vendor/github.com/mattermost/platform/model/team_member.go b/vendor/github.com/mattermost/platform/model/team_member.go index ae687c10..7d932dec 100644 --- a/vendor/github.com/mattermost/platform/model/team_member.go +++ b/vendor/github.com/mattermost/platform/model/team_member.go @@ -14,9 +14,10 @@ const ( ) type TeamMember struct { - TeamId string `json:"team_id"` - UserId string `json:"user_id"` - Roles string `json:"roles"` + TeamId string `json:"team_id"` + UserId string `json:"user_id"` + Roles string `json:"roles"` + DeleteAt int64 `json:"delete_at"` } func (o *TeamMember) ToJson() string { diff --git a/vendor/github.com/mattermost/platform/model/user.go b/vendor/github.com/mattermost/platform/model/user.go index ab076894..c792f80d 100644 --- a/vendor/github.com/mattermost/platform/model/user.go +++ b/vendor/github.com/mattermost/platform/model/user.go @@ -27,7 +27,6 @@ const ( DEFAULT_LOCALE = "en" USER_AUTH_SERVICE_EMAIL = "email" USER_AUTH_SERVICE_USERNAME = "username" - MIN_PASSWORD_LENGTH = 5 ) type User struct { @@ -95,10 +94,6 @@ func (u *User) IsValid() *AppError { return NewLocAppError("User.IsValid", "model.user.is_valid.last_name.app_error", nil, "user_id="+u.Id) } - if len(u.Password) > 128 { - return NewLocAppError("User.IsValid", "model.user.is_valid.pwd.app_error", nil, "user_id="+u.Id) - } - if u.AuthData != nil && len(*u.AuthData) > 128 { return NewLocAppError("User.IsValid", "model.user.is_valid.auth_data.app_error", nil, "user_id="+u.Id) } @@ -208,7 +203,6 @@ func (u *User) SetDefaultNotifications() { u.NotifyProps["desktop"] = USER_NOTIFY_ALL u.NotifyProps["desktop_sound"] = "true" u.NotifyProps["mention_keys"] = u.Username + ",@" + u.Username - u.NotifyProps["all"] = "true" u.NotifyProps["channel"] = "true" if u.FirstName == "" { @@ -244,8 +238,8 @@ func (u *User) ToJson() string { } // Generate a valid strong etag so the browser can cache the results -func (u *User) Etag() string { - return Etag(u.Id, u.UpdateAt) +func (u *User) Etag(showFullName, showEmail bool) string { + return Etag(u.Id, u.UpdateAt, showFullName, showEmail) } func (u *User) IsOffline() bool { @@ -363,13 +357,13 @@ func isValidRole(role string) bool { return false } -// Make sure you acually want to use this function. In context.go there are functions to check permssions +// Make sure you acually want to use this function. In context.go there are functions to check permissions // This function should not be used to check permissions. func (u *User) IsInRole(inRole string) bool { return IsInRole(u.Roles, inRole) } -// Make sure you acually want to use this function. In context.go there are functions to check permssions +// Make sure you acually want to use this function. In context.go there are functions to check permissions // This function should not be used to check permissions. func IsInRole(userRoles string, inRole string) bool { roles := strings.Split(userRoles, " ") diff --git a/vendor/github.com/mattermost/platform/model/utils.go b/vendor/github.com/mattermost/platform/model/utils.go index 27093c09..27ab3e27 100644 --- a/vendor/github.com/mattermost/platform/model/utils.go +++ b/vendor/github.com/mattermost/platform/model/utils.go @@ -20,6 +20,13 @@ import ( "github.com/pborman/uuid" ) +const ( + LOWERCASE_LETTERS = "abcdefghijklmnopqrstuvwxyz" + UPPERCASE_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + NUMBERS = "0123456789" + SYMBOLS = " !\"\\#$%&'()*+,-./:;<=>?@[]^_`|~" +) + type StringInterface map[string]interface{} type StringMap map[string]string type StringArray []string diff --git a/vendor/github.com/mattermost/platform/model/version.go b/vendor/github.com/mattermost/platform/model/version.go index d486f5c5..c6f49525 100644 --- a/vendor/github.com/mattermost/platform/model/version.go +++ b/vendor/github.com/mattermost/platform/model/version.go @@ -13,6 +13,7 @@ import ( // It should be maitained in chronological order with most current // release at the front of the list. var versions = []string{ + "3.2.0", "3.1.0", "3.0.0", "2.2.0", diff --git a/vendor/manifest b/vendor/manifest index 11862129..ddf6d9c7 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -63,8 +63,8 @@ "importpath": "github.com/mattermost/platform/einterfaces", "repository": "https://github.com/mattermost/platform", "vcs": "git", - "revision": "974238231b9cdbd39a825ec8e9299fbb0b51f6b8", - "branch": "release-3.1", + "revision": "ab52700aaa76a5623de23cd0156f5dbd9a24e264", + "branch": "release-3.2", "path": "/einterfaces", "notests": true }, @@ -72,8 +72,8 @@ "importpath": "github.com/mattermost/platform/model", "repository": "https://github.com/mattermost/platform", "vcs": "git", - "revision": "974238231b9cdbd39a825ec8e9299fbb0b51f6b8", - "branch": "release-3.1", + "revision": "ab52700aaa76a5623de23cd0156f5dbd9a24e264", + "branch": "release-3.2", "path": "/model", "notests": true },