async def proxy(request: web.Request, handler: web.RequestHandler): try: req_start_time = time() if pydash.starts_with(request.path_qs, '/raven'): return await handler(request) service = Regex.best_match(await Regex.get_matched_paths(request.path, DB.get(request, service_controller.table))) await handle_service(service, request.remote) rate_limiter_rules = await RateLimiter.get_rule_by_service_id(str(service['_id']), DB.get_redis(request)) rate_limiter_rule = rate_limiter_rules[0] if rate_limiter_rules else None await handle_rate_limiter(request, str(service['_id']), rate_limiter_rule) breakers = await CircuitBreaker.get_by_service_id(str(service['_id']), DB.get(request, circuit_breaker_controller.table)) breaker = breakers[0] if breakers else None request_validators = await RequestValidator.get_by_service_id(str(service['_id']), DB.get(request, request_validator_controller.table)) request_validator = request_validators[0] if request_validators else None endpoint_cachers = not pydash.is_empty(service) and await EndpointCacher.get_by_service_id(str(service['_id']), DB.get_redis(request)) or None endpoint_cacher = endpoint_cachers[0] if endpoint_cachers else None await handle_request_validator(request_validator, json.loads(await request.text()), request.method) req, req_cache_hit = await handle_request(request, service, endpoint_cacher) checks = [] if not pydash.is_empty( breaker) and breaker['status'] == CircuitBreakerStatus.ON.name: if req['status'] in breaker['status_codes']: checks.append(handle_circuit_breaker( breaker, service, request, req)) else: await CircuitBreaker.incr_count(str(breaker['_id']), DB.get_redis(request)) queue_async_func.s({ 'func': 'Service.advance_target', 'args': [str(service['_id']), f'mongo:{service_controller.table}'], 'kwargs': {} }).apply_async() req_finish_time = time() req_elapsed_time = req_finish_time - req_start_time checks.append(handle_insights(request, req, str( service['_id']), req_elapsed_time, req_cache_hit)) await Async.all(checks) return web.Response( body=Bytes.decode_bytes( req['body_bytes']), status=req['status'], content_type=req['content_type'], headers=CIMultiDict( pydash.omit( req['headers'], 'Content-Type', 'Transfer-Encoding', 'Content-Encoding'))) except Exception as err: return Error.handle(err)
def _pad_data(data: str): """ appends padding to the provided data """ padder = padding.PKCS7(128).padder() padded_data = padder.update(Bytes.str_to_bytes(data)) padded_data += padder.finalize() return padded_data
def sign(message: object, private_key: str) -> str: """ signs a message @param message: (object) message to sign @param private_key: (str) private key to sign with """ private_key_bytes = serialization.load_pem_private_key( private_key.encode('utf-8'), password=None, backend=default_backend() ) message_bytes = Bytes.object_to_bytes(message) signature_bytes = private_key_bytes.sign( message_bytes, ec.ECDSA(hashes.SHA256()) ) return Bytes.encode_bytes(signature_bytes).decode('utf-8')
def verify(message: object, signature: str, public_key: str) -> bool: """ verfies message with digital signature @param message: (object) message to verify @param signature: (str) signature to verify message with @param public_key: (str) public key to verify message with """ try: public_key_bytes = serialization.load_pem_public_key( public_key.encode('utf-8'), backend=default_backend() ) signature_bytes = Bytes.decode_bytes(signature.encode('utf-8')) message_bytes = Bytes.object_to_bytes(message) public_key_bytes.verify( signature_bytes, message_bytes, ec.ECDSA(hashes.SHA256()) ) return True except InvalidSignature: return False
async def call(method=None, url=None, params=None, data=None, json=None, cookies=None, headers=None, auth=None): """ makes a request @returns: request response """ async with aiohttp.request(method=method, url=url, params=params, data=data, json=json, cookies=cookies, headers=headers, auth=auth) as response: return { 'headers': dict(response.headers), 'body_bytes': Bytes.encode_bytes(await response.read()).decode('utf-8'), 'body_text': await response.text(), 'content_length': response.content_length, 'content_type': response.content_type, 'cookies': dict(response.cookies), 'method': response.method, 'reason': response.reason, 'status': int(response.status), 'url': str(response.url), }
def encrypt( message: object, private_key: str, receiver_public_key: str) -> str: """ encrypts message @param message: (object) message to encrypt @param private_key: (str) private key to encrypt message with @param receiver_public_key: (str) public key of person able to decrypt message """ iv = '000000000000'.encode('utf-8') private_key_bytes = serialization.load_pem_private_key( private_key.encode('utf-8'), password=None, backend=default_backend() ) receiver_public_key = serialization.load_pem_public_key( receiver_public_key.encode('utf-8'), backend=default_backend() ) shared_key = private_key_bytes.exchange(ec.ECDH(), receiver_public_key) point = private_key_bytes.public_key().public_numbers().encode_point() xkdf = x963kdf.X963KDF( algorithm=hashes.SHA256(), length=32, sharedinfo=''.encode('utf-8'), backend=default_backend() ) key = xkdf.derive(shared_key) encryptor = Cipher( algorithms.AES(key), modes.GCM(iv), backend=default_backend() ).encryptor() padded_message = Crypt._pad_data(json.dumps(message)) ciphertext = encryptor.update(padded_message) + encryptor.finalize() complete_ciphertext = point + encryptor.tag + ciphertext return Bytes.encode_bytes(complete_ciphertext).decode('utf-8')
def decrypt(message: str, receiver_private_key: str) -> str: """ decrypts message @param message: (str) message to decrypt @param receiver_private_key: (str) private key to decrypt with """ message = Bytes.decode_bytes(message.encode('utf-8')) point = message[0:65] tag = message[65:81] ciphertext = message[81:] receiver_private_key_bytes = serialization.load_pem_private_key( receiver_private_key.encode('utf-8'), password=None, backend=default_backend() ) sender_public_numbers = ec.EllipticCurvePublicNumbers.from_encoded_point( ec.SECP256K1(), point) sender_public_key = sender_public_numbers.public_key(default_backend()) shared_key = receiver_private_key_bytes.exchange( ec.ECDH(), sender_public_key ) iv = '000000000000'.encode('utf-8') xkdf = x963kdf.X963KDF( algorithm=hashes.SHA256(), length=32, sharedinfo=''.encode('utf-8'), backend=default_backend() ) key = xkdf.derive(shared_key) decryptor = Cipher( algorithms.AES(key), modes.GCM(iv, tag), backend=default_backend() ).decryptor() dt = decryptor.update(ciphertext) + decryptor.finalize() return Crypt._unpad_data(dt).decode('utf-8')