2026-02-01 09:31:38 +01:00

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)