diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index cb977b2..34b93f0 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8, 3.9] + python-version: ['3.10'] steps: - name: Checkout @@ -22,17 +22,20 @@ jobs: run: | python -m venv venv . venv/bin/activate + - name: Install dependencies run: | python -m pip install --upgrade pip pip install flake8 pytest if [ -f requirements_test.txt ]; then pip install -r requirements_test.txt; fi + - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=12 --max-line-length=127 --statistics --ignore E722,E501 + - name: Test with pytest run: | pytest \ @@ -42,5 +45,4 @@ jobs: --numprocesses=auto \ --dist=loadfile \ --cov=core \ - --aiohttp-fast \ tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 36bd8bf..8851dd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,13 @@ +## [0.2.2] - 2022-06-15 +### Fixed +- persist refreshed token + + ## [0.2.1] - 2022-06-13 ### Fixed - token refresh call + ## [0.2.0] - 2022-06-07 ### Added - core client for internal communication @@ -9,16 +15,19 @@ ### Changed - renamed configuration file to `frontend_configuration.json` + ## [0.1.1] - 2022-05-08 ### Added - gettext mo files + ## [0.1.0] - 2022-04-30 ### Added - oauth login via core - draft of profile page +[0.2.2]: https://github.com/photos-network/frontend/compare/Release/v0.2.1...Release/v0.2.2 [0.2.1]: https://github.com/photos-network/frontend/compare/Release/v0.2.0...Release/v0.2.1 [0.2.0]: https://github.com/photos-network/frontend/compare/Release/v0.1.0...Release/v0.2.0 [0.1.1]: https://github.com/photos-network/frontend/compare/Release/v0.1.0...Release/v0.1.1 diff --git a/Dockerfile b/Dockerfile index 94838fa..3b4b78f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.10 LABEL "description"="Photos.network web frontend" -LABEL "version"="0.2.1" +LABEL "version"="0.2.2" LABEL "maintainer"="github.com/photos-network" WORKDIR /app diff --git a/frontend/base/oauth.py b/frontend/base/oauth.py index 96f8f22..29a1bad 100644 --- a/frontend/base/oauth.py +++ b/frontend/base/oauth.py @@ -1,9 +1,11 @@ import asyncio import logging +import time from dataclasses import dataclass from typing import Any, Dict import aiohttp +import aiohttp_session from aiohttp import request, web from frontend.config import Config @@ -104,39 +106,47 @@ async def user_info(self): response["lastname"], ) - async def refresh_token(self): + async def refresh_access_token_call(self): """refresh access token""" url = str(self.config.core_url) + ":" + str(self.config.core_port) + "/api/oauth/token" - raw_data = ( - "grant_type=refresh_token" - + "&refresh_token=" - + str(self.refresh_token) - + "&client_id=" - + self.config.client_id - + "&scope=" - + self.scope - ) - - async with aiohttp.ClientSession() as session: - async with session.request( - method="POST", - url=url, - headers={"Content-Type": "application/x-www-form-urlencoded"}, - data=raw_data, - ssl=None, - verify_ssl=False, - ) as resp: - response = await resp.json() - - self.accessToken = response["access_token"] - self.refreshToken = response["refresh_token"] - self.expiresIn = response["expires_in"] - - await session.close() - - return resp.status() + if self.refreshToken is not None and self.scope is not None: + + raw_data = ( + "grant_type=refresh_token" + + "&refresh_token=" + + str(self.refreshToken) + + "&client_id=" + + self.config.client_id + + "&scope=" + + self.scope + ) + + async with aiohttp.ClientSession() as clientSession: + async with clientSession.request( + method="POST", + url=url, + headers={"Content-Type": "application/x-www-form-urlencoded"}, + data=raw_data, + ssl=None, + verify_ssl=False, + ) as resp: + response = await resp.json() + + timestamp = time.time() + expires_in = int(timestamp) + response["expires_in"] + + self.accessToken = response["access_token"] + self.refreshToken = response["refresh_token"] + self.expiresIn = expires_in + + status = resp.status + await clientSession.close() + + return (status, self.accessToken, self.refreshToken, self.expiresIn) + else: + return (None, None, None, None) async def get_photos(self): async with aiohttp.ClientSession() as session: diff --git a/frontend/const.py b/frontend/const.py index d4866bd..ad06558 100644 --- a/frontend/const.py +++ b/frontend/const.py @@ -1,7 +1,7 @@ """Constants used by Photos.network frontend.""" MAJOR_VERSION = 0 MINOR_VERSION = 2 -PATCH_VERSION = 1 +PATCH_VERSION = 2 __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1) diff --git a/frontend/webserver.py b/frontend/webserver.py index 2132184..4ad8026 100644 --- a/frontend/webserver.py +++ b/frontend/webserver.py @@ -139,11 +139,26 @@ async def auth_middleware( # refresh token if access_token expires in next 3 minutes or has been expired already if (expires_in - now) <= 180: - status_code = await self.frontend.core_client.refresh_token() - - _LOGGER.error("status: " + str(status_code)) - - authenticated = True + _LOGGER.info("access token is expiring in " + str((expires_in - now)) + " seconds. Try to refresh...") + + ( + statusCode, + accessToken, + refreshToken, + expiresIn, + ) = await self.frontend.core_client.refresh_access_token_call() + if statusCode is not None and statusCode == 200: + session["expires_in"] = expiresIn + session["access_token"] = str(accessToken) + session["refresh_token"] = str(refreshToken) + + authenticated = True + else: + authenticated = False + + else: + # still authenticated + authenticated = True validate_access_token_status = await self.frontend.core_client.check_access_token() if validate_access_token_status != 200: