#!/usr/bin/env perl

use Getopt::Long;

use Template;
use Template::Directive::XSSAudit;
use Pod::Usage;

my $help;
my @libs;
my @plugins;
my @filters;

GetOptions(
    'help'     => \$help,
    'lib=s'    => \@libs,
    'plugin=s' => \@plugins,
    'filter=s' => \@filters,
) or pod2usage(2);
pod2usage(1) if $help;

foreach my $class (@plugins) {
    eval "require $class";
    warn($@) if $@;
}

my $tt_config = {
    FACTORY => 'Template::Directive::XSSAudit',
    ABSOLUTE => 1,
    INCLUDE_PATH => \@libs,
};
my $tt = Template->new($tt_config);

Template::Directive::XSSAudit->good_filters(
    \@filters
) if @filters;

Template::Directive::XSSAudit->on_error(sub {
    my ($context) = @_;
    print pretty_event_message('on_error',$context);
});
Template::Directive::XSSAudit->on_filtered(sub {
    my ($context) = @_;
    print pretty_event_message('on_filtered',$context);
});
foreach my $file (@ARGV) {
    $tt->process($file, {}, \my $out) || warn($tt->error());
}

exit;

sub pretty_event_message {
    my($event, $context) = @_;

    my $var_name     = $context->{variable_name};
    my $filters      = $context->{filtered_by};
    my $file         = $context->{file_name} || '<unknown_file>';
    my $line_no      = $context->{file_line} || 0;

    my $problem_type = $event eq "on_filtered" ? "OK"
                       : @$filters             ? "NO_SAFE_FILTER"
                       :                         "NO_FILTERS";
    my $used_filters = @$filters ? "\t" . (join ",", @$filters) : "";

    sprintf("%s\t%s\tline:%-5d\t%s%s\n",
        $file, $problem_type, $line_no, $var_name, $used_filters
    )
}

1;
__END__

=head1 NAME

ttxsscheck - list potential XSS problems with a Template Toolkit file

=head1 SYNOPSIS

 Usage:
   ttxsscheck [options] [files]

 Options:
   -h     (--help)       This help
   -l DIR (--lib=DIR)    Library directory (INCLUDE_PATH) (multiple)
   -p MOD (--plugin=MOD) Additional perl class names that you would
                         like to load. Useful if you have custom
                         filters. (multiple)
   -f     (--filter)     Override what is considered a 'good' filter
                         (multiple)

 Examples:
   # single file check -- setting INCLUDE_PATH to handle relative includes
   # one or more of the 'html' or 'uri' filters must be used for the GET
   # to be considered "good"
   ttxsscheck -l /your/tt/root -f html -f uri -f other_filter /your/tt/root/index.tt
  
   # using xargs and find to do a whole bunch of TT files
   find /your/tt/root-name '*.tt' | xargs ttxsscheck [options] 
