tty1
  "   li~h8Z!\e1hy      # Copyright (C) 2023 Red Hat, Inc., Jose Castillo <jcastillo@redhat.com>

# This file is part of the sos project: https://github.com/sosreport/sos
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# version 2 of the GNU General Public License.
#
# See the LICENSE file in the source distribution for further information.

import logging
try:
    import requests
    REQUESTS_LOADED = True
except ImportError:
    REQUESTS_LOADED = False
import time
from datetime import datetime, timedelta

DEVICE_AUTH_CLIENT_ID = "sos-tools"
GRANT_TYPE_DEVICE_CODE = "urn:ietf:params:oauth:grant-type:device_code"

logger = logging.getLogger("sos")


class DeviceAuthorizationClass:
    """
    Device Authorization Class
    """

    def __init__(self, client_identifier_url, token_endpoint):

        self._access_token = None
        self._access_expires_at = None
        self.__device_code = None

        self.client_identifier_url = client_identifier_url
        self.token_endpoint = token_endpoint
        self._use_device_code_grant()

    def _use_device_code_grant(self):
        """
        Start the device auth flow. In the future we will
        store the tokens in an in-memory keyring.
        """

        self._request_device_code()
        print(
            "Please visit the following URL to authenticate this device: {}"
            .format(self._verification_uri_complete)
        )
        self.poll_for_auth_completion()

    def _request_device_code(self):
        """
        Initialize new Device Authorization Grant attempt by
        requesting a new device code.
        """
        data = "client_id={}".format(DEVICE_AUTH_CLIENT_ID)
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        if not REQUESTS_LOADED:
            raise Exception("python3-requests is not installed and is required"
                            " for obtaining device auth token.")
        try:
            res = requests.post(
                self.client_identifier_url,
                data=data,
                headers=headers)
            res.raise_for_status()
            response = res.json()
            self._user_code = response.get("user_code")
            self._verification_uri = response.get("verification_uri")
            self._interval = response.get("interval")
            self.__device_code = response.get("device_code")
            self._verification_uri_complete = response.get(
                "verification_uri_complete")
        except requests.HTTPError as e:
            raise requests.HTTPError(
                "HTTP request failed while attempting to acquire the tokens."
                " Error returned was {}".format(res.status_code)
            )

    def poll_for_auth_completion(self):
        """
        Continuously poll OIDC token endpoint until the user is successfully
        authenticated or an error occurs.
        """
        token_data = {'grant_type': GRANT_TYPE_DEVICE_CODE,
                      'client_id': DEVICE_AUTH_CLIENT_ID,
                      'device_code': self.__device_code}

        if not REQUESTS_LOADED:
            raise Exception("python3-requests is not installed and is required"
                            " for obtaining device auth token.")
        while self._access_token is None:
            time.sleep(self._interval)
            try:
                check_auth_completion = requests.post(self.token_endpoint,
                                                      data=token_data)

                status_code = check_auth_completion.status_code

                if status_code == 200:
                    logger.info("The SSO authentication is successful")
                    self._set_token_data(check_auth_completion.json())
                if status_code not in [200, 400]:
                    raise Exception(status_code, check_auth_completion.text)
                if status_code == 400 and \
                    check_auth_completi