def ensure_root_dyn_token() -> None: """ Create a dynamic app token owned by root, if none exist. """ root = User.objects.get(character_id=0) if (token.Token.objects(owner=root, token_type=token.Token.TokenType.dyn).count() > 0): return root_dyn_token = token.create_dynamic_app_token(root, comments="Primary token") logging.info( "No dynamic app token owned by root, created one: %r", token.to_jwt(root_dyn_token), )
async def post_token_use_from_per( tkn: Token = Depends(from_authotization_header), ): """ Authenticates an application permanent token and returns a user token tied to the owner of that app token. """ if tkn.token_type != Token.TokenType.per: raise HTTPException( status.HTTP_401_UNAUTHORIZED, detail="Must use a permanent app token for this path.", ) assert_has_clearance(tkn.owner, "sni.create_use_token") user_token = create_user_token( tkn, User.objects.get(character_id=0), ) user_token_str = to_jwt(user_token) return PostUseFromPerOut(user_token=user_token_str)
async def post_token_per( data: PostTokenPerIn, tkn: Token = Depends(from_authotization_header_nondyn), ): """ Creates a new permanent app token. Must be called with a permanent app token, and the owner must have a clearance level of 10. """ assert_has_clearance(tkn.owner, "sni.create_per_token") if tkn.token_type != Token.TokenType.per: raise HTTPException(status.HTTP_401_UNAUTHORIZED) new_token = create_permanent_app_token( tkn.owner, callback=data.callback, comments=data.comments, parent=tkn, ) return PostTokenPerOut(tkn=to_jwt(new_token))
async def get_callback_esi(code: str, state: str): """ ESI callback. You should not manually call this. Upon receiving a notification from EVE SSO, SNI redirects the client to the appropriate frontend callback, with the state code and user token in URL parameters. Reference: `OAuth 2.0 for Web Based Applications <https://docs.esi.evetech.net/docs/sso/web_based_sso_flow.html>`_ """ logging.info("Received callback from ESI for state %s", state) state_code: StateCode = StateCode.objects.get(uuid=state) state_code.delete() try: esi_response = get_access_token_from_callback_code(code) access_token = decode_access_token(esi_response.access_token) save_esi_tokens(esi_response) except EsiTokenError: return token_manipulation_error_response() usr: User = User.objects.get(character_id=access_token.character_id) if state_code.inviting_corporation is not None: usr.corporation = state_code.inviting_corporation usr.clearance_level = -1 usr.save() if not is_authorized_to_login(usr): return not_authorized_to_login_response(usr.character_name, usr.character_id) if not token_has_enough_scopes(access_token, usr): return not_enough_scopes_response( usr.character_name, usr.character_id, list(usr.cumulated_mandatory_esi_scopes()), access_token.scp, ) user_token = create_user_token(state_code.app_token, usr) user_jwt_str = to_jwt(user_token) logging.info("Issuing token %s to app %s", user_jwt_str, state_code.app_token.uuid) if state_code.app_token.callback is None: return { "created_on": user_token.created_on, "expires_on": user_token.expires_on, "jwt": user_jwt_str, "owner": { "character_id": user_token.owner.character_id, "character_name": user_token.owner.character_name, "clearance_level": user_token.owner.clearance_level, }, } request = requests.Request( "GET", state_code.app_token.callback, params={ "state_code": str(state_code.uuid), "user_token": user_jwt_str, }, ) url = request.prepare().url if url is None: logging.error( "Failed to redirect user to %s", state_code.app_token.callback, ) return PlainTextResponse( f"Failed to redirect to {state_code.app_token.callback}") return RedirectResponse(url=url)