github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/app/session.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  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"math"
    11  	"net/http"
    12  	"os"
    13  	"sync"
    14  	"time"
    15  
    16  	"github.com/mattermost/mattermost-server/v5/audit"
    17  	"github.com/mattermost/mattermost-server/v5/mlog"
    18  	"github.com/mattermost/mattermost-server/v5/model"
    19  	"github.com/mattermost/mattermost-server/v5/store"
    20  )
    21  
    22  func (a *App) CreateSession(session *model.Session) (*model.Session, *model.AppError) {
    23  	session.Token = ""
    24  
    25  	session, err := a.Srv().Store.Session().Save(session)
    26  	if err != nil {
    27  		var invErr *store.ErrInvalidInput
    28  		switch {
    29  		case errors.As(err, &invErr):
    30  			return nil, model.NewAppError("CreateSession", "app.session.save.existing.app_error", nil, invErr.Error(), http.StatusBadRequest)
    31  		default:
    32  			return nil, model.NewAppError("CreateSession", "app.session.save.app_error", nil, err.Error(), http.StatusInternalServerError)
    33  		}
    34  	}
    35  
    36  	a.AddSessionToCache(session)
    37  
    38  	return session, nil
    39  }
    40  
    41  func ReturnSessionToPool(session *model.Session) {
    42  	if session != nil {
    43  		session.Id = ""
    44  		userSessionPool.Put(session)
    45  	}
    46  }
    47  
    48  var userSessionPool = sync.Pool{
    49  	New: func() interface{} {
    50  		return &model.Session{}
    51  	},
    52  }
    53  
    54  func (a *App) GetCloudSession(token string) (*model.Session, *model.AppError) {
    55  	apiKey := os.Getenv("MM_CLOUD_API_KEY")
    56  	if apiKey != "" && apiKey == token {
    57  		// Need a bare-bones session object for later checks
    58  		session := &model.Session{
    59  			Token:   token,
    60  			IsOAuth: false,
    61  		}
    62  
    63  		session.AddProp(model.SESSION_PROP_TYPE, model.SESSION_TYPE_CLOUD_KEY)
    64  		return session, nil
    65  	}
    66  	return nil, model.NewAppError("GetCloudSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token, "Error": ""}, "The provided token is invalid", http.StatusUnauthorized)
    67  }
    68  
    69  func (a *App) GetSession(token string) (*model.Session, *model.AppError) {
    70  	metrics := a.Metrics()
    71  
    72  	var session = userSessionPool.Get().(*model.Session)
    73  
    74  	var err *model.AppError
    75  	if err := a.Srv().sessionCache.Get(token, session); err == nil {
    76  		if metrics != nil {
    77  			metrics.IncrementMemCacheHitCounterSession()
    78  		}
    79  	} else {
    80  		if metrics != nil {
    81  			metrics.IncrementMemCacheMissCounterSession()
    82  		}
    83  	}
    84  
    85  	if session.Id == "" {
    86  		var nErr error
    87  		if session, nErr = a.Srv().Store.Session().Get(token); nErr == nil {
    88  			if session != nil {
    89  				if session.Token != token {
    90  					return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token, "Error": ""}, "session token is different from the one in DB", http.StatusUnauthorized)
    91  				}
    92  
    93  				if !session.IsExpired() {
    94  					a.AddSessionToCache(session)
    95  				}
    96  			}
    97  		} else if nfErr := new(store.ErrNotFound); !errors.As(nErr, &nfErr) {
    98  			return nil, model.NewAppError("GetSession", "app.session.get.app_error", nil, nErr.Error(), http.StatusInternalServerError)
    99  		}
   100  	}
   101  
   102  	if session == nil || session.Id == "" {
   103  		session, err = a.createSessionForUserAccessToken(token)
   104  		if err != nil {
   105  			detailedError := ""
   106  			statusCode := http.StatusUnauthorized
   107  			if err.Id != "app.user_access_token.invalid_or_missing" {
   108  				detailedError = err.Error()
   109  				statusCode = err.StatusCode
   110  			} else {
   111  				mlog.Warn("Error while creating session for user access token", mlog.Err(err))
   112  			}
   113  			return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token, "Error": detailedError}, "", statusCode)
   114  		}
   115  	}
   116  
   117  	if session.Id == "" || session.IsExpired() {
   118  		return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token, "Error": ""}, "session is either nil or expired", http.StatusUnauthorized)
   119  	}
   120  
   121  	if *a.Config().ServiceSettings.SessionIdleTimeoutInMinutes > 0 &&
   122  		!session.IsOAuth && !session.IsMobileApp() &&
   123  		session.Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_USER_ACCESS_TOKEN &&
   124  		!*a.Config().ServiceSettings.ExtendSessionLengthWithActivity {
   125  
   126  		timeout := int64(*a.Config().ServiceSettings.SessionIdleTimeoutInMinutes) * 1000 * 60
   127  		if (model.GetMillis() - session.LastActivityAt) > timeout {
   128  			// Revoking the session is an asynchronous task anyways since we are not checking
   129  			// for the return value of the call before returning the error.
   130  			// So moving this to a goroutine has 2 advantages:
   131  			// 1. We are treating this as a proper asynchronous task.
   132  			// 2. This also fixes a race condition in the web hub, where GetSession
   133  			// gets called from (*WebConn).isMemberOfTeam and revoking a session involves
   134  			// clearing the webconn cache, which needs the hub again.
   135  			a.Srv().Go(func() {
   136  				err := a.RevokeSessionById(session.Id)
   137  				if err != nil {
   138  					mlog.Warn("Error while revoking session", mlog.Err(err))
   139  				}
   140  			})
   141  			return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token, "Error": ""}, "idle timeout", http.StatusUnauthorized)
   142  		}
   143  	}
   144  
   145  	return session, nil
   146  }
   147  
   148  func (a *App) GetSessions(userID string) ([]*model.Session, *model.AppError) {
   149  
   150  	sessions, err := a.Srv().Store.Session().GetSessions(userID)
   151  	if err != nil {
   152  		return nil, model.NewAppError("GetSessions", "app.session.get_sessions.app_error", nil, err.Error(), http.StatusInternalServerError)
   153  	}
   154  
   155  	return sessions, nil
   156  }
   157  
   158  func (a *App) UpdateSessionsIsGuest(userID string, isGuest bool) {
   159  	sessions, err := a.Srv().Store.Session().GetSessions(userID)
   160  	if err != nil {
   161  		mlog.Error("Unable to get user sessions", mlog.String("user_id", userID), mlog.Err(err))
   162  		return
   163  	}
   164  
   165  	for _, session := range sessions {
   166  		session.AddProp(model.SESSION_PROP_IS_GUEST, fmt.Sprintf("%t", isGuest))
   167  		err := a.Srv().Store.Session().UpdateProps(session)
   168  		if err != nil {
   169  			mlog.Warn("Unable to update isGuest session", mlog.Err(err))
   170  			continue
   171  		}
   172  		a.AddSessionToCache(session)
   173  	}
   174  }
   175  
   176  func (a *App) RevokeAllSessions(userID string) *model.AppError {
   177  	sessions, err := a.Srv().Store.Session().GetSessions(userID)
   178  	if err != nil {
   179  		return model.NewAppError("RevokeAllSessions", "app.session.get_sessions.app_error", nil, err.Error(), http.StatusInternalServerError)
   180  	}
   181  	for _, session := range sessions {
   182  		if session.IsOAuth {
   183  			a.RevokeAccessToken(session.Token)
   184  		} else {
   185  			if err := a.Srv().Store.Session().Remove(session.Id); err != nil {
   186  				return model.NewAppError("RevokeAllSessions", "app.session.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
   187  			}
   188  		}
   189  	}
   190  
   191  	a.ClearSessionCacheForUser(userID)
   192  
   193  	return nil
   194  }
   195  
   196  // RevokeSessionsFromAllUsers will go through all the sessions active
   197  // in the server and revoke them
   198  func (a *App) RevokeSessionsFromAllUsers() *model.AppError {
   199  	// revoke tokens before sessions so they can't be used to relogin
   200  	nErr := a.Srv().Store.OAuth().RemoveAllAccessData()
   201  	if nErr != nil {
   202  		return model.NewAppError("RevokeSessionsFromAllUsers", "app.oauth.remove_access_data.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   203  	}
   204  	err := a.Srv().Store.Session().RemoveAllSessions()
   205  	if err != nil {
   206  		return model.NewAppError("RevokeSessionsFromAllUsers", "app.session.remove_all_sessions_for_team.app_error", nil, err.Error(), http.StatusInternalServerError)
   207  	}
   208  	a.ClearSessionCacheForAllUsers()
   209  
   210  	return nil
   211  }
   212  
   213  func (a *App) ClearSessionCacheForUser(userID string) {
   214  	a.ClearSessionCacheForUserSkipClusterSend(userID)
   215  
   216  	if a.Cluster() != nil {
   217  		msg := &model.ClusterMessage{
   218  			Event:    model.CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER,
   219  			SendType: model.CLUSTER_SEND_RELIABLE,
   220  			Data:     userID,
   221  		}
   222  		a.Cluster().SendClusterMessage(msg)
   223  	}
   224  }
   225  
   226  func (a *App) ClearSessionCacheForAllUsers() {
   227  	a.ClearSessionCacheForAllUsersSkipClusterSend()
   228  
   229  	if a.Cluster() != nil {
   230  		msg := &model.ClusterMessage{
   231  			Event:    model.CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_ALL_USERS,
   232  			SendType: model.CLUSTER_SEND_RELIABLE,
   233  		}
   234  		a.Cluster().SendClusterMessage(msg)
   235  	}
   236  }
   237  
   238  func (a *App) ClearSessionCacheForUserSkipClusterSend(userID string) {
   239  	if keys, err := a.Srv().sessionCache.Keys(); err == nil {
   240  		var session *model.Session
   241  		for _, key := range keys {
   242  			if err := a.Srv().sessionCache.Get(key, &session); err == nil {
   243  				if session.UserId == userID {
   244  					a.Srv().sessionCache.Remove(key)
   245  					if a.Metrics() != nil {
   246  						a.Metrics().IncrementMemCacheInvalidationCounterSession()
   247  					}
   248  				}
   249  			}
   250  		}
   251  	}
   252  
   253  	a.InvalidateWebConnSessionCacheForUser(userID)
   254  }
   255  
   256  func (a *App) ClearSessionCacheForAllUsersSkipClusterSend() {
   257  	mlog.Info("Purging sessions cache")
   258  	a.Srv().sessionCache.Purge()
   259  }
   260  
   261  func (a *App) AddSessionToCache(session *model.Session) {
   262  	a.Srv().sessionCache.SetWithExpiry(session.Token, session, time.Duration(int64(*a.Config().ServiceSettings.SessionCacheInMinutes))*time.Minute)
   263  }
   264  
   265  func (a *App) SessionCacheLength() int {
   266  	if l, err := a.Srv().sessionCache.Len(); err == nil {
   267  		return l
   268  	}
   269  	return 0
   270  }
   271  
   272  func (a *App) RevokeSessionsForDeviceId(userID string, deviceId string, currentSessionId string) *model.AppError {
   273  	sessions, err := a.Srv().Store.Session().GetSessions(userID)
   274  	if err != nil {
   275  		return model.NewAppError("RevokeSessionsForDeviceId", "app.session.get_sessions.app_error", nil, err.Error(), http.StatusInternalServerError)
   276  	}
   277  	for _, session := range sessions {
   278  		if session.DeviceId == deviceId && session.Id != currentSessionId {
   279  			mlog.Debug("Revoking sessionId for userId. Re-login with the same device Id", mlog.String("session_id", session.Id), mlog.String("user_id", userID))
   280  			if err := a.RevokeSession(session); err != nil {
   281  				mlog.Warn("Could not revoke session for device", mlog.String("device_id", deviceId), mlog.Err(err))
   282  			}
   283  		}
   284  	}
   285  
   286  	return nil
   287  }
   288  
   289  func (a *App) GetSessionById(sessionId string) (*model.Session, *model.AppError) {
   290  	session, err := a.Srv().Store.Session().Get(sessionId)
   291  	if err != nil {
   292  		return nil, model.NewAppError("GetSessionById", "app.session.get.app_error", nil, err.Error(), http.StatusBadRequest)
   293  	}
   294  
   295  	return session, nil
   296  }
   297  
   298  func (a *App) RevokeSessionById(sessionId string) *model.AppError {
   299  	session, err := a.Srv().Store.Session().Get(sessionId)
   300  	if err != nil {
   301  		return model.NewAppError("RevokeSessionById", "app.session.get.app_error", nil, err.Error(), http.StatusBadRequest)
   302  	}
   303  	return a.RevokeSession(session)
   304  
   305  }
   306  
   307  func (a *App) RevokeSession(session *model.Session) *model.AppError {
   308  	if session.IsOAuth {
   309  		if err := a.RevokeAccessToken(session.Token); err != nil {
   310  			return err
   311  		}
   312  	} else {
   313  		if err := a.Srv().Store.Session().Remove(session.Id); err != nil {
   314  			return model.NewAppError("RevokeSession", "app.session.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
   315  		}
   316  	}
   317  
   318  	a.ClearSessionCacheForUser(session.UserId)
   319  
   320  	return nil
   321  }
   322  
   323  func (a *App) AttachDeviceId(sessionId string, deviceId string, expiresAt int64) *model.AppError {
   324  	_, err := a.Srv().Store.Session().UpdateDeviceId(sessionId, deviceId, expiresAt)
   325  	if err != nil {
   326  		return model.NewAppError("AttachDeviceId", "app.session.update_device_id.app_error", nil, err.Error(), http.StatusInternalServerError)
   327  	}
   328  
   329  	return nil
   330  }
   331  
   332  func (a *App) UpdateLastActivityAtIfNeeded(session model.Session) {
   333  	now := model.GetMillis()
   334  
   335  	a.UpdateWebConnUserActivity(session, now)
   336  
   337  	if now-session.LastActivityAt < model.SESSION_ACTIVITY_TIMEOUT {
   338  		return
   339  	}
   340  
   341  	if err := a.Srv().Store.Session().UpdateLastActivityAt(session.Id, now); err != nil {
   342  		mlog.Warn("Failed to update LastActivityAt", mlog.String("user_id", session.UserId), mlog.String("session_id", session.Id), mlog.Err(err))
   343  	}
   344  
   345  	session.LastActivityAt = now
   346  	a.AddSessionToCache(&session)
   347  }
   348  
   349  // ExtendSessionExpiryIfNeeded extends Session.ExpiresAt based on session lengths in config.
   350  // A new ExpiresAt is only written if enough time has elapsed since last update.
   351  // Returns true only if the session was extended.
   352  func (a *App) ExtendSessionExpiryIfNeeded(session *model.Session) bool {
   353  	if session == nil || session.IsExpired() {
   354  		return false
   355  	}
   356  
   357  	sessionLength := a.GetSessionLengthInMillis(session)
   358  
   359  	// Only extend the expiry if the lessor of 1% or 1 day has elapsed within the
   360  	// current session duration.
   361  	threshold := int64(math.Min(float64(sessionLength)*0.01, float64(24*60*60*1000)))
   362  	// Minimum session length is 1 day as of this writing, therefore a minimum ~14 minutes threshold.
   363  	// However we'll add a sanity check here in case that changes. Minimum 5 minute threshold,
   364  	// meaning we won't write a new expiry more than every 5 minutes.
   365  	if threshold < 5*60*1000 {
   366  		threshold = 5 * 60 * 1000
   367  	}
   368  
   369  	now := model.GetMillis()
   370  	elapsed := now - (session.ExpiresAt - sessionLength)
   371  	if elapsed < threshold {
   372  		return false
   373  	}
   374  
   375  	auditRec := a.MakeAuditRecord("extendSessionExpiry", audit.Fail)
   376  	defer a.LogAuditRec(auditRec, nil)
   377  	auditRec.AddMeta("session", session)
   378  
   379  	newExpiry := now + sessionLength
   380  	if err := a.Srv().Store.Session().UpdateExpiresAt(session.Id, newExpiry); err != nil {
   381  		mlog.Error("Failed to update ExpiresAt", mlog.String("user_id", session.UserId), mlog.String("session_id", session.Id), mlog.Err(err))
   382  		auditRec.AddMeta("err", err.Error())
   383  		return false
   384  	}
   385  
   386  	// Update local cache. No need to invalidate cache for cluster as the session cache timeout
   387  	// ensures each node will get an extended expiry within the next 10 minutes.
   388  	// Worst case is another node may generate a redundant expiry update.
   389  	session.ExpiresAt = newExpiry
   390  	a.AddSessionToCache(session)
   391  
   392  	mlog.Debug("Session extended", mlog.String("user_id", session.UserId), mlog.String("session_id", session.Id),
   393  		mlog.Int64("newExpiry", newExpiry), mlog.Int64("session_length", sessionLength))
   394  
   395  	auditRec.Success()
   396  	auditRec.AddMeta("extended_session", session)
   397  	return true
   398  }
   399  
   400  // GetSessionLengthInMillis returns the session length, in milliseconds,
   401  // based on the type of session (Mobile, SSO, Web/LDAP).
   402  func (a *App) GetSessionLengthInMillis(session *model.Session) int64 {
   403  	if session == nil {
   404  		return 0
   405  	}
   406  
   407  	var days int
   408  	if session.IsMobileApp() {
   409  		days = *a.Config().ServiceSettings.SessionLengthMobileInDays
   410  	} else if session.IsSSOLogin() {
   411  		days = *a.Config().ServiceSettings.SessionLengthSSOInDays
   412  	} else {
   413  		days = *a.Config().ServiceSettings.SessionLengthWebInDays
   414  	}
   415  	return int64(days * 24 * 60 * 60 * 1000)
   416  }
   417  
   418  // SetSessionExpireInDays sets the session's expiry the specified number of days
   419  // relative to either the session creation date or the current time, depending
   420  // on the `ExtendSessionOnActivity` config setting.
   421  func (a *App) SetSessionExpireInDays(session *model.Session, days int) {
   422  	if session.CreateAt == 0 || *a.Config().ServiceSettings.ExtendSessionLengthWithActivity {
   423  		session.ExpiresAt = model.GetMillis() + (1000 * 60 * 60 * 24 * int64(days))
   424  	} else {
   425  		session.ExpiresAt = session.CreateAt + (1000 * 60 * 60 * 24 * int64(days))
   426  	}
   427  }
   428  
   429  func (a *App) CreateUserAccessToken(token *model.UserAccessToken) (*model.UserAccessToken, *model.AppError) {
   430  
   431  	user, nErr := a.Srv().Store.User().Get(context.Background(), token.UserId)
   432  	if nErr != nil {
   433  		var nfErr *store.ErrNotFound
   434  		switch {
   435  		case errors.As(nErr, &nfErr):
   436  			return nil, model.NewAppError("CreateUserAccessToken", MissingAccountError, nil, nfErr.Error(), http.StatusNotFound)
   437  		default:
   438  			return nil, model.NewAppError("CreateUserAccessToken", "app.user.get.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   439  		}
   440  	}
   441  
   442  	if !*a.Config().ServiceSettings.EnableUserAccessTokens && !user.IsBot {
   443  		return nil, model.NewAppError("CreateUserAccessToken", "app.user_access_token.disabled", nil, "", http.StatusNotImplemented)
   444  	}
   445  
   446  	token.Token = model.NewId()
   447  
   448  	token, nErr = a.Srv().Store.UserAccessToken().Save(token)
   449  	if nErr != nil {
   450  		var appErr *model.AppError
   451  		switch {
   452  		case errors.As(nErr, &appErr):
   453  			return nil, appErr
   454  		default:
   455  			return nil, model.NewAppError("CreateUserAccessToken", "app.user_access_token.save.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   456  		}
   457  	}
   458  
   459  	// Don't send emails to bot users.
   460  	if !user.IsBot {
   461  		if err := a.Srv().EmailService.sendUserAccessTokenAddedEmail(user.Email, user.Locale, a.GetSiteURL()); err != nil {
   462  			a.Log().Error("Unable to send user access token added email", mlog.Err(err), mlog.String("user_id", user.Id))
   463  		}
   464  	}
   465  
   466  	return token, nil
   467  
   468  }
   469  
   470  func (a *App) createSessionForUserAccessToken(tokenString string) (*model.Session, *model.AppError) {
   471  	token, nErr := a.Srv().Store.UserAccessToken().GetByToken(tokenString)
   472  	if nErr != nil {
   473  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, nErr.Error(), http.StatusUnauthorized)
   474  	}
   475  
   476  	if !token.IsActive {
   477  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_token", http.StatusUnauthorized)
   478  	}
   479  
   480  	user, nErr := a.Srv().Store.User().Get(context.Background(), token.UserId)
   481  	if nErr != nil {
   482  		var nfErr *store.ErrNotFound
   483  		switch {
   484  		case errors.As(nErr, &nfErr):
   485  			return nil, model.NewAppError("createSessionForUserAccessToken", MissingAccountError, nil, nfErr.Error(), http.StatusNotFound)
   486  		default:
   487  			return nil, model.NewAppError("createSessionForUserAccessToken", "app.user.get.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   488  		}
   489  	}
   490  
   491  	if !*a.Config().ServiceSettings.EnableUserAccessTokens && !user.IsBot {
   492  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "EnableUserAccessTokens=false", http.StatusUnauthorized)
   493  	}
   494  
   495  	if user.DeleteAt != 0 {
   496  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_user_id="+user.Id, http.StatusUnauthorized)
   497  	}
   498  
   499  	session := &model.Session{
   500  		Token:   token.Token,
   501  		UserId:  user.Id,
   502  		Roles:   user.GetRawRoles(),
   503  		IsOAuth: false,
   504  	}
   505  
   506  	session.AddProp(model.SESSION_PROP_USER_ACCESS_TOKEN_ID, token.Id)
   507  	session.AddProp(model.SESSION_PROP_TYPE, model.SESSION_TYPE_USER_ACCESS_TOKEN)
   508  	if user.IsBot {
   509  		session.AddProp(model.SESSION_PROP_IS_BOT, model.SESSION_PROP_IS_BOT_VALUE)
   510  	}
   511  	if user.IsGuest() {
   512  		session.AddProp(model.SESSION_PROP_IS_GUEST, "true")
   513  	} else {
   514  		session.AddProp(model.SESSION_PROP_IS_GUEST, "false")
   515  	}
   516  	a.SetSessionExpireInDays(session, model.SESSION_USER_ACCESS_TOKEN_EXPIRY)
   517  
   518  	session, nErr = a.Srv().Store.Session().Save(session)
   519  	if nErr != nil {
   520  		var invErr *store.ErrInvalidInput
   521  		switch {
   522  		case errors.As(nErr, &invErr):
   523  			return nil, model.NewAppError("CreateSession", "app.session.save.existing.app_error", nil, invErr.Error(), http.StatusBadRequest)
   524  		default:
   525  			return nil, model.NewAppError("CreateSession", "app.session.save.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   526  		}
   527  	}
   528  
   529  	a.AddSessionToCache(session)
   530  
   531  	return session, nil
   532  
   533  }
   534  
   535  func (a *App) RevokeUserAccessToken(token *model.UserAccessToken) *model.AppError {
   536  	var session *model.Session
   537  	session, _ = a.Srv().Store.Session().Get(token.Token)
   538  
   539  	if err := a.Srv().Store.UserAccessToken().Delete(token.Id); err != nil {
   540  		return model.NewAppError("RevokeUserAccessToken", "app.user_access_token.delete.app_error", nil, err.Error(), http.StatusInternalServerError)
   541  	}
   542  
   543  	if session == nil {
   544  		return nil
   545  	}
   546  
   547  	return a.RevokeSession(session)
   548  }
   549  
   550  func (a *App) DisableUserAccessToken(token *model.UserAccessToken) *model.AppError {
   551  	var session *model.Session
   552  	session, _ = a.Srv().Store.Session().Get(token.Token)
   553  
   554  	if err := a.Srv().Store.UserAccessToken().UpdateTokenDisable(token.Id); err != nil {
   555  		return model.NewAppError("DisableUserAccessToken", "app.user_access_token.update_token_disable.app_error", nil, err.Error(), http.StatusInternalServerError)
   556  	}
   557  
   558  	if session == nil {
   559  		return nil
   560  	}
   561  
   562  	return a.RevokeSession(session)
   563  }
   564  
   565  func (a *App) EnableUserAccessToken(token *model.UserAccessToken) *model.AppError {
   566  	var session *model.Session
   567  	session, _ = a.Srv().Store.Session().Get(token.Token)
   568  
   569  	err := a.Srv().Store.UserAccessToken().UpdateTokenEnable(token.Id)
   570  	if err != nil {
   571  		return model.NewAppError("EnableUserAccessToken", "app.user_access_token.update_token_enable.app_error", nil, err.Error(), http.StatusInternalServerError)
   572  	}
   573  
   574  	if session == nil {
   575  		return nil
   576  	}
   577  
   578  	return nil
   579  }
   580  
   581  func (a *App) GetUserAccessTokens(page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
   582  	tokens, err := a.Srv().Store.UserAccessToken().GetAll(page*perPage, perPage)
   583  	if err != nil {
   584  		return nil, model.NewAppError("GetUserAccessTokens", "app.user_access_token.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
   585  	}
   586  
   587  	for _, token := range tokens {
   588  		token.Token = ""
   589  	}
   590  
   591  	return tokens, nil
   592  }
   593  
   594  func (a *App) GetUserAccessTokensForUser(userID string, page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
   595  	tokens, err := a.Srv().Store.UserAccessToken().GetByUser(userID, page*perPage, perPage)
   596  	if err != nil {
   597  		return nil, model.NewAppError("GetUserAccessTokensForUser", "app.user_access_token.get_by_user.app_error", nil, err.Error(), http.StatusInternalServerError)
   598  	}
   599  	for _, token := range tokens {
   600  		token.Token = ""
   601  	}
   602  
   603  	return tokens, nil
   604  
   605  }
   606  
   607  func (a *App) GetUserAccessToken(tokenID string, sanitize bool) (*model.UserAccessToken, *model.AppError) {
   608  	token, err := a.Srv().Store.UserAccessToken().Get(tokenID)
   609  	if err != nil {
   610  		var nfErr *store.ErrNotFound
   611  		switch {
   612  		case errors.As(err, &nfErr):
   613  			return nil, model.NewAppError("GetUserAccessToken", "app.user_access_token.get_by_user.app_error", nil, nfErr.Error(), http.StatusNotFound)
   614  		default:
   615  			return nil, model.NewAppError("GetUserAccessToken", "app.user_access_token.get_by_user.app_error", nil, err.Error(), http.StatusInternalServerError)
   616  		}
   617  	}
   618  
   619  	if sanitize {
   620  		token.Token = ""
   621  	}
   622  	return token, nil
   623  }
   624  
   625  func (a *App) SearchUserAccessTokens(term string) ([]*model.UserAccessToken, *model.AppError) {
   626  	tokens, err := a.Srv().Store.UserAccessToken().Search(term)
   627  	if err != nil {
   628  		return nil, model.NewAppError("SearchUserAccessTokens", "app.user_access_token.search.app_error", nil, err.Error(), http.StatusInternalServerError)
   629  	}
   630  	for _, token := range tokens {
   631  		token.Token = ""
   632  	}
   633  	return tokens, nil
   634  }