github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/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 "errors" 9 "net/http" 10 "os" 11 "strings" 12 13 "github.com/mattermost/mattermost-server/v5/mlog" 14 "github.com/mattermost/mattermost-server/v5/model" 15 "github.com/mattermost/mattermost-server/v5/utils" 16 ) 17 18 const ( 19 requestTrialURL = "https://customers.mattermost.com/api/v1/trials" 20 LicenseEnv = "MM_LICENSE" 21 ) 22 23 func (s *Server) LoadLicense() { 24 // ENV var overrides all other sources of license. 25 licenseStr := os.Getenv(LicenseEnv) 26 if licenseStr != "" { 27 if s.ValidateAndSetLicenseBytes([]byte(licenseStr)) { 28 mlog.Info("License key from ENV is valid, unlocking enterprise features.") 29 } 30 return 31 } 32 33 licenseId := "" 34 props, err := s.Store.System().Get() 35 if err == nil { 36 licenseId = props[model.SYSTEM_ACTIVE_LICENSE_ID] 37 } 38 39 if !model.IsValidId(licenseId) { 40 // Lets attempt to load the file from disk since it was missing from the DB 41 license, licenseBytes := utils.GetAndValidateLicenseFileFromDisk(*s.Config().ServiceSettings.LicenseFileLocation) 42 43 if license != nil { 44 if _, err = s.SaveLicense(licenseBytes); err != nil { 45 mlog.Info("Failed to save license key loaded from disk.", mlog.Err(err)) 46 } else { 47 licenseId = license.Id 48 } 49 } 50 } 51 52 record, nErr := s.Store.License().Get(licenseId) 53 if nErr != nil { 54 mlog.Info("License key from https://mattermost.com required to unlock enterprise features.") 55 s.SetLicense(nil) 56 return 57 } 58 59 s.ValidateAndSetLicenseBytes([]byte(record.Bytes)) 60 mlog.Info("License key valid unlocking enterprise features.") 61 } 62 63 func (s *Server) SaveLicense(licenseBytes []byte) (*model.License, *model.AppError) { 64 success, licenseStr := utils.ValidateLicense(licenseBytes) 65 if !success { 66 return nil, model.NewAppError("addLicense", model.INVALID_LICENSE_ERROR, nil, "", http.StatusBadRequest) 67 } 68 license := model.LicenseFromJson(strings.NewReader(licenseStr)) 69 70 uniqueUserCount, err := s.Store.User().Count(model.UserCountOptions{}) 71 if err != nil { 72 return nil, model.NewAppError("addLicense", "api.license.add_license.invalid_count.app_error", nil, err.Error(), http.StatusBadRequest) 73 } 74 75 if uniqueUserCount > int64(*license.Features.Users) { 76 return nil, model.NewAppError("addLicense", "api.license.add_license.unique_users.app_error", map[string]interface{}{"Users": *license.Features.Users, "Count": uniqueUserCount}, "", http.StatusBadRequest) 77 } 78 79 if license != nil && license.IsExpired() { 80 return nil, model.NewAppError("addLicense", model.EXPIRED_LICENSE_ERROR, nil, "", http.StatusBadRequest) 81 } 82 83 if ok := s.SetLicense(license); !ok { 84 return nil, model.NewAppError("addLicense", model.EXPIRED_LICENSE_ERROR, nil, "", http.StatusBadRequest) 85 } 86 87 record := &model.LicenseRecord{} 88 record.Id = license.Id 89 record.Bytes = string(licenseBytes) 90 91 _, nErr := s.Store.License().Save(record) 92 if nErr != nil { 93 s.RemoveLicense() 94 var appErr *model.AppError 95 switch { 96 case errors.As(nErr, &appErr): 97 return nil, appErr 98 default: 99 return nil, model.NewAppError("addLicense", "api.license.add_license.save.app_error", nil, err.Error(), http.StatusInternalServerError) 100 } 101 } 102 103 sysVar := &model.System{} 104 sysVar.Name = model.SYSTEM_ACTIVE_LICENSE_ID 105 sysVar.Value = license.Id 106 if err := s.Store.System().SaveOrUpdate(sysVar); err != nil { 107 s.RemoveLicense() 108 return nil, model.NewAppError("addLicense", "api.license.add_license.save_active.app_error", nil, "", http.StatusInternalServerError) 109 } 110 111 s.ReloadConfig() 112 s.InvalidateAllCaches() 113 114 // start job server if necessary - this handles the edge case where a license file is uploaded, but the job server 115 // doesn't start until the server is restarted, which prevents the 'run job now' buttons in system console from 116 // functioning as expected 117 if *s.Config().JobSettings.RunJobs && s.Jobs != nil && s.Jobs.Workers != nil { 118 s.Jobs.StartWorkers() 119 } 120 if *s.Config().JobSettings.RunScheduler && s.Jobs != nil && s.Jobs.Schedulers != nil { 121 s.Jobs.StartSchedulers() 122 } 123 124 return license, nil 125 } 126 127 func (s *Server) SetLicense(license *model.License) bool { 128 oldLicense := s.licenseValue.Load() 129 130 defer func() { 131 for _, listener := range s.licenseListeners { 132 if oldLicense == nil { 133 listener(nil, license) 134 } else { 135 listener(oldLicense.(*model.License), license) 136 } 137 } 138 }() 139 140 if license != nil { 141 license.Features.SetDefaults() 142 143 s.licenseValue.Store(license) 144 s.clientLicenseValue.Store(utils.GetClientLicense(license)) 145 return true 146 } 147 148 s.licenseValue.Store((*model.License)(nil)) 149 s.clientLicenseValue.Store(map[string]string(nil)) 150 return false 151 } 152 153 func (s *Server) ValidateAndSetLicenseBytes(b []byte) bool { 154 if success, licenseStr := utils.ValidateLicense(b); success { 155 license := model.LicenseFromJson(strings.NewReader(licenseStr)) 156 s.SetLicense(license) 157 return true 158 } 159 160 mlog.Warn("No valid enterprise license found") 161 return false 162 } 163 164 func (s *Server) SetClientLicense(m map[string]string) { 165 s.clientLicenseValue.Store(m) 166 } 167 168 func (s *Server) ClientLicense() map[string]string { 169 if clientLicense, _ := s.clientLicenseValue.Load().(map[string]string); clientLicense != nil { 170 return clientLicense 171 } 172 return map[string]string{"IsLicensed": "false"} 173 } 174 175 func (s *Server) RemoveLicense() *model.AppError { 176 if license, _ := s.licenseValue.Load().(*model.License); license == nil { 177 return nil 178 } 179 180 mlog.Info("Remove license.", mlog.String("id", model.SYSTEM_ACTIVE_LICENSE_ID)) 181 182 sysVar := &model.System{} 183 sysVar.Name = model.SYSTEM_ACTIVE_LICENSE_ID 184 sysVar.Value = "" 185 186 if err := s.Store.System().SaveOrUpdate(sysVar); err != nil { 187 return err 188 } 189 190 s.SetLicense(nil) 191 s.ReloadConfig() 192 s.InvalidateAllCaches() 193 194 return nil 195 } 196 197 func (s *Server) AddLicenseListener(listener func(oldLicense, newLicense *model.License)) string { 198 id := model.NewId() 199 s.licenseListeners[id] = listener 200 return id 201 } 202 203 func (s *Server) RemoveLicenseListener(id string) { 204 delete(s.licenseListeners, id) 205 } 206 207 func (s *Server) GetSanitizedClientLicense() map[string]string { 208 sanitizedLicense := make(map[string]string) 209 210 for k, v := range s.ClientLicense() { 211 sanitizedLicense[k] = v 212 } 213 214 delete(sanitizedLicense, "Id") 215 delete(sanitizedLicense, "Name") 216 delete(sanitizedLicense, "Email") 217 delete(sanitizedLicense, "IssuedAt") 218 delete(sanitizedLicense, "StartsAt") 219 delete(sanitizedLicense, "ExpiresAt") 220 delete(sanitizedLicense, "SkuName") 221 delete(sanitizedLicense, "SkuShortName") 222 223 return sanitizedLicense 224 } 225 226 // RequestTrialLicense request a trial license from the mattermost offical license server 227 func (s *Server) RequestTrialLicense(trialRequest *model.TrialLicenseRequest) *model.AppError { 228 resp, err := http.Post(requestTrialURL, "application/json", bytes.NewBuffer([]byte(trialRequest.ToJson()))) 229 if err != nil { 230 return model.NewAppError("RequestTrialLicense", "api.license.request_trial_license.app_error", nil, err.Error(), http.StatusBadRequest) 231 } 232 defer resp.Body.Close() 233 licenseResponse := model.MapFromJson(resp.Body) 234 235 if _, ok := licenseResponse["license"]; !ok { 236 return model.NewAppError("RequestTrialLicense", "api.license.request_trial_license.app_error", nil, licenseResponse["message"], http.StatusBadRequest) 237 } 238 239 if _, err := s.SaveLicense([]byte(licenseResponse["license"])); err != nil { 240 return err 241 } 242 243 s.ReloadConfig() 244 s.InvalidateAllCaches() 245 246 return nil 247 }