2017-04-12 08:27:57 -04:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2015-06-14 23:53:32 -08:00
// See License.txt for license information.
2017-09-25 09:11:25 -05:00
package sqlstore
2015-06-14 23:53:32 -08:00
import (
2018-04-27 12:49:45 -07:00
"fmt"
2017-09-20 14:34:50 +01:00
"net/http"
2018-01-17 08:50:49 -05:00
"time"
2017-09-20 14:34:50 +01:00
2018-04-27 12:49:45 -07:00
"github.com/mattermost/mattermost-server/mlog"
2017-09-06 23:05:10 -07:00
"github.com/mattermost/mattermost-server/model"
2017-09-25 09:11:25 -05:00
"github.com/mattermost/mattermost-server/store"
2018-01-17 08:50:49 -05:00
)
const (
SESSIONS_CLEANUP_DELAY_MILLISECONDS = 100
2015-06-14 23:53:32 -08:00
)
type SqlSessionStore struct {
2017-06-27 08:02:08 -07:00
SqlStore
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func NewSqlSessionStore ( sqlStore SqlStore ) store . SessionStore {
2015-06-14 23:53:32 -08:00
us := & SqlSessionStore { sqlStore }
for _ , db := range sqlStore . GetAllConns ( ) {
table := db . AddTableWithName ( model . Session { } , "Sessions" ) . SetKeys ( false , "Id" )
table . ColMap ( "Id" ) . SetMaxSize ( 26 )
2015-09-16 15:49:12 -04:00
table . ColMap ( "Token" ) . SetMaxSize ( 26 )
2015-06-14 23:53:32 -08:00
table . ColMap ( "UserId" ) . SetMaxSize ( 26 )
2016-02-22 16:08:40 -08:00
table . ColMap ( "DeviceId" ) . SetMaxSize ( 512 )
2015-06-14 23:53:32 -08:00
table . ColMap ( "Roles" ) . SetMaxSize ( 64 )
table . ColMap ( "Props" ) . SetMaxSize ( 1000 )
}
return us
}
func ( me SqlSessionStore ) CreateIndexesIfNotExists ( ) {
2015-07-12 18:19:03 -08:00
me . CreateIndexIfNotExists ( "idx_sessions_user_id" , "Sessions" , "UserId" )
2015-09-16 15:49:12 -04:00
me . CreateIndexIfNotExists ( "idx_sessions_token" , "Sessions" , "Token" )
2016-10-24 17:05:27 -03:00
me . CreateIndexIfNotExists ( "idx_sessions_expires_at" , "Sessions" , "ExpiresAt" )
me . CreateIndexIfNotExists ( "idx_sessions_create_at" , "Sessions" , "CreateAt" )
me . CreateIndexIfNotExists ( "idx_sessions_last_activity_at" , "Sessions" , "LastActivityAt" )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) Save ( session * model . Session ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-06-14 23:53:32 -08:00
if len ( session . Id ) > 0 {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.Save" , "store.sql_session.save.existing.app_error" , nil , "id=" + session . Id , http . StatusBadRequest )
2015-06-14 23:53:32 -08:00
return
}
session . PreSave ( )
2016-04-21 22:37:01 -07:00
tcs := me . Team ( ) . GetTeamsForUser ( session . UserId )
2015-06-14 23:53:32 -08:00
if err := me . GetMaster ( ) . Insert ( session ) ; err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.Save" , "store.sql_session.save.app_error" , nil , "id=" + session . Id + ", " + err . Error ( ) , http . StatusInternalServerError )
2016-04-21 22:37:01 -07:00
return
2015-06-14 23:53:32 -08:00
} else {
result . Data = session
}
2016-04-21 22:37:01 -07:00
if rtcs := <- tcs ; rtcs . Err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.Save" , "store.sql_session.save.app_error" , nil , "id=" + session . Id + ", " + rtcs . Err . Error ( ) , http . StatusInternalServerError )
2016-04-21 22:37:01 -07:00
return
} else {
2016-07-06 13:40:59 -08:00
tempMembers := rtcs . Data . ( [ ] * model . TeamMember )
session . TeamMembers = make ( [ ] * model . TeamMember , 0 , len ( tempMembers ) )
for _ , tm := range tempMembers {
if tm . DeleteAt == 0 {
session . TeamMembers = append ( session . TeamMembers , tm )
}
}
2016-04-21 22:37:01 -07:00
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) Get ( sessionIdOrToken string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-09-16 15:49:12 -04:00
var sessions [ ] * model . Session
if _ , err := me . GetReplica ( ) . Select ( & sessions , "SELECT * FROM Sessions WHERE Token = :Token OR Id = :Id LIMIT 1" , map [ string ] interface { } { "Token" : sessionIdOrToken , "Id" : sessionIdOrToken } ) ; err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.Get" , "store.sql_session.get.app_error" , nil , "sessionIdOrToken=" + sessionIdOrToken + ", " + err . Error ( ) , http . StatusInternalServerError )
2017-10-30 11:57:24 -05:00
} else if len ( sessions ) == 0 {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.Get" , "store.sql_session.get.app_error" , nil , "sessionIdOrToken=" + sessionIdOrToken , http . StatusNotFound )
2015-06-14 23:53:32 -08:00
} else {
2015-09-16 15:49:12 -04:00
result . Data = sessions [ 0 ]
2016-04-21 22:37:01 -07:00
tcs := me . Team ( ) . GetTeamsForUser ( sessions [ 0 ] . UserId )
if rtcs := <- tcs ; rtcs . Err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.Get" , "store.sql_session.get.app_error" , nil , "sessionIdOrToken=" + sessionIdOrToken + ", " + rtcs . Err . Error ( ) , http . StatusInternalServerError )
2016-04-21 22:37:01 -07:00
return
} else {
2016-07-06 13:40:59 -08:00
tempMembers := rtcs . Data . ( [ ] * model . TeamMember )
sessions [ 0 ] . TeamMembers = make ( [ ] * model . TeamMember , 0 , len ( tempMembers ) )
for _ , tm := range tempMembers {
if tm . DeleteAt == 0 {
sessions [ 0 ] . TeamMembers = append ( sessions [ 0 ] . TeamMembers , tm )
}
}
2016-04-21 22:37:01 -07:00
}
2015-06-14 23:53:32 -08:00
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) GetSessions ( userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-06-14 23:53:32 -08:00
var sessions [ ] * model . Session
2016-04-21 22:37:01 -07:00
tcs := me . Team ( ) . GetTeamsForUser ( userId )
2015-07-12 18:19:03 -08:00
if _ , err := me . GetReplica ( ) . Select ( & sessions , "SELECT * FROM Sessions WHERE UserId = :UserId ORDER BY LastActivityAt DESC" , map [ string ] interface { } { "UserId" : userId } ) ; err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.GetSessions" , "store.sql_session.get_sessions.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
} else {
result . Data = sessions
}
2016-04-21 22:37:01 -07:00
if rtcs := <- tcs ; rtcs . Err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.GetSessions" , "store.sql_session.get_sessions.app_error" , nil , rtcs . Err . Error ( ) , http . StatusInternalServerError )
2016-04-21 22:37:01 -07:00
return
} else {
for _ , session := range sessions {
2016-07-06 13:40:59 -08:00
tempMembers := rtcs . Data . ( [ ] * model . TeamMember )
session . TeamMembers = make ( [ ] * model . TeamMember , 0 , len ( tempMembers ) )
for _ , tm := range tempMembers {
if tm . DeleteAt == 0 {
session . TeamMembers = append ( session . TeamMembers , tm )
}
}
2016-04-21 22:37:01 -07:00
}
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) GetSessionsWithActiveDeviceIds ( userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-10-24 17:04:11 -07:00
var sessions [ ] * model . Session
if _ , err := me . GetReplica ( ) . Select ( & sessions , "SELECT * FROM Sessions WHERE UserId = :UserId AND ExpiresAt != 0 AND :ExpiresAt <= ExpiresAt AND DeviceId != ''" , map [ string ] interface { } { "UserId" : userId , "ExpiresAt" : model . GetMillis ( ) } ) ; err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.GetActiveSessionsWithDeviceIds" , "store.sql_session.get_sessions.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-10-24 17:04:11 -07:00
} else {
result . Data = sessions
}
2017-10-06 08:12:10 -07:00
} )
2016-10-24 17:04:11 -07:00
}
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) Remove ( sessionIdOrToken string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-09-16 15:49:12 -04:00
_ , err := me . GetMaster ( ) . Exec ( "DELETE FROM Sessions WHERE Id = :Id Or Token = :Token" , map [ string ] interface { } { "Id" : sessionIdOrToken , "Token" : sessionIdOrToken } )
2015-06-14 23:53:32 -08:00
if err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.RemoveSession" , "store.sql_session.remove.app_error" , nil , "id=" + sessionIdOrToken + ", err=" + err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) RemoveAllSessions ( ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-04-21 22:37:01 -07:00
_ , err := me . GetMaster ( ) . Exec ( "DELETE FROM Sessions" )
2015-09-23 12:49:28 -07:00
if err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.RemoveAllSessions" , "store.sql_session.remove_all_sessions_for_team.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2015-09-23 12:49:28 -07:00
}
2017-10-06 08:12:10 -07:00
} )
2015-09-23 12:49:28 -07:00
}
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) PermanentDeleteSessionsByUser ( userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-11-15 18:18:02 -08:00
_ , err := me . GetMaster ( ) . Exec ( "DELETE FROM Sessions WHERE UserId = :UserId" , map [ string ] interface { } { "UserId" : userId } )
if err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.RemoveAllSessionsForUser" , "store.sql_session.permanent_delete_sessions_by_user.app_error" , nil , "id=" + userId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
2015-11-15 18:18:02 -08:00
}
2017-10-06 08:12:10 -07:00
} )
2015-11-15 18:18:02 -08:00
}
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) UpdateLastActivityAt ( sessionId string , time int64 ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-07-12 18:19:03 -08:00
if _ , err := me . GetMaster ( ) . Exec ( "UPDATE Sessions SET LastActivityAt = :LastActivityAt WHERE Id = :Id" , map [ string ] interface { } { "LastActivityAt" : time , "Id" : sessionId } ) ; err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.UpdateLastActivityAt" , "store.sql_session.update_last_activity.app_error" , nil , "sessionId=" + sessionId , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
} else {
result . Data = sessionId
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2015-08-17 09:28:20 -04:00
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) UpdateRoles ( userId , roles string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-08-17 09:28:20 -04:00
if _ , err := me . GetMaster ( ) . Exec ( "UPDATE Sessions SET Roles = :Roles WHERE UserId = :UserId" , map [ string ] interface { } { "Roles" : roles , "UserId" : userId } ) ; err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.UpdateRoles" , "store.sql_session.update_roles.app_error" , nil , "userId=" + userId , http . StatusInternalServerError )
2015-08-17 09:28:20 -04:00
} else {
result . Data = userId
}
2017-10-06 08:12:10 -07:00
} )
2015-08-17 09:28:20 -04:00
}
2016-01-26 20:32:24 -05:00
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) UpdateDeviceId ( id string , deviceId string , expiresAt int64 ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-07-21 08:36:11 -08:00
if _ , err := me . GetMaster ( ) . Exec ( "UPDATE Sessions SET DeviceId = :DeviceId, ExpiresAt = :ExpiresAt WHERE Id = :Id" , map [ string ] interface { } { "DeviceId" : deviceId , "Id" : id , "ExpiresAt" : expiresAt } ) ; err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.UpdateDeviceId" , "store.sql_session.update_device_id.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-01-26 20:32:24 -05:00
} else {
result . Data = deviceId
}
2017-10-06 08:12:10 -07:00
} )
2016-01-26 20:32:24 -05:00
}
2016-02-25 12:32:46 -05:00
2017-09-25 09:11:25 -05:00
func ( me SqlSessionStore ) AnalyticsSessionCount ( ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-02-25 12:32:46 -05:00
query :=
` SELECT
COUNT ( * )
FROM
2016-02-26 11:27:45 -05:00
Sessions
WHERE ExpiresAt > : Time `
2016-02-25 12:32:46 -05:00
2016-04-21 22:37:01 -07:00
if c , err := me . GetReplica ( ) . SelectInt ( query , map [ string ] interface { } { "Time" : model . GetMillis ( ) } ) ; err != nil {
2017-09-20 14:34:50 +01:00
result . Err = model . NewAppError ( "SqlSessionStore.AnalyticsSessionCount" , "store.sql_session.analytics_session_count.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2016-02-25 12:32:46 -05:00
} else {
result . Data = c
}
2017-10-06 08:12:10 -07:00
} )
2016-02-25 12:32:46 -05:00
}
2018-01-17 08:50:49 -05:00
func ( me SqlSessionStore ) Cleanup ( expiryTime int64 , batchSize int64 ) {
2018-04-27 12:49:45 -07:00
mlog . Debug ( "Cleaning up session store." )
2018-01-17 08:50:49 -05:00
var query string
if me . DriverName ( ) == model . DATABASE_DRIVER_POSTGRES {
query = "DELETE FROM Sessions WHERE Id = any (array (SELECT Id FROM Sessions WHERE ExpiresAt != 0 AND :ExpiresAt > ExpiresAt LIMIT :Limit))"
} else {
query = "DELETE FROM Sessions WHERE ExpiresAt != 0 AND :ExpiresAt > ExpiresAt LIMIT :Limit"
}
var rowsAffected int64 = 1
for rowsAffected > 0 {
if sqlResult , err := me . GetMaster ( ) . Exec ( query , map [ string ] interface { } { "ExpiresAt" : expiryTime , "Limit" : batchSize } ) ; err != nil {
2018-04-27 12:49:45 -07:00
mlog . Error ( fmt . Sprintf ( "Unable to cleanup session store. err=%v" , err . Error ( ) ) )
2018-01-17 08:50:49 -05:00
return
} else {
var rowErr error
rowsAffected , rowErr = sqlResult . RowsAffected ( )
if rowErr != nil {
2018-04-27 12:49:45 -07:00
mlog . Error ( fmt . Sprintf ( "Unable to cleanup session store. err=%v" , err . Error ( ) ) )
2018-01-17 08:50:49 -05:00
return
}
}
time . Sleep ( SESSIONS_CLEANUP_DELAY_MILLISECONDS * time . Millisecond )
}
}