From f15a7dc141d4075c240fe2f9899e19f49d7e20b1 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 12 Dec 2023 08:29:36 +1000 Subject: [PATCH 1/2] Don't use hardcoded expiry time, take from reply --- koordinates/auth.py | 14 +++++++++++--- koordinates/gui/login_widget.py | 15 ++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/koordinates/auth.py b/koordinates/auth.py index e00fb34..b93f2bc 100644 --- a/koordinates/auth.py +++ b/koordinates/auth.py @@ -158,6 +158,7 @@ def do_GET(self): self.server.apikey = resp["key"] self.server.refresh_token = refresh_token + self.server.expires_in = expires_in self._send_response() def _send_response(self): @@ -184,6 +185,8 @@ class OAuthWorkflow(QThread): finished = pyqtSignal(str, str) error_occurred = pyqtSignal(str) + EXPIRY_DURATION_SECONDS = 0 + def __init__(self): super().__init__() @@ -239,6 +242,7 @@ def _refresh_oauth_finished(self, reply: QNetworkReply): access_token = result['access_token'] refresh_token = result['refresh_token'] + expires_in = result['expires_in'] body = { "scope": SCOPE_KX, @@ -259,11 +263,13 @@ def _refresh_oauth_finished(self, reply: QNetworkReply): self._refresh_kx_key_reply.finished.connect( partial(self._refresh_kx_key_finished, self._refresh_kx_key_reply, - refresh_token)) + refresh_token, + expires_in)) def _refresh_kx_key_finished(self, reply: QNetworkReply, - refresh_token: str): + refresh_token: str, + expires_in: int): if (reply != self._refresh_kx_key_reply or sip.isdeleted(self._refresh_kx_key_reply)): return @@ -277,7 +283,7 @@ def _refresh_kx_key_finished(self, return kx_key = result['key'] - + OAuthWorkflow.EXPIRY_DURATION_SECONDS = expires_in self.finished.emit(kx_key, refresh_token) def force_stop(self): @@ -298,6 +304,7 @@ def run(self): self.server.code_verifier = self.code_verifier self.server.apikey = None self.server.refresh_token = None + self.server.expires_in = None self.server.error = None QDesktopServices.openUrl(QUrl(self.authorization_url)) @@ -306,6 +313,7 @@ def run(self): err = self.server.error apikey = self.server.apikey refresh_token = self.server.refresh_token + OAuthWorkflow.EXPIRY_DURATION_SECONDS = self.server.expires_in or 0 if err: self.error_occurred.emit(err) diff --git a/koordinates/gui/login_widget.py b/koordinates/gui/login_widget.py index 9d46ca6..f20c9e0 100644 --- a/koordinates/gui/login_widget.py +++ b/koordinates/gui/login_widget.py @@ -290,13 +290,14 @@ def _auth_finished(self, key: str, refresh_token: Optional[str]): self.login_button.set_state(AuthState.LoggedIn) self.open_login_window_label.hide() - self.oauth_refresh_timer = QTimer(self) - self.oauth_refresh_timer.setSingleShot(True) - # request refresh after 9 hours, even though the token - # expires after 10... - self.oauth_refresh_timer.setInterval(32400*1000) - self.oauth_refresh_timer.timeout.connect(self._refresh_auth) - self.oauth_refresh_timer.start() + if OAuthWorkflow.EXPIRY_DURATION_SECONDS > 0: + self.oauth_refresh_timer = QTimer(self) + self.oauth_refresh_timer.setSingleShot(True) + # request refresh 30 mins before expiry + self.oauth_refresh_timer.setInterval( + (OAuthWorkflow.EXPIRY_DURATION_SECONDS - 1800) * 1000) + self.oauth_refresh_timer.timeout.connect(self._refresh_auth) + self.oauth_refresh_timer.start() except FileExistsError: iface.messageBar().pushMessage( From 37d64fd20006c87d33e277abed4c5adf4a2e0581 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 12 Dec 2023 08:34:11 +1000 Subject: [PATCH 2/2] Ensure refresh body is fully encoded --- koordinates/auth.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/koordinates/auth.py b/koordinates/auth.py index b93f2bc..8a1b0ce 100644 --- a/koordinates/auth.py +++ b/koordinates/auth.py @@ -14,7 +14,8 @@ from qgis.PyQt.QtCore import ( QThread, pyqtSignal, - QUrl + QUrl, + QUrlQuery ) from qgis.PyQt.QtGui import QDesktopServices from qgis.PyQt.QtNetwork import ( @@ -212,16 +213,17 @@ def __init__(self): self._refresh_kx_key_reply: Optional[QNetworkReply] = None def refresh(self, refresh_token: str): - body = (f"grant_type=refresh_token&" - f"client_id={CLIENT_ID}&" - f"refresh_token={refresh_token}") + query = QUrlQuery() + query.addQueryItem('grant_type', 'refresh_token') + query.addQueryItem('client_id', CLIENT_ID) + query.addQueryItem('refresh_token', refresh_token) network_request = QNetworkRequest(QUrl(TOKEN_URL)) network_request.setHeader(QNetworkRequest.ContentTypeHeader, 'application/x-www-form-urlencoded') self._refresh_reply = QgsNetworkAccessManager.instance().post( network_request, - body.encode() + query.toString(QUrl.FullyEncoded).encode() ) self._refresh_reply.finished.connect( partial(self._refresh_oauth_finished, self._refresh_reply))