Cookie

 view release on metacpan or  search on metacpan

t/004_cookies.t  view on Meta::CPAN

    my $token = q{eyJleHAiOjE2MzYwNzEwMzksImFsZyI6IkhTMjU2In0.eyJqdGkiOiJkMDg2Zjk0OS1mYWJmLTRiMzgtOTE1ZC1hMDJkNzM0Y2ZmNzAiLCJmaXJzdF9uYW1lIjoiSm9obiIsImlhdCI6MTYzNTk4NDYzOSwiYXpwIjoiNGQ0YWFiYWQtYmJiMy00ODgwLThlM2ItNTA0OWMwZTczNjBlIiwiaXNzIjoiaHR0cHM6...
    # For double authentication cookie scheme for example
    # See: <https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie>
    my $csrf = q{9849724969dbcffd48c074b894c8fbda14610dc0ae62fac0f78b2aa091216e0b.1635825594};
    my $rv;
    my $session_cookie = $srv->make( name => 'session_token' => value => $token, path => '/', expires => "Monday, 01-Nov-2021 17:12:40 GMT" ) ||
    do
    {
        diag( "Unable to create cookie session_token: ", $srv->error ) if( $DEBUG );
    };
    
    # $resp->header( 'Set-Cookie' => qq{session_token=${token}; path=/ ; expires=Monday, 01-Nov-2021 17:12:40 GMT} );
    $rv = $srv->set( $session_cookie, response => $resp ) || do
    {
        diag( "set returned an error: ", $srv->error ) if( $DEBUG );
    };
    $rv = $jar->extract( $resp ) || do
    {
        diag( "extract returned an error: ", $jar->error ) if( $DEBUG );
    };
    $rv = $jar->add_request_header( $req );
    if( !defined( $rv ) )
    {
        diag( "add_request_header returned an error: ", $jar->error ) if( $DEBUG );
    }
    ok( $rv, 'add_request_header' );
    is( $req->header( 'Cookie' ), "session_token=$token" );
    
    $req = HTTP::Request->new( GET => 'https://www.example.com/' );
    $req->header( Host => 'www.example.com' );
    $resp = HTTP::Response->new( 200 => 'OK' );
    $resp->request( $req );
    my $csrf_cookie = $srv->make( name => 'csrf_token', value => $csrf, path => '/' ) || do
    {
        diag( "Unable to create cookie: ", $srv->error ) if( $DEBUG );
    };
    # $resp->header( 'Set-Cookie' => qq{csrf_token=${csrf}; path=/} );
    $rv = $srv->set( $csrf_cookie, response => $resp ) || do
    {
        diag( "set returned an error: ", $srv->error ) if( $DEBUG );
    };
    $rv = $jar->extract( $resp ) || do
    {
        diag( "extract returned an error: ", $jar->error ) if( $DEBUG );
    };
    
    $req = HTTP::Request->new( GET => 'https://www.example.com/foo/bar' );
    $req->header( Host => 'www.example.com' );
    $rv = $jar->add_request_header( $req );
    if( !defined( $rv ) )
    {
        diag( "add_request_header returned an error: ", $jar->error ) if( $DEBUG );
    }

    my $h = $req->header( 'Cookie' );
    like( $h, qr/session_token=${token}/ );
    like( $h, qr/csrf_token=${csrf}/ );
    
    $resp = HTTP::Response->new( 200 => 'OK' );
    $resp->request( $req );
    # $resp->header( 'Set-Cookie' => qq{site_prefs=lang%3Den-GB; path=/account} );
    my $prefs_cookie = $srv->make( name => 'site_prefs', value => "lang=en-GB", path => '/account' ) || do
    {
        diag( "Unable to add cookie site_prefs: ", $srv->error ) if( $DEBUG );
    };
    $rv = $srv->set( $prefs_cookie, response => $resp ) || do
    {
        diag( "set returned an error: ", $srv->error ) if( $DEBUG );
    };
    $rv = $jar->extract( $resp ) || do
    {
        diag( "extract returned an error: ", $jar->error ) if( $DEBUG );
    };
    
    $req = HTTP::Request->new( GET => 'https://www.example.com/' );
    $req->header( Host => 'www.example.com' );
    $rv = $jar->add_request_header( $req );
    if( !defined( $rv ) )
    {
        diag( "add_request_header returned an error: ", $jar->error ) if( $DEBUG );
    }
    $h = $req->header( 'Cookie' );
    diag( "HTTP request is: ", $req->as_string ) if( $DEBUG );
    like( $h, qr/session_token=${token}/ );
    like( $h, qr/csrf_token=${csrf}/ );
    unlike( $h, qr/site_prefs=lang%3Den-GB/ );
    
    $req = HTTP::Request->new( GET => 'https://www.example.com/account/images/' );
    $req->header( Host => 'www.example.com' );
    $rv = $jar->add_request_header( $req );
    if( !defined( $rv ) )
    {
        diag( "add_request_header returned an error: ", $jar->error ) if( $DEBUG );
    }
    $h = $req->header( 'Cookie' );
    diag( "HTTP request is: ", $req->as_string ) if( $DEBUG );
    like( $h, qr/session_token=${token}/ );
    like( $h, qr/csrf_token=${csrf}/ );
    like( $h, qr/site_prefs=lang%3Den-GB/ );
    
    # my $csrf_cookie = $jar->make( name => 'csrf_token', path => '/' )->elapse;
    $rv = $srv->fetch( request => $req ) || do
    {
        diag( "fetch returned an error: ", $srv->error ) if( $DEBUG );
    };
    $csrf_cookie = $srv->get( csrf_token => 'example.com' );
    ok( $csrf_cookie );
    if( !defined( $csrf_cookie ) )
    {
        diag( "Cannot find cookie name 'csrf_token' with host 'example.com': ", $srv->error );
    }
    $resp = HTTP::Response->new( 200 => 'OK' );
    SKIP:
    {
        if( !defined( $csrf_cookie ) )
        {
            skip( "Cannot find cookie \"csrf_cookie\".", 3 );
        }
        $csrf_cookie->elapse;
        diag( "Setting cookie csrf_token to expire: ", $csrf_cookie->as_string ) if( $DEBUG );
        # Set the Set-Cookie header fields
        $rv = $srv->set( $csrf_cookie, response => $resp ) || do
        {
            diag( "set returned an error: ", $srv->error ) if( $DEBUG );
        };
        diag( "Response header is now: ", $resp->as_string ) if( $DEBUG );
        $req = HTTP::Request->new( GET => 'https://www.example.com/account/' );
        $req->header( Host => 'www.example.com' );
        $resp->request( $req );
        # Extract them
        $rv = $jar->extract( $resp ) || do
        {
            diag( "extract returned an error: ", $jar->error ) if( $DEBUG );
        };
        # Add them back to the client request object
        $rv = $jar->add_request_header( $req );
        if( !defined( $rv ) )
        {
            diag( "add_request_header returned an error: ", $jar->error ) if( $DEBUG );
        }
        $h = $req->header( 'Cookie' );
        like( $h, qr/session_token=${token}/ );
        # should not be here anymore
        unlike( $h, qr/csrf_token=${csrf}/ );
        like( $h, qr/site_prefs=lang%3Den-GB/ );
    };
};

subtest 'extract one cookie' => sub
{
    my $jar = Cookie::Jar->new( debug => $DEBUG );
    my $cookie_str = q{session_token=fe3fc36d-4104-4cd1-8f07-56cb96b2c78b; path=/ ; expires=Monday, 01-Nov-2021 17:12:40 GMT};
    my $co = $jar->extract_one( $cookie_str, { port => 443, host => 'www.example.com' } );
    ok( $co );
    SKIP:
    {
        if( !defined( $co ) )
        {
            skip( "Cannot parse cookie string.", 1 );
        }
        is( $co->name, 'session_token', 'name' );
        is( $co->value, 'fe3fc36d-4104-4cd1-8f07-56cb96b2c78b', 'value' );
        is( $co->path, '/', 'path' );
        is( $co->expires->iso8601, '2021-11-01T17:12:40', 'expires' );
        is( $co->port, 443, 'port' );
        is( $co->domain, 'example.com', 'domain' );
    };
};

subtest 'save and load' => sub
{
    my $jar = Cookie::Jar->new( debug => $DEBUG );
    $jar->add( name => 'cookie1', value => 'value1', path => '/', domain => 'example.com', secure => 1 );
    $jar->add( name => 'cookie2', value => 'value2', path => '/account', domain => 'api.example.com', secure => 1, http_only => 1 );
    $jar->add( name => 'cookie3', value => 'value3', path => '/', domain => 'img.example.com', secure => 1 );
    my $f = $jar->new_file( __FILE__ )->parent->child( 'cookies.json' );
    diag( "Saving to file '$f'" ) if( $DEBUG );
    SKIP:
    {
        $jar->save( $f ) || do
        {
            diag( "Unable to save to file \"$f\": ", $jar->error ) if( $DEBUG );
            skip( "Cannot save file", 9 );
        };
        ok( $f->size > 0, 'Saved json file size' );
        my $repo = Cookie::Jar->new( debug => $DEBUG );
        $repo->load( $f ) || do
        {
            diag( "Unable to load cookies from file \"$f\": ", $repo->error ) if( $DEBUG );
            skip( "Cannot load cookies", 8 );
        };
        ok( $repo->repo->size == $jar->repo->size, 'size' );
        diag( "Checking our cookie names '", $jar->repo->keys->sort->join( ',' ), "' vs the loaded repo ones '", $repo->repo->keys->sort->join( ',' ), "'." ) if( $DEBUG );
        ok( $repo->repo->keys->sort->join( ',' ) eq $jar->repo->keys->sort->join( ',' ), 'cookie names' );
        $jar->do(sub
        {
            my $c = shift( @_ );
            my $alter = $repo->get( $c->name => $c->domain );
            ok( $alter, "equivalent cookie" );
            if( !$alter )
            {
                skip( "Cannot find equivalent cookie \"" . $c->name . "\"", 1 );
            }
            ok( $c eq $alter, "cookie \"" . $c->name . "\" identical" );
        });



( run in 2.405 seconds using v1.01-cache-2.11-cpan-364913b4093 )