1// Copyright 2020 The Gitea Authors. All rights reserved. 2// Use of this source code is governed by a MIT-style 3// license that can be found in the LICENSE file. 4 5package auth 6 7import ( 8 "fmt" 9 10 "code.gitea.io/gitea/models/db" 11 "code.gitea.io/gitea/modules/timeutil" 12) 13 14// Session represents a session compatible for go-chi session 15type Session struct { 16 Key string `xorm:"pk CHAR(16)"` // has to be Key to match with go-chi/session 17 Data []byte `xorm:"BLOB"` // on MySQL this has a maximum size of 64Kb - this may need to be increased 18 Expiry timeutil.TimeStamp // has to be Expiry to match with go-chi/session 19} 20 21func init() { 22 db.RegisterModel(new(Session)) 23} 24 25// UpdateSession updates the session with provided id 26func UpdateSession(key string, data []byte) error { 27 _, err := db.GetEngine(db.DefaultContext).ID(key).Update(&Session{ 28 Data: data, 29 Expiry: timeutil.TimeStampNow(), 30 }) 31 return err 32} 33 34// ReadSession reads the data for the provided session 35func ReadSession(key string) (*Session, error) { 36 session := Session{ 37 Key: key, 38 } 39 40 ctx, committer, err := db.TxContext() 41 if err != nil { 42 return nil, err 43 } 44 defer committer.Close() 45 46 if has, err := db.GetByBean(ctx, &session); err != nil { 47 return nil, err 48 } else if !has { 49 session.Expiry = timeutil.TimeStampNow() 50 if err := db.Insert(ctx, &session); err != nil { 51 return nil, err 52 } 53 } 54 55 return &session, committer.Commit() 56} 57 58// ExistSession checks if a session exists 59func ExistSession(key string) (bool, error) { 60 session := Session{ 61 Key: key, 62 } 63 return db.GetEngine(db.DefaultContext).Get(&session) 64} 65 66// DestroySession destroys a session 67func DestroySession(key string) error { 68 _, err := db.GetEngine(db.DefaultContext).Delete(&Session{ 69 Key: key, 70 }) 71 return err 72} 73 74// RegenerateSession regenerates a session from the old id 75func RegenerateSession(oldKey, newKey string) (*Session, error) { 76 ctx, committer, err := db.TxContext() 77 if err != nil { 78 return nil, err 79 } 80 defer committer.Close() 81 82 if has, err := db.GetByBean(ctx, &Session{ 83 Key: newKey, 84 }); err != nil { 85 return nil, err 86 } else if has { 87 return nil, fmt.Errorf("session Key: %s already exists", newKey) 88 } 89 90 if has, err := db.GetByBean(ctx, &Session{ 91 Key: oldKey, 92 }); err != nil { 93 return nil, err 94 } else if !has { 95 if err := db.Insert(ctx, &Session{ 96 Key: oldKey, 97 Expiry: timeutil.TimeStampNow(), 98 }); err != nil { 99 return nil, err 100 } 101 } 102 103 if _, err := db.Exec(ctx, "UPDATE "+db.TableName(&Session{})+" SET `key` = ? WHERE `key`=?", newKey, oldKey); err != nil { 104 return nil, err 105 } 106 107 s := Session{ 108 Key: newKey, 109 } 110 if _, err := db.GetByBean(ctx, &s); err != nil { 111 return nil, err 112 } 113 114 return &s, committer.Commit() 115} 116 117// CountSessions returns the number of sessions 118func CountSessions() (int64, error) { 119 return db.GetEngine(db.DefaultContext).Count(&Session{}) 120} 121 122// CleanupSessions cleans up expired sessions 123func CleanupSessions(maxLifetime int64) error { 124 _, err := db.GetEngine(db.DefaultContext).Where("expiry <= ?", timeutil.TimeStampNow().Add(-maxLifetime)).Delete(&Session{}) 125 return err 126} 127