1// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2// See LICENSE.txt for license information. 3 4package model 5 6import ( 7 "fmt" 8 "net/http" 9 "unicode/utf8" 10) 11 12const ( 13 OAuthActionSignup = "signup" 14 OAuthActionLogin = "login" 15 OAuthActionEmailToSSO = "email_to_sso" 16 OAuthActionSSOToEmail = "sso_to_email" 17 OAuthActionMobile = "mobile" 18) 19 20type OAuthApp struct { 21 Id string `json:"id"` 22 CreatorId string `json:"creator_id"` 23 CreateAt int64 `json:"create_at"` 24 UpdateAt int64 `json:"update_at"` 25 ClientSecret string `json:"client_secret"` 26 Name string `json:"name"` 27 Description string `json:"description"` 28 IconURL string `json:"icon_url"` 29 CallbackUrls StringArray `json:"callback_urls"` 30 Homepage string `json:"homepage"` 31 IsTrusted bool `json:"is_trusted"` 32} 33 34// IsValid validates the app and returns an error if it isn't configured 35// correctly. 36func (a *OAuthApp) IsValid() *AppError { 37 38 if !IsValidId(a.Id) { 39 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.app_id.app_error", nil, "", http.StatusBadRequest) 40 } 41 42 if a.CreateAt == 0 { 43 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.create_at.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) 44 } 45 46 if a.UpdateAt == 0 { 47 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.update_at.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) 48 } 49 50 if !IsValidId(a.CreatorId) { 51 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.creator_id.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) 52 } 53 54 if a.ClientSecret == "" || len(a.ClientSecret) > 128 { 55 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.client_secret.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) 56 } 57 58 if a.Name == "" || len(a.Name) > 64 { 59 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.name.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) 60 } 61 62 if len(a.CallbackUrls) == 0 || len(fmt.Sprintf("%s", a.CallbackUrls)) > 1024 { 63 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) 64 } 65 66 for _, callback := range a.CallbackUrls { 67 if !IsValidHTTPURL(callback) { 68 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "", http.StatusBadRequest) 69 } 70 } 71 72 if a.Homepage == "" || len(a.Homepage) > 256 || !IsValidHTTPURL(a.Homepage) { 73 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.homepage.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) 74 } 75 76 if utf8.RuneCountInString(a.Description) > 512 { 77 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.description.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) 78 } 79 80 if a.IconURL != "" { 81 if len(a.IconURL) > 512 || !IsValidHTTPURL(a.IconURL) { 82 return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.icon_url.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) 83 } 84 } 85 86 return nil 87} 88 89// PreSave will set the Id and ClientSecret if missing. It will also fill 90// in the CreateAt, UpdateAt times. It should be run before saving the app to the db. 91func (a *OAuthApp) PreSave() { 92 if a.Id == "" { 93 a.Id = NewId() 94 } 95 96 if a.ClientSecret == "" { 97 a.ClientSecret = NewId() 98 } 99 100 a.CreateAt = GetMillis() 101 a.UpdateAt = a.CreateAt 102} 103 104// PreUpdate should be run before updating the app in the db. 105func (a *OAuthApp) PreUpdate() { 106 a.UpdateAt = GetMillis() 107} 108 109// Generate a valid strong etag so the browser can cache the results 110func (a *OAuthApp) Etag() string { 111 return Etag(a.Id, a.UpdateAt) 112} 113 114// Remove any private data from the app object 115func (a *OAuthApp) Sanitize() { 116 a.ClientSecret = "" 117} 118 119func (a *OAuthApp) IsValidRedirectURL(url string) bool { 120 for _, u := range a.CallbackUrls { 121 if u == url { 122 return true 123 } 124 } 125 126 return false 127} 128