Skip to content

Commit

Permalink
add strict mode
Browse files Browse the repository at this point in the history
  • Loading branch information
peczenyj committed Dec 15, 2023
1 parent be9b81c commit 783c8fd
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 14 deletions.
2 changes: 2 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
- add strict mode (disabled by default) to validate the consent string version

0.084
- fix a bug while parsing valid consent strings range-based, see https://github.com/peczenyj/GDPR-IAB-TCFv2/issues/20

Expand Down
7 changes: 6 additions & 1 deletion README.pod
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,10 @@ or
boolean_values => [ 0, 1 ],
date_format => '%Y%m%d', # yyymmdd
},
strict => 1,
);

Parse may receive an optional hash parameter C<json> with the following properties:
Parse may receive an optional hash of parameters: C<strict> (boolean) and C<json> (hashref with the following properties):

=over

Expand Down Expand Up @@ -149,6 +150,10 @@ except if the option C<use_epoch> is true.

=back

On C<strict> mode we will validate if the version of the consent string is the version 2 (or die with an exception).

The C<strict> mode is disabled by default.

=head1 METHODS

=head2 tc_string
Expand Down
29 changes: 20 additions & 9 deletions lib/GDPR/IAB/TCFv2.pm
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ our $VERSION = "0.084";
use constant {
CONSENT_STRING_TCF2_SEPARATOR => '.',
CONSENT_STRING_TCF2_PREFIX => 'C',
MIN_BYTE_SIZE => 29,
TCF_V2_MIN_BYTE_SIZE => 29,
TCF_VERSION => 2,
ASSUMED_MAX_VENDOR_ID => 0x7FFF, # 32767 or (1 << 15) -1
MAX_SPECIAL_FEATURE_ID => 12,
Expand Down Expand Up @@ -90,14 +90,13 @@ sub Parse {

my $core_tc_string = _get_core_tc_string($tc_string);

my $data = unpack 'B*', _validate_and_decode_base64($core_tc_string);
my $data_size = length($data);
my ( $data, $data_size ) = _validate_and_decode_base64($core_tc_string);

croak "vendor consent strings are at least @{[ MIN_BYTE_SIZE ]} bytes long"
if $data_size < 8 * MIN_BYTE_SIZE;
my $strict = !!$opts{strict};

my %options = (
json => $opts{json} || {},
json => $opts{json} || {},
strict => $strict,
);

$options{json}->{date_format} ||= DATE_FORMAT_ISO_8601;
Expand All @@ -116,7 +115,7 @@ sub Parse {
bless $self, $klass;

croak "consent string is not tcf version @{[ TCF_VERSION ]}"
unless $self->version == TCF_VERSION;
if $strict && $self->version != TCF_VERSION;

croak 'invalid vendor list version' if $self->vendor_list_version == 0;

Expand Down Expand Up @@ -534,7 +533,14 @@ sub _validate_and_decode_base64 {
\z
}x;

return _decode_base64url($s);
my $data = unpack 'B*', _decode_base64url($s);
my $data_size = length($data);

croak
"vendor consent strings are at least @{[ TCF_V2_MIN_BYTE_SIZE ]} bytes long"
if $data_size < 8 * TCF_V2_MIN_BYTE_SIZE;

return ( $data, $data_size );
}

sub _decode_base64url {
Expand Down Expand Up @@ -714,9 +720,10 @@ or
boolean_values => [ 0, 1 ],
date_format => '%Y%m%d', # yyymmdd
},
strict => 1,
);
Parse may receive an optional hash parameter C<json> with the following properties:
Parse may receive an optional hash of parameters: C<strict> (boolean) and C<json> (hashref with the following properties):
=over
Expand Down Expand Up @@ -750,6 +757,10 @@ except if the option C<use_epoch> is true.
=back
On C<strict> mode we will validate if the version of the consent string is the version 2 (or die with an exception).
The C<strict> mode is disabled by default.
=head1 METHODS
=head2 tc_string
Expand Down
24 changes: 20 additions & 4 deletions t/01-parse.t
Original file line number Diff line number Diff line change
Expand Up @@ -389,25 +389,41 @@ subtest "invalid tcf consent string candidates" => sub {
}
qr/missing gdpr consent string/, 'empty consent string should throw error';

lives_ok {
my $consent = GDPR::IAB::TCFv2->Parse(
"BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASAAAAAAAAAA");

is $consent->version, 1, "tcf v1";

}
'valid tcf v1 consent string should now throw error without strict flag';

throws_ok {
GDPR::IAB::TCFv2->Parse(
"BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASAAAAAAAAAA");
"BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASAAAAAAAAAA", strict => 1 );
}
qr/consent string is not tcf version 2/,
'valid tcf v1 consent string should throw error (deprecated)';
'valid tcf v1 consent string should throw error with strict flag';

throws_ok {
GDPR::IAB::TCFv2->Parse("Clc");
}
qr/vendor consent strings are at least 29 bytes long/,
'short (less than 29 bytes) tcf v2 consent string should throw error';

lives_ok {
my $consent = GDPR::IAB::TCFv2->Parse(
"DOEFEAyOEFEAyAHABDENAI4AAAB9vABAASAAAAAAAAAA", strict => 0 );
is $consent->version, 3, "tcf v3";
}
'possible tcf v3 consent string should not throw error without strict flag';

throws_ok {
GDPR::IAB::TCFv2->Parse(
"DOEFEAyOEFEAyAHABDENAI4AAAB9vABAASAAAAAAAAAA");
"DOEFEAyOEFEAyAHABDENAI4AAAB9vABAASAAAAAAAAAA", strict => 1 );
}
qr/consent string is not tcf version 2/,
'possible tcf v3 consent string should throw error';
'possible tcf v3 consent string should throw error with strict flag';

throws_ok {
GDPR::IAB::TCFv2->Parse(
Expand Down

0 comments on commit 783c8fd

Please sign in to comment.