NAME

GDPR::IAB::TCFv2::CMPValidator - IAB Registry-based Consent Management Platform validation

SYNOPSIS

use GDPR::IAB::TCFv2::CMPValidator;

# Load from a local snapshot of the IAB CMP registry JSON
my $cmp_v = GDPR::IAB::TCFv2::CMPValidator->new(
    file => '/path/to/cmp-list.json',
);

if ( $cmp_v->is_valid(21) ) {
    print "CMP 21 exists and has not been retired\n";
}

# Compose with the main validator
use GDPR::IAB::TCFv2::Validator;

my $validator = GDPR::IAB::TCFv2::Validator->new(
    vendor_id     => 284,
    cmp_validator => $cmp_v,
);

my $result = $validator->validate($tc_string);
warn "compliance failed: $result\n" unless $result;

DESCRIPTION

GDPR::IAB::TCFv2::CMPValidator validates the cmp_id embedded in a TC string against a snapshot of the IAB TCF CMP registry. A registered CMP that has been retired (the JSON record carries a deletedDate in the past) is treated as invalid.

This module does not refresh the registry on its own. The caller is responsible for periodically downloading a fresh copy of https://cmplist.consensu.org/v2/cmp-list.json (or wherever the IAB publishes the current registry) and pointing this validator at it.

NETWORK FETCH IS OPT-IN

The url form does not fetch by default. A library that silently dials out over the network on construction is a footgun -- it traps on blocked egress, surprises operators with latency, and broadens the supply-chain surface. To enable, pass network_ok => 1 alongside url:

GDPR::IAB::TCFv2::CMPValidator->new(
    url        => 'https://cmplist.consensu.org/v2/cmp-list.json',
    network_ok => 1,
);

Without network_ok, passing url croaks with a message pointing the caller at file => ... / data => ... instead.

CONSTRUCTOR

new

my $v = GDPR::IAB::TCFv2::CMPValidator->new( %args );

Recognized keys:

  • file -- path to a local JSON file in the IAB CMP-list shape. Read synchronously via load_from_file.

  • data -- raw JSON text in the same shape. Parsed via load_from_data.

  • url -- HTTP(S) URL of the registry. Requires network_ok => 1 to actually fetch (see "NETWORK FETCH IS OPT-IN"). Uses HTTP::Tiny when allowed; croaks if the module is not installed.

  • network_ok -- boolean. Without it, the url path croaks rather than dialing out.

  • verify_ssl -- boolean, default 1. Convenience option for the default HTTP::Tiny client: when true, server certificates are verified. Disable only when targeting a CMP server with a self-signed or otherwise non-public-CA certificate. Mutually exclusive with http_client (configure SSL on the injected client itself).

  • timeout -- integer seconds, default 30. Convenience option for the default HTTP::Tiny client. Mutually exclusive with http_client.

  • http_client -- a pre-built object that responds to ->get($url) in the HTTP::Tiny-compatible shape (see "INJECTING AN HTTP CLIENT"). When provided, the validator uses this object verbatim and does not construct its own HTTP::Tiny; the verify_ssl and timeout options are not accepted in this case (passing either alongside http_client croaks).

  • now -- test only. Override the wall clock used for deletedDate comparisons and the 28-day staleness check (e.g. now => 1776254400 pins comparisons to 2026-04-15). Production code should leave this unset; the validator reads the real wall clock by default.

METHODS

is_valid

my $ok = $v->is_valid($cmp_id);

Returns true when the registry knows about $cmp_id and the entry either carries no deletedDate or its deletedDate is still in the future relative to "now".

last_updated_epoch

Returns the registry's lastUpdated timestamp as a Unix epoch, or undef when the field is absent or unparseable.

load_from_file($path)

Drop-in load that re-reads the registry from $path. Useful when the file has been refreshed out-of-band.

load_from_data($json_text)

Re-load from a raw JSON string.

load_from_url($url)

Fetch and load from $url. Bypasses the network_ok gate -- the intent is that the caller has already validated they want to make a network call. Uses the http_client passed to the constructor when present; otherwise constructs a default HTTP::Tiny with env_proxy => 1, verify_SSL from verify_ssl, and timeout from timeout.

NETWORK PROXIES

When load_from_url uses the default HTTP::Tiny client (i.e. no http_client was injected), the standard HTTP-proxy environment variables are honored automatically:

  • https_proxy -- proxy for https:// URLs.

  • http_proxy -- proxy for http:// URLs.

  • all_proxy -- fallback for both.

  • no_proxy -- comma-separated host/domain patterns to bypass (e.g. localhost,*.internal).

Lowercase names are the canonical form. HTTP::Tiny accepts uppercase as well, but the lowercase variants are preferred (some hardened environments treat the uppercase form as a security risk because of historical CGI injection bugs).

When an injected http_client is used, this module does no proxy configuration of its own: configure the client however you need before handing it in.

INJECTING AN HTTP CLIENT

For test fakes, custom CA bundles, signed-request middleware, or any other case the convenience options do not cover, hand the validator a pre-built object via http_client:

package FakeHttp;
sub new { bless { responses => $_[1] }, $_[0] }
sub get { my $self = shift; shift @{ $self->{responses} } }

my $cmp_v = GDPR::IAB::TCFv2::CMPValidator->new(
    url         => 'https://does-not-matter.example/',
    network_ok  => 1,
    http_client => FakeHttp->new( [
        { success => 1, content => '{"cmps": {"7": {"id": 7}}}' },
    ] ),
);

The injected object must be a blessed reference that responds to a ->get($url) method returning a hashref in the HTTP::Tiny shape: at minimum, success (boolean), content (response body on success), and reason (error text on failure). The constructor verifies the object is blessed and "can" in UNIVERSAL a get method, so AUTOLOAD-using classes must override can to advertise their methods (the standard Perl convention).

STALE DATA WARNING

When the registry's lastUpdated is older than 28 days (relative to "now"), the constructor emits a warning via Carp::carp. Suppress with a local $SIG{__WARN__} if your audit pipeline does not benefit from it.

SEE ALSO

GDPR::IAB::TCFv2::Validator for the rule engine that composes this class as the cmp_validator rule.