From 6766cecb1f96fb5ae971b225d18fa520e7e5e19d Mon Sep 17 00:00:00 2001 From: Sese Schneider Date: Mon, 31 Jul 2023 11:18:12 +0200 Subject: [PATCH] Release: 1.1.0 --- CHANGELOG.md | 15 +++++++++ LICENSE | 4 +-- README.md | 16 +++++---- custom_components/personio/api.py | 42 ++++++++---------------- custom_components/personio/manifest.json | 4 +-- 5 files changed, 42 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e858b39..f0e98c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +## 1.1.0 (2023-07-31) + +### Bug Fixes + +* Fix authentication after a [breaking change](https://developer.personio.de/changelog/authentication-api-improved-bearer-token) in the Personio API. + +### Documentation + +* Add HACS Default badges + +### Chore + +* Add `pt-PT` translation. (@ViPeR5000 - #5) +* Migrate to [POST body `client_secret` and `client_id`](https://developer.personio.de/changelog/auth-api-moved-client_secret-and-client_id-to-post-body) in the Personio API. + ## 1.0.2 (2023-03-02) ### Bug Fixes diff --git a/LICENSE b/LICENSE index 6893c34..38b0a88 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Custom cards for Home Assistant +Copyright (c) 2023 Sebastian Schneider Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 14de34a..fe9fc96 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A Home Assistant integration with the Personio API. -[![hacs_badge](https://img.shields.io/badge/HACS-Custom-41BDF5.svg?style=for-the-badge)](https://github.com/hacs/integration) +[![hacs_badge](https://img.shields.io/badge/HACS-Default-41BDF5.svg?style=for-the-badge)](https://my.home-assistant.io/redirect/hacs_repository/?owner=Sese-Schneider&repository=ha-personio&category=integration) [![GitHub Release][releases-shield]][releases] ![GitHub Downloads][downloads-shield] @@ -21,14 +21,16 @@ A Home Assistant integration with the Personio API. ### HACS -*This repo can be installed as a custom repository in HACS.* +*This repo is available for install through the HACS.* -* Go to HACS → Integration -* Click on the three-dot-menu → Custom repositories -* Add `Sese-Schneider/ha-personio` as Integration. +* Go to HACS → Integrations * Use the FAB "Explore and download repositories" to search "Personio". -* Restart Home Assistant -* Install "Personio" as an integration in your settings. + +_or_ + +Click here: + +[![](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=Sese-Schneider&repository=ha-personio&category=integration) ## Setup diff --git a/custom_components/personio/api.py b/custom_components/personio/api.py index 7fe26ba..2cb584e 100644 --- a/custom_components/personio/api.py +++ b/custom_components/personio/api.py @@ -4,7 +4,6 @@ import logging import time -import jwt import requests from requests import Response @@ -19,46 +18,40 @@ class Authentication: _current_config: dict = None _current_token: str = None + _current_token_time: float = None def set_config(self, config: dict): """Set the current API configuration.""" self._current_config = config["data"] # self test current auth config, fetch initial token for usage - self.get_bearer(invalidate=False) + self.get_bearer() - def get_bearer(self, invalidate: bool = True): + def get_bearer(self): """Get a currently valid authentication bearer.""" if not self._current_config: raise HomeAssistantError("Config not defined.") if self._current_token: - jwt_token = jwt.decode( - self._current_token, - algorithms=["HS256"], - options={"verify_signature": False}, - ) - if jwt_token["exp"] > time.time(): - _LOGGER.debug("Reusing existing JWT token") + # Bearers are valid for 24 hours + if self._current_token_time + (24 * 60 * 60) > time.time(): + _LOGGER.debug("Using cached token") bearer = "Bearer " + self._current_token - if invalidate: - # bearers are one-time use only - _LOGGER.debug("Invalidating JWT token") - self._current_token = None - return bearer - _LOGGER.debug("Requesting new JWT token") + _LOGGER.debug("Requesting new token") + + self._current_token_time = time.time() authentication = authenticate( self._current_config["client_id"], self._current_config["client_secret"], self._current_config["partner_id"], self._current_config["app_id"], ) - self._current_token = authentication.json()["data"]["token"] - return self.get_bearer(invalidate=invalidate) + + return self.get_bearer() def get_headers(self): """Returns all headers required for a successful Personio API request.""" @@ -73,12 +66,6 @@ def get_headers(self): headers["X-Personio-App-ID"] = app_id return headers - def set_response(self, response: Response): - """Callback after receiving a new response. - Call this to set new authorization headers after each successful request.""" - self._current_token = response.headers["authorization"].removeprefix("Bearer ") - _LOGGER.debug("New JWT token received") - class Employees: """Employees for the Persionio API.""" @@ -96,7 +83,6 @@ def get_employee_id_by_mail(self, employee_email: int) -> bool: timeout=10000, ) result.raise_for_status() - self._authentication.set_response(result) return result.json()["data"][0]["attributes"]["id"]["value"] @@ -145,9 +131,9 @@ def add_attendance( json={"attendances": attendances}, ) result.raise_for_status() - self._authentication.set_response(result) - _LOGGER.info("Attendance for employee %s added successfully", employee_id) + _LOGGER.info( + "Attendance for employee %s added successfully", employee_id) def authenticate( @@ -165,7 +151,7 @@ def authenticate( result = requests.post( BASE_URL + "/auth", - params={"client_id": client_id, "client_secret": client_secret}, + json={"client_id": client_id, "client_secret": client_secret}, headers=headers, timeout=10000, ) diff --git a/custom_components/personio/manifest.json b/custom_components/personio/manifest.json index f632a49..80b0061 100644 --- a/custom_components/personio/manifest.json +++ b/custom_components/personio/manifest.json @@ -7,6 +7,6 @@ "integration_type": "hub", "iot_class": "cloud_polling", "issue_tracker": "https://github.com/Sese-Schneider/ha-personio/issues", - "requirements": ["pyjwt"], - "version": "1.0.2" + "requirements": [], + "version": "1.1.0" }