use strict; use warnings; use utf8; use Encode; use Test::More; # see done_testing() use_ok( 'Zonemaster::Backend::DB' ); sub encode_and_fingerprint { my $params = shift; my $self = "Zonemaster::Backend::DB"; my $encoded_params = $self->encode_params( $params ); my $fingerprint = $self->generate_fingerprint( $params ); return ( $encoded_params, $fingerprint ); } subtest 'encoding and fingerprint' => sub { subtest 'missing properties' => sub { my %params = ( domain => "example.com" ); my $expected_encoded_params = '{"domain":"example.com","ds_info":[],"ipv4":null,"ipv6":null,"nameservers":[],"profile":"default"}'; my ( $encoded_params, $fingerprint ) = encode_and_fingerprint( \%params ); is $encoded_params, $expected_encoded_params, 'domain only: the encoded strings should match'; #diag ($fingerprint); my $expected_encoded_params_v4_true = '{"domain":"example.com","ds_info":[],"ipv4":true,"ipv6":null,"nameservers":[],"profile":"default"}'; $params{ipv4} = JSON::PP->true; my ( $encoded_params_ipv4, $fingerprint_ipv4 ) = encode_and_fingerprint( \%params ); is $encoded_params_ipv4, $expected_encoded_params_v4_true, 'add ipv4: the encoded strings should match'; isnt $fingerprint_ipv4, $fingerprint, 'fingerprints should not match'; }; subtest 'array properties' => sub { subtest 'ds_info' => sub { my %params1 = ( domain => "example.com", ds_info => [{ algorithm => 8, keytag => 11627, digtype => 2, digest => "a6cca9e6027ecc80ba0f6d747923127f1d69005fe4f0ec0461bd633482595448" }] ); my %params2 = ( ds_info => [{ digtype => 2, algorithm => 8, keytag => 11627, digest => "a6cca9e6027ecc80ba0f6d747923127f1d69005fe4f0ec0461bd633482595448" }], domain => "example.com" ); my ( $encoded_params1, $fingerprint1 ) = encode_and_fingerprint( \%params1 ); my ( $encoded_params2, $fingerprint2 ) = encode_and_fingerprint( \%params2 ); is $fingerprint1, $fingerprint2, 'ds_info same fingerprint'; is $encoded_params1, $encoded_params2, 'ds_info same encoded string'; }; subtest 'nameservers order' => sub { my %params1 = ( domain => "example.com", nameservers => [ { ns => "ns2.nic.fr", ip => "192.134.4.1" }, { ns => "ns1.nic.fr" }, { ip => "192.0.2.1", ns => "ns3.nic.fr"} ] ); my %params2 = ( nameservers => [ { ns => "ns3.nic.fr", ip => "192.0.2.1" }, { ns => "ns1.nic.fr" }, { ip => "192.134.4.1", ns => "ns2.nic.fr"} ], domain => "example.com" ); my %params3 = ( domain => "example.com", nameservers => [ { ip => "", ns => "ns1.nic.fr" }, { ns => "ns3.nic.FR", ip => "192.0.2.1" }, { ns => "ns2.nic.fr", ip => "192.134.4.1" } ] ); my %params4 = ( domain => "example.com", nameservers => [ { ip => "192.134.4.1", ns => "nS2.Nic.FR"}, { ns => "Ns1.nIC.fR", ip => "" }, { ns => "ns3.nic.fr", ip => "192.0.2.1" } ] ); my ( $encoded_params1, $fingerprint1 ) = encode_and_fingerprint( \%params1 ); my ( $encoded_params2, $fingerprint2 ) = encode_and_fingerprint( \%params2 ); my ( $encoded_params3, $fingerprint3 ) = encode_and_fingerprint( \%params3 ); my ( $encoded_params4, $fingerprint4 ) = encode_and_fingerprint( \%params4 ); is $fingerprint1, $fingerprint2, 'nameservers: same fingerprint'; is $encoded_params1, $encoded_params2, 'nameservers: same encoded string'; is $fingerprint1, $fingerprint3, 'nameservers: same fingerprint (empty ip)'; is $encoded_params1, $encoded_params3, 'nameservers: same encoded string (empty ip)'; is $fingerprint1, $fingerprint4, 'nameservers: same fingerprint (ignore nameservers\' ns case)'; is $encoded_params1, $encoded_params4, 'nameservers: same encoded string (ignore nameservers\' ns case)'; }; }; subtest 'should be case insensitive' => sub { my %params1 = ( domain => "example.com" ); my %params2 = ( domain => "eXamPLe.COm" ); my ( $encoded_params1, $fingerprint1 ) = encode_and_fingerprint( \%params1 ); my ( $encoded_params2, $fingerprint2 ) = encode_and_fingerprint( \%params2 ); is $fingerprint1, $fingerprint2, 'same fingerprint'; is $encoded_params1, $encoded_params2, 'same encoded string'; }; subtest 'garbage properties set' => sub { my $expected_encoded_params = '{"client":"GUI v3.3.0","domain":"example.com","ds_info":[],"ipv4":null,"ipv6":null,"nameservers":[],"profile":"default"}'; my %params1 = ( domain => "example.com", ); my %params2 = ( domain => "example.com", client => "GUI v3.3.0" ); my ( $encoded_params1, $fingerprint1 ) = encode_and_fingerprint( \%params1 ); my ( $encoded_params2, $fingerprint2 ) = encode_and_fingerprint( \%params2 ); is $fingerprint1, $fingerprint2, 'leave out garbage property in fingerprint computation...'; is $encoded_params2, $expected_encoded_params, '...but keep it in the encoded string'; }; subtest 'should have different fingerprints' => sub { subtest 'different profiles' => sub { my %params1 = ( domain => "example.com", profile => "profile_1" ); my %params2 = ( domain => "example.com", profile => "profile_2" ); my ( undef, $fingerprint1 ) = encode_and_fingerprint( \%params1 ); my ( undef, $fingerprint2 ) = encode_and_fingerprint( \%params2 ); isnt $fingerprint1, $fingerprint2, 'different profiles, different fingerprints'; }; subtest 'different IP protocols' => sub { my %params1 = ( domain => "example.com", ipv4 => "true", ipv6 => "false" ); my %params2 = ( domain => "example.com", ipv4 => "false", ipv6 => "true" ); my ( undef, $fingerprint1 ) = encode_and_fingerprint( \%params1 ); my ( undef, $fingerprint2 ) = encode_and_fingerprint( \%params2 ); isnt $fingerprint1, $fingerprint2, 'different IP protocols, different fingerprints'; }; }; subtest 'IDN domain' => sub { my $expected_encoded_params = encode_utf8( '{"domain":"xn--caf-dma.example","ds_info":[],"ipv4":true,"ipv6":true,"nameservers":[],"profile":"default"}' ); my $expected_fingerprint = '8cb027ff2c175f48aed2623abad0cdd2'; my %params = ( domain => "café.example" ); $params{ipv4} = JSON::PP->true; $params{ipv6} = JSON::PP->true; my ( $encoded_params, $fingerprint ) = encode_and_fingerprint( \%params ); is $encoded_params, $expected_encoded_params, 'IDN domain: the encoded strings should match'; is $fingerprint, $expected_fingerprint, 'IDN domain: correct fingerprint'; }; subtest 'final dots' => sub { subtest 'in domain' => sub { my %params1 = ( domain => "example.com" ); my %params2 = ( domain => "example.com." ); my $expected_encoded_params = encode_utf8( '{"domain":"example.com","ds_info":[],"ipv4":null,"ipv6":null,"nameservers":[],"profile":"default"}' ); my ( $encoded_params1, $fingerprint1 ) = encode_and_fingerprint( \%params1 ); my ( $encoded_params2, $fingerprint2 ) = encode_and_fingerprint( \%params2 ); is $fingerprint1, $fingerprint2, 'same fingerprint'; is $encoded_params1, $expected_encoded_params, 'the encoded strings should match'; }; subtest 'in nameserver' => sub { my %params1 = ( domain => "example.com", nameservers => [ { ns => "ns1.example.com." } ] ); my %params2 = ( domain => "example.com", nameservers => [ { ns => "ns1.example.com" } ] ); my $expected_encoded_params = encode_utf8( '{"domain":"example.com","ds_info":[],"ipv4":null,"ipv6":null,"nameservers":[{"ns":"ns1.example.com"}],"profile":"default"}' ); my ( $encoded_params1, $fingerprint1 ) = encode_and_fingerprint( \%params1 ); my ( $encoded_params2, $fingerprint2 ) = encode_and_fingerprint( \%params2 ); is $fingerprint1, $fingerprint2, 'same fingerprint'; is $encoded_params1, $expected_encoded_params, 'the encoded strings should match'; }; subtest 'root is not modified' => sub { my %params = ( domain => "." ); my $expected_encoded_params = encode_utf8( '{"domain":".","ds_info":[],"ipv4":null,"ipv6":null,"nameservers":[],"profile":"default"}' ); my ( $encoded_params, $fingerprint ) = encode_and_fingerprint( \%params ); is $encoded_params, $expected_encoded_params, 'the encoded strings should match'; }; }; }; done_testing();