Fix number of mypy mistakes

CURA-5744
This commit is contained in:
Jaime van Kessel 2018-09-21 13:54:37 +02:00
parent 3ae223334f
commit d0fc4878c2
5 changed files with 33 additions and 20 deletions

View file

@ -16,7 +16,7 @@ from cura.OAuth2.Models import AuthenticationResponse, UserProfile, OAuth2Settin
class AuthorizationHelpers: class AuthorizationHelpers:
"""Class containing several helpers to deal with the authorization flow.""" """Class containing several helpers to deal with the authorization flow."""
def __init__(self, settings: "OAuth2Settings"): def __init__(self, settings: "OAuth2Settings") -> None:
self._settings = settings self._settings = settings
self._token_url = "{}/token".format(self._settings.OAUTH_SERVER_URL) self._token_url = "{}/token".format(self._settings.OAUTH_SERVER_URL)
@ -25,8 +25,7 @@ class AuthorizationHelpers:
"""Get the OAuth2 settings object.""" """Get the OAuth2 settings object."""
return self._settings return self._settings
def getAccessTokenUsingAuthorizationCode(self, authorization_code: str, verification_code: str)->\ def getAccessTokenUsingAuthorizationCode(self, authorization_code: str, verification_code: str)-> "AuthenticationResponse":
Optional["AuthenticationResponse"]:
""" """
Request the access token from the authorization server. Request the access token from the authorization server.
:param authorization_code: The authorization code from the 1st step. :param authorization_code: The authorization code from the 1st step.
@ -42,7 +41,7 @@ class AuthorizationHelpers:
"scope": self._settings.CLIENT_SCOPES "scope": self._settings.CLIENT_SCOPES
})) }))
def getAccessTokenUsingRefreshToken(self, refresh_token: str) -> Optional["AuthenticationResponse"]: def getAccessTokenUsingRefreshToken(self, refresh_token: str) -> AuthenticationResponse:
""" """
Request the access token from the authorization server using a refresh token. Request the access token from the authorization server using a refresh token.
:param refresh_token: :param refresh_token:
@ -57,7 +56,7 @@ class AuthorizationHelpers:
})) }))
@staticmethod @staticmethod
def parseTokenResponse(token_response: "requests.request") -> Optional["AuthenticationResponse"]: def parseTokenResponse(token_response: requests.models.Response) -> AuthenticationResponse:
""" """
Parse the token response from the authorization server into an AuthenticationResponse object. Parse the token response from the authorization server into an AuthenticationResponse object.
:param token_response: The JSON string data response from the authorization server. :param token_response: The JSON string data response from the authorization server.

View file

@ -1,6 +1,6 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional, Callable from typing import Optional, Callable, Tuple, Dict, Any, List
from http.server import BaseHTTPRequestHandler from http.server import BaseHTTPRequestHandler
from urllib.parse import parse_qs, urlparse from urllib.parse import parse_qs, urlparse
@ -49,16 +49,17 @@ class AuthorizationRequestHandler(BaseHTTPRequestHandler):
# This will cause the server to shut down, so we do it at the very end of the request handling. # This will cause the server to shut down, so we do it at the very end of the request handling.
self.authorization_callback(token_response) self.authorization_callback(token_response)
def _handleCallback(self, query: dict) -> ("ResponseData", Optional["AuthenticationResponse"]): def _handleCallback(self, query: Dict[Any, List]) -> Tuple["ResponseData", Optional["AuthenticationResponse"]]:
""" """
Handler for the callback URL redirect. Handler for the callback URL redirect.
:param query: Dict containing the HTTP query parameters. :param query: Dict containing the HTTP query parameters.
:return: HTTP ResponseData containing a success page to show to the user. :return: HTTP ResponseData containing a success page to show to the user.
""" """
if self._queryGet(query, "code"): code = self._queryGet(query, "code")
if code:
# If the code was returned we get the access token. # If the code was returned we get the access token.
token_response = self.authorization_helpers.getAccessTokenUsingAuthorizationCode( token_response = self.authorization_helpers.getAccessTokenUsingAuthorizationCode(
self._queryGet(query, "code"), self.verification_code) code, self.verification_code)
elif self._queryGet(query, "error_code") == "user_denied": elif self._queryGet(query, "error_code") == "user_denied":
# Otherwise we show an error message (probably the user clicked "Deny" in the auth dialog). # Otherwise we show an error message (probably the user clicked "Deny" in the auth dialog).
@ -99,6 +100,6 @@ class AuthorizationRequestHandler(BaseHTTPRequestHandler):
self.wfile.write(data) self.wfile.write(data)
@staticmethod @staticmethod
def _queryGet(query_data: dict, key: str, default=None) -> Optional[str]: def _queryGet(query_data: Dict[Any, List], key: str, default=None) -> Optional[str]:
"""Helper for getting values from a pre-parsed query string""" """Helper for getting values from a pre-parsed query string"""
return query_data.get(key, [default])[0] return query_data.get(key, [default])[0]

View file

@ -27,7 +27,7 @@ class AuthorizationService:
# Emit signal when authentication failed. # Emit signal when authentication failed.
onAuthenticationError = Signal() onAuthenticationError = Signal()
def __init__(self, preferences, settings: "OAuth2Settings"): def __init__(self, preferences, settings: "OAuth2Settings") -> None:
self._settings = settings self._settings = settings
self._auth_helpers = AuthorizationHelpers(settings) self._auth_helpers = AuthorizationHelpers(settings)
self._auth_url = "{}/authorize".format(self._settings.OAUTH_SERVER_URL) self._auth_url = "{}/authorize".format(self._settings.OAUTH_SERVER_URL)
@ -55,7 +55,7 @@ class AuthorizationService:
Tries to parse the JWT if all the needed data exists. Tries to parse the JWT if all the needed data exists.
:return: UserProfile if found, otherwise None. :return: UserProfile if found, otherwise None.
""" """
if not self._auth_data: if not self._auth_data or self._auth_data.access_token is None:
# If no auth data exists, we should always log in again. # If no auth data exists, we should always log in again.
return None return None
user_data = self._auth_helpers.parseJWT(self._auth_data.access_token) user_data = self._auth_helpers.parseJWT(self._auth_data.access_token)
@ -63,10 +63,13 @@ class AuthorizationService:
# If the profile was found, we return it immediately. # If the profile was found, we return it immediately.
return user_data return user_data
# The JWT was expired or invalid and we should request a new one. # The JWT was expired or invalid and we should request a new one.
if self._auth_data.refresh_token is None:
return None
self._auth_data = self._auth_helpers.getAccessTokenUsingRefreshToken(self._auth_data.refresh_token) self._auth_data = self._auth_helpers.getAccessTokenUsingRefreshToken(self._auth_data.refresh_token)
if not self._auth_data: if not self._auth_data or self._auth_data.access_token is None:
# The token could not be refreshed using the refresh token. We should login again. # The token could not be refreshed using the refresh token. We should login again.
return None return None
return self._auth_helpers.parseJWT(self._auth_data.access_token) return self._auth_helpers.parseJWT(self._auth_data.access_token)
def getAccessToken(self) -> Optional[str]: def getAccessToken(self) -> Optional[str]:
@ -78,16 +81,23 @@ class AuthorizationService:
# We check if we can get the user profile. # We check if we can get the user profile.
# If we can't get it, that means the access token (JWT) was invalid or expired. # If we can't get it, that means the access token (JWT) was invalid or expired.
return None return None
if self._auth_data is None:
return None
return self._auth_data.access_token return self._auth_data.access_token
def refreshAccessToken(self) -> None: def refreshAccessToken(self) -> None:
""" """
Refresh the access token when it expired. Refresh the access token when it expired.
""" """
if self._auth_data is None or self._auth_data.refresh_token is None:
Logger.log("w", "Unable to refresh acces token, since there is no refresh token.")
return
self._storeAuthData(self._auth_helpers.getAccessTokenUsingRefreshToken(self._auth_data.refresh_token)) self._storeAuthData(self._auth_helpers.getAccessTokenUsingRefreshToken(self._auth_data.refresh_token))
self.onAuthStateChanged.emit(logged_in=True) self.onAuthStateChanged.emit(logged_in=True)
def deleteAuthData(self): def deleteAuthData(self) -> None:
"""Delete authentication data from preferences and locally.""" """Delete authentication data from preferences and locally."""
self._storeAuthData() self._storeAuthData()
self.onAuthStateChanged.emit(logged_in=False) self.onAuthStateChanged.emit(logged_in=False)

View file

@ -2,7 +2,7 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import threading import threading
from http.server import HTTPServer from http.server import HTTPServer
from typing import Optional, Callable from typing import Optional, Callable, Any
# As this module is specific for Cura plugins, we can rely on these imports. # As this module is specific for Cura plugins, we can rely on these imports.
from UM.Logger import Logger from UM.Logger import Logger
@ -16,22 +16,22 @@ from cura.OAuth2.Models import AuthenticationResponse
class LocalAuthorizationServer: class LocalAuthorizationServer:
def __init__(self, auth_helpers: "AuthorizationHelpers", def __init__(self, auth_helpers: "AuthorizationHelpers",
auth_state_changed_callback: "Callable[[AuthenticationResponse], any]", auth_state_changed_callback: "Callable[[AuthenticationResponse], Any]",
daemon: bool): daemon: bool) -> None:
""" """
:param auth_helpers: An instance of the authorization helpers class. :param auth_helpers: An instance of the authorization helpers class.
:param auth_state_changed_callback: A callback function to be called when the authorization state changes. :param auth_state_changed_callback: A callback function to be called when the authorization state changes.
:param daemon: Whether the server thread should be run in daemon mode. Note: Daemon threads are abruptly stopped :param daemon: Whether the server thread should be run in daemon mode. Note: Daemon threads are abruptly stopped
at shutdown. Their resources (e.g. open files) may never be released. at shutdown. Their resources (e.g. open files) may never be released.
""" """
self._web_server = None # type: Optional[HTTPServer] self._web_server = None # type: Optional[AuthorizationRequestServer]
self._web_server_thread = None # type: Optional[threading.Thread] self._web_server_thread = None # type: Optional[threading.Thread]
self._web_server_port = auth_helpers.settings.CALLBACK_PORT self._web_server_port = auth_helpers.settings.CALLBACK_PORT
self._auth_helpers = auth_helpers self._auth_helpers = auth_helpers
self._auth_state_changed_callback = auth_state_changed_callback self._auth_state_changed_callback = auth_state_changed_callback
self._daemon = daemon self._daemon = daemon
def start(self, verification_code: "str") -> None: def start(self, verification_code: str) -> None:
""" """
Starts the local web server to handle the authorization callback. Starts the local web server to handle the authorization callback.
:param verification_code: The verification code part of the OAuth2 client identification. :param verification_code: The verification code part of the OAuth2 client identification.
@ -42,6 +42,9 @@ class LocalAuthorizationServer:
self._web_server.setVerificationCode(verification_code) self._web_server.setVerificationCode(verification_code)
return return
if self._web_server_port is None:
raise Exception("Unable to start server without specifying the port.")
Logger.log("d", "Starting local web server to handle authorization callback on port %s", Logger.log("d", "Starting local web server to handle authorization callback on port %s",
self._web_server_port) self._web_server_port)

View file

@ -9,7 +9,7 @@ class BaseModel:
# OAuth OAuth2Settings data template. # OAuth OAuth2Settings data template.
class OAuth2Settings(BaseModel): class OAuth2Settings(BaseModel):
CALLBACK_PORT = None # type: Optional[str] CALLBACK_PORT = None # type: Optional[int]
OAUTH_SERVER_URL = None # type: Optional[str] OAUTH_SERVER_URL = None # type: Optional[str]
CLIENT_ID = None # type: Optional[str] CLIENT_ID = None # type: Optional[str]
CLIENT_SCOPES = None # type: Optional[str] CLIENT_SCOPES = None # type: Optional[str]