Skip to content

Commit e4434af

Browse files
committed
Store identity type in decrypted token
1 parent 5918b26 commit e4434af

File tree

4 files changed

+40
-11
lines changed

4 files changed

+40
-11
lines changed

examples/sample_bidstream_client.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ def _usage():
2424
client.refresh()
2525
decrypt_result = client.decrypt_token_into_raw_uid(ad_token, domain_name)
2626

27+
print('Status =', decrypt_result.status)
2728
print('UID =', decrypt_result.uid)
2829
print('Established =', decrypt_result.established)
2930
print('Site ID =', decrypt_result.site_id)
31+
print('Identity Scope =', decrypt_result.identity_scope)
32+
print('Identity Type =', decrypt_result.identity_type)
33+
print('Advertising Token Version =', decrypt_result.advertising_token_version)
3034
print('Site Key Site ID =', decrypt_result.site_key_site_id)

examples/sample_sharing_client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ def _usage():
2727

2828
decrypt_result = client.decrypt_token_into_raw_uid(encryption_data_response.encrypted_data)
2929

30+
print('Status =', decrypt_result.status)
3031
print('Decrypted UID =', decrypt_result.uid)
32+
print('UID =', decrypt_result.uid)
3133
print('Established =', decrypt_result.established)
3234
print('Site ID =', decrypt_result.site_id)
35+
print('Identity Scope =', decrypt_result.identity_scope)
36+
print('Identity Type =', decrypt_result.identity_type)
37+
print('Advertising Token Version =', decrypt_result.advertising_token_version)
38+
print('Site Key Site ID =', decrypt_result.site_key_site_id)

tests/test_bidstream_client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ class TestBidStreamClient(unittest.TestCase):
1212

1313
def assert_success(self, decryption_response, token_version, scope):
1414
self.assertEqual(decryption_response.advertising_token_version, token_version)
15+
if (token_version == AdvertisingTokenVersion.ADVERTISING_TOKEN_V3
16+
or token_version == AdvertisingTokenVersion.ADVERTISING_TOKEN_V4):
17+
self.assertEqual(decryption_response.identity_type, IdentityType.Email)
18+
else:
19+
self.assertEqual(decryption_response.identity_type, None)
1520
self.assertEqual(decryption_response.uid, example_uid)
1621
self.assertEqual(decryption_response.identity_scope, scope)
1722
self.assertEqual((now - decryption_response.established).total_seconds(), 0)
@@ -45,6 +50,7 @@ def test_phone_uids(self, mock_refresh_bidstream_keys): # PhoneTest
4550
result = self._client.decrypt_token_into_raw_uid(token, None)
4651
self.assertIsNotNone(result)
4752
self.assertEqual(result.uid, phone_uid)
53+
self.assertEqual(result.identity_type, IdentityType.Phone)
4854
self.assertEqual(result.identity_scope, expected_scope)
4955
self.assertEqual(result.advertising_token_version, expected_version)
5056

uid2_client/encryption.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,13 @@ def _decrypt_token_v2(token_bytes, keys, domain_name, client_type, now):
158158
expires = dt.datetime.fromtimestamp(expires_ms / 1000.0, tz=timezone.utc)
159159
if expires < now:
160160
return DecryptedToken(DecryptionStatus.TOKEN_EXPIRED, None, None, None, None,
161-
keys.get_identity_scope(), AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
161+
keys.get_identity_scope(), None, AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
162162

163163
site_key_id = int.from_bytes(master_payload[8:12], 'big')
164164
site_key = keys.get(site_key_id)
165165
if site_key is None:
166166
return DecryptedToken(DecryptionStatus.NOT_AUTHORIZED_FOR_KEY, None, None, None, site_key.site_id,
167-
keys.get_identity_scope(), AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
167+
keys.get_identity_scope(), None, AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
168168

169169
identity_iv = master_payload[12:28]
170170
identity = _decrypt(master_payload[28:], identity_iv, site_key)
@@ -180,13 +180,25 @@ def _decrypt_token_v2(token_bytes, keys, domain_name, client_type, now):
180180

181181
if not _token_has_valid_lifetime(keys, client_type, established, expires, now):
182182
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)
183+
keys.get_identity_scope(), None, AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
184184

185185
return DecryptedToken(DecryptionStatus.SUCCESS, id_str, established, site_id, site_key.site_id,
186-
keys.get_identity_scope(), AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
186+
keys.get_identity_scope(), None, AdvertisingTokenVersion.ADVERTISING_TOKEN_V2, expires)
187+
188+
189+
def _get_identity_type_from_token(token_bytes):
190+
first_byte = token_bytes[0]
191+
type_byte = (first_byte & 0x0F) >> 2
192+
if type_byte == 0:
193+
identity_type = IdentityType.Email
194+
else:
195+
identity_type = IdentityType.Phone
196+
return identity_type
187197

188198

189199
def _decrypt_token_v3(token_bytes, keys, domain_name, client_type, now, token_version):
200+
identity_type = _get_identity_type_from_token(token_bytes)
201+
190202
master_key_id = int.from_bytes(token_bytes[2:6], 'big')
191203
master_key = keys.get(master_key_id)
192204
if master_key is None:
@@ -198,7 +210,7 @@ def _decrypt_token_v3(token_bytes, keys, domain_name, client_type, now, token_ve
198210
expires = dt.datetime.fromtimestamp(expires_ms / 1000.0, tz=timezone.utc)
199211
if expires < now:
200212
return DecryptedToken(DecryptionStatus.TOKEN_EXPIRED, None, None, None, None,
201-
keys.get_identity_scope(), token_version, expires)
213+
keys.get_identity_scope(), identity_type, token_version, expires)
202214

203215
# created 8:16
204216
# operator site id 16:20
@@ -210,7 +222,7 @@ def _decrypt_token_v3(token_bytes, keys, domain_name, client_type, now, token_ve
210222
site_key = keys.get(site_key_id)
211223
if site_key is None:
212224
return DecryptedToken(DecryptionStatus.NOT_AUTHORIZED_FOR_KEY, None, None, None, site_key.site_id,
213-
keys.get_identity_scope(), token_version, expires)
225+
keys.get_identity_scope(), identity_type, token_version, expires)
214226

215227
site_payload = _decrypt_gcm(master_payload[33:], site_key.secret)
216228

@@ -223,21 +235,21 @@ def _decrypt_token_v3(token_bytes, keys, domain_name, client_type, now, token_ve
223235

224236
if not _is_domain_name_allowed_for_site(client_type, domain_name, privacy_bits):
225237
return DecryptedToken(DecryptionStatus.DOMAIN_NAME_CHECK_FAILED, None, None, site_id, site_key.site_id,
226-
keys.get_identity_scope(), token_version, expires)
238+
keys.get_identity_scope(), identity_type, token_version, expires)
227239

228240
established_ms = int.from_bytes(site_payload[20:28], 'big')
229241
established = dt.datetime.fromtimestamp(established_ms / 1000.0, tz=timezone.utc)
230242
# refreshed_ms 28:36
231243

232244
if not _token_has_valid_lifetime(keys, client_type, established, expires, now):
233245
return DecryptedToken(DecryptionStatus.INVALID_TOKEN_LIFETIME, None, established, site_id, site_key.site_id,
234-
keys.get_identity_scope(), token_version, expires)
246+
keys.get_identity_scope(), identity_type, token_version, expires)
235247

236248
id_bytes = site_payload[36:]
237249
id_str = base64.b64encode(id_bytes).decode('ascii')
238250

239251
return DecryptedToken(DecryptionStatus.SUCCESS, id_str, established, site_id, site_key.site_id,
240-
keys.get_identity_scope(), token_version, expires)
252+
keys.get_identity_scope(), identity_type, token_version, expires)
241253

242254

243255
def _encrypt_token(uid2, identity_scope, master_key, site_key, site_id, now, token_expiry, ad_token_version):
@@ -525,12 +537,13 @@ class DecryptedToken:
525537
site_key_site_id (int): site ID of the site key which the token is encrypted with
526538
"""
527539

528-
def __init__(self, status, uid, established, site_id, site_key_site_id, identity_scope, advertising_token_version, expiry):
540+
def __init__(self, status, uid, established, site_id, site_key_site_id, identity_scope, identity_type, advertising_token_version, expiry):
529541
self.status = status
530542
self.uid = uid
531543
self.established = established
532544
self.site_id = site_id
533545
self.site_key_site_id = site_key_site_id
546+
self.identity_type = identity_type
534547
self.identity_scope = identity_scope
535548
self.advertising_token_version = advertising_token_version
536549
self.expiry = expiry
@@ -541,7 +554,7 @@ def success(self):
541554

542555
@staticmethod
543556
def make_error(decryption_status):
544-
return DecryptedToken(decryption_status, None, None, None, None, None, None, None)
557+
return DecryptedToken(decryption_status, None, None, None, None, None, None, None, None)
545558

546559

547560
class DecryptedData:

0 commit comments

Comments
 (0)