def CheckPermission( self, permission ): if self._IsBanned(): raise HydrusExceptions.PermissionException( 'This account is banned!' ) if self._IsExpired(): raise HydrusExceptions.PermissionException( 'This account is expired.' ) if self._IsBytesExceeded(): raise HydrusExceptions.PermissionException( 'You have hit your data transfer limit, and cannot make any more requests for the month.' ) if self._IsRequestsExceeded(): raise HydrusExceptions.PermissionException( 'You have hit your requests limit, and cannot make any more requests for the month.' ) if not self._info[ 'account_type' ].HasPermission( permission ): raise HydrusExceptions.PermissionException( 'You do not have permission to do that.' )
def ProcessStartingAction( db_dir, action ): already_running = HydrusData.IsAlreadyRunning( db_dir, 'server' ) if action == 'start': if already_running: HydrusData.Print( 'The server is already running. Would you like to [s]top it, [r]estart it, or e[x]it?' ) answer = raw_input() if len( answer ) > 0: answer = answer[0] if answer == 's': return 'stop' elif answer == 'r': return 'restart' raise HydrusExceptions.PermissionException( 'Exiting!' ) else: return action elif action == 'stop': if already_running: return action else: raise HydrusExceptions.PermissionException( 'The server is not running, so it cannot be stopped!' ) elif action == 'restart': if already_running: return action else: return 'start'
def InitDB(self): try: def make_temp_files_deletable(function_called, path, traceback_gumpf): os.chmod(path, stat.S_IWRITE) try: function_called(path) # try again except: pass if os.path.exists(HC.TEMP_DIR): shutil.rmtree(HC.TEMP_DIR, onerror=make_temp_files_deletable) except: pass try: if not os.path.exists(HC.TEMP_DIR): os.mkdir(HC.TEMP_DIR) except: pass db_initialised = False while not db_initialised: try: self._db = ClientDB.DB() db_initialised = True except HydrusExceptions.DBAccessException as e: try: print(HC.u(e)) except: print(repr(HC.u(e))) message = 'This instance of the client had a problem connecting to the database, which probably means an old instance is still closing.' message += os.linesep * 2 message += 'If the old instance does not close for a _very_ long time, you can usually safely force-close it from task manager.' with ClientGUIDialogs.DialogYesNo( None, message, 'There was a problem connecting to the database.', yes_label='wait a bit, then try again', no_label='forget it') as dlg: if dlg.ShowModal() == wx.ID_YES: time.sleep(3) else: raise HydrusExceptions.PermissionException() threading.Thread(target=self._db.MainLoop, name='Database Main Loop').start()
def InitClientFilesManager(self): self.client_files_manager = ClientCaches.ClientFilesManager(self) missing_locations = self.client_files_manager.GetMissing() while len(missing_locations) > 0: with ClientGUITopLevelWindows.DialogManage( None, 'repair file system') as dlg: panel = ClientGUIScrolledPanelsManagement.RepairFileSystemPanel( dlg, missing_locations) dlg.SetPanel(panel) if dlg.ShowModal() == wx.ID_OK: self.client_files_manager = ClientCaches.ClientFilesManager( self) missing_locations = self.client_files_manager.GetMissing() else: raise HydrusExceptions.PermissionException( 'File system failed, user chose to quit.')
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!' ) account = HG.server_controller.server_session_manager.GetAccount( self._service_key, session_key ) request.hydrus_account = account return request
def _threadDoPOSTJob(self, request): services = request.hydrus_args['services'] unique_ports = {service.GetPort() for service in services} if len(unique_ports) < len(services): raise HydrusExceptions.PermissionException( 'It looks like some of those services share ports! Please give them unique ports!' ) if len(unique_ports) < services: pass with HG.dirty_object_lock: service_keys_to_access_keys = HG.server_controller.WriteSynchronous( 'services', request.hydrus_account, services) HG.server_controller.SetServices(services) body = HydrusNetwork.DumpToBodyString( {'service_keys_to_access_keys': service_keys_to_access_keys}) response_context = HydrusServerResources.ResponseContext(200, body=body) return response_context
def wx_code(): message = 'It looks like another instance of this client is already running, so this instance cannot start.' message += os.linesep * 2 message += 'If the old instance is closing and does not quit for a _very_ long time, it is usually safe to force-close it from task manager.' with ClientGUIDialogs.DialogYesNo( self._splash, message, 'The client is already running.', yes_label = 'wait a bit, then try again', no_label = 'forget it' ) as dlg: if dlg.ShowModal() != wx.ID_YES: raise HydrusExceptions.PermissionException()
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 InitCheckPassword(self): while True: with wx.PasswordEntryDialog(None, 'Enter your password', 'Enter password') as dlg: if dlg.ShowModal() == wx.ID_OK: if hashlib.sha256( dlg.GetValue()).digest() == HC.options['password']: break else: raise HydrusExceptions.PermissionException()
def wx_code_password(): while True: with wx.PasswordEntryDialog( self._splash, 'Enter your password', 'Enter password' ) as dlg: if dlg.ShowModal() == wx.ID_OK: # this can produce unicode with cyrillic or w/e keyboards, which hashlib can't handle password = HydrusData.ToByteString( dlg.GetValue() ) if hashlib.sha256( password ).digest() == self.options[ 'password' ]: break else: raise HydrusExceptions.PermissionException( 'Bad password check' )
def wx_code_password(): while True: with wx.PasswordEntryDialog(self._splash, 'Enter your password', 'Enter password') as dlg: if dlg.ShowModal() == wx.ID_OK: if hashlib.sha256(dlg.GetValue()).digest( ) == self._options['password']: break else: raise HydrusExceptions.PermissionException( 'Bad password check')
def CheckIfAdminPortInUse( self ): ( service_type, options ) = self.Read( 'service_info', HC.SERVER_ADMIN_KEY ) port = options[ 'port' ] already_bound = False try: connection = HydrusNetworking.GetLocalConnection( port ) connection.close() already_bound = True except: pass if already_bound: raise HydrusExceptions.PermissionException( 'Something was already bound to port ' + str( port ) )
def _threadDoGETJob( self, request ): subject_identifier = request.hydrus_args[ 'subject_identifier' ] if subject_identifier.HasAccountKey(): subject_account_key = subject_identifier.GetData() else: raise HydrusExceptions.PermissionException( 'I was expecting an account key, but did not get one!' ) subject_account = HG.server_controller.Read( 'account', self._service_key, subject_account_key ) account_info = HG.server_controller.Read( 'account_info', self._service_key, request.hydrus_account, subject_account ) body = HydrusNetwork.DumpToBodyString( { 'account_info' : account_info } ) response_context = HydrusServerResources.ResponseContext( 200, body = body ) return response_context
def ShutdownSiblingInstance(db_dir): port_found = False ports = HydrusData.GetSiblingProcessPorts(db_dir, 'server') if ports is None: raise HydrusExceptions.PermissionException( 'Could not figure out the existing server\'s ports, so could not shut it down!' ) for port in ports: try: connection = HydrusNetworking.GetLocalConnection(port, https=True) connection.request('GET', '/') response = connection.getresponse() response.read() server_name = response.getheader('Server') except: text = 'Could not contact existing server\'s port ' + str( port) + '!' text += os.linesep text += traceback.format_exc() raise HydrusExceptions.PermissionException(text) if 'server administration' in server_name: port_found = True HydrusData.Print(u'Sending shut down instruction\u2026') connection.request('POST', '/shutdown') response = connection.getresponse() result = response.read() if response.status != 200: text = 'When told to shut down, the existing server gave an error!' text += os.linesep text += result raise HydrusExceptions.PermissionException(text) time_waited = 0 while HydrusData.IsAlreadyRunning(db_dir, 'server'): time.sleep(1) time_waited += 1 if time_waited > 20: raise HydrusExceptions.PermissionException( 'Attempted to shut the existing server down, but it took too long!' ) break if not port_found: raise HydrusExceptions.PermissionException( 'The existing server did not have an administration service!') HydrusData.Print('The existing server is shut down!')
def Request(self, method, path_and_query, request_headers, body, report_hooks=[], response_to_path=False): if method == HC.GET: method_string = 'GET' elif method == HC.POST: method_string = 'POST' if 'User-Agent' not in request_headers: request_headers['User-Agent'] = 'hydrus/' + HC.u( HC.NETWORK_VERSION) # it is important to only send str, not unicode, to httplib # it uses += to extend the message body, which propagates the unicode (and thus fails) when # you try to push non-ascii bytes as the body (e.g. during a file upload!) method_string = str(method_string) path_and_query = str(path_and_query) request_headers = { str(k): str(v) for (k, v) in request_headers.items() } try: self._connection.request(method_string, path_and_query, headers=request_headers, body=body) response = self._connection.getresponse() except (httplib.CannotSendRequest, httplib.BadStatusLine): # for some reason, we can't send a request on the current connection, so let's make a new one and try again! self._RefreshConnection() self._connection.request(method_string, path_and_query, headers=request_headers, body=body) response = self._connection.getresponse() if response.status == 200 and response_to_path: (temp_path, size_of_response) = self._WriteResponseToPath( response, report_hooks) parsed_response = temp_path else: (parsed_response, size_of_response) = self._ParseResponse(response, report_hooks) response_headers = { k: v for (k, v) in response.getheaders() if k != 'set-cookie' } cookies = self._ParseCookies(response.getheader('set-cookie')) self._last_request_time = HC.GetNow() if response.status == 200: return (parsed_response, None, size_of_response, response_headers, cookies) elif response.status in (301, 302, 303, 307): location = response.getheader('Location') if location is None: raise Exception(parsed_response) else: url = location if ' ' in url: # some booru is giving daft redirect responses print(url) url = urllib.quote(url, safe='/?=&') print(url) if not url.startswith(self._scheme): # assume it is like 'index.php' or '/index.php', rather than 'http://blah.com/index.php' if url.startswith('/'): slash_sep = '' else: slash_sep = '/' url = self._scheme + '://' + self._host + slash_sep + url if response.status in (301, 307): # 301: moved permanently, repeat request # 307: moved temporarily, repeat request redirect_info = (method, url) elif response.status in (302, 303): # 302: moved temporarily, repeat request (except everyone treats it like 303 for no good f*****g reason) # 303: thanks, now go here with GET redirect_info = (HC.GET, url) return (parsed_response, redirect_info, size_of_response, response_headers, cookies) elif response.status == 304: raise HydrusExceptions.NotModifiedException() else: if response.status == 401: raise HydrusExceptions.PermissionException(parsed_response) elif response.status == 403: raise HydrusExceptions.ForbiddenException(parsed_response) elif response.status == 404: raise HydrusExceptions.NotFoundException(parsed_response) elif response.status == 426: raise HydrusExceptions.NetworkVersionException(parsed_response) elif response.status in (500, 501, 502, 503): raise Exception(parsed_response) else: raise Exception(parsed_response)
def Request( self, method, path_and_query, request_headers, body, report_hooks = None, temp_path = None ): if report_hooks is None: report_hooks = [] if method == HC.GET: method_string = 'GET' elif method == HC.POST: method_string = 'POST' if 'User-Agent' not in request_headers: request_headers[ 'User-Agent' ] = 'hydrus/' + str( HC.NETWORK_VERSION ) path_and_query = HydrusData.ToByteString( path_and_query ) request_headers = { str( k ) : str( v ) for ( k, v ) in request_headers.items() } response = self._GetResponse( method_string, path_and_query, request_headers, body ) ( parsed_response, size_of_response ) = self._ReadResponse( response, report_hooks, temp_path ) response_headers = { k : v for ( k, v ) in response.getheaders() if k != 'set-cookie' } cookies = self._ParseCookies( response.getheader( 'set-cookie' ) ) self._last_request_time = HydrusData.GetNow() if response.status == 200: return ( parsed_response, None, size_of_response, response_headers, cookies ) elif response.status in ( 301, 302, 303, 307 ): location = response.getheader( 'Location' ) if location is None: raise Exception( 'Received an invalid redirection response.' ) else: url = location if ', ' in url: url = url.split( ', ' )[0] elif ' ' in url: # some booru is giving daft redirect responses HydrusData.Print( url ) url = urllib.quote( HydrusData.ToByteString( url ), safe = '/?=&' ) HydrusData.Print( url ) if not url.startswith( self._scheme ): # assume it is like 'index.php' or '/index.php', rather than 'http://blah.com/index.php' if url.startswith( '/' ): slash_sep = '' else: slash_sep = '/' url = self._scheme + '://' + self._host + slash_sep + url if response.status in ( 301, 307 ): # 301: moved permanently, repeat request # 307: moved temporarily, repeat request redirect_info = ( method, url ) elif response.status in ( 302, 303 ): # 302: moved temporarily, repeat request (except everyone treats it like 303 for no good f*****g reason) # 303: thanks, now go here with GET redirect_info = ( HC.GET, url ) return ( parsed_response, redirect_info, size_of_response, response_headers, cookies ) elif response.status == 304: raise HydrusExceptions.NotModifiedException() else: if response.status == 401: raise HydrusExceptions.PermissionException( parsed_response ) elif response.status == 403: raise HydrusExceptions.ForbiddenException( parsed_response ) elif response.status == 404: raise HydrusExceptions.NotFoundException( parsed_response ) elif response.status == 419: raise HydrusExceptions.SessionException( parsed_response ) elif response.status == 426: raise HydrusExceptions.NetworkVersionException( parsed_response ) elif response.status in ( 500, 501, 502, 503 ): server_header = response.getheader( 'Server' ) if server_header is not None and 'hydrus' in server_header: hydrus_service = True else: hydrus_service = False if response.status == 503 and hydrus_service: raise HydrusExceptions.ServerBusyException( 'Server is busy, please try again later.' ) else: raise Exception( parsed_response ) else: raise Exception( parsed_response )
def GetStartingAction(): action = 'help' args = sys.argv[1:] if len(args) > 0: command = args[0] while command.startswith('-'): command = command[1:] if command == 'help': action = 'help' else: already_running = HydrusData.IsAlreadyRunning(HC.DB_DIR, 'server') if command == 'start': if already_running: raise HydrusExceptions.PermissionException( 'The server is already running!') else: action = 'start' elif command == 'stop': if already_running: action = 'stop' else: raise HydrusExceptions.PermissionException( 'The server is not running, so it cannot be stopped!') elif command == 'restart': if already_running: action = 'restart' else: action = 'start' else: already_running = HydrusData.IsAlreadyRunning(HC.DB_DIR, 'server') if not already_running: action = 'start' else: HydrusData.Print( 'The server is already running. Would you like to [s]top it, or [r]estart it?' ) answer = raw_input() if len(answer) > 0: answer = answer[0] if answer == 's': action = 'stop' elif answer == 'r': action = 'restart' return action