@@ -33,13 +33,13 @@ internal static DecryptionResponse Decrypt(string token, KeyContainer keys, Date
33
33
34
34
if ( data [ 1 ] == ( int ) AdvertisingTokenVersion . V3 )
35
35
{
36
- return DecryptV3 ( Convert . FromBase64String ( token ) , keys , now , domainName , identityScope , enableDomainNameCheck ) ;
36
+ return DecryptV3 ( Convert . FromBase64String ( token ) , keys , now , identityScope , 3 , domainName , enableDomainNameCheck ) ;
37
37
}
38
38
39
39
if ( data [ 1 ] == ( int ) AdvertisingTokenVersion . V4 )
40
40
{
41
41
//same as V3 but use Base64URL encoding
42
- return DecryptV3 ( UID2Base64UrlCoder . Decode ( token ) , keys , now , domainName , identityScope , enableDomainNameCheck ) ;
42
+ return DecryptV3 ( UID2Base64UrlCoder . Decode ( token ) , keys , now , identityScope , 4 , domainName , enableDomainNameCheck ) ;
43
43
}
44
44
45
45
return DecryptionResponse . MakeError ( DecryptionStatus . VersionNotSupported ) ;
@@ -93,26 +93,26 @@ private static DecryptionResponse DecryptV2(byte[] encryptedId, KeyContainer key
93
93
var expiry = DateTimeUtils . FromEpochMilliseconds ( expiresMilliseconds ) ;
94
94
if ( expiry < now )
95
95
{
96
- return new DecryptionResponse ( DecryptionStatus . ExpiredToken , null , established , siteId , siteKey . SiteId , privacyBits . IsClientSideGenerated ) ;
96
+ return new DecryptionResponse ( DecryptionStatus . ExpiredToken , null , established , siteId , siteKey . SiteId , null , 2 , privacyBits . IsClientSideGenerated ) ;
97
97
}
98
98
99
99
if ( privacyBits . IsOptedOut )
100
100
{
101
- return new DecryptionResponse ( DecryptionStatus . UserOptedOut , null , established , siteId , siteKey . SiteId , privacyBits . IsClientSideGenerated ) ;
101
+ return new DecryptionResponse ( DecryptionStatus . UserOptedOut , null , established , siteId , siteKey . SiteId , null , 2 , privacyBits . IsClientSideGenerated ) ;
102
102
}
103
103
104
104
if ( enableDomainNameCheck && ! IsDomainNameAllowedForSite ( privacyBits , siteId , domainName , keys ) )
105
105
{
106
- return new DecryptionResponse ( DecryptionStatus . DomainNameCheckFailed , null , established , siteId , siteKey . SiteId , privacyBits . IsClientSideGenerated ) ;
106
+ return new DecryptionResponse ( DecryptionStatus . DomainNameCheckFailed , null , established , siteId , siteKey . SiteId , null , 2 , privacyBits . IsClientSideGenerated ) ;
107
107
}
108
108
109
- return new DecryptionResponse ( DecryptionStatus . Success , idString , established , siteId , siteKey . SiteId , privacyBits . IsClientSideGenerated ) ;
109
+ return new DecryptionResponse ( DecryptionStatus . Success , idString , established , siteId , siteKey . SiteId , null , 2 , privacyBits . IsClientSideGenerated ) ;
110
110
}
111
111
112
- private static DecryptionResponse DecryptV3 ( byte [ ] encryptedId , KeyContainer keys , DateTime now ,
113
- string domainName ,
114
- IdentityScope identityScope , bool enableDomainNameCheck )
112
+ private static DecryptionResponse DecryptV3 ( byte [ ] encryptedId , KeyContainer keys , DateTime now , IdentityScope identityScope , int advertisingTokenVersion , string domainName , bool enableDomainNameCheck )
115
113
{
114
+ IdentityType identityType = GetIdentityType ( encryptedId ) ;
115
+
116
116
var reader = new BigEndianByteReader ( new MemoryStream ( encryptedId ) ) ;
117
117
118
118
var prefix = reader . ReadByte ( ) ;
@@ -170,20 +170,21 @@ private static DecryptionResponse DecryptV3(byte[] encryptedId, KeyContainer key
170
170
var expiry = DateTimeUtils . FromEpochMilliseconds ( expiresMilliseconds ) ;
171
171
if ( expiry < now )
172
172
{
173
- return new DecryptionResponse ( DecryptionStatus . ExpiredToken , null , established , siteId , siteKey . SiteId , privacyBits . IsClientSideGenerated ) ;
173
+ return new DecryptionResponse ( DecryptionStatus . ExpiredToken , null , established , siteId , siteKey . SiteId , identityType , advertisingTokenVersion , privacyBits . IsClientSideGenerated ) ;
174
174
}
175
175
176
176
if ( privacyBits . IsOptedOut )
177
177
{
178
- return new DecryptionResponse ( DecryptionStatus . UserOptedOut , null , established , siteId , siteKey . SiteId , privacyBits . IsClientSideGenerated ) ;
178
+ return new DecryptionResponse ( DecryptionStatus . UserOptedOut , null , established , siteId , siteKey . SiteId , identityType , advertisingTokenVersion , privacyBits . IsClientSideGenerated ) ;
179
179
}
180
180
181
181
if ( enableDomainNameCheck && ! IsDomainNameAllowedForSite ( privacyBits , siteId , domainName , keys ) )
182
182
{
183
- return new DecryptionResponse ( DecryptionStatus . DomainNameCheckFailed , null , established , siteId , siteKey . SiteId , privacyBits . IsClientSideGenerated ) ;
183
+ return new DecryptionResponse ( DecryptionStatus . DomainNameCheckFailed , null , established , siteId , siteKey . SiteId , identityType , advertisingTokenVersion ,
184
+ privacyBits . IsClientSideGenerated ) ;
184
185
}
185
186
186
- return new DecryptionResponse ( DecryptionStatus . Success , idString , established , siteId , siteKey . SiteId , privacyBits . IsClientSideGenerated ) ;
187
+ return new DecryptionResponse ( DecryptionStatus . Success , idString , established , siteId , siteKey . SiteId , identityType , advertisingTokenVersion , privacyBits . IsClientSideGenerated ) ;
187
188
}
188
189
189
190
private static bool IsDomainNameAllowedForSite ( PrivacyBits privacyBits , int siteId , string domainName , KeyContainer keys )
@@ -468,5 +469,17 @@ private static IdentityScope DecodeIdentityScopeV3(byte value)
468
469
{
469
470
return ( IdentityScope ) ( ( value >> 4 ) & 1 ) ;
470
471
}
472
+
473
+ private static IdentityType GetIdentityType ( byte [ ] encryptedId )
474
+ {
475
+ // For specifics about the bitwise logic, check:
476
+ // Confluence - UID2-79 UID2 Token v3/v4 and Raw UID2 format v3
477
+ // In the base64-encoded version of encryptedId, the first character is always either A/B/E/F.
478
+ // After converting to binary and performing the AND operation against 1100,the result is always 0X00.
479
+ // So just bitshift right twice to get 000X, which results in either 0 or 1.
480
+ byte idType = encryptedId [ 0 ] ;
481
+ byte piiType = ( byte ) ( ( idType & 0b_1100 ) >> 2 ) ;
482
+ return piiType == 0 ? IdentityType . Email : IdentityType . Phone ;
483
+ }
471
484
}
472
485
}
0 commit comments