Skip to content

Commit

Permalink
Merge pull request #44 from IABTechLab/mkc-UID2-3626-requests
Browse files Browse the repository at this point in the history
Replace urllib with requests
  • Loading branch information
asloobq authored Jun 21, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents 8f46336 + afebbab commit cec164b
Showing 8 changed files with 51 additions and 48 deletions.
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "uid2_client"
version = "2.4.6"
version = "3.0.0a1"
authors = [
{ name = "UID2 team", email = "[email protected]" }
]
@@ -18,9 +18,9 @@ classifiers = [
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
requires-python = ">=3.6"
requires-python = ">=3.8"
dependencies = [
"setuptools",
"requests",
"pycryptodome",
"bitarray"
]
9 changes: 5 additions & 4 deletions tests/test_identity_map_client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import unittest
from urllib.error import URLError, HTTPError

import requests

from uid2_client import IdentityMapClient, IdentityMapInput, normalize_and_hash_email, normalize_and_hash_phone

@@ -134,19 +135,19 @@ def test_identity_map_bad_url(self):
identity_map_input = IdentityMapInput.from_emails(
["[email protected]", "[email protected]", "[email protected]"])
client = IdentityMapClient("https://operator-bad-url.uidapi.com", os.getenv("UID2_API_KEY"), os.getenv("UID2_SECRET_KEY"))
self.assertRaises(URLError, client.generate_identity_map, identity_map_input)
self.assertRaises(requests.exceptions.ConnectionError, client.generate_identity_map, identity_map_input)

def test_identity_map_bad_api_key(self):
identity_map_input = IdentityMapInput.from_emails(
["[email protected]", "[email protected]", "[email protected]"])
client = IdentityMapClient(os.getenv("UID2_BASE_URL"), "bad-api-key", os.getenv("UID2_SECRET_KEY"))
self.assertRaises(HTTPError, client.generate_identity_map,identity_map_input)
self.assertRaises(requests.exceptions.HTTPError, client.generate_identity_map,identity_map_input)

def test_identity_map_bad_secret(self):
identity_map_input = IdentityMapInput.from_emails(
["[email protected]", "[email protected]", "[email protected]"])
client = IdentityMapClient(os.getenv("UID2_BASE_URL"), os.getenv("UID2_API_KEY"), "wJ0hP19QU4hmpB64Y3fV2dAed8t/mupw3sjN5jNRFzg=")
self.assertRaises(HTTPError, client.generate_identity_map,
self.assertRaises(requests.exceptions.HTTPError, client.generate_identity_map,
identity_map_input)

def assert_mapped(self, response, dii):
12 changes: 6 additions & 6 deletions tests/test_publisher_client.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import os
import unittest

import requests

from uid2_client import Uid2PublisherClient
from uid2_client import TokenGenerateInput
from uid2_client import TokenGenerateResponse
from uid2_client.identity_tokens import IdentityTokens
from urllib.request import HTTPError


class PublisherEuidIntegrationTests(unittest.TestCase):
@@ -175,7 +175,7 @@ def test_integration_bad_requests(self):

expired_respose = "{\"advertising_token\":\"AgAAAAN6QZRCFTau+sfOlMMUY2ftElFMq2TCrcu1EAaD9WmEfoT2BWm2ZKz1tumbT00tWLffRDQ/9POXfA0O/Ljszn7FLtG5EzTBM3HYs4f5irkqeEvu38DhVCxUEpI+gZZZkynRap1oYx6AmC/ip3rk+7pmqa3r3saDs1mPRSSTm+Nh6A==\",\"user_token\":\"AgAAAAL6aleYI4BubI5ZXMBshqmMEfCkbCJF4fLeg1sdI0BTLzj9sXsSISjkG0lMC743diC2NVy3ElkbO1lLysd+Lm6alkqevPrcuWDisQ1939YdoH6LqpwBH3FNSE4/xa3Q+94=\",\"refresh_token\":\"AAAAAARomrP3NjjH+8mt5djfTHbmRZXjOMnAN8WpjJoe30AhUCvYksO/xoDSj77GzWv4M99DhnPl2cVco8CZFTcE10nauXI4Barr890ILnH0IIacOei5Zjwh6DycFkoXkAAuHY1zjmxb7niGLfSP2RctWkZdRVGWQv/UW/grw6+paU9bnKEWPzVvLwwdW2NgjDKu+szE6A+b5hkY+I3voKoaz8/kLDmX8ddJGLy/YOh/LIveBspSAvEg+v89OuUCwAqm8L3Rt8PxDzDnt0U4Na+AUawvvfsIhmsn/zMpRRks6GHhIAB/EQUHID8TedU8Hv1WFRsiraG9Dfn1Kc5/uYnDJhEagWc+7RgTGT+U5GqI6+afrAl5091eBLbmvXnXn9ts\",\"identity_expires\":1668059799628,\"refresh_expires\":1668142599628,\"refresh_from\":1668056202628,\"refresh_response_key\":\"P941vVeuyjaDRVnFQ8DPd0AZnW4bPeiJPXER2K9QXcU=\"}"
current_identity = IdentityTokens.from_json_string(expired_respose)
with self.assertRaises(HTTPError):
with self.assertRaises(requests.exceptions.HTTPError):
self.publisher_client.refresh_token(current_identity)

with self.assertRaises(TypeError):
@@ -185,15 +185,15 @@ def test_integration_bad_requests(self):
self.publisher_client.refresh_token(None)

bad_url_client = Uid2PublisherClient("https://www.something.com", self.UID2_API_KEY, self.UID2_SECRET_KEY)
with self.assertRaises(HTTPError):
with self.assertRaises(requests.exceptions.HTTPError):
bad_url_client.generate_token(TokenGenerateInput.from_email("[email protected]"))

bad_secret_client = Uid2PublisherClient(self.UID2_BASE_URL, self.UID2_API_KEY, "badSecretKeypB64Y3fV2dAed8t/mupw3sjN5jNRFzg=")
with self.assertRaises(HTTPError):
with self.assertRaises(requests.exceptions.HTTPError):
bad_secret_client.generate_token(TokenGenerateInput.from_email("[email protected]"))

bad_api_client = Uid2PublisherClient(self.UID2_BASE_URL, "not-real-key", self.UID2_SECRET_KEY)
with self.assertRaises(HTTPError):
with self.assertRaises(requests.exceptions.HTTPError):
bad_secret_client.generate_token(TokenGenerateInput.from_email("[email protected]"))


46 changes: 23 additions & 23 deletions tests/test_refresh_keys_util.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import json
import unittest
from unittest.mock import patch

import responses

from uid2_client import refresh_keys_util
from test_utils import *
from uid2_client.encryption import _encrypt_gcm, _decrypt_gcm


class TestRefreshKeysUtil(unittest.TestCase):
class MockPostResponse:
def __init__(self, return_value):
self.return_value = return_value

def read(self):
return base64.b64encode(self.return_value)

def _make_post_response(self, request_data, response_payload):
d = base64.b64decode(request_data)[1:]
d = _decrypt_gcm(d, client_secret_bytes)
@@ -25,11 +19,11 @@ def _make_post_response(self, request_data, response_payload):
payload += response_payload
envelope = _encrypt_gcm(payload, None, client_secret_bytes)

return self.MockPostResponse(envelope)
return 200, {}, base64.b64encode(envelope)

def _get_post_refresh_keys_response(self, base_url, path, headers, data):
def _get_post_refresh_keys_response(self, request):
response_payload = key_set_to_json_for_sharing([master_key, site_key]).encode()
return self._make_post_response(data, response_payload)
return self._make_post_response(request.body, response_payload)

def _validate_master_and_site_key(self, keys):
self.assertEqual(len(keys.values()), 2)
@@ -55,23 +49,29 @@ def _validate_master_and_site_key(self, keys):
self.assertEqual(master_secret, master.secret)
self.assertEqual(1, master.keyset_id)

@patch('uid2_client.refresh_keys_util.post')
def test_refresh_sharing_keys(self, mock_post):
mock_post.side_effect = self._get_post_refresh_keys_response
refresh_response = refresh_keys_util.refresh_sharing_keys("base_url", "auth_key", base64.b64decode(client_secret))
@responses.activate
def test_refresh_sharing_keys(self):
responses.add_callback(
responses.POST,
"https://base_url/v2/key/sharing",
callback=self._get_post_refresh_keys_response,
)

refresh_response = refresh_keys_util.refresh_sharing_keys("https://base_url", "auth_key", base64.b64decode(client_secret))
self.assertTrue(refresh_response.success)
self._validate_master_and_site_key(refresh_response.keys)
mock_post.assert_called_once()
self.assertEqual(mock_post.call_args[0], ('base_url', '/v2/key/sharing'))

@patch('uid2_client.refresh_keys_util.post')
def test_refresh_bidstream_keys(self, mock_post):
mock_post.side_effect = self._get_post_refresh_keys_response
refresh_response = refresh_keys_util.refresh_bidstream_keys("base_url", "auth_key", base64.b64decode(client_secret))
@responses.activate
def test_refresh_bidstream_keys(self):
responses.add_callback(
responses.POST,
"https://base_url/v2/key/bidstream",
callback=self._get_post_refresh_keys_response,
)

refresh_response = refresh_keys_util.refresh_bidstream_keys("https://base_url", "auth_key", base64.b64decode(client_secret))
self.assertTrue(refresh_response.success)
self._validate_master_and_site_key(refresh_response.keys)
mock_post.assert_called_once()
self.assertEqual(mock_post.call_args[0], ('base_url', '/v2/key/bidstream'))

def test_parse_keys_json_identity(self):
response_body_str = key_set_to_json_for_sharing([master_key, site_key])
3 changes: 2 additions & 1 deletion uid2_client/identity_map_client.py
Original file line number Diff line number Diff line change
@@ -36,5 +36,6 @@ def generate_identity_map(self, identity_map_input):
req, nonce = make_v2_request(self._client_secret, dt.datetime.now(tz=timezone.utc),
identity_map_input.get_identity_map_input_as_json_string().encode())
resp = post(self._base_url, '/v2/identity/map', headers=auth_headers(self._api_key), data=req)
resp_body = parse_v2_response(self._client_secret, resp.read(), nonce)
resp.raise_for_status()
resp_body = parse_v2_response(self._client_secret, resp.text, nonce)
return IdentityMapResponse(resp_body, identity_map_input)
6 changes: 4 additions & 2 deletions uid2_client/publisher_client.py
Original file line number Diff line number Diff line change
@@ -50,12 +50,14 @@ def generate_token(self, token_generate_input):
req, nonce = make_v2_request(self._secret_key, dt.datetime.now(tz=timezone.utc),
token_generate_input.get_as_json_string().encode())
resp = post(self._base_url, '/v2/token/generate', headers=auth_headers(self._auth_key), data=req)
resp_body = parse_v2_response(self._secret_key, resp.read(), nonce)
resp.raise_for_status()
resp_body = parse_v2_response(self._secret_key, resp.text, nonce)
return TokenGenerateResponse(resp_body)

def refresh_token(self, current_identity):
resp = post(self._base_url, '/v2/token/refresh', headers=auth_headers(self._auth_key),
data=current_identity.get_refresh_token().encode())
resp_bytes = base64_to_byte_array(resp.read())
resp.raise_for_status()
resp_bytes = base64_to_byte_array(resp.text)
decrypted = _decrypt_gcm(resp_bytes, base64_to_byte_array(current_identity.get_refresh_response_key()))
return TokenRefreshResponse(decrypted.decode(), dt.datetime.now(tz=timezone.utc))
3 changes: 2 additions & 1 deletion uid2_client/refresh_keys_util.py
Original file line number Diff line number Diff line change
@@ -38,7 +38,8 @@ def _fetch_keys(base_url, path, auth_key, secret_key):
try:
req, nonce = make_v2_request(secret_key, dt.datetime.now(tz=timezone.utc))
resp = post(base_url, path, headers=auth_headers(auth_key), data=req)
resp_body = json.loads(parse_v2_response(secret_key, resp.read(), nonce)).get('body')
resp.raise_for_status()
resp_body = json.loads(parse_v2_response(secret_key, resp.text, nonce)).get('body')
keys = _parse_keys_json(resp_body)
return RefreshResponse.make_success(keys)
except Exception as exc:
14 changes: 6 additions & 8 deletions uid2_client/request_response_util.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import base64
from importlib.metadata import version
import os
from urllib import request

import pkg_resources
import requests

from uid2_client.encryption import _encrypt_gcm, _decrypt_gcm

@@ -13,12 +12,12 @@ def _make_url(base_url, path):

def auth_headers(auth_key):
try:
version = pkg_resources.get_distribution("uid2_client").version
client_version = version("uid2_client")
except Exception:
version = "non-packaged-mode"
client_version = "non-packaged-mode"

return {'Authorization': 'Bearer ' + auth_key,
"X-UID2-Client-Version": "uid2-client-python-" + version}
"X-UID2-Client-Version": "uid2-client-python-" + client_version}


def make_v2_request(secret_key, now, data=None):
@@ -42,5 +41,4 @@ def parse_v2_response(secret_key, encrypted, nonce):


def post(base_url, path, headers, data):
req = request.Request(_make_url(base_url, path), headers=headers, method='POST', data=data)
return request.urlopen(req)
return requests.post(_make_url(base_url, path), data=data, headers=headers)

0 comments on commit cec164b

Please sign in to comment.