def load_pem_key(self, pem_key, password=None): """Method to load the key from string. Args: pem_key (str): Key to be loaded. password (str): Password for the key. """ for key in private_key_re.findall(if_bytes_to_unicode(pem_key)): key = if_unicode_to_bytes(key) password = if_unicode_to_bytes(password) self._private_key = serialization.load_pem_private_key( key, password=password, backend=default_backend() ) return for key in public_key_re.findall(if_bytes_to_unicode(pem_key)): key = if_unicode_to_bytes(key) password = if_unicode_to_bytes(password) self._public_key = serialization.load_pem_public_key( key, backend=default_backend() ) return raise ValueError('Invalid PEM Key')
def token(self): if self._token is not None and self._cached_token is None: self._cached_token = self._token.copy() self._cached_token['token'] = if_unicode_to_bytes(self._token_sig) \ + b'!!!!' + \ if_unicode_to_bytes(base64.b64encode( if_unicode_to_bytes(js.dumps(self._token)))) return self._cached_token
def load_pem_key(self, pem_key, password=None): for key in private_key_re.findall(if_bytes_to_unicode(pem_key)): key = if_unicode_to_bytes(key) password = if_unicode_to_bytes(password) self._private_key = serialization.load_pem_private_key( key, password=password, backend=default_backend()) return for key in public_key_re.findall(if_bytes_to_unicode(pem_key)): key = if_unicode_to_bytes(key) password = if_unicode_to_bytes(password) self._public_key = serialization.load_pem_public_key( key, backend=default_backend()) return raise ValueError('Invalid PEM Key')
def generate_private_key(self, bits=4096, password=None): """Method to generate a private RSA key. Args: bits (int): Key bit length. password (str): Key password. Returns: Unicode encoded private key. """ self._private_key = rsa.generate_private_key( public_exponent=65537, key_size=bits, backend=default_backend() ) self._public_key = None if password is not None: password = if_unicode_to_bytes(password) encryption_algorithm = serialization.BestAvailableEncryption( password ) else: encryption_algorithm = serialization.NoEncryption() return if_bytes_to_unicode(self._private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=encryption_algorithm ))
def request(app, method='GET', path='/', query_string='', headers={}, body=None, file_wrapper=None, wsgierrors=sys.stdout, protocol='http'): if not path.startswith('/'): raise ValueError("path must start with '/'") if query_string and query_string.startswith('?'): raise ValueError("query_string should not start with '?'") if '?' in path: raise ValueError('path may not contain a query string. Please use the ' 'query_string parameter instead.') env = {} env['REQUEST_METHOD'] = method.upper() env['HTTP_HOST'] = 'tachyonic.org' env['SCRIPT_NAME'] = '/wsgi' env['PATH_INFO'] = path env['SERVER_NAME'] = 'tachyonic.org' env['SERVER_PORT'] = '80' env['SRRVER_PROTOCOL'] = 'HTTP/1/1' env['QUERY_STRING'] = query_string env['wsgi.errors'] = wsgierrors env['wsgi.input'] = BytesIO() if body is not None: env['wsgi.input'].write(if_unicode_to_bytes(body)) env['wsgi.input'].seek(0) env['wsgi.multiprocess'] = True env['wsgi.multithread'] = True env['wsgi.run_once'] = False env['wsgi.url_scheme'] = protocol env['wsgi.version'] = (1, 0) for header in headers: if header.lower() == 'content-type': env['CONTENT_TYPE'] = headers[header] elif header.lower() == 'content-length': env['CONTENT_LENGTH'] = headers[header] else: wsgi_name = 'HTTP_' + header.upper().replace('-', '_') env[wsgi_name] = headers[header] srmock = StartResponseMock() validator = wsgiref.validate.validator(app) iterable = validator(env, srmock) result = Result(iterable, srmock.status, srmock.headers) if not srmock._called: raise Exception('Start Response not called') return result
def verify(self, signature, message): """Method to verify the authenticity of a signed message Args: signature (str): The message's signature. message (str): The cleartext message that was signed and for which authenticity is to be verified. """ if self._public_key is None and self._private_key is None: raise ValueError('No Public or Private Key Loaded') if self._public_key is None: self._public_key = self._private_key.public_key() message = if_unicode_to_bytes(message) signature = base64.b64decode(signature) try: self._public_key.verify( signature, message, padding.PSS( mgf=padding.MGF1(hashes.SHA512()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA512() ) return True except InvalidSignature: raise ValueError('RSA Verify Invalid Signature') from None
def encrypt(self, message): """Method to encrypt a message with the public Key. Args: message (str): Cleartext message to be encrypted. Returns: base64 encoded encrypted message. """ if self._public_key is None and self._private_key is None: raise ValueError('No Public or Private Key Loaded') if self._public_key is None: self._public_key = self._private_key.public_key() message = if_unicode_to_bytes(message) enc = self._public_key.encrypt( message, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) return if_bytes_to_unicode(base64.b64encode(enc))
def md5sum(val): """Returns an md5 hash as a hex digest Args: val (binary str): value to be hashed""" val = if_unicode_to_bytes(val) return md5(val).hexdigest()
def encrypt(self, message): """Method to encrypt a message with the symmetric Key. Args: message (str): Cleartext message to be encrypted. Returns: base64 encoded encrypted message. """ if self._key is None and self._iv is None: raise ValueError('No Key and Initialization vector Loaded') _padder = self._padding.padder() message = if_unicode_to_bytes(message) padded_data = _padder.update(message) + _padder.finalize() _cipher = Cipher(self._algorithm(self._key), self._modes(self._iv), backend=self._backend) _encryptor = _cipher.encryptor() _ct = _encryptor.update(padded_data) + _encryptor.finalize() return if_bytes_to_unicode(base64.b64encode(_ct))
def load_iv(self, iv): """Method to load the initialization vector from binary. Args: iv (str): Initialization vector to be loaded. """ self._iv = if_unicode_to_bytes(iv)
def new_token(self, user_id, username, domain=None, tenant_id=None, expire=None): """Create Token. This part of step 1 during the authentication after validation. Args: user_id (str): User ID username (str): Username. email (str): User email address. token (str): Unique token for specific user. domain_id (str): Current domain id. tenant_id (str): Current tenant id. """ self._token = {} if user_id is None: raise ValueError('Require user_id for new_token') if username is None: raise ValueError('Require username for new_token') # These are only set during valid login. # Unique user id. self._token['user_id'] = user_id # Unique username. self._token['username'] = username # Token creation datetime, format YYYY/MM/DD HH:MM:SS. self._token['creation'] = now() # Token expire datetime, format YYYY/MM/DD HH:MM:SS. if expire is None: expire = (now() + timedelta(seconds=self._token_expire)) self._token['expire'] = expire.strftime("%Y/%m/%d %H:%M:%S") else: self._token['expire'] = expire # Scope domain. self._token['domain'] = domain self._token['domain_id'] = domain_id(domain) # Scope tenant. self._token['tenant_id'] = tenant_id # Scope roles. self._token['roles'] = user_roles(user_id, domain, tenant_id) # Token Signature private_key = g.app.app_root.rstrip('/') + '/token.key' bytes_token = if_unicode_to_bytes(js.dumps(self._token)) self._token_sig = pki.sign(private_key, base64.b64encode(bytes_token)) return self._token_sig
def token(self): # Return serialized token. if not self.authenticated: raise AccessDeniedError("Credentials token missing") utc_expire = utc(self._credentials['expire']) if now() > utc_expire: raise AccessDeniedError('Auth Token Expired') bytes_token = if_unicode_to_bytes( js.dumps(self._credentials, indent=None)) b64_token = base64.b64encode(bytes_token) token_sig = if_unicode_to_bytes(self._rsakey.sign(b64_token)) token = if_bytes_to_unicode(token_sig + b'!!!!' + b64_token) if len(token) > 1280: raise ValueError("Auth Token exceeded 10KB" + " - Revise Assignments for credentials") return token
def sign(self, message): if self._private_key is None: raise ValueError('No Private Key Loaded') message = if_unicode_to_bytes(message) signature = self._private_key.sign( message, padding.PSS(mgf=padding.MGF1(hashes.SHA512()), salt_length=padding.PSS.MAX_LENGTH), hashes.SHA512()) return if_bytes_to_unicode(base64.b64encode(signature))
def body(self, obj): """Set Response Body. Accepts following objects: 'str', and 'bytes', if str will be encoded to bytes. file, iter like objects must return bytes. OrderedDict, dict and list will be translated json and encoded to 'UTF-8' Args: obj (object): Any valid object for response body. """ if isinstance(obj, ( str, bytes, )): # If Body is string, bytes. obj = if_unicode_to_bytes(obj) if self.content_type is None: self.content_type = self._DEFAULT_CONTENT_TYPE self._stream = obj elif isinstance(obj, ( OrderedDict, dict, list, tuple, )): # If JSON serializeable object. self.content_type = const.APPLICATION_JSON self._stream = if_unicode_to_bytes(js.dumps(obj)) elif hasattr(obj, 'json'): # If JSON serializeable object. self.content_type = const.APPLICATION_JSON self._stream = if_unicode_to_bytes(obj.json) elif hasattr(obj, 'read') or hasattr(obj, '__iter__'): # If body content behaves like file. if self.content_type is None: self.content_type = const.APPLICATION_OCTET_STREAM self._stream = obj else: raise ValueError('resource not returning acceptable object %s' % type(obj))
def parse_token(self, token): self._initial() token = if_unicode_to_bytes(token) signature, token = token.split(b'!!!!') self._token_sig = self._check_token(signature, token) self._token = js.loads(base64.b64decode(token)) self._token_sig = signature utc_now = now() utc_expire = utc(self._token['expire']) if utc_now > utc_expire: raise AccessDenied('Token Expired')
def load(self, reference): if self.redis is not None: reference = if_unicode_to_bytes(reference) ref = hashlib.md5(reference).hexdigest() name = 'cache:%s' % ref cached = self.redis.get(name) if cached is not None: return pickle.loads(cached) else: return None else: return None
def encrypt(self, message): if self._public_key is None and self._private_key is None: raise ValueError('No Public or Private Key Loaded') if self._public_key is None: self._public_key = self._private_key.public_key() message = if_unicode_to_bytes(message) enc = self._public_key.encrypt( message, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)) return if_bytes_to_unicode(base64.b64encode(enc))
def save(self): req = g.current_request content = if_unicode_to_bytes(js.dumps(self._session)) content = base64.b64encode(content) content = if_bytes_to_unicode(content) if len(content) > 1920: raise ValueError('SessionCookie size exceeded 15KB') cookie = self._session_id path = '/' + req.app.lstrip('/') req.response.set_cookie(cookie, content, path=path, domain=req.host, max_age=self._expire)
def token(self, token): # Load exisiting token token = if_unicode_to_bytes(token) signature, b64_token = token.split(b'!!!!') try: self._rsakey.verify(signature, b64_token) except ValueError as e: raise AccessDeniedError('Invalid Auth Token. %s' % e) decoded = js.loads(base64.b64decode(b64_token)) utc_expire = utc(decoded['expire']) if now() > utc_expire: raise AccessDeniedError('Auth Token Expired') self._credentials = decoded
def generate_private_key(self, bits=4096, password=None): self._private_key = rsa.generate_private_key(public_exponent=65537, key_size=bits, backend=default_backend()) self._public_key = None if password is not None: password = if_unicode_to_bytes(password) encryption_algorithm = serialization.BestAvailableEncryption( password) else: encryption_algorithm = serialization.NoEncryption() return if_bytes_to_unicode( self._private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=encryption_algorithm))
def verify(self, signature, message): if self._public_key is None and self._private_key is None: raise ValueError('No Public or Private Key Loaded') if self._public_key is None: self._public_key = self._private_key.public_key() message = if_unicode_to_bytes(message) signature = base64.b64decode(signature) try: self._public_key.verify( signature, message, padding.PSS(mgf=padding.MGF1(hashes.SHA512()), salt_length=padding.PSS.MAX_LENGTH), hashes.SHA512()) return True except InvalidSignature: raise ValueError('RSA Verify Invalid Signature') from None
def write(self, value): """Write bytes to response body. Args: value (bytes): Data to be written. Returns: int: The number of bytes written. """ value = if_unicode_to_bytes(value) if not isinstance(self._stream, BytesIO): self._stream = BytesIO() length = self._stream.write(value) if self.content_type is None: self.content_type = self._DEFAULT_CONTENT_TYPE return length
def sign(self, message): """Method to sign a message with the Private key. Args: message (str): Message to by cryptograpically signed Returns: base64 encoded signed message. """ if self._private_key is None: raise ValueError('No Private Key Loaded') message = if_unicode_to_bytes(message) signature = self._private_key.sign( message, padding.PSS( mgf=padding.MGF1(hashes.SHA512()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA512() ) return if_bytes_to_unicode(base64.b64encode(signature))
def conf_manager(srv): global clients_hash # add clients (address, secret, name) while True: with db() as conn: with conn.cursor() as crsr: clients = crsr.execute('SELECT INET6_NTOA(server) as server' + ', secret FROM' + ' calabiyau_nas').fetchall() string = str(clients).encode('utf-8') new_hash = md5(string).digest() if new_hash != clients_hash: if clients: for client in clients: host = client['server'] secret = if_unicode_to_bytes(client['secret']) srv.add_host(host, secret) else: srv.set_hosts({}) clients_hash = new_hash crsr.commit() sleep(10)
def store(self, reference, obj, expire): if self.redis is not None: reference = if_unicode_to_bytes(reference) ref = hashlib.md5(reference).hexdigest() name = 'cache:%s' % ref self.redis.set(name, pickle.dumps(obj), ex=expire)
def etagger(*args): to_hash = b"".join([if_unicode_to_bytes(str(arg) or b'') for arg in args]) if to_hash != b'': return md5sum(to_hash)
def request(client, method, url, params={}, data=None, headers={}, stream=False, **kwargs): with Timer() as elapsed: method = method.upper() headers = headers.copy() params = params.copy() try: _cache_engine = Cache() except NoContextError: _cache_engine = None try: if g.current_request.user_token: headers['X-Auth-Token'] = g.current_request.user_token if g.current_request.context_domain: headers['X-Domain'] = g.current_request.context_domain if g.current_request.context_tenant_id: headers['X-Tenant-Id'] = g.current_request.context_tenant_id except NoContextError: pass for kwarg in kwargs: headers[kwarg] = kwargs if data is not None: if hasattr(data, 'json'): data = data.json elif isinstance(data, (dict, list, OrderedDict)): data = js.dumps(data) data = if_unicode_to_bytes(data) if isinstance(data, bytes): headers['Content-Length'] = str(len(data)) cached = None if (_cache_engine and stream is False and method == 'GET' and data is None): if isinstance(params, dict): cache_params = list(orderdict(params).values()) if isinstance(headers, dict): cache_headers = list(orderdict(headers).values()) cache_key = (method, url, cache_params, cache_headers) cache_key = str(md5sum(pickle.dumps(cache_key))) cached = _cache_engine.load(cache_key) if cached is not None: cache_control = parse_cache_control_header( cached.headers.get('Cache-Control')) max_age = cache_control.max_age date = cached.headers.get('Date') etag = cached.headers.get('Etag') date = utc(date) current = now() diff = (current - date).total_seconds() if cache_control.no_cache: # If no-cache revalidate. headers['If-None-Match'] = etag elif max_age and diff < int(max_age): # If not expired, use cache. _debug(method, url, params, data, headers, cached.headers, cached.content, cached.status_code, elapsed(), 'Memory') return cached else: # If expired, revalidate.. headers['If-None-Match'] = etag try: response = Response( client._s.request(method.upper(), url, params=params, data=data, headers=headers, stream=stream)) if (_cache_engine and cached is not None and response.status_code == 304): _debug(method, url, params, data, headers, cached.headers, cached.content, cached.status_code, elapsed(), 'Validated (304)') return cached if response.status_code >= 400: try: title = None description = None if 'error' in response.json: error = response.json['error'] try: title = error.get('title') description = error.get('description') except AttributeError: pass raise HTTPError(response.status_code, description, title) except HTTPClientContentDecodingError: raise HTTPError(response.status_code) if _cache_engine and stream is False and method == 'GET': if response.status_code == 200: cache_control = parse_cache_control_header( response.headers.get('Cache-Control')) if (not cache_control.no_store and cache_control.max_age and response.headers.get('Etag') and response.headers.get('Date') and data is None): _cache_engine.store(cache_key, response, 604800) except requests.exceptions.InvalidHeader as e: raise HTTPClientInvalidHeader(e) except requests.exceptions.InvalidURL as e: raise HTTPClientInvalidURL(e) except requests.exceptions.InvalidSchema as e: raise HTTPClientInvalidSchema(e) except requests.exceptions.MissingSchema as e: raise HTTPClientMissingSchema(e) except requests.exceptions.ConnectionError as e: raise HTTPClientConnectionError(e) except requests.exceptions.ProxyError as e: raise HTTPClientProxyError(e) except requests.exceptions.SSLError as e: raise HTTPClientSSLError(e) except requests.exceptions.Timeout as e: raise HTTPClientTimeoutError(e) except requests.exceptions.ConnectTimeout as e: raise HTTPClientConnectTimeoutError(e) except requests.exceptions.ReadTimeout as e: raise HTTPClientReadTimeoutError(e) except requests.exceptions.HTTPError as e: raise HTTPError(e.response.status_code, e) _debug(method, url, params, data, headers, response.headers, response.content, response.status_code, elapsed()) return response
def request(client, method, url, params={}, data=None, headers={}, stream=False, endpoint=None, **kwargs): if endpoint is None: endpoint = url with Timer() as elapsed: method = method.upper() headers = headers.copy() params = params.copy() try: _cache_engine = Cache() except NoContextError: _cache_engine = None for kwarg in kwargs: # NOTE(cfrademan): # Generally headers have '-' not '_'. Also kwargs # cannot contain '-'. if kwargs[kwarg] is not None: header = kwarg.replace('_', '-') headers[header] = str(kwargs[kwarg]) if data is not None: if hasattr(data, 'json'): data = data.json elif isinstance(data, (dict, list, OrderedDict)): data = js.dumps(data) data = if_unicode_to_bytes(data) if isinstance(data, bytes): headers['Content-Length'] = str(len(data)) cached = None if (_cache_engine and stream is False and method == 'GET' and data is None): if isinstance(params, dict): cache_params = list(orderdict(params).values()) if isinstance(headers, dict): cache_headers = list(orderdict(headers).values()) cache_key = (method, url, cache_params, cache_headers) cache_key = str(md5sum(pickle.dumps(cache_key))) cached = _cache_engine.load(cache_key) if cached is not None: cache_control = parse_cache_control_header( cached.headers.get('Cache-Control')) max_age = cache_control.max_age date = cached.headers.get('Date') etag = cached.headers.get('Etag') date = utc(date) current = now() diff = (current - date).total_seconds() if cache_control.no_cache: # If no-cache revalidate. headers['If-None-Match'] = etag elif max_age and diff < int(max_age): # If not expired, use cache. _debug(method, url, params, data, headers, cached.headers, cached.content, cached.status_code, elapsed(), 'Memory') return cached else: # If expired, revalidate.. headers['If-None-Match'] = etag try: # response = Response(client._s.request(method.upper(), # url, # params=params, # data=data, # headers=headers, # stream=stream)) # NOTE(cfrademan): Using prepared requests, because we need to # no Transfer Encoding chunked, and expect Content-Length... # Chunked encoding is not well supported uploading to WSGI app. prepped = client._s.prepare_request( requests.Request(method.upper(), url, params=params, data=data, headers=headers)) if 'Content-Length' in prepped.headers: if 'Transfer-Encoding' in prepped.headers: del prepped.headers['Transfer-Encoding'] response = Response(client._s.send(prepped, stream=stream)) if (_cache_engine and cached is not None and response.status_code == 304): _debug(method, url, params, data, headers, cached.headers, cached.content, cached.status_code, elapsed(), 'Validated (304)') return cached if response.status_code >= 400: if 'X-Expired-Token' in response.headers: raise TokenExpiredError() try: title = None description = None if ('json' in response.content_type.lower() and 'error' in response.json): error = response.json['error'] try: title = error.get('title') description = error.get('description') if endpoint is not None: title += " (%s)" % endpoint except AttributeError: if endpoint is not None: description = " Endpoint: %s" % endpoint else: if endpoint is not None: description = " Endpoint: %s" % endpoint if stream is True: _debug(method, url, params, data, headers, response.headers, None, response.status_code, elapsed()) else: _debug(method, url, params, data, headers, response.headers, response.content, response.status_code, elapsed()) raise HTTPError(response.status_code, description, title) except HTTPClientContentDecodingError: if endpoint is not None: description = 'Endpoint: %s' raise HTTPError(response.status_code, description=description) from None else: raise HTTPError(response.status_code) from None if _cache_engine and stream is False and method == 'GET': if response.status_code == 200: cache_control = parse_cache_control_header( response.headers.get('Cache-Control')) if (not cache_control.no_store and cache_control.max_age and response.headers.get('Etag') and response.headers.get('Date') and data is None): _cache_engine.store(cache_key, response, 604800) except requests.exceptions.InvalidHeader as e: e = append_to_error(e, endpoint) raise HTTPClientInvalidHeader(e) except requests.exceptions.InvalidURL as e: e = append_to_error(e, endpoint) raise HTTPClientInvalidURL(e) except requests.exceptions.InvalidSchema as e: e = append_to_error(e, endpoint) raise HTTPClientInvalidSchema(e) except requests.exceptions.MissingSchema as e: e = append_to_error(e, endpoint) raise HTTPClientMissingSchema(e) except requests.exceptions.ConnectionError as e: e = append_to_error(e, endpoint) log.critical(e) raise HTTPClientConnectionError( "API Connection error to '%s' (%s)" % ( url, endpoint, )) except requests.exceptions.ProxyError as e: e = append_to_error(e, endpoint) log.critical(e) raise HTTPClientProxyError("API proxy error to '%s' (%s)" % ( url, endpoint, )) except requests.exceptions.SSLError as e: e = append_to_error(e, endpoint) log.critical(e) raise HTTPClientSSLError("API SSL error to '%s' (%s)" % ( url, endpoint, )) except requests.exceptions.Timeout as e: e = append_to_error(e, endpoint) log.critical(e) raise HTTPClientTimeoutError( "API connection timeout to '%s' (%s)" % ( url, endpoint, )) except requests.exceptions.ConnectTimeout as e: e = append_to_error(e, endpoint) log.critical(e) raise HTTPClientConnectTimeoutError( "API connect timeout to '%s' (%s)" % ( url, endpoint, )) except requests.exceptions.ReadTimeout as e: e = append_to_error(e, endpoint) log.critical(e) raise HTTPClientReadTimeoutError("API read timeout to '%s' (%s)" % ( url, endpoint, )) except requests.exceptions.HTTPError as e: e = append_to_error(e, endpoint) raise HTTPError(e.response.status_code, e) if stream is True: _debug(method, url, params, data, headers, response.headers, None, response.status_code, elapsed()) else: _debug(method, url, params, data, headers, response.headers, response.content, response.status_code, elapsed()) return response
def request(method, uri, data, headers={}, auth=None, timeout=(2, 8), verify=True, cert=None): with Timer() as elapsed: method = method.upper() cache = Cache() if data is not None: if hasattr(data, 'json'): data = data.json elif isinstance(data, (dict, list, OrderedDict)): data = js.dumps(data) data = if_unicode_to_bytes(data) host = host_from_uri(uri) cache_obj = str(method) + str(uri) + str(data) cached = cache.load(cache_obj) if cached is not None: return Response(cached) try: session = sessions[host] log.debug("Using exisiting session: '%s'" % host) except KeyError: session = sessions[host] = requests.Session() if data is None: data = '' headers['User-Agent'] = __identity__ headers['Content-Length'] = str(len(data)) request = requests.Request(method, uri, data=data, headers=headers, auth=auth) session_request = session.prepare_request(request) response = session.send(session_request, timeout=timeout, verify=verify, cert=cert) _debug(method, uri, data, headers, response.headers, response.content, response.status_code, elapsed()) if 'Cache-Control' in response.headers: cache_control = parse_cache_control_header( response.headers['cache-control']) if cache_control.max_age is not None: cache.store(cache_obj, response, int(cache_control.max_age)) return Response(response)