From a7a686cfe307484c97196f721af0fae3c4a279d4 Mon Sep 17 00:00:00 2001 From: maxkahan Date: Wed, 15 May 2024 18:16:41 +0100 Subject: [PATCH] refactor jwt package, get tests passing --- jwt/BUILD | 16 ++++++++++++++++ jwt/CHANGES.md | 4 ++++ jwt/README.md | 8 ++++---- jwt/pyproject.toml | 4 +--- jwt/src/vonage_jwt/__init__.py | 5 +++-- jwt/src/vonage_jwt/errors.py | 9 +++++++++ jwt/src/vonage_jwt/jwt.py | 15 +++++++-------- jwt/src/vonage_jwt/verify_jwt.py | 10 +++------- jwt/tests/BUILD | 2 +- jwt/tests/test_jwt_generator.py | 16 +++++++++------- jwt/tests/test_verify_jwt.py | 3 ++- pants.toml | 1 + 12 files changed, 60 insertions(+), 33 deletions(-) create mode 100644 jwt/BUILD create mode 100644 jwt/src/vonage_jwt/errors.py diff --git a/jwt/BUILD b/jwt/BUILD new file mode 100644 index 00000000..c49d3ee3 --- /dev/null +++ b/jwt/BUILD @@ -0,0 +1,16 @@ +resource(name='pyproject', source='pyproject.toml') +file(name='readme', source='README.md') + +files(sources=['tests/data/*']) + +python_distribution( + name='vonage-jwt', + dependencies=[ + ':pyproject', + ':readme', + 'jwt/src/vonage_jwt', + ], + provides=python_artifact(), + generate_setup=False, + repositories=['@pypi'], +) diff --git a/jwt/CHANGES.md b/jwt/CHANGES.md index 2808b330..62166af4 100644 --- a/jwt/CHANGES.md +++ b/jwt/CHANGES.md @@ -1,3 +1,7 @@ +# 1.1.1 +- Exceptions inherit from `VonageError` +- Moving the package into the Vonage Python SDK monorepo + # 1.1.0 - Add new module with method to verify JWT signatures, `verify_jwt.verify_signature` diff --git a/jwt/README.md b/jwt/README.md index 9d52db72..d577c8ff 100644 --- a/jwt/README.md +++ b/jwt/README.md @@ -2,9 +2,9 @@ This package (`vonage-jwt`) provides functionality to generate a JWT in Python code. -It is used by the [Vonage Python SDK](https://github.com/Vonage/vonage-python-sdk), specifically by the `vonage-http-client` package, to generate JWTs for authentication. Thus, it doesn't require manual installation or configuration unless you're using this package independently of a SDK. +It is used by the [Vonage Python SDK](https://github.com/Vonage/vonage-python-sdk), specifically by the `vonage-http-client` package, to generate JWTs for authentication. Thus, it doesn't require manual installation or configuration unless you're using this package independently of an SDK. -For full API documentation, refer to the [Vonage Developer documentation](https://developer.vonage.com). +For full API documentation, refer to the [Vonage developer documentation](https://developer.vonage.com). - [Installation](#installation) - [Generating JWTs](#generating-jwts) @@ -27,7 +27,7 @@ It can also be used as a standalone JWT generator for use with Vonage APIs, like ### Import the `JwtClient` object ```python -from vonage_jwt.jwt import JwtClient +from vonage_jwt import JwtClient ``` ### Create a `JwtClient` object @@ -54,7 +54,7 @@ jwt_client.generate_application_jwt(claims) You can use the `verify_jwt.verify_signature` method to verify a JWT signature is valid. ```python -from vonage_jwt.verify_jwt import verify_signature +from vonage_jwt import verify_signature verify_signature(TOKEN, SIGNATURE_SECRET) # Returns a boolean ``` diff --git a/jwt/pyproject.toml b/jwt/pyproject.toml index 20269708..569b7723 100644 --- a/jwt/pyproject.toml +++ b/jwt/pyproject.toml @@ -5,9 +5,7 @@ description = "Tooling for working with JWTs for Vonage APIs in Python." readme = "README.md" authors = [{ name = "Vonage", email = "devrel@vonage.com" }] requires-python = ">=3.8" -dependencies = [ - "pyjwt[crypto] >=1.6.4" -] +dependencies = ["vonage-utils>=1.1.2", "pyjwt[crypto]>=1.6.4"] classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", diff --git a/jwt/src/vonage_jwt/__init__.py b/jwt/src/vonage_jwt/__init__.py index 0e9b94b4..4419f04f 100644 --- a/jwt/src/vonage_jwt/__init__.py +++ b/jwt/src/vonage_jwt/__init__.py @@ -1,4 +1,5 @@ -from .jwt import JwtClient, VonageJwtError +from .errors import VonageJwtError, VonageVerifyJwtError +from .jwt import JwtClient from .verify_jwt import verify_signature -__all__ = ['JwtClient', 'VonageJwtError', 'verify_signature'] +__all__ = ['JwtClient', 'VonageJwtError', 'VonageVerifyJwtError', 'verify_signature'] diff --git a/jwt/src/vonage_jwt/errors.py b/jwt/src/vonage_jwt/errors.py new file mode 100644 index 00000000..80177182 --- /dev/null +++ b/jwt/src/vonage_jwt/errors.py @@ -0,0 +1,9 @@ +from vonage_utils import VonageError + + +class VonageJwtError(VonageError): + """An error relating to the Vonage JWT Generator.""" + + +class VonageVerifyJwtError(VonageError): + """The signature could not be verified.""" diff --git a/jwt/src/vonage_jwt/jwt.py b/jwt/src/vonage_jwt/jwt.py index 67d9b987..b1c93359 100644 --- a/jwt/src/vonage_jwt/jwt.py +++ b/jwt/src/vonage_jwt/jwt.py @@ -1,8 +1,11 @@ import re from time import time -from jwt import encode -from uuid import uuid4 from typing import Union +from uuid import uuid4 + +from jwt import encode + +from .errors import VonageJwtError class JwtClient: @@ -22,8 +25,8 @@ def __init__(self, application_id: str, private_key: str): ) def generate_application_jwt(self, jwt_options: dict = {}): - """ - Generates a JWT for the specified Vonage application. + """Generates a JWT for the specified Vonage application. + You can override values for application_id and private_key on the JWTClient object by specifying them in the `jwt_options` dict if required. """ @@ -51,7 +54,3 @@ def _set_private_key(self, key: Union[str, bytes]): ) else: self._private_key = key - - -class VonageJwtError(Exception): - """An error relating to the Vonage JWT Generator.""" diff --git a/jwt/src/vonage_jwt/verify_jwt.py b/jwt/src/vonage_jwt/verify_jwt.py index 982eefff..31de3302 100644 --- a/jwt/src/vonage_jwt/verify_jwt.py +++ b/jwt/src/vonage_jwt/verify_jwt.py @@ -1,10 +1,10 @@ from jwt import InvalidSignatureError, decode +from .errors import VonageVerifyJwtError + def verify_signature(token: str, signature_secret: str = None) -> bool: - """ - Method to verify that an incoming JWT was sent by Vonage. - """ + """Method to verify that an incoming JWT was sent by Vonage.""" try: decode(token, signature_secret, algorithms='HS256') @@ -13,7 +13,3 @@ def verify_signature(token: str, signature_secret: str = None) -> bool: return False except Exception as e: raise VonageVerifyJwtError(repr(e)) - - -class VonageVerifyJwtError(Exception): - """The signature could not be verified.""" diff --git a/jwt/tests/BUILD b/jwt/tests/BUILD index 72fce921..dec8ad99 100644 --- a/jwt/tests/BUILD +++ b/jwt/tests/BUILD @@ -1 +1 @@ -python_tests(dependencies=['messages', 'testutils']) +python_tests(dependencies=['jwt', 'testutils']) diff --git a/jwt/tests/test_jwt_generator.py b/jwt/tests/test_jwt_generator.py index 1fa006af..f32f0225 100644 --- a/jwt/tests/test_jwt_generator.py +++ b/jwt/tests/test_jwt_generator.py @@ -1,23 +1,25 @@ -from vonage_jwt.jwt import JwtClient, VonageJwtError +from os import environ +from os.path import dirname, join +from time import time -import os +from jwt.exceptions import ImmatureSignatureError from pytest import raises +from vonage_jwt.jwt import JwtClient, VonageJwtError + from jwt import decode -from jwt.exceptions import ImmatureSignatureError -from time import time # Ensure the client isn't being configured with real values -os.environ.clear() +environ.clear() def read_file(path): - with open(os.path.join(os.path.dirname(__file__), path)) as input_file: + with open(join(dirname(__file__), path)) as input_file: return input_file.read() application_id = 'asdf1234' private_key_string = read_file('data/private_key.txt') -private_key_file_path = './tests/data/private_key.txt' +private_key_file_path = 'jwt/tests/data/private_key.txt' jwt_client = JwtClient(application_id, private_key_file_path) public_key = read_file('data/public_key.txt') diff --git a/jwt/tests/test_verify_jwt.py b/jwt/tests/test_verify_jwt.py index 1e5175d7..6e7e7286 100644 --- a/jwt/tests/test_verify_jwt.py +++ b/jwt/tests/test_verify_jwt.py @@ -1,5 +1,6 @@ -from vonage_jwt.verify_jwt import verify_signature, VonageVerifyJwtError import pytest +from vonage_jwt.errors import VonageVerifyJwtError +from vonage_jwt.verify_jwt import verify_signature token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2OTc2MzQ2ODAsImV4cCI6MzMyNTQ1NDA4MjgsImF1ZCI6IiIsInN1YiI6IiJ9.88vJc3I2HhuqEDixHXVhc9R30tA6U_HQHZTC29y6CGM' valid_signature = "qwertyuiopasdfghjklzxcvbnm123456" diff --git a/pants.toml b/pants.toml index 8be53d31..bcbc4d63 100644 --- a/pants.toml +++ b/pants.toml @@ -33,6 +33,7 @@ filter = [ 'vonage/src', 'http_client/src', 'application/src', + 'jwt/src', 'messages/src', 'number_insight/src', 'number_insight_v2/src',