def _performCall(self, parameters): if self.mode == 'PPMS API': response = self._sendToAPI(parameters) # check if we got a proper response, i.e. HTTP status code == 200 if not response.status_code == 200: raise Errors.APIError(True, False, msg='Error ' + str(response.status_code) + ': API didn\'t return a proper response') # check if there is some data in the response if response.text: return response.text else: raise Errors.APIError(False, True, msg='Empty response from API') elif self.mode == 'Proxy': response = self._sendToProxy(parameters) # the proxy may forward an exception or a proper response try: raise response except TypeError: return response else: raise Errors.FatalError( msg= 'Unknown communication method, must be \'PPMS API\' or \'Proxy\'' )
def checkKeys(self, required_keys): for key in required_keys: try: _ = self.options[key] except KeyError: raise Errors.FatalError(key + ' was not found in ' + self.option_file)
def _sendToProxy(self, param_dict): pickled_dict = pickle.dumps(param_dict, protocol=2) iv = Random.new().read(AES.block_size) AES_plainkey = self.SYSTEMoptions.getValue('AES_key').encode('utf8') AES_key = SHA256.new() AES_key.update(AES_plainkey) AES_key = AES_key.digest() encryptor = AES.new(AES_key, AES.MODE_CFB, iv) encrypted_dict = iv + encryptor.encrypt(pickled_dict) packed_dict = bytes(struct.pack('>I', len(encrypted_dict))) + encrypted_dict proxy_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: proxy_socket.connect( (self.SYSTEMoptions.getValue('proxy_address'), int(self.SYSTEMoptions.getValue('API_port')))) proxy_socket.sendall(packed_dict) except socket.error as e: raise Errors.APIError(msg=e) # From here we handle the encrypted response from the proxy encrypted_call = self._receive_data(proxy_socket) proxy_socket.close() iv_response = encrypted_call[:AES.block_size] encrypted_response = encrypted_call[AES.block_size:] decryptor = AES.new(AES_key, AES.MODE_CFB, iv_response) decrypted_response = decryptor.decrypt(encrypted_response) # try to catch wrong AES-keys at unpickle step with KeyError try: response = pickle.loads(decrypted_response) except KeyError: raise Errors.APIError( msg='Unpickle step failed, probably AES-keys don\'t match') return response
def __init__(self, mode, system_options=None): self.mode = mode # if we want to contact the Proxy, we need SystemOptions.txt for the AESkey and Proxy address:port if self.mode == 'Proxy': if system_options is not None: self.SYSTEMoptions = system_options required_keys = ('AES_key', 'proxy_address', 'API_port') self.SYSTEMoptions.checkKeys(required_keys) else: raise Errors.FatalError( msg= 'SystemOptions info not provided, only direct API calls possible' ) # if we want to contact the API directly, we need ProxyOptions for the APIkeys and URLs if self.mode == 'PPMS API': try: self.APIoptions = Options.OptionReader('ProxyOptions.txt') except: raise Errors.FatalError( msg='ProxyOptions.txt is missing, only Proxy calls possible' )
def setUserRight(self, system_id, user_login, user_right=None): valid_user_rights = ['A', 'N', 'S', 'D'] if not user_right: user_right = 'A' if user_right not in valid_user_rights: raise Errors.APIError( "User right abbreviation not valid! Must be 'A', 'N', 'S' or 'D'" ) parameters = { 'action': 'setright', 'id': str(system_id), 'login': user_login, 'type': user_right, 'API_type': 'PUMAPI', } self._performCall(parameters)
def _sendToAPI(self, parameters): header = {'Content-Type': 'application/x-www-form-urlencoded'} API_type = parameters.pop('API_type') if API_type == 'PUMAPI': parameters['apikey'] = self.APIoptions.getValue('PUMAPI_key') URL = self.APIoptions.getValue('PUMAPI_URL') elif API_type == 'API2': parameters['apikey'] = self.APIoptions.getValue('API2_key') URL = self.APIoptions.getValue('API2_URL') else: raise Errors.APIError( msg='Unknown API interface type, must be \'PUMAPI\' or \'API2\'' ) return requests.post(URL, headers=header, data=parameters)
def __init__(self, file_name, required_keys=()): self.option_file = os.path.join(sys.path[0], file_name) try: with open(self.option_file, 'r') as f: content = f.readlines() except FileNotFoundError: raise Errors.FatalError(file_name + ' not found!') self.options = {} for line in content: if not (line.startswith('#') or line in ['\n', '\r\n']): single_option = line.strip('\r\n').split('=') self.options[single_option[0].strip( ' ')] = single_option[1].strip(' ') self.checkKeys(required_keys)
def getUserRights(self, login=None, system_id=None): if not (login or system_id): raise Errors.APIError( msg='User login or system id have to be specified!') if login: parameters = { 'action': 'getuserrights', 'login': login, 'API_type': 'PUMAPI', 'format': 'csv', 'noheaders': 'true', } if system_id: parameters = { 'action': 'getsysrights', 'id': system_id, 'API_type': 'PUMAPI', 'format': 'csv', 'noheaders': 'true', } return self._performCall(parameters).split()
def getLastUsage(self, login=None, system_id=None): if not (login or system_id): raise Errors.APIError( msg='User login or system id have to be specified!') parameters = { 'action': 'getuserexp', 'API_type': 'PUMAPI', 'format': 'json', } if login: parameters['login'] = login if system_id: parameters['id'] = system_id try: response_json = self._performCall(parameters) except Errors.APIError as e: if e.empty_response: response_json = '{}' else: raise e return json.loads(response_json)