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  }