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 viaload_from_file.data-- raw JSON text in the same shape. Parsed viaload_from_data.url-- HTTP(S) URL of the registry. Requiresnetwork_ok => 1to 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, theurlpath croaks rather than dialing out.verify_ssl-- boolean, default1. 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 withhttp_client(configure SSL on the injected client itself).timeout-- integer seconds, default30. Convenience option for the default HTTP::Tiny client. Mutually exclusive withhttp_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; theverify_sslandtimeoutoptions are not accepted in this case (passing either alongsidehttp_clientcroaks).now-- test only. Override the wall clock used fordeletedDatecomparisons and the 28-day staleness check (e.g.now => 1776254400pins 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 forhttps://URLs.http_proxy-- proxy forhttp://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.