async def oauth_callback(request): logger = request.app.logger bot = request.app.bot config = settings.EVERNOTE['basic_access'] params = parse_qs(request.query_string) callback_key = params.get('key', [''])[0] session_key = params.get('session_key')[0] try: session = StartSession.get({'oauth_data.callback_key': callback_key}) user_data = session.data['user'] first_name = user_data['first_name'] last_name = user_data['last_name'] username = user_data['username'] user = User(id=session.id, name="{0} {1}".format(first_name, last_name), username=username, telegram_chat_id=session.data['chat_id'], mode='multiple_notes', places={}, settings={'evernote_access': 'basic'}) except ModelNotFound as e: logger.error(e, exc_info=1) return web.HTTPForbidden() if session.key != session_key: text = "Session is expired. Please, send /start command to create new session" asyncio.ensure_future(bot.api.sendMessage(user.telegram_chat_id, text)) return web.HTTPFound(bot.url) try: if params.get('oauth_verifier'): future = asyncio.ensure_future( bot.evernote_api.get_access_token( config['key'], config['secret'], session.oauth_data['oauth_token'], session.oauth_data['oauth_token_secret'], params['oauth_verifier'][0])) future.add_done_callback( functools.partial(set_access_token, bot, user)) text = 'Evernote account is connected.\nFrom now you can just send message and note be created.' asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text)) user.save() else: # User decline access logger.info('User declined access. No access token =(') text = "We are sorry, but you declined authorization 😢" asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text)) except TokenRequestDenied as e: logger.error(e, exc_info=1) text = "We are sorry, but we have some problems with Evernote connection. Please try again later" asyncio.ensure_future(bot.api.sendMessage(user.telegram_chat_id, text)) except Exception as e: logger.fatal(e, exc_info=1) text = "Oops. Unknown error. Our best specialist already working to fix it" if user: asyncio.ensure_future( bot.api.sendMessage(user.telegram_chat_id, text)) return web.HTTPFound(bot.url)
async def credential_exchange_send_bound_offer(request: web.BaseRequest): """ Request handler for sending bound credential offer. A holder initiates this sequence with a credential proposal; this message responds with an offer bound to the proposal. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context = request.app["request_context"] outbound_handler = request.app["outbound_message_router"] credential_exchange_id = request.match_info["cred_ex_id"] try: cred_ex_record = await V10CredentialExchange.retrieve_by_id( context, credential_exchange_id) except StorageNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err connection_record = None connection_id = cred_ex_record.connection_id try: if cred_ex_record.state != ( V10CredentialExchange.STATE_PROPOSAL_RECEIVED ): # check state here: manager call creates free offers too raise CredentialManagerError( f"Credential exchange {cred_ex_record.credential_exchange_id} " f"in {cred_ex_record.state} state " f"(must be {V10CredentialExchange.STATE_PROPOSAL_RECEIVED})") connection_record = await ConnectionRecord.retrieve_by_id( context, connection_id) if not connection_record.is_ready: raise web.HTTPForbidden( reason=f"Connection {connection_id} not ready") credential_manager = CredentialManager(context) ( cred_ex_record, credential_offer_message, ) = await credential_manager.create_offer(cred_ex_record, comment=None) result = cred_ex_record.serialize() except (StorageError, BaseModelError, CredentialManagerError, LedgerError) as err: await internal_error( err, web.HTTPBadRequest, cred_ex_record or connection_record, outbound_handler, ) await outbound_handler(credential_offer_message, connection_id=connection_id) trace_event( context.settings, credential_offer_message, outcome="credential_exchange_send_bound_offer.END", perf_counter=r_time, ) return web.json_response(result)
async def wallet_did_list(request: web.BaseRequest): """ Request handler for searching wallet DIDs. Args: request: aiohttp request object Returns: The DID list response """ context: AdminRequestContext = request["context"] session = await context.session() wallet = session.inject(BaseWallet, required=False) if not wallet: raise web.HTTPForbidden(reason="No wallet available") filter_did = request.query.get("did") filter_verkey = request.query.get("verkey") filter_posture = DIDPosture.get(request.query.get("posture")) results = [] public_did_info = await wallet.get_public_did() posted_did_infos = await wallet.get_posted_dids() if filter_posture is DIDPosture.PUBLIC: if (public_did_info and (not filter_verkey or public_did_info.verkey == filter_verkey) and (not filter_did or public_did_info.did == filter_did)): results.append(format_did_info(public_did_info)) elif filter_posture is DIDPosture.POSTED: results = [] for info in posted_did_infos: if (not filter_verkey or info.verkey == filter_verkey) and ( not filter_did or info.did == filter_did): results.append(format_did_info(info)) elif filter_did: try: info = await wallet.get_local_did(filter_did) except WalletError: # badly formatted DID or record not found info = None if (info and (not filter_verkey or info.verkey == filter_verkey) and (filter_posture is None or (filter_posture is DIDPosture.WALLET_ONLY and not info.metadata.get("posted")))): results.append(format_did_info(info)) elif filter_verkey: try: info = await wallet.get_local_did_for_verkey(filter_verkey) except WalletError: info = None if info and (filter_posture is None or (filter_posture is DID_POSTURE.WALLET_ONLY and not info.metadata.get("posted"))): results.append(format_did_info(info)) else: dids = await wallet.get_local_dids() results = [ format_did_info(info) for info in dids if filter_posture is None or DIDPosture.get(info.metadata) is DIDPosture.WALLET_ONLY ] results.sort(key=lambda info: (DIDPosture.get(info["posture"]).ordinal, info["did"])) return web.json_response({"results": results})
async def credential_exchange_store(request: web.BaseRequest): """ Request handler for storing credential. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context = request.app["request_context"] outbound_handler = request.app["outbound_message_router"] try: body = await request.json() or {} credential_id = body.get("credential_id") except JSONDecodeError: credential_id = None credential_exchange_id = request.match_info["cred_ex_id"] try: cred_ex_record = await V10CredentialExchange.retrieve_by_id( context, credential_exchange_id) except StorageNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err connection_record = None connection_id = cred_ex_record.connection_id try: connection_record = await ConnectionRecord.retrieve_by_id( context, connection_id) if not connection_record.is_ready: raise web.HTTPForbidden( reason=f"Connection {connection_id} not ready") credential_manager = CredentialManager(context) ( cred_ex_record, credential_stored_message, ) = await credential_manager.store_credential(cred_ex_record, credential_id) result = cred_ex_record.serialize() except (StorageError, CredentialManagerError, BaseModelError) as err: await internal_error( err, web.HTTPBadRequest, cred_ex_record or connection_record, outbound_handler, ) await outbound_handler(credential_stored_message, connection_id=connection_id) trace_event( context.settings, credential_stored_message, outcome="credential_exchange_store.END", perf_counter=r_time, ) return web.json_response(result)
async def credential_exchange_send_proposal(request: web.BaseRequest): """ Request handler for sending credential proposal. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context = request.app["request_context"] outbound_handler = request.app["outbound_message_router"] body = await request.json() connection_id = body.get("connection_id") comment = body.get("comment") preview_spec = body.get("credential_proposal") auto_remove = body.get("auto_remove") trace_msg = body.get("trace") connection_record = None cred_ex_record = None try: preview = CredentialPreview.deserialize( preview_spec) if preview_spec else None connection_record = await ConnectionRecord.retrieve_by_id( context, connection_id) if not connection_record.is_ready: raise web.HTTPForbidden( reason=f"Connection {connection_id} not ready") credential_manager = CredentialManager(context) cred_ex_record = await credential_manager.create_proposal( connection_id, comment=comment, credential_preview=preview, auto_remove=auto_remove, trace=trace_msg, **{t: body.get(t) for t in CRED_DEF_TAGS if body.get(t)}, ) credential_proposal = CredentialProposal.deserialize( cred_ex_record.credential_proposal_dict) result = cred_ex_record.serialize() except (BaseModelError, StorageError) as err: await internal_error( err, web.HTTPBadRequest, cred_ex_record or connection_record, outbound_handler, ) await outbound_handler( credential_proposal, connection_id=connection_id, ) trace_event( context.settings, credential_proposal, outcome="credential_exchange_send_proposal.END", perf_counter=r_time, ) return web.json_response(result)
async def create_bot_seek(request): auth = request.headers.get("Authorization") if auth is None: return web.HTTPForbidden() token = auth[auth.find("Bearer") + 7:] if token not in BOT_TOKENS: log.error("BOT account auth with token %s failed" % token) return web.HTTPForbidden() user_agent = request.headers.get("User-Agent") username = user_agent[user_agent.find("user:"******"users"] seeks = request.app["seeks"] sockets = request.app["lobbysockets"] bot_player = users[username] log.info("+++ %s created %s seek" % (bot_player.username, data["variant"])) # Try to create BOT vs BOT game to test TV test_TV = True matching_seek = None if test_TV: for seek in seeks.values(): if seek.variant == data["variant"] and seek.user.bot and seek.user.online() and seek.user.username != username and seek.level > 0: log.debug("MATCHING BOT SEEK %s FOUND!" % seek.id) matching_seek = seek break if matching_seek is None: seek = None for existing_seek in seeks.values(): if existing_seek.user == bot_player and existing_seek.variant == data["variant"]: seek = existing_seek break if seek is None: seek = Seek(bot_player, data["variant"]) seeks[seek.id] = seek bot_player.seeks[seek.id] = seek # inform others await lobby_broadcast(sockets, get_seeks(seeks)) else: games = request.app["games"] response = await new_game(request.app, bot_player, matching_seek.id) gameId = response["gameId"] game = games[gameId] chall = challenge(seek, gameId) await seek.user.event_queue.put(chall) seek.user.game_queues[gameId] = asyncio.Queue() await bot_player.event_queue.put(chall) bot_player.game_queues[gameId] = asyncio.Queue() await seek.user.event_queue.put(game.game_start) await bot_player.event_queue.put(game.game_start) return web.json_response({"ok": True})
async def expect_handler(request): if request.version == HttpVersion11: if auth_err: raise web.HTTPForbidden() request.writer.write(b"HTTP/1.1 100 Continue\r\n\r\n")
async def set_session_context(self): # noqa session_token_name = self.request.app.config.session_key session_token = self.request.cookies.get(session_token_name, None) session_ttl = self.request.app.config.session_ttl if not session_token and self.needs_session: raise web.HTTPUnauthorized(reason='No session token found') if session_token and not self.needs_session and self.operation in self.disallow_authed: raise web.HTTPConflict(reason='Public access resource only') if session_token: if self.request.path == '/actor/login/': self.session_ctxt = MappingProxyType({}) return try: actor_id = self.request.app.commons.decrypt(session_token, ttl=session_ttl) except InvalidToken: resp = web.HTTPForbidden( reason='Session token invalid or expired') resp.del_cookie(session_token_name) raise resp self.is_authed = True account_details_key = self.request.app.config.account_details_key.format( actor_id) workspaces_key = self.request.app.config.workspaces_key.format( actor_id) roles_key = self.request.app.config.roles_key.format(actor_id) if not self.needs_session and self.forced_logout: # erase the session aka forced logout if this is an authed request await self.request.app.redis_cli.delete( account_details_key, roles_key) self.session_ctxt = MappingProxyType({}) self.delete_session_cookie = True return pipe = self.request.app.redis_cli.pipeline() pipe.hgetall(account_details_key) pipe.smembers(workspaces_key) pipe.smembers(roles_key) session_ctxt, workspaces, roles = await pipe.execute() if not session_ctxt: # session cookie is valid, but not pointing to any active account resp = web.HTTPUnauthorized(reason='Unknown actor') resp.actor_id = actor_id raise resp if session_ctxt['workspace'] == '-1' and 'Admin' not in roles: raise web.HTTPUnauthorized( reason='Actor not assigned to any workspace') if not session_ctxt: # most likely session invalidated by removing session context from cache raise web.HTTPUnauthorized(reason='Session has been shut down') session_ctxt['phone_confirmed'] = int( session_ctxt['phone_confirmed']) session_ctxt['email_confirmed'] = int( session_ctxt['email_confirmed']) session_ctxt['workspaces'] = BracketedFrozenset(workspaces) session_ctxt['roles'] = BracketedFrozenset(roles) else: session_ctxt = {} self._session_ctxt = session_ctxt self.session_ctxt = MappingProxyType(self._session_ctxt)
async def credential_exchange_send_free_offer(request: web.BaseRequest): """ Request handler for sending free credential offer. An issuer initiates a such a credential offer, free from any holder-initiated corresponding credential proposal with preview. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context = request.app["request_context"] outbound_handler = request.app["outbound_message_router"] body = await request.json() connection_id = body.get("connection_id") cred_def_id = body.get("cred_def_id") if not cred_def_id: raise web.HTTPBadRequest(reason="cred_def_id is required") auto_issue = body.get( "auto_issue", context.settings.get("debug.auto_respond_credential_request")) auto_remove = body.get("auto_remove") comment = body.get("comment") preview_spec = body.get("credential_preview") if not preview_spec: raise web.HTTPBadRequest(reason=("Missing credential_preview")) trace_msg = body.get("trace") try: connection_record = await ConnectionRecord.retrieve_by_id( context, connection_id) except StorageNotFoundError: raise web.HTTPBadRequest() if not connection_record.is_ready: raise web.HTTPForbidden() credential_preview = CredentialPreview.deserialize(preview_spec) credential_proposal = CredentialProposal( comment=comment, credential_proposal=credential_preview, cred_def_id=cred_def_id, ) credential_proposal.assign_trace_decorator( context.settings, trace_msg, ) credential_proposal_dict = credential_proposal.serialize() credential_exchange_record = V10CredentialExchange( connection_id=connection_id, initiator=V10CredentialExchange.INITIATOR_SELF, credential_definition_id=cred_def_id, credential_proposal_dict=credential_proposal_dict, auto_issue=auto_issue, auto_remove=auto_remove, trace=trace_msg, ) credential_manager = CredentialManager(context) ( credential_exchange_record, credential_offer_message, ) = await credential_manager.create_offer(credential_exchange_record, comment=comment) await outbound_handler(credential_offer_message, connection_id=connection_id) trace_event( context.settings, credential_offer_message, outcome="credential_exchange_send_free_offer.END", perf_counter=r_time, ) return web.json_response(credential_exchange_record.serialize())
async def presentation_exchange_send_presentation(request: web.BaseRequest): """ Request handler for sending a presentation. Args: request: aiohttp request object Returns: The presentation exchange details """ r_time = get_timer() context: AdminRequestContext = request["context"] outbound_handler = request.app["outbound_message_router"] presentation_exchange_id = request.match_info["pres_ex_id"] session = await context.session() pres_ex_record = await V10PresentationExchange.retrieve_by_id( session, presentation_exchange_id) if pres_ex_record.state != ( V10PresentationExchange.STATE_REQUEST_RECEIVED): raise web.HTTPBadRequest(reason=( f"Presentation exchange {presentation_exchange_id} " f"in {pres_ex_record.state} state " f"(must be {V10PresentationExchange.STATE_REQUEST_RECEIVED})")) body = await request.json() connection_id = pres_ex_record.connection_id try: connection_record = await ConnRecord.retrieve_by_id( session, connection_id) except StorageNotFoundError as err: raise web.HTTPBadRequest(reason=err.roll_up) from err if not connection_record.is_ready: raise web.HTTPForbidden(reason=f"Connection {connection_id} not ready") presentation_manager = PresentationManager(session) try: ( pres_ex_record, presentation_message, ) = await presentation_manager.create_presentation( pres_ex_record, { "self_attested_attributes": body.get("self_attested_attributes"), "requested_attributes": body.get("requested_attributes"), "requested_predicates": body.get("requested_predicates"), }, comment=body.get("comment"), ) result = pres_ex_record.serialize() except ( BaseModelError, IndyHolderError, LedgerError, StorageError, WalletNotFoundError, ) as err: await internal_error( err, web.HTTPBadRequest, pres_ex_record or connection_record, outbound_handler, ) trace_msg = body.get("trace") presentation_message.assign_trace_decorator( session.settings, trace_msg, ) await outbound_handler(presentation_message, connection_id=connection_id) trace_event( session.settings, presentation_message, outcome="presentation_exchange_send_request.END", perf_counter=r_time, ) return web.json_response(result)
def _preflight_handler(self, request: web.Request): """CORS preflight request handler""" # Handle according to part 6.2 of the CORS specification. origin = request.headers.get(hdrs.ORIGIN) if origin is None: # Terminate CORS according to CORS 6.2.1. raise web.HTTPForbidden( text="CORS preflight request failed: " "origin header is not specified in the request") # CORS 6.2.3. Doing it out of order is not an error. request_method = self._parse_request_method(request) # CORS 6.2.5. Doing it out of order is not an error. try: config = \ yield from self._router_adapter.get_preflight_request_config( request, origin, request_method) except KeyError: raise web.HTTPForbidden( text="CORS preflight request failed: " "request method {!r} is not allowed " "for {!r} origin".format(request_method, origin)) if not config: # No allowed origins for the route. # Terminate CORS according to CORS 6.2.1. raise web.HTTPForbidden(text="CORS preflight request failed: " "no origins are allowed") options = config.get(origin, config.get("*")) if options is None: # No configuration for the origin - deny. # Terminate CORS according to CORS 6.2.2. raise web.HTTPForbidden( text="CORS preflight request failed: " "origin '{}' is not allowed".format(origin)) # CORS 6.2.4 request_headers = self._parse_request_headers(request) # CORS 6.2.6 if options.allow_headers == "*": pass else: disallowed_headers = request_headers - options.allow_headers if disallowed_headers: raise web.HTTPForbidden(text="CORS preflight request failed: " "headers are not allowed: {}".format( ", ".join(disallowed_headers))) # Ok, CORS actual request with specified in the preflight request # parameters is allowed. # Set appropriate headers and return 200 response. response = web.Response() # CORS 6.2.7 response.headers[hdrs.ACCESS_CONTROL_ALLOW_ORIGIN] = origin if options.allow_credentials: # Set allowed credentials. response.headers[hdrs.ACCESS_CONTROL_ALLOW_CREDENTIALS] = _TRUE # CORS 6.2.8 if options.max_age is not None: response.headers[hdrs.ACCESS_CONTROL_MAX_AGE] = \ str(options.max_age) # CORS 6.2.9 # TODO: more optimal for client preflight request cache would be to # respond with ALL allowed methods. response.headers[hdrs.ACCESS_CONTROL_ALLOW_METHODS] = request_method # CORS 6.2.10 if request_headers: # Note: case of the headers in the request is changed, but this # shouldn't be a problem, since the headers should be compared in # the case-insensitive way. response.headers[hdrs.ACCESS_CONTROL_ALLOW_HEADERS] = \ ",".join(request_headers) return response
async def presentation_exchange_send_free_request(request: web.BaseRequest): """ Request handler for sending a presentation request free from any proposal. Args: request: aiohttp request object Returns: The presentation exchange details """ r_time = get_timer() context: AdminRequestContext = request["context"] outbound_handler = request.app["outbound_message_router"] session = await context.session() body = await request.json() connection_id = body.get("connection_id") try: connection_record = await ConnRecord.retrieve_by_id( session, connection_id) except StorageNotFoundError as err: raise web.HTTPBadRequest(reason=err.roll_up) from err if not connection_record.is_ready: raise web.HTTPForbidden(reason=f"Connection {connection_id} not ready") comment = body.get("comment") indy_proof_request = body.get("proof_request") if not indy_proof_request.get("nonce"): indy_proof_request["nonce"] = await generate_pr_nonce() presentation_request_message = PresentationRequest( comment=comment, request_presentations_attach=[ AttachDecorator.from_indy_dict( indy_dict=indy_proof_request, ident=ATTACH_DECO_IDS[PRESENTATION_REQUEST], ) ], ) trace_msg = body.get("trace") presentation_request_message.assign_trace_decorator( session.settings, trace_msg, ) presentation_manager = PresentationManager(session) pres_ex_record = None try: (pres_ex_record ) = await presentation_manager.create_exchange_for_request( connection_id=connection_id, presentation_request_message=presentation_request_message, ) result = pres_ex_record.serialize() except (BaseModelError, StorageError) as err: await internal_error( err, web.HTTPBadRequest, pres_ex_record or connection_record, outbound_handler, ) await outbound_handler(presentation_request_message, connection_id=connection_id) trace_event( session.settings, presentation_request_message, outcome="presentation_exchange_send_request.END", perf_counter=r_time, ) return web.json_response(result)
async def presentation_exchange_send_proposal(request: web.BaseRequest): """ Request handler for sending a presentation proposal. Args: request: aiohttp request object Returns: The presentation exchange details """ r_time = get_timer() context: AdminRequestContext = request["context"] outbound_handler = request.app["outbound_message_router"] session = await context.session() body = await request.json() comment = body.get("comment") connection_id = body.get("connection_id") # Aries RFC 37 calls it a proposal in the proposal struct but it's of type preview presentation_preview = body.get("presentation_proposal") connection_record = None try: connection_record = await ConnRecord.retrieve_by_id( session, connection_id) presentation_proposal_message = PresentationProposal( comment=comment, presentation_proposal=PresentationPreview.deserialize( presentation_preview), ) except (BaseModelError, StorageError) as err: await internal_error(err, web.HTTPBadRequest, connection_record, outbound_handler) if not connection_record.is_ready: raise web.HTTPForbidden(reason=f"Connection {connection_id} not ready") trace_msg = body.get("trace") presentation_proposal_message.assign_trace_decorator( session.settings, trace_msg, ) auto_present = body.get( "auto_present", session.settings.get("debug.auto_respond_presentation_request")) presentation_manager = PresentationManager(session) pres_ex_record = None try: pres_ex_record = await presentation_manager.create_exchange_for_proposal( connection_id=connection_id, presentation_proposal_message=presentation_proposal_message, auto_present=auto_present, ) result = pres_ex_record.serialize() except (BaseModelError, StorageError) as err: await internal_error( err, web.HTTPBadRequest, pres_ex_record or connection_record, outbound_handler, ) await outbound_handler(presentation_proposal_message, connection_id=connection_id) trace_event( session.settings, presentation_proposal_message, outcome="presentation_exchange_propose.END", perf_counter=r_time, ) return web.json_response(result)
def _check_owner(self, target_object: BaseModel): if self.user.id != target_object.created_by_id: raise web.HTTPForbidden( body=f"You have not access to {target_object}")
async def credential_exchange_send_proposal(request: web.BaseRequest): """ Request handler for sending credential proposal. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context: AdminRequestContext = request["context"] outbound_handler = request["outbound_message_router"] body = await request.json() conn_id = body.get("connection_id") comment = body.get("comment") preview_spec = body.get("credential_preview") filt_spec = body.get("filter") if not filt_spec: raise web.HTTPBadRequest(reason="Missing filter") auto_remove = body.get("auto_remove") trace_msg = body.get("trace") conn_record = None cred_ex_record = None try: cred_preview = (V20CredPreview.deserialize(preview_spec) if preview_spec else None) async with context.session() as session: conn_record = await ConnRecord.retrieve_by_id(session, conn_id) if not conn_record.is_ready: raise web.HTTPForbidden( reason=f"Connection {conn_id} not ready") cred_manager = V20CredManager(context.profile) cred_ex_record = await cred_manager.create_proposal( conn_id=conn_id, auto_remove=auto_remove, comment=comment, cred_preview=cred_preview, trace=trace_msg, fmt2filter={ V20CredFormat.Format.get(fmt_aka): filt_by_fmt for (fmt_aka, filt_by_fmt) in filt_spec.items() }, ) cred_proposal_message = V20CredProposal.deserialize( cred_ex_record.cred_proposal) result = cred_ex_record.serialize() except (BaseModelError, StorageError) as err: await internal_error( err, web.HTTPBadRequest, cred_ex_record or conn_record, outbound_handler, ) await outbound_handler(cred_proposal_message, connection_id=conn_id) trace_event( context.settings, cred_proposal_message, outcome="credential_exchange_send_proposal.END", perf_counter=r_time, ) return web.json_response(result)
async def credential_exchange_issue(request: web.BaseRequest): """ Request handler for sending credential. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context = request.app["request_context"] outbound_handler = request.app["outbound_message_router"] body = await request.json() comment = body.get("comment") preview_spec = body.get("credential_preview") if not preview_spec: raise web.HTTPBadRequest(reason="credential_preview must be provided") credential_exchange_id = request.match_info["cred_ex_id"] cred_exch_record = await V10CredentialExchange.retrieve_by_id( context, credential_exchange_id) connection_id = cred_exch_record.connection_id assert cred_exch_record.state == V10CredentialExchange.STATE_REQUEST_RECEIVED try: connection_record = await ConnectionRecord.retrieve_by_id( context, connection_id) except StorageNotFoundError: raise web.HTTPBadRequest() if not connection_record.is_ready: raise web.HTTPForbidden() credential_preview = CredentialPreview.deserialize(preview_spec) credential_manager = CredentialManager(context) try: ( cred_exch_record, credential_issue_message, ) = await credential_manager.issue_credential( cred_exch_record, comment=comment, credential_values=credential_preview.attr_dict(decode=False), ) except IssuerRevocationRegistryFullError: raise web.HTTPBadRequest(reason="Revocation registry is full") await outbound_handler(credential_issue_message, connection_id=connection_id) trace_event( context.settings, credential_issue_message, outcome="credential_exchange_issue.END", perf_counter=r_time, ) return web.json_response(cred_exch_record.serialize())
async def credential_exchange_send_request(request: web.BaseRequest): """ Request handler for sending credential request. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context: AdminRequestContext = request["context"] outbound_handler = request["outbound_message_router"] cred_ex_id = request.match_info["cred_ex_id"] cred_ex_record = None conn_record = None try: async with context.session() as session: try: cred_ex_record = await V20CredExRecord.retrieve_by_id( session, cred_ex_id, ) except StorageNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err conn_id = cred_ex_record.conn_id conn_record = await ConnRecord.retrieve_by_id(session, conn_id) if not conn_record.is_ready: raise web.HTTPForbidden( reason=f"Connection {conn_id} not ready") cred_manager = V20CredManager(context.profile) (cred_ex_record, cred_request_message) = await cred_manager.create_request( cred_ex_record, conn_record.my_did, ) result = cred_ex_record.serialize() except (StorageError, V20CredManagerError, BaseModelError) as err: await internal_error( err, web.HTTPBadRequest, cred_ex_record or conn_record, outbound_handler, ) await outbound_handler(cred_request_message, connection_id=conn_id) trace_event( context.settings, cred_request_message, outcome="credential_exchange_send_request.END", perf_counter=r_time, ) return web.json_response(result)
async def credential_definitions_send_credential_definition( request: web.BaseRequest): """ Request handler for sending a credential definition to the ledger. Args: request: aiohttp request object Returns: The credential definition identifier """ context = request.app["request_context"] body = await request.json() schema_id = body.get("schema_id") support_revocation = bool(body.get("support_revocation")) tag = body.get("tag") revocation_registry_size = body.get("revocation_registry_size") ledger: BaseLedger = await context.inject(BaseLedger, required=False) if not ledger: reason = "No ledger available" if not context.settings.get_value("wallet.type"): reason += ": missing wallet-type?" raise web.HTTPForbidden(reason=reason) issuer: BaseIssuer = await context.inject(BaseIssuer) try: async with ledger: credential_definition_id, credential_definition = await shield( ledger.create_and_send_credential_definition( issuer, schema_id, signature_type=None, tag=tag, support_revocation=support_revocation, )) except LedgerError as e: raise web.HTTPBadRequest(reason=e.message) from e # If revocation is requested, create revocation registry if support_revocation: tails_base_url = context.settings.get("tails_server_base_url") if not tails_base_url: raise web.HTTPBadRequest( reason="tails_server_base_url not configured") try: # Create registry issuer_did = credential_definition_id.split(":")[0] revoc = IndyRevocation(context) registry_record = await revoc.init_issuer_registry( credential_definition_id, issuer_did, max_cred_num=revocation_registry_size, ) except RevocationNotSupportedError as e: raise web.HTTPBadRequest(reason=e.message) from e await shield(registry_record.generate_registry(context)) try: await registry_record.set_tails_file_public_uri( context, f"{tails_base_url}/{registry_record.revoc_reg_id}") await registry_record.publish_registry_definition(context) await registry_record.publish_registry_entry(context) tails_server: BaseTailsServer = await context.inject( BaseTailsServer) upload_success, reason = await tails_server.upload_tails_file( context, registry_record.revoc_reg_id, registry_record.tails_local_path) if not upload_success: raise web.HTTPInternalServerError( reason=f"Tails file failed to upload: {reason}") pending_registry_record = await revoc.init_issuer_registry( registry_record.cred_def_id, registry_record.issuer_did, max_cred_num=registry_record.max_cred_num, ) ensure_future( pending_registry_record.stage_pending_registry_definition( context)) except RevocationError as e: raise web.HTTPBadRequest(reason=e.message) from e return web.json_response( {"credential_definition_id": credential_definition_id})
async def handler(request): return web.HTTPForbidden()
f"{service}:{version}" for service, version in unavilable_services) # TODO: lack of permissions should be notified with https://httpstatuses.com/403 web.HTTPForbidden raise web.HTTPNotFound(reason=( f"Project '{project_uuid}' uses unavailable services. Please ask " f"for permission for the following services {formatted_services}" )) if new_uuid := request.get(RQ_REQUESTED_REPO_PROJECT_UUID_KEY): project["uuid"] = new_uuid return {"data": project} except ProjectInvalidRightsError as exc: raise web.HTTPForbidden( reason= f"You do not have sufficient rights to read project {project_uuid}" ) from exc except ProjectNotFoundError as exc: raise web.HTTPNotFound( reason=f"Project {project_uuid} not found") from exc @routes.get(f"/{VTAG}/projects/active") @login_required @permission_required("project.read") async def get_active_project(request: web.Request) -> web.Response: user_id: int = request[RQT_USERID_KEY] try: client_session_id = request.query["client_session_id"]
async def credential_exchange_send_free_offer(request: web.BaseRequest): """ Request handler for sending free credential offer. An issuer initiates a such a credential offer, which is free any holder-initiated corresponding proposal. Args: request: aiohttp request object Returns: The credential exchange record """ context = request.app["request_context"] outbound_handler = request.app["outbound_message_router"] body = await request.json() connection_id = body.get("connection_id") credential_definition_id = body.get("credential_definition_id") auto_issue = body.get( "auto_issue", context.settings.get("debug.auto_respond_credential_request")) comment = body.get("comment", None) credential_preview = CredentialPreview(attributes=[ CredAttrSpec(name=attr_preview['name'], value=attr_preview['value'], mime_type=attr_preview.get('mime_type', None)) for attr_preview in body.get("credential_preview")["attributes"] ]) if auto_issue and not credential_preview: raise web.HTTPBadRequest( reason="If auto_issue is set to" + " true then credential_preview must also be provided.") credential_proposal = CredentialProposal( comment=comment, credential_proposal=credential_preview, cred_def_id=credential_definition_id) credential_manager = CredentialManager(context) try: connection_record = await ConnectionRecord.retrieve_by_id( context, connection_id) except StorageNotFoundError: raise web.HTTPBadRequest() if not connection_record.is_ready: raise web.HTTPForbidden() credential_exchange_record = V10CredentialExchange( connection_id=connection_id, initiator=V10CredentialExchange.INITIATOR_SELF, credential_definition_id=credential_definition_id, credential_proposal_dict=credential_proposal.serialize(), auto_issue=auto_issue) ( credential_exchange_record, credential_offer_message, ) = await credential_manager.create_offer(credential_exchange_record, comment=comment) await outbound_handler(credential_offer_message, connection_id=connection_id) return web.json_response(credential_exchange_record.serialize())
async def replace_project(request: web.Request): """Implements PUT /projects In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version. Also, another difference is that when you want to update a resource with PUT request, you have to send the full payload as the request whereas with PATCH, you only send the parameters which you want to update. :raises web.HTTPNotFound: cannot find project id in repository """ user_id: int = request[RQT_USERID_KEY] try: project_uuid = ProjectID(request.match_info["project_id"]) new_project = await request.json() # Prune state field (just in case) new_project.pop("state", None) except AttributeError as err: # NOTE: if new_project is not a dict, .pop will raise this error raise web.HTTPBadRequest( reason="Invalid request payload, expected a project model" ) from err except KeyError as err: raise web.HTTPBadRequest( reason=f"Invalid request parameter {err}") from err except json.JSONDecodeError as exc: raise web.HTTPBadRequest(reason="Invalid request body") from exc db: ProjectDBAPI = request.config_dict[APP_PROJECT_DBAPI] await check_permission( request, "project.update | project.workbench.node.inputs.update", context={ "dbapi": db, "project_id": f"{project_uuid}", "user_id": user_id, "new_data": new_project, }, ) try: await projects_api.validate_project(request.app, new_project) current_project = await projects_api.get_project_for_user( request.app, project_uuid=f"{project_uuid}", user_id=user_id, include_templates=True, include_state=True, ) if current_project["accessRights"] != new_project["accessRights"]: await check_permission(request, "project.access_rights.update") if await director_v2_api.is_pipeline_running(request.app, user_id, project_uuid): if any_node_inputs_changed(new_project, current_project): # NOTE: This is a conservative measure that we take # until nodeports logic is re-designed to tackle with this # particular state. # # This measure avoid having a state with different node *links* in the # comp-tasks table and the project's workbench column. # The limitation is that nodeports only "sees" those in the comptask # and this table does not add the new ones since it remains "blocked" # for modification from that project while the pipeline runs. Therefore # any extra link created while the pipeline is running can not # be managed by nodeports because it basically "cannot see it" # # Responds https://httpstatuses.com/409: # The request could not be completed due to a conflict with the current # state of the target resource (i.e. pipeline is running). This code is used in # situations where the user might be able to resolve the conflict # and resubmit the request (front-end will show a pop-up with message below) # raise web.HTTPConflict( reason= f"Project {project_uuid} cannot be modified while pipeline is still running." ) new_project = await db.replace_user_project(new_project, user_id, f"{project_uuid}", include_templates=True) await director_v2_api.create_or_update_pipeline( request.app, user_id, project_uuid) # Appends state new_project = await projects_api.add_project_states_for_user( user_id=user_id, project=new_project, is_template=False, app=request.app, ) except ValidationError as exc: raise web.HTTPBadRequest( reason=f"Invalid project update: {exc.message}") from exc except ProjectInvalidRightsError as exc: raise web.HTTPForbidden( reason="You do not have sufficient rights to save the project" ) from exc except ProjectNotFoundError as exc: raise web.HTTPNotFound from exc return {"data": new_project}
async def credential_exchange_send(request: web.BaseRequest): """ Request handler for sending credential from issuer to holder from attr values. If both issuer and holder are configured for automatic responses, the operation ultimately results in credential issue; otherwise, the result waits on the first response not automated; the credential exchange record retains state regardless. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context = request.app["request_context"] outbound_handler = request.app["outbound_message_router"] body = await request.json() comment = body.get("comment") connection_id = body.get("connection_id") preview_spec = body.get("credential_proposal") if not preview_spec: raise web.HTTPBadRequest(reason="credential_proposal must be provided") auto_remove = body.get("auto_remove") trace_msg = body.get("trace") connection_record = None cred_ex_record = None try: preview = CredentialPreview.deserialize(preview_spec) connection_record = await ConnectionRecord.retrieve_by_id( context, connection_id) if not connection_record.is_ready: raise web.HTTPForbidden( reason=f"Connection {connection_id} not ready") credential_proposal = CredentialProposal( comment=comment, credential_proposal=preview, **{t: body.get(t) for t in CRED_DEF_TAGS if body.get(t)}, ) credential_proposal.assign_trace_decorator( context.settings, trace_msg, ) trace_event( context.settings, credential_proposal, outcome="credential_exchange_send.START", ) credential_manager = CredentialManager(context) ( cred_ex_record, credential_offer_message, ) = await credential_manager.prepare_send( connection_id, credential_proposal=credential_proposal, auto_remove=auto_remove, ) result = cred_ex_record.serialize() except (StorageError, BaseModelError, CredentialManagerError) as err: await internal_error( err, web.HTTPBadRequest, cred_ex_record or connection_record, outbound_handler, ) await outbound_handler(credential_offer_message, connection_id=cred_ex_record.connection_id) trace_event( context.settings, credential_offer_message, outcome="credential_exchange_send.END", perf_counter=r_time, ) return web.json_response(result)
async def wallet_set_public_did(request: web.BaseRequest): """ Request handler for setting the current public DID. Args: request: aiohttp request object Returns: The updated DID info """ context: AdminRequestContext = request["context"] session = await context.session() wallet = session.inject_or(BaseWallet) if not wallet: raise web.HTTPForbidden(reason="No wallet available") did = request.query.get("did") if not did: raise web.HTTPBadRequest(reason="Request query must include DID") # Multitenancy setup multitenant_mgr = session.inject_or(BaseMultitenantManager) wallet_id = session.settings.get("wallet.id") try: ledger = session.inject_or(BaseLedger) if not ledger: reason = "No ledger available" if not session.settings.get_value("wallet.type"): reason += ": missing wallet-type?" raise web.HTTPForbidden(reason=reason) async with ledger: if not await ledger.get_key_for_did(did): raise web.HTTPNotFound(reason=f"DID {did} is not posted to the ledger") did_info = await wallet.get_local_did(did) info = await wallet.set_public_did(did_info) if info: # Publish endpoint if necessary endpoint = did_info.metadata.get("endpoint") if not endpoint: endpoint = session.settings.get("default_endpoint") await wallet.set_did_endpoint(info.did, endpoint, ledger) async with ledger: await ledger.update_endpoint_for_did(info.did, endpoint) # Add multitenant relay mapping so implicit invitations are still routed if multitenant_mgr and wallet_id: await multitenant_mgr.add_key( wallet_id, info.verkey, skip_if_exists=True ) except WalletNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err except (LedgerError, WalletError) as err: raise web.HTTPBadRequest(reason=err.roll_up) from err return web.json_response({"result": format_did_info(info)})
async def credential_exchange_send_free_offer(request: web.BaseRequest): """ Request handler for sending free credential offer. An issuer initiates a such a credential offer, free from any holder-initiated corresponding credential proposal with preview. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context = request.app["request_context"] outbound_handler = request.app["outbound_message_router"] body = await request.json() connection_id = body.get("connection_id") cred_def_id = body.get("cred_def_id") if not cred_def_id: raise web.HTTPBadRequest(reason="cred_def_id is required") auto_issue = body.get( "auto_issue", context.settings.get("debug.auto_respond_credential_request")) auto_remove = body.get("auto_remove") comment = body.get("comment") preview_spec = body.get("credential_preview") if not preview_spec: raise web.HTTPBadRequest(reason=("Missing credential_preview")) trace_msg = body.get("trace") cred_ex_record = None connection_record = None try: connection_record = await ConnectionRecord.retrieve_by_id( context, connection_id) if not connection_record.is_ready: raise web.HTTPForbidden( reason=f"Connection {connection_id} not ready") ( cred_ex_record, credential_offer_message, ) = await _create_free_offer( context, cred_def_id, connection_id, auto_issue, auto_remove, preview_spec, comment, trace_msg, ) result = cred_ex_record.serialize() except ( StorageNotFoundError, BaseModelError, CredentialManagerError, LedgerError, ) as err: await internal_error( err, web.HTTPBadRequest, cred_ex_record or connection_record, outbound_handler, ) await outbound_handler(credential_offer_message, connection_id=connection_id) trace_event( context.settings, credential_offer_message, outcome="credential_exchange_send_free_offer.END", perf_counter=r_time, ) return web.json_response(result)
async def hello(request): raise web.HTTPForbidden()
def route(request): session = yield from get_session(request) if 'uid' in session: uid = session['uid'] else: return web.HTTPForbidden() query_parameters = request.rel_url.query if "fid" in query_parameters: try: fid = str(int(query_parameters["fid"])).zfill(8) except: return web.HTTPBadRequest() else: return web.HTTPBadRequest() if request.content_type != "application/x-www-form-urlencoded": return web.HTTPBadRequest() data = yield from request.post() if 'title' in data: title = data['title'] else: return web.HTTPBadRequest() if 'subtitle' in data: subtitle = data['subtitle'] else: return web.HTTPBadRequest() if 'type' in data: try: type_number = int(data['type']) if toolbox.number_to_type(type_number) == None: return web.HTTPBadRequest() except: return web.HTTPBadRequest() else: return web.HTTPBadRequest() if 'article' in data: article = data['article'] article = re.sub(r'\r\n','\n',article) else: return web.HTTPBadRequest() post = datetime.datetime.now() snippet = re.sub(r'http://',"", article) snippet = re.sub(r'https://',"", snippet) snippet = re.sub(r'\!\[[^\]]*\]\([^\)]+?\)',"",snippet) snippet = re.sub(r'\s+'," ",snippet) snippet = re.sub(r'^\s+',"",snippet) snippet = snippet[0:80] snippet = re.sub(r'\s$',"",snippet) if len(snippet) == 80: snippet = snippet+"..." images_raw = re.findall(r'([\d|a-f]{32}\.(jpg|png|gif))',article) images_raw = [image[0] for image in images_raw] images = list(set(images_raw)) images.sort(key=images_raw.index) with (yield from request.app['pool']) as connect: cursor = yield from connect.cursor() yield from cursor.execute('''SELECT post,type FROM feed WHERE id = %s AND uid = %s''',(fid,uid)) check = yield from cursor.fetchone() try: if not check: return web.HTTPForbidden() elif check[1] == 0: yield from cursor.execute(''' UPDATE feed SET post = %s, type = %s, title = %s, subtitle = %s, snippet = %s, images = %s, status = 1 WHERE id = %s; ''',(post.strftime("%Y/%m/%d %H:%M"),type_number,title,subtitle,snippet,",".join(images),fid)) else: post = check[0] yield from cursor.execute(''' UPDATE feed SET type = %s, title = %s, subtitle = %s, snippet = %s, images = %s, status = 1 WHERE id = %s; ''',(type_number,title,subtitle,snippet,",".join(images),fid)) yield from connect.commit() yield from cursor.execute(''' UPDATE article SET text = %s WHERE id = %s; ''',(article,fid)) yield from connect.commit() except Exception as e: print(e) return web.HTTPBadRequest() yield from cursor.close() connect.close() os.system("python3 {working_dir}/server/transmit.py {fid} &".format( working_dir = request.app["working_dir"], fid = fid )) return web.Response( text = toolbox.jsonify({ "id": str(fid).zfill(8), "post": toolbox.time_utc(post), "title": title, "subtitle": subtitle, "snippet": snippet, }), headers = {'Access-Control-Allow-Origin':'*'}, content_type='application/json', charset='utf-8' )
async def credential_exchange_store(request: web.BaseRequest): """ Request handler for storing credential. Args: request: aiohttp request object Returns: The credential exchange record """ r_time = get_timer() context: AdminRequestContext = request["context"] outbound_handler = request["outbound_message_router"] try: body = await request.json() or {} cred_id = body.get("credential_id") except JSONDecodeError: cred_id = None cred_ex_id = request.match_info["cred_ex_id"] cred_ex_record = None conn_record = None try: async with context.session() as session: try: cred_ex_record = await V20CredExRecord.retrieve_by_id( session, cred_ex_id, ) except StorageNotFoundError as err: raise web.HTTPNotFound(reason=err.roll_up) from err conn_id = cred_ex_record.conn_id conn_record = await ConnRecord.retrieve_by_id(session, conn_id) if not conn_record.is_ready: raise web.HTTPForbidden( reason=f"Connection {conn_id} not ready") cred_manager = V20CredManager(context.profile) (cred_ex_record, cred_stored_message) = await cred_manager.store_credential( cred_ex_record, cred_id, ) indy_record = await cred_manager.get_detail_record( cred_ex_id, V20CredFormat.Format.INDY) dif_record = await cred_manager.get_detail_record( cred_ex_id, V20CredFormat.Format.DIF) result = { "cred_ex_record": cred_ex_record.serialize(), "indy": indy_record.serialize() if indy_record else None, "dif": dif_record.serialize() if dif_record else None, } except (StorageError, V20CredManagerError, BaseModelError) as err: await internal_error( err, web.HTTPBadRequest, cred_ex_record or conn_record, outbound_handler, ) await outbound_handler(cred_stored_message, connection_id=conn_id) trace_event( context.settings, cred_stored_message, outcome="credential_exchange_store.END", perf_counter=r_time, ) return web.json_response(result)
async def event_stream(request): auth = request.headers.get("Authorization") if auth is None: return web.HTTPForbidden() token = auth[auth.find("Bearer") + 7:] if token not in BOT_TOKENS: log.error("BOT account auth with token %s failed", token) return web.HTTPForbidden() user_agent = request.headers.get("User-Agent") username = user_agent[user_agent.find("user:"******"users"] seeks = request.app["seeks"] sockets = request.app["lobbysockets"] games = request.app["games"] db = request.app["db"] resp = web.StreamResponse() resp.content_type = "text/plain" await resp.prepare(request) if username in users: bot_player = users[username] # After BOT lost connection it may have ongoing games # We notify BOT and he can ask to create new game_streams # to continue those games for gameId in bot_player.game_queues: if gameId in games and games[gameId].status == STARTED: await bot_player.event_queue.put(games[gameId].game_start) else: bot_player = User(request.app, bot=True, username=username) users[bot_player.username] = bot_player doc = await db.user.find_one({"_id": username}) if doc is None: result = await db.user.insert_one({ "_id": username, "first_name": None, "last_name": None, "country": None, "title": "BOT", }) print("db insert user result %s" % repr(result.inserted_id)) bot_player.online = True log.info("+++ BOT %s connected", bot_player.username) loop = asyncio.get_event_loop() pinger_task = loop.create_task( bot_player.pinger(sockets, seeks, users, games)) # inform others # TODO: do we need this at all? await lobby_broadcast(sockets, get_seeks(seeks)) # send "challenge" and "gameStart" events from event_queue to the BOT while bot_player.online: answer = await bot_player.event_queue.get() try: bot_player.event_queue.task_done() except ValueError: log.error( "task_done() called more times than there were items placed in the queue in bot_api.py event_stream()" ) try: if request.protocol.transport.is_closing(): log.error( "BOT %s request.protocol.transport.is_closing() == True ...", username) break else: await resp.write(answer.encode("utf-8")) await resp.drain() except Exception: log.error("BOT %s event_stream is broken...", username) break pinger_task.cancel() await bot_player.clear_seeks(sockets, seeks) return resp
async def handle_add_blurb_post(request): if await util.has_session(request): session_context = await util.get_session_context(request) request_session = await get_session(request) data = await request.post() csrf_form = data.get("csrf", "").strip() if not util.compare_csrf_tokens( csrf_form, util.get_csrf_token(session=request_session)): raise web.HTTPForbidden(reason="Invalid CSRF token. Please retry.") bpo_number = data.get("bpo_number", "").strip() section = data.get("section", "").strip() news_entry = data.get("news_entry", "").strip() path = await util.get_misc_news_filename(bpo_number, section, news_entry) pr_number = data.get("pr_number", "").strip() context = {} context.update(session_context) async with aiohttp.ClientSession() as session: gh = GitHubAPI(session, session_context["username"]) jwt = util.get_jwt(os.getenv("GH_APP_ID"), os.getenv("GH_PRIVATE_KEY")) try: installation = await util.get_installation( gh, jwt, session_context["username"]) except error.InstallationNotFound: return web.HTTPFound( location=request.app.router["install"].url_for()) else: access_token = await util.get_installation_access_token( gh, jwt=jwt, installation_id=installation["id"]) gh = GitHubAPI( session, session_context["username"], oauth_token=access_token["token"], ) pr = await gh.getitem( f"/repos/python/cpython/pulls/{pr_number}") pr_repo_full_name = pr["head"]["repo"]["full_name"] encoded = base64.b64encode(str.encode(news_entry)) decoded = encoded.decode("utf-8") put_data = { "branch": pr["head"]["ref"], "content": decoded, "path": path, "message": "📜🤖 Added by blurb_it.", } try: response = await gh.put( f"/repos/{pr_repo_full_name}/contents/{path}", data=put_data) except gidgethub.BadRequest as bac: print("BadRequest") print(int(bac.status_code)) print(bac) context[ "pr_url"] = f"https://github.com/python/cpython/pull/{pr_number}" context["pr_number"] = pr_number context["status"] = "failure" else: commit_url = response["commit"]["html_url"] context["commit_url"] = commit_url context["path"] = response["content"]["path"] context[ "pr_url"] = f"https://github.com/python/cpython/pull/{pr_number}" context["pr_number"] = pr_number context["status"] = "success" template = "add_blurb.html" response = aiohttp_jinja2.render_template(template, request, context=context) return response else: return web.HTTPFound( location=request.app.router["add_blurb"].url_for())