code.gitea.io/gitea@v1.19.3/modules/session/db.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package session
     5  
     6  import (
     7  	"log"
     8  	"sync"
     9  
    10  	"code.gitea.io/gitea/models/auth"
    11  	"code.gitea.io/gitea/modules/timeutil"
    12  
    13  	"gitea.com/go-chi/session"
    14  )
    15  
    16  // DBStore represents a session store implementation based on the DB.
    17  type DBStore struct {
    18  	sid  string
    19  	lock sync.RWMutex
    20  	data map[interface{}]interface{}
    21  }
    22  
    23  // NewDBStore creates and returns a DB session store.
    24  func NewDBStore(sid string, kv map[interface{}]interface{}) *DBStore {
    25  	return &DBStore{
    26  		sid:  sid,
    27  		data: kv,
    28  	}
    29  }
    30  
    31  // Set sets value to given key in session.
    32  func (s *DBStore) Set(key, val interface{}) error {
    33  	s.lock.Lock()
    34  	defer s.lock.Unlock()
    35  
    36  	s.data[key] = val
    37  	return nil
    38  }
    39  
    40  // Get gets value by given key in session.
    41  func (s *DBStore) Get(key interface{}) interface{} {
    42  	s.lock.RLock()
    43  	defer s.lock.RUnlock()
    44  
    45  	return s.data[key]
    46  }
    47  
    48  // Delete delete a key from session.
    49  func (s *DBStore) Delete(key interface{}) error {
    50  	s.lock.Lock()
    51  	defer s.lock.Unlock()
    52  
    53  	delete(s.data, key)
    54  	return nil
    55  }
    56  
    57  // ID returns current session ID.
    58  func (s *DBStore) ID() string {
    59  	return s.sid
    60  }
    61  
    62  // Release releases resource and save data to provider.
    63  func (s *DBStore) Release() error {
    64  	// Skip encoding if the data is empty
    65  	if len(s.data) == 0 {
    66  		return nil
    67  	}
    68  
    69  	data, err := session.EncodeGob(s.data)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	return auth.UpdateSession(s.sid, data)
    75  }
    76  
    77  // Flush deletes all session data.
    78  func (s *DBStore) Flush() error {
    79  	s.lock.Lock()
    80  	defer s.lock.Unlock()
    81  
    82  	s.data = make(map[interface{}]interface{})
    83  	return nil
    84  }
    85  
    86  // DBProvider represents a DB session provider implementation.
    87  type DBProvider struct {
    88  	maxLifetime int64
    89  }
    90  
    91  // Init initializes DB session provider.
    92  // connStr: username:password@protocol(address)/dbname?param=value
    93  func (p *DBProvider) Init(maxLifetime int64, connStr string) error {
    94  	p.maxLifetime = maxLifetime
    95  	return nil
    96  }
    97  
    98  // Read returns raw session store by session ID.
    99  func (p *DBProvider) Read(sid string) (session.RawStore, error) {
   100  	s, err := auth.ReadSession(sid)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	var kv map[interface{}]interface{}
   106  	if len(s.Data) == 0 || s.Expiry.Add(p.maxLifetime) <= timeutil.TimeStampNow() {
   107  		kv = make(map[interface{}]interface{})
   108  	} else {
   109  		kv, err = session.DecodeGob(s.Data)
   110  		if err != nil {
   111  			return nil, err
   112  		}
   113  	}
   114  
   115  	return NewDBStore(sid, kv), nil
   116  }
   117  
   118  // Exist returns true if session with given ID exists.
   119  func (p *DBProvider) Exist(sid string) bool {
   120  	has, err := auth.ExistSession(sid)
   121  	if err != nil {
   122  		panic("session/DB: error checking existence: " + err.Error())
   123  	}
   124  	return has
   125  }
   126  
   127  // Destroy deletes a session by session ID.
   128  func (p *DBProvider) Destroy(sid string) error {
   129  	return auth.DestroySession(sid)
   130  }
   131  
   132  // Regenerate regenerates a session store from old session ID to new one.
   133  func (p *DBProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) {
   134  	s, err := auth.RegenerateSession(oldsid, sid)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	var kv map[interface{}]interface{}
   140  	if len(s.Data) == 0 || s.Expiry.Add(p.maxLifetime) <= timeutil.TimeStampNow() {
   141  		kv = make(map[interface{}]interface{})
   142  	} else {
   143  		kv, err = session.DecodeGob(s.Data)
   144  		if err != nil {
   145  			return nil, err
   146  		}
   147  	}
   148  
   149  	return NewDBStore(sid, kv), nil
   150  }
   151  
   152  // Count counts and returns number of sessions.
   153  func (p *DBProvider) Count() int {
   154  	total, err := auth.CountSessions()
   155  	if err != nil {
   156  		panic("session/DB: error counting records: " + err.Error())
   157  	}
   158  	return int(total)
   159  }
   160  
   161  // GC calls GC to clean expired sessions.
   162  func (p *DBProvider) GC() {
   163  	if err := auth.CleanupSessions(p.maxLifetime); err != nil {
   164  		log.Printf("session/DB: error garbage collecting: %v", err)
   165  	}
   166  }
   167  
   168  func init() {
   169  	session.Register("db", &DBProvider{})
   170  }