code.gitea.io/gitea@v1.22.3/models/auth/session.go (about)

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