about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints')
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py8
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py215
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py158
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py244
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py14
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py209
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py163
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py82
8 files changed, 1093 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py
new file mode 100644
index 00000000..9f30389f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py
@@ -0,0 +1,8 @@
+from .access_token import AccessTokenEndpoint
+from .authorization import AuthorizationEndpoint
+from .base import BaseEndpoint
+from .request_token import RequestTokenEndpoint
+from .resource import ResourceEndpoint
+from .signature_only import SignatureOnlyEndpoint
+
+from .pre_configured import WebApplicationServer  # isort:skip
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py
new file mode 100644
index 00000000..13665db0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py
@@ -0,0 +1,215 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.access_token
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of the access token provider logic of
+OAuth 1.0 RFC 5849. It validates the correctness of access token requests,
+creates and persists tokens as well as create the proper response to be
+returned to the client.
+"""
+import logging
+
+from oauthlib.common import urlencode
+
+from .. import errors
+from .base import BaseEndpoint
+
+log = logging.getLogger(__name__)
+
+
+class AccessTokenEndpoint(BaseEndpoint):
+
+    """An endpoint responsible for providing OAuth 1 access tokens.
+
+    Typical use is to instantiate with a request validator and invoke the
+    ``create_access_token_response`` from a view function. The tuple returned
+    has all information necessary (body, status, headers) to quickly form
+    and return a proper response. See :doc:`/oauth1/validator` for details on which
+    validator methods to implement for this endpoint.
+    """
+
+    def create_access_token(self, request, credentials):
+        """Create and save a new access token.
+
+        Similar to OAuth 2, indication of granted scopes will be included as a
+        space separated list in ``oauth_authorized_realms``.
+
+        :param request: OAuthlib request.
+        :type request: oauthlib.common.Request
+        :returns: The token as an urlencoded string.
+        """
+        request.realms = self.request_validator.get_realms(
+            request.resource_owner_key, request)
+        token = {
+            'oauth_token': self.token_generator(),
+            'oauth_token_secret': self.token_generator(),
+            # Backport the authorized scopes indication used in OAuth2
+            'oauth_authorized_realms': ' '.join(request.realms)
+        }
+        token.update(credentials)
+        self.request_validator.save_access_token(token, request)
+        return urlencode(token.items())
+
+    def create_access_token_response(self, uri, http_method='GET', body=None,
+                                     headers=None, credentials=None):
+        """Create an access token response, with a new request token if valid.
+
+        :param uri: The full URI of the token request.
+        :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+        :param body: The request body as a string.
+        :param headers: The request headers as a dict.
+        :param credentials: A list of extra credentials to include in the token.
+        :returns: A tuple of 3 elements.
+                  1. A dict of headers to set on the response.
+                  2. The response body as a string.
+                  3. The response status code as an integer.
+
+        An example of a valid request::
+
+            >>> from your_validator import your_validator
+            >>> from oauthlib.oauth1 import AccessTokenEndpoint
+            >>> endpoint = AccessTokenEndpoint(your_validator)
+            >>> h, b, s = endpoint.create_access_token_response(
+            ...     'https://your.provider/access_token?foo=bar',
+            ...     headers={
+            ...         'Authorization': 'OAuth oauth_token=234lsdkf....'
+            ...     },
+            ...     credentials={
+            ...         'my_specific': 'argument',
+            ...     })
+            >>> h
+            {'Content-Type': 'application/x-www-form-urlencoded'}
+            >>> b
+            'oauth_token=lsdkfol23w54jlksdef&oauth_token_secret=qwe089234lkjsdf&oauth_authorized_realms=movies+pics&my_specific=argument'
+            >>> s
+            200
+
+        An response to invalid request would have a different body and status::
+
+            >>> b
+            'error=invalid_request&description=missing+resource+owner+key'
+            >>> s
+            400
+
+        The same goes for an an unauthorized request:
+
+            >>> b
+            ''
+            >>> s
+            401
+        """
+        resp_headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+        try:
+            request = self._create_request(uri, http_method, body, headers)
+            valid, processed_request = self.validate_access_token_request(
+                request)
+            if valid:
+                token = self.create_access_token(request, credentials or {})
+                self.request_validator.invalidate_request_token(
+                    request.client_key,
+                    request.resource_owner_key,
+                    request)
+                return resp_headers, token, 200
+            else:
+                return {}, None, 401
+        except errors.OAuth1Error as e:
+            return resp_headers, e.urlencoded, e.status_code
+
+    def validate_access_token_request(self, request):
+        """Validate an access token request.
+
+        :param request: OAuthlib request.
+        :type request: oauthlib.common.Request
+        :raises: OAuth1Error if the request is invalid.
+        :returns: A tuple of 2 elements.
+                  1. The validation result (True or False).
+                  2. The request object.
+        """
+        self._check_transport_security(request)
+        self._check_mandatory_parameters(request)
+
+        if not request.resource_owner_key:
+            raise errors.InvalidRequestError(
+                description='Missing resource owner.')
+
+        if not self.request_validator.check_request_token(
+                request.resource_owner_key):
+            raise errors.InvalidRequestError(
+                description='Invalid resource owner key format.')
+
+        if not request.verifier:
+            raise errors.InvalidRequestError(
+                description='Missing verifier.')
+
+        if not self.request_validator.check_verifier(request.verifier):
+            raise errors.InvalidRequestError(
+                description='Invalid verifier format.')
+
+        if not self.request_validator.validate_timestamp_and_nonce(
+                request.client_key, request.timestamp, request.nonce, request,
+                request_token=request.resource_owner_key):
+            return False, request
+
+        # The server SHOULD return a 401 (Unauthorized) status code when
+        # receiving a request with invalid client credentials.
+        # Note: This is postponed in order to avoid timing attacks, instead
+        # a dummy client is assigned and used to maintain near constant
+        # time request verification.
+        #
+        # Note that early exit would enable client enumeration
+        valid_client = self.request_validator.validate_client_key(
+            request.client_key, request)
+        if not valid_client:
+            request.client_key = self.request_validator.dummy_client
+
+        # The server SHOULD return a 401 (Unauthorized) status code when
+        # receiving a request with invalid or expired token.
+        # Note: This is postponed in order to avoid timing attacks, instead
+        # a dummy token is assigned and used to maintain near constant
+        # time request verification.
+        #
+        # Note that early exit would enable resource owner enumeration
+        valid_resource_owner = self.request_validator.validate_request_token(
+            request.client_key, request.resource_owner_key, request)
+        if not valid_resource_owner:
+            request.resource_owner_key = self.request_validator.dummy_request_token
+
+        # The server MUST verify (Section 3.2) the validity of the request,
+        # ensure that the resource owner has authorized the provisioning of
+        # token credentials to the client, and ensure that the temporary
+        # credentials have not expired or been used before.  The server MUST
+        # also verify the verification code received from the client.
+        # .. _`Section 3.2`: https://tools.ietf.org/html/rfc5849#section-3.2
+        #
+        # Note that early exit would enable resource owner authorization
+        # verifier enumertion.
+        valid_verifier = self.request_validator.validate_verifier(
+            request.client_key,
+            request.resource_owner_key,
+            request.verifier,
+            request)
+
+        valid_signature = self._check_signature(request, is_token_request=True)
+
+        # log the results to the validator_log
+        # this lets us handle internal reporting and analysis
+        request.validator_log['client'] = valid_client
+        request.validator_log['resource_owner'] = valid_resource_owner
+        request.validator_log['verifier'] = valid_verifier
+        request.validator_log['signature'] = valid_signature
+
+        # We delay checking validity until the very end, using dummy values for
+        # calculations and fetching secrets/keys to ensure the flow of every
+        # request remains almost identical regardless of whether valid values
+        # have been supplied. This ensures near constant time execution and
+        # prevents malicious users from guessing sensitive information
+        v = all((valid_client, valid_resource_owner, valid_verifier,
+                 valid_signature))
+        if not v:
+            log.info("[Failure] request verification failed.")
+            log.info("Valid client:, %s", valid_client)
+            log.info("Valid token:, %s", valid_resource_owner)
+            log.info("Valid verifier:, %s", valid_verifier)
+            log.info("Valid signature:, %s", valid_signature)
+        return v, request
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py
new file mode 100644
index 00000000..00d9576b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py
@@ -0,0 +1,158 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.authorization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of various logic needed
+for signing and checking OAuth 1.0 RFC 5849 requests.
+"""
+from urllib.parse import urlencode
+
+from oauthlib.common import add_params_to_uri
+
+from .. import errors
+from .base import BaseEndpoint
+
+
+class AuthorizationEndpoint(BaseEndpoint):
+
+    """An endpoint responsible for letting authenticated users authorize access
+    to their protected resources to a client.
+
+    Typical use would be to have two views, one for displaying the authorization
+    form and one to process said form on submission.
+
+    The first view will want to utilize ``get_realms_and_credentials`` to fetch
+    requested realms and useful client credentials, such as name and
+    description, to be used when creating the authorization form.
+
+    During form processing you can use ``create_authorization_response`` to
+    validate the request, create a verifier as well as prepare the final
+    redirection URI used to send the user back to the client.
+
+    See :doc:`/oauth1/validator` for details on which validator methods to implement
+    for this endpoint.
+    """
+
+    def create_verifier(self, request, credentials):
+        """Create and save a new request token.
+
+        :param request: OAuthlib request.
+        :type request: oauthlib.common.Request
+        :param credentials: A dict of extra token credentials.
+        :returns: The verifier as a dict.
+        """
+        verifier = {
+            'oauth_token': request.resource_owner_key,
+            'oauth_verifier': self.token_generator(),
+        }
+        verifier.update(credentials)
+        self.request_validator.save_verifier(
+            request.resource_owner_key, verifier, request)
+        return verifier
+
+    def create_authorization_response(self, uri, http_method='GET', body=None,
+                                      headers=None, realms=None, credentials=None):
+        """Create an authorization response, with a new request token if valid.
+
+        :param uri: The full URI of the token request.
+        :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+        :param body: The request body as a string.
+        :param headers: The request headers as a dict.
+        :param credentials: A list of credentials to include in the verifier.
+        :returns: A tuple of 3 elements.
+                  1. A dict of headers to set on the response.
+                  2. The response body as a string.
+                  3. The response status code as an integer.
+
+        If the callback URI tied to the current token is "oob", a response with
+        a 200 status code will be returned. In this case, it may be desirable to
+        modify the response to better display the verifier to the client.
+
+        An example of an authorization request::
+
+            >>> from your_validator import your_validator
+            >>> from oauthlib.oauth1 import AuthorizationEndpoint
+            >>> endpoint = AuthorizationEndpoint(your_validator)
+            >>> h, b, s = endpoint.create_authorization_response(
+            ...     'https://your.provider/authorize?oauth_token=...',
+            ...     credentials={
+            ...         'extra': 'argument',
+            ...     })
+            >>> h
+            {'Location': 'https://the.client/callback?oauth_verifier=...&extra=argument'}
+            >>> b
+            None
+            >>> s
+            302
+
+        An example of a request with an "oob" callback::
+
+            >>> from your_validator import your_validator
+            >>> from oauthlib.oauth1 import AuthorizationEndpoint
+            >>> endpoint = AuthorizationEndpoint(your_validator)
+            >>> h, b, s = endpoint.create_authorization_response(
+            ...     'https://your.provider/authorize?foo=bar',
+            ...     credentials={
+            ...         'extra': 'argument',
+            ...     })
+            >>> h
+            {'Content-Type': 'application/x-www-form-urlencoded'}
+            >>> b
+            'oauth_verifier=...&extra=argument'
+            >>> s
+            200
+        """
+        request = self._create_request(uri, http_method=http_method, body=body,
+                                       headers=headers)
+
+        if not request.resource_owner_key:
+            raise errors.InvalidRequestError(
+                'Missing mandatory parameter oauth_token.')
+        if not self.request_validator.verify_request_token(
+                request.resource_owner_key, request):
+            raise errors.InvalidClientError()
+
+        request.realms = realms
+        if (request.realms and not self.request_validator.verify_realms(
+                request.resource_owner_key, request.realms, request)):
+            raise errors.InvalidRequestError(
+                description=('User granted access to realms outside of '
+                             'what the client may request.'))
+
+        verifier = self.create_verifier(request, credentials or {})
+        redirect_uri = self.request_validator.get_redirect_uri(
+            request.resource_owner_key, request)
+        if redirect_uri == 'oob':
+            response_headers = {
+                'Content-Type': 'application/x-www-form-urlencoded'}
+            response_body = urlencode(verifier)
+            return response_headers, response_body, 200
+        else:
+            populated_redirect = add_params_to_uri(
+                redirect_uri, verifier.items())
+            return {'Location': populated_redirect}, None, 302
+
+    def get_realms_and_credentials(self, uri, http_method='GET', body=None,
+                                   headers=None):
+        """Fetch realms and credentials for the presented request token.
+
+        :param uri: The full URI of the token request.
+        :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+        :param body: The request body as a string.
+        :param headers: The request headers as a dict.
+        :returns: A tuple of 2 elements.
+                  1. A list of request realms.
+                  2. A dict of credentials which may be useful in creating the
+                  authorization form.
+        """
+        request = self._create_request(uri, http_method=http_method, body=body,
+                                       headers=headers)
+
+        if not self.request_validator.verify_request_token(
+                request.resource_owner_key, request):
+            raise errors.InvalidClientError()
+
+        realms = self.request_validator.get_realms(
+            request.resource_owner_key, request)
+        return realms, {'resource_owner_key': request.resource_owner_key}
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py
new file mode 100644
index 00000000..7831be7c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py
@@ -0,0 +1,244 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.base
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of various logic needed
+for signing and checking OAuth 1.0 RFC 5849 requests.
+"""
+import time
+
+from oauthlib.common import CaseInsensitiveDict, Request, generate_token
+
+from .. import (
+    CONTENT_TYPE_FORM_URLENCODED, SIGNATURE_HMAC_SHA1, SIGNATURE_HMAC_SHA256,
+    SIGNATURE_HMAC_SHA512, SIGNATURE_PLAINTEXT, SIGNATURE_RSA_SHA1,
+    SIGNATURE_RSA_SHA256, SIGNATURE_RSA_SHA512, SIGNATURE_TYPE_AUTH_HEADER,
+    SIGNATURE_TYPE_BODY, SIGNATURE_TYPE_QUERY, errors, signature, utils,
+)
+
+
+class BaseEndpoint:
+
+    def __init__(self, request_validator, token_generator=None):
+        self.request_validator = request_validator
+        self.token_generator = token_generator or generate_token
+
+    def _get_signature_type_and_params(self, request):
+        """Extracts parameters from query, headers and body. Signature type
+        is set to the source in which parameters were found.
+        """
+        # Per RFC5849, only the Authorization header may contain the 'realm'
+        # optional parameter.
+        header_params = signature.collect_parameters(headers=request.headers,
+                                                     exclude_oauth_signature=False, with_realm=True)
+        body_params = signature.collect_parameters(body=request.body,
+                                                   exclude_oauth_signature=False)
+        query_params = signature.collect_parameters(uri_query=request.uri_query,
+                                                    exclude_oauth_signature=False)
+
+        params = []
+        params.extend(header_params)
+        params.extend(body_params)
+        params.extend(query_params)
+        signature_types_with_oauth_params = list(filter(lambda s: s[2], (
+            (SIGNATURE_TYPE_AUTH_HEADER, params,
+                utils.filter_oauth_params(header_params)),
+            (SIGNATURE_TYPE_BODY, params,
+                utils.filter_oauth_params(body_params)),
+            (SIGNATURE_TYPE_QUERY, params,
+                utils.filter_oauth_params(query_params))
+        )))
+
+        if len(signature_types_with_oauth_params) > 1:
+            found_types = [s[0] for s in signature_types_with_oauth_params]
+            raise errors.InvalidRequestError(
+                description=('oauth_ params must come from only 1 signature'
+                             'type but were found in %s',
+                             ', '.join(found_types)))
+
+        try:
+            signature_type, params, oauth_params = signature_types_with_oauth_params[
+                0]
+        except IndexError:
+            raise errors.InvalidRequestError(
+                description='Missing mandatory OAuth parameters.')
+
+        return signature_type, params, oauth_params
+
+    def _create_request(self, uri, http_method, body, headers):
+        # Only include body data from x-www-form-urlencoded requests
+        headers = CaseInsensitiveDict(headers or {})
+        if ("Content-Type" in headers and
+                CONTENT_TYPE_FORM_URLENCODED in headers["Content-Type"]):
+            request = Request(uri, http_method, body, headers)
+        else:
+            request = Request(uri, http_method, '', headers)
+
+        signature_type, params, oauth_params = (
+            self._get_signature_type_and_params(request))
+
+        # The server SHOULD return a 400 (Bad Request) status code when
+        # receiving a request with duplicated protocol parameters.
+        if len(dict(oauth_params)) != len(oauth_params):
+            raise errors.InvalidRequestError(
+                description='Duplicate OAuth1 entries.')
+
+        oauth_params = dict(oauth_params)
+        request.signature = oauth_params.get('oauth_signature')
+        request.client_key = oauth_params.get('oauth_consumer_key')
+        request.resource_owner_key = oauth_params.get('oauth_token')
+        request.nonce = oauth_params.get('oauth_nonce')
+        request.timestamp = oauth_params.get('oauth_timestamp')
+        request.redirect_uri = oauth_params.get('oauth_callback')
+        request.verifier = oauth_params.get('oauth_verifier')
+        request.signature_method = oauth_params.get('oauth_signature_method')
+        request.realm = dict(params).get('realm')
+        request.oauth_params = oauth_params
+
+        # Parameters to Client depend on signature method which may vary
+        # for each request. Note that HMAC-SHA1 and PLAINTEXT share parameters
+        request.params = [(k, v) for k, v in params if k != "oauth_signature"]
+
+        if 'realm' in request.headers.get('Authorization', ''):
+            request.params = [(k, v)
+                              for k, v in request.params if k != "realm"]
+
+        return request
+
+    def _check_transport_security(self, request):
+        # TODO: move into oauthlib.common from oauth2.utils
+        if (self.request_validator.enforce_ssl and
+                not request.uri.lower().startswith("https://")):
+            raise errors.InsecureTransportError()
+
+    def _check_mandatory_parameters(self, request):
+        # The server SHOULD return a 400 (Bad Request) status code when
+        # receiving a request with missing parameters.
+        if not all((request.signature, request.client_key,
+                    request.nonce, request.timestamp,
+                    request.signature_method)):
+            raise errors.InvalidRequestError(
+                description='Missing mandatory OAuth parameters.')
+
+        # OAuth does not mandate a particular signature method, as each
+        # implementation can have its own unique requirements.  Servers are
+        # free to implement and document their own custom methods.
+        # Recommending any particular method is beyond the scope of this
+        # specification.  Implementers should review the Security
+        # Considerations section (`Section 4`_) before deciding on which
+        # method to support.
+        # .. _`Section 4`: https://tools.ietf.org/html/rfc5849#section-4
+        if (not request.signature_method in
+                self.request_validator.allowed_signature_methods):
+            raise errors.InvalidSignatureMethodError(
+                description="Invalid signature, {} not in {!r}.".format(
+                    request.signature_method,
+                    self.request_validator.allowed_signature_methods))
+
+        # Servers receiving an authenticated request MUST validate it by:
+        #   If the "oauth_version" parameter is present, ensuring its value is
+        #   "1.0".
+        if ('oauth_version' in request.oauth_params and
+                request.oauth_params['oauth_version'] != '1.0'):
+            raise errors.InvalidRequestError(
+                description='Invalid OAuth version.')
+
+        # The timestamp value MUST be a positive integer. Unless otherwise
+        # specified by the server's documentation, the timestamp is expressed
+        # in the number of seconds since January 1, 1970 00:00:00 GMT.
+        if len(request.timestamp) != 10:
+            raise errors.InvalidRequestError(
+                description='Invalid timestamp size')
+
+        try:
+            ts = int(request.timestamp)
+
+        except ValueError:
+            raise errors.InvalidRequestError(
+                description='Timestamp must be an integer.')
+
+        else:
+            # To avoid the need to retain an infinite number of nonce values for
+            # future checks, servers MAY choose to restrict the time period after
+            # which a request with an old timestamp is rejected.
+            if abs(time.time() - ts) > self.request_validator.timestamp_lifetime:
+                raise errors.InvalidRequestError(
+                    description=('Timestamp given is invalid, differ from '
+                                 'allowed by over %s seconds.' % (
+                                     self.request_validator.timestamp_lifetime)))
+
+        # Provider specific validation of parameters, used to enforce
+        # restrictions such as character set and length.
+        if not self.request_validator.check_client_key(request.client_key):
+            raise errors.InvalidRequestError(
+                description='Invalid client key format.')
+
+        if not self.request_validator.check_nonce(request.nonce):
+            raise errors.InvalidRequestError(
+                description='Invalid nonce format.')
+
+    def _check_signature(self, request, is_token_request=False):
+        # ---- RSA Signature verification ----
+        if request.signature_method == SIGNATURE_RSA_SHA1 or \
+           request.signature_method == SIGNATURE_RSA_SHA256 or \
+           request.signature_method == SIGNATURE_RSA_SHA512:
+            # RSA-based signature method
+
+            # The server verifies the signature per `[RFC3447] section 8.2.2`_
+            # .. _`[RFC3447] section 8.2.2`: https://tools.ietf.org/html/rfc3447#section-8.2.1
+
+            rsa_key = self.request_validator.get_rsa_key(
+                request.client_key, request)
+
+            if request.signature_method == SIGNATURE_RSA_SHA1:
+                valid_signature = signature.verify_rsa_sha1(request, rsa_key)
+            elif request.signature_method == SIGNATURE_RSA_SHA256:
+                valid_signature = signature.verify_rsa_sha256(request, rsa_key)
+            elif request.signature_method == SIGNATURE_RSA_SHA512:
+                valid_signature = signature.verify_rsa_sha512(request, rsa_key)
+            else:
+                valid_signature = False
+
+        # ---- HMAC or Plaintext Signature verification ----
+        else:
+            # Non-RSA based signature method
+
+            # Servers receiving an authenticated request MUST validate it by:
+            #   Recalculating the request signature independently as described in
+            #   `Section 3.4`_ and comparing it to the value received from the
+            #   client via the "oauth_signature" parameter.
+            # .. _`Section 3.4`: https://tools.ietf.org/html/rfc5849#section-3.4
+
+            client_secret = self.request_validator.get_client_secret(
+                request.client_key, request)
+
+            resource_owner_secret = None
+            if request.resource_owner_key:
+                if is_token_request:
+                    resource_owner_secret = \
+                        self.request_validator.get_request_token_secret(
+                            request.client_key, request.resource_owner_key,
+                            request)
+                else:
+                    resource_owner_secret = \
+                        self.request_validator.get_access_token_secret(
+                            request.client_key, request.resource_owner_key,
+                            request)
+
+            if request.signature_method == SIGNATURE_HMAC_SHA1:
+                valid_signature = signature.verify_hmac_sha1(
+                    request, client_secret, resource_owner_secret)
+            elif request.signature_method == SIGNATURE_HMAC_SHA256:
+                valid_signature = signature.verify_hmac_sha256(
+                    request, client_secret, resource_owner_secret)
+            elif request.signature_method == SIGNATURE_HMAC_SHA512:
+                valid_signature = signature.verify_hmac_sha512(
+                    request, client_secret, resource_owner_secret)
+            elif request.signature_method == SIGNATURE_PLAINTEXT:
+                valid_signature = signature.verify_plaintext(
+                    request, client_secret, resource_owner_secret)
+            else:
+                valid_signature = False
+
+        return valid_signature
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py
new file mode 100644
index 00000000..23e3cfc8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py
@@ -0,0 +1,14 @@
+from . import (
+    AccessTokenEndpoint, AuthorizationEndpoint, RequestTokenEndpoint,
+    ResourceEndpoint,
+)
+
+
+class WebApplicationServer(RequestTokenEndpoint, AuthorizationEndpoint,
+                           AccessTokenEndpoint, ResourceEndpoint):
+
+    def __init__(self, request_validator):
+        RequestTokenEndpoint.__init__(self, request_validator)
+        AuthorizationEndpoint.__init__(self, request_validator)
+        AccessTokenEndpoint.__init__(self, request_validator)
+        ResourceEndpoint.__init__(self, request_validator)
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py
new file mode 100644
index 00000000..0323cfb8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py
@@ -0,0 +1,209 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.request_token
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of the request token provider logic of
+OAuth 1.0 RFC 5849. It validates the correctness of request token requests,
+creates and persists tokens as well as create the proper response to be
+returned to the client.
+"""
+import logging
+
+from oauthlib.common import urlencode
+
+from .. import errors
+from .base import BaseEndpoint
+
+log = logging.getLogger(__name__)
+
+
+class RequestTokenEndpoint(BaseEndpoint):
+
+    """An endpoint responsible for providing OAuth 1 request tokens.
+
+    Typical use is to instantiate with a request validator and invoke the
+    ``create_request_token_response`` from a view function. The tuple returned
+    has all information necessary (body, status, headers) to quickly form
+    and return a proper response. See :doc:`/oauth1/validator` for details on which
+    validator methods to implement for this endpoint.
+    """
+
+    def create_request_token(self, request, credentials):
+        """Create and save a new request token.
+
+        :param request: OAuthlib request.
+        :type request: oauthlib.common.Request
+        :param credentials: A dict of extra token credentials.
+        :returns: The token as an urlencoded string.
+        """
+        token = {
+            'oauth_token': self.token_generator(),
+            'oauth_token_secret': self.token_generator(),
+            'oauth_callback_confirmed': 'true'
+        }
+        token.update(credentials)
+        self.request_validator.save_request_token(token, request)
+        return urlencode(token.items())
+
+    def create_request_token_response(self, uri, http_method='GET', body=None,
+                                      headers=None, credentials=None):
+        """Create a request token response, with a new request token if valid.
+
+        :param uri: The full URI of the token request.
+        :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+        :param body: The request body as a string.
+        :param headers: The request headers as a dict.
+        :param credentials: A list of extra credentials to include in the token.
+        :returns: A tuple of 3 elements.
+                  1. A dict of headers to set on the response.
+                  2. The response body as a string.
+                  3. The response status code as an integer.
+
+        An example of a valid request::
+
+            >>> from your_validator import your_validator
+            >>> from oauthlib.oauth1 import RequestTokenEndpoint
+            >>> endpoint = RequestTokenEndpoint(your_validator)
+            >>> h, b, s = endpoint.create_request_token_response(
+            ...     'https://your.provider/request_token?foo=bar',
+            ...     headers={
+            ...         'Authorization': 'OAuth realm=movies user, oauth_....'
+            ...     },
+            ...     credentials={
+            ...         'my_specific': 'argument',
+            ...     })
+            >>> h
+            {'Content-Type': 'application/x-www-form-urlencoded'}
+            >>> b
+            'oauth_token=lsdkfol23w54jlksdef&oauth_token_secret=qwe089234lkjsdf&oauth_callback_confirmed=true&my_specific=argument'
+            >>> s
+            200
+
+        An response to invalid request would have a different body and status::
+
+            >>> b
+            'error=invalid_request&description=missing+callback+uri'
+            >>> s
+            400
+
+        The same goes for an an unauthorized request:
+
+            >>> b
+            ''
+            >>> s
+            401
+        """
+        resp_headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+        try:
+            request = self._create_request(uri, http_method, body, headers)
+            valid, processed_request = self.validate_request_token_request(
+                request)
+            if valid:
+                token = self.create_request_token(request, credentials or {})
+                return resp_headers, token, 200
+            else:
+                return {}, None, 401
+        except errors.OAuth1Error as e:
+            return resp_headers, e.urlencoded, e.status_code
+
+    def validate_request_token_request(self, request):
+        """Validate a request token request.
+
+        :param request: OAuthlib request.
+        :type request: oauthlib.common.Request
+        :raises: OAuth1Error if the request is invalid.
+        :returns: A tuple of 2 elements.
+                  1. The validation result (True or False).
+                  2. The request object.
+        """
+        self._check_transport_security(request)
+        self._check_mandatory_parameters(request)
+
+        if request.realm:
+            request.realms = request.realm.split(' ')
+        else:
+            request.realms = self.request_validator.get_default_realms(
+                request.client_key, request)
+        if not self.request_validator.check_realms(request.realms):
+            raise errors.InvalidRequestError(
+                description='Invalid realm {}. Allowed are {!r}.'.format(
+                    request.realms, self.request_validator.realms))
+
+        if not request.redirect_uri:
+            raise errors.InvalidRequestError(
+                description='Missing callback URI.')
+
+        if not self.request_validator.validate_timestamp_and_nonce(
+                request.client_key, request.timestamp, request.nonce, request,
+                request_token=request.resource_owner_key):
+            return False, request
+
+        # The server SHOULD return a 401 (Unauthorized) status code when
+        # receiving a request with invalid client credentials.
+        # Note: This is postponed in order to avoid timing attacks, instead
+        # a dummy client is assigned and used to maintain near constant
+        # time request verification.
+        #
+        # Note that early exit would enable client enumeration
+        valid_client = self.request_validator.validate_client_key(
+            request.client_key, request)
+        if not valid_client:
+            request.client_key = self.request_validator.dummy_client
+
+        # Note that `realm`_ is only used in authorization headers and how
+        # it should be interpreted is not included in the OAuth spec.
+        # However they could be seen as a scope or realm to which the
+        # client has access and as such every client should be checked
+        # to ensure it is authorized access to that scope or realm.
+        # .. _`realm`: https://tools.ietf.org/html/rfc2617#section-1.2
+        #
+        # Note that early exit would enable client realm access enumeration.
+        #
+        # The require_realm indicates this is the first step in the OAuth
+        # workflow where a client requests access to a specific realm.
+        # This first step (obtaining request token) need not require a realm
+        # and can then be identified by checking the require_resource_owner
+        # flag and absence of realm.
+        #
+        # Clients obtaining an access token will not supply a realm and it will
+        # not be checked. Instead the previously requested realm should be
+        # transferred from the request token to the access token.
+        #
+        # Access to protected resources will always validate the realm but note
+        # that the realm is now tied to the access token and not provided by
+        # the client.
+        valid_realm = self.request_validator.validate_requested_realms(
+            request.client_key, request.realms, request)
+
+        # Callback is normally never required, except for requests for
+        # a Temporary Credential as described in `Section 2.1`_
+        # .._`Section 2.1`: https://tools.ietf.org/html/rfc5849#section-2.1
+        valid_redirect = self.request_validator.validate_redirect_uri(
+            request.client_key, request.redirect_uri, request)
+        if not request.redirect_uri:
+            raise NotImplementedError('Redirect URI must either be provided '
+                                      'or set to a default during validation.')
+
+        valid_signature = self._check_signature(request)
+
+        # log the results to the validator_log
+        # this lets us handle internal reporting and analysis
+        request.validator_log['client'] = valid_client
+        request.validator_log['realm'] = valid_realm
+        request.validator_log['callback'] = valid_redirect
+        request.validator_log['signature'] = valid_signature
+
+        # We delay checking validity until the very end, using dummy values for
+        # calculations and fetching secrets/keys to ensure the flow of every
+        # request remains almost identical regardless of whether valid values
+        # have been supplied. This ensures near constant time execution and
+        # prevents malicious users from guessing sensitive information
+        v = all((valid_client, valid_realm, valid_redirect, valid_signature))
+        if not v:
+            log.info("[Failure] request verification failed.")
+            log.info("Valid client: %s.", valid_client)
+            log.info("Valid realm: %s.", valid_realm)
+            log.info("Valid callback: %s.", valid_redirect)
+            log.info("Valid signature: %s.", valid_signature)
+        return v, request
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py
new file mode 100644
index 00000000..8641152e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py
@@ -0,0 +1,163 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.resource
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of the resource protection provider logic of
+OAuth 1.0 RFC 5849.
+"""
+import logging
+
+from .. import errors
+from .base import BaseEndpoint
+
+log = logging.getLogger(__name__)
+
+
+class ResourceEndpoint(BaseEndpoint):
+
+    """An endpoint responsible for protecting resources.
+
+    Typical use is to instantiate with a request validator and invoke the
+    ``validate_protected_resource_request`` in a decorator around a view
+    function. If the request is valid, invoke and return the response of the
+    view. If invalid create and return an error response directly from the
+    decorator.
+
+    See :doc:`/oauth1/validator` for details on which validator methods to implement
+    for this endpoint.
+
+    An example decorator::
+
+        from functools import wraps
+        from your_validator import your_validator
+        from oauthlib.oauth1 import ResourceEndpoint
+        endpoint = ResourceEndpoint(your_validator)
+
+        def require_oauth(realms=None):
+            def decorator(f):
+                @wraps(f)
+                def wrapper(request, *args, **kwargs):
+                    v, r = provider.validate_protected_resource_request(
+                            request.url,
+                            http_method=request.method,
+                            body=request.data,
+                            headers=request.headers,
+                            realms=realms or [])
+                    if v:
+                        return f(*args, **kwargs)
+                    else:
+                        return abort(403)
+    """
+
+    def validate_protected_resource_request(self, uri, http_method='GET',
+                                            body=None, headers=None, realms=None):
+        """Create a request token response, with a new request token if valid.
+
+        :param uri: The full URI of the token request.
+        :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+        :param body: The request body as a string.
+        :param headers: The request headers as a dict.
+        :param realms: A list of realms the resource is protected under.
+                       This will be supplied to the ``validate_realms``
+                       method of the request validator.
+        :returns: A tuple of 2 elements.
+                  1. True if valid, False otherwise.
+                  2. An oauthlib.common.Request object.
+        """
+        try:
+            request = self._create_request(uri, http_method, body, headers)
+        except errors.OAuth1Error:
+            return False, None
+
+        try:
+            self._check_transport_security(request)
+            self._check_mandatory_parameters(request)
+        except errors.OAuth1Error:
+            return False, request
+
+        if not request.resource_owner_key:
+            return False, request
+
+        if not self.request_validator.check_access_token(
+                request.resource_owner_key):
+            return False, request
+
+        if not self.request_validator.validate_timestamp_and_nonce(
+                request.client_key, request.timestamp, request.nonce, request,
+                access_token=request.resource_owner_key):
+            return False, request
+
+        # The server SHOULD return a 401 (Unauthorized) status code when
+        # receiving a request with invalid client credentials.
+        # Note: This is postponed in order to avoid timing attacks, instead
+        # a dummy client is assigned and used to maintain near constant
+        # time request verification.
+        #
+        # Note that early exit would enable client enumeration
+        valid_client = self.request_validator.validate_client_key(
+            request.client_key, request)
+        if not valid_client:
+            request.client_key = self.request_validator.dummy_client
+
+        # The server SHOULD return a 401 (Unauthorized) status code when
+        # receiving a request with invalid or expired token.
+        # Note: This is postponed in order to avoid timing attacks, instead
+        # a dummy token is assigned and used to maintain near constant
+        # time request verification.
+        #
+        # Note that early exit would enable resource owner enumeration
+        valid_resource_owner = self.request_validator.validate_access_token(
+            request.client_key, request.resource_owner_key, request)
+        if not valid_resource_owner:
+            request.resource_owner_key = self.request_validator.dummy_access_token
+
+        # Note that `realm`_ is only used in authorization headers and how
+        # it should be interpreted is not included in the OAuth spec.
+        # However they could be seen as a scope or realm to which the
+        # client has access and as such every client should be checked
+        # to ensure it is authorized access to that scope or realm.
+        # .. _`realm`: https://tools.ietf.org/html/rfc2617#section-1.2
+        #
+        # Note that early exit would enable client realm access enumeration.
+        #
+        # The require_realm indicates this is the first step in the OAuth
+        # workflow where a client requests access to a specific realm.
+        # This first step (obtaining request token) need not require a realm
+        # and can then be identified by checking the require_resource_owner
+        # flag and absence of realm.
+        #
+        # Clients obtaining an access token will not supply a realm and it will
+        # not be checked. Instead the previously requested realm should be
+        # transferred from the request token to the access token.
+        #
+        # Access to protected resources will always validate the realm but note
+        # that the realm is now tied to the access token and not provided by
+        # the client.
+        valid_realm = self.request_validator.validate_realms(request.client_key,
+                                                             request.resource_owner_key, request, uri=request.uri,
+                                                             realms=realms)
+
+        valid_signature = self._check_signature(request)
+
+        # log the results to the validator_log
+        # this lets us handle internal reporting and analysis
+        request.validator_log['client'] = valid_client
+        request.validator_log['resource_owner'] = valid_resource_owner
+        request.validator_log['realm'] = valid_realm
+        request.validator_log['signature'] = valid_signature
+
+        # We delay checking validity until the very end, using dummy values for
+        # calculations and fetching secrets/keys to ensure the flow of every
+        # request remains almost identical regardless of whether valid values
+        # have been supplied. This ensures near constant time execution and
+        # prevents malicious users from guessing sensitive information
+        v = all((valid_client, valid_resource_owner, valid_realm,
+                 valid_signature))
+        if not v:
+            log.info("[Failure] request verification failed.")
+            log.info("Valid client: %s", valid_client)
+            log.info("Valid token: %s", valid_resource_owner)
+            log.info("Valid realm: %s", valid_realm)
+            log.info("Valid signature: %s", valid_signature)
+        return v, request
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py
new file mode 100644
index 00000000..d693ccb7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.signature_only
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of the signing logic of OAuth 1.0 RFC 5849.
+"""
+
+import logging
+
+from .. import errors
+from .base import BaseEndpoint
+
+log = logging.getLogger(__name__)
+
+
+class SignatureOnlyEndpoint(BaseEndpoint):
+
+    """An endpoint only responsible for verifying an oauth signature."""
+
+    def validate_request(self, uri, http_method='GET',
+                         body=None, headers=None):
+        """Validate a signed OAuth request.
+
+        :param uri: The full URI of the token request.
+        :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+        :param body: The request body as a string.
+        :param headers: The request headers as a dict.
+        :returns: A tuple of 2 elements.
+                  1. True if valid, False otherwise.
+                  2. An oauthlib.common.Request object.
+        """
+        try:
+            request = self._create_request(uri, http_method, body, headers)
+        except errors.OAuth1Error as err:
+            log.info(
+                'Exception caught while validating request, %s.' % err)
+            return False, None
+
+        try:
+            self._check_transport_security(request)
+            self._check_mandatory_parameters(request)
+        except errors.OAuth1Error as err:
+            log.info(
+                'Exception caught while validating request, %s.' % err)
+            return False, request
+
+        if not self.request_validator.validate_timestamp_and_nonce(
+                request.client_key, request.timestamp, request.nonce, request):
+            log.debug('[Failure] verification failed: timestamp/nonce')
+            return False, request
+
+        # The server SHOULD return a 401 (Unauthorized) status code when
+        # receiving a request with invalid client credentials.
+        # Note: This is postponed in order to avoid timing attacks, instead
+        # a dummy client is assigned and used to maintain near constant
+        # time request verification.
+        #
+        # Note that early exit would enable client enumeration
+        valid_client = self.request_validator.validate_client_key(
+            request.client_key, request)
+        if not valid_client:
+            request.client_key = self.request_validator.dummy_client
+
+        valid_signature = self._check_signature(request)
+
+        # log the results to the validator_log
+        # this lets us handle internal reporting and analysis
+        request.validator_log['client'] = valid_client
+        request.validator_log['signature'] = valid_signature
+
+        # We delay checking validity until the very end, using dummy values for
+        # calculations and fetching secrets/keys to ensure the flow of every
+        # request remains almost identical regardless of whether valid values
+        # have been supplied. This ensures near constant time execution and
+        # prevents malicious users from guessing sensitive information
+        v = all((valid_client, valid_signature))
+        if not v:
+            log.info("[Failure] request verification failed.")
+            log.info("Valid client: %s", valid_client)
+            log.info("Valid signature: %s", valid_signature)
+        return v, request