Beispiel #1
0
def create_user_token(app_token: Token, owner: User) -> Token:
    """
    Derives a new user token from an existing app token, and set the owner to
    be the user given in argument.
    """
    if app_token.token_type == Token.TokenType.dyn:
        new_token = Token(  # nosec
            created_on=utils.now(),
            expires_on=utils.now_plus(days=1),
            owner=owner,
            parent=app_token,
            token_type="use",
            uuid=str(uuid4()),
        )
    elif app_token.token_type == Token.TokenType.per:
        new_token = Token(  # nosec
            created_on=utils.now(),
            owner=owner,
            parent=app_token,
            token_type="use",
            uuid=str(uuid4()),
        )
    else:
        raise ValueError("Expected an app token")
    new_token.save()
    logging.info("Created user token %s for app %s", new_token.uuid,
                 app_token.uuid)
    return new_token
Beispiel #2
0
def get_access_token(character_id: int,
                     scope: EsiScope = EsiScope.PUBLICDATA) -> EsiAccessToken:
    """
    Returns an access token, refreshes if needed

    Todo:
        Support multiple scopes.
    """
    scope_str: str = scope.value
    owner: User = User.objects.get(character_id=character_id)
    esi_access_token: EsiAccessToken = EsiAccessToken.objects(
        owner=owner,
        scopes=scope_str,
        expires_on__gt=utils.now(),
    ).first()
    if not esi_access_token:
        esi_refresh_token: EsiRefreshToken = EsiRefreshToken.objects(
            owner=owner, scopes=scope_str, valid=True).first()
        if not esi_refresh_token:
            logging.error(
                "Could not find refresh token for user %s with scope %s",
                owner.character_name,
                scope_str,
            )
            raise LookupError(
                (f"Could not find access token with scope {scope_str} "
                 f"for user {character_id}"))
        esi_access_token = save_esi_tokens(
            refresh_access_token(esi_refresh_token.refresh_token))
    return esi_access_token
Beispiel #3
0
def create_state_code(
    app_token: Optional[Token],
    *,
    inviting_corporation: Optional[Corporation] = None,
    code_prefix: Optional[str] = None,
) -> StateCode:
    """
    Creates a new state code.

    See also:
        :class:`sni.uac.token.StateCode`
    """
    code = str(uuid4())
    if code_prefix is not None:
        code = code_prefix + ":" + code
    state_code = StateCode(
        app_token=app_token,
        created_on=utils.now(),
        inviting_corporation=inviting_corporation,
        uuid=code,
    )
    state_code.save()
    logging.info(
        "Created state code %s deriving from app token %s",
        state_code.uuid,
        app_token.uuid if app_token is not None else "N/A",
    )
    return state_code
Beispiel #4
0
def new_authentication_challenge(usr: User) -> str:
    """
    Initiates an authentication challenge. The challenge proceeds as follows:

    1. A user (:class:`sni.user`) asks to start a challenge by calling
       this method.

    2. This methods returns a UUID, and the user has 60 seconds to change its
       teamspeak nickname to that UUID.

    3. The user notifies SNI that (s)he has done so.

    4. The server checks (see
       :meth:`sni.teamspeak.complete_authentication_challenge`), and if
       sucessful, the corresponding teamspeak client is registered in the
       database and bound to that user. The nickname is also automatically
       assigned.
    """
    logging.info("Starting authentication challenge for %s",
                 usr.character_name)
    challenge_nickname = utils.random_code(20)
    TeamspeakAuthenticationChallenge.objects(user=usr).update(
        set__challenge_nickname=challenge_nickname,
        set__created_on=utils.now(),
        set__user=usr,
        upsert=True,
    )
    return challenge_nickname
Beispiel #5
0
def update_user_from_esi(usr: User):
    """
    Updates a user's information from the ESI
    """
    data = esi_get(f"latest/characters/{usr.character_id}").data
    old_corporation = usr.corporation
    usr.corporation = ensure_corporation(int(data["corporation_id"]))
    usr.updated_on = utils.now()
    if usr.corporation != old_corporation:
        logging.debug("Corporation of user %s changed", usr.character_name)
        reset_clearance(usr)
    usr.save()
Beispiel #6
0
def esi_request(
    http_method: str,
    path: str,
    *,
    kwargs: dict = {},
    token: Optional[str] = None,
) -> EsiResponse:
    """
    Makes an HTTP request to the ESI, and returns the response object.
    """
    kwargs["headers"] = {
        "Accept-Encoding": "gzip",
        "accept": "application/json",
        "User-Agent": "SeAT Navy Issue @ " + conf.general.root_url,
        **kwargs.get("headers", {}),
    }
    if token:
        kwargs["headers"]["Authorization"] = "Bearer " + token

    if http_method.upper() != "GET":
        raw = request(http_method, ESI_BASE + path, **kwargs)
        raw.raise_for_status()
        return EsiResponse.from_response(raw)

    key = ("esi", [path, token, sorted(kwargs.get("params", {}).items())])
    response = cache_get(key)
    if response is not None:
        return EsiResponse(**response)

    raw = request(http_method, ESI_BASE + path, **kwargs)
    raw.raise_for_status()
    response = EsiResponse.from_response(raw)

    ttl = 60
    if "Expires" in response.headers:
        try:
            ttl = int((parser.parse(response.headers["Expires"]) -
                       utils.now()).total_seconds())
        except ValueError as error:
            logging.warning("Could not determine ESI TTL: %s", str(error))
    if ttl > 0:
        cache_set(key, response.dict(), ttl)

    return response
Beispiel #7
0
def create_permanent_app_token(
    owner: User,
    *,
    callback: Optional[str] = None,
    comments: Optional[str] = None,
    parent: Optional[Token] = None,
) -> Token:
    """
    Creates a new permanent app token for that user.

    Warning: Does not check that the user is allowed to actually do that.
    """
    new_token = Token(
        callback=callback,
        comments=comments,
        created_on=utils.now(),
        owner=owner,
        parent=parent,
        token_type=Token.TokenType.per,
        uuid=str(uuid4()),
    )
    new_token.save()
    logging.info("Created permanent app token %s", new_token.uuid)
    return new_token
Beispiel #8
0
def on_pre_save(_sender: Any, document: me.Document):
    """
    If the document has a `updated_on`, sets it to the current datetime.
    """
    if "updated_on" in document:
        document.updated_on = utils.now()