diff --git a/messages/CHANGES.md b/messages/CHANGES.md index 2019adce..4b4c7285 100644 --- a/messages/CHANGES.md +++ b/messages/CHANGES.md @@ -1,3 +1,6 @@ +# 1.3.0 +- Add support for API key/secret header authentication + # 1.2.3 - Update dependency versions diff --git a/messages/src/vonage_messages/_version.py b/messages/src/vonage_messages/_version.py index 5a5df3be..19b4f1d6 100644 --- a/messages/src/vonage_messages/_version.py +++ b/messages/src/vonage_messages/_version.py @@ -1 +1 @@ -__version__ = '1.2.3' +__version__ = '1.3.0' diff --git a/messages/src/vonage_messages/messages.py b/messages/src/vonage_messages/messages.py index c39af991..3fd62f65 100644 --- a/messages/src/vonage_messages/messages.py +++ b/messages/src/vonage_messages/messages.py @@ -16,6 +16,10 @@ class Messages: def __init__(self, http_client: HttpClient) -> None: self._http_client = http_client + self._auth_type = 'jwt' + + if self._http_client.auth.application_id is None: + self._auth_type = 'basic' @property def http_client(self) -> HttpClient: @@ -42,7 +46,9 @@ def send(self, message: BaseMessage) -> SendMessageResponse: self._http_client.api_host, '/v1/messages', message.model_dump(by_alias=True, exclude_none=True) or message, + self._auth_type, ) + return SendMessageResponse(**response) @validate_call @@ -63,6 +69,7 @@ def mark_whatsapp_message_read(self, message_uuid: str) -> None: self._http_client.api_host, f'/v1/messages/{message_uuid}', {'status': 'read'}, + self._auth_type, ) @validate_call @@ -83,4 +90,5 @@ def revoke_rcs_message(self, message_uuid: str) -> None: self._http_client.api_host, f'/v1/messages/{message_uuid}', {'status': 'revoked'}, + self._auth_type, ) diff --git a/messages/tests/test_messages.py b/messages/tests/test_messages.py index beba2945..9bcf3c64 100644 --- a/messages/tests/test_messages.py +++ b/messages/tests/test_messages.py @@ -2,6 +2,7 @@ import responses from pytest import raises +from vonage_http_client.auth import Auth from vonage_http_client.errors import HttpRequestError from vonage_http_client.http_client import HttpClient, HttpClientOptions from vonage_messages.messages import Messages @@ -13,7 +14,7 @@ ) from vonage_messages.responses import SendMessageResponse -from testutils import build_response, get_mock_jwt_auth +from testutils import build_response, get_mock_api_key_auth, get_mock_jwt_auth path = abspath(__file__) @@ -21,6 +22,21 @@ messages = Messages(HttpClient(get_mock_jwt_auth())) +@responses.activate +def test_default_auth_type(): + messages = Messages( + HttpClient( + Auth( + api_key='asdf', + api_secret='asdf', + application_id='asdf', + private_key='-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZz9Zz\n-----END PRIVATE-KEY----', + ) + ) + ) + assert messages._auth_type == 'jwt' + + @responses.activate def test_send_message(): build_response( @@ -34,6 +50,24 @@ def test_send_message(): response = messages.send(sms) assert type(response) == SendMessageResponse assert response.message_uuid == 'd8f86df1-dec6-442f-870a-2241be27d721' + assert messages._auth_type == 'jwt' + + +@responses.activate +def test_send_message_basic_auth(): + build_response( + path, 'POST', 'https://api.nexmo.com/v1/messages', 'send_message.json', 202 + ) + messages = Messages(HttpClient(get_mock_api_key_auth())) + sms = Sms( + from_='Vonage APIs', + to='1234567890', + text='Hello, World!', + ) + response = messages.send(sms) + assert type(response) == SendMessageResponse + assert response.message_uuid == 'd8f86df1-dec6-442f-870a-2241be27d721' + assert messages._auth_type == 'basic' @responses.activate diff --git a/pants.toml b/pants.toml index 16761ca5..3b13e505 100644 --- a/pants.toml +++ b/pants.toml @@ -1,5 +1,5 @@ [GLOBAL] -pants_version = '2.23.0rc1' +pants_version = '2.23.0' backend_packages = [ 'pants.backend.python', @@ -29,30 +29,6 @@ args = ['-vv', '--no-header'] [coverage-py] interpreter_constraints = ['>=3.8'] report = ['html', 'console'] -filter = [ - 'vonage/src', - 'http_client/src', - 'account/src', - 'application/src', - 'jwt/src', - 'messages/src', - 'network_auth/src', - 'network_number_verification/src', - 'network_sim_swap/src', - 'number_insight/src', - 'number_insight_v2/src', - 'number_management/src', - 'sms/src', - 'subaccounts/src', - 'users/src', - 'utils/src', - 'testutils', - 'verify/src', - 'verify_legacy/src', - 'video/src', - 'voice/src', - 'vonage_utils/src', -] [black] args = ['--line-length=90', '--skip-string-normalization'] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..867680d4 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[tool.coverage.run] +omit = ['**/tests/*', '**/src/**/_version.py'] diff --git a/verify/CHANGES.md b/verify/CHANGES.md index 769d8e2b..55dc5e03 100644 --- a/verify/CHANGES.md +++ b/verify/CHANGES.md @@ -1,3 +1,6 @@ +# 2.1.0 +- Add support for API key/secret header authentication + # 2.0.0 - Rename `vonage-verify-v2` package -> `vonage-verify`, `VerifyV2` -> `Verify`, etc. This package now contains code for the Verify v2 API - Update dependency versions diff --git a/verify/src/vonage_verify/_version.py b/verify/src/vonage_verify/_version.py index afced147..a33997dd 100644 --- a/verify/src/vonage_verify/_version.py +++ b/verify/src/vonage_verify/_version.py @@ -1 +1 @@ -__version__ = '2.0.0' +__version__ = '2.1.0' diff --git a/verify/src/vonage_verify/verify.py b/verify/src/vonage_verify/verify.py index 20eabc22..d87b4d38 100644 --- a/verify/src/vonage_verify/verify.py +++ b/verify/src/vonage_verify/verify.py @@ -10,6 +10,10 @@ class Verify: def __init__(self, http_client: HttpClient) -> None: self._http_client = http_client + self._auth_type = 'jwt' + + if self._http_client.auth.application_id is None: + self._auth_type = 'basic' @property def http_client(self) -> HttpClient: @@ -37,6 +41,7 @@ def start_verification( self._http_client.api_host, '/v2/verify', verify_request.model_dump(by_alias=True, exclude_none=True), + self._auth_type, ) return StartVerificationResponse(**response) @@ -53,7 +58,10 @@ def check_code(self, request_id: str, code: str) -> CheckCodeResponse: CheckCodeResponse: The response object containing the verification result. """ response = self._http_client.post( - self._http_client.api_host, f'/v2/verify/{request_id}', {'code': code} + self._http_client.api_host, + f'/v2/verify/{request_id}', + {'code': code}, + self._auth_type, ) return CheckCodeResponse(**response) @@ -64,7 +72,11 @@ def cancel_verification(self, request_id: str) -> None: Args: request_id (str): The request ID. """ - self._http_client.delete(self._http_client.api_host, f'/v2/verify/{request_id}') + self._http_client.delete( + self._http_client.api_host, + f'/v2/verify/{request_id}', + auth_type=self._auth_type, + ) @validate_call def trigger_next_workflow(self, request_id: str) -> None: @@ -77,4 +89,5 @@ def trigger_next_workflow(self, request_id: str) -> None: self._http_client.post( self._http_client.api_host, f'/v2/verify/{request_id}/next_workflow', + auth_type=self._auth_type, ) diff --git a/verify/tests/test_verify.py b/verify/tests/test_verify.py index 40251c6b..b5926137 100644 --- a/verify/tests/test_verify.py +++ b/verify/tests/test_verify.py @@ -2,12 +2,13 @@ import responses from pytest import raises +from vonage_http_client.auth import Auth from vonage_http_client.errors import HttpRequestError from vonage_http_client.http_client import HttpClient from vonage_verify.requests import * from vonage_verify.verify import Verify -from testutils import build_response, get_mock_jwt_auth +from testutils import build_response, get_mock_api_key_auth, get_mock_jwt_auth path = abspath(__file__) @@ -15,6 +16,21 @@ verify = Verify(HttpClient(get_mock_jwt_auth())) +@responses.activate +def test_default_auth_type(): + verify = Verify( + HttpClient( + Auth( + api_key='asdf', + api_secret='asdf', + application_id='asdf', + private_key='-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZz9Zz\n-----END PRIVATE-KEY----', + ) + ) + ) + assert verify._auth_type == 'jwt' + + @responses.activate def test_make_verify_request(): build_response( @@ -37,6 +53,27 @@ def test_make_verify_request(): == 'https://api-eu-3.vonage.com/v2/verify/cfbc9a3b-27a2-40d4-a4e0-0c59b3b41901/silent-auth/redirect' ) assert verify._http_client.last_response.status_code == 202 + assert verify._auth_type == 'jwt' + + +@responses.activate +def test_make_verify_request_basic_auth(): + build_response( + path, 'POST', 'https://api.nexmo.com/v2/verify', 'verify_request.json', 202 + ) + sms_channel = SmsChannel(channel=ChannelType.SMS, to='1234567890', from_='Vonage') + params = { + 'brand': 'Vonage', + 'workflow': [sms_channel], + } + request = VerifyRequest(**params) + + verify = Verify(HttpClient(get_mock_api_key_auth())) + + response = verify.start_verification(request) + assert response.request_id == '2c59e3f4-a047-499f-a14f-819cd1989d2e' + assert verify._http_client.last_response.status_code == 202 + assert verify._auth_type == 'basic' @responses.activate @@ -108,6 +145,23 @@ def test_check_code(): assert response.status == 'completed' +@responses.activate +def test_check_code_basic_auth(): + build_response( + path, + 'POST', + 'https://api.nexmo.com/v2/verify/36e7060d-2b23-4257-bad0-773ab47f85ef', + 'check_code.json', + ) + verify = Verify(HttpClient(get_mock_api_key_auth())) + response = verify.check_code( + request_id='36e7060d-2b23-4257-bad0-773ab47f85ef', code='1234' + ) + assert response.request_id == '36e7060d-2b23-4257-bad0-773ab47f85ef' + assert response.status == 'completed' + assert verify._auth_type == 'basic' + + @responses.activate def test_check_code_invalid_code_error(): build_response( @@ -153,6 +207,20 @@ def test_cancel_verification(): assert verify._http_client.last_response.status_code == 204 +@responses.activate +def test_cancel_verification_basic_auth(): + responses.add( + responses.DELETE, + 'https://api.nexmo.com/v2/verify/36e7060d-2b23-4257-bad0-773ab47f85ef', + status=204, + ) + + verify = Verify(HttpClient(get_mock_api_key_auth())) + assert verify.cancel_verification('36e7060d-2b23-4257-bad0-773ab47f85ef') is None + assert verify._http_client.last_response.status_code == 204 + assert verify._auth_type == 'basic' + + @responses.activate def test_trigger_next_workflow(): responses.add( @@ -164,6 +232,20 @@ def test_trigger_next_workflow(): assert verify._http_client.last_response.status_code == 200 +@responses.activate +def test_trigger_next_workflow_basic_auth(): + responses.add( + responses.POST, + 'https://api.nexmo.com/v2/verify/36e7060d-2b23-4257-bad0-773ab47f85ef/next_workflow', + status=200, + ) + + verify = Verify(HttpClient(get_mock_api_key_auth())) + assert verify.trigger_next_workflow('36e7060d-2b23-4257-bad0-773ab47f85ef') is None + assert verify._http_client.last_response.status_code == 200 + assert verify._auth_type == 'basic' + + @responses.activate def test_trigger_next_event_error(): build_response( diff --git a/vonage/CHANGES.md b/vonage/CHANGES.md index 13b053de..64057f62 100644 --- a/vonage/CHANGES.md +++ b/vonage/CHANGES.md @@ -1,3 +1,6 @@ +# 4.1.0 +- Add support for API key/secret header authentication for the Messages and Verify APIs (JWT is the default and recommended method) + # 4.0.0 A complete, ground-up rewrite of the SDK. Key changes: diff --git a/vonage/pyproject.toml b/vonage/pyproject.toml index 6fafde0a..c546c9c0 100644 --- a/vonage/pyproject.toml +++ b/vonage/pyproject.toml @@ -9,7 +9,7 @@ dependencies = [ "vonage-http-client>=1.4.3", "vonage-account>=1.1.0", "vonage-application>=2.0.0", - "vonage-messages>=1.2.3", + "vonage-messages>=1.3.0", "vonage-network-auth>=1.0.1", "vonage-network-sim-swap>=1.1.1", "vonage-network-number-verification>=1.0.1", @@ -18,7 +18,7 @@ dependencies = [ "vonage-sms>=1.1.4", "vonage-subaccounts>=1.0.4", "vonage-users>=1.2.0", - "vonage-verify>=2.0.0", + "vonage-verify>=2.1.0", "vonage-verify-legacy>=1.0.0", "vonage-video>=1.0.3", "vonage-voice>=1.0.6", diff --git a/vonage/src/vonage/_version.py b/vonage/src/vonage/_version.py index d6497a81..fa721b49 100644 --- a/vonage/src/vonage/_version.py +++ b/vonage/src/vonage/_version.py @@ -1 +1 @@ -__version__ = '4.0.0' +__version__ = '4.1.0'