hydrus/hydrus/client/networking/ClientNetworkingSessions.py

426 lines
14 KiB
Python
Raw Normal View History

2019-01-09 22:59:03 +00:00
import pickle
2020-05-20 21:36:02 +00:00
import requests
import threading
2021-01-13 21:48:58 +00:00
import typing
2020-05-20 21:36:02 +00:00
2020-04-22 21:00:35 +00:00
from hydrus.core import HydrusData
from hydrus.core import HydrusSerialisable
from hydrus.core import HydrusGlobals as HG
2018-04-18 22:10:15 +00:00
2020-07-29 20:52:44 +00:00
from hydrus.client import ClientConstants as CC
from hydrus.client.networking import ClientNetworkingContexts
from hydrus.client.networking import ClientNetworkingDomain
2018-11-21 22:22:36 +00:00
try:
import socket
import socks
SOCKS_PROXY_OK = True
except:
SOCKS_PROXY_OK = False
2021-01-13 21:48:58 +00:00
class NetworkSessionManagerSessionContainer( HydrusSerialisable.SerialisableBaseNamed ):
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_NETWORK_SESSION_MANAGER_SESSION_CONTAINER
SERIALISABLE_NAME = 'Session Manager Session Container'
2021-05-12 20:49:20 +00:00
SERIALISABLE_VERSION = 2
2021-01-13 21:48:58 +00:00
def __init__( self, name, network_context = None, session = None ):
if network_context is None:
network_context = ClientNetworkingContexts.GLOBAL_NETWORK_CONTEXT
HydrusSerialisable.SerialisableBaseNamed.__init__( self, name )
self.network_context = network_context
self.session = session
def _InitialiseEmptySession( self ):
self.session = requests.Session()
if self.network_context.context_type == CC.NETWORK_CONTEXT_HYDRUS:
self.session.verify = False
def _GetSerialisableInfo( self ):
serialisable_network_context = self.network_context.GetSerialisableTuple()
2021-05-12 20:49:20 +00:00
self.session.cookies.clear_session_cookies()
pickled_cookies_hex = pickle.dumps( self.session.cookies ).hex()
2021-01-13 21:48:58 +00:00
2021-05-12 20:49:20 +00:00
return ( serialisable_network_context, pickled_cookies_hex )
2021-01-13 21:48:58 +00:00
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
2021-05-12 20:49:20 +00:00
( serialisable_network_context, pickled_cookies_hex ) = serialisable_info
2021-01-13 21:48:58 +00:00
self.network_context = HydrusSerialisable.CreateFromSerialisableTuple( serialisable_network_context )
2021-05-12 20:49:20 +00:00
self._InitialiseEmptySession()
2021-01-13 21:48:58 +00:00
try:
2021-05-12 20:49:20 +00:00
cookies = pickle.loads( bytes.fromhex( pickled_cookies_hex ) )
2021-01-13 21:48:58 +00:00
2021-05-12 20:49:20 +00:00
self.session.cookies = cookies
2021-01-13 21:48:58 +00:00
2021-05-12 20:49:20 +00:00
except:
2021-01-13 21:48:58 +00:00
2021-05-12 20:49:20 +00:00
HydrusData.Print( "Could not load and set cookies for session {}".format( self.network_context ) )
2021-01-13 21:48:58 +00:00
self.session.cookies.clear_session_cookies()
2021-05-12 20:49:20 +00:00
def _UpdateSerialisableInfo( self, version, old_serialisable_info ):
if version == 1:
( serialisable_network_context, pickled_session_hex ) = old_serialisable_info
try:
session = pickle.loads( bytes.fromhex( pickled_session_hex ) )
except:
session = requests.Session()
pickled_cookies_hex = pickle.dumps( session.cookies ).hex()
new_serialisable_info = ( serialisable_network_context, pickled_cookies_hex )
return ( 2, new_serialisable_info )
2021-01-13 21:48:58 +00:00
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_NETWORK_SESSION_MANAGER_SESSION_CONTAINER ] = NetworkSessionManagerSessionContainer
2018-04-18 22:10:15 +00:00
class NetworkSessionManager( HydrusSerialisable.SerialisableBase ):
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_NETWORK_SESSION_MANAGER
SERIALISABLE_NAME = 'Session Manager'
SERIALISABLE_VERSION = 1
SESSION_TIMEOUT = 60 * 60
def __init__( self ):
HydrusSerialisable.SerialisableBase.__init__( self )
self.engine = None
self._dirty = False
2021-01-13 21:48:58 +00:00
self._dirty_session_container_names = set()
self._deletee_session_container_names = set()
2018-04-18 22:10:15 +00:00
self._lock = threading.Lock()
2021-01-13 21:48:58 +00:00
self._session_container_names = set()
self._session_container_names_to_session_containers = {}
self._network_contexts_to_session_containers = {}
2018-04-18 22:10:15 +00:00
self._network_contexts_to_session_timeouts = {}
2018-11-21 22:22:36 +00:00
self._proxies_dict = {}
2021-01-13 21:48:58 +00:00
self._ReinitialiseProxies()
2018-11-21 22:22:36 +00:00
2021-01-13 21:48:58 +00:00
HG.client_controller.sub( self, 'ReinitialiseProxies', 'notify_new_options' )
2018-11-21 22:22:36 +00:00
2018-04-18 22:10:15 +00:00
def _CleanSessionCookies( self, network_context, session ):
if network_context not in self._network_contexts_to_session_timeouts:
self._network_contexts_to_session_timeouts[ network_context ] = 0
if HydrusData.TimeHasPassed( self._network_contexts_to_session_timeouts[ network_context ] ):
session.cookies.clear_session_cookies()
self._network_contexts_to_session_timeouts[ network_context ] = HydrusData.GetNow() + self.SESSION_TIMEOUT
session.cookies.clear_expired_cookies()
def _GetSerialisableInfo( self ):
2021-01-13 21:48:58 +00:00
return sorted( self._session_container_names )
2018-04-18 22:10:15 +00:00
2018-10-24 21:34:02 +00:00
def _GetSessionNetworkContext( self, network_context ):
# just in case one of these slips through somehow
if network_context.context_type == CC.NETWORK_CONTEXT_DOMAIN:
second_level_domain = ClientNetworkingDomain.ConvertDomainIntoSecondLevelDomain( network_context.context_data )
network_context = ClientNetworkingContexts.NetworkContext( CC.NETWORK_CONTEXT_DOMAIN, second_level_domain )
return network_context
2018-04-18 22:10:15 +00:00
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
2021-01-13 21:48:58 +00:00
self._session_container_names = set( serialisable_info )
2018-04-18 22:10:15 +00:00
2021-01-13 21:48:58 +00:00
def _InitialiseSessionContainer( self, network_context ):
session = requests.Session()
if network_context.context_type == CC.NETWORK_CONTEXT_HYDRUS:
2018-04-18 22:10:15 +00:00
2021-01-13 21:48:58 +00:00
session.verify = False
2018-04-18 22:10:15 +00:00
2021-01-13 21:48:58 +00:00
session_container_name = HydrusData.GenerateKey().hex()
session_container = NetworkSessionManagerSessionContainer( session_container_name, network_context = network_context, session = session )
self._session_container_names_to_session_containers[ session_container_name ] = session_container
self._network_contexts_to_session_containers[ network_context ] = session_container
self._session_container_names.add( session_container_name )
self._dirty_session_container_names.add( session_container_name )
self._SetDirty()
2018-04-18 22:10:15 +00:00
2021-01-13 21:48:58 +00:00
def _ReinitialiseProxies( self ):
2018-11-21 22:22:36 +00:00
self._proxies_dict = {}
http_proxy = HG.client_controller.new_options.GetNoneableString( 'http_proxy' )
https_proxy = HG.client_controller.new_options.GetNoneableString( 'https_proxy' )
2020-09-23 21:02:02 +00:00
no_proxy = HG.client_controller.new_options.GetNoneableString( 'no_proxy' )
2018-11-21 22:22:36 +00:00
if http_proxy is not None:
self._proxies_dict[ 'http' ] = http_proxy
if https_proxy is not None:
self._proxies_dict[ 'https' ] = https_proxy
2020-09-23 21:02:02 +00:00
if ( http_proxy is not None or https_proxy is not None ) and no_proxy is not None:
self._proxies_dict[ 'no_proxy' ] = no_proxy
2018-11-21 22:22:36 +00:00
2018-04-18 22:10:15 +00:00
def _SetDirty( self ):
self._dirty = True
def ClearSession( self, network_context ):
with self._lock:
2018-10-24 21:34:02 +00:00
network_context = self._GetSessionNetworkContext( network_context )
2021-01-13 21:48:58 +00:00
if network_context in self._network_contexts_to_session_timeouts:
2018-04-18 22:10:15 +00:00
2021-01-13 21:48:58 +00:00
del self._network_contexts_to_session_timeouts[ network_context ]
if network_context in self._network_contexts_to_session_containers:
session_container = self._network_contexts_to_session_containers[ network_context ]
del self._network_contexts_to_session_containers[ network_context ]
session_container_name = session_container.GetName()
if session_container_name in self._session_container_names_to_session_containers:
del self._session_container_names_to_session_containers[ session_container_name ]
self._session_container_names.discard( session_container_name )
2021-01-20 22:22:03 +00:00
self._dirty_session_container_names.discard( session_container_name )
2021-01-13 21:48:58 +00:00
self._deletee_session_container_names.add( session_container_name )
2018-04-18 22:10:15 +00:00
self._SetDirty()
2021-01-13 21:48:58 +00:00
def GetDeleteeSessionNames( self ):
with self._lock:
return set( self._deletee_session_container_names )
def GetDirtySessionContainers( self ):
with self._lock:
return [ self._session_container_names_to_session_containers[ session_container_name ] for session_container_name in self._dirty_session_container_names ]
2018-04-18 22:10:15 +00:00
def GetNetworkContexts( self ):
with self._lock:
2021-01-13 21:48:58 +00:00
return list( self._network_contexts_to_session_containers.keys() )
2018-04-18 22:10:15 +00:00
def GetSession( self, network_context ):
with self._lock:
2018-10-24 21:34:02 +00:00
network_context = self._GetSessionNetworkContext( network_context )
2018-04-18 22:10:15 +00:00
2021-01-13 21:48:58 +00:00
if network_context not in self._network_contexts_to_session_containers:
2018-04-18 22:10:15 +00:00
2021-01-13 21:48:58 +00:00
self._InitialiseSessionContainer( network_context )
2018-04-18 22:10:15 +00:00
2021-01-13 21:48:58 +00:00
session = self._network_contexts_to_session_containers[ network_context ].session
2018-04-18 22:10:15 +00:00
2018-11-21 22:22:36 +00:00
if session.proxies != self._proxies_dict:
session.proxies = dict( self._proxies_dict )
2018-04-18 22:10:15 +00:00
#
self._CleanSessionCookies( network_context, session )
#
# tumblr can't into ssl for some reason, and the data subdomain they use has weird cert properties, looking like amazon S3
# perhaps it is inward-facing somehow? whatever the case, let's just say fuck it for tumblr
if network_context.context_type == CC.NETWORK_CONTEXT_DOMAIN and network_context.context_data == 'tumblr.com':
session.verify = False
2021-04-14 21:54:17 +00:00
if not HG.client_controller.new_options.GetBoolean( 'verify_regular_https' ):
session.verify = False
2018-04-18 22:10:15 +00:00
return session
2018-10-31 21:41:14 +00:00
def GetSessionForDomain( self, domain ):
network_context = ClientNetworkingContexts.NetworkContext( context_type = CC.NETWORK_CONTEXT_DOMAIN, context_data = domain )
return self.GetSession( network_context )
2021-01-13 21:48:58 +00:00
def HasDirtySessionContainers( self ):
with self._lock:
return len( self._dirty_session_container_names ) > 0 or len( self._deletee_session_container_names ) > 0
2018-04-18 22:10:15 +00:00
def IsDirty( self ):
with self._lock:
return self._dirty
2021-01-13 21:48:58 +00:00
def ReinitialiseProxies( self ):
2018-11-21 22:22:36 +00:00
with self._lock:
2021-01-13 21:48:58 +00:00
self._ReinitialiseProxies()
2018-11-21 22:22:36 +00:00
2018-04-18 22:10:15 +00:00
def SetClean( self ):
with self._lock:
self._dirty = False
2021-01-13 21:48:58 +00:00
self._dirty_session_container_names = set()
self._deletee_session_container_names = set()
2018-04-18 22:10:15 +00:00
2019-08-07 22:59:53 +00:00
def SetDirty( self ):
with self._lock:
2021-01-13 21:48:58 +00:00
self._SetDirty()
def SetSessionContainers( self, session_containers: typing.Collection[ NetworkSessionManagerSessionContainer ], set_all_sessions_dirty = False ):
with self._lock:
self._session_container_names_to_session_containers = {}
self._network_contexts_to_session_containers = {}
self._session_container_names = set()
self._dirty_session_container_names = set()
self._deletee_session_container_names = set()
for session_container in session_containers:
session_container_name = session_container.GetName()
self._session_container_names_to_session_containers[ session_container_name ] = session_container
self._network_contexts_to_session_containers[ session_container.network_context ] = session_container
self._session_container_names.add( session_container_name )
if set_all_sessions_dirty:
self._dirty_session_container_names.add( session_container_name )
def SetSessionDirty( self, network_context: ClientNetworkingContexts.NetworkContext ):
with self._lock:
network_context = self._GetSessionNetworkContext( network_context )
if network_context in self._network_contexts_to_session_containers:
self._dirty_session_container_names.add( self._network_contexts_to_session_containers[ network_context ].GetName() )
2019-08-07 22:59:53 +00:00
2018-04-18 22:10:15 +00:00
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_NETWORK_SESSION_MANAGER ] = NetworkSessionManager