2013-10-02 22:06:06 +00:00
import Cookie
import HydrusConstants as HC
import HydrusExceptions
import HydrusFileHandling
import HydrusImageHandling
2015-07-22 19:40:39 +00:00
import HydrusThreading
2013-10-02 22:06:06 +00:00
import os
2015-03-18 21:46:29 +00:00
import ServerFiles
2014-07-16 20:50:18 +00:00
import time
2013-10-02 22:06:06 +00:00
import traceback
import yaml
from twisted . internet import reactor , defer
from twisted . internet . threads import deferToThread
2015-04-29 19:20:35 +00:00
from twisted . web . server import NOT_DONE_YET
2013-10-02 22:06:06 +00:00
from twisted . web . resource import Resource
from twisted . web . static import File as FileResource , NoRangeStaticProducer
2015-03-25 22:04:19 +00:00
import HydrusData
import HydrusGlobals
2013-10-02 22:06:06 +00:00
CLIENT_ROOT_MESSAGE = ''' <html>
< head >
< title > hydrus client < / title >
< / head >
< body >
2015-03-25 22:04:19 +00:00
< p > This hydrus client uses software version ''' + HydrusData.ToString( HC.SOFTWARE_VERSION ) + ''' and network version ''' + HydrusData.ToString( HC.NETWORK_VERSION ) + ''' . < / p >
2013-10-02 22:06:06 +00:00
< p > It only serves requests from 127.0 .0 .1 . < / p >
< / body >
< / html > '''
ROOT_MESSAGE_BEGIN = ''' <html>
< head >
< title > hydrus service < / title >
< / head >
< body >
2015-03-25 22:04:19 +00:00
< p > This hydrus service uses software version ''' + HydrusData.ToString( HC.SOFTWARE_VERSION ) + ''' and network version ''' + HydrusData.ToString( HC.NETWORK_VERSION ) + ''' . < / p >
2013-10-02 22:06:06 +00:00
< p > '''
ROOT_MESSAGE_END = ''' </p>
< / body >
< / html > '''
def ParseFileArguments ( path ) :
HydrusImageHandling . ConvertToPngIfBmp ( path )
hash = HydrusFileHandling . GetHashFromPath ( path )
2015-03-04 22:44:32 +00:00
try :
( size , mime , width , height , duration , num_frames , num_words ) = HydrusFileHandling . GetFileInfo ( path )
except HydrusExceptions . SizeException :
raise HydrusExceptions . ForbiddenException ( ' File is of zero length! ' )
except HydrusExceptions . MimeException :
raise HydrusExceptions . ForbiddenException ( ' Filetype is not permitted! ' )
except Exception as e :
2015-03-25 22:04:19 +00:00
raise HydrusExceptions . ForbiddenException ( HydrusData . ToString ( e ) )
2015-03-04 22:44:32 +00:00
2013-10-02 22:06:06 +00:00
args = { }
args [ ' path ' ] = path
args [ ' hash ' ] = hash
args [ ' size ' ] = size
args [ ' mime ' ] = mime
if width is not None : args [ ' width ' ] = width
if height is not None : args [ ' height ' ] = height
if duration is not None : args [ ' duration ' ] = duration
if num_frames is not None : args [ ' num_frames ' ] = num_frames
if num_words is not None : args [ ' num_words ' ] = num_words
if mime in HC . IMAGES :
2014-05-21 21:37:35 +00:00
try : thumbnail = HydrusFileHandling . GenerateThumbnail ( path )
2013-10-02 22:06:06 +00:00
except : raise HydrusExceptions . ForbiddenException ( ' Could not generate thumbnail from that file. ' )
args [ ' thumbnail ' ] = thumbnail
return args
2014-07-16 20:50:18 +00:00
hydrus_favicon = FileResource ( HC . STATIC_DIR + os . path . sep + ' hydrus.ico ' , defaultType = ' image/x-icon ' )
local_booru_css = FileResource ( HC . STATIC_DIR + os . path . sep + ' local_booru_style.css ' , defaultType = ' text/css ' )
2013-10-02 22:06:06 +00:00
2014-07-09 22:15:14 +00:00
class HydrusDomain ( object ) :
def __init__ ( self , local_only ) :
self . _local_only = local_only
def CheckValid ( self , client_ip ) :
if self . _local_only and client_ip != ' 127.0.0.1 ' : raise HydrusExceptions . ForbiddenException ( ' Only local access allowed! ' )
2015-07-22 19:40:39 +00:00
class HydrusResourceBusyCheck ( Resource ) :
def __init__ ( self ) :
Resource . __init__ ( self )
self . _server_version_string = HC . service_string_lookup [ HC . SERVER_ADMIN ] + ' / ' + str ( HC . NETWORK_VERSION )
def render_GET ( self , request ) :
request . setHeader ( ' Server ' , self . _server_version_string )
if HydrusGlobals . server_busy : return ' 1 '
else : return ' 0 '
2013-10-02 22:06:06 +00:00
class HydrusResourceWelcome ( Resource ) :
2015-08-05 18:42:35 +00:00
def __init__ ( self , service_type , message ) :
2013-10-02 22:06:06 +00:00
Resource . __init__ ( self )
2015-08-05 18:42:35 +00:00
if service_type == HC . LOCAL_FILE : body = CLIENT_ROOT_MESSAGE
2013-10-02 22:06:06 +00:00
else : body = ROOT_MESSAGE_BEGIN + message + ROOT_MESSAGE_END
self . _body = body . encode ( ' utf-8 ' )
2014-01-01 20:01:00 +00:00
self . _server_version_string = HC . service_string_lookup [ service_type ] + ' / ' + str ( HC . NETWORK_VERSION )
2015-07-22 19:40:39 +00:00
2014-01-01 20:01:00 +00:00
def render_GET ( self , request ) :
request . setHeader ( ' Server ' , self . _server_version_string )
return self . _body
2013-10-02 22:06:06 +00:00
class HydrusResourceCommand ( Resource ) :
2014-08-27 22:15:22 +00:00
def __init__ ( self , service_key , service_type , domain ) :
2013-10-02 22:06:06 +00:00
Resource . __init__ ( self )
2014-08-27 22:15:22 +00:00
self . _service_key = service_key
self . _service_type = service_type
2014-07-09 22:15:14 +00:00
self . _domain = domain
2013-10-02 22:06:06 +00:00
self . _server_version_string = HC . service_string_lookup [ service_type ] + ' / ' + str ( HC . NETWORK_VERSION )
2015-07-22 19:40:39 +00:00
def _checkServerBusy ( self ) :
if HydrusGlobals . server_busy :
raise HydrusExceptions . ServerBusyException ( ' This server is busy, please try again later. ' )
2013-10-02 22:06:06 +00:00
def _callbackCheckRestrictions ( self , request ) :
2015-07-22 19:40:39 +00:00
self . _checkServerBusy ( )
2013-10-02 22:06:06 +00:00
self . _checkUserAgent ( request )
2014-07-09 22:15:14 +00:00
self . _domain . CheckValid ( request . getClientIP ( ) )
2013-10-02 22:06:06 +00:00
return request
def _callbackParseGETArgs ( self , request ) :
hydrus_args = { }
for name in request . args :
values = request . args [ name ]
value = values [ 0 ]
2015-06-03 21:05:13 +00:00
if name in ( ' begin ' , ' expires ' , ' lifetime ' , ' num ' , ' service_type ' , ' service_port ' , ' since ' , ' subindex ' , ' timespan ' ) :
2013-10-02 22:06:06 +00:00
try : hydrus_args [ name ] = int ( value )
except : raise HydrusExceptions . ForbiddenException ( ' I was expecting to parse \' ' + name + ' \' as an integer, but it failed. ' )
2014-10-01 22:58:32 +00:00
elif name in ( ' access_key ' , ' title ' , ' subject_account_key ' , ' contact_key ' , ' hash ' , ' subject_hash ' , ' subject_tag ' , ' message_key ' , ' share_key ' ) :
2013-10-02 22:06:06 +00:00
try : hydrus_args [ name ] = value . decode ( ' hex ' )
except : raise HydrusExceptions . ForbiddenException ( ' I was expecting to parse \' ' + name + ' \' as a hex-encoded string, but it failed. ' )
2015-03-25 22:04:19 +00:00
if ' subject_account_key ' in hydrus_args : hydrus_args [ ' subject_identifier ' ] = HydrusData . AccountIdentifier ( account_key = hydrus_args [ ' subject_account_key ' ] )
2013-10-02 22:06:06 +00:00
elif ' subject_hash ' in hydrus_args :
2015-03-25 22:04:19 +00:00
if ' subject_tag ' in hydrus_args : hydrus_args [ ' subject_identifier ' ] = HydrusData . AccountIdentifier ( tag = hydrus_args [ ' subject_tag ' ] , hash = hydrus_args [ ' subject_hash ' ] )
else : hydrus_args [ ' subject_identifier ' ] = HydrusData . AccountIdentifier ( hash = hydrus_args [ ' subject_hash ' ] )
2013-10-02 22:06:06 +00:00
request . hydrus_args = hydrus_args
return request
def _callbackParsePOSTArgs ( self , request ) :
request . content . seek ( 0 )
if not request . requestHeaders . hasHeader ( ' Content-Type ' ) : raise HydrusExceptions . ForbiddenException ( ' No Content-Type header found! ' )
content_types = request . requestHeaders . getRawHeaders ( ' Content-Type ' )
content_type = content_types [ 0 ]
try : mime = HC . mime_enum_lookup [ content_type ]
except : raise HydrusExceptions . ForbiddenException ( ' Did not recognise Content-Type header! ' )
if mime == HC . APPLICATION_YAML :
yaml_string = request . content . read ( )
request . hydrus_request_data_usage + = len ( yaml_string )
hydrus_args = yaml . safe_load ( yaml_string )
else :
2015-03-25 22:04:19 +00:00
( os_file_handle , temp_path ) = HydrusFileHandling . GetTempPath ( )
request . temp_file_info = ( os_file_handle , temp_path )
2013-10-02 22:06:06 +00:00
with open ( temp_path , ' wb ' ) as f :
2015-03-25 22:04:19 +00:00
for block in HydrusData . ReadFileLikeAsBlocks ( request . content , 65536 ) :
2013-10-02 22:06:06 +00:00
f . write ( block )
request . hydrus_request_data_usage + = len ( block )
hydrus_args = ParseFileArguments ( temp_path )
request . hydrus_args = hydrus_args
return request
def _callbackRenderResponseContext ( self , request ) :
2015-03-25 22:04:19 +00:00
self . _CleanUpTempFile ( request )
2013-10-02 22:06:06 +00:00
response_context = request . hydrus_response_context
status_code = response_context . GetStatusCode ( )
request . setResponseCode ( status_code )
for ( k , v , kwargs ) in response_context . GetCookies ( ) : request . addCookie ( k , v , * * kwargs )
do_finish = True
if response_context . HasBody ( ) :
( mime , body ) = response_context . GetMimeBody ( )
content_type = HC . mime_string_lookup [ mime ]
content_length = len ( body )
request . setHeader ( ' Content-Type ' , content_type )
request . setHeader ( ' Content-Length ' , str ( content_length ) )
if type ( body ) == unicode : body = body . encode ( ' utf-8 ' )
request . write ( body )
elif response_context . HasPath ( ) :
path = response_context . GetPath ( )
info = os . lstat ( path )
size = info [ 6 ]
2015-06-03 21:05:13 +00:00
if response_context . IsJSON ( ) :
2013-10-02 22:06:06 +00:00
2015-06-03 21:05:13 +00:00
mime = HC . APPLICATION_JSON
2013-10-02 22:06:06 +00:00
content_type = HC . mime_string_lookup [ mime ]
else :
mime = HydrusFileHandling . GetMime ( path )
( base , filename ) = os . path . split ( path )
content_type = HC . mime_string_lookup [ mime ] + ' ; ' + filename
content_length = size
request . setHeader ( ' Content-Type ' , content_type )
request . setHeader ( ' Content-Length ' , str ( content_length ) )
2014-07-16 20:50:18 +00:00
request . setHeader ( ' Expires ' , time . strftime ( ' %a , %d % b % Y % H: % M: % S GMT ' , time . gmtime ( time . time ( ) + 86400 * 365 ) ) )
request . setHeader ( ' Cache-Control ' , str ( 86400 * 365 ) )
2013-10-02 22:06:06 +00:00
fileObject = open ( path , ' rb ' )
producer = NoRangeStaticProducer ( request , fileObject )
producer . start ( )
do_finish = False
else :
content_length = 0
request . setHeader ( ' Content-Length ' , str ( content_length ) )
request . hydrus_request_data_usage + = content_length
self . _recordDataUsage ( request )
if do_finish : request . finish ( )
def _callbackDoGETJob ( self , request ) :
def wrap_thread_result ( response_context ) :
request . hydrus_response_context = response_context
return request
d = deferToThread ( self . _threadDoGETJob , request )
d . addCallback ( wrap_thread_result )
return d
def _callbackDoPOSTJob ( self , request ) :
def wrap_thread_result ( response_context ) :
request . hydrus_response_context = response_context
return request
d = deferToThread ( self . _threadDoPOSTJob , request )
d . addCallback ( wrap_thread_result )
return d
def _checkUserAgent ( self , request ) :
request . is_hydrus_user_agent = False
if request . requestHeaders . hasHeader ( ' User-Agent ' ) :
user_agent_texts = request . requestHeaders . getRawHeaders ( ' User-Agent ' )
user_agent_text = user_agent_texts [ 0 ]
try :
user_agents = user_agent_text . split ( ' ' )
2013-12-04 22:44:16 +00:00
except : return # crazy user agent string, so just assume not a hydrus client
for user_agent in user_agents :
if ' / ' in user_agent :
( client , network_version ) = user_agent . split ( ' / ' , 1 )
2013-10-02 22:06:06 +00:00
2013-12-04 22:44:16 +00:00
if client == ' hydrus ' :
2013-10-02 22:06:06 +00:00
2013-12-04 22:44:16 +00:00
request . is_hydrus_user_agent = True
2013-10-02 22:06:06 +00:00
2013-12-04 22:44:16 +00:00
network_version = int ( network_version )
if network_version == HC . NETWORK_VERSION : return
else :
2013-10-02 22:06:06 +00:00
2013-12-04 22:44:16 +00:00
if network_version < HC . NETWORK_VERSION : message = ' Your client is out of date; please download the latest release. '
else : message = ' This server is out of date; please ask its admin to update to the latest release. '
2013-10-02 22:06:06 +00:00
2015-03-25 22:04:19 +00:00
raise HydrusExceptions . NetworkVersionException ( ' Network version mismatch! This server \' s network version is ' + HydrusData . ToString ( HC . NETWORK_VERSION ) + ' , whereas your client \' s is ' + HydrusData . ToString ( network_version ) + ' ! ' + message )
2013-10-02 22:06:06 +00:00
def _errbackHandleEmergencyError ( self , failure , request ) :
2015-08-12 20:35:24 +00:00
try : self . _CleanUpTempFile ( request )
except : pass
2015-03-25 22:04:19 +00:00
2015-08-12 20:35:24 +00:00
try : print ( failure . getTraceback ( ) )
except : pass
2013-10-02 22:06:06 +00:00
try : request . write ( failure . getTraceback ( ) )
except : pass
2015-08-12 20:35:24 +00:00
request . finish ( )
2013-10-02 22:06:06 +00:00
def _errbackHandleProcessingError ( self , failure , request ) :
2015-03-25 22:04:19 +00:00
self . _CleanUpTempFile ( request )
2014-01-01 20:01:00 +00:00
do_yaml = True
try :
# the error may have occured before user agent was set up!
if not request . is_hydrus_user_agent : do_yaml = False
except : pass
if do_yaml :
2013-10-02 22:06:06 +00:00
default_mime = HC . APPLICATION_YAML
2015-03-25 22:04:19 +00:00
default_encoding = lambda x : yaml . safe_dump ( HydrusData . ToString ( x ) )
2013-10-02 22:06:06 +00:00
else :
default_mime = HC . TEXT_HTML
2015-03-25 22:04:19 +00:00
default_encoding = lambda x : HydrusData . ToString ( x )
2013-10-02 22:06:06 +00:00
2015-03-25 22:04:19 +00:00
if failure . type == KeyError : response_context = ResponseContext ( 403 , mime = default_mime , body = default_encoding ( ' It appears one or more parameters required for that request were missing: ' + os . linesep + failure . getTraceback ( ) ) )
elif failure . type == HydrusExceptions . PermissionException : response_context = ResponseContext ( 401 , mime = default_mime , body = default_encoding ( failure . value ) )
elif failure . type == HydrusExceptions . ForbiddenException : response_context = ResponseContext ( 403 , mime = default_mime , body = default_encoding ( failure . value ) )
elif failure . type == HydrusExceptions . NotFoundException : response_context = ResponseContext ( 404 , mime = default_mime , body = default_encoding ( failure . value ) )
elif failure . type == HydrusExceptions . NetworkVersionException : response_context = ResponseContext ( 426 , mime = default_mime , body = default_encoding ( failure . value ) )
2015-07-22 19:40:39 +00:00
elif failure . type == HydrusExceptions . ServerBusyException : response_context = ResponseContext ( 503 , mime = default_mime , body = default_encoding ( failure . value ) )
2015-05-06 20:26:18 +00:00
elif failure . type == HydrusExceptions . SessionException : response_context = ResponseContext ( 419 , mime = default_mime , body = default_encoding ( failure . value ) )
2013-10-02 22:06:06 +00:00
else :
print ( failure . getTraceback ( ) )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 500 , mime = default_mime , body = default_encoding ( ' The repository encountered an error it could not handle! Here is a dump of what happened, which will also be written to your client.log file. If it persists, please forward it to hydrus.admin@gmail.com: ' + os . linesep * 2 + failure . getTraceback ( ) ) )
2013-10-02 22:06:06 +00:00
request . hydrus_response_context = response_context
return request
def _parseAccessKey ( self , request ) :
if not request . requestHeaders . hasHeader ( ' Hydrus-Key ' ) : raise HydrusExceptions . PermissionException ( ' No hydrus key header found! ' )
hex_keys = request . requestHeaders . getRawHeaders ( ' Hydrus-Key ' )
hex_key = hex_keys [ 0 ]
try : access_key = hex_key . decode ( ' hex ' )
except : raise HydrusExceptions . ForbiddenException ( ' Could not parse the hydrus key! ' )
return access_key
2014-07-16 20:50:18 +00:00
def _recordDataUsage ( self , request ) : pass
2013-10-02 22:06:06 +00:00
def _threadDoGETJob ( self , request ) : raise HydrusExceptions . NotFoundException ( ' This service does not support that request! ' )
def _threadDoPOSTJob ( self , request ) : raise HydrusExceptions . NotFoundException ( ' This service does not support that request! ' )
2015-03-25 22:04:19 +00:00
def _CleanUpTempFile ( self , request ) :
if hasattr ( request , ' temp_file_info ' ) :
( os_file_handle , temp_path ) = request . temp_file_info
HydrusFileHandling . CleanUpTempPath ( os_file_handle , temp_path )
2015-08-12 20:35:24 +00:00
del request . temp_file_info
2015-03-25 22:04:19 +00:00
2013-10-02 22:06:06 +00:00
def render_GET ( self , request ) :
request . setHeader ( ' Server ' , self . _server_version_string )
d = defer . Deferred ( )
d . addCallback ( self . _callbackCheckRestrictions )
d . addCallback ( self . _callbackParseGETArgs )
d . addCallback ( self . _callbackDoGETJob )
d . addErrback ( self . _errbackHandleProcessingError , request )
d . addCallback ( self . _callbackRenderResponseContext )
d . addErrback ( self . _errbackHandleEmergencyError , request )
reactor . callLater ( 0 , d . callback , request )
return NOT_DONE_YET
def render_POST ( self , request ) :
request . setHeader ( ' Server ' , self . _server_version_string )
d = defer . Deferred ( )
d . addCallback ( self . _callbackCheckRestrictions )
d . addCallback ( self . _callbackParsePOSTArgs )
d . addCallback ( self . _callbackDoPOSTJob )
d . addErrback ( self . _errbackHandleProcessingError , request )
d . addCallback ( self . _callbackRenderResponseContext )
d . addErrback ( self . _errbackHandleEmergencyError , request )
reactor . callLater ( 0 , d . callback , request )
return NOT_DONE_YET
class HydrusResourceCommandAccessKey ( HydrusResourceCommand ) :
def _threadDoGETJob ( self , request ) :
registration_key = self . _parseAccessKey ( request )
2015-08-26 21:18:39 +00:00
access_key = HydrusGlobals . controller . Read ( ' access_key ' , registration_key )
2013-10-02 22:06:06 +00:00
body = yaml . safe_dump ( { ' access_key ' : access_key } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
2014-01-01 20:01:00 +00:00
class HydrusResourceCommandAccessKeyVerification ( HydrusResourceCommand ) :
def _threadDoGETJob ( self , request ) :
access_key = self . _parseAccessKey ( request )
2015-08-26 21:18:39 +00:00
verified = HydrusGlobals . controller . Read ( ' verify_access_key ' , self . _service_key , access_key )
2014-01-01 20:01:00 +00:00
body = yaml . safe_dump ( { ' verified ' : verified } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2014-01-01 20:01:00 +00:00
return response_context
2014-07-09 22:15:14 +00:00
class HydrusResourceCommandInit ( HydrusResourceCommand ) :
def _threadDoGETJob ( self , request ) :
2013-10-02 22:06:06 +00:00
2015-08-26 21:18:39 +00:00
access_key = HydrusGlobals . controller . Read ( ' init ' )
2014-07-09 22:15:14 +00:00
body = yaml . safe_dump ( { ' access_key ' : access_key } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
2014-07-09 22:15:14 +00:00
class HydrusResourceCommandSessionKey ( HydrusResourceCommand ) :
def _threadDoGETJob ( self , request ) :
access_key = self . _parseAccessKey ( request )
2015-08-26 21:18:39 +00:00
session_manager = HydrusGlobals . controller . GetManager ( ' restricted_services_sessions ' )
2014-07-09 22:15:14 +00:00
2014-10-01 22:58:32 +00:00
( session_key , expires ) = session_manager . AddSession ( self . _service_key , access_key )
2014-07-09 22:15:14 +00:00
2015-03-25 22:04:19 +00:00
now = HydrusData . GetNow ( )
2014-07-09 22:15:14 +00:00
2014-10-01 22:58:32 +00:00
max_age = now - expires
2014-07-09 22:15:14 +00:00
cookies = [ ( ' session_key ' , session_key . encode ( ' hex ' ) , { ' max_age ' : max_age , ' path ' : ' / ' } ) ]
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , cookies = cookies )
2014-07-09 22:15:14 +00:00
return response_context
2013-10-02 22:06:06 +00:00
class HydrusResourceCommandRestricted ( HydrusResourceCommand ) :
GET_PERMISSION = HC . GENERAL_ADMIN
POST_PERMISSION = HC . GENERAL_ADMIN
def _callbackCheckRestrictions ( self , request ) :
2015-07-22 19:40:39 +00:00
self . _checkServerBusy ( )
2013-10-02 22:06:06 +00:00
self . _checkUserAgent ( request )
2014-07-09 22:15:14 +00:00
self . _domain . CheckValid ( request . getClientIP ( ) )
2013-10-02 22:06:06 +00:00
self . _checkSession ( request )
self . _checkPermission ( request )
return request
def _checkPermission ( self , request ) :
account = request . hydrus_account
method = request . method
2015-06-17 20:01:41 +00:00
permission = None
2013-10-02 22:06:06 +00:00
if method == ' GET ' : permission = self . GET_PERMISSION
elif method == ' POST ' : permission = self . POST_PERMISSION
if permission is not None : account . CheckPermission ( permission )
return request
def _checkSession ( self , request ) :
if not request . requestHeaders . hasHeader ( ' Cookie ' ) : raise HydrusExceptions . PermissionException ( ' No cookies found! ' )
cookie_texts = request . requestHeaders . getRawHeaders ( ' Cookie ' )
cookie_text = cookie_texts [ 0 ]
try :
cookies = Cookie . SimpleCookie ( cookie_text )
if ' session_key ' not in cookies : session_key = None
else : session_key = cookies [ ' session_key ' ] . value . decode ( ' hex ' )
except : raise Exception ( ' Problem parsing cookies! ' )
2015-08-26 21:18:39 +00:00
session_manager = HydrusGlobals . controller . GetManager ( ' restricted_services_sessions ' )
2013-11-06 18:22:07 +00:00
2014-08-27 22:15:22 +00:00
account = session_manager . GetAccount ( self . _service_key , session_key )
2013-10-02 22:06:06 +00:00
request . hydrus_account = account
return request
def _recordDataUsage ( self , request ) :
2015-06-17 20:01:41 +00:00
path = request . path [ 1 : ] # /account -> account
if request . method == ' GET ' : method = HC . GET
else : method = HC . POST
2013-10-02 22:06:06 +00:00
2015-06-17 20:01:41 +00:00
if ( self . _service_type , method , path ) in HC . BANDWIDTH_CONSUMING_REQUESTS :
2013-10-02 22:06:06 +00:00
account = request . hydrus_account
if account is not None :
num_bytes = request . hydrus_request_data_usage
account . RequestMade ( num_bytes )
2015-08-26 21:18:39 +00:00
HydrusGlobals . controller . pub ( ' request_made ' , ( account . GetAccountKey ( ) , num_bytes ) )
2013-10-02 22:06:06 +00:00
class HydrusResourceCommandRestrictedAccount ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = None
POST_PERMISSION = HC . MANAGE_USERS
def _threadDoGETJob ( self , request ) :
account = request . hydrus_account
body = yaml . safe_dump ( { ' account ' : account } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
def _threadDoPOSTJob ( self , request ) :
admin_account = request . hydrus_account
2014-10-01 22:58:32 +00:00
admin_account_key = admin_account . GetAccountKey ( )
2013-10-02 22:06:06 +00:00
action = request . hydrus_args [ ' action ' ]
subject_identifiers = request . hydrus_args [ ' subject_identifiers ' ]
2015-08-26 21:18:39 +00:00
subject_account_keys = { HydrusGlobals . controller . Read ( ' account_key_from_identifier ' , self . _service_key , subject_identifier ) for subject_identifier in subject_identifiers }
2014-10-01 22:58:32 +00:00
kwargs = request . hydrus_args # for things like expires, title, and so on
2013-10-30 22:28:06 +00:00
2015-08-26 21:18:39 +00:00
HydrusGlobals . controller . WriteSynchronous ( ' account ' , self . _service_key , admin_account_key , action , subject_account_keys , kwargs )
2013-10-02 22:06:06 +00:00
2015-08-26 21:18:39 +00:00
session_manager = HydrusGlobals . controller . GetManager ( ' restricted_services_sessions ' )
2013-11-06 18:22:07 +00:00
2014-10-01 22:58:32 +00:00
session_manager . RefreshAccounts ( self . _service_key , subject_account_keys )
2013-11-06 18:22:07 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 )
2013-10-02 22:06:06 +00:00
return response_context
class HydrusResourceCommandRestrictedAccountInfo ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GENERAL_ADMIN
def _threadDoGETJob ( self , request ) :
subject_identifier = request . hydrus_args [ ' subject_identifier ' ]
2015-08-26 21:18:39 +00:00
subject_account_key = HydrusGlobals . controller . Read ( ' account_key_from_identifier ' , self . _service_key , subject_identifier )
2014-10-01 22:58:32 +00:00
2015-08-26 21:18:39 +00:00
account_info = HydrusGlobals . controller . Read ( ' account_info ' , self . _service_key , subject_account_key )
2013-10-02 22:06:06 +00:00
body = yaml . safe_dump ( { ' account_info ' : account_info } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
class HydrusResourceCommandRestrictedAccountTypes ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GENERAL_ADMIN
POST_PERMISSION = HC . GENERAL_ADMIN
def _threadDoGETJob ( self , request ) :
2015-08-26 21:18:39 +00:00
account_types = HydrusGlobals . controller . Read ( ' account_types ' , self . _service_key )
2013-10-02 22:06:06 +00:00
body = yaml . safe_dump ( { ' account_types ' : account_types } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
def _threadDoPOSTJob ( self , request ) :
edit_log = request . hydrus_args [ ' edit_log ' ]
2015-08-26 21:18:39 +00:00
HydrusGlobals . controller . WriteSynchronous ( ' account_types ' , self . _service_key , edit_log )
2013-10-02 22:06:06 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 )
2013-10-02 22:06:06 +00:00
return response_context
class HydrusResourceCommandRestrictedBackup ( HydrusResourceCommandRestricted ) :
POST_PERMISSION = HC . GENERAL_ADMIN
def _threadDoPOSTJob ( self , request ) :
2015-07-22 19:40:39 +00:00
def do_it ( ) :
HydrusGlobals . server_busy = True
2015-08-26 21:18:39 +00:00
HydrusGlobals . controller . WriteSynchronous ( ' backup ' )
2015-07-22 19:40:39 +00:00
HydrusGlobals . server_busy = False
2014-02-05 20:54:28 +00:00
2015-08-26 21:18:39 +00:00
HydrusGlobals . controller . CallToThread ( do_it )
2013-10-02 22:06:06 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 )
2013-10-02 22:06:06 +00:00
return response_context
class HydrusResourceCommandRestrictedIP ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GENERAL_ADMIN
def _threadDoGETJob ( self , request ) :
hash = request . hydrus_args [ ' hash ' ]
2015-08-26 21:18:39 +00:00
( ip , timestamp ) = HydrusGlobals . controller . Read ( ' ip ' , self . _service_key , hash )
2013-10-02 22:06:06 +00:00
body = yaml . safe_dump ( { ' ip ' : ip , ' timestamp ' : timestamp } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
class HydrusResourceCommandRestrictedNews ( HydrusResourceCommandRestricted ) :
POST_PERMISSION = HC . GENERAL_ADMIN
def _threadDoPOSTJob ( self , request ) :
news = request . hydrus_args [ ' news ' ]
2015-08-26 21:18:39 +00:00
HydrusGlobals . controller . WriteSynchronous ( ' news ' , self . _service_key , news )
2013-10-02 22:06:06 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 )
2013-10-02 22:06:06 +00:00
return response_context
class HydrusResourceCommandRestrictedNumPetitions ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . RESOLVE_PETITIONS
def _threadDoGETJob ( self , request ) :
2015-08-26 21:18:39 +00:00
num_petitions = HydrusGlobals . controller . Read ( ' num_petitions ' , self . _service_key )
2013-10-02 22:06:06 +00:00
body = yaml . safe_dump ( { ' num_petitions ' : num_petitions } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
class HydrusResourceCommandRestrictedPetition ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . RESOLVE_PETITIONS
def _threadDoGETJob ( self , request ) :
2015-08-26 21:18:39 +00:00
petition = HydrusGlobals . controller . Read ( ' petition ' , self . _service_key )
2013-10-02 22:06:06 +00:00
body = yaml . safe_dump ( { ' petition ' : petition } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
class HydrusResourceCommandRestrictedRegistrationKeys ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GENERAL_ADMIN
def _threadDoGETJob ( self , request ) :
num = request . hydrus_args [ ' num ' ]
title = request . hydrus_args [ ' title ' ]
2013-12-04 22:44:16 +00:00
if ' lifetime ' in request . hydrus_args : lifetime = request . hydrus_args [ ' lifetime ' ]
else : lifetime = None
2013-10-02 22:06:06 +00:00
2015-08-26 21:18:39 +00:00
registration_keys = HydrusGlobals . controller . Read ( ' registration_keys ' , self . _service_key , num , title , lifetime )
2013-10-02 22:06:06 +00:00
body = yaml . safe_dump ( { ' registration_keys ' : registration_keys } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
2014-07-09 22:15:14 +00:00
class HydrusResourceCommandRestrictedRepositoryFile ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GET_DATA
POST_PERMISSION = HC . POST_DATA
def _threadDoGETJob ( self , request ) :
hash = request . hydrus_args [ ' hash ' ]
# don't I need to check that we aren't stealing the file from another service?
2015-03-18 21:46:29 +00:00
path = ServerFiles . GetPath ( ' file ' , hash )
2014-07-09 22:15:14 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , path = path )
2014-07-09 22:15:14 +00:00
return response_context
def _threadDoPOSTJob ( self , request ) :
account = request . hydrus_account
2014-10-01 22:58:32 +00:00
account_key = account . GetAccountKey ( )
2014-07-09 22:15:14 +00:00
file_dict = request . hydrus_args
file_dict [ ' ip ' ] = request . getClientIP ( )
2015-08-26 21:18:39 +00:00
HydrusGlobals . controller . WriteSynchronous ( ' file ' , self . _service_key , account_key , file_dict )
2014-07-09 22:15:14 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 )
2014-07-09 22:15:14 +00:00
return response_context
class HydrusResourceCommandRestrictedRepositoryThumbnail ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GET_DATA
def _threadDoGETJob ( self , request ) :
hash = request . hydrus_args [ ' hash ' ]
# don't I need to check that we aren't stealing the file from another service?
2015-03-18 21:46:29 +00:00
path = ServerFiles . GetPath ( ' thumbnail ' , hash )
2014-07-09 22:15:14 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , path = path )
2014-07-09 22:15:14 +00:00
return response_context
2013-10-02 22:06:06 +00:00
class HydrusResourceCommandRestrictedServices ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GENERAL_ADMIN
2013-11-06 18:22:07 +00:00
POST_PERMISSION = HC . GENERAL_ADMIN
2013-10-02 22:06:06 +00:00
2014-09-17 21:28:26 +00:00
def _threadDoPOSTJob ( self , request ) :
2013-10-02 22:06:06 +00:00
2014-09-17 21:28:26 +00:00
account = request . hydrus_account
2013-10-02 22:06:06 +00:00
2014-10-01 22:58:32 +00:00
account_key = account . GetAccountKey ( )
2014-09-17 21:28:26 +00:00
edit_log = request . hydrus_args [ ' edit_log ' ]
2015-08-26 21:18:39 +00:00
service_keys_to_access_keys = HydrusGlobals . controller . WriteSynchronous ( ' services ' , account_key , edit_log )
2014-09-17 21:28:26 +00:00
body = yaml . safe_dump ( { ' service_keys_to_access_keys ' : service_keys_to_access_keys } )
2013-10-02 22:06:06 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
2014-09-17 21:28:26 +00:00
class HydrusResourceCommandRestrictedServicesInfo ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GENERAL_ADMIN
POST_PERMISSION = HC . GENERAL_ADMIN
def _threadDoGETJob ( self , request ) :
2013-10-02 22:06:06 +00:00
2015-08-26 21:18:39 +00:00
services_info = HydrusGlobals . controller . Read ( ' services_info ' )
2013-10-02 22:06:06 +00:00
2014-09-17 21:28:26 +00:00
body = yaml . safe_dump ( { ' services_info ' : services_info } )
2013-11-27 18:27:11 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
class HydrusResourceCommandRestrictedStats ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GENERAL_ADMIN
def _threadDoGETJob ( self , request ) :
2015-08-26 21:18:39 +00:00
stats = HydrusGlobals . controller . Read ( ' stats ' , self . _service_key )
2013-10-02 22:06:06 +00:00
body = yaml . safe_dump ( { ' stats ' : stats } )
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 , body = body )
2013-10-02 22:06:06 +00:00
return response_context
2015-06-03 21:05:13 +00:00
class HydrusResourceCommandRestrictedContentUpdate ( HydrusResourceCommandRestricted ) :
2013-10-02 22:06:06 +00:00
GET_PERMISSION = HC . GET_DATA
POST_PERMISSION = HC . POST_DATA
def _threadDoGETJob ( self , request ) :
begin = request . hydrus_args [ ' begin ' ]
2015-06-03 21:05:13 +00:00
subindex = request . hydrus_args [ ' subindex ' ]
2013-10-02 22:06:06 +00:00
2015-06-03 21:05:13 +00:00
path = ServerFiles . GetContentUpdatePackagePath ( self . _service_key , begin , subindex )
2013-10-02 22:06:06 +00:00
2015-06-03 21:05:13 +00:00
response_context = ResponseContext ( 200 , path = path , is_json = True )
2013-10-02 22:06:06 +00:00
return response_context
def _threadDoPOSTJob ( self , request ) :
account = request . hydrus_account
2014-10-01 22:58:32 +00:00
account_key = account . GetAccountKey ( )
2013-10-02 22:06:06 +00:00
update = request . hydrus_args [ ' update ' ]
2015-08-26 21:18:39 +00:00
HydrusGlobals . controller . WriteSynchronous ( ' update ' , self . _service_key , account_key , update )
2013-10-02 22:06:06 +00:00
2015-03-25 22:04:19 +00:00
response_context = ResponseContext ( 200 )
2013-10-02 22:06:06 +00:00
return response_context
2015-06-03 21:05:13 +00:00
class HydrusResourceCommandRestrictedServiceUpdate ( HydrusResourceCommandRestricted ) :
GET_PERMISSION = HC . GET_DATA
def _threadDoGETJob ( self , request ) :
begin = request . hydrus_args [ ' begin ' ]
path = ServerFiles . GetServiceUpdatePackagePath ( self . _service_key , begin )
response_context = ResponseContext ( 200 , path = path , is_json = True )
return response_context
2015-03-25 22:04:19 +00:00
class ResponseContext ( object ) :
2015-06-03 21:05:13 +00:00
def __init__ ( self , status_code , mime = HC . APPLICATION_YAML , body = None , path = None , is_json = False , cookies = None ) :
2015-03-25 22:04:19 +00:00
if cookies is None : cookies = [ ]
self . _status_code = status_code
self . _mime = mime
self . _body = body
self . _path = path
2015-06-03 21:05:13 +00:00
self . _is_json = is_json
2015-03-25 22:04:19 +00:00
self . _cookies = cookies
def GetCookies ( self ) : return self . _cookies
def GetLength ( self ) : return len ( self . _body )
def GetMimeBody ( self ) : return ( self . _mime , self . _body )
def GetPath ( self ) : return self . _path
def GetStatusCode ( self ) : return self . _status_code
def HasBody ( self ) : return self . _body is not None
def HasPath ( self ) : return self . _path is not None
2015-06-03 21:05:13 +00:00
def IsJSON ( self ) : return self . _is_json
2013-10-02 22:06:06 +00:00