HTML::FormFu::Element::RequestToken - Hidden text field which contains a unique


Catalyst-Controller-HTML-FormFu documentation Contained in the Catalyst-Controller-HTML-FormFu distribution.

Index


Code Index:

NAME

Top

HTML::FormFu::Element::RequestToken - Hidden text field which contains a unique token

SYNOPSIS

Top

  my $e = $form->element( { type => 'Token' } );

  my $p = $form->element( { plugin => 'Token' } );

DESCRIPTION

Top

This field can prevent CSRF attacks. It contains a random token. After submission the token is checked with the token which is stored in the session of the current user. See "request_token_enable" in Catalyst::Controller::HTML::FormFu for a convenient way how to use it.

ATTRIBUTES

Top

context

Value of the stash key for the Catalyst context object ($c). Defaults to context.

expiration_time

Time to life for a token in seconds. Defaults to 3600.

session_key

Session key which is used to store the tokens. Defaults to __token.

limit

Limit the number of tokens which are kept in the session. Defaults to 20.

constraints

Defaults to HTML::FormFu::Constraint::RequestToken and HTML::FormFu::Constraint::Required.

message

Set the error message.

METHODS

Top

expire_token

This method looks in the session for expired tokens and removes them.

get_token

Generates a new token and stores it in the stash.

verify_token

Checks whether a given token is already in the session. Returns 1 if it exists, 0 otherwise.

SEE ALSO

Top

Catalyst::Controller::HTML::FormFu, HTML::FormFu::Plugin::RequestToken, HTML::FormFu::Constraint::RequestToken

HTML::FormFu

AUTHOR

Top

Moritz Onken, onken@houseofdesign.de

LICENSE

Top

This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself.


Catalyst-Controller-HTML-FormFu documentation Contained in the Catalyst-Controller-HTML-FormFu distribution.

package HTML::FormFu::Element::RequestToken;
use Moose;
use MooseX::ChainedAccessors;

extends 'HTML::FormFu::Element::Text';

use HTML::FormFu::Util qw( process_attrs );
use Carp qw( croak );

has expiration_time => ( is => 'rw', traits  => ['Chained'], default => 3600 );
has session_key     => ( is => 'rw', traits  => ['Chained'], default => '__token' );
has context         => ( is => 'rw', traits  => ['Chained'], default => 'context' );
has limit           => ( is => 'rw', traits  => ['Chained'], default => 20 );
has message         => ( is => 'rw', traits  => ['Chained'], default => 'Form submission failed. Please try again.' );

after BUILD => sub {
    my $self = shift;
    $self->name('_token');
    $self->constraints([qw(RequestToken Required)]);
    $self->field_type('hidden');
};

sub process_value {
    my ($self, $value) = @_;
    
    return $self->verify_token($value) ? $value
                                       : $self->value($self->get_token)->value;
}

sub verify_token {
    my ($self, $token) = @_;
	
    return undef unless($token);
    
    my $form = $self->form;
    
    croak "verify_token() can only be called if form has been submitted"
        if !$form->submitted;
    
    my $field_name = $self->name;
    
    my $c = $self->form->stash->{ $self->context };
    
    for ( @{ $c->session->{ $self->session_key } || [] } ) {
        return 1 if ( $_->[0] eq $token );
    }
	
    return undef;
}

sub expire_token {
    my ($self) = @_;
    
    my $c = $self->form->stash->{ $self->context };
    
    my @token;
    for ( @{ $c->session->{ $self->session_key } || [] } ) {
        push( @token, $_ ) if ( $_->[1] > time );
    }
    
    @token = splice(@token, -$self->limit, $self->limit)  if(@token > $self->limit);
    
    $c->session->{ $self->session_key } = \@token;
}

sub get_token {
    my ($self) = @_;
    
    my $token;
    my $c = $self->form->stash->{ $self->context };
    my @chars = ( 'a' .. 'z', 0 .. 9 );
    
    $token .= $chars[ int( rand() * 36 ) ] for ( 0 .. 15 );
    
    $c->session->{ $self->session_key } ||= [];
    
    push @{ $c->session->{ $self->session_key } },
        [ $token, time + $self->expiration_time ];
    
    $self->expire_token;
    
    return $token;
}

1;

__END__