141 lines
5.8 KiB
Python
141 lines
5.8 KiB
Python
"""Provide the Auth class."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from prawcore import Authorizer, ImplicitAuthorizer, UntrustedAuthenticator, session
|
|
|
|
from ..exceptions import InvalidImplicitAuth, MissingRequiredAttributeException
|
|
from ..util import _deprecate_args
|
|
from .base import PRAWBase
|
|
|
|
|
|
class Auth(PRAWBase):
|
|
"""Auth provides an interface to Reddit's authorization."""
|
|
|
|
@property
|
|
def limits(self) -> dict[str, str | int | None]:
|
|
"""Return a dictionary containing the rate limit info.
|
|
|
|
The keys are:
|
|
|
|
:remaining: The number of requests remaining to be made in the current rate
|
|
limit window.
|
|
:reset_timestamp: A unix timestamp providing an upper bound on when the rate
|
|
limit counters will reset.
|
|
:used: The number of requests made in the current rate limit window.
|
|
|
|
All values are initially ``None`` as these values are set in response to issued
|
|
requests.
|
|
|
|
The ``reset_timestamp`` value is an upper bound as the real timestamp is
|
|
computed on Reddit's end in preparation for sending the response. This value may
|
|
change slightly within a given window due to slight changes in response times
|
|
and rounding.
|
|
|
|
"""
|
|
data = self._reddit._core._rate_limiter
|
|
return {
|
|
"remaining": data.remaining,
|
|
"reset_timestamp": data.reset_timestamp,
|
|
"used": data.used,
|
|
}
|
|
|
|
def authorize(self, code: str) -> str | None:
|
|
"""Complete the web authorization flow and return the refresh token.
|
|
|
|
:param code: The code obtained through the request to the redirect uri.
|
|
|
|
:returns: The obtained refresh token, if available, otherwise ``None``.
|
|
|
|
The session's active authorization will be updated upon success.
|
|
|
|
"""
|
|
authenticator = self._reddit._read_only_core._authorizer._authenticator
|
|
authorizer = Authorizer(authenticator)
|
|
authorizer.authorize(code)
|
|
authorized_session = session(
|
|
authorizer=authorizer, window_size=self._reddit.config.window_size
|
|
)
|
|
self._reddit._core = self._reddit._authorized_core = authorized_session
|
|
return authorizer.refresh_token
|
|
|
|
@_deprecate_args("access_token", "expires_in", "scope")
|
|
def implicit(self, *, access_token: str, expires_in: int, scope: str):
|
|
"""Set the active authorization to be an implicit authorization.
|
|
|
|
:param access_token: The access_token obtained from Reddit's callback.
|
|
:param expires_in: The number of seconds the ``access_token`` is valid for. The
|
|
origin of this value was returned from Reddit's callback. You may need to
|
|
subtract an offset before passing in this number to account for a delay
|
|
between when Reddit prepared the response, and when you make this function
|
|
call.
|
|
:param scope: A space-delimited string of Reddit OAuth2 scope names as returned
|
|
from Reddit's callback.
|
|
|
|
:raises: :class:`.InvalidImplicitAuth` if :class:`.Reddit` was initialized for a
|
|
non-installed application type.
|
|
|
|
"""
|
|
authenticator = self._reddit._read_only_core._authorizer._authenticator
|
|
if not isinstance(authenticator, UntrustedAuthenticator):
|
|
raise InvalidImplicitAuth
|
|
implicit_session = session(
|
|
authorizer=ImplicitAuthorizer(
|
|
authenticator, access_token, expires_in, scope
|
|
),
|
|
window_size=self._reddit.config.window_size,
|
|
)
|
|
self._reddit._core = self._reddit._authorized_core = implicit_session
|
|
|
|
def scopes(self) -> set[str]:
|
|
"""Return a set of scopes included in the current authorization.
|
|
|
|
For read-only authorizations this should return ``{"*"}``.
|
|
|
|
"""
|
|
authorizer = self._reddit._core._authorizer
|
|
if not authorizer.is_valid():
|
|
authorizer.refresh()
|
|
return authorizer.scopes
|
|
|
|
@_deprecate_args("scopes", "state", "duration", "implicit")
|
|
def url(
|
|
self,
|
|
*,
|
|
duration: str = "permanent",
|
|
implicit: bool = False,
|
|
scopes: list[str],
|
|
state: str,
|
|
) -> str:
|
|
"""Return the URL used out-of-band to grant access to your application.
|
|
|
|
:param duration: Either ``"permanent"`` or ``"temporary"`` (default:
|
|
``"permanent"``). ``"temporary"`` authorizations generate access tokens that
|
|
last only 1 hour. ``"permanent"`` authorizations additionally generate a
|
|
refresh token that expires 1 year after the last use and can be used
|
|
indefinitely to generate new hour-long access tokens. This value is ignored
|
|
when ``implicit=True``.
|
|
:param implicit: For **installed** applications, this value can be set to use
|
|
the implicit, rather than the code flow. When ``True``, the ``duration``
|
|
argument has no effect as only temporary tokens can be retrieved.
|
|
:param scopes: A list of OAuth scopes to request authorization for.
|
|
:param state: A string that will be reflected in the callback to
|
|
``redirect_uri``. This value should be temporarily unique to the client for
|
|
whom the URL was generated for.
|
|
|
|
"""
|
|
authenticator = self._reddit._read_only_core._authorizer._authenticator
|
|
if authenticator.redirect_uri is self._reddit.config.CONFIG_NOT_SET:
|
|
msg = "redirect_uri must be provided"
|
|
raise MissingRequiredAttributeException(msg)
|
|
if isinstance(authenticator, UntrustedAuthenticator):
|
|
return authenticator.authorize_url(
|
|
"temporary" if implicit else duration,
|
|
scopes,
|
|
state,
|
|
implicit=implicit,
|
|
)
|
|
if implicit:
|
|
raise InvalidImplicitAuth
|
|
return authenticator.authorize_url(duration, scopes, state)
|