github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/store/sqlstore/session_store.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "net/http" 8 "time" 9 10 "github.com/vnforks/kid/v5/mlog" 11 "github.com/vnforks/kid/v5/model" 12 "github.com/vnforks/kid/v5/store" 13 ) 14 15 const ( 16 SESSIONS_CLEANUP_DELAY_MILLISECONDS = 100 17 ) 18 19 type SqlSessionStore struct { 20 SqlStore 21 } 22 23 func newSqlSessionStore(sqlStore SqlStore) store.SessionStore { 24 us := &SqlSessionStore{sqlStore} 25 26 for _, db := range sqlStore.GetAllConns() { 27 table := db.AddTableWithName(model.Session{}, "Sessions").SetKeys(false, "Id") 28 table.ColMap("Id").SetMaxSize(26) 29 table.ColMap("Token").SetMaxSize(26) 30 table.ColMap("UserId").SetMaxSize(26) 31 table.ColMap("DeviceId").SetMaxSize(512) 32 table.ColMap("Roles").SetMaxSize(64) 33 table.ColMap("Props").SetMaxSize(1000) 34 } 35 36 return us 37 } 38 39 func (me SqlSessionStore) createIndexesIfNotExists() { 40 me.CreateIndexIfNotExists("idx_sessions_user_id", "Sessions", "UserId") 41 me.CreateIndexIfNotExists("idx_sessions_token", "Sessions", "Token") 42 me.CreateIndexIfNotExists("idx_sessions_expires_at", "Sessions", "ExpiresAt") 43 me.CreateIndexIfNotExists("idx_sessions_create_at", "Sessions", "CreateAt") 44 me.CreateIndexIfNotExists("idx_sessions_last_activity_at", "Sessions", "LastActivityAt") 45 } 46 47 func (me SqlSessionStore) Save(session *model.Session) (*model.Session, *model.AppError) { 48 if len(session.Id) > 0 { 49 return nil, model.NewAppError("SqlSessionStore.Save", "store.sql_session.save.existing.app_error", nil, "id="+session.Id, http.StatusBadRequest) 50 } 51 session.PreSave() 52 53 if err := me.GetMaster().Insert(session); err != nil { 54 return nil, model.NewAppError("SqlSessionStore.Save", "store.sql_session.save.app_error", nil, "id="+session.Id+", "+err.Error(), http.StatusInternalServerError) 55 } 56 57 branchMembers, err := me.Branch().GetBranchesForUser(session.UserId) 58 if err != nil { 59 return nil, model.NewAppError("SqlSessionStore.Save", "store.sql_session.save.app_error", nil, "id="+session.Id+", "+err.Error(), http.StatusInternalServerError) 60 } 61 62 session.BranchMembers = make([]*model.BranchMember, 0, len(branchMembers)) 63 for _, tm := range branchMembers { 64 if tm.DeleteAt == 0 { 65 session.BranchMembers = append(session.BranchMembers, tm) 66 } 67 } 68 69 return session, nil 70 } 71 72 func (me SqlSessionStore) Get(sessionIdOrToken string) (*model.Session, *model.AppError) { 73 var sessions []*model.Session 74 75 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 { 76 return nil, model.NewAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken+", "+err.Error(), http.StatusInternalServerError) 77 } else if len(sessions) == 0 { 78 return nil, model.NewAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken, http.StatusNotFound) 79 } 80 session := sessions[0] 81 82 tempMembers, err := me.Branch().GetBranchesForUser(sessions[0].UserId) 83 if err != nil { 84 return nil, model.NewAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken+", "+err.Error(), http.StatusInternalServerError) 85 } 86 sessions[0].BranchMembers = make([]*model.BranchMember, 0, len(tempMembers)) 87 for _, tm := range tempMembers { 88 if tm.DeleteAt == 0 { 89 sessions[0].BranchMembers = append(sessions[0].BranchMembers, tm) 90 } 91 } 92 return session, nil 93 } 94 95 func (me SqlSessionStore) GetSessions(userId string) ([]*model.Session, *model.AppError) { 96 var sessions []*model.Session 97 98 if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE UserId = :UserId ORDER BY LastActivityAt DESC", map[string]interface{}{"UserId": userId}); err != nil { 99 return nil, model.NewAppError("SqlSessionStore.GetSessions", "store.sql_session.get_sessions.app_error", nil, err.Error(), http.StatusInternalServerError) 100 } 101 102 branchMembers, err := me.Branch().GetBranchesForUser(userId) 103 if err != nil { 104 return nil, model.NewAppError("SqlSessionStore.GetSessions", "store.sql_session.get_sessions.app_error", nil, err.Error(), http.StatusInternalServerError) 105 } 106 107 for _, session := range sessions { 108 session.BranchMembers = make([]*model.BranchMember, 0, len(branchMembers)) 109 for _, tm := range branchMembers { 110 if tm.DeleteAt == 0 { 111 session.BranchMembers = append(session.BranchMembers, tm) 112 } 113 } 114 } 115 return sessions, nil 116 } 117 118 func (me SqlSessionStore) GetSessionsWithActiveDeviceIds(userId string) ([]*model.Session, *model.AppError) { 119 query := 120 `SELECT * 121 FROM 122 Sessions 123 WHERE 124 UserId = :UserId AND 125 ExpiresAt != 0 AND 126 :ExpiresAt <= ExpiresAt AND 127 DeviceId != ''` 128 129 var sessions []*model.Session 130 131 _, err := me.GetReplica().Select(&sessions, query, map[string]interface{}{"UserId": userId, "ExpiresAt": model.GetMillis()}) 132 if err != nil { 133 return nil, model.NewAppError("SqlSessionStore.GetActiveSessionsWithDeviceIds", "store.sql_session.get_sessions.app_error", nil, err.Error(), http.StatusInternalServerError) 134 } 135 return sessions, nil 136 } 137 138 func (me SqlSessionStore) Remove(sessionIdOrToken string) *model.AppError { 139 _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE Id = :Id Or Token = :Token", map[string]interface{}{"Id": sessionIdOrToken, "Token": sessionIdOrToken}) 140 if err != nil { 141 return model.NewAppError("SqlSessionStore.RemoveSession", "store.sql_session.remove.app_error", nil, "id="+sessionIdOrToken+", err="+err.Error(), http.StatusInternalServerError) 142 } 143 return nil 144 } 145 146 func (me SqlSessionStore) RemoveAllSessions() *model.AppError { 147 _, err := me.GetMaster().Exec("DELETE FROM Sessions") 148 if err != nil { 149 return model.NewAppError("SqlSessionStore.RemoveAllSessions", "store.sql_session.remove_all_sessions_for_branch.app_error", nil, err.Error(), http.StatusInternalServerError) 150 } 151 return nil 152 } 153 154 func (me SqlSessionStore) PermanentDeleteSessionsByUser(userId string) *model.AppError { 155 _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}) 156 if err != nil { 157 return model.NewAppError("SqlSessionStore.RemoveAllSessionsForUser", "store.sql_session.permanent_delete_sessions_by_user.app_error", nil, "id="+userId+", err="+err.Error(), http.StatusInternalServerError) 158 } 159 160 return nil 161 } 162 163 func (me SqlSessionStore) UpdateLastActivityAt(sessionId string, time int64) *model.AppError { 164 _, err := me.GetMaster().Exec("UPDATE Sessions SET LastActivityAt = :LastActivityAt WHERE Id = :Id", map[string]interface{}{"LastActivityAt": time, "Id": sessionId}) 165 if err != nil { 166 return model.NewAppError("SqlSessionStore.UpdateLastActivityAt", "store.sql_session.update_last_activity.app_error", nil, "sessionId="+sessionId, http.StatusInternalServerError) 167 } 168 return nil 169 } 170 171 func (me SqlSessionStore) UpdateRoles(userId, roles string) (string, *model.AppError) { 172 query := "UPDATE Sessions SET Roles = :Roles WHERE UserId = :UserId" 173 174 _, err := me.GetMaster().Exec(query, map[string]interface{}{"Roles": roles, "UserId": userId}) 175 if err != nil { 176 return "", model.NewAppError("SqlSessionStore.UpdateRoles", "store.sql_session.update_roles.app_error", nil, "userId="+userId, http.StatusInternalServerError) 177 } 178 return userId, nil 179 } 180 181 func (me SqlSessionStore) UpdateDeviceId(id string, deviceId string, expiresAt int64) (string, *model.AppError) { 182 query := "UPDATE Sessions SET DeviceId = :DeviceId, ExpiresAt = :ExpiresAt WHERE Id = :Id" 183 184 _, err := me.GetMaster().Exec(query, map[string]interface{}{"DeviceId": deviceId, "Id": id, "ExpiresAt": expiresAt}) 185 if err != nil { 186 return "", model.NewAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, err.Error(), http.StatusInternalServerError) 187 } 188 return deviceId, nil 189 } 190 191 func (me SqlSessionStore) UpdateProps(session *model.Session) *model.AppError { 192 oldSession, appErr := me.Get(session.Id) 193 if appErr != nil { 194 return appErr 195 } 196 oldSession.Props = session.Props 197 198 count, err := me.GetMaster().Update(oldSession) 199 if err != nil { 200 return model.NewAppError("SqlSessionStore.UpdateProps", "store.sql_session.update_props.app_error", nil, err.Error(), http.StatusInternalServerError) 201 } 202 if count != 1 { 203 return model.NewAppError("SqlSessionStore.UpdateProps", "store.sql_session.update_props.app_error", nil, "", http.StatusInternalServerError) 204 } 205 return nil 206 } 207 208 func (me SqlSessionStore) AnalyticsSessionCount() (int64, *model.AppError) { 209 query := 210 `SELECT 211 COUNT(*) 212 FROM 213 Sessions 214 WHERE ExpiresAt > :Time` 215 count, err := me.GetReplica().SelectInt(query, map[string]interface{}{"Time": model.GetMillis()}) 216 if err != nil { 217 return int64(0), model.NewAppError("SqlSessionStore.AnalyticsSessionCount", "store.sql_session.analytics_session_count.app_error", nil, err.Error(), http.StatusInternalServerError) 218 } 219 return count, nil 220 } 221 222 func (me SqlSessionStore) Cleanup(expiryTime int64, batchSize int64) { 223 mlog.Debug("Cleaning up session store.") 224 225 var query string 226 if me.DriverName() == model.DATABASE_DRIVER_POSTGRES { 227 query = "DELETE FROM Sessions WHERE Id = any (array (SELECT Id FROM Sessions WHERE ExpiresAt != 0 AND :ExpiresAt > ExpiresAt LIMIT :Limit))" 228 } else { 229 query = "DELETE FROM Sessions WHERE ExpiresAt != 0 AND :ExpiresAt > ExpiresAt LIMIT :Limit" 230 } 231 232 var rowsAffected int64 = 1 233 234 for rowsAffected > 0 { 235 if sqlResult, err := me.GetMaster().Exec(query, map[string]interface{}{"ExpiresAt": expiryTime, "Limit": batchSize}); err != nil { 236 mlog.Error("Unable to cleanup session store.", mlog.Err(err)) 237 return 238 } else { 239 var rowErr error 240 rowsAffected, rowErr = sqlResult.RowsAffected() 241 if rowErr != nil { 242 mlog.Error("Unable to cleanup session store.", mlog.Err(err)) 243 return 244 } 245 } 246 247 time.Sleep(SESSIONS_CLEANUP_DELAY_MILLISECONDS * time.Millisecond) 248 } 249 }