# # Copyright (C) 2004 by Robert James Kaes # All rights reserved. # package WormBytes::CGI::Application; use base qw(CGI::Application); # Bring in some of the standard plugin modules use CGI::Application::Plugin::TT; use CGI::Application::Plugin::Session; # Modules use to handle other tasks in the application use File::Spec; use Digest::SHA1 qw(sha1_hex); # # Initialize part of the application state here. # sub cgiapp_init { my $self = shift; my %arg = @_; # Where are session cookies stored? unless ($self->param('DISABLE_SESSION_SUPPORT')) { my $session_dir = $self->param('SESSION_DIR') || File::Spec->tmpdir; # Define how the session cookie information is stored $self->session_config(CGI_SESSION_OPTIONS => [ "driver:File;id:UUID", $self->query, { Directory => $session_dir }, ], COOKIE_PARAMS => { -expiry => '+1h' }, ); } # # Define where the templates are loaded from # $self->tt_config(TEMPLATE_OPTIONS => { INCLUDE_PATH => $self->tmpl_path, POST_CHOMP => 1, }); # # Whenever an error occurs in the app, call this routine # $self->error_mode('log_internal_error'); } # # If there is a problem with one of the run modes, log that # fact and display the information to the user. # sub log_internal_error { my ($self, $error) = @_; return $self->tt_process('error.tt', { reason => $error }); } # # Before doing _anything_ make sure the session is still valid, and # that the user is logged in. # sub cgiapp_prerun { my $self = shift; return if $self->param('DISABLE_SESSION_SUPPORT'); # Start by making sure the MAC cookie matches what we have # stored in the session. unless ($self->validate_session_mac) { # If the MAC does not validate, log the user off. $self->log_user_out; return $self->prerun_mode("login"); } # Simply return if the user is logged in return if $self->is_logged_in; # Otherwise, we redirect to the login mode $self->prerun_mode("login"); } # # Update the MAC cookie # sub cgiapp_postrun { my ($self, $output_ref) = @_; # Add the new session MAC to the cookie and the session $self->generate_session_mac unless $self->param('DISABLE_SESSION_SUPPORT'); } # # Instead of using the CGI module, we use CGI::Simple. Just like # CGI, but smaller. # sub cgiapp_get_query { my $self = shift; # Bring in the CGI::Simple module require CGI::Simple; # now return the query object return CGI::Simple->new; } # # Always add the query paramaters to the template # sub tt_pre_process { my ($self, $template, $params) = @_; $params->{self} = $self; $params->{cgi} = $self->query; $params->{query} = $self->query->Vars; } # # Checks that the information supplied by the client in the MAC # matches what we have stored in the session. # sub validate_session_mac { my $self = shift; my $r = $self->session->param("~MAC"); my $h = $self->query->cookie('MAC'); return 0 unless $r && $h; my $ua = uc sha1_hex(_return_user_agent()); my $hp = uc sha1_hex("$ua:$r"); return $h == $hp; } # # Update the session MAC. Generates a random number, stores that in # the session, and then hashes it with the current USER-AGENT variable, # and finally updates the cookie the browser will send back. # sub generate_session_mac { my $self = shift; my $ua = uc sha1_hex(_return_user_agent()); my $r = uc unpack("H*", pack('N4', map { rand 0xffffffff } 1..4)); my $h = uc sha1_hex("$ua:$r"); # Store a copy of the random number for later comparison $self->session->param("~MAC", $r); # Now write that value to the end user my $cookie = $self->query->cookie(-name => "MAC", -values => $h, -expires => 0, -path => '/', ); $self->header_add(-cookie => [ $cookie ]); } sub _return_user_agent { $ENV{'HTTP_USER_AGENT'} || 'unknown user-agent' } # # Untaint a parameter using CGI::Untaint # sub cgi_untaint { my $self = shift; unless (defined($self->param("__CGI_UNTAINT_OBJ"))) { require CGI::Untaint; my $untaint = CGI::Untaint->new($self->query->Vars); $self->param("__CGI_UNTAINT_OBJ" => $untaint); } return $self->param("__CGI_UNTAINT_OBJ"); } # # Issue a redirect to a given URL # sub redirect_url { my ($self, $url) = @_; $self->header_type('redirect'); $self->header_add(-url => $url); return "Redirecting to $url"; } 1;