Skip to content

Commit

Permalink
finish adding network apis and prepare for release
Browse files Browse the repository at this point in the history
  • Loading branch information
maxkahan committed Jun 21, 2024
1 parent 8ef8ece commit b3b5150
Show file tree
Hide file tree
Showing 22 changed files with 148 additions and 89 deletions.
3 changes: 3 additions & 0 deletions http_client/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 1.4.0
- Add new `oauth2` logic for calling APIs that require Oauth

# 1.3.1
- Update minimum dependency version

Expand Down
4 changes: 2 additions & 2 deletions http_client/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[project]
name = "vonage-http-client"
version = "1.3.1"
version = "1.4.0"
description = "An HTTP client for making requests to Vonage APIs."
readme = "README.md"
authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
requires-python = ">=3.8"
dependencies = [
"vonage-utils>=1.1.1",
"vonage-utils>=1.1.2",
"vonage-jwt>=1.1.1",
"requests>=2.27.0",
"typing-extensions>=4.9.0",
Expand Down
10 changes: 7 additions & 3 deletions http_client/src/vonage_http_client/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,12 @@ def post(
host: str,
request_path: str = '',
params: dict = None,
auth_type: Literal['jwt', 'basic', 'body', 'signature'] = 'jwt',
auth_type: Literal['jwt', 'basic', 'body', 'signature', 'oauth2'] = 'jwt',
sent_data_type: Literal['json', 'form', 'query-params'] = 'json',
token: Optional[str] = None,
) -> Union[dict, None]:
return self.make_request(
'POST', host, request_path, params, auth_type, sent_data_type
'POST', host, request_path, params, auth_type, sent_data_type, token
)

def get(
Expand Down Expand Up @@ -192,8 +193,9 @@ def make_request(
host: str,
request_path: str = '',
params: Optional[dict] = None,
auth_type: Literal['jwt', 'basic', 'body', 'signature'] = 'jwt',
auth_type: Literal['jwt', 'basic', 'body', 'signature', 'oauth2'] = 'jwt',
sent_data_type: Literal['json', 'form', 'query_params'] = 'json',
token: Optional[str] = None,
):
url = f'https://{host}{request_path}'
logger.debug(
Expand All @@ -206,6 +208,8 @@ def make_request(
elif auth_type == 'body':
params['api_key'] = self._auth.api_key
params['api_secret'] = self._auth.api_secret
elif auth_type == 'oauth2':
self._headers['Authorization'] = f'Bearer {token}'
elif auth_type == 'signature':
params['api_key'] = self._auth.api_key
params['sig'] = self._auth.sign_params(params)
Expand Down
2 changes: 1 addition & 1 deletion network_auth/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# 1.0.0
# 0.1.0b0
- Initial upload
4 changes: 3 additions & 1 deletion network_auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ This package is intended to be used as part of an SDK, accessing required method

For full API documentation, refer to the [Vonage developer documentation](https://developer.vonage.com).

Please note this package is in beta.

## Installation

Install from the Python Package Index with pip:
Expand All @@ -28,7 +30,7 @@ network_auth = NetworkAuth(HttpClient(Auth(application_id='application-id', priv
### Generate an Authenticated Access Token

```python
token = camara_auth.get_oauth2_user_token(
token = network_auth.get_oauth2_user_token(
number='447700900000', scope='dpv:FraudPreventionAndDetection#check-sim-swap'
)
```
4 changes: 2 additions & 2 deletions network_auth/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[project]
name = "vonage-network-auth"
version = "1.0.0"
version = "0.1.0b0"
description = "Package for working with Network APIs that require Oauth2 in Python."
readme = "README.md"
authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
requires-python = ">=3.8"
dependencies = ["vonage-http-client>=1.3.1", "vonage-utils>=1.1.2"]
dependencies = ["vonage-http-client>=1.4.0", "vonage-utils>=1.1.2"]
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
Expand Down
4 changes: 2 additions & 2 deletions network_auth/src/vonage_network_auth/network_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ def __init__(self, http_client: HttpClient):

@property
def http_client(self) -> HttpClient:
"""The HTTP client used to make requests to the Users API.
"""The HTTP client used to make requests to the Network Auth API.
Returns:
HttpClient: The HTTP client used to make requests to the Users API.
HttpClient: The HTTP client used to make requests to the Network Auth API.
"""
return self._http_client

Expand Down
6 changes: 6 additions & 0 deletions network_auth/tests/data/oidc_request_permissions_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "https://developer.vonage.com/api-errors#invalid-param",
"title": "Bad Request",
"detail": "No Network Application associated with Vonage Application: 29f760f8-7ce1-46c9-ade3-f2dedee4ed5f",
"instance": "b45ae630-7621-42b0-8ff0-6c1ad98e6e32"
}
20 changes: 20 additions & 0 deletions network_auth/tests/test_network_auth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from os.path import abspath

import responses
from pytest import raises
from vonage_http_client.errors import HttpRequestError
from vonage_http_client.http_client import HttpClient
from vonage_network_auth import NetworkAuth
from vonage_network_auth.responses import OidcResponse
Expand Down Expand Up @@ -89,3 +91,21 @@ def test_whole_oauth2_flow():
def test_number_plus_prefixes():
assert network_auth._ensure_plus_prefix('447700900000') == '+447700900000'
assert network_auth._ensure_plus_prefix('+447700900000') == '+447700900000'


@responses.activate
def test_oidc_request_permissions_error():
build_response(
path,
'POST',
'https://api-eu.vonage.com/oauth2/bc-authorize',
'oidc_request_permissions_error.json',
status_code=400,
)

with raises(HttpRequestError) as err:
response = network_auth.make_oidc_request(
number='447700900000',
scope='dpv:FraudPreventionAndDetection#check-sim-swap',
)
assert err.match('"title": "Bad Request"')
2 changes: 1 addition & 1 deletion network_sim_swap/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# 1.0.0
# 0.1.0b0
- Initial upload
25 changes: 14 additions & 11 deletions network_sim_swap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ This package is not intended to be used directly, instead being accessed from an

For full API documentation, refer to the [Vonage developer documentation](https://developer.vonage.com).

Please note this package is in beta.

## Registering to Use the Sim Swap API

To use this API, you must first create and register your business profile with the Vonage Network Registry. [This documentation page](https://developer.vonage.com/en/getting-started-network/registration) explains how this can be done. You need to obtain approval for each network and region you want to use the APIs in.
Expand All @@ -15,24 +17,25 @@ To use this API, you must first create and register your business profile with t
Install from the Python Package Index with pip:

```bash
pip install vonage-camara-auth
pip install vonage-network-sim-swap
```

## Usage

### Create a `CamaraAuth` Object
It is recommended to use this as part of the `vonage-network` package. The examples below assume you've created an instance of the `vonage_network.VonageNetwork` class called `network_client`.

```python
from vonage_camara_auth import CamaraAuth
from vonage_http_client import HttpClient, Auth
### Check if a SIM Has Been Swapped

camara_auth = CamaraAuth(HttpClient(Auth(application_id='application-id', private_key='private-key')))
```python
from vonage_network_sim_swap import SwapStatus
swap_status: SwapStatus = vonage_network.sim_swap.check(phone_number='MY_NUMBER')
print(swap_status.swapped)
```

### Generate an Authenticated Access Token
### Get the Date of the Last SIM Swap

```python
token = camara_auth.get_oauth2_user_token(
number='447700900000', scope='dpv:FraudPreventionAndDetection#check-sim-swap'
)
```
from vonage_network_sim_swap import LastSwapDate
swap_date: LastSwapDate = vonage_network.sim_swap.get_last_swap_date
print(swap_date.last_swap_date)
```
6 changes: 3 additions & 3 deletions network_sim_swap/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[project]
name = "vonage-network-sim-swap"
version = "1.0.0"
version = "0.1.0b0"
description = "Package for working with the Vonage Sim Swap Network API."
readme = "README.md"
authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
requires-python = ">=3.8"
dependencies = [
"vonage-http-client>=1.3.1",
"vonage-network-auth>=1.0.0",
"vonage-http-client>=1.4.0",
"vonage-network-auth>=0.1.0b0",
"vonage-utils>=1.1.2",
]
classifiers = [
Expand Down
2 changes: 1 addition & 1 deletion network_sim_swap/src/vonage_network_sim_swap/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ class SwapStatus(BaseModel):


class LastSwapDate(BaseModel):
last_swap_date = Field(..., validation_alias='latestSimChange')
last_swap_date: str = Field(..., validation_alias='latestSimChange')
30 changes: 22 additions & 8 deletions network_sim_swap/src/vonage_network_sim_swap/sim_swap.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from pydantic import validate_call
from vonage_http_client import HttpClient
from vonage_network_auth import NetworkAuth
from vonage_utils.types import PhoneNumber

from .responses import LastSwapDate, SwapStatus

Expand All @@ -16,12 +15,22 @@ def __init__(self, http_client: HttpClient):
self._auth_type = 'oauth2'
self._network_auth = NetworkAuth(self._http_client)

@property
def http_client(self) -> HttpClient:
"""The HTTP client used to make requests to the Network Sim Swap API.
Returns:
HttpClient: The HTTP client used to make requests to the Network Sim Swap API.
"""
return self._http_client

@validate_call
def check(self, phone_number: PhoneNumber, max_age: int = None) -> SwapStatus:
def check(self, phone_number: str, max_age: int = None) -> SwapStatus:
"""Check if a SIM swap has been performed in a given time frame.
Args:
phone_number (str): The phone number to check. Use the E.164 format without a leading +.
phone_number (str): The phone number to check. Use the E.164 format with
or without a leading +.
max_age (int, optional): Period in hours to be checked for SIM swap.
Returns:
Expand All @@ -31,20 +40,25 @@ def check(self, phone_number: PhoneNumber, max_age: int = None) -> SwapStatus:
number=phone_number, scope='dpv:FraudPreventionAndDetection#check-sim-swap'
)

params = {'phoneNumber': phone_number}
if max_age:
params['maxAge'] = max_age

return self._http_client.post(
self._host,
'/camara/sim-swap/v040/check',
params={'phoneNumber': phone_number, 'maxAge': max_age},
params,
auth_type=self._auth_type,
oauth_token=token,
token=token,
)

@validate_call
def get_last_swap_date(self, phone_number: PhoneNumber) -> LastSwapDate:
def get_last_swap_date(self, phone_number: str) -> LastSwapDate:
"""Get the last SIM swap date for a phone number.
Args:
phone_number (str): The phone number to check. Use the E.164 format without a leading +.
phone_number (str): The phone number to check. Use the E.164 format with
or without a leading +.
Returns:
"""
Expand All @@ -57,5 +71,5 @@ def get_last_swap_date(self, phone_number: PhoneNumber) -> LastSwapDate:
'/camara/sim-swap/v040/retrieve-date',
params={'phoneNumber': phone_number},
auth_type=self._auth_type,
oauth_token=token,
token=token,
)
2 changes: 1 addition & 1 deletion network_sim_swap/tests/data/get_swap_date.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"latestSimChange": "2019-08-24T14:15:22Z"
"latestSimChange": "2023-12-22T04:00:44.000Z"
}
62 changes: 31 additions & 31 deletions network_sim_swap/tests/test_sim_swap.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
from os.path import abspath
from unittest.mock import MagicMock, patch

import responses
from util import *
from vonage_gnp_sim_swap import SimSwap
from vonage_http_client.http_client import HttpClient
from vonage_network_sim_swap import NetworkSimSwap

from testutils import build_response, get_mock_jwt_auth

path = abspath(__file__)

sim_swap = NetworkSimSwap(HttpClient(get_mock_jwt_auth()))


def test_http_client_property():
http_client = sim_swap.http_client
assert isinstance(http_client, HttpClient)


@patch('vonage_network_auth.NetworkAuth.get_oauth2_user_token')
@responses.activate
def test_check_sim_swap(sim_swap: SimSwap):
stub(
responses.POST,
'https://api-eu.vonage.com/oauth2/bc-authorize',
fixture_path='camara_auth/oidc_request.json',
)
stub(
responses.POST,
'https://api-eu.vonage.com/oauth2/token',
fixture_path='camara_auth/token_request.json',
)
stub(
responses.POST,
def test_check_sim_swap(mock_get_oauth2_user_token: MagicMock):
build_response(
path,
'POST',
'https://api-eu.vonage.com/camara/sim-swap/v040/check',
fixture_path='sim_swap/check_sim_swap.json',
'check_sim_swap.json',
)
mock_get_oauth2_user_token.return_value = 'token'

response = sim_swap.check('447700900000', max_age=24)

assert response['swapped'] == True


@patch('vonage_network_auth.NetworkAuth.get_oauth2_user_token')
@responses.activate
def test_get_last_swap_date(sim_swap: SimSwap):
stub(
responses.POST,
'https://api-eu.vonage.com/oauth2/bc-authorize',
fixture_path='camara_auth/oidc_request.json',
)
stub(
responses.POST,
'https://api-eu.vonage.com/oauth2/token',
fixture_path='camara_auth/token_request.json',
)
stub(
responses.POST,
def test_get_last_swap_date(mock_get_oauth2_user_token: MagicMock):
build_response(
path,
'POST',
'https://api-eu.vonage.com/camara/sim-swap/v040/retrieve-date',
fixture_path='sim_swap/get_swap_date.json',
'get_swap_date.json',
)
mock_get_oauth2_user_token.return_value = 'token'

response = sim_swap.get_last_swap_date('447700900000')

assert response['latestSimChange'] == '2019-08-24T14:15:22Z'
assert response['latestSimChange'] == '2023-12-22T04:00:44.000Z'
4 changes: 2 additions & 2 deletions pants.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ interpreter_constraints = ['>=3.8']
report = ['html', 'console']
filter = [
'vonage/src',
'vonage_gnp/src',
'vonage_network/src',
'http_client/src',
'application/src',
'gnp_sim_swap/src',
'jwt/src',
'messages/src',
'network_auth/src',
'network_sim_swap/src',
'number_insight/src',
'number_insight_v2/src',
'sms/src',
Expand Down
Loading

0 comments on commit b3b5150

Please sign in to comment.