Skip to content

Commit 1b4c766

Browse files
committed
Fix TCF CA field types
Core fields VendorExpressConsent and VendorImpliedConsent are documented to be of type OptimizedRange. However, The Java implementation uses the same encoder/decoder as for TCF EU v2, which uses the OptimizedIntRange type. As consequence, some payloads generated by the iabgpp.com tool failed to decode in this library. This commit switches the TCF CA fields to use OptimizedIntRange.
1 parent a1d128e commit 1b4c766

File tree

4 files changed

+86
-2
lines changed

4 files changed

+86
-2
lines changed

iab_gpp/src/sections/tcfcav1.rs

+52-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ pub struct Core {
4141
pub purpose_express_consents: IdSet,
4242
#[gpp(fixed_bitfield(24))]
4343
pub purpose_implied_consents: IdSet,
44-
#[gpp(optimized_range)]
44+
// BUG: specification says optimized_range
45+
#[gpp(optimized_integer_range)]
4546
pub vendor_express_consents: IdSet,
46-
#[gpp(optimized_range)]
47+
// BUG: specification says optimized_range
48+
#[gpp(optimized_integer_range)]
4749
pub vendor_implied_consents: IdSet,
4850
/// Introduced in TCF CA v1.1
4951
#[gpp(parse_with = parse_publisher_restrictions)]
@@ -180,4 +182,52 @@ mod tests {
180182
fn error(s: &str) -> SectionDecodeError {
181183
TcfCaV1::from_str(s).unwrap_err()
182184
}
185+
186+
#[test]
187+
fn full_str() {
188+
let actual =
189+
TcfCaV1::from_str("BQMC4oAQMC4oAPoABABGB0CYAf8AAf8AAAqdA-AAUABwAFQALQAaABLACgAF0ANoAdwA_QCCAIQARQAnwBWgC3AGUANMAc4A7gCAQElASYAnYBPwDFAGaAM6AZ8A14B_AEngJyAT-Ao8BUQCpQFvALhAXQAvcBf4DBwGYANNAbUA3EBxoDxAHmgPkAgIBCQCNwEpYJgAmCBNUCa4E5gJ-AUmApYBU4FToHwACgAOAAqABaADQAJYAUAAugBtADuAH6AQQBCACKAE-AK0AW4AygBpgDnAHcAQCAkoCTAE7AJ-AYoAzQBnQDPgGvAP4Ak8BOQCfwFHgKiAVKAt4BcIC6AF7gL_AYOAzABpoDagG4gONAeIA80B8gEBAISARuAlLBMAEwQJqgTXAnMBPwCkwFLAKnAAAA.YAAAAAAAAAA").unwrap();
190+
let expected = TcfCaV1 {
191+
core: Core {
192+
created: 1738195200,
193+
last_updated: 1738195200,
194+
cmp_id: 1000,
195+
cmp_version: 1,
196+
consent_screen: 0,
197+
consent_language: "BG".to_string(),
198+
vendor_list_version: 116,
199+
policy_version: 2,
200+
use_non_standard_stacks: false,
201+
special_feature_express_consents: [1, 2].into(),
202+
purpose_express_consents: [1, 2, 3, 4, 5, 6, 7, 8, 9].into(),
203+
purpose_implied_consents: [1, 2, 3, 4, 5, 6, 7, 8, 9].into(),
204+
vendor_express_consents: [
205+
10, 28, 42, 45, 52, 75, 80, 93, 109, 119, 126, 130, 131, 132, 138, 159, 173,
206+
183, 202, 211, 231, 238, 256, 293, 294, 315, 319, 394, 410, 413, 415, 431, 508,
207+
591, 626, 639, 655, 674, 677, 734, 737, 744, 759, 767, 775, 816, 845, 874, 881,
208+
909, 964, 973, 996, 1028, 1060, 1134, 1189, 1216, 1217, 1237, 1239, 1254, 1276,
209+
1318, 1324, 1358,
210+
]
211+
.into(),
212+
vendor_implied_consents: [
213+
10, 28, 42, 45, 52, 75, 80, 93, 109, 119, 126, 130, 131, 132, 138, 159, 173,
214+
183, 202, 211, 231, 238, 256, 293, 294, 315, 319, 394, 410, 413, 415, 431, 508,
215+
591, 626, 639, 655, 674, 677, 734, 737, 744, 759, 767, 775, 816, 845, 874, 881,
216+
909, 964, 973, 996, 1028, 1060, 1134, 1189, 1216, 1217, 1237, 1239, 1254, 1276,
217+
1318, 1324, 1358,
218+
]
219+
.into(),
220+
pub_restrictions: Default::default(),
221+
},
222+
disclosed_vendors: None,
223+
publisher_purposes: Some(PublisherPurposes {
224+
purpose_express_consents: Default::default(),
225+
purpose_implied_consents: Default::default(),
226+
custom_purpose_express_consents: Default::default(),
227+
custom_purpose_implied_consents: Default::default(),
228+
}),
229+
};
230+
231+
assert_eq!(actual, expected);
232+
}
183233
}

iab_gpp/src/v1/mod.rs

+28
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,34 @@ mod tests {
555555
assert!(matches!(r[0], Err(SectionDecodeError::Read { .. })));
556556
}
557557

558+
#[test]
559+
fn very_large_string() {
560+
let s = "DBACMYA~CQMC4oAQMC4oAPoABABGBaEAAP_gAP_gAAqIKxtX_G__bXlv-X736ftkeY1f99h77sQxBhbJs-4FzLvW_JwX32E7NE36tqYKmRIAu3TBIQNtHJjURVChaogVrTDsaEyUoTtKJ-BkiHMRY2dYCFxvm4tjeQCZ5vr_91d52R_t7dr-3dzyy5hnv3a9_-S1WJidK5-tHfv9bROb-_I-9_x-_4v4_N7pE2_eT1t_tWvt739-8tv_9__99__7_f______3_-_f__f____grG1f8b_9teW_5fvfp-2R5jV_32HvuxDEGFsmz7gXMu9b8nBffYTs0Tfq2pgqZEgC7dMEhA20cmNRFUKFqiBWtMOxoTJShO0on4GSIcxFjZ1gIXG-bi2N5AJnm-v_3V3nZH-3t2v7d3PLLmGe_dr3_5LVYmJ0rn60d-_1tE5v78j73_H7_i_j83ukTb95PW3-1a-3vf37y2__3__33__v9_______f_79__9____-AAA.QKxtX_G__bXlv-X736ftkeY1f99h77sQxBhbJs-4FzLvW_JwX32E7NE36tqYKmRIAu3TBIQNtHJjURVChaogVrTDsaEyUoTtKJ-BkiHMRY2dYCFxvm4tjeQCZ5vr_91d52R_t7dr-3dzyy5hnv3a9_-S1WJidK5-tHfv9bROb-_I-9_x-_4v4_N7pE2_eT1t_tWvt739-8tv_9__99__7_f______3_-_f__f____gAA.IKxtX_G__bXlv-X736ftkeY1f99h77sQxBhbJs-4FzLvW_JwX32E7NE36tqYKmRIAu3TBIQNtHJjURVChaogVrTDsaEyUoTtKJ-BkiHMRY2dYCFxvm4tjeQCZ5vr_91d52R_t7dr-3dzyy5hnv3a9_-S1WJidK5-tHfv9bROb-_I-9_x-_4v4_N7pE2_eT1t_tWvt739-8tv_9__99__7_f______3_-_f__f____gAA~BQMC4oAQMC4oAPoABABGB0CYAf8AAf8AAAqdA-AAUABwAFQALQAaABLACgAF0ANoAdwA_QCCAIQARQAnwBWgC3AGUANMAc4A7gCAQElASYAnYBPwDFAGaAM6AZ8A14B_AEngJyAT-Ao8BUQCpQFvALhAXQAvcBf4DBwGYANNAbUA3EBxoDxAHmgPkAgIBCQCNwEpYJgAmCBNUCa4E5gJ-AUmApYBU4FToHwACgAOAAqABaADQAJYAUAAugBtADuAH6AQQBCACKAE-AK0AW4AygBpgDnAHcAQCAkoCTAE7AJ-AYoAzQBnQDPgGvAP4Ak8BOQCfwFHgKiAVKAt4BcIC6AF7gL_AYOAzABpoDagG4gONAeIA80B8gEBAISARuAlLBMAEwQJqgTXAnMBPwCkwFLAKnAAAA.YAAAAAAAAAA";
561+
let r = GPPString::from_str(s);
562+
assert!(matches!(r, Ok(GPPString { .. })));
563+
564+
let gpp = r.unwrap();
565+
566+
assert_eq!(
567+
gpp.section_ids,
568+
vec![SectionId::TcfEuV2, SectionId::TcfCaV1]
569+
);
570+
571+
let tcfeuv2 = gpp.decode_section(SectionId::TcfEuV2);
572+
assert!(
573+
matches!(tcfeuv2, Ok(Section::TcfEuV2(_))),
574+
"got {:?}",
575+
tcfeuv2
576+
);
577+
578+
let tcfcav1 = gpp.decode_section(SectionId::TcfCaV1);
579+
assert!(
580+
matches!(tcfcav1, Ok(Section::TcfCaV1(_))),
581+
"got {:?}",
582+
tcfcav1
583+
);
584+
}
585+
558586
macro_rules! assert_implements {
559587
($type:ty, [$($trait:path),+]) => {
560588
{

iab_gpp_derive/src/from_data_reader.rs

+5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ pub fn derive_struct_from_data_reader(
4646

4747
let attr = GPPFieldHelperAttribute::new(&field.attrs).expect("attribute parsing failed");
4848

49+
// debug next field
50+
/*parse_statements.push(quote! {
51+
println!("Parsing field: {}", stringify!(#name));
52+
});*/
53+
4954
// Handle where attribute
5055
if let Some(where_spec) = attr.where_spec {
5156
let name = where_spec.name;

iab_gpp_derive/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod from_data_reader;
1212
mod optional_segment_parser;
1313
mod struct_attr;
1414

15+
/// Derive the FromDataReader trait
1516
#[proc_macro_derive(FromDataReader, attributes(gpp))]
1617
pub fn derive_from_data_reader(input: TokenStream) -> TokenStream {
1718
let input = parse_macro_input!(input as DeriveInput);

0 commit comments

Comments
 (0)