github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/app/session.go (about)

     1  // Copyright (c) 2016-present Xenia, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  
    10  	"github.com/xzl8028/xenia-server/mlog"
    11  	"github.com/xzl8028/xenia-server/model"
    12  )
    13  
    14  func (a *App) CreateSession(session *model.Session) (*model.Session, *model.AppError) {
    15  	session.Token = ""
    16  
    17  	session, err := a.Srv.Store.Session().Save(session)
    18  	if err != nil {
    19  		return nil, err
    20  	}
    21  
    22  	a.AddSessionToCache(session)
    23  
    24  	return session, nil
    25  }
    26  
    27  func (a *App) GetSession(token string) (*model.Session, *model.AppError) {
    28  	metrics := a.Metrics
    29  
    30  	var session *model.Session
    31  	var err *model.AppError
    32  	if ts, ok := a.Srv.sessionCache.Get(token); ok {
    33  		session = ts.(*model.Session)
    34  		if metrics != nil {
    35  			metrics.IncrementMemCacheHitCounterSession()
    36  		}
    37  	} else {
    38  		if metrics != nil {
    39  			metrics.IncrementMemCacheMissCounterSession()
    40  		}
    41  	}
    42  
    43  	if session == nil {
    44  		if session, err = a.Srv.Store.Session().Get(token); err == nil {
    45  			if session != nil {
    46  				if session.Token != token {
    47  					return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token, "Error": ""}, "", http.StatusUnauthorized)
    48  				}
    49  
    50  				if !session.IsExpired() {
    51  					a.AddSessionToCache(session)
    52  				}
    53  			}
    54  		} else if err.StatusCode == http.StatusInternalServerError {
    55  			return nil, err
    56  		}
    57  	}
    58  
    59  	if session == nil {
    60  		session, err = a.createSessionForUserAccessToken(token)
    61  		if err != nil {
    62  			detailedError := ""
    63  			statusCode := http.StatusUnauthorized
    64  			if err.Id != "app.user_access_token.invalid_or_missing" {
    65  				detailedError = err.Error()
    66  				statusCode = err.StatusCode
    67  			}
    68  			return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, detailedError, statusCode)
    69  		}
    70  	}
    71  
    72  	if session == nil || session.IsExpired() {
    73  		return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, "", http.StatusUnauthorized)
    74  	}
    75  
    76  	if session != nil &&
    77  		*a.Config().ServiceSettings.SessionIdleTimeoutInMinutes > 0 &&
    78  		!session.IsOAuth &&
    79  		session.Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_USER_ACCESS_TOKEN {
    80  
    81  		timeout := int64(*a.Config().ServiceSettings.SessionIdleTimeoutInMinutes) * 1000 * 60
    82  		if (model.GetMillis() - session.LastActivityAt) > timeout {
    83  			a.RevokeSessionById(session.Id)
    84  			return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, "idle timeout", http.StatusUnauthorized)
    85  		}
    86  	}
    87  
    88  	return session, nil
    89  }
    90  
    91  func (a *App) GetSessions(userId string) ([]*model.Session, *model.AppError) {
    92  
    93  	return a.Srv.Store.Session().GetSessions(userId)
    94  }
    95  
    96  func (a *App) RevokeAllSessions(userId string) *model.AppError {
    97  	sessions, err := a.Srv.Store.Session().GetSessions(userId)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	for _, session := range sessions {
   102  		if session.IsOAuth {
   103  			a.RevokeAccessToken(session.Token)
   104  		} else {
   105  			if err := a.Srv.Store.Session().Remove(session.Id); err != nil {
   106  				return err
   107  			}
   108  		}
   109  	}
   110  
   111  	a.ClearSessionCacheForUser(userId)
   112  
   113  	return nil
   114  }
   115  
   116  // RevokeSessionsFromAllUsers will go through all the sessions active
   117  // in the server and revoke them
   118  func (a *App) RevokeSessionsFromAllUsers() *model.AppError {
   119  	// revoke tokens before sessions so they can't be used to relogin
   120  	tErr := a.Srv.Store.OAuth().RemoveAllAccessData()
   121  	if tErr != nil {
   122  		return tErr
   123  	}
   124  	err := a.Srv.Store.Session().RemoveAllSessions()
   125  	if err != nil {
   126  		return err
   127  	}
   128  	a.ClearSessionCacheForAllUsers()
   129  
   130  	return nil
   131  }
   132  
   133  func (a *App) ClearSessionCacheForUser(userId string) {
   134  	a.ClearSessionCacheForUserSkipClusterSend(userId)
   135  
   136  	if a.Cluster != nil {
   137  		msg := &model.ClusterMessage{
   138  			Event:    model.CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER,
   139  			SendType: model.CLUSTER_SEND_RELIABLE,
   140  			Data:     userId,
   141  		}
   142  		a.Cluster.SendClusterMessage(msg)
   143  	}
   144  }
   145  
   146  func (a *App) ClearSessionCacheForAllUsers() {
   147  	a.ClearSessionCacheForAllUsersSkipClusterSend()
   148  
   149  	if a.Cluster != nil {
   150  		msg := &model.ClusterMessage{
   151  			Event:    model.CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_ALL_USERS,
   152  			SendType: model.CLUSTER_SEND_RELIABLE,
   153  		}
   154  		a.Cluster.SendClusterMessage(msg)
   155  	}
   156  }
   157  
   158  func (a *App) ClearSessionCacheForUserSkipClusterSend(userId string) {
   159  	keys := a.Srv.sessionCache.Keys()
   160  
   161  	for _, key := range keys {
   162  		if ts, ok := a.Srv.sessionCache.Get(key); ok {
   163  			session := ts.(*model.Session)
   164  			if session.UserId == userId {
   165  				a.Srv.sessionCache.Remove(key)
   166  				if a.Metrics != nil {
   167  					a.Metrics.IncrementMemCacheInvalidationCounterSession()
   168  				}
   169  			}
   170  		}
   171  	}
   172  
   173  	a.InvalidateWebConnSessionCacheForUser(userId)
   174  }
   175  
   176  func (a *App) ClearSessionCacheForAllUsersSkipClusterSend() {
   177  	mlog.Info("Purging sessions cache")
   178  	a.Srv.sessionCache.Purge()
   179  }
   180  
   181  func (a *App) AddSessionToCache(session *model.Session) {
   182  	a.Srv.sessionCache.AddWithExpiresInSecs(session.Token, session, int64(*a.Config().ServiceSettings.SessionCacheInMinutes*60))
   183  }
   184  
   185  func (a *App) SessionCacheLength() int {
   186  	return a.Srv.sessionCache.Len()
   187  }
   188  
   189  func (a *App) RevokeSessionsForDeviceId(userId string, deviceId string, currentSessionId string) *model.AppError {
   190  	sessions, err := a.Srv.Store.Session().GetSessions(userId)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	for _, session := range sessions {
   195  		if session.DeviceId == deviceId && session.Id != currentSessionId {
   196  			mlog.Debug(fmt.Sprintf("Revoking sessionId=%v for userId=%v re-login with same device Id", session.Id, userId), mlog.String("user_id", userId))
   197  			if err := a.RevokeSession(session); err != nil {
   198  				// Soft error so we still remove the other sessions
   199  				mlog.Error(err.Error())
   200  			}
   201  		}
   202  	}
   203  
   204  	return nil
   205  }
   206  
   207  func (a *App) GetSessionById(sessionId string) (*model.Session, *model.AppError) {
   208  	session, err := a.Srv.Store.Session().Get(sessionId)
   209  	if err != nil {
   210  		err.StatusCode = http.StatusBadRequest
   211  		return nil, err
   212  	}
   213  	return session, nil
   214  }
   215  
   216  func (a *App) RevokeSessionById(sessionId string) *model.AppError {
   217  	session, err := a.Srv.Store.Session().Get(sessionId)
   218  	if err != nil {
   219  		err.StatusCode = http.StatusBadRequest
   220  		return err
   221  	}
   222  	return a.RevokeSession(session)
   223  
   224  }
   225  
   226  func (a *App) RevokeSession(session *model.Session) *model.AppError {
   227  	if session.IsOAuth {
   228  		if err := a.RevokeAccessToken(session.Token); err != nil {
   229  			return err
   230  		}
   231  	} else {
   232  		if err := a.Srv.Store.Session().Remove(session.Id); err != nil {
   233  			return err
   234  		}
   235  	}
   236  
   237  	a.ClearSessionCacheForUser(session.UserId)
   238  
   239  	return nil
   240  }
   241  
   242  func (a *App) AttachDeviceId(sessionId string, deviceId string, expiresAt int64) *model.AppError {
   243  	_, err := a.Srv.Store.Session().UpdateDeviceId(sessionId, deviceId, expiresAt)
   244  	if err != nil {
   245  		return err
   246  	}
   247  
   248  	return nil
   249  }
   250  
   251  func (a *App) UpdateLastActivityAtIfNeeded(session model.Session) {
   252  	now := model.GetMillis()
   253  
   254  	a.UpdateWebConnUserActivity(session, now)
   255  
   256  	if now-session.LastActivityAt < model.SESSION_ACTIVITY_TIMEOUT {
   257  		return
   258  	}
   259  
   260  	if err := a.Srv.Store.Session().UpdateLastActivityAt(session.Id, now); err != nil {
   261  		mlog.Error(fmt.Sprintf("Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v", session.UserId, session.Id, err), mlog.String("user_id", session.UserId))
   262  	}
   263  
   264  	session.LastActivityAt = now
   265  	a.AddSessionToCache(&session)
   266  }
   267  
   268  func (a *App) CreateUserAccessToken(token *model.UserAccessToken) (*model.UserAccessToken, *model.AppError) {
   269  
   270  	user, err := a.Srv.Store.User().Get(token.UserId)
   271  	if err != nil {
   272  		return nil, err
   273  	}
   274  
   275  	if !*a.Config().ServiceSettings.EnableUserAccessTokens && !user.IsBot {
   276  		return nil, model.NewAppError("CreateUserAccessToken", "app.user_access_token.disabled", nil, "", http.StatusNotImplemented)
   277  	}
   278  
   279  	token.Token = model.NewId()
   280  
   281  	token, err = a.Srv.Store.UserAccessToken().Save(token)
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  
   286  	// Don't send emails to bot users.
   287  	if !user.IsBot {
   288  		if err := a.SendUserAccessTokenAddedEmail(user.Email, user.Locale, a.GetSiteURL()); err != nil {
   289  			a.Log.Error("Unable to send user access token added email", mlog.Err(err), mlog.String("user_id", user.Id))
   290  		}
   291  	}
   292  
   293  	return token, nil
   294  
   295  }
   296  
   297  func (a *App) createSessionForUserAccessToken(tokenString string) (*model.Session, *model.AppError) {
   298  	token, err := a.Srv.Store.UserAccessToken().GetByToken(tokenString)
   299  	if err != nil {
   300  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, err.Error(), http.StatusUnauthorized)
   301  	}
   302  
   303  	if !token.IsActive {
   304  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_token", http.StatusUnauthorized)
   305  	}
   306  
   307  	user, err := a.Srv.Store.User().Get(token.UserId)
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  
   312  	if !*a.Config().ServiceSettings.EnableUserAccessTokens && !user.IsBot {
   313  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "EnableUserAccessTokens=false", http.StatusUnauthorized)
   314  	}
   315  
   316  	if user.DeleteAt != 0 {
   317  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_user_id="+user.Id, http.StatusUnauthorized)
   318  	}
   319  
   320  	session := &model.Session{
   321  		Token:   token.Token,
   322  		UserId:  user.Id,
   323  		Roles:   user.GetRawRoles(),
   324  		IsOAuth: false,
   325  	}
   326  
   327  	session.AddProp(model.SESSION_PROP_USER_ACCESS_TOKEN_ID, token.Id)
   328  	session.AddProp(model.SESSION_PROP_TYPE, model.SESSION_TYPE_USER_ACCESS_TOKEN)
   329  	if user.IsBot {
   330  		session.AddProp(model.SESSION_PROP_IS_BOT, model.SESSION_PROP_IS_BOT_VALUE)
   331  	}
   332  	session.SetExpireInDays(model.SESSION_USER_ACCESS_TOKEN_EXPIRY)
   333  
   334  	session, err = a.Srv.Store.Session().Save(session)
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  
   339  	a.AddSessionToCache(session)
   340  
   341  	return session, nil
   342  
   343  }
   344  
   345  func (a *App) RevokeUserAccessToken(token *model.UserAccessToken) *model.AppError {
   346  	var session *model.Session
   347  	session, _ = a.Srv.Store.Session().Get(token.Token)
   348  
   349  	if err := a.Srv.Store.UserAccessToken().Delete(token.Id); err != nil {
   350  		return err
   351  	}
   352  
   353  	if session == nil {
   354  		return nil
   355  	}
   356  
   357  	return a.RevokeSession(session)
   358  }
   359  
   360  func (a *App) DisableUserAccessToken(token *model.UserAccessToken) *model.AppError {
   361  	var session *model.Session
   362  	session, _ = a.Srv.Store.Session().Get(token.Token)
   363  
   364  	if err := a.Srv.Store.UserAccessToken().UpdateTokenDisable(token.Id); err != nil {
   365  		return err
   366  	}
   367  
   368  	if session == nil {
   369  		return nil
   370  	}
   371  
   372  	return a.RevokeSession(session)
   373  }
   374  
   375  func (a *App) EnableUserAccessToken(token *model.UserAccessToken) *model.AppError {
   376  	var session *model.Session
   377  	session, _ = a.Srv.Store.Session().Get(token.Token)
   378  
   379  	err := a.Srv.Store.UserAccessToken().UpdateTokenEnable(token.Id)
   380  	if err != nil {
   381  		return err
   382  	}
   383  
   384  	if session == nil {
   385  		return nil
   386  	}
   387  
   388  	return nil
   389  }
   390  
   391  func (a *App) GetUserAccessTokens(page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
   392  	tokens, err := a.Srv.Store.UserAccessToken().GetAll(page*perPage, perPage)
   393  	if err != nil {
   394  		return nil, err
   395  	}
   396  
   397  	for _, token := range tokens {
   398  		token.Token = ""
   399  	}
   400  
   401  	return tokens, nil
   402  }
   403  
   404  func (a *App) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
   405  	tokens, err := a.Srv.Store.UserAccessToken().GetByUser(userId, page*perPage, perPage)
   406  	if err != nil {
   407  		return nil, err
   408  	}
   409  	for _, token := range tokens {
   410  		token.Token = ""
   411  	}
   412  
   413  	return tokens, nil
   414  
   415  }
   416  
   417  func (a *App) GetUserAccessToken(tokenId string, sanitize bool) (*model.UserAccessToken, *model.AppError) {
   418  	token, err := a.Srv.Store.UserAccessToken().Get(tokenId)
   419  	if err != nil {
   420  		return nil, err
   421  	}
   422  
   423  	if sanitize {
   424  		token.Token = ""
   425  	}
   426  	return token, nil
   427  }
   428  
   429  func (a *App) SearchUserAccessTokens(term string) ([]*model.UserAccessToken, *model.AppError) {
   430  	tokens, err := a.Srv.Store.UserAccessToken().Search(term)
   431  	if err != nil {
   432  		return nil, err
   433  	}
   434  	for _, token := range tokens {
   435  		token.Token = ""
   436  	}
   437  	return tokens, nil
   438  }