GDPR-IAB-TCFv2

 view release on metacpan or  search on metacpan

bin/iabtcfv2  view on Meta::CPAN

      ['-w', '--enable-warnings',              '',              'Emit human-readable warnings on STDERR'],
      ['-q', '--quiet',                        '',              'Suppress STDOUT (exit code only)'],
    ],
  },
);

my %global_opts;
GetOptions(
  'help'      => \$global_opts{full_help},
  'h'         => \$global_opts{short_help},
  'man'       => \$global_opts{man},
  'version|V' => \$global_opts{version},
) or pod2usage(-input => $script_path, -exitval => 2, -verbose => 0);

if ($global_opts{version}) {
  print "iabtcfv2 version $GDPR::IAB::TCFv2::VERSION\n";
  exit EXIT_SUCCESS;
}

if ($global_opts{short_help}) {
  _show_short_help($ARGV[0]);
}
if ($global_opts{full_help}) {
  _show_help($ARGV[0]);
}
pod2usage(-input => $script_path, -exitval => 1, -verbose => 2) if $global_opts{man};

my $subcommand = shift @ARGV;

# Bare invocation: brief overview, exit 1 (mirrors `--help` behavior).
_show_short_help() unless defined $subcommand;

# `iabtcfv2 help [<sub>]` keeps showing the full POD, same as before.
if ($subcommand eq 'help') {
  _show_help(shift @ARGV);
}

my $entry = $SUBCOMMANDS{$subcommand};
_unknown_subcommand($subcommand) unless $entry;
$entry->{runner}->(@ARGV);

sub run_dump {
  my @args = @_;
  my %opts = (
    pretty               => 0,
    compact              => 0,
    'ignore-errors'      => 0,
    'fail-fast'          => 0,
    'errors-to-stderr'   => 0,
    'quiet'              => 0,
    'enable-warnings'    => 0,
    'vendor-id'          => undef,
    'strict-legal-basis' => 0,
  );

  require Getopt::Long;
  my $parser = Getopt::Long::Parser->new(config => [qw(no_pass_through require_order bundling)]);

  my $getopt_ok;
  {
    local @ARGV = @args;
    $getopt_ok = $parser->getoptions(
      'pretty|p'             => \$opts{pretty},
      'compact|c'            => \$opts{compact},
      'ignore-errors|i'      => \$opts{'ignore-errors'},
      'fail-fast|f'          => \$opts{'fail-fast'},
      'errors-to-stderr|e'   => \$opts{'errors-to-stderr'},
      'quiet|q'              => \$opts{'quiet'},
      'enable-warnings|w'    => \$opts{'enable-warnings'},
      'vendor-id|v=i'        => \$opts{'vendor-id'},
      'strict-legal-basis|s' => \$opts{'strict-legal-basis'},
      'help'                 => sub {
        pod2usage(-input => $script_path, -exitval => 1, -verbose => 99, -sections => "DUMP|BUGS");
      },
      'h' => sub { _show_subcommand_short_help('dump'); exit 1; },
    );
    @args = @ARGV;
  }
  $getopt_ok or pod2usage(-input => $script_path, -exitval => 2, -verbose => 99, -sections => "DUMP/Usage");

  my $json_pkg = JSON->can('new') ? 'JSON' : 'JSON::PP';
  my $json     = $json_pkg->new->utf8;
  if ($opts{pretty}) {
    $json->pretty(1);
    $json->indent_length(4) if $json->isa('JSON::PP');
  }

  my $state = {count => 0, line_num => 0,};

  if (@args) {
    foreach my $str (@args) {
      $state->{line_num}++;
      _process_string($str, $state, \%opts, $json);
    }
  }
  else {
    binmode(STDIN, ':encoding(UTF-8)') if -t STDIN;    ## no critic (InputOutput::ProhibitInteractiveTest, InputOutput::RequireEncodingWithUTF8Layer)
    while (my $line = <STDIN>) {                       ## no critic (InputOutput::ProhibitExplicitStdin)
      $state->{line_num}++;
      chomp $line;
      next unless $line =~ /\S/;
      _process_string($line, $state, \%opts, $json);
    }
  }

  exit EXIT_SUCCESS;
}

sub _process_string {
  my ($str, $state, $o, $j) = @_;
  my $output_data;

  eval {
    my $tcf = GDPR::IAB::TCFv2->Parse(
      $str,
      json   => {compact => $o->{compact}, vendor_id => $o->{'vendor-id'},},
      strict => $o->{'strict-legal-basis'},
    );
    $output_data = $tcf->TO_JSON;
  };
  if (my $err = $@) {

bin/iabtcfv2  view on Meta::CPAN

    $left_width = length($left_col) if length($left_col) > $left_width;
    push @lines, [$left_col, $desc];
  }

  for my $r (@lines) {
    printf {*STDERR} "%-${left_width}s  %s\n", $r->[0], $r->[1];
  }

  print {*STDERR} "\nReads TC strings from positional args, or one per line from STDIN.\n";
  print {*STDERR} "\nRun 'iabtcfv2 $name --help' for the full documentation.\n";
}

sub _unknown_subcommand {
  my $name = shift;

  print {*STDERR} "iabtcfv2: unknown subcommand '$name'\n\n";
  print {*STDERR} "Available subcommands:\n";
  for my $sc (sort keys %SUBCOMMANDS) {
    printf {*STDERR} "    %-10s %s\n", $sc, $SUBCOMMANDS{$sc}{summary};
  }
  print {*STDERR} "\n";
  print {*STDERR} "Run 'iabtcfv2 -h' for a short overview, or 'iabtcfv2 --help' for the full manual.\n";
  exit 2;
}

sub _parse_id_list {
  my $s = shift;
  return [] unless defined $s && length $s;
  return [map { 0 + $_ } grep { length $_ } split /\s*,\s*/, $s];
}

sub run_validate {    ## no critic (Subroutines::ProhibitExcessComplexity)
  my @args = @_;
  my %opts = (
    pretty                         => 0,
    'ignore-errors'                => 0,
    'fail-fast'                    => 0,
    'errors-to-stderr'             => 0,
    quiet                          => 0,
    'enable-warnings'              => 0,
    'vendor-id'                    => undef,
    'consent-purposes'             => undef,
    'legitimate-interest-purposes' => undef,
    'flexible-purposes'            => undef,
    'verify-disclosed-vendors'     => 0,
    'strict-legal-basis'           => 0,
    'min-tcf-policy-version'       => undef,
    'cmp-validator'                => undef,
    'cmp-validator-network-ok'     => 0,
    'cmp-validator-verify-ssl'     => 1,
    'cmp-validator-timeout'        => 30,
    all                            => 0,
    text                           => 0,
  );

  require Getopt::Long;
  my $parser = Getopt::Long::Parser->new(config => [qw(no_pass_through require_order bundling)]);

  my $getopt_ok;
  {
    local @ARGV = @args;
    $getopt_ok = $parser->getoptions(
      'pretty|p'                         => \$opts{pretty},
      'ignore-errors|i'                  => \$opts{'ignore-errors'},
      'fail-fast|f'                      => \$opts{'fail-fast'},
      'errors-to-stderr|e'               => \$opts{'errors-to-stderr'},
      'quiet|q'                          => \$opts{quiet},
      'enable-warnings|w'                => \$opts{'enable-warnings'},
      'vendor-id|v=i'                    => \$opts{'vendor-id'},
      'consent-purposes|C=s'             => \$opts{'consent-purposes'},
      'legitimate-interest-purposes|L=s' => \$opts{'legitimate-interest-purposes'},
      'flexible-purposes|F=s'            => \$opts{'flexible-purposes'},
      'verify-disclosed-vendors|d'       => \$opts{'verify-disclosed-vendors'},
      'strict-legal-basis|s'             => \$opts{'strict-legal-basis'},
      'min-tcf-policy-version|m=i'       => \$opts{'min-tcf-policy-version'},
      'cmp-validator=s'                  => \$opts{'cmp-validator'},
      'cmp-validator-network-ok'         => \$opts{'cmp-validator-network-ok'},
      'cmp-validator-verify-ssl!'        => \$opts{'cmp-validator-verify-ssl'},
      'cmp-validator-timeout=i'          => \$opts{'cmp-validator-timeout'},
      'all|a'                            => \$opts{all},
      'text|t'                           => \$opts{text},
      'help'                             => sub {
        pod2usage(-input => $script_path, -exitval => 1, -verbose => 99, -sections => "VALIDATE|BUGS");
      },
      'h' => sub { _show_subcommand_short_help('validate'); exit 1; },
    );
    @args = @ARGV;
  }
  $getopt_ok or pod2usage(-input => $script_path, -exitval => 2, -verbose => 99, -sections => "VALIDATE/Usage");

  unless (defined $opts{'vendor-id'}) {
    pod2usage(
      -input    => $script_path,
      -exitval  => 2,
      -message  => "validate: --vendor-id|-v is required",
      -verbose  => 99,
      -sections => "VALIDATE/Usage"
    );
  }

  require GDPR::IAB::TCFv2::Validator;

  my %vargs = (
    vendor_id                => $opts{'vendor-id'},
    verify_disclosed_vendors => $opts{'verify-disclosed-vendors'},
    strict_legal_basis       => $opts{'strict-legal-basis'},
  );
  $vargs{consent_purpose_ids} = _parse_id_list($opts{'consent-purposes'}) if defined $opts{'consent-purposes'};
  $vargs{legitimate_interest_purpose_ids} = _parse_id_list($opts{'legitimate-interest-purposes'})
    if defined $opts{'legitimate-interest-purposes'};
  $vargs{flexible_purpose_ids}   = _parse_id_list($opts{'flexible-purposes'}) if defined $opts{'flexible-purposes'};
  $vargs{min_tcf_policy_version} = $opts{'min-tcf-policy-version'} if defined $opts{'min-tcf-policy-version'};

  if (defined $opts{'cmp-validator'}) {
    require GDPR::IAB::TCFv2::CMPValidator;

    my $src      = $opts{'cmp-validator'};
    my %cmp_args = (verify_ssl => $opts{'cmp-validator-verify-ssl'}, timeout => $opts{'cmp-validator-timeout'},);

    if ($src =~ m{^https?://}i) {
      $cmp_args{url}        = $src;



( run in 1.627 second using v1.01-cache-2.11-cpan-b9db842bd85 )