Skip to content

Commit 5918b26

Browse files
committed
Expose expiry time in decryption response
1 parent cfbda5c commit 5918b26

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

tests/test_bidstream_client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ def test_token_expiry_custom_decryption_time(self, mock_refresh_bidstream_keys):
149149
result = self._client._decrypt_token_into_raw_uid(token, None, expires_at + dt.timedelta(seconds=1))
150150
self.assertFalse(result.success)
151151
self.assertEqual(result.status, DecryptionStatus.TOKEN_EXPIRED)
152+
self.assertEqual(result.expiry, expires_at)
152153

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

tests/test_sharing_client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ def test_expiry_in_token_matches_expiry_in_response(self, mock_refresh_keys_util
196196
result = self._client._decrypt_token_into_raw_uid(encryption_data_response.encrypted_data, now + dt.timedelta(seconds=3))
197197
self.assertFalse(result.success)
198198
self.assertEqual(DecryptionStatus.TOKEN_EXPIRED, result.status)
199+
self.assertEqual(now + dt.timedelta(seconds=2), result.expiry)
199200

200201
def test_encrypt_key_inactive(self, mock_refresh_keys_util): #EncryptKeyInactive
201202
def get_post_refresh_keys_response_with_key_inactive():

uid2_client/encryption.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,14 @@ def _decrypt_token_v2(token_bytes, keys, domain_name, client_type, now):
157157
expires_ms = int.from_bytes(master_payload[:8], 'big')
158158
expires = dt.datetime.fromtimestamp(expires_ms / 1000.0, tz=timezone.utc)
159159
if expires < now:
160-
return DecryptedToken.make_error(DecryptionStatus.TOKEN_EXPIRED)
160+
return DecryptedToken(DecryptionStatus.TOKEN_EXPIRED, None, None, None, None,
161+
keys.get_identity_scope(), AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
161162

162163
site_key_id = int.from_bytes(master_payload[8:12], 'big')
163164
site_key = keys.get(site_key_id)
164165
if site_key is None:
165-
return DecryptedToken.make_error(DecryptionStatus.NOT_AUTHORIZED_FOR_KEY)
166+
return DecryptedToken(DecryptionStatus.NOT_AUTHORIZED_FOR_KEY, None, None, None, site_key.site_id,
167+
keys.get_identity_scope(), AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
166168

167169
identity_iv = master_payload[12:28]
168170
identity = _decrypt(master_payload[28:], identity_iv, site_key)
@@ -177,10 +179,11 @@ def _decrypt_token_v2(token_bytes, keys, domain_name, client_type, now):
177179
established = dt.datetime.fromtimestamp(established_ms / 1000.0, tz=timezone.utc)
178180

179181
if not _token_has_valid_lifetime(keys, client_type, established, expires, now):
180-
return DecryptedToken.make_error(DecryptionStatus.INVALID_TOKEN_LIFETIME)
182+
return DecryptedToken(DecryptionStatus.INVALID_TOKEN_LIFETIME, id_str, established, site_id, site_key.site_id,
183+
keys.get_identity_scope(), AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
181184

182185
return DecryptedToken(DecryptionStatus.SUCCESS, id_str, established, site_id, site_key.site_id,
183-
keys.get_identity_scope(), AdvertisingTokenVersion.ADVERTISING_TOKEN_V2)
186+
keys.get_identity_scope(), AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
184187

185188

186189
def _decrypt_token_v3(token_bytes, keys, domain_name, client_type, now, token_version):
@@ -194,7 +197,8 @@ def _decrypt_token_v3(token_bytes, keys, domain_name, client_type, now, token_ve
194197
expires_ms = int.from_bytes(master_payload[:8], 'big')
195198
expires = dt.datetime.fromtimestamp(expires_ms / 1000.0, tz=timezone.utc)
196199
if expires < now:
197-
return DecryptedToken.make_error(DecryptionStatus.TOKEN_EXPIRED)
200+
return DecryptedToken(DecryptionStatus.TOKEN_EXPIRED, None, None, None, None,
201+
keys.get_identity_scope(), token_version, expires)
198202

199203
# created 8:16
200204
# operator site id 16:20
@@ -205,7 +209,8 @@ def _decrypt_token_v3(token_bytes, keys, domain_name, client_type, now, token_ve
205209
site_key_id = int.from_bytes(master_payload[29:33], 'big')
206210
site_key = keys.get(site_key_id)
207211
if site_key is None:
208-
return DecryptedToken.make_error(DecryptionStatus.NOT_AUTHORIZED_FOR_KEY)
212+
return DecryptedToken(DecryptionStatus.NOT_AUTHORIZED_FOR_KEY, None, None, None, site_key.site_id,
213+
keys.get_identity_scope(), token_version, expires)
209214

210215
site_payload = _decrypt_gcm(master_payload[33:], site_key.secret)
211216

@@ -217,20 +222,22 @@ def _decrypt_token_v3(token_bytes, keys, domain_name, client_type, now, token_ve
217222
privacy_bits.frombytes(site_payload[16:20])
218223

219224
if not _is_domain_name_allowed_for_site(client_type, domain_name, privacy_bits):
220-
return DecryptedToken.make_error(DecryptionStatus.DOMAIN_NAME_CHECK_FAILED)
225+
return DecryptedToken(DecryptionStatus.DOMAIN_NAME_CHECK_FAILED, None, None, site_id, site_key.site_id,
226+
keys.get_identity_scope(), token_version, expires)
221227

222228
established_ms = int.from_bytes(site_payload[20:28], 'big')
223229
established = dt.datetime.fromtimestamp(established_ms / 1000.0, tz=timezone.utc)
224230
# refreshed_ms 28:36
225231

226232
if not _token_has_valid_lifetime(keys, client_type, established, expires, now):
227-
return DecryptedToken.make_error(DecryptionStatus.INVALID_TOKEN_LIFETIME)
233+
return DecryptedToken(DecryptionStatus.INVALID_TOKEN_LIFETIME, None, established, site_id, site_key.site_id,
234+
keys.get_identity_scope(), token_version, expires)
228235

229236
id_bytes = site_payload[36:]
230237
id_str = base64.b64encode(id_bytes).decode('ascii')
231238

232239
return DecryptedToken(DecryptionStatus.SUCCESS, id_str, established, site_id, site_key.site_id,
233-
keys.get_identity_scope(), token_version)
240+
keys.get_identity_scope(), token_version, expires)
234241

235242

236243
def _encrypt_token(uid2, identity_scope, master_key, site_key, site_id, now, token_expiry, ad_token_version):
@@ -518,22 +525,23 @@ class DecryptedToken:
518525
site_key_site_id (int): site ID of the site key which the token is encrypted with
519526
"""
520527

521-
def __init__(self, status, uid, established, site_id, site_key_site_id, identity_scope, advertising_token_version):
528+
def __init__(self, status, uid, established, site_id, site_key_site_id, identity_scope, advertising_token_version, expiry):
522529
self.status = status
523530
self.uid = uid
524531
self.established = established
525532
self.site_id = site_id
526533
self.site_key_site_id = site_key_site_id
527534
self.identity_scope = identity_scope
528535
self.advertising_token_version = advertising_token_version
536+
self.expiry = expiry
529537

530538
@property
531539
def success(self):
532540
return self.status == DecryptionStatus.SUCCESS
533541

534542
@staticmethod
535543
def make_error(decryption_status):
536-
return DecryptedToken(decryption_status, None, None, None, None, None, None)
544+
return DecryptedToken(decryption_status, None, None, None, None, None, None, None)
537545

538546

539547
class DecryptedData:

0 commit comments

Comments
 (0)