

use Test::More 'no_plan';
use strict;
$ENV{CGI_APP_RETURN_ONLY} = 1;

{
    package WebApp;
    use CGI::Application;
    use vars qw(@ISA);
    use URI;
    BEGIN { @ISA = ('CGI::Application'); }

    use Test::More;
    use CGI::Application::Plugin::LinkIntegrity;

    sub setup {
        my $self = shift;
        $self->run_modes([qw/start/]);

        $self->link_integrity_config(
            'secret'           => 'foo',
            'disable'          => 1,
        );

    }

    sub start {
        my $self = shift;

        # Test that the checksum actually is generated.  Using a known
        # method ('Digest::MD5') independently verify the checksum
        # checking it against the one generated by CAP::LI

        my $secret = 'some super secret';

        $self->link_integrity_config(
            'secret'          => $secret,
            'digest_module'   => 'Digest::MD5',
            'additional_data' => '12345',
        );

        my $uri = '/foo/bar/baz?one=foo&two=boom';
        my $link = $self->make_link($uri);

        my $hmac = Digest::HMAC->new($secret, 'Digest::MD5');

        my $u = URI->new($uri, 'http');
        $hmac->add($u->scheme      || '');
        $hmac->add($u->authority   || '');
        $hmac->add($u->port        || '');
        $hmac->add($u->path        || '');

        foreach my $key (sort $u->query_param) {
            $hmac->add('key');
            $hmac->add($key);
            $hmac->add('values');
            foreach my $val (sort $u->query_param($key)) {
                $hmac->add($val);
            }
        }

        $hmac->add('12345'); # additional_data;

        my $checksum = $hmac->hexdigest;

        my %params = $link->query_form;

        ok(keys %params == 3,                '[_checksum] param keys');
        is($params{'one'}, 'foo',            '[_checksum] param "one"');
        is($params{'two'}, 'boom',           '[_checksum] param "two"');
        is($params{'_checksum'}, $checksum,  '[_checksum] param "_checksum"');


        # Same test as above, except using a different parameter than
        # checksum, and also checking that Digest::MD5 is the default

        $secret = 'again with the secrets';

        $self->link_integrity_config(
            'secret'         => $secret,
            'checksum_param' => '??_link_guardian__??',
            'additional_data' => '54321',
        );

        $uri = '/foo/bar/baz?one=foo&two=boom';
        $link = $self->make_link($uri);

        $hmac = Digest::HMAC->new($secret, 'Digest::MD5');

        $u = URI->new($uri, 'http');
        $hmac->add($u->scheme     || '');
        $hmac->add($u->authority  || '');
        $hmac->add($u->port       || '');
        $hmac->add($u->path       || '');
        foreach my $key (sort $u->query_param) {
            $hmac->add('key');
            $hmac->add($key);
            $hmac->add('values');
            foreach my $val (sort $u->query_param($key)) {
                $hmac->add($val);
            }
        }
        $hmac->add('54321'); # additional_data;

        $checksum = $hmac->hexdigest;


        %params = $link->query_form;

        ok(keys %params == 3,                           '[??_link_guardian__??] param keys');
        is($params{'one'}, 'foo',                       '[??_link_guardian__??] param "one"');
        is($params{'two'}, 'boom',                      '[??_link_guardian__??] param "two"');
        is($params{'??_link_guardian__??'}, $checksum,  '[??_link_guardian__??] param "??_link_guardian__??"');



        # Same test but with SHA1 (if available)
        SKIP: {
            eval {
                require Digest::SHA1;
            };

            skip 'Digest::SHA1 not installed', 3 if $@;

            $secret = 'even secreter';

            $self->link_integrity_config(
                'secret'          => $secret,
                'digest_module'   => 'Digest::SHA1',
                'additional_data' => 'abcde',
            );

            $uri = '/foo/bar/baz?one=foo&two=boom';
            $link = $self->make_link($uri);

            $hmac = Digest::HMAC->new($secret, 'Digest::SHA1');

            $u = URI->new($uri, 'http');
            $hmac->add($u->scheme     || '');
            $hmac->add($u->authority  || '');
            $hmac->add($u->port       || '');
            $hmac->add($u->path       || '');
            foreach my $key (sort $u->query_param) {
                $hmac->add('key');
                $hmac->add($key);
                $hmac->add('values');
                foreach my $val (sort $u->query_param($key)) {
                    $hmac->add($val);
                }
            }
            $hmac->add('abcde'); # additional_data;

            $checksum = $hmac->hexdigest;

            %params = $link->query_form;

            ok(keys %params == 3,                '[(SHA1)_checksum] param keys');
            is($params{'one'}, 'foo',            '[(SHA1)_checksum] param "one"');
            is($params{'two'}, 'boom',           '[(SHA1)_checksum] param "two"');
            is($params{'_checksum'}, $checksum,  '[(SHA1)_checksum] param "_checksum"');
        }


        # Now use a custom checksum_generator

        $secret = '_X_';

        $self->link_integrity_config(
            'secret'             => $secret,
            'additional_data'    => 'edcba',
            'checksum_generator' => sub {
                my ($secret, $uri, $additional_data) = @_;
                my @words = split /\W/, $uri->as_string;
                return (join $secret, @words) . '|' . $additional_data;
            }
        );

        $uri = '/foo/bar/baz?one=foo&two=boom';
        $link = $self->make_link($uri);

        $checksum = '_X_foo_X_bar_X_baz_X_one_X_foo_X_two_X_boom|edcba';

        %params = $link->query_form;

        ok(keys %params == 3,                '[checksum_generator] param keys');
        is($params{'one'}, 'foo',            '[checksum_generator] param "one"');
        is($params{'two'}, 'boom',           '[checksum_generator] param "two"');
        is($params{'_checksum'}, $checksum,  '[checksum_generator] param "_checksum"');


    }
}


WebApp->new->run;






