github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/app/license.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "bytes" 8 "net/http" 9 "os" 10 "strings" 11 "time" 12 13 "github.com/dgrijalva/jwt-go" 14 "github.com/pkg/errors" 15 16 "github.com/mattermost/mattermost-server/v5/mlog" 17 "github.com/mattermost/mattermost-server/v5/model" 18 "github.com/mattermost/mattermost-server/v5/utils" 19 ) 20 21 const ( 22 requestTrialURL = "https://customers.mattermost.com/api/v1/trials" 23 LicenseEnv = "MM_LICENSE" 24 LicenseRenewalURL = "https://customers.mattermost.com/subscribe/renew" 25 JWTDefaultTokenExpiration = 7 * 24 * time.Hour // 7 days of expiration 26 ) 27 28 // JWTClaims custom JWT claims with the needed information for the 29 // renewal process 30 type JWTClaims struct { 31 LicenseID string `json:"license_id"` 32 ActiveUsers int64 `json:"active_users"` 33 jwt.StandardClaims 34 } 35 36 func (s *Server) LoadLicense() { 37 // ENV var overrides all other sources of license. 38 licenseStr := os.Getenv(LicenseEnv) 39 if licenseStr != "" { 40 if s.ValidateAndSetLicenseBytes([]byte(licenseStr)) { 41 mlog.Info("License key from ENV is valid, unlocking enterprise features.") 42 } 43 return 44 } 45 46 licenseId := "" 47 props, nErr := s.Store.System().Get() 48 if nErr == nil { 49 licenseId = props[model.SYSTEM_ACTIVE_LICENSE_ID] 50 } 51 52 if !model.IsValidId(licenseId) { 53 // Lets attempt to load the file from disk since it was missing from the DB 54 license, licenseBytes := utils.GetAndValidateLicenseFileFromDisk(*s.Config().ServiceSettings.LicenseFileLocation) 55 56 if license != nil { 57 if _, err := s.SaveLicense(licenseBytes); err != nil { 58 mlog.Info("Failed to save license key loaded from disk.", mlog.Err(err)) 59 } else { 60 licenseId = license.Id 61 } 62 } 63 } 64 65 record, nErr := s.Store.License().Get(licenseId) 66 if nErr != nil { 67 mlog.Info("License key from https://mattermost.com required to unlock enterprise features.") 68 s.SetLicense(nil) 69 return 70 } 71 72 s.ValidateAndSetLicenseBytes([]byte(record.Bytes)) 73 mlog.Info("License key valid unlocking enterprise features.") 74 } 75 76 func (s *Server) SaveLicense(licenseBytes []byte) (*model.License, *model.AppError) { 77 success, licenseStr := utils.ValidateLicense(licenseBytes) 78 if !success { 79 return nil, model.NewAppError("addLicense", model.INVALID_LICENSE_ERROR, nil, "", http.StatusBadRequest) 80 } 81 license := model.LicenseFromJson(strings.NewReader(licenseStr)) 82 83 uniqueUserCount, err := s.Store.User().Count(model.UserCountOptions{}) 84 if err != nil { 85 return nil, model.NewAppError("addLicense", "api.license.add_license.invalid_count.app_error", nil, err.Error(), http.StatusBadRequest) 86 } 87 88 if uniqueUserCount > int64(*license.Features.Users) { 89 return nil, model.NewAppError("addLicense", "api.license.add_license.unique_users.app_error", map[string]interface{}{"Users": *license.Features.Users, "Count": uniqueUserCount}, "", http.StatusBadRequest) 90 } 91 92 if license != nil && license.IsExpired() { 93 return nil, model.NewAppError("addLicense", model.EXPIRED_LICENSE_ERROR, nil, "", http.StatusBadRequest) 94 } 95 96 if ok := s.SetLicense(license); !ok { 97 return nil, model.NewAppError("addLicense", model.EXPIRED_LICENSE_ERROR, nil, "", http.StatusBadRequest) 98 } 99 100 record := &model.LicenseRecord{} 101 record.Id = license.Id 102 record.Bytes = string(licenseBytes) 103 104 _, nErr := s.Store.License().Save(record) 105 if nErr != nil { 106 s.RemoveLicense() 107 var appErr *model.AppError 108 switch { 109 case errors.As(nErr, &appErr): 110 return nil, appErr 111 default: 112 return nil, model.NewAppError("addLicense", "api.license.add_license.save.app_error", nil, nErr.Error(), http.StatusInternalServerError) 113 } 114 } 115 116 sysVar := &model.System{} 117 sysVar.Name = model.SYSTEM_ACTIVE_LICENSE_ID 118 sysVar.Value = license.Id 119 if err := s.Store.System().SaveOrUpdate(sysVar); err != nil { 120 s.RemoveLicense() 121 return nil, model.NewAppError("addLicense", "api.license.add_license.save_active.app_error", nil, "", http.StatusInternalServerError) 122 } 123 124 s.ReloadConfig() 125 s.InvalidateAllCaches() 126 127 // start job server if necessary - this handles the edge case where a license file is uploaded, but the job server 128 // doesn't start until the server is restarted, which prevents the 'run job now' buttons in system console from 129 // functioning as expected 130 if *s.Config().JobSettings.RunJobs && s.Jobs != nil && s.Jobs.Workers != nil { 131 s.Jobs.StartWorkers() 132 } 133 if *s.Config().JobSettings.RunScheduler && s.Jobs != nil && s.Jobs.Schedulers != nil { 134 s.Jobs.StartSchedulers() 135 } 136 137 return license, nil 138 } 139 140 func (s *Server) SetLicense(license *model.License) bool { 141 oldLicense := s.licenseValue.Load() 142 143 defer func() { 144 for _, listener := range s.licenseListeners { 145 if oldLicense == nil { 146 listener(nil, license) 147 } else { 148 listener(oldLicense.(*model.License), license) 149 } 150 } 151 }() 152 153 if license != nil { 154 license.Features.SetDefaults() 155 156 s.licenseValue.Store(license) 157 s.clientLicenseValue.Store(utils.GetClientLicense(license)) 158 return true 159 } 160 161 s.licenseValue.Store((*model.License)(nil)) 162 s.clientLicenseValue.Store(map[string]string(nil)) 163 return false 164 } 165 166 func (s *Server) ValidateAndSetLicenseBytes(b []byte) bool { 167 if success, licenseStr := utils.ValidateLicense(b); success { 168 license := model.LicenseFromJson(strings.NewReader(licenseStr)) 169 s.SetLicense(license) 170 return true 171 } 172 173 mlog.Warn("No valid enterprise license found") 174 return false 175 } 176 177 func (s *Server) SetClientLicense(m map[string]string) { 178 s.clientLicenseValue.Store(m) 179 } 180 181 func (s *Server) ClientLicense() map[string]string { 182 if clientLicense, _ := s.clientLicenseValue.Load().(map[string]string); clientLicense != nil { 183 return clientLicense 184 } 185 return map[string]string{"IsLicensed": "false"} 186 } 187 188 func (s *Server) RemoveLicense() *model.AppError { 189 if license, _ := s.licenseValue.Load().(*model.License); license == nil { 190 return nil 191 } 192 193 mlog.Info("Remove license.", mlog.String("id", model.SYSTEM_ACTIVE_LICENSE_ID)) 194 195 sysVar := &model.System{} 196 sysVar.Name = model.SYSTEM_ACTIVE_LICENSE_ID 197 sysVar.Value = "" 198 199 if err := s.Store.System().SaveOrUpdate(sysVar); err != nil { 200 return model.NewAppError("RemoveLicense", "app.system.save.app_error", nil, err.Error(), http.StatusInternalServerError) 201 } 202 203 s.SetLicense(nil) 204 s.ReloadConfig() 205 s.InvalidateAllCaches() 206 207 return nil 208 } 209 210 func (s *Server) AddLicenseListener(listener func(oldLicense, newLicense *model.License)) string { 211 id := model.NewId() 212 s.licenseListeners[id] = listener 213 return id 214 } 215 216 func (s *Server) RemoveLicenseListener(id string) { 217 delete(s.licenseListeners, id) 218 } 219 220 func (s *Server) GetSanitizedClientLicense() map[string]string { 221 sanitizedLicense := make(map[string]string) 222 223 for k, v := range s.ClientLicense() { 224 sanitizedLicense[k] = v 225 } 226 227 delete(sanitizedLicense, "Id") 228 delete(sanitizedLicense, "Name") 229 delete(sanitizedLicense, "Email") 230 delete(sanitizedLicense, "IssuedAt") 231 delete(sanitizedLicense, "StartsAt") 232 delete(sanitizedLicense, "ExpiresAt") 233 delete(sanitizedLicense, "SkuName") 234 delete(sanitizedLicense, "SkuShortName") 235 236 return sanitizedLicense 237 } 238 239 // RequestTrialLicense request a trial license from the mattermost official license server 240 func (s *Server) RequestTrialLicense(trialRequest *model.TrialLicenseRequest) *model.AppError { 241 resp, err := http.Post(requestTrialURL, "application/json", bytes.NewBuffer([]byte(trialRequest.ToJson()))) 242 if err != nil { 243 return model.NewAppError("RequestTrialLicense", "api.license.request_trial_license.app_error", nil, err.Error(), http.StatusBadRequest) 244 } 245 defer resp.Body.Close() 246 licenseResponse := model.MapFromJson(resp.Body) 247 248 if _, ok := licenseResponse["license"]; !ok { 249 return model.NewAppError("RequestTrialLicense", "api.license.request_trial_license.app_error", nil, licenseResponse["message"], http.StatusBadRequest) 250 } 251 252 if _, err := s.SaveLicense([]byte(licenseResponse["license"])); err != nil { 253 return err 254 } 255 256 s.ReloadConfig() 257 s.InvalidateAllCaches() 258 259 return nil 260 } 261 262 // GenerateRenewalToken returns the current active token or generate a new one if 263 // the current active one has expired 264 func (s *Server) GenerateRenewalToken(expiration time.Duration) (string, *model.AppError) { 265 license := s.License() 266 if license == nil { 267 // Clean renewal token if there is no license present 268 if _, err := s.Store.System().PermanentDeleteByName(model.SYSTEM_LICENSE_RENEWAL_TOKEN); err != nil { 269 mlog.Warn("error removing the renewal token", mlog.Err(err)) 270 } 271 return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.no_license", nil, "", http.StatusBadRequest) 272 } 273 274 if *license.Features.Cloud { 275 return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.bad_license", nil, "", http.StatusBadRequest) 276 } 277 278 currentToken, _ := s.Store.System().GetByName(model.SYSTEM_LICENSE_RENEWAL_TOKEN) 279 if currentToken != nil { 280 tokenIsValid, err := s.renewalTokenValid(currentToken.Value, license.Customer.Email) 281 if err != nil { 282 mlog.Warn("error checking license renewal token validation", mlog.Err(err)) 283 } 284 if currentToken.Value != "" && tokenIsValid { 285 return currentToken.Value, nil 286 } 287 } 288 289 activeUsers, err := s.Store.User().Count(model.UserCountOptions{}) 290 if err != nil { 291 return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.app_error", 292 nil, err.Error(), http.StatusInternalServerError) 293 } 294 295 expirationTime := time.Now().UTC().Add(expiration) 296 claims := &JWTClaims{ 297 LicenseID: license.Id, 298 ActiveUsers: activeUsers, 299 StandardClaims: jwt.StandardClaims{ 300 ExpiresAt: expirationTime.Unix(), 301 }, 302 } 303 304 token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 305 tokenString, err := token.SignedString([]byte(license.Customer.Email)) 306 if err != nil { 307 return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.app_error", nil, err.Error(), http.StatusInternalServerError) 308 } 309 err = s.Store.System().SaveOrUpdate(&model.System{ 310 Name: model.SYSTEM_LICENSE_RENEWAL_TOKEN, 311 Value: tokenString, 312 }) 313 if err != nil { 314 return "", model.NewAppError("GenerateRenewalToken", "app.license.generate_renewal_token.app_error", nil, err.Error(), http.StatusInternalServerError) 315 } 316 return tokenString, nil 317 } 318 319 func (s *Server) renewalTokenValid(tokenString, signingKey string) (bool, error) { 320 claims := &JWTClaims{} 321 322 token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { 323 return []byte(signingKey), nil 324 }) 325 if err != nil && !token.Valid { 326 return false, errors.Wrapf(err, "Error validating JWT token") 327 } 328 expirationTime := time.Unix(claims.ExpiresAt, 0) 329 if expirationTime.Before(time.Now().UTC()) { 330 return false, nil 331 } 332 return true, nil 333 } 334 335 // GenerateLicenseRenewalLink returns a link that points to the CWS where clients can renew license 336 func (s *Server) GenerateLicenseRenewalLink() (string, *model.AppError) { 337 renewalToken, err := s.GenerateRenewalToken(JWTDefaultTokenExpiration) 338 if err != nil { 339 return "", err 340 } 341 renewalLink := LicenseRenewalURL + "?token=" + renewalToken 342 return renewalLink, nil 343 }