import BaseHTTPServer import ClientConstants as CC import ClientFiles import Cookie import hashlib import httplib import HydrusAudioHandling import HydrusConstants as HC import HydrusDocumentHandling import HydrusExceptions import HydrusFileHandling import HydrusFlashHandling import HydrusNATPunch import HydrusImageHandling import os import random import ServerFiles import SocketServer import threading import time import traceback import urllib import wx import yaml from twisted.internet import reactor, defer from twisted.internet.threads import deferToThread from twisted.web.server import Request, Site, NOT_DONE_YET from twisted.web.resource import Resource from twisted.web.static import File as FileResource, NoRangeStaticProducer from twisted.python import log CLIENT_ROOT_MESSAGE = ''' hydrus client

This hydrus client uses software version ''' + HC.u( HC.SOFTWARE_VERSION ) + ''' and network version ''' + HC.u( HC.NETWORK_VERSION ) + '''.

It only serves requests from 127.0.0.1.

''' ROOT_MESSAGE_BEGIN = ''' hydrus service

This hydrus service uses software version ''' + HC.u( HC.SOFTWARE_VERSION ) + ''' and network version ''' + HC.u( HC.NETWORK_VERSION ) + '''.

''' ROOT_MESSAGE_END = '''

''' def ParseFileArguments( path ): HydrusImageHandling.ConvertToPngIfBmp( path ) hash = HydrusFileHandling.GetHashFromPath( path ) 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: raise HydrusExceptions.ForbiddenException( HC.u( e ) ) 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: try: thumbnail = HydrusFileHandling.GenerateThumbnail( path ) except: raise HydrusExceptions.ForbiddenException( 'Could not generate thumbnail from that file.' ) args[ 'thumbnail' ] = thumbnail return args 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' ) 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!' ) class HydrusResourceWelcome( Resource ): def __init__( self, service_key, service_type, message ): Resource.__init__( self ) if service_key == HC.LOCAL_FILE_SERVICE_KEY: body = CLIENT_ROOT_MESSAGE else: body = ROOT_MESSAGE_BEGIN + message + ROOT_MESSAGE_END self._body = body.encode( 'utf-8' ) self._server_version_string = HC.service_string_lookup[ service_type ] + '/' + str( HC.NETWORK_VERSION ) def render_GET( self, request ): request.setHeader( 'Server', self._server_version_string ) return self._body class HydrusResourceCommand( Resource ): def __init__( self, service_key, service_type, domain ): Resource.__init__( self ) self._service_key = service_key self._service_type = service_type self._domain = domain self._server_version_string = HC.service_string_lookup[ service_type ] + '/' + str( HC.NETWORK_VERSION ) def _callbackCheckRestrictions( self, request ): self._checkUserAgent( request ) self._domain.CheckValid( request.getClientIP() ) return request def _callbackParseGETArgs( self, request ): hydrus_args = {} for name in request.args: values = request.args[ name ] value = values[0] if name in ( 'begin', 'expires', 'lifetime', 'num', 'service_type', 'service_port', 'since', 'timespan' ): try: hydrus_args[ name ] = int( value ) except: raise HydrusExceptions.ForbiddenException( 'I was expecting to parse \'' + name + '\' as an integer, but it failed.' ) elif name in ( 'access_key', 'title', 'subject_account_key', 'contact_key', 'hash', 'subject_hash', 'subject_tag', 'message_key', 'share_key' ): 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.' ) if 'subject_account_key' in hydrus_args: hydrus_args[ 'subject_identifier' ] = HC.AccountIdentifier( account_key = hydrus_args[ 'subject_account_key' ] ) elif 'subject_hash' in hydrus_args: if 'subject_tag' in hydrus_args: hydrus_args[ 'subject_identifier' ] = HC.AccountIdentifier( tag = hydrus_args[ 'subject_tag' ], hash = hydrus_args[ 'subject_hash' ] ) else: hydrus_args[ 'subject_identifier' ] = HC.AccountIdentifier( hash = hydrus_args[ 'subject_hash' ] ) 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: temp_path = HC.GetTempPath() with open( temp_path, 'wb' ) as f: for block in HC.ReadFileLikeAsBlocks( request.content, 65536 ): 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 ): 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] if response_context.IsYAML(): mime = HC.APPLICATION_YAML 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 ) ) 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 ) ) 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( ' ' ) 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 ) if client == 'hydrus': request.is_hydrus_user_agent = True network_version = int( network_version ) if network_version == HC.NETWORK_VERSION: return else: 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.' raise HydrusExceptions.NetworkVersionException( 'Network version mismatch! This server\'s network version is ' + HC.u( HC.NETWORK_VERSION ) + ', whereas your client\'s is ' + HC.u( network_version ) + '! ' + message ) def _errbackHandleEmergencyError( self, failure, request ): print( failure.getTraceback() ) try: request.write( failure.getTraceback() ) except: pass try: request.finish() except: pass def _errbackHandleProcessingError( self, failure, request ): 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: default_mime = HC.APPLICATION_YAML default_encoding = lambda x: yaml.safe_dump( HC.u( x ) ) else: default_mime = HC.TEXT_HTML default_encoding = lambda x: HC.u( x ) if failure.type == KeyError: response_context = HC.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 = HC.ResponseContext( 401, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.ForbiddenException: response_context = HC.ResponseContext( 403, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.NotFoundException: response_context = HC.ResponseContext( 404, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.NetworkVersionException: response_context = HC.ResponseContext( 426, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.SessionException: response_context = HC.ResponseContext( 403, mime = default_mime, body = default_encoding( failure.value ) ) else: print( failure.getTraceback() ) response_context = HC.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() ) ) 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 def _recordDataUsage( self, request ): pass 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!' ) 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 ) access_key = HC.app.Read( 'access_key', registration_key ) body = yaml.safe_dump( { 'access_key' : access_key } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandAccessKeyVerification( HydrusResourceCommand ): def _threadDoGETJob( self, request ): access_key = self._parseAccessKey( request ) verified = HC.app.Read( 'verify_access_key', self._service_key, access_key ) body = yaml.safe_dump( { 'verified' : verified } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandBooru( HydrusResourceCommand ): RECORD_GET_DATA_USAGE = False RECORD_POST_DATA_USAGE = False def _recordDataUsage( self, request ): p1 = request.method == 'GET' and self.RECORD_GET_DATA_USAGE p2 = request.method == 'POST' and self.RECORD_POST_DATA_USAGE if p1 or p2: num_bytes = request.hydrus_request_data_usage HC.pubsub.pub( 'service_updates_delayed', { HC.LOCAL_BOORU_SERVICE_KEY : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_REQUEST_MADE, num_bytes ) ] } ) def _callbackCheckRestrictions( self, request ): self._checkUserAgent( request ) self._domain.CheckValid( request.getClientIP() ) return request class HydrusResourceCommandBooruGallery( HydrusResourceCommandBooru ): RECORD_GET_DATA_USAGE = True def _threadDoGETJob( self, request ): # in future, make this a standard frame with a search key that'll load xml or yaml AJAX stuff # with file info included, so the page can sort and whatever share_key = request.hydrus_args[ 'share_key' ] local_booru_manager = HC.app.GetManager( 'local_booru' ) local_booru_manager.CheckShareAuthorised( share_key ) ( name, text, timeout, media_results ) = local_booru_manager.GetGalleryInfo( share_key ) body = ''' ''' if name == '': body += ''' hydrus network local booru share''' else: body += ''' ''' + name + '''''' body += ''' ''' ( thumbnail_width, thumbnail_height ) = HC.options[ 'thumbnail_dimensions' ] body += ''' ''' body += ''' ''' body += '''
This share ''' + HC.ConvertTimestampToPrettyExpires( timeout ) + '''.
''' if name != '': body += '''

''' + name + '''

''' if text != '': newline = '''

''' body += '''

''' + text.replace( os.linesep, newline ).replace( '\n', newline ) + '''

''' body+= '''
''' for media_result in media_results: hash = media_result.GetHash() mime = media_result.GetMime() # if mime in flash or pdf or whatever, get other thumbnail body += ''' ''' body += '''
''' response_context = HC.ResponseContext( 200, mime = HC.TEXT_HTML, body = body ) return response_context class HydrusResourceCommandBooruFile( HydrusResourceCommandBooru ): RECORD_GET_DATA_USAGE = True def _threadDoGETJob( self, request ): share_key = request.hydrus_args[ 'share_key' ] hash = request.hydrus_args[ 'hash' ] local_booru_manager = HC.app.GetManager( 'local_booru' ) local_booru_manager.CheckFileAuthorised( share_key, hash ) path = ClientFiles.GetFilePath( hash ) response_context = HC.ResponseContext( 200, path = path ) return response_context class HydrusResourceCommandBooruPage( HydrusResourceCommandBooru ): RECORD_GET_DATA_USAGE = True def _threadDoGETJob( self, request ): share_key = request.hydrus_args[ 'share_key' ] hash = request.hydrus_args[ 'hash' ] local_booru_manager = HC.app.GetManager( 'local_booru' ) local_booru_manager.CheckFileAuthorised( share_key, hash ) ( name, text, timeout, media_result ) = local_booru_manager.GetPageInfo( share_key, hash ) body = ''' ''' if name == '': body += ''' hydrus network local booru share''' else: body += ''' ''' + name + '''''' body += ''' ''' body += ''' ''' body += '''
This share ''' + HC.ConvertTimestampToPrettyExpires( timeout ) + '''.
''' if name != '': body += '''

''' + name + '''

''' if text != '': newline = '''

''' body += '''

''' + text.replace( os.linesep, newline ).replace( '\n', newline ) + '''

''' body+= '''
''' mime = media_result.GetMime() if mime in HC.IMAGES: ( width, height ) = media_result.GetResolution() body += ''' ''' elif mime in HC.VIDEO: ( width, height ) = media_result.GetResolution() body += '''
''' response_context = HC.ResponseContext( 200, mime = HC.TEXT_HTML, body = body ) return response_context class HydrusResourceCommandBooruThumbnail( HydrusResourceCommandBooru ): RECORD_GET_DATA_USAGE = True def _threadDoGETJob( self, request ): share_key = request.hydrus_args[ 'share_key' ] hash = request.hydrus_args[ 'hash' ] local_booru_manager = HC.app.GetManager( 'local_booru' ) local_booru_manager.CheckFileAuthorised( share_key, hash ) media_result = local_booru_manager.GetMediaResult( share_key, hash ) mime = media_result.GetMime() if mime in HC.MIMES_WITH_THUMBNAILS: path = ClientFiles.GetThumbnailPath( hash, full_size = False ) elif mime in HC.AUDIO: path = HC.STATIC_DIR + os.path.sep + 'audio_resized.png' elif mime in HC.VIDEO: path = HC.STATIC_DIR + os.path.sep + 'video_resized.png' elif mime == HC.APPLICATION_FLASH: path = HC.STATIC_DIR + os.path.sep + 'flash_resized.png' elif mime == HC.APPLICATION_PDF: path = HC.STATIC_DIR + os.path.sep + 'pdf_resized.png' else: path = HC.STATIC_DIR + os.path.sep + 'hydrus_resized.png' response_context = HC.ResponseContext( 200, path = path ) return response_context class HydrusResourceCommandInit( HydrusResourceCommand ): def _threadDoGETJob( self, request ): access_key = HC.app.Read( 'init' ) body = yaml.safe_dump( { 'access_key' : access_key } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandLocalFile( HydrusResourceCommand ): def _threadDoGETJob( self, request ): hash = request.hydrus_args[ 'hash' ] path = ClientFiles.GetFilePath( hash ) response_context = HC.ResponseContext( 200, path = path ) return response_context class HydrusResourceCommandLocalThumbnail( HydrusResourceCommand ): def _threadDoGETJob( self, request ): hash = request.hydrus_args[ 'hash' ] path = ClientFiles.GetThumbnailPath( hash ) response_context = HC.ResponseContext( 200, path = path ) return response_context class HydrusResourceCommandSessionKey( HydrusResourceCommand ): def _threadDoGETJob( self, request ): access_key = self._parseAccessKey( request ) session_manager = HC.app.GetManager( 'restricted_services_sessions' ) ( session_key, expires ) = session_manager.AddSession( self._service_key, access_key ) now = HC.GetNow() max_age = now - expires cookies = [ ( 'session_key', session_key.encode( 'hex' ), { 'max_age' : max_age, 'path' : '/' } ) ] response_context = HC.ResponseContext( 200, cookies = cookies ) return response_context class HydrusResourceCommandRestricted( HydrusResourceCommand ): GET_PERMISSION = HC.GENERAL_ADMIN POST_PERMISSION = HC.GENERAL_ADMIN RECORD_GET_DATA_USAGE = False RECORD_POST_DATA_USAGE = False def _callbackCheckRestrictions( self, request ): self._checkUserAgent( request ) self._domain.CheckValid( request.getClientIP() ) self._checkSession( request ) self._checkPermission( request ) return request def _checkPermission( self, request ): account = request.hydrus_account method = request.method 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!' ) session_manager = HC.app.GetManager( 'restricted_services_sessions' ) account = session_manager.GetAccount( self._service_key, session_key ) request.hydrus_account = account return request def _recordDataUsage( self, request ): p1 = request.method == 'GET' and self.RECORD_GET_DATA_USAGE p2 = request.method == 'POST' and self.RECORD_POST_DATA_USAGE if p1 or p2: account = request.hydrus_account if account is not None: num_bytes = request.hydrus_request_data_usage account.RequestMade( num_bytes ) HC.pubsub.pub( 'request_made', ( account.GetAccountKey(), num_bytes ) ) 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 } ) response_context = HC.ResponseContext( 200, body = body ) return response_context def _threadDoPOSTJob( self, request ): admin_account = request.hydrus_account admin_account_key = admin_account.GetAccountKey() action = request.hydrus_args[ 'action' ] subject_identifiers = request.hydrus_args[ 'subject_identifiers' ] subject_account_keys = { HC.app.Read( 'account_key_from_identifier', self._service_key, subject_identifier ) for subject_identifier in subject_identifiers } kwargs = request.hydrus_args # for things like expires, title, and so on HC.app.Write( 'account', self._service_key, admin_account_key, action, subject_account_keys, kwargs ) session_manager = HC.app.GetManager( 'restricted_services_sessions' ) session_manager.RefreshAccounts( self._service_key, subject_account_keys ) response_context = HC.ResponseContext( 200 ) return response_context class HydrusResourceCommandRestrictedAccountInfo( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.GENERAL_ADMIN def _threadDoGETJob( self, request ): subject_identifier = request.hydrus_args[ 'subject_identifier' ] subject_account_key = HC.app.Read( 'account_key_from_identifier', self._service_key, subject_identifier ) account_info = HC.app.Read( 'account_info', self._service_key, subject_account_key ) body = yaml.safe_dump( { 'account_info' : account_info } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandRestrictedAccountTypes( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.GENERAL_ADMIN POST_PERMISSION = HC.GENERAL_ADMIN def _threadDoGETJob( self, request ): account_types = HC.app.Read( 'account_types', self._service_key ) body = yaml.safe_dump( { 'account_types' : account_types } ) response_context = HC.ResponseContext( 200, body = body ) return response_context def _threadDoPOSTJob( self, request ): edit_log = request.hydrus_args[ 'edit_log' ] HC.app.Write( 'account_types', self._service_key, edit_log ) response_context = HC.ResponseContext( 200 ) return response_context class HydrusResourceCommandRestrictedBackup( HydrusResourceCommandRestricted ): POST_PERMISSION = HC.GENERAL_ADMIN def _threadDoPOSTJob( self, request ): #threading.Thread( target = HC.app.Write, args = ( 'backup', ), name = 'Backup Thread' ).start() HC.app.Write( 'backup' ) response_context = HC.ResponseContext( 200 ) return response_context class HydrusResourceCommandRestrictedIP( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.GENERAL_ADMIN def _threadDoGETJob( self, request ): hash = request.hydrus_args[ 'hash' ] ( ip, timestamp ) = HC.app.Read( 'ip', self._service_key, hash ) body = yaml.safe_dump( { 'ip' : ip, 'timestamp' : timestamp } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandRestrictedNews( HydrusResourceCommandRestricted ): POST_PERMISSION = HC.GENERAL_ADMIN def _threadDoPOSTJob( self, request ): news = request.hydrus_args[ 'news' ] HC.app.Write( 'news', self._service_key, news ) response_context = HC.ResponseContext( 200 ) return response_context class HydrusResourceCommandRestrictedNumPetitions( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.RESOLVE_PETITIONS def _threadDoGETJob( self, request ): num_petitions = HC.app.Read( 'num_petitions', self._service_key ) body = yaml.safe_dump( { 'num_petitions' : num_petitions } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandRestrictedPetition( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.RESOLVE_PETITIONS def _threadDoGETJob( self, request ): petition = HC.app.Read( 'petition', self._service_key ) body = yaml.safe_dump( { 'petition' : petition } ) response_context = HC.ResponseContext( 200, body = body ) 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' ] if 'lifetime' in request.hydrus_args: lifetime = request.hydrus_args[ 'lifetime' ] else: lifetime = None registration_keys = HC.app.Read( 'registration_keys', self._service_key, num, title, lifetime ) body = yaml.safe_dump( { 'registration_keys' : registration_keys } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandRestrictedRepositoryFile( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.GET_DATA POST_PERMISSION = HC.POST_DATA RECORD_GET_DATA_USAGE = True RECORD_POST_DATA_USAGE = True 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? path = ServerFiles.GetPath( 'file', hash ) response_context = HC.ResponseContext( 200, path = path ) return response_context def _threadDoPOSTJob( self, request ): account = request.hydrus_account account_key = account.GetAccountKey() file_dict = request.hydrus_args file_dict[ 'ip' ] = request.getClientIP() HC.app.Write( 'file', self._service_key, account_key, file_dict ) response_context = HC.ResponseContext( 200 ) return response_context class HydrusResourceCommandRestrictedRepositoryThumbnail( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.GET_DATA RECORD_GET_DATA_USAGE = True 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? path = ServerFiles.GetPath( 'thumbnail', hash ) response_context = HC.ResponseContext( 200, path = path ) return response_context class HydrusResourceCommandRestrictedServices( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.GENERAL_ADMIN POST_PERMISSION = HC.GENERAL_ADMIN def _threadDoPOSTJob( self, request ): account = request.hydrus_account account_key = account.GetAccountKey() edit_log = request.hydrus_args[ 'edit_log' ] service_keys_to_access_keys = HC.app.Write( 'services', account_key, edit_log ) body = yaml.safe_dump( { 'service_keys_to_access_keys' : service_keys_to_access_keys } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandRestrictedServicesInfo( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.GENERAL_ADMIN POST_PERMISSION = HC.GENERAL_ADMIN def _threadDoGETJob( self, request ): services_info = HC.app.Read( 'services_info' ) body = yaml.safe_dump( { 'services_info' : services_info } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandRestrictedStats( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.GENERAL_ADMIN def _threadDoGETJob( self, request ): stats = HC.app.Read( 'stats', self._service_key ) body = yaml.safe_dump( { 'stats' : stats } ) response_context = HC.ResponseContext( 200, body = body ) return response_context class HydrusResourceCommandRestrictedUpdate( HydrusResourceCommandRestricted ): GET_PERMISSION = HC.GET_DATA POST_PERMISSION = HC.POST_DATA RECORD_GET_DATA_USAGE = True RECORD_POST_DATA_USAGE = True def _threadDoGETJob( self, request ): begin = request.hydrus_args[ 'begin' ] path = ServerFiles.GetUpdatePath( self._service_key, begin ) response_context = HC.ResponseContext( 200, path = path, is_yaml = True ) return response_context def _threadDoPOSTJob( self, request ): account = request.hydrus_account account_key = account.GetAccountKey() update = request.hydrus_args[ 'update' ] HC.app.Write( 'update', self._service_key, account_key, update ) response_context = HC.ResponseContext( 200 ) return response_context