@@ -33,13 +33,13 @@ internal static DecryptionResponse Decrypt(string token, KeyContainer keys, Date
3333
3434 if ( data [ 1 ] == ( int ) AdvertisingTokenVersion . V3 )
3535 {
36- return DecryptV3 ( Convert . FromBase64String ( token ) , keys , now , domainName , identityScope , enableDomainNameCheck ) ;
36+ return DecryptV3 ( Convert . FromBase64String ( token ) , keys , now , identityScope , 3 , domainName , enableDomainNameCheck ) ;
3737 }
3838
3939 if ( data [ 1 ] == ( int ) AdvertisingTokenVersion . V4 )
4040 {
4141 //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 ) ;
4343 }
4444
4545 return DecryptionResponse . MakeError ( DecryptionStatus . VersionNotSupported ) ;
@@ -93,26 +93,26 @@ private static DecryptionResponse DecryptV2(byte[] encryptedId, KeyContainer key
9393 var expiry = DateTimeUtils . FromEpochMilliseconds ( expiresMilliseconds ) ;
9494 if ( expiry < now )
9595 {
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 ) ;
9797 }
9898
9999 if ( privacyBits . IsOptedOut )
100100 {
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 ) ;
102102 }
103103
104104 if ( enableDomainNameCheck && ! IsDomainNameAllowedForSite ( privacyBits , siteId , domainName , keys ) )
105105 {
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 ) ;
107107 }
108108
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 ) ;
110110 }
111111
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 )
115113 {
114+ IdentityType identityType = GetIdentityType ( encryptedId ) ;
115+
116116 var reader = new BigEndianByteReader ( new MemoryStream ( encryptedId ) ) ;
117117
118118 var prefix = reader . ReadByte ( ) ;
@@ -170,20 +170,21 @@ private static DecryptionResponse DecryptV3(byte[] encryptedId, KeyContainer key
170170 var expiry = DateTimeUtils . FromEpochMilliseconds ( expiresMilliseconds ) ;
171171 if ( expiry < now )
172172 {
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 ) ;
174174 }
175175
176176 if ( privacyBits . IsOptedOut )
177177 {
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 ) ;
179179 }
180180
181181 if ( enableDomainNameCheck && ! IsDomainNameAllowedForSite ( privacyBits , siteId , domainName , keys ) )
182182 {
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 ) ;
184185 }
185186
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 ) ;
187188 }
188189
189190 private static bool IsDomainNameAllowedForSite ( PrivacyBits privacyBits , int siteId , string domainName , KeyContainer keys )
@@ -468,5 +469,17 @@ private static IdentityScope DecodeIdentityScopeV3(byte value)
468469 {
469470 return ( IdentityScope ) ( ( value >> 4 ) & 1 ) ;
470471 }
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+ }
471484 }
472485}
0 commit comments