2021-02-15 08:33:31 +03:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2021-02-15 08:33:31 +03:00
package session
import (
"log"
"sync"
2022-01-02 16:12:35 +03:00
"code.gitea.io/gitea/models/auth"
2021-02-15 08:33:31 +03:00
"code.gitea.io/gitea/modules/timeutil"
"gitea.com/go-chi/session"
)
// DBStore represents a session store implementation based on the DB.
type DBStore struct {
sid string
lock sync . RWMutex
2023-07-04 21:36:08 +03:00
data map [ any ] any
2021-02-15 08:33:31 +03:00
}
// NewDBStore creates and returns a DB session store.
2023-07-04 21:36:08 +03:00
func NewDBStore ( sid string , kv map [ any ] any ) * DBStore {
2021-02-15 08:33:31 +03:00
return & DBStore {
sid : sid ,
data : kv ,
}
}
// Set sets value to given key in session.
2023-07-04 21:36:08 +03:00
func ( s * DBStore ) Set ( key , val any ) error {
2021-02-15 08:33:31 +03:00
s . lock . Lock ( )
defer s . lock . Unlock ( )
s . data [ key ] = val
return nil
}
// Get gets value by given key in session.
2023-07-04 21:36:08 +03:00
func ( s * DBStore ) Get ( key any ) any {
2021-02-15 08:33:31 +03:00
s . lock . RLock ( )
defer s . lock . RUnlock ( )
return s . data [ key ]
}
// Delete delete a key from session.
2023-07-04 21:36:08 +03:00
func ( s * DBStore ) Delete ( key any ) error {
2021-02-15 08:33:31 +03:00
s . lock . Lock ( )
defer s . lock . Unlock ( )
delete ( s . data , key )
return nil
}
// ID returns current session ID.
func ( s * DBStore ) ID ( ) string {
return s . sid
}
// Release releases resource and save data to provider.
func ( s * DBStore ) Release ( ) error {
// Skip encoding if the data is empty
if len ( s . data ) == 0 {
return nil
}
data , err := session . EncodeGob ( s . data )
if err != nil {
return err
}
2022-01-02 16:12:35 +03:00
return auth . UpdateSession ( s . sid , data )
2021-02-15 08:33:31 +03:00
}
// Flush deletes all session data.
func ( s * DBStore ) Flush ( ) error {
s . lock . Lock ( )
defer s . lock . Unlock ( )
2023-07-04 21:36:08 +03:00
s . data = make ( map [ any ] any )
2021-02-15 08:33:31 +03:00
return nil
}
// DBProvider represents a DB session provider implementation.
type DBProvider struct {
maxLifetime int64
}
// Init initializes DB session provider.
// connStr: username:password@protocol(address)/dbname?param=value
func ( p * DBProvider ) Init ( maxLifetime int64 , connStr string ) error {
p . maxLifetime = maxLifetime
return nil
}
// Read returns raw session store by session ID.
func ( p * DBProvider ) Read ( sid string ) ( session . RawStore , error ) {
2022-01-02 16:12:35 +03:00
s , err := auth . ReadSession ( sid )
2021-02-15 08:33:31 +03:00
if err != nil {
return nil , err
}
2023-07-04 21:36:08 +03:00
var kv map [ any ] any
2021-02-15 08:33:31 +03:00
if len ( s . Data ) == 0 || s . Expiry . Add ( p . maxLifetime ) <= timeutil . TimeStampNow ( ) {
2023-07-04 21:36:08 +03:00
kv = make ( map [ any ] any )
2021-02-15 08:33:31 +03:00
} else {
kv , err = session . DecodeGob ( s . Data )
if err != nil {
return nil , err
}
}
return NewDBStore ( sid , kv ) , nil
}
// Exist returns true if session with given ID exists.
func ( p * DBProvider ) Exist ( sid string ) bool {
2022-01-02 16:12:35 +03:00
has , err := auth . ExistSession ( sid )
2021-02-15 08:33:31 +03:00
if err != nil {
panic ( "session/DB: error checking existence: " + err . Error ( ) )
}
return has
}
// Destroy deletes a session by session ID.
func ( p * DBProvider ) Destroy ( sid string ) error {
2022-01-02 16:12:35 +03:00
return auth . DestroySession ( sid )
2021-02-15 08:33:31 +03:00
}
// Regenerate regenerates a session store from old session ID to new one.
func ( p * DBProvider ) Regenerate ( oldsid , sid string ) ( _ session . RawStore , err error ) {
2022-01-02 16:12:35 +03:00
s , err := auth . RegenerateSession ( oldsid , sid )
2021-02-15 08:33:31 +03:00
if err != nil {
return nil , err
}
2023-07-04 21:36:08 +03:00
var kv map [ any ] any
2021-02-15 08:33:31 +03:00
if len ( s . Data ) == 0 || s . Expiry . Add ( p . maxLifetime ) <= timeutil . TimeStampNow ( ) {
2023-07-04 21:36:08 +03:00
kv = make ( map [ any ] any )
2021-02-15 08:33:31 +03:00
} else {
kv , err = session . DecodeGob ( s . Data )
if err != nil {
return nil , err
}
}
return NewDBStore ( sid , kv ) , nil
}
// Count counts and returns number of sessions.
func ( p * DBProvider ) Count ( ) int {
2022-01-02 16:12:35 +03:00
total , err := auth . CountSessions ( )
2021-02-15 08:33:31 +03:00
if err != nil {
panic ( "session/DB: error counting records: " + err . Error ( ) )
}
return int ( total )
}
// GC calls GC to clean expired sessions.
func ( p * DBProvider ) GC ( ) {
2022-01-02 16:12:35 +03:00
if err := auth . CleanupSessions ( p . maxLifetime ) ; err != nil {
2021-02-15 08:33:31 +03:00
log . Printf ( "session/DB: error garbage collecting: %v" , err )
}
}
func init ( ) {
session . Register ( "db" , & DBProvider { } )
}