hydrus/include/HydrusServerResources.py

1065 lines
35 KiB
Python
Raw Normal View History

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