Skip to content

Commit c49be71

Browse files
committed
Don't throw exception. Reply with encryption-decryption response
1 parent 4c7a471 commit c49be71

13 files changed

Lines changed: 216 additions & 128 deletions

examples/sample_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def _usage():
2727
# client = EuidClientFactory.create(base_url, auth_key, secret_key)
2828
# for UID2 use:
2929
client = Uid2ClientFactory.create(base_url, auth_key, secret_key)
30-
client.refresh()
30+
client.refresh_keys()
3131
decrypt_result = client.decrypt(ad_token)
3232

3333
print('UID =', decrypt_result.uid)

examples/sample_sharing_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ def _usage():
2121

2222
client = SharingClient(base_url, auth_key, secret_key)
2323
client.refresh()
24-
new_sharing_token = client.encrypt_raw_uid_into_token(raw_uid)
24+
encryption_data_response = client.encrypt_raw_uid_into_token(raw_uid)
2525

26-
print('New Sharing Token =', new_sharing_token)
26+
print('New Sharing Token =', encryption_data_response.encrypted_data)
2727

28-
decrypt_result = client.decrypt_token_into_raw_uid(new_sharing_token)
28+
decrypt_result = client.decrypt_token_into_raw_uid(encryption_data_response.encrypted_data)
2929

3030
print('Decrypted UID =', decrypt_result.uid)
3131
print('Established =', decrypt_result.established)

tests/test_bidstream_client.py

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,24 @@
22
from unittest.mock import patch
33

44
from test_utils import *
5-
from uid2_client import BidstreamClient, EncryptionError, Uid2Base64UrlCoder
5+
from uid2_client import BidstreamClient, EncryptionError, Uid2Base64UrlCoder, DecryptionStatus
66

77

88
@patch('uid2_client.bid_stream_client.refresh_bidstream_keys')
99
class TestBidStreamClient(unittest.TestCase):
1010
_CONST_BASE_URL = 'base_url'
1111
_CONST_API_KEY = 'api_key'
1212

13+
def assert_success(self, decryption_response, token_version, scope):
14+
self.assertEqual(decryption_response.advertising_token_version, token_version)
15+
self.assertEqual(decryption_response.uid, example_uid)
16+
self.assertEqual(decryption_response.identity_scope, scope)
17+
self.assertEqual((now - decryption_response.established).total_seconds(), 0)
18+
19+
def decrypt_and_assert_success(self, token, token_version, scope):
20+
decrypted = self._client.decrypt_token_into_raw_uid(token, None)
21+
self.assert_success(decrypted, token_version, scope)
22+
1323
def setUp(self):
1424
self._key_collection = create_key_collection(IdentityScope.UID2)
1525
self._client = BidstreamClient(self._CONST_BASE_URL, self._CONST_API_KEY, client_secret)
@@ -20,10 +30,8 @@ def test_smoke_test(self, mock_refresh_bidstream_keys): # SmokeTest
2030
token = generate_uid_token(expected_scope, expected_version)
2131
mock_refresh_bidstream_keys.return_value = create_key_collection(expected_scope)
2232
self._client.refresh()
23-
decrypted = self._client.decrypt_token_into_raw_uid(token, None)
24-
self.assertEqual(decrypted.identity_scope, expected_scope)
25-
self.assertEqual(decrypted.advertising_token_version, expected_version)
26-
self.assertEqual((now - decrypted.established).total_seconds(), 0)
33+
self.decrypt_and_assert_success(token, expected_version, expected_scope)
34+
2735

2836
def test_phone_uids(self, mock_refresh_bidstream_keys): # PhoneTest
2937
for expected_scope, expected_version in test_cases_all_scopes_v3_v4_versions:
@@ -51,9 +59,9 @@ def test_token_lifetime_too_long_for_bidstream(self, mock_refresh_bidstream_keys
5159
99999, 86400,
5260
max_bidstream_lifetime_seconds=max_bidstream_lifetime)
5361
self._client.refresh()
54-
with self.assertRaises(EncryptionError) as context:
55-
self._client.decrypt_token_into_raw_uid(token, None)
56-
self.assertEqual('invalid token lifetime', str(context.exception))
62+
result = self._client.decrypt_token_into_raw_uid(token, None)
63+
self.assertFalse(result.success)
64+
self.assertEqual(result.status, DecryptionStatus.INVALID_TOKEN_LIFETIME)
5765

5866
def test_token_generated_in_the_future_to_simulate_clock_skew(self, mock_refresh_bidstream_keys): # TokenGeneratedInTheFutureToSimulateClockSkew
5967
created_at_future = dt.datetime.now(tz=timezone.utc) + dt.timedelta(minutes=31) #max allowed clock skew is 30m
@@ -64,9 +72,9 @@ def test_token_generated_in_the_future_to_simulate_clock_skew(self, mock_refresh
6472
expected_scope, site_id, 1,
6573
99999, 86400)
6674
self._client.refresh()
67-
with self.assertRaises(EncryptionError) as context:
68-
self._client.decrypt_token_into_raw_uid(token, None)
69-
self.assertEqual('invalid token lifetime', str(context.exception))
75+
result = self._client.decrypt_token_into_raw_uid(token, None)
76+
self.assertFalse(result.success)
77+
self.assertEqual(result.status, DecryptionStatus.INVALID_TOKEN_LIFETIME)
7078

7179
def test_token_generated_in_the_future_within_allowed_clock_skew(self, mock_refresh_bidstream_keys): # TokenGeneratedInTheFutureWithinAllowedClockSkew
7280
created_at_future = dt.datetime.now(tz=timezone.utc) + dt.timedelta(minutes=29) #max allowed clock skew is 30m
@@ -86,9 +94,9 @@ def test_empty_keys(self, mock_refresh_bidstream_keys): # EmptyKeyContainer
8694
token = generate_uid_token(IdentityScope.UID2, AdvertisingTokenVersion.ADVERTISING_TOKEN_V3)
8795
mock_refresh_bidstream_keys.return_value = None
8896
self._client.refresh()
89-
with self.assertRaises(EncryptionError) as context:
90-
self._client.decrypt_token_into_raw_uid(token, None)
91-
self.assertEqual('keys not initialized', str(context.exception))
97+
result = self._client.decrypt_token_into_raw_uid(token, None)
98+
self.assertFalse(result.success)
99+
self.assertEqual(result.status, DecryptionStatus.NOT_INITIALIZED)
92100

93101
def test_master_key_expired(self, mock_refresh_bidstream_keys): #ExpiredKeyContainer
94102
def get_post_refresh_keys_response_with_key_expired():
@@ -101,10 +109,9 @@ def get_post_refresh_keys_response_with_key_expired():
101109
mock_refresh_bidstream_keys.return_value = get_post_refresh_keys_response_with_key_expired()
102110
self._client.refresh()
103111

104-
with self.assertRaises(EncryptionError) as context:
105-
self._client.decrypt_token_into_raw_uid(example_uid, None)
106-
107-
self.assertEqual('no keys available or all keys have expired; refresh the latest keys from UID2 service', str(context.exception))
112+
result = self._client.decrypt_token_into_raw_uid(example_uid, None)
113+
self.assertFalse(result.success)
114+
self.assertEqual(result.status, DecryptionStatus.KEYS_NOT_SYNCED)
108115

109116
def test_not_authorized_for_master_key(self, mock_refresh_bidstream_keys): #NotAuthorizedForMasterKey
110117
def get_post_refresh_keys_response_with_key_expired():
@@ -116,10 +123,9 @@ def get_post_refresh_keys_response_with_key_expired():
116123
self._client.refresh()
117124
token = generate_uid_token(IdentityScope.UID2, AdvertisingTokenVersion.ADVERTISING_TOKEN_V4)
118125

119-
with self.assertRaises(EncryptionError) as context:
120-
self._client.decrypt_token_into_raw_uid(token, None)
121-
122-
self.assertEqual('not authorized for master key', str(context.exception))
126+
result = self._client.decrypt_token_into_raw_uid(token, None)
127+
self.assertFalse(result.success)
128+
self.assertEqual(result.status, DecryptionStatus.NOT_AUTHORIZED_FOR_MASTER_KEY)
123129

124130
def test_invalid_payload(self, mock_refresh_bidstream_keys): #InvalidPayload
125131
mock_refresh_bidstream_keys.return_value = create_default_key_collection([master_key, site_key])
@@ -128,21 +134,21 @@ def test_invalid_payload(self, mock_refresh_bidstream_keys): #InvalidPayload
128134
payload = Uid2Base64UrlCoder.decode(token)
129135
bad_token = base64.urlsafe_b64encode(payload[:0])
130136

131-
with self.assertRaises(EncryptionError) as context:
132-
self._client.decrypt_token_into_raw_uid(bad_token, None)
133-
self.assertEqual('invalid payload', str(context.exception))
137+
result = self._client.decrypt_token_into_raw_uid(bad_token, None)
138+
self.assertFalse(result.success)
139+
self.assertEqual(result.status, DecryptionStatus.INVALID_PAYLOAD)
134140

135-
def test_token_expiry_custom_decryption_time(self, mock_refresh_bidstream_keys):
141+
def test_token_expiry_custom_decryption_time(self, mock_refresh_bidstream_keys): #TokenExpiryAndCustomNow
136142
mock_refresh_bidstream_keys.return_value = create_default_key_collection([master_key, site_key])
137143
self._client.refresh()
138144

139145
expires_at = now - dt.timedelta(days=60)
140146
created_at = expires_at - dt.timedelta(minutes=1)
141147
token = generate_uid_token(IdentityScope.UID2, AdvertisingTokenVersion.ADVERTISING_TOKEN_V4,
142148
created_at=created_at, expires_at=expires_at)
143-
with self.assertRaises(EncryptionError) as context:
144-
self._client._decrypt_token_into_raw_uid(token, None, expires_at + dt.timedelta(seconds=1))
145-
self.assertEqual('token expired', str(context.exception))
149+
result = self._client._decrypt_token_into_raw_uid(token, None, expires_at + dt.timedelta(seconds=1))
150+
self.assertFalse(result.success)
151+
self.assertEqual(result.status, DecryptionStatus.TOKEN_EXPIRED)
146152

147153
result = self._client._decrypt_token_into_raw_uid(token, None, expires_at - dt.timedelta(seconds=1))
148154
self.assertIsNotNone(result)

tests/test_client.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,15 @@ def test_raw_uid_produces_correct_identity_type_in_token(self, mock_refresh_keys
9090
ad_token = client.encrypt(example_uid)
9191

9292
self.assertEqual(IdentityType.Email,
93-
get_token_identity_type("Q4bGug8t1xjsutKLCNjnb5fTlXSvIQukmahYDJeLBtk=", client._keys))
93+
get_identity_type(client.encrypt("Q4bGug8t1xjsutKLCNjnb5fTlXSvIQukmahYDJeLBtk=")))
9494
self.assertEqual(IdentityType.Phone,
95-
get_token_identity_type("BEOGxroPLdcY7LrSiwjY52+X05V0ryELpJmoWAyXiwbZ", client._keys))
95+
get_identity_type(client.encrypt("BEOGxroPLdcY7LrSiwjY52+X05V0ryELpJmoWAyXiwbZ")))
9696
self.assertEqual(IdentityType.Email,
97-
get_token_identity_type("oKg0ZY9ieD/CGMEjAA0kcq+8aUbLMBG0MgCT3kWUnJs=", client._keys))
97+
get_identity_type(client.encrypt("oKg0ZY9ieD/CGMEjAA0kcq+8aUbLMBG0MgCT3kWUnJs=")))
9898
self.assertEqual(IdentityType.Email,
99-
get_token_identity_type("AKCoNGWPYng/whjBIwANJHKvvGlGyzARtDIAk95FlJyb", client._keys))
99+
get_identity_type(client.encrypt("AKCoNGWPYng/whjBIwANJHKvvGlGyzARtDIAk95FlJyb")))
100100
self.assertEqual(IdentityType.Email,
101-
get_token_identity_type("EKCoNGWPYng/whjBIwANJHKvvGlGyzARtDIAk95FlJyb", client._keys))
101+
get_identity_type(client.encrypt("EKCoNGWPYng/whjBIwANJHKvvGlGyzARtDIAk95FlJyb")))
102102

103103
def test_multiple_keys_per_keyset(self, mock_refresh_keys_util):
104104
def get_post_refresh_keys_response_with_multiple_keys():
@@ -123,7 +123,7 @@ def get_post_refresh_keys_response_with_no_default_keyset_key():
123123

124124
with self.assertRaises(EncryptionError) as context:
125125
client.encrypt(example_uid)
126-
self.assertTrue('No Site ID in keys' in context.exception)
126+
self.assertEqual('No Keyset Key Found', str(context.exception))
127127

128128
def test_cannot_encrypt_if_theres_no_default_keyset_header(self, mock_refresh_keys_util):
129129
def get_post_refresh_keys_response_with_no_default_keyset_header():
@@ -137,7 +137,7 @@ def get_post_refresh_keys_response_with_no_default_keyset_header():
137137

138138
with self.assertRaises(EncryptionError) as context:
139139
client.encrypt(example_uid)
140-
self.assertTrue('No Keyset Key Found' in context.exception)
140+
self.assertEqual('No Keyset Key Found', str(context.exception))
141141

142142
def test_expiry_in_token_matches_expiry_in_response(self, mock_refresh_keys_util):
143143
def get_post_refresh_keys_response_with_token_expiry():
@@ -162,7 +162,7 @@ def decrypt_side_effect(token_bytes, keys, now):
162162

163163
with self.assertRaises(EncryptionError) as context:
164164
client.decrypt(ad_token)
165-
self.assertTrue('token expired' in context.exception)
165+
self.assertEqual('invalid payload', str(context.exception))
166166

167167
def test_encrypt_key_inactive(self, mock_refresh_keys_util):
168168
def get_post_refresh_keys_response_with_key_inactive():
@@ -176,7 +176,7 @@ def get_post_refresh_keys_response_with_key_inactive():
176176

177177
with self.assertRaises(EncryptionError) as context:
178178
client.encrypt(example_uid)
179-
self.assertTrue('No Keyset Key Found' in context.exception)
179+
self.assertEqual('No Keyset Key Found', str(context.exception))
180180

181181
def test_encrypt_key_expired(self, mock_refresh_keys_util):
182182
def get_post_refresh_keys_response_with_key_expired():
@@ -190,4 +190,4 @@ def get_post_refresh_keys_response_with_key_expired():
190190

191191
with self.assertRaises(EncryptionError) as context:
192192
client.encrypt(example_uid)
193-
self.assertTrue('No Keyset Key Found' in context.exception)
193+
self.assertEqual('No Keyset Key Found', str(context.exception))

tests/test_encryption.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import unittest
22

3-
from tests.uid2_token_generator import UID2TokenGenerator, Params
3+
from test_utils import *
4+
from tests.uid2_token_generator import Params
45
from uid2_client import *
56
from uid2_client.encryption import _encrypt_token
6-
from test_utils import *
77

88
_master_secret = bytes([139, 37, 241, 173, 18, 92, 36, 232, 165, 168, 23, 18, 38, 195, 123, 92, 160, 136, 185, 40, 91, 173, 165, 221, 168, 16, 169, 164, 38, 139, 8, 155])
99
_site_secret = bytes([32, 251, 7, 194, 132, 154, 250, 86, 202, 116, 104, 29, 131, 192, 139, 215, 48, 164, 11, 65, 226, 110, 167, 14, 108, 51, 254, 125, 65, 24, 23, 133])
@@ -20,6 +20,7 @@
2020
_keyset_key = EncryptionKey(_site_key_id, _site_id, _now - dt.timedelta(days=-1), _now, _now + dt.timedelta(days=1), _site_secret, keyset_id=20)
2121
_test_site_key = EncryptionKey(_test_site_key_id, _site_id, dt.datetime(2020, 1, 1, tzinfo=timezone.utc), dt.datetime(2020, 1, 1, tzinfo=timezone.utc), _now + dt.timedelta(days=1), encryption_block_size * b'9')
2222

23+
2324
class TestEncryptionFunctions(unittest.TestCase):
2425

2526
def test_cross_platform_consistency_check_base64_url_test_cases(self):
@@ -200,11 +201,8 @@ def test_decrypt_token_2_invalid_lifetime_exception(self):
200201
None, None,
201202
max_sharing_lifetime_seconds, max_bidstream_lifetime_seconds,
202203
None)
203-
204-
with self.assertRaises(EncryptionError) as context:
205-
decrypt_token(token, key_collection, "", client_type)
206-
207-
self.assertEqual(str(context.exception), "invalid token lifetime")
204+
decrypted_token = decrypt_token(token, key_collection, "", client_type)
205+
self.assertEqual(decrypted_token.status, DecryptionStatus.INVALID_TOKEN_LIFETIME)
208206

209207
def test_decrypt_token_invalid_lifetime_pass(self):
210208
seconds_since_established = 3600 # from UID2TokenGenerator.generate_uid2_token_v4
@@ -414,7 +412,7 @@ def test_smoke_token_v3(self):
414412
token_expiry=now + dt.timedelta(days=30) if keys.get_token_expiry_seconds() is None \
415413
else now + dt.timedelta(seconds=int(keys.get_token_expiry_seconds())),
416414
ad_token_version=AdvertisingTokenVersion.ADVERTISING_TOKEN_V3)
417-
final = decrypt(result, keys, now=now)
415+
final = decrypt(result.encrypted_data, keys, now=now)
418416

419417
self.assertEqual(uid2, final.uid)
420418

@@ -427,7 +425,7 @@ def test_smoke_token_v4(self):
427425
master_keyset_id=9999, caller_site_id=20)
428426

429427
result = encrypt(uid2, identity_scope, keys, now=now)
430-
final = decrypt(result, keys, now=now)
428+
final = decrypt(result.encrypted_data, keys, now=now)
431429

432430
self.assertEqual(uid2, final.uid)
433431

0 commit comments

Comments
 (0)