@ -28,6 +28,7 @@ import flask_babel
import ipaddress
import ipaddress
import redis
import redis
from datetime import datetime , timedelta
from flask . sessions import SessionMixin , SessionInterface
from flask . sessions import SessionMixin , SessionInterface
from itsdangerous . encoding import want_bytes
from itsdangerous . encoding import want_bytes
from werkzeug . datastructures import CallbackDict
from werkzeug . datastructures import CallbackDict
@ -125,8 +126,6 @@ migrate = flask_migrate.Migrate()
class RedisStore :
class RedisStore :
""" Stores session data in a redis db. """
""" Stores session data in a redis db. """
has_ttl = True
def __init__ ( self , redisstore ) :
def __init__ ( self , redisstore ) :
self . redis = redisstore
self . redis = redisstore
@ -157,8 +156,6 @@ class RedisStore:
class DictStore :
class DictStore :
""" Stores session data in a python dict. """
""" Stores session data in a python dict. """
has_ttl = False
def __init__ ( self ) :
def __init__ ( self ) :
self . dict = { }
self . dict = { }
@ -166,7 +163,7 @@ class DictStore:
""" load item from store. """
""" load item from store. """
return self . dict [ key ]
return self . dict [ key ]
def put ( self , key , value , ttl _secs = None ) :
def put ( self , key , value , ttl = None ) :
""" save item to store. """
""" save item to store. """
self . dict [ key ] = value
self . dict [ key ] = value
@ -284,14 +281,11 @@ class MailuSession(CallbackDict, SessionMixin):
if key != self . _key :
if key != self . _key :
self . delete ( )
self . delete ( )
# remember time to refresh
self [ ' _refresh ' ] = int ( time . time ( ) ) + self . app . permanent_session_lifetime . total_seconds ( ) / 2
# save session
# save session
self . app . session_store . put (
self . app . session_store . put (
key ,
key ,
pickle . dumps ( dict ( self ) ) ,
pickle . dumps ( dict ( self ) ) ,
self . app . permanent_session_lifetime . total_seconds ( )
int ( app . config [ ' SESSION_TIMEOUT ' ] ) ,
)
)
self . _key = key
self . _key = key
@ -301,11 +295,6 @@ class MailuSession(CallbackDict, SessionMixin):
return set_cookie
return set_cookie
def needs_refresh ( self ) :
""" Checks if server side session needs to be refreshed. """
return int ( time . time ( ) ) > self . get ( ' _refresh ' , 0 )
class MailuSessionConfig :
class MailuSessionConfig :
""" Stores sessions crypto config """
""" Stores sessions crypto config """
@ -350,7 +339,7 @@ class MailuSessionConfig:
""" Generate base64 representation of creation time. """
""" Generate base64 representation of creation time. """
return self . _encode ( int ( now or time . time ( ) ) . to_bytes ( 8 , byteorder = ' big ' ) . lstrip ( b ' \0 ' ) )
return self . _encode ( int ( now or time . time ( ) ) . to_bytes ( 8 , byteorder = ' big ' ) . lstrip ( b ' \0 ' ) )
def parse_key ( self , key , app = None , validate= False , now= None ) :
def parse_key ( self , key , app = None , now= None ) :
""" Split key into sid, uid and creation time. """
""" Split key into sid, uid and creation time. """
if not ( isinstance ( key , bytes ) and self . _key_min < = len ( key ) < = self . _key_max ) :
if not ( isinstance ( key , bytes ) and self . _key_min < = len ( key ) < = self . _key_max ) :
@ -365,12 +354,11 @@ class MailuSessionConfig:
if created is None or self . _decode ( uid ) is None or self . _decode ( sid ) is None :
if created is None or self . _decode ( uid ) is None or self . _decode ( sid ) is None :
return None
return None
# validate creation time when requested or store does not support ttl
# validate creation time
if validate or not app . session_store . has_ttl :
if now is None :
if now is None :
now = int ( time . time ( ) )
now = int ( time . time ( ) )
created = int . from_bytes ( created , byteorder = ' big ' )
created = int . from_bytes ( created , byteorder = ' big ' )
if not created < now < created + app . permanent_session_lifetime. total_seconds ( ) :
if not created < = now < = created + app . config[ ' PERMANENT_SESSION_LIFETIME ' ] :
return None
return None
return ( uid , sid , crt )
return ( uid , sid , crt )
@ -410,23 +398,12 @@ class MailuSessionInterface(SessionInterface):
if session . accessed :
if session . accessed :
response . vary . add ( ' Cookie ' )
response . vary . add ( ' Cookie ' )
set_cookie = session . permanent and app . config [ ' SESSION_REFRESH_EACH_REQUEST ' ]
# save session and update cookie if necessary
need_refresh = session . needs_refresh ( )
if session . save ( ) :
# save modified session or refresh unmodified session
if session . modified or need_refresh :
set_cookie | = session . save ( )
# set cookie on refreshed permanent sessions
if need_refresh and session . permanent :
set_cookie = True
# set or update cookie if necessary
if set_cookie :
response . set_cookie (
response . set_cookie (
app . session_cookie_name ,
app . session_cookie_name ,
session . sid ,
session . sid ,
expires = self . get_expiration_time ( app , session ) ,
expires = datetime . now ( ) + timedelta ( seconds = int ( app . config [ ' PERMANENT_SESSION_LIFETIME ' ] ) ) ,
httponly = self . get_cookie_httponly ( app ) ,
httponly = self . get_cookie_httponly ( app ) ,
domain = self . get_cookie_domain ( app ) ,
domain = self . get_cookie_domain ( app ) ,
path = self . get_cookie_path ( app ) ,
path = self . get_cookie_path ( app ) ,
@ -446,7 +423,7 @@ class MailuSessionExtension:
count = 0
count = 0
for key in app . session_store . list ( ) :
for key in app . session_store . list ( ) :
if not app . session_config . parse_key ( key , app , validate= True , now= now ) :
if not app . session_config . parse_key ( key , app , now= now ) :
app . session_store . delete ( key )
app . session_store . delete ( key )
count + = 1
count + = 1