2020-05-20 21:36:02 +00:00
import threading
2022-03-09 22:18:23 +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 HydrusExceptions
from hydrus . core import HydrusGlobals as HG
from hydrus . core import HydrusSerialisable
2021-04-07 21:26:45 +00:00
from hydrus . core import HydrusTags
2020-07-29 20:52:44 +00:00
2022-03-09 22:18:23 +00:00
from hydrus . client import ClientSearch
2019-01-23 22:19:16 +00:00
CLIENT_API_PERMISSION_ADD_URLS = 0
CLIENT_API_PERMISSION_ADD_FILES = 1
CLIENT_API_PERMISSION_ADD_TAGS = 2
CLIENT_API_PERMISSION_SEARCH_FILES = 3
2019-06-05 19:42:39 +00:00
CLIENT_API_PERMISSION_MANAGE_PAGES = 4
2023-03-29 20:57:59 +00:00
CLIENT_API_PERMISSION_MANAGE_HEADERS = 5
2021-05-27 00:09:06 +00:00
CLIENT_API_PERMISSION_MANAGE_DATABASE = 6
2022-03-07 02:44:01 +00:00
CLIENT_API_PERMISSION_ADD_NOTES = 7
2023-01-11 21:10:29 +00:00
CLIENT_API_PERMISSION_MANAGE_FILE_RELATIONSHIPS = 8
2019-01-23 22:19:16 +00:00
2023-03-29 20:57:59 +00:00
ALLOWED_PERMISSIONS = ( CLIENT_API_PERMISSION_ADD_FILES , CLIENT_API_PERMISSION_ADD_TAGS , CLIENT_API_PERMISSION_ADD_URLS , CLIENT_API_PERMISSION_SEARCH_FILES , CLIENT_API_PERMISSION_MANAGE_PAGES , CLIENT_API_PERMISSION_MANAGE_HEADERS , CLIENT_API_PERMISSION_MANAGE_DATABASE , CLIENT_API_PERMISSION_ADD_NOTES , CLIENT_API_PERMISSION_MANAGE_FILE_RELATIONSHIPS )
2019-02-06 22:41:35 +00:00
2019-01-23 22:19:16 +00:00
basic_permission_to_str_lookup = { }
2023-01-11 21:10:29 +00:00
basic_permission_to_str_lookup [ CLIENT_API_PERMISSION_ADD_URLS ] = ' import and edit urls '
basic_permission_to_str_lookup [ CLIENT_API_PERMISSION_ADD_FILES ] = ' import and delete files '
basic_permission_to_str_lookup [ CLIENT_API_PERMISSION_ADD_TAGS ] = ' edit file tags '
basic_permission_to_str_lookup [ CLIENT_API_PERMISSION_SEARCH_FILES ] = ' search and fetch files '
2019-06-05 19:42:39 +00:00
basic_permission_to_str_lookup [ CLIENT_API_PERMISSION_MANAGE_PAGES ] = ' manage pages '
2023-03-29 20:57:59 +00:00
basic_permission_to_str_lookup [ CLIENT_API_PERMISSION_MANAGE_HEADERS ] = ' manage cookies and headers '
2021-05-27 00:09:06 +00:00
basic_permission_to_str_lookup [ CLIENT_API_PERMISSION_MANAGE_DATABASE ] = ' manage database '
2023-01-11 21:10:29 +00:00
basic_permission_to_str_lookup [ CLIENT_API_PERMISSION_ADD_NOTES ] = ' edit file notes '
basic_permission_to_str_lookup [ CLIENT_API_PERMISSION_MANAGE_FILE_RELATIONSHIPS ] = ' manage file relationships '
2019-01-23 22:19:16 +00:00
SEARCH_RESULTS_CACHE_TIMEOUT = 4 * 3600
2019-06-26 21:27:18 +00:00
SESSION_EXPIRY = 86400
2019-02-06 22:41:35 +00:00
api_request_dialog_open = False
last_api_permissions_request = None
2019-01-23 22:19:16 +00:00
class APIManager ( HydrusSerialisable . SerialisableBase ) :
SERIALISABLE_TYPE = HydrusSerialisable . SERIALISABLE_TYPE_CLIENT_API_MANAGER
SERIALISABLE_NAME = ' Client API Manager '
SERIALISABLE_VERSION = 1
def __init__ ( self ) :
HydrusSerialisable . SerialisableBase . __init__ ( self )
self . _dirty = False
self . _access_keys_to_permissions = { }
2019-06-26 21:27:18 +00:00
self . _session_keys_to_access_keys_and_expirys = { }
2019-01-23 22:19:16 +00:00
self . _lock = threading . Lock ( )
HG . client_controller . sub ( self , ' MaintainMemory ' , ' memory_maintenance_pulse ' )
def _GetSerialisableInfo ( self ) :
2019-02-06 22:41:35 +00:00
serialisable_api_permissions_objects = [ api_permissions . GetSerialisableTuple ( ) for api_permissions in self . _access_keys_to_permissions . values ( ) ]
2019-01-23 22:19:16 +00:00
2019-02-06 22:41:35 +00:00
return serialisable_api_permissions_objects
2019-01-23 22:19:16 +00:00
def _InitialiseFromSerialisableInfo ( self , serialisable_info ) :
2019-02-06 22:41:35 +00:00
serialisable_api_permissions_objects = serialisable_info
2019-01-23 22:19:16 +00:00
2019-02-06 22:41:35 +00:00
api_permissions_objects = [ HydrusSerialisable . CreateFromSerialisableTuple ( serialisable_api_permissions ) for serialisable_api_permissions in serialisable_api_permissions_objects ]
2019-01-23 22:19:16 +00:00
2019-02-06 22:41:35 +00:00
self . _access_keys_to_permissions = { api_permissions . GetAccessKey ( ) : api_permissions for api_permissions in api_permissions_objects }
2019-01-23 22:19:16 +00:00
2019-01-30 22:14:54 +00:00
def _SetDirty ( self ) :
self . _dirty = True
2019-02-06 22:41:35 +00:00
def AddAccess ( self , api_permissions ) :
with self . _lock :
self . _access_keys_to_permissions [ api_permissions . GetAccessKey ( ) ] = api_permissions
self . _SetDirty ( )
2019-01-30 22:14:54 +00:00
def DeleteAccess ( self , access_keys ) :
2019-01-23 22:19:16 +00:00
with self . _lock :
2019-01-30 22:14:54 +00:00
for access_key in access_keys :
2019-01-23 22:19:16 +00:00
2019-01-30 22:14:54 +00:00
if access_key in self . _access_keys_to_permissions :
del self . _access_keys_to_permissions [ access_key ]
2019-01-23 22:19:16 +00:00
2019-01-30 22:14:54 +00:00
self . _SetDirty ( )
2019-06-26 21:27:18 +00:00
def GenerateSessionKey ( self , access_key ) :
session_key = HydrusData . GenerateKey ( )
with self . _lock :
self . _session_keys_to_access_keys_and_expirys [ session_key ] = ( access_key , HydrusData . GetNow ( ) + SESSION_EXPIRY )
return session_key
def GetAccessKey ( self , session_key ) :
2019-01-30 22:14:54 +00:00
with self . _lock :
2019-06-26 21:27:18 +00:00
if session_key not in self . _session_keys_to_access_keys_and_expirys :
2019-01-30 22:14:54 +00:00
2019-06-26 21:27:18 +00:00
raise HydrusExceptions . DataMissing ( ' Did not find an entry for that session key! ' )
2019-01-30 22:14:54 +00:00
2019-06-26 21:27:18 +00:00
( access_key , session_expiry ) = self . _session_keys_to_access_keys_and_expirys [ session_key ]
if HydrusData . TimeHasPassed ( session_expiry ) :
2019-01-30 22:14:54 +00:00
2019-06-26 21:27:18 +00:00
del self . _session_keys_to_access_keys_and_expirys [ session_expiry ]
2019-01-30 22:14:54 +00:00
2019-06-26 21:27:18 +00:00
raise HydrusExceptions . SessionException ( ' That session key has expired! ' )
2019-01-30 22:14:54 +00:00
2019-01-23 22:19:16 +00:00
2019-06-26 21:27:18 +00:00
self . _session_keys_to_access_keys_and_expirys [ session_key ] = ( access_key , HydrusData . GetNow ( ) + SESSION_EXPIRY )
return access_key
def GetAllPermissions ( self ) :
return list ( self . _access_keys_to_permissions . values ( ) )
def GetPermissions ( self , access_key ) :
with self . _lock :
if access_key not in self . _access_keys_to_permissions :
raise HydrusExceptions . DataMissing ( ' Did not find an entry for that access key! ' )
return self . _access_keys_to_permissions [ access_key ]
2019-01-23 22:19:16 +00:00
def IsDirty ( self ) :
with self . _lock :
return self . _dirty
def MaintainMemory ( self ) :
with self . _lock :
2019-02-06 22:41:35 +00:00
for api_permissions in self . _access_keys_to_permissions . values ( ) :
2019-01-23 22:19:16 +00:00
2019-02-06 22:41:35 +00:00
api_permissions . MaintainMemory ( )
2019-01-23 22:19:16 +00:00
2019-02-06 22:41:35 +00:00
def OverwriteAccess ( self , api_permissions ) :
self . AddAccess ( api_permissions )
2019-01-23 22:19:16 +00:00
def SetClean ( self ) :
with self . _lock :
self . _dirty = False
2019-02-06 22:41:35 +00:00
def SetPermissions ( self , api_permissions_objects ) :
2019-01-23 22:19:16 +00:00
with self . _lock :
2019-02-06 22:41:35 +00:00
self . _access_keys_to_permissions = { api_permissions . GetAccessKey ( ) : api_permissions for api_permissions in api_permissions_objects }
2019-01-23 22:19:16 +00:00
2019-01-30 22:14:54 +00:00
self . _SetDirty ( )
2019-01-23 22:19:16 +00:00
HydrusSerialisable . SERIALISABLE_TYPES_TO_OBJECT_TYPES [ HydrusSerialisable . SERIALISABLE_TYPE_CLIENT_API_MANAGER ] = APIManager
class APIPermissions ( HydrusSerialisable . SerialisableBaseNamed ) :
SERIALISABLE_TYPE = HydrusSerialisable . SERIALISABLE_TYPE_CLIENT_API_PERMISSIONS
SERIALISABLE_NAME = ' Client API Permissions '
SERIALISABLE_VERSION = 1
2019-02-06 22:41:35 +00:00
def __init__ ( self , name = ' new api permissions ' , access_key = None , basic_permissions = None , search_tag_filter = None ) :
if access_key is None :
access_key = HydrusData . GenerateKey ( )
if basic_permissions is None :
basic_permissions = set ( )
if search_tag_filter is None :
2021-04-07 21:26:45 +00:00
search_tag_filter = HydrusTags . TagFilter ( )
2019-02-06 22:41:35 +00:00
2019-01-23 22:19:16 +00:00
HydrusSerialisable . SerialisableBaseNamed . __init__ ( self , name )
2019-02-06 22:41:35 +00:00
self . _access_key = access_key
2019-01-23 22:19:16 +00:00
2019-02-13 22:26:43 +00:00
self . _basic_permissions = set ( basic_permissions )
2019-02-06 22:41:35 +00:00
self . _search_tag_filter = search_tag_filter
2019-01-23 22:19:16 +00:00
self . _last_search_results = None
self . _search_results_timeout = 0
self . _lock = threading . Lock ( )
def _GetSerialisableInfo ( self ) :
serialisable_access_key = self . _access_key . hex ( )
serialisable_basic_permissions = list ( self . _basic_permissions )
serialisable_search_tag_filter = self . _search_tag_filter . GetSerialisableTuple ( )
return ( serialisable_access_key , serialisable_basic_permissions , serialisable_search_tag_filter )
2019-02-06 22:41:35 +00:00
def _HasPermission ( self , permission ) :
return permission in self . _basic_permissions
2019-01-23 22:19:16 +00:00
def _InitialiseFromSerialisableInfo ( self , serialisable_info ) :
( serialisable_access_key , serialisable_basic_permissions , serialisable_search_tag_filter ) = serialisable_info
self . _access_key = bytes . fromhex ( serialisable_access_key )
self . _basic_permissions = set ( serialisable_basic_permissions )
self . _search_tag_filter = HydrusSerialisable . CreateFromSerialisableTuple ( serialisable_search_tag_filter )
2021-05-27 00:09:06 +00:00
def CheckAtLeastOnePermission ( self , permissions ) :
with self . _lock :
if True not in ( self . _HasPermission ( permission ) for permission in permissions ) :
raise HydrusExceptions . InsufficientCredentialsException ( ' You need at least one these permissions: {} ' . format ( ' , ' . join ( basic_permission_to_str_lookup [ permission ] for permission in permissions ) ) )
2019-03-06 23:06:22 +00:00
def CheckCanSearchTags ( self , tags ) :
2019-01-23 22:19:16 +00:00
with self . _lock :
2019-03-06 23:06:22 +00:00
if self . _search_tag_filter . AllowsEverything ( ) :
return
if len ( tags ) > 0 :
filtered_tags = self . _search_tag_filter . Filter ( tags )
if len ( filtered_tags ) > 0 :
2019-03-13 21:04:21 +00:00
return
2019-03-06 23:06:22 +00:00
2019-01-23 22:19:16 +00:00
2019-03-06 23:06:22 +00:00
raise HydrusExceptions . InsufficientCredentialsException ( ' You do not have permission to do this search. Your tag search permissions are: {} ' . format ( self . _search_tag_filter . ToPermittedString ( ) ) )
2019-01-23 22:19:16 +00:00
2019-03-13 21:04:21 +00:00
def CheckCanSeeAllFiles ( self ) :
with self . _lock :
if not ( self . _HasPermission ( CLIENT_API_PERMISSION_SEARCH_FILES ) and self . _search_tag_filter . AllowsEverything ( ) ) :
raise HydrusExceptions . InsufficientCredentialsException ( ' You do not have permission to see all files, so you cannot do this. ' )
2019-02-06 22:41:35 +00:00
def CheckPermission ( self , permission ) :
if not self . HasPermission ( permission ) :
raise HydrusExceptions . InsufficientCredentialsException ( ' You do not have permission to: {} ' . format ( basic_permission_to_str_lookup [ permission ] ) )
2019-01-23 22:19:16 +00:00
def CheckPermissionToSeeFiles ( self , hash_ids ) :
with self . _lock :
if self . _search_tag_filter . AllowsEverything ( ) :
return
if self . _last_search_results is None :
2019-02-27 23:03:30 +00:00
raise HydrusExceptions . BadRequestException ( ' It looks like those search results are no longer available--please run the search again! ' )
2019-01-23 22:19:16 +00:00
num_files_asked_for = len ( hash_ids )
num_files_allowed_to_see = len ( self . _last_search_results . intersection ( hash_ids ) )
if num_files_allowed_to_see != num_files_asked_for :
error_text = ' You do not seem to have access to all those files! You asked to see {} files, but you were only authorised to see {} of them! '
error_text = error_text . format ( HydrusData . ToHumanInt ( num_files_asked_for ) , HydrusData . ToHumanInt ( num_files_allowed_to_see ) )
2019-03-13 21:04:21 +00:00
raise HydrusExceptions . InsufficientCredentialsException ( error_text )
2019-01-23 22:19:16 +00:00
self . _search_results_timeout = HydrusData . GetNow ( ) + SEARCH_RESULTS_CACHE_TIMEOUT
2022-03-09 22:18:23 +00:00
def FilterTagPredicateResponse ( self , predicates : typing . List [ ClientSearch . Predicate ] ) :
with self . _lock :
if self . _search_tag_filter . AllowsEverything ( ) :
return predicates
return [ predicate for predicate in predicates if self . _search_tag_filter . TagOK ( predicate . GetValue ( ) ) ]
2019-01-30 22:14:54 +00:00
def GenerateNewAccessKey ( self ) :
with self . _lock :
self . _access_key = HydrusData . GenerateKey ( )
def GetAccessKey ( self ) :
with self . _lock :
return self . _access_key
2019-01-23 22:19:16 +00:00
def GetAdvancedPermissionsString ( self ) :
with self . _lock :
p_strings = [ ]
2019-02-06 22:41:35 +00:00
if self . _HasPermission ( CLIENT_API_PERMISSION_SEARCH_FILES ) :
2019-01-23 22:19:16 +00:00
2020-11-11 22:20:16 +00:00
p_strings . append ( ' Can search: {} ' . format ( self . _search_tag_filter . ToPermittedString ( ) ) )
2019-01-23 22:19:16 +00:00
return ' ' . join ( p_strings )
def GetBasicPermissions ( self ) :
with self . _lock :
return self . _basic_permissions
2019-01-30 22:14:54 +00:00
def GetBasicPermissionsString ( self ) :
with self . _lock :
2020-05-13 19:03:16 +00:00
l = sorted ( ( basic_permission_to_str_lookup [ p ] for p in self . _basic_permissions ) )
2019-01-30 22:14:54 +00:00
return ' , ' . join ( l )
2019-02-06 22:41:35 +00:00
def GetSearchTagFilter ( self ) :
2019-01-23 22:19:16 +00:00
with self . _lock :
return self . _search_tag_filter
def HasPermission ( self , permission ) :
with self . _lock :
2019-02-06 22:41:35 +00:00
return self . _HasPermission ( permission )
2019-01-23 22:19:16 +00:00
def MaintainMemory ( self ) :
with self . _lock :
if self . _last_search_results is not None and HydrusData . TimeHasPassed ( self . _search_results_timeout ) :
self . _last_search_results = None
def SetLastSearchResults ( self , hash_ids ) :
with self . _lock :
if self . _search_tag_filter . AllowsEverything ( ) :
return
self . _last_search_results = set ( hash_ids )
self . _search_results_timeout = HydrusData . GetNow ( ) + SEARCH_RESULTS_CACHE_TIMEOUT
2019-02-06 22:41:35 +00:00
def SetSearchTagFilter ( self , search_tag_filter ) :
with self . _lock :
self . _search_tag_filter = search_tag_filter
def ToHumanString ( self ) :
s = ' API Permissions ( {} ): ' . format ( self . _name )
basic_string = self . GetBasicPermissionsString ( )
advanced_string = self . GetAdvancedPermissionsString ( )
if len ( basic_string ) == ' ' :
s + = ' does not have permission to do anything '
else :
s + = basic_string
if len ( advanced_string ) > 0 :
2020-11-11 22:20:16 +00:00
s + = ' : {} ' . format ( advanced_string )
2019-02-06 22:41:35 +00:00
return s
2019-01-23 22:19:16 +00:00
HydrusSerialisable . SERIALISABLE_TYPES_TO_OBJECT_TYPES [ HydrusSerialisable . SERIALISABLE_TYPE_CLIENT_API_PERMISSIONS ] = APIPermissions