1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
/// `TCModel` serves as a convenience wrapper to parse a given TCString /// without checking the version on the calling side /// /// ```rust,edition2018 /// use std::convert::TryFrom; /// // will return a Result which contains the variant for the TCString version or an Error /// // if the TCString could not be parsed or the TCString includes an unsupported version /// let tc_model = lib_tcstring::TCModel::try_from("COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA"); /// ``` #[derive(PartialEq, Clone, Debug)] pub enum TCModel { /// Contains a reference to the [`TCModelV1`] /// /// [`TCModelV1`]: struct.TCModelV1.html V1(Box<TCModelV1>), /// Contains a reference to the [`TCModelV2`] /// /// [`TCModelV2`]: struct.TCModelV2.html V2(Box<TCModelV2>), } /// Contains restriction types as defined in [`Vendor Consent String Format V2 Core String`] /// /// [`Vendor Consent String Format V2 Core String`]: https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/81a3b9ed1545148be380b4408e6361cd2294446d/TCFv2/IAB%20Tech%20Lab%20-%20Consent%20string%20and%20vendor%20list%20formats%20v2.md#the-core-string #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(PartialEq, Clone, PartialOrd, Hash, Debug)] pub enum PublisherRestrictionType { /// Purpose Flatly Not Allowed by Publisher NotAllowed, /// Specifies that vendors need to have consent RequireConsent, /// Specifies that vendors need to have "Legitimate Interest" RequireLegitimateInterest, /// Should not be used Undefined, } /// `VendorSet` contains a list of vendors which are either allowed or blocked /// based on the [`is_blocklist`] field /// /// [`is_blocklist`]: struct.VendorSet.html#structfield.is_blocklist #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(PartialEq, Clone, PartialOrd, Hash, Debug, Default)] pub struct VendorSet { /// `is_blocklist` defines if [`list`] is an blocklist or an allowlist /// /// [`list`]: struct.VendorSet.html#structfield.list pub is_blocklist: bool, /// List of vendors which are either allowed or blocked based on the [`is_blocklist`] /// /// [`is_blocklist`]: struct.VendorSet.html#structfield.is_blocklist pub list: Vec<u16>, } /// `TCModelV1` contains all relevant fields specified in the [`Vendor Consent String Format V1`] /// except for the `Version` field which is omitted /// /// Field mapping /// * `Created` -> [`created_at`] /// * `LastUpdated` -> [`updated_at`] /// * `CmpId` -> [`cmp_id`] /// * `CmpVersion` -> [`cmp_version`] /// * `ConsentScreen` -> [`consent_screen`] /// * `ConsentLanguage` -> [`consent_lang`] /// * `VendorListVersion` -> [`vendor_list_version`] /// * `PurposesAllowed` -> [`purposes_consent`] /// * `VendorConsents` -> [`vendors`] /// /// ```rust,edition2018 /// use std::convert::TryFrom; /// // will return a Result which contains either the TCModel or an Error /// // if the TCString could not be parsed or the TCString includes an unsupported version /// let tc_model = lib_tcstring::TCModelV1::try_from("BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA"); /// ``` /// /// [`created_at`]: struct.TCModelV1.html#structfield.created_at /// [`updated_at`]: struct.TCModelV1.html#structfield.updated_at /// [`cmp_id`]: struct.TCModelV1.html#structfield.cmp_id /// [`cmp_version`]: struct.TCModelV1.html#structfield.cmp_version /// [`consent_screen`]: struct.TCModelV1.html#structfield.consent_screen /// [`consent_lang`]: struct.TCModelV1.html#structfield.consent_lang /// [`vendor_list_version`]: struct.TCModelV1.html#structfield.vendor_list_version /// [`purposes_consent`]: struct.TCModelV1.html#structfield.purposes_consent /// [`vendors`]: struct.TCModelV1.html#structfield.vendors /// [`Vendor Consent String Format V1`]: https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/ab7e3dcf8c493c743cac87c9bce49c16fc0523e4/Consent%20string%20and%20vendor%20list%20formats%20v1.1%20Final.md#vendor-consent-string-format- #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(PartialEq, Clone, PartialOrd, Hash, Debug, Default)] pub struct TCModelV1 { /// Epoch milliseconds when consent string was first created pub created_at: u64, /// Epoch milliseconds when consent string was last updated pub updated_at: u64, /// Consent Manager Provider ID that last updated the consent string pub cmp_id: u16, /// Consent Manager Provider version pub cmp_version: u16, /// Screen number in the CMP where consent was given pub consent_screen: u8, /// [`ISO 639-1`] language code in which the CMP UI was presented /// /// [`ISO 639-1`]: https://en.wikipedia.org/wiki/ISO_639-1 pub consent_lang: String, /// Version of vendor list used in most recent consent string update pub vendor_list_version: u16, /// List of permitted purposes pub purposes_consent: Vec<u8>, /// List of allowed or blocked vendors /// /// See [`VendorSet`] for more details /// /// [`VendorSet`]: struct.VendorSet.html pub vendors: VendorSet, } /// `TCModelV2` contains all relevant fields specified in the [`Vendor Consent String Format V2`] /// except for the `Version` field which is omitted /// /// Note that the "Core String", "Disclosed Vendors", "Allowed Vendors" and "Publisher TC" segments are mapped into fields /// /// "Core String" field mapping /// * `Created` -> [`created_at`] /// * `LastUpdated` -> [`updated_at`] /// * `CmpId` -> [`cmp_id`] /// * `CmpVersion` -> [`cmp_version`] /// * `ConsentScreen` -> [`consent_screen`] /// * `ConsentLanguage` -> [`consent_language`] /// * `VendorListVersion` -> [`vendor_list_version`] /// * `TcfPolicyVersion` -> [`tcf_policy_version`] /// * `IsServiceSpecific` -> [`is_service_specific`] /// * `UseNonStandardStacks` -> [`use_non_standard_stacks`] /// * `SpecialFeatureOptIns` -> [`special_feature_opt_ins`] /// * `PurposesConsent` -> [`purposes_consent`] /// * `PurposesLITransparancy` -> [`purposes_li_transparency`] /// * `PurposeOneTreatment` -> [`purpose_one_treatment`] /// * `PublisherCC` -> [`publisher_country_code`] /// * `VendorsConsent` -> [`vendors_consent`] /// * `VendorsLIConsent` -> [`vendors_li_consent`] /// * `PublisherRestrictions` -> [`publisher_restrictions`] /// /// "Disclosed Vendors" segment is mapped by the [`disclosed_vendors`] field /// /// "Allowed Vendors" segment is mapped by the [`allowed_vendors`] field /// /// "Publisher TC" field mapping /// * `PubPurposesConsent` -> [`publisher_purposes_consent`] /// * `PubPurposesLITransparency` -> [`publisher_purposes_li_transparency`] /// * `CustomPurposesConsent` -> [`custom_purposes_consent`] /// * `CustomPurposesLITransparency` -> [`custom_purposes_li_transparency`] /// /// ```rust,edition2018 /// use std::convert::TryFrom; /// // will return a Result which contains either the TCModel or an Error /// // if the TCString could not be parsed or the TCString includes an unsupported version /// let tc_model = lib_tcstring::TCModelV2::try_from("COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA"); /// ``` /// /// [`created_at`]: struct.TCModelV2.html#structfield.created_at /// [`updated_at`]: struct.TCModelV2.html#structfield.updated_at /// [`cmp_id`]: struct.TCModelV2.html#structfield.cmp_id /// [`cmp_version`]: struct.TCModelV2.html#structfield.cmp_version /// [`consent_screen`]: struct.TCModelV2.html#structfield.consent_screen /// [`consent_language`]: struct.TCModelV2.html#structfield.consent_language /// [`vendor_list_version`]: struct.TCModelV2.html#structfield.vendor_list_version /// [`tcf_policy_version`]: struct.TCModelV2.html#structfield.tcf_policy_version /// [`is_service_specific`]: struct.TCModelV2.html#structfield.is_service_specific /// [`use_non_standard_stacks`]: struct.TCModelV2.html#structfield.use_non_standard_stacks /// [`special_feature_opt_ins`]: struct.TCModelV2.html#structfield.special_feature_opt_ins /// [`purposes_consent`]: struct.TCModelV2.html#structfield.purposes_consent /// [`purposes_li_transparency`]: struct.TCModelV2.html#structfield.purposes_li_transparency /// [`purpose_one_treatment`]: struct.TCModelV2.html#structfield.purpose_one_treatment /// [`publisher_country_code`]: struct.TCModelV2.html#structfield.publisher_country_code /// [`vendors_consent`]: struct.TCModelV2.html#structfield.vendors_consent /// [`vendors_li_consent`]: struct.TCModelV2.html#structfield.vendors_li_consent /// [`publisher_restrictions`]: struct.TCModelV2.html#structfield.publisher_restrictions /// [`disclosed_vendors`]: struct.TCModelV2.html#structfield.disclosed_vendors /// [`allowed_vendors`]: struct.TCModelV2.html#structfield.allowed_vendors /// [`publisher_purposes_consent`]: struct.TCModelV2.html#structfield.publisher_purposes_consent /// [`publisher_purposes_li_transparency`]: struct.TCModelV2.html#structfield.publisher_purposes_li_transparency /// [`custom_purposes_consent`]: struct.TCModelV2.html#structfield.custom_purposes_consent /// [`custom_purposes_li_transparency`]: struct.TCModelV2.html#structfield.custom_purposes_li_transparency /// [`Vendor Consent String Format V2`]: https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/81a3b9ed1545148be380b4408e6361cd2294446d/TCFv2/IAB%20Tech%20Lab%20-%20Consent%20string%20and%20vendor%20list%20formats%20v2.md#tc-string-format #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(PartialEq, Clone, PartialOrd, Hash, Debug, Default)] pub struct TCModelV2 { /// Epoch milliseconds when this TC String was first created pub created_at: u64, /// Epoch milliseconds when TC String was last updated pub updated_at: u64, /// Consent Management Platform ID that last updated the TC String pub cmp_id: u16, /// Consent Management Platform version of the CMP that last updated this TC String pub cmp_version: u16, /// CMP Screen number at which consent was given for a user with the CMP that last updated this TC String pub consent_screen: u8, /// [`ISO 639-1`] language code in which the CMP UI was presented /// /// [`ISO 639-1`]: https://en.wikipedia.org/wiki/ISO_639-1 pub consent_language: String, /// Version of the global vendor list used to create this TC String pub vendor_list_version: u16, /// Version of the corresponding field in the global vendor list that was used for obtaining consent pub tcf_policy_version: u16, /// Whether the signals encoded in this TC String were from service-specific storage (`true`) or shared storage (`false`) pub is_service_specific: bool, /// `true` means that a CMP is using customized Stack descriptions and not the standard stack descriptions /// defined in the [`Policies`] (Appendix A, Section E) /// /// `false` means standard stacks were used /// /// [`Policies`]: https://iabeurope.eu/iab-europe-transparency-consent-framework-policies/#___E_Stacks__ pub use_non_standard_stacks: bool, /// List of opted-in "Special Features" /// /// "Special Features" are numerically identified in the global vendor list separately from normal features pub special_feature_opt_ins: Vec<u8>, /// List of allowed purposes pub purposes_consent: Vec<u8>, /// List of allowed "Legitimate Interest" purposes pub purposes_li_transparency: Vec<u8>, /// `true` means "Purpose 1" was not disclosed /// /// `false` means "Purpose 1" was disclosed commonly as consent pub purpose_one_treatment: bool, /// [`ISO 3166-1 alpha-2`] code /// /// [`ISO 3166-1 alpha-2`]: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 pub publisher_country_code: String, /// List of allowed vendors pub vendors_consent: Vec<u16>, /// List of vendors "Legitimate Interest" disclosures pub vendors_li_consent: Vec<u16>, /// List of publisher restrictions on a per purpose basis /// /// See [`PublisherRestriction`] for more details /// /// [`PublisherRestriction`]: struct.PublisherRestriction.html pub publisher_restrictions: Vec<PublisherRestriction>, /// List of vendors that have been disclosed to a given user by a CMP pub disclosed_vendors: Vec<u16>, /// List of vendors the publisher permits to use OOB legal bases pub allowed_vendors: Vec<u16>, /// List of purposes which are established on the legal basis of consent, for the publisher pub publisher_purposes_consent: Vec<u8>, /// List of purposes which are established on the legal basis of "Legitimate Interest" and the user has not exercised their “Right to Object” pub publisher_purposes_li_transparency: Vec<u8>, /// List of allowed custom purposes, for the publisher pub custom_purposes_consent: Vec<u8>, /// List of custom purposes which are are established on the legal basis of "Legitimate Interest" pub custom_purposes_li_transparency: Vec<u8>, } /// Publisher restriction which overrides the specificed purpose #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(PartialEq, Clone, PartialOrd, Hash, Debug, Default)] pub struct PublisherRestriction { /// ID of publisher restricted purpose pub purpose_id: u8, /// publisher restriction for this purpose, see [`PublisherRestrictionType`] for more details /// /// [`PublisherRestrictionType`]: enum.PublisherRestrictionType.html pub restriction_type: PublisherRestrictionType, /// List of relevant vendors pub vendor_list: Vec<u16>, } #[cfg_attr(test, derive(Debug))] pub(crate) enum RangeSectionType { Vendor(Vec<u16>), VendorLegitimateInterest(Vec<u16>), PublisherRestriction(Vec<PublisherRestriction>), } #[cfg_attr(test, derive(Debug))] pub(crate) struct TCSegment { pub disclosed_vendors: Option<Vec<u16>>, pub allowed_vendors: Option<Vec<u16>>, pub publisher_tc: Option<PublisherTC>, } #[cfg_attr(test, derive(Debug))] pub(crate) struct RangeSection { pub last_bit: usize, pub value: RangeSectionType, } #[cfg_attr(test, derive(Debug))] pub(crate) struct PublisherTC { pub publisher_purposes_consent: Vec<u8>, pub publisher_purposes_li_transparency: Vec<u8>, pub custom_purposes_consent: Vec<u8>, pub custom_purposes_li_transparency: Vec<u8>, } impl Default for PublisherTC { fn default() -> Self { Self { custom_purposes_consent: vec![], custom_purposes_li_transparency: vec![], publisher_purposes_consent: vec![], publisher_purposes_li_transparency: vec![], } } } impl Default for PublisherRestrictionType { fn default() -> Self { Self::Undefined } } impl VendorSet { #[allow(dead_code)] fn new() -> Self { Self::default() } } impl TCModelV1 { #[allow(dead_code)] fn new() -> Self { Self::default() } } impl TCModelV2 { #[allow(dead_code)] fn new() -> Self { Self::default() } } impl PublisherRestriction { #[allow(dead_code)] fn new() -> Self { Self::default() } }